2
0

Theater.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. /******************************************************************************/
  4. TheaterClass Theater;
  5. /******************************************************************************/
  6. /******************************************************************************/
  7. cchar8 *TheaterClass::t_show[]=
  8. {
  9. "All",
  10. "Publishable",
  11. "Non-Publishable",
  12. "Invalid",
  13. };
  14. ELM_TYPE TheaterClass::modes[]=
  15. {
  16. ELM_OBJ, ELM_MTRL, ELM_IMAGE,
  17. };
  18. cchar8 *TheaterClass::t_obj_mode[]=
  19. {
  20. "Rotate",
  21. "Scale",
  22. };
  23. /******************************************************************************/
  24. void TheaterClass::Options::Horizontal( Options &options, C Str &text) { options.horizontal= TextBool(text) ; Theater.refreshSize();}
  25. void TheaterClass::Options::Rows( Options &options, C Str &text) {Theater.old_rows=options.rows; options.rows = TextInt (text) ; Theater.refreshSize();}
  26. void TheaterClass::Options::Size( Options &options, C Str &text) { options.item_size = TextFlt (text) ; Theater.refreshSize();}
  27. void TheaterClass::Options::Show( Options &options, C Str &text) { options.show =SHOW(TextInt (text)); Theater.refreshData();}
  28. void TheaterClass::Options::FOV( Options &options, C Str &text) {Theater.viewport.fov=DegToRad(TextFlt(text));}
  29. Str TheaterClass::Options::FOV(C Options &options ) {return Round(RadToDeg(Theater.viewport.fov));}
  30. void TheaterClass::Options::Angle( Options &options, C Str &text) {options.angle=DegToRad(TextVec2(text));}
  31. Str TheaterClass::Options::Angle(C Options &options ) {return Round(RadToDeg(options.angle));}
  32. void TheaterClass::Options::Env( Options &options, C Str &text) {options.env_id=Proj.findElmID(text, ELM_ENV);}
  33. Str TheaterClass::Options::Env(C Options &options ) {return Proj.elmFullName(options.env_id);}
  34. void TheaterClass::Options::EditMode( Options &options, C Str &text) {Theater.obj_mode.visible(TextBool(text));}
  35. Str TheaterClass::Options::EditMode(C Options &options ) {return Theater.obj_mode.visible();}
  36. ::TheaterClass::Options& TheaterClass::Options::create()
  37. {
  38. add("Horizontal" , MemberDesc(MEMBER(Options, horizontal )).setTextToDataFunc(Horizontal));
  39. p_rows=&add("Rows" , MemberDesc(MEMBER(Options, rows )).setTextToDataFunc(Rows)).range(1, 10).mouseEditSpeed(2).desc("Change with: Ctrl+MouseWheel");
  40. p_size=&add("Item Size" , MemberDesc(MEMBER(Options, item_size )).setTextToDataFunc(Size)).range(0.1f, 1.5f).mouseEditMode(PROP_MOUSE_EDIT_SCALAR).desc("Change with: Alt+MouseWheel");
  41. p_angle=&add("Item Angle" , MemberDesc(DATA_VECI2).setFunc(Angle, Angle));
  42. p_scale=&add("Item 3D Scale" , MemberDesc(MEMBER(Options, item_3d_scale))).range(0.01f, 20).mouseEditMode(PROP_MOUSE_EDIT_SCALAR).desc("Change with: Shift+MouseWheel");
  43. add("Scale to Fit" , MemberDesc(MEMBER(Options, scale_fit ))).desc("Keyboard Shortcut: Alt+S");
  44. add("Draw at Center" , MemberDesc(MEMBER(Options, center ))).desc("Keyboard Shortcut: Alt+C");
  45. add("Draw Box" , MemberDesc(MEMBER(Options, draw_box ))).desc("Keyboard Shortcut: Alt+B");
  46. add("Draw Axis" , MemberDesc(MEMBER(Options, draw_axis ))).desc("Keyboard Shortcut: Alt+A");
  47. add("Draw Axis on Top" , MemberDesc(MEMBER(Options, axis_on_top ))).desc("Keyboard Shortcut: Shift+Alt+A");
  48. add("Axis Size" , MemberDesc(MEMBER(Options, axis_size ))).range(0.01f, 100).mouseEditMode(PROP_MOUSE_EDIT_SCALAR).mouseEditSpeed(0.5f);
  49. add("Rotate" , MemberDesc(MEMBER(Options, rotate )));
  50. add("Rotation Speed" , MemberDesc(MEMBER(Options, rot_speed ))).range(-4, 4);
  51. add("Variation Cycle Speed" , MemberDesc(MEMBER(Options, var_speed ))).range(0, 5).desc("How fast are Object Mesh Material variations cycled through");
  52. add("Auto Align Flat Objects", MemberDesc(MEMBER(Options, auto_rot_flat_objects)));
  53. add("Show Elements" , MemberDesc(MEMBER(Options, show )).setTextToDataFunc(Show)).setEnum(t_show, Elms(t_show));
  54. add("Light Direction" , MemberDesc(MEMBER(Options, light_dir ))).desc("Keyboard Shortcut: Alt+L");
  55. add("Environment" , MemberDesc(MEMBER(Options, env_id )).setFunc(Env, Env)).elmType(ELM_ENV);
  56. add("Field of View" , MemberDesc(DATA_INT ).setFunc(FOV, FOV)).range(5, 75);
  57. add("Allow Edit Mode" , MemberDesc(DATA_BOOL).setFunc(EditMode, EditMode)).desc("Edit Mode allows Transforming Objects directly in the Theater");
  58. autoData(this);
  59. Rect r=::PropWin::create("Options", Vec2(0.02f, -0.02f), 0.04f, 0.045f, 0.26f); barVisible(false).show(); FlagDisable(flag, WIN_MOVABLE); button[2].func(null);
  60. size(Vec2(r.max.x, -r.min.y)+0.02f+defaultInnerPaddingSize());
  61. return T;
  62. }
  63. void TheaterClass::Options::rowsDelta(int delta ) {if(p_rows )p_rows ->textline.set(S+p_rows ->clamp(rows+delta));}
  64. void TheaterClass::Options::sizeFactor(flt factor) {if(p_size )p_size ->textline.set(S+p_size ->clamp(item_size *ScaleFactor(factor)));}
  65. void TheaterClass::Options::scaleFactor(flt factor) {if(p_scale)p_scale->textline.set(S+p_scale->clamp(item_3d_scale*ScaleFactor(factor)));}
  66. int TheaterClass::List2::screenToVis(C Vec2 &screen, C GuiPC *gpc)C
  67. {
  68. Theater.viewport.setDisplayView(); Camera temp=ActiveCam, cam; cam.set(MatrixIdentity).set();
  69. Vec pos, dir; ScreenToPosDir(screen, pos, dir); dir*=D.viewRange();
  70. int vis=-1; flt frac;
  71. VecI2 vis_range=visibleElmsOnScreen();
  72. MAX(vis_range.x-=Theater.options.rows, 0);
  73. MIN(vis_range.y+=Theater.options.rows, elms()-1);
  74. for(int i=vis_range.x; i<=vis_range.y; i++)
  75. {
  76. if(Elm *elm=Proj.findElm(visToData(i)->id))switch(elm->type)
  77. {
  78. case ELM_OBJ: if(ObjectPtr obj=Proj.gamePath(elm->id))if(C MeshPtr &mesh=obj->mesh())
  79. {
  80. Rect rect=visToScreenRect(i);
  81. Matrix m=Theater.getMatrix(UIDZero, mesh->ext, rect); // use 'UIDZero' so highlight will not change while transforming an object
  82. flt f; if(Sweep(pos, dir, *mesh, &m, &f))if(vis<0 || f<frac){vis=i; frac=f;}
  83. }
  84. }
  85. }
  86. temp.set();
  87. if(vis>=0)return vis;
  88. return ::EE::_List::screenToVis(screen, gpc);
  89. }
  90. void TheaterClass::ModeChanged(TheaterClass &theater) {theater.refreshData(); theater.refreshNow();}
  91. void TheaterClass::Mode0(TheaterClass &theater) {theater.mode.set(0);}
  92. void TheaterClass::Mode1(TheaterClass &theater) {theater.mode.set(1);}
  93. void TheaterClass::Mode2(TheaterClass &theater) {theater.mode.set(2);}
  94. void TheaterClass::ModeS0(TheaterClass &theater) {theater.obj_mode.toggle(0);}
  95. void TheaterClass::ModeS1(TheaterClass &theater) {theater.obj_mode.toggle(1);}
  96. void TheaterClass::ToggleAxis(TheaterClass &theater) {theater.options.draw_axis ^=1; theater.options.toGui();}
  97. void TheaterClass::ToggleAxisTop(TheaterClass &theater) {theater.options.axis_on_top^=1; theater.options.toGui();}
  98. void TheaterClass::ToggleBox(TheaterClass &theater) {theater.options.draw_box ^=1; theater.options.toGui();}
  99. void TheaterClass::ToggleCenter(TheaterClass &theater) {theater.options.center ^=1; theater.options.toGui();}
  100. void TheaterClass::ToggleScale(TheaterClass &theater) {theater.options.scale_fit ^=1; theater.options.toGui();}
  101. void TheaterClass::ToggleLight(TheaterClass &theater) {theater.options.light_dir ^=1; theater.options.toGui();}
  102. void TheaterClass::ToggleOptions(TheaterClass &theater) {theater.show_options.toggle(0);}
  103. void TheaterClass::DragElmsStart(ProjectEx &proj)
  104. {
  105. // get elements from theater list
  106. proj.drag_list_sel.clear();
  107. if(ListElm *list_elm=Theater.list())proj.drag_list_sel.add(list_elm->id);
  108. //REPA(Theater.list.sel)if(ListElm *list_elm=Theater.list.absToData(Theater.list.sel[i]))proj.drag_list_sel.include(list_elm.id);
  109. // start drag
  110. proj.dragElmsStart();
  111. }
  112. flt TheaterClass::depth()C {return D.viewRange()/10;}
  113. Matrix TheaterClass::getMatrix(C UID &elm_id, Box box, C Rect &rect)
  114. {
  115. bool small=(options.auto_rot_flat_objects && box.size().y<box.size().max()*0.3f);
  116. flt depth=T.depth();
  117. Vec pos =ScreenToPos (rect.center(), depth);
  118. Vec2 size (ScreenToPosD(Vec2(rect.w(), 0), depth).length(),
  119. ScreenToPosD(Vec2(0, rect.h()), depth).length());
  120. Matrix m(1); if(transform_ids.binaryHas(elm_id, Compare))m=transform_matrix;
  121. if(options.center)
  122. {
  123. m.move(-box.center()); box-=box.center(); // move so it's at the center
  124. }
  125. flt scale=1; if(options.scale_fit)
  126. {
  127. box|=box*Matrix3().setRotateY(PI_4); // include the box when it's rotated at 45 deg
  128. scale=Min(size.x/box.xz().size().max(), size.y/box.h()); // scale to visible screen size
  129. }else
  130. {
  131. scale*=2*Tan(D.viewFovY()/2);
  132. }
  133. scale*=options.item_3d_scale;
  134. m.scale(scale);
  135. m.rotateY(options.time_angle-options.angle.x+PI); // rotate Y, use -angle.x to match mouse rotation in all other editors, add PI to front-face objects by default
  136. m.rotateX(options.angle.y);
  137. if(small)m.rotateX(-PI_4); // if it's short, then rotate to look from above
  138. m*=ActiveCam.matrix.orn(); // adjust to camera orientation
  139. m.move(pos); // move to screen position
  140. return m;
  141. }
  142. void TheaterClass::draw(C UID &elm_id, C Mesh &mesh, C Rect &rect)
  143. {
  144. mesh.MeshLod::draw(getMatrix(elm_id, mesh.ext, rect)); // use best LOD
  145. }
  146. bool TheaterClass::litSel()C {return obj_mode.visible() && obj_mode()>=0;}
  147. bool TheaterClass::highlighted(int i)C {return list.lit==i;}
  148. bool TheaterClass::selected(int i)C {return list.sel.has(list.visToAbs(i));}
  149. void TheaterClass::MeshMtrls::clean() {REP(variations)parts[0].variation(i, null, -1); variations=0;}
  150. ::TheaterClass::MeshMtrls& TheaterClass::MeshMtrls::create() {::EE::Mesh::create(1).parts[0].variations(32).base.create(Ball(0.42f), VTX_NRM|VTX_TAN|VTX_TEX0, 16); setRender().setBox(); delBase(); return T;}
  151. bool TheaterClass::MeshMtrls::available()C {return InRange(variations, parts[0].variations());}
  152. Mesh& TheaterClass::MeshMtrls::set(C MaterialPtr &mtrl, int &variation) {parts[0].variation(variations, mtrl); variation=variations++; return T;}
  153. void TheaterClass::cleanMeshMaterial() {REPAO(mesh_mtrls).clean();}
  154. Mesh& TheaterClass::getMeshMaterial(C MaterialPtr &mtrl, int &variation)
  155. {
  156. MeshMtrls *mm=null; FREPA(mesh_mtrls){MeshMtrls &mesh_mtrl=mesh_mtrls[i]; if(mesh_mtrl.available()){mm=&mesh_mtrl; goto found;}}
  157. mm=&mesh_mtrls.New().create();
  158. found:
  159. return mm->set(mtrl, variation);
  160. }
  161. void TheaterClass::Render() {Theater.render();}
  162. void TheaterClass::render()
  163. {
  164. switch(Renderer())
  165. {
  166. case RM_PREPARE:
  167. {
  168. LightDir(options.light_dir ? !(ActiveCam.matrix.z*2+ActiveCam.matrix.x-ActiveCam.matrix.y) : ActiveCam.matrix.z, 1-D.ambientColor()).add(false);
  169. VecI2 vis_range=list.visibleElmsOnScreen();
  170. MAX(vis_range.x-=options.rows, 0);
  171. MIN(vis_range.y+=options.rows, data.elms()-1);
  172. for(int i=vis_range.x; i<=vis_range.y; i++)
  173. if(Elm *elm=Proj.findElm(data[i].id))
  174. {
  175. Rect rect=list.visToScreenRect(i);
  176. bool highlighted=(litSel() && T.highlighted(i)),
  177. selected =(litSel() && T.selected (i));
  178. switch(elm->type)
  179. {
  180. case ELM_OBJ: if(ObjectPtr obj=Proj.gamePath(elm->id))if(C MeshPtr &mesh=obj->mesh()) // use "obj->mesh" instead of "Proj.gamePath(obj_data.mesh_id)" in case the object inherits mesh from base
  181. {
  182. int variation=obj->meshVariationIndex();
  183. if(!obj->customMeshVariationAny()) // if object doesn't specify a custom variation
  184. if(int variations=mesh->variations()) // copy to temp var to avoid div by zero in case mesh for some reason gets modified on another thread (shouldn't happen)
  185. variation=Trunc(Time.realTime()*options.var_speed)%variations; // cycle through all available variations
  186. Color lit=ColorBrightness(GetLitSelCol(highlighted, selected, TRANSPARENT), 0.33f);
  187. SetVariation(variation); SetHighlight(lit); draw(elm->id, *mesh, rect);
  188. SetVariation( ); SetHighlight( );
  189. }break;
  190. case ELM_MTRL: if(MaterialPtr mtrl=Proj.gamePath(elm->id))
  191. {
  192. #if 0 // changing materials during rendering is now illegal
  193. Mesh &mesh=MtrlEdit.preview_mesh[0];
  194. mesh.material(mtrl);
  195. draw(elm.id, mesh, rect);
  196. #else
  197. int variation; Mesh &mesh=getMeshMaterial(mtrl, variation);
  198. SetVariation(variation); draw(elm->id, mesh, rect); SetVariation();
  199. #endif
  200. }break;
  201. }
  202. }
  203. }break;
  204. }
  205. }
  206. void TheaterClass::Draw(Viewport &viewport) {Theater.draw();}
  207. void TheaterClass::draw()
  208. {
  209. // environment
  210. EnvironmentPtr env=EnvEdit.cur(); if(!env)env=Proj.gamePath(options.env_id); if(!env)env=&DefaultEnvironment; env->set();
  211. bool line_smooth=D.lineSmooth(true); // this can be very slow, so don't use it everywhere
  212. AMBIENT_MODE ambient =D. ambientMode(); D. ambientMode(AMBIENT_FLAT);
  213. DOF_MODE dof =D. dofMode(); D. dofMode( DOF_NONE);
  214. MOTION_MODE motion =D. motionMode(); D. motionMode( MOTION_NONE);
  215. bool eye_adapt=D.eyeAdaptation(); D.eyeAdaptation( false);
  216. bool astros =AstrosDraw ; AstrosDraw =false;
  217. bool ocean =Water.draw ; Water.draw =false;
  218. Camera temp =ActiveCam, cam; cam .set(MatrixIdentity).set();
  219. Renderer(Render); cleanMeshMaterial(); // clean after rendering finished
  220. if(options.draw_axis || options.draw_box)
  221. {
  222. if(options.axis_on_top)D.depthLock(false);else Renderer.setDepthForDebugDrawing();
  223. SetMatrix();
  224. }
  225. VecI2 vis_range=list.visibleElmsOnScreen();
  226. for(int i=vis_range.x; i<=vis_range.y; i++)
  227. {
  228. Rect rect=list.visToScreenRect(i);
  229. if(Elm *elm=Proj.findElm(data[i].id))switch(elm->type)
  230. {
  231. case ELM_OBJ: if(options.draw_axis || options.draw_box)if(ObjectPtr obj=Proj.gamePath(elm->id))if(C MeshPtr &mesh=obj->mesh())
  232. {
  233. Matrix m=getMatrix(UIDZero, mesh->ext, rect); // use 'UIDZero' to avoid scaling matrix for drawing
  234. if(options.draw_box)OBox(mesh->ext, m).draw();
  235. if(options.draw_axis)m.scaleOrn(options.axis_size).draw();
  236. }break;
  237. case ELM_IMAGE: if(ImagePtr image=Proj.gamePath(elm->id))
  238. {
  239. Rect image_rect=image->fit(rect);
  240. if(image->mode()==IMAGE_CUBE)image->drawCubeFace(WHITE, TRANSPARENT, image_rect, DIR_FORWARD);
  241. else image->drawFilter (image_rect);
  242. }break;
  243. }
  244. if(litSel())
  245. {
  246. Color lit=GetLitSelCol(highlighted(i), selected(i), TRANSPARENT); if(lit.a)
  247. {
  248. lit.a/= 2; rect.draw(lit, false);
  249. lit.a/=12; rect.draw(lit, true );
  250. }
  251. }
  252. }
  253. if(options.draw_axis || options.draw_box)
  254. if(options.axis_on_top)D.depthUnlock();
  255. temp.set();
  256. D. dofMode(dof );
  257. D. motionMode(motion );
  258. D. ambientMode(ambient );
  259. D.eyeAdaptation(eye_adapt );
  260. D.lineSmooth (line_smooth);
  261. AstrosDraw =astros;
  262. Water.draw =ocean;
  263. }
  264. void TheaterClass::setVisibility(bool vis)
  265. {
  266. vis&=Proj.theater();
  267. visible(vis);
  268. viewport .visible(vis);
  269. mode .visible(vis);
  270. show_options.visible(vis);
  271. menu .enabled(vis);
  272. SetKbExclusive();
  273. }
  274. void TheaterClass::hideDo()
  275. {
  276. if(Proj.theater())Proj.theater.push();
  277. }
  278. void TheaterClass::create()
  279. {
  280. cchar8 *options_t[]={"Options"};
  281. Gui+=viewport .create(Draw); viewport.fov=DegToRad(30);
  282. Gui+=::EE::Region::create().slidebarSize(0.06f).skin(&EmptyGuiSkin, false); kb_lit=false; REPAO(slidebar).skin(&HalfTransparentSkin);
  283. Gui+=mode .create((cchar8**)null, ELMS(modes)).valid(true).set(0).func(ModeChanged, T); REPA(mode)mode.tab(i).setText(Plural(ElmTypeName[modes[i]])).desc(S+"Keyboard Shortcut: F"+(i+1));
  284. FREPA(modes)if(modes[i]==ELM_OBJ)
  285. {
  286. mode.tab(i)+=obj_mode.create(t_obj_mode, Elms(t_obj_mode)).hide();
  287. REPA(obj_mode)obj_mode.tab(i).desc(S+"Select with LMB\nTransform with RMB\nKeyboard Shortcut: Shift+F"+(i+1));
  288. break;
  289. }
  290. Gui+=show_options.create(options_t, Elms(options_t)); show_options.tab(0)+=options.create(); show_options.tab(0).desc("Keyboard Shortcut: F10");
  291. T +=list.create().drawMode(LDM_RECTS).horizontal(true).skin(&EmptyGuiSkin); list.flag|=LIST_MULTI_SEL;
  292. Node<MenuElm> menu;
  293. menu.New().create("Mode0" , Mode0 , T).kbsc(KbSc(KB_F1));
  294. menu.New().create("Mode1" , Mode1 , T).kbsc(KbSc(KB_F2));
  295. menu.New().create("Mode2" , Mode2 , T).kbsc(KbSc(KB_F3));
  296. menu.New().create("ModeS0" , ModeS0, T).kbsc(KbSc(KB_F1, KBSC_SHIFT));
  297. menu.New().create("ModeS1" , ModeS1, T).kbsc(KbSc(KB_F2, KBSC_SHIFT));
  298. menu.New().create("Options", ToggleOptions, T).kbsc(KbSc(KB_F10));
  299. menu.New().create("Box" , ToggleBox , T).kbsc(KbSc(KB_B, KBSC_ALT));
  300. menu.New().create("Axis" , ToggleAxis , T).kbsc(KbSc(KB_A, KBSC_ALT));
  301. menu.New().create("AxisTop", ToggleAxisTop, T).kbsc(KbSc(KB_A, KBSC_ALT|KBSC_SHIFT));
  302. menu.New().create("Center" , ToggleCenter , T).kbsc(KbSc(KB_C, KBSC_ALT));
  303. menu.New().create("Scale" , ToggleScale , T).kbsc(KbSc(KB_S, KBSC_ALT));
  304. menu.New().create("Light" , ToggleLight , T).kbsc(KbSc(KB_L, KBSC_ALT));
  305. Gui+=T.menu.create(menu);
  306. setVisibility(false);
  307. }
  308. void TheaterClass::moveAbove(GuiObj &go)
  309. {
  310. show_options.moveAbove(go);
  311. mode .moveAbove(go);
  312. ::EE::GuiObj::moveAbove(go);
  313. viewport .moveAbove(go);
  314. }
  315. void TheaterClass::listElms(ElmNode &node, bool parent_contains_name)
  316. {
  317. node.children.sort(ProjectEx::CompareChildren); // needs to be sorted in case it wasn't before (this can happen if these elements aren't visible in the list)
  318. ELM_TYPE elm_type=modes[mode()];
  319. bool ignore_publish=(options.show!=PUBLISHABLE && options.show!=INVALID);
  320. FREPA(node.children)
  321. {
  322. int child_i=node.children [i];
  323. ElmNode &child =Proj.hierarchy[child_i];
  324. Elm &elm =Proj.elms [child_i];
  325. if(elm.finalExists())
  326. if(ignore_publish || elm.finalPublish()) // we're going recursively down, from parents to their children, so before checking children, we can only check for modes that will affect all children in the same way, and this is only if element is going to be published
  327. {
  328. bool this_contains_name=true, child_contains_name=true; // always show when no filter
  329. if(Proj.filter().is())
  330. {
  331. this_contains_name=(FlagTest(child.flag, ELM_CONTAINS_NAME) || parent_contains_name); // for performance reasons, merge 'this_contains_name' with 'parent_contains_name'
  332. child_contains_name= FlagTest(child.flag, ELM_CONTAINS_NAME_CHILD);
  333. }
  334. if(elm.type==elm_type && this_contains_name)
  335. {
  336. switch(options.show)
  337. {
  338. case NON_PUBLISHABLE: if( elm.finalPublish() )goto skip; break;
  339. case INVALID : if(!Proj.invalidRefs(elm))goto skip; break;
  340. }
  341. data.New().id=elm.id;
  342. }
  343. skip:
  344. listElms(child, this_contains_name); // list children
  345. }
  346. }
  347. }
  348. Vec2 TheaterClass::offset()C
  349. {
  350. Vec2 offset=0; if(flt size=list.imageSizeBase().c[!options.horizontal])
  351. {
  352. flt scale=(old_rows ? old_rows : options.rows)/size;
  353. REPA(offset)offset.c[i]=slidebar[i].offset()*scale;
  354. }
  355. return offset;
  356. }
  357. void TheaterClass::offset(C Vec2 &offset)
  358. {
  359. flt scale=list.imageSizeBase().c[!options.horizontal]/options.rows;
  360. REPA(offset)slidebar[i].offset(offset.c[i]*scale);
  361. }
  362. void TheaterClass::refreshSize() {refresh|=REFRESH_SIZE;}
  363. void TheaterClass::refreshData() {refresh|=REFRESH_DATA;}
  364. void TheaterClass::refreshNow()
  365. {
  366. Vec2 offset=T.offset();
  367. Vec2 size=rect().size()-slidebarSize();
  368. if(options.horizontal)
  369. {
  370. size=size.y/options.rows;
  371. size.x*=options.item_size;
  372. }else
  373. {
  374. size.x/=options.rows;
  375. MIN(size.y, size.x);
  376. size.y*=options.item_size;
  377. }
  378. if(refresh&REFRESH_DATA)
  379. {
  380. // save selection
  381. Memt<UID> sel; sel.reserve(list.sel.elms()); FREPA(list.sel)if(ListElm *elm=list.absToData(list.sel[i]))sel.binaryInclude(elm->id, Compare);
  382. data.clear();
  383. if(!Proj.filter_is_id)listElms(Proj.root);else
  384. if( Proj.findElm(Proj.filter_id))data.New().id=Proj.filter_id;
  385. list.setData(data);
  386. // restore selection
  387. list.sel.clear(); if(sel.elms())FREPA(data)if(sel.binaryHas(data[i].id, Compare))list.sel.add(i);
  388. }
  389. list.imageSize(size, 0).horizontal(options.horizontal);
  390. T.offset(offset);
  391. old_rows=0;
  392. Rect sr=slidebar[0].rect(); MAX(sr.min.x, Misc.rect().max.x); slidebar[0].rect(sr);
  393. refresh=0;
  394. }
  395. void TheaterClass::update(C GuiPC &gpc)
  396. {
  397. // process mouse wheel before super.update so it's not handled by the region slidebars
  398. if(visible() && gpc.visible && Gui.ms()==&list && Ms.wheel())
  399. if(Kb.ctrl() || Kb.shift() || Kb.alt())
  400. {
  401. if(Kb.ctrl ())options. rowsDelta (-Ms.wheel() );else
  402. {
  403. if(Kb.shift())options.scaleFactor( Ms.wheel()*0.1f); // allow processing both alt+shift at the same time
  404. if(Kb.alt ())options. sizeFactor( Ms.wheel()*0.1f); // allow processing both alt+shift at the same time
  405. }
  406. Ms.eatWheel();
  407. }
  408. ::EE::Region::update(gpc);
  409. if(visible() && gpc.visible)
  410. {
  411. bool rotate=options.rotate, can_transform=false;
  412. if(Gui.ms()==&list)
  413. {
  414. if(litSel() && modes[mode()]==ELM_OBJ)
  415. {
  416. // transform
  417. if(Ms.bp(1)) // start transforming
  418. {
  419. transform_ids.clear();
  420. if(!list.sel.has(list.visToAbs(list.lit)))list.sel.clear(); // if highlited is not selected, then clear selection
  421. FREPA(list.sel)if(ListElm *elm=list.absToData(list.sel[i]))transform_ids.binaryInclude(elm->id, Compare);
  422. if(!transform_ids.elms())if(ListElm *elm=list.visToData(list.lit))transform_ids.add(elm->id);
  423. transform_rotate_y=0;
  424. transform_rotate_y_frac=0;
  425. transform_scale=1;
  426. }else
  427. if(Ms.br(1) && transform_ids.elms()) // apply transform
  428. {
  429. Proj.transformApply(transform_ids, transform_matrix);
  430. transform_ids.clear();
  431. }
  432. if(transform_ids.elms() && Ms.b(1)) // adjust transform
  433. {
  434. can_transform=true; rotate=false;
  435. Ms.freeze();
  436. switch(obj_mode())
  437. {
  438. case OBJ_ROT:
  439. {
  440. transform_rotate_y_frac+=Ms.d().sum()*-1.33f;
  441. if(int t=Trunc(transform_rotate_y_frac))
  442. {
  443. transform_rotate_y+=t;
  444. transform_rotate_y_frac-=t;
  445. }
  446. }break;
  447. case OBJ_SCALE:
  448. {
  449. transform_scale*=ScaleFactor(Ms.d().sum()*(Kb.shift() ? 0.1f : 1.0f));
  450. }break;
  451. }
  452. transform_matrix.setRotateY(transform_rotate_y*PI_2).scale(transform_scale);
  453. }
  454. }
  455. if(Ms.bp(0))
  456. if(ListElm *elm=list())
  457. {
  458. if(Ms.bd(0))Proj.elmToggle(elm->id); // call this first, because it may open folders (parents)
  459. Proj.elmLocate(elm->id, true); // call this next, once parents are opened
  460. Gui.drag(ProjectEx::DragElmsFinish, Proj, null, DragElmsStart, ProjectEx::DragElmsCancel);
  461. }
  462. if(Ms.wheel())
  463. {
  464. if(Kb.ctrl ()){options. rowsDelta (-Ms.wheel() ); Ms.eatWheel();}else
  465. if(Kb.shift()){options.scaleFactor( Ms.wheel()*0.1f); Ms.eatWheel();}else
  466. if(Kb.alt ()){options. sizeFactor( Ms.wheel()*0.1f); Ms.eatWheel();}
  467. }
  468. if(Ms.b(2) || Ms.b(4) || Kb.win())
  469. {
  470. Ms.freeze();
  471. if(!(!Kb.ctrlCmd() && Kb.alt()))options.angle.x+=Ms.d().x; // disable X rotation when only alt pressed
  472. if(!( Kb.ctrlCmd() && !Kb.alt()))options.angle.y+=Ms.d().y; // disable Y rotation when only ctrl pressed
  473. options.toGui();
  474. rotate=false;
  475. }
  476. }
  477. if(Ms.bp(2) && Gui.window()==&options)show_options.toggle(0);
  478. if(refresh)refreshNow();
  479. if(options.p_angle && options.p_angle->button())rotate=false;
  480. if(rotate)options.time_angle+=options.rot_speed*Time.ad();
  481. if(!can_transform || Kb.kf(KB_ESC))transform_ids.clear(); // cancel transform
  482. }
  483. }
  484. void TheaterClass::resize()
  485. {
  486. if(visible())
  487. {
  488. Rect r=EditRect(false); if(rect()!=r)
  489. {
  490. rect(r);
  491. viewport .rect(r);
  492. mode .rect(Rect_U(r.up(), 0.6f, 0.06f));
  493. show_options.rect(Rect_RU(r.ru()-Vec2(slidebarSize(), 0), 0.24f, 0.06f));
  494. obj_mode .rect(Rect_U(Avg(mode.rect().max.x, show_options.rect().min.x), r.max.y, 0.28f, 0.06f), 0, true);
  495. options .posRU(show_options.rect().rd()-Vec2(0, 0.02f));
  496. refreshNow();
  497. }
  498. }
  499. }
  500. TheaterClass::TheaterClass() : refresh(0), old_rows(0) {}
  501. TheaterClass::Options::Options() : horizontal(true), rotate(true), auto_rot_flat_objects(true), scale_fit(true), center(true), draw_axis(false), axis_on_top(true), draw_box(false), light_dir(true), rows(2), item_size(1), item_3d_scale(1), axis_size(1), time_angle(0), rot_speed(0.5f), var_speed(1), angle(0), env_id(UIDZero), show(PUBLISHABLE), p_rows(null), p_size(null), p_scale(null), p_angle(null) {}
  502. TheaterClass::ListElm::ListElm() : id(UIDZero) {}
  503. TheaterClass::MeshMtrls::MeshMtrls() : variations(0) {}
  504. /******************************************************************************/