EditorScene.as 45 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551
  1. /// Urho3D editor scene handling
  2. #include "Scripts/Editor/EditorHierarchyWindow.as"
  3. #include "Scripts/Editor/EditorInspectorWindow.as"
  4. #include "Scripts/Editor/EditorCubeCapture.as"
  5. const int PICK_GEOMETRIES = 0;
  6. const int PICK_LIGHTS = 1;
  7. const int PICK_ZONES = 2;
  8. const int PICK_RIGIDBODIES = 3;
  9. const int PICK_UI_ELEMENTS = 4;
  10. const int MAX_PICK_MODES = 5;
  11. const int MAX_UNDOSTACK_SIZE = 256;
  12. Scene@ editorScene;
  13. String instantiateFileName;
  14. CreateMode instantiateMode = REPLICATED;
  15. bool sceneModified = false;
  16. bool runUpdate = false;
  17. Array<Node@> selectedNodes;
  18. Array<Component@> selectedComponents;
  19. Node@ editNode;
  20. Array<Node@> editNodes;
  21. Array<Component@> editComponents;
  22. uint numEditableComponentsPerNode = 1;
  23. Array<XMLFile@> sceneCopyBuffer;
  24. bool suppressSceneChanges = false;
  25. bool inSelectionModify = false;
  26. bool skipMruScene = false;
  27. Array<EditActionGroup> undoStack;
  28. uint undoStackPos = 0;
  29. bool revertOnPause = false;
  30. XMLFile@ revertData;
  31. Vector3 lastOffsetForSmartDuplicate;
  32. void ClearSceneSelection()
  33. {
  34. selectedNodes.Clear();
  35. selectedComponents.Clear();
  36. editNode = null;
  37. editNodes.Clear();
  38. editComponents.Clear();
  39. numEditableComponentsPerNode = 1;
  40. HideGizmo();
  41. }
  42. void CreateScene()
  43. {
  44. // Create a scene only once here
  45. editorScene = Scene();
  46. // Allow access to the scene from the console
  47. script.defaultScene = editorScene;
  48. // Always pause the scene, and do updates manually
  49. editorScene.updateEnabled = false;
  50. }
  51. bool ResetScene()
  52. {
  53. ui.cursor.shape = CS_BUSY;
  54. if (messageBoxCallback is null && sceneModified)
  55. {
  56. MessageBox@ messageBox = MessageBox("Scene has been modified.\nContinue to reset?", "Warning");
  57. if (messageBox.window !is null)
  58. {
  59. Button@ cancelButton = messageBox.window.GetChild("CancelButton", true);
  60. cancelButton.visible = true;
  61. cancelButton.focus = true;
  62. SubscribeToEvent(messageBox, "MessageACK", "HandleMessageAcknowledgement");
  63. messageBoxCallback = @ResetScene;
  64. return false;
  65. }
  66. }
  67. else
  68. messageBoxCallback = null;
  69. // Clear stored script attributes
  70. scriptAttributes.Clear();
  71. suppressSceneChanges = true;
  72. // Create a scene with default values, these will be overridden when loading scenes
  73. editorScene.Clear();
  74. editorScene.CreateComponent("Octree");
  75. editorScene.CreateComponent("DebugRenderer");
  76. // Release resources that became unused after the scene clear
  77. cache.ReleaseAllResources(false);
  78. sceneModified = false;
  79. revertData = null;
  80. StopSceneUpdate();
  81. UpdateWindowTitle();
  82. DisableInspectorLock();
  83. UpdateHierarchyItem(editorScene, true);
  84. ClearEditActions();
  85. suppressSceneChanges = false;
  86. ResetCamera();
  87. CreateGizmo();
  88. CreateGrid();
  89. SetActiveViewport(viewports[0]);
  90. return true;
  91. }
  92. void SetResourcePath(String newPath, bool usePreferredDir = true, bool additive = false)
  93. {
  94. if (newPath.empty)
  95. return;
  96. if (!IsAbsolutePath(newPath))
  97. newPath = fileSystem.currentDir + newPath;
  98. if (usePreferredDir)
  99. newPath = AddTrailingSlash(cache.GetPreferredResourceDir(newPath));
  100. else
  101. newPath = AddTrailingSlash(newPath);
  102. if (newPath == sceneResourcePath)
  103. return;
  104. // Remove the old scene resource path if any. However make sure that the default data paths do not get removed
  105. if (!additive)
  106. {
  107. cache.ReleaseAllResources(false);
  108. renderer.ReloadShaders();
  109. String check = AddTrailingSlash(sceneResourcePath);
  110. bool isDefaultResourcePath = check.Compare(fileSystem.programDir + "Data/", false) == 0 ||
  111. check.Compare(fileSystem.programDir + "CoreData/", false) == 0;
  112. if (!sceneResourcePath.empty && !isDefaultResourcePath)
  113. cache.RemoveResourceDir(sceneResourcePath);
  114. }
  115. else
  116. {
  117. // If additive (path of a loaded prefab) check that the new path isn't already part of an old path
  118. Array<String>@ resourceDirs = cache.resourceDirs;
  119. for (uint i = 0; i < resourceDirs.length; ++i)
  120. {
  121. if (newPath.StartsWith(resourceDirs[i], false))
  122. return;
  123. }
  124. }
  125. // Add resource path as first priority so that it takes precedence over the default data paths
  126. cache.AddResourceDir(newPath, 0);
  127. RebuildResourceDatabase();
  128. if (!additive)
  129. {
  130. sceneResourcePath = newPath;
  131. uiScenePath = GetResourceSubPath(newPath, "Scenes");
  132. uiElementPath = GetResourceSubPath(newPath, "UI");
  133. uiNodePath = GetResourceSubPath(newPath, "Objects");
  134. uiScriptPath = GetResourceSubPath(newPath, "Scripts");
  135. uiParticlePath = GetResourceSubPath(newPath, "Particle");
  136. }
  137. }
  138. String GetResourceSubPath(String basePath, const String&in subPath)
  139. {
  140. basePath = AddTrailingSlash(basePath);
  141. if (fileSystem.DirExists(basePath + subPath))
  142. return AddTrailingSlash(basePath + subPath);
  143. else
  144. return basePath;
  145. }
  146. bool LoadScene(const String&in fileName)
  147. {
  148. if (fileName.empty)
  149. return false;
  150. ui.cursor.shape = CS_BUSY;
  151. // Always load the scene from the filesystem, not from resource paths
  152. if (!fileSystem.FileExists(fileName))
  153. {
  154. MessageBox("No such scene.\n" + fileName);
  155. return false;
  156. }
  157. File file(fileName, FILE_READ);
  158. if (!file.open)
  159. {
  160. MessageBox("Could not open file.\n" + fileName);
  161. return false;
  162. }
  163. // Reset stored script attributes.
  164. scriptAttributes.Clear();
  165. // Add the scene's resource path in case it's necessary
  166. String newScenePath = GetPath(fileName);
  167. if (!rememberResourcePath || !sceneResourcePath.StartsWith(newScenePath, false))
  168. SetResourcePath(newScenePath);
  169. suppressSceneChanges = true;
  170. sceneModified = false;
  171. revertData = null;
  172. StopSceneUpdate();
  173. String extension = GetExtension(fileName);
  174. bool loaded;
  175. if (extension != ".xml")
  176. loaded = editorScene.Load(file);
  177. else
  178. loaded = editorScene.LoadXML(file);
  179. // Release resources which are not used by the new scene
  180. cache.ReleaseAllResources(false);
  181. // Always pause the scene, and do updates manually
  182. editorScene.updateEnabled = false;
  183. UpdateWindowTitle();
  184. DisableInspectorLock();
  185. UpdateHierarchyItem(editorScene, true);
  186. CollapseHierarchy();
  187. ClearEditActions();
  188. suppressSceneChanges = false;
  189. // global variable to mostly bypass adding mru upon importing tempscene
  190. if (!skipMruScene)
  191. UpdateSceneMru(fileName);
  192. skipMruScene = false;
  193. ResetCamera();
  194. CreateGizmo();
  195. CreateGrid();
  196. SetActiveViewport(viewports[0]);
  197. // Store all ScriptInstance and LuaScriptInstance attributes
  198. UpdateScriptInstances();
  199. return loaded;
  200. }
  201. bool SaveScene(const String&in fileName)
  202. {
  203. if (fileName.empty)
  204. return false;
  205. ui.cursor.shape = CS_BUSY;
  206. // Unpause when saving so that the scene will work properly when loaded outside the editor
  207. editorScene.updateEnabled = true;
  208. MakeBackup(fileName);
  209. File file(fileName, FILE_WRITE);
  210. String extension = GetExtension(fileName);
  211. bool success = (extension != ".xml" ? editorScene.Save(file) : editorScene.SaveXML(file));
  212. RemoveBackup(success, fileName);
  213. editorScene.updateEnabled = false;
  214. if (success)
  215. {
  216. UpdateSceneMru(fileName);
  217. sceneModified = false;
  218. UpdateWindowTitle();
  219. }
  220. else
  221. MessageBox("Could not save scene successfully!\nSee Urho3D.log for more detail.");
  222. return success;
  223. }
  224. bool SaveSceneWithExistingName()
  225. {
  226. if (editorScene.fileName.empty || editorScene.fileName == TEMP_SCENE_NAME)
  227. return PickFile();
  228. else
  229. return SaveScene(editorScene.fileName);
  230. }
  231. Node@ CreateNode(CreateMode mode)
  232. {
  233. Node@ newNode = null;
  234. if (editNode !is null)
  235. newNode = editNode.CreateChild("", mode);
  236. else
  237. newNode = editorScene.CreateChild("", mode);
  238. newNode.worldPosition = GetNewNodePosition();
  239. // Create an undo action for the create
  240. CreateNodeAction action;
  241. action.Define(newNode);
  242. SaveEditAction(action);
  243. SetSceneModified();
  244. FocusNode(newNode);
  245. return newNode;
  246. }
  247. void CreateComponent(const String&in componentType)
  248. {
  249. // If this is the root node, do not allow to create duplicate scene-global components
  250. if (editNode is editorScene && CheckForExistingGlobalComponent(editNode, componentType))
  251. return;
  252. // Group for storing undo actions
  253. EditActionGroup group;
  254. // For now, make a local node's all components local
  255. /// \todo Allow to specify the createmode
  256. for (uint i = 0; i < editNodes.length; ++i)
  257. {
  258. Component@ newComponent = editNodes[i].CreateComponent(componentType, editNodes[i].id < FIRST_LOCAL_ID ? REPLICATED : LOCAL);
  259. if (newComponent !is null)
  260. {
  261. // Some components such as CollisionShape do not create their internal object before the first call to ApplyAttributes()
  262. // to prevent unnecessary initialization with default values. Call now
  263. newComponent.ApplyAttributes();
  264. CreateComponentAction action;
  265. action.Define(newComponent);
  266. group.actions.Push(action);
  267. }
  268. }
  269. SaveEditActionGroup(group);
  270. SetSceneModified();
  271. // Although the edit nodes selection are not changed, call to ensure attribute inspector notices new components of the edit nodes
  272. HandleHierarchyListSelectionChange();
  273. }
  274. void CreateLoadedComponent(Component@ component)
  275. {
  276. if (component is null) return;
  277. CreateComponentAction action;
  278. action.Define(component);
  279. SaveEditAction(action);
  280. SetSceneModified();
  281. FocusComponent(component);
  282. }
  283. Node@ LoadNode(const String&in fileName, Node@ parent = null)
  284. {
  285. if (fileName.empty)
  286. return null;
  287. if (!fileSystem.FileExists(fileName))
  288. {
  289. MessageBox("No such node file.\n" + fileName);
  290. return null;
  291. }
  292. File file(fileName, FILE_READ);
  293. if (!file.open)
  294. {
  295. MessageBox("Could not open file.\n" + fileName);
  296. return null;
  297. }
  298. ui.cursor.shape = CS_BUSY;
  299. // Before instantiating, add object's resource path if necessary
  300. SetResourcePath(GetPath(fileName), true, true);
  301. Ray cameraRay = camera.GetScreenRay(0.5, 0.5); // Get ray at view center
  302. Vector3 position, normal;
  303. GetSpawnPosition(cameraRay, newNodeDistance, position, normal, 0, true);
  304. Node@ newNode = InstantiateNodeFromFile(file, position, Quaternion(), 1, parent, instantiateMode);
  305. if (newNode !is null)
  306. {
  307. FocusNode(newNode);
  308. instantiateFileName = fileName;
  309. }
  310. return newNode;
  311. }
  312. Node@ InstantiateNodeFromFile(File@ file, const Vector3& position, const Quaternion& rotation, float scaleMod = 1.0f, Node@ parent = null, CreateMode mode = REPLICATED)
  313. {
  314. if (file is null)
  315. return null;
  316. Node@ newNode;
  317. uint numSceneComponent = editorScene.numComponents;
  318. suppressSceneChanges = true;
  319. String extension = GetExtension(file.name);
  320. if (extension != ".xml")
  321. newNode = editorScene.Instantiate(file, position, rotation, mode);
  322. else
  323. newNode = editorScene.InstantiateXML(file, position, rotation, mode);
  324. suppressSceneChanges = false;
  325. if (parent !is null)
  326. newNode.parent = parent;
  327. if (newNode !is null)
  328. {
  329. newNode.scale = newNode.scale * scaleMod;
  330. if (alignToAABBBottom)
  331. {
  332. Drawable@ drawable = GetFirstDrawable(newNode);
  333. if (drawable !is null)
  334. {
  335. BoundingBox aabb = drawable.worldBoundingBox;
  336. Vector3 aabbBottomCenter(aabb.center.x, aabb.min.y, aabb.center.z);
  337. Vector3 offset = aabbBottomCenter - newNode.worldPosition;
  338. newNode.worldPosition = newNode.worldPosition - offset;
  339. }
  340. }
  341. // Create an undo action for the load
  342. CreateNodeAction action;
  343. action.Define(newNode);
  344. SaveEditAction(action);
  345. SetSceneModified();
  346. if (numSceneComponent != editorScene.numComponents)
  347. UpdateHierarchyItem(editorScene);
  348. else
  349. UpdateHierarchyItem(newNode);
  350. }
  351. return newNode;
  352. }
  353. bool SaveNode(const String&in fileName)
  354. {
  355. if (fileName.empty)
  356. return false;
  357. ui.cursor.shape = CS_BUSY;
  358. MakeBackup(fileName);
  359. File file(fileName, FILE_WRITE);
  360. if (!file.open)
  361. {
  362. MessageBox("Could not open file.\n" + fileName);
  363. return false;
  364. }
  365. String extension = GetExtension(fileName);
  366. bool success = (extension != ".xml" ? editNode.Save(file) : editNode.SaveXML(file));
  367. RemoveBackup(success, fileName);
  368. if (success)
  369. instantiateFileName = fileName;
  370. else
  371. MessageBox("Could not save node successfully!\nSee Urho3D.log for more detail.");
  372. return success;
  373. }
  374. void UpdateScene(float timeStep)
  375. {
  376. if (runUpdate)
  377. editorScene.Update(timeStep);
  378. }
  379. void StopSceneUpdate()
  380. {
  381. runUpdate = false;
  382. audio.Stop();
  383. toolBarDirty = true;
  384. // If scene should revert on update stop, load saved data now
  385. if (revertOnPause && revertData !is null)
  386. {
  387. suppressSceneChanges = true;
  388. editorScene.Clear();
  389. editorScene.LoadXML(revertData.GetRoot());
  390. CreateGrid();
  391. UpdateHierarchyItem(editorScene, true);
  392. ClearEditActions();
  393. suppressSceneChanges = false;
  394. }
  395. revertData = null;
  396. }
  397. void StartSceneUpdate()
  398. {
  399. runUpdate = true;
  400. // Run audio playback only when scene is updating, so that audio components' time-dependent attributes stay constant when
  401. // paused (similar to physics)
  402. audio.Play();
  403. toolBarDirty = true;
  404. // Save scene data for reverting if enabled
  405. if (revertOnPause)
  406. {
  407. revertData = XMLFile();
  408. XMLElement root = revertData.CreateRoot("scene");
  409. editorScene.SaveXML(root);
  410. }
  411. else
  412. revertData = null;
  413. }
  414. bool ToggleSceneUpdate()
  415. {
  416. if (!runUpdate)
  417. StartSceneUpdate();
  418. else
  419. StopSceneUpdate();
  420. return true;
  421. }
  422. bool ShowLayerMover()
  423. {
  424. if (ui.focusElement is null)
  425. return ShowLayerEditor();
  426. else
  427. return false;
  428. }
  429. void SetSceneModified()
  430. {
  431. if (!sceneModified)
  432. {
  433. sceneModified = true;
  434. UpdateWindowTitle();
  435. }
  436. }
  437. bool SceneDelete()
  438. {
  439. ui.cursor.shape = CS_BUSY;
  440. BeginSelectionModify();
  441. // Clear the selection now to prevent repopulation of selectedNodes and selectedComponents combo
  442. hierarchyList.ClearSelection();
  443. // Group for storing undo actions
  444. EditActionGroup group;
  445. // Remove nodes
  446. for (uint i = 0; i < selectedNodes.length; ++i)
  447. {
  448. Node@ node = selectedNodes[i];
  449. if (node.parent is null || node.scene is null)
  450. continue; // Root or already deleted
  451. uint nodeIndex = GetListIndex(node);
  452. // Create undo action
  453. DeleteNodeAction action;
  454. action.Define(node);
  455. group.actions.Push(action);
  456. node.Remove();
  457. SetSceneModified();
  458. // If deleting only one node, select the next item in the same index
  459. if (selectedNodes.length == 1 && selectedComponents.empty)
  460. hierarchyList.selection = nodeIndex;
  461. }
  462. // Then remove components, if they still remain
  463. for (uint i = 0; i < selectedComponents.length; ++i)
  464. {
  465. Component@ component = selectedComponents[i];
  466. Node@ node = component.node;
  467. if (node is null)
  468. continue; // Already deleted
  469. uint index = GetComponentListIndex(component);
  470. uint nodeIndex = GetListIndex(node);
  471. if (index == NO_ITEM || nodeIndex == NO_ITEM)
  472. continue;
  473. // Do not allow to remove the Octree, DebugRenderer or MaterialCache2D or DrawableProxy2D from the root node
  474. if (node is editorScene && (component.typeName == "Octree" || component.typeName == "DebugRenderer" ||
  475. component.typeName == "MaterialCache2D" || component.typeName == "DrawableProxy2D"))
  476. continue;
  477. // Create undo action
  478. DeleteComponentAction action;
  479. action.Define(component);
  480. group.actions.Push(action);
  481. node.RemoveComponent(component);
  482. SetSceneModified();
  483. // If deleting only one component, select the next item in the same index
  484. if (selectedComponents.length == 1 && selectedNodes.empty)
  485. hierarchyList.selection = index;
  486. }
  487. SaveEditActionGroup(group);
  488. EndSelectionModify();
  489. return true;
  490. }
  491. bool SceneCut()
  492. {
  493. return SceneCopy() && SceneDelete();
  494. }
  495. bool SceneCopy()
  496. {
  497. ui.cursor.shape = CS_BUSY;
  498. sceneCopyBuffer.Clear();
  499. // Copy components
  500. if (!selectedComponents.empty)
  501. {
  502. for (uint i = 0; i < selectedComponents.length; ++i)
  503. {
  504. XMLFile@ xml = XMLFile();
  505. XMLElement rootElem = xml.CreateRoot("component");
  506. selectedComponents[i].SaveXML(rootElem);
  507. rootElem.SetBool("local", selectedComponents[i].id >= FIRST_LOCAL_ID);
  508. sceneCopyBuffer.Push(xml);
  509. }
  510. }
  511. // Copy nodes.
  512. else
  513. {
  514. for (uint i = 0; i < selectedNodes.length; ++i)
  515. {
  516. // Skip the root scene node as it cannot be copied
  517. if (selectedNodes[i] is editorScene)
  518. continue;
  519. XMLFile@ xml = XMLFile();
  520. XMLElement rootElem = xml.CreateRoot("node");
  521. selectedNodes[i].SaveXML(rootElem);
  522. rootElem.SetBool("local", selectedNodes[i].id >= FIRST_LOCAL_ID);
  523. sceneCopyBuffer.Push(xml);
  524. }
  525. }
  526. return true;
  527. }
  528. bool ScenePaste(bool pasteRoot = false, bool duplication = false)
  529. {
  530. ui.cursor.shape = CS_BUSY;
  531. // Group for storing undo actions
  532. EditActionGroup group;
  533. for (uint i = 0; i < sceneCopyBuffer.length; ++i)
  534. {
  535. XMLElement rootElem = sceneCopyBuffer[i].root;
  536. String mode = rootElem.name;
  537. if (mode == "component" && editNode !is null)
  538. {
  539. // If this is the root node, do not allow to create duplicate scene-global components
  540. if (editNode is editorScene && CheckForExistingGlobalComponent(editNode, rootElem.GetAttribute("type")))
  541. return false;
  542. // If copied component was local, make the new local too
  543. Component@ newComponent = editNode.CreateComponent(rootElem.GetAttribute("type"), rootElem.GetBool("local") ? LOCAL :
  544. REPLICATED);
  545. if (newComponent is null)
  546. return false;
  547. newComponent.LoadXML(rootElem);
  548. newComponent.ApplyAttributes();
  549. // Create an undo action
  550. CreateComponentAction action;
  551. action.Define(newComponent);
  552. group.actions.Push(action);
  553. }
  554. else if (mode == "node")
  555. {
  556. // If copied node was local, make the new local too
  557. Node@ newNode;
  558. // Are we pasting into the root node?
  559. if (pasteRoot)
  560. newNode = editorScene.CreateChild("", rootElem.GetBool("local") ? LOCAL : REPLICATED);
  561. else
  562. {
  563. // If we are duplicating or have the original node selected, paste into the selected nodes parent
  564. if (duplication || editNode is null || editNode.id == rootElem.GetUInt("id"))
  565. {
  566. if (editNode !is null && editNode.parent !is null)
  567. newNode = editNode.parent.CreateChild("", rootElem.GetBool("local") ? LOCAL : REPLICATED);
  568. else
  569. newNode = editorScene.CreateChild("", rootElem.GetBool("local") ? LOCAL : REPLICATED);
  570. }
  571. // If we aren't duplicating, paste into the selected node
  572. else
  573. {
  574. newNode = editNode.CreateChild("", rootElem.GetBool("local") ? LOCAL : REPLICATED);
  575. }
  576. }
  577. newNode.LoadXML(rootElem);
  578. // Create an undo action
  579. CreateNodeAction action;
  580. action.Define(newNode);
  581. group.actions.Push(action);
  582. }
  583. }
  584. SaveEditActionGroup(group);
  585. SetSceneModified();
  586. return true;
  587. }
  588. bool SceneDuplicate()
  589. {
  590. Array<XMLFile@> copy = sceneCopyBuffer;
  591. if (!SceneCopy())
  592. {
  593. sceneCopyBuffer = copy;
  594. return false;
  595. }
  596. if (!ScenePaste(false, true))
  597. {
  598. sceneCopyBuffer = copy;
  599. return false;
  600. }
  601. sceneCopyBuffer = copy;
  602. return true;
  603. }
  604. bool SceneUnparent()
  605. {
  606. if (!CheckHierarchyWindowFocus() || !selectedComponents.empty || selectedNodes.empty)
  607. return false;
  608. ui.cursor.shape = CS_BUSY;
  609. // Group for storing undo actions
  610. EditActionGroup group;
  611. // Parent selected nodes to root
  612. Array<Node@> changedNodes;
  613. for (uint i = 0; i < selectedNodes.length; ++i)
  614. {
  615. Node@ sourceNode = selectedNodes[i];
  616. if (sourceNode.parent is null || sourceNode.parent is editorScene)
  617. continue; // Root or already parented to root
  618. // Perform the reparenting, continue loop even if action fails
  619. ReparentNodeAction action;
  620. action.Define(sourceNode, editorScene);
  621. group.actions.Push(action);
  622. SceneChangeParent(sourceNode, editorScene, false);
  623. changedNodes.Push(sourceNode);
  624. }
  625. // Reselect the changed nodes at their new position in the list
  626. for (uint i = 0; i < changedNodes.length; ++i)
  627. hierarchyList.AddSelection(GetListIndex(changedNodes[i]));
  628. SaveEditActionGroup(group);
  629. SetSceneModified();
  630. return true;
  631. }
  632. bool NodesParentToLastSelected()
  633. {
  634. if (lastSelectedNode.Get() is null)
  635. return false;
  636. if (!CheckHierarchyWindowFocus() || !selectedComponents.empty || selectedNodes.empty)
  637. return false;
  638. ui.cursor.shape = CS_BUSY;
  639. // Group for storing undo actions
  640. EditActionGroup group;
  641. // Parent selected nodes to root
  642. Array<Node@> changedNodes;
  643. // Find new parent node it selected last
  644. Node@ lastNode = lastSelectedNode.Get(); //GetListNode(hierarchyList.selection);
  645. for (uint i = 0; i < selectedNodes.length; ++i)
  646. {
  647. Node@ sourceNode = selectedNodes[i];
  648. if ( sourceNode.id == lastNode.id)
  649. continue; // Skip last node it is parent
  650. if (sourceNode.parent.id == lastNode.id)
  651. continue; // Root or already parented to root
  652. // Perform the reparenting, continue loop even if action fails
  653. ReparentNodeAction action;
  654. action.Define(sourceNode, lastNode);
  655. group.actions.Push(action);
  656. SceneChangeParent(sourceNode, lastNode, false);
  657. changedNodes.Push(sourceNode);
  658. }
  659. // Reselect the changed nodes at their new position in the list
  660. for (uint i = 0; i < changedNodes.length; ++i)
  661. hierarchyList.AddSelection(GetListIndex(changedNodes[i]));
  662. SaveEditActionGroup(group);
  663. SetSceneModified();
  664. return true;
  665. }
  666. bool SceneSmartDuplicateNode()
  667. {
  668. const float minOffset = 0.1;
  669. if (!CheckHierarchyWindowFocus() || !selectedComponents.empty
  670. || selectedNodes.empty || lastSelectedNode.Get() is null)
  671. return false;
  672. Node@ node = lastSelectedNode.Get();
  673. Node@ parent = node.parent;
  674. Vector3 offset = Vector3(1,0,0); // default offset
  675. if (parent is editorScene) // if parent of selected node is Scene make empty parent for it and place in same position;
  676. {
  677. parent = CreateNode(LOCAL);
  678. SceneChangeParent(parent, editorScene, false);
  679. parent.worldPosition = node.worldPosition;
  680. parent.name = node.name + "Group";
  681. node.name = parent.name + "Instance" + String(parent.numChildren);
  682. SceneChangeParent(node, parent, false);
  683. parent = node.parent;
  684. SelectNode(node, false);
  685. }
  686. Vector3 size;
  687. BoundingBox bb;
  688. // get bb for offset
  689. Drawable@ drawable = GetFirstDrawable(node);
  690. if (drawable !is null)
  691. {
  692. bb = drawable.boundingBox;
  693. size = bb.size * drawable.node.worldScale;
  694. offset = Vector3(size.x, 0, 0);
  695. }
  696. // make offset on axis that select user by mouse
  697. if (gizmoAxisX.selected)
  698. {
  699. if (size.x < minOffset) size.x = minOffset;
  700. offset = node.worldRotation * Vector3(size.x,0,0);
  701. }
  702. else if (gizmoAxisY.selected)
  703. {
  704. if (size.y < minOffset) size.y = minOffset;
  705. offset = node.worldRotation * Vector3(0,size.y,0);
  706. }
  707. else if (gizmoAxisZ.selected)
  708. {
  709. if (size.z < minOffset) size.z = minOffset;
  710. offset = node.worldRotation * Vector3(0,0,size.z);
  711. }
  712. else
  713. offset = lastOffsetForSmartDuplicate;
  714. Vector3 lastInstancePosition = node.worldPosition;
  715. SelectNode(node, false);
  716. SceneDuplicate();
  717. Node@ newInstance = parent.children[parent.numChildren-1];
  718. SelectNode(newInstance, false);
  719. newInstance.worldPosition = lastInstancePosition;
  720. newInstance.Translate(offset, TS_WORLD);
  721. newInstance.name = parent.name + "Instance" + String(parent.numChildren-1);
  722. lastOffsetForSmartDuplicate = offset;
  723. UpdateNodeAttributes();
  724. return true;
  725. }
  726. bool ViewCloser()
  727. {
  728. return (viewCloser = true);
  729. }
  730. bool SceneToggleEnable()
  731. {
  732. if (!CheckHierarchyWindowFocus())
  733. return false;
  734. ui.cursor.shape = CS_BUSY;
  735. EditActionGroup group;
  736. // Toggle enabled state of nodes recursively
  737. for (uint i = 0; i < selectedNodes.length; ++i)
  738. {
  739. // Do not attempt to disable the Scene
  740. if (selectedNodes[i].typeName == "Node")
  741. {
  742. bool oldEnabled = selectedNodes[i].enabled;
  743. selectedNodes[i].SetEnabledRecursive(!oldEnabled);
  744. // Create undo action
  745. ToggleNodeEnabledAction action;
  746. action.Define(selectedNodes[i], oldEnabled);
  747. group.actions.Push(action);
  748. }
  749. }
  750. for (uint i = 0; i < selectedComponents.length; ++i)
  751. {
  752. // Some components purposefully do not expose the Enabled attribute, and it does not affect them in any way
  753. // (Octree, PhysicsWorld). Check that the first attribute is in fact called "Is Enabled"
  754. if (selectedComponents[i].numAttributes > 0 && selectedComponents[i].attributeInfos[0].name == "Is Enabled")
  755. {
  756. bool oldEnabled = selectedComponents[i].enabled;
  757. selectedComponents[i].enabled = !oldEnabled;
  758. // Create undo action
  759. EditAttributeAction action;
  760. action.Define(selectedComponents[i], 0, Variant(oldEnabled));
  761. group.actions.Push(action);
  762. }
  763. }
  764. SaveEditActionGroup(group);
  765. SetSceneModified();
  766. return true;
  767. }
  768. bool SceneEnableAllNodes()
  769. {
  770. if (!CheckHierarchyWindowFocus())
  771. return false;
  772. ui.cursor.shape = CS_BUSY;
  773. EditActionGroup group;
  774. // Toggle enabled state of nodes recursively
  775. Array<Node@> allNodes;
  776. allNodes = editorScene.GetChildren(true);
  777. for (uint i = 0; i < allNodes.length; ++i)
  778. {
  779. // Do not attempt to disable the Scene
  780. if (allNodes[i].typeName == "Node")
  781. {
  782. bool oldEnabled = allNodes[i].enabled;
  783. if (oldEnabled == false)
  784. allNodes[i].SetEnabledRecursive(true);
  785. // Create undo action
  786. ToggleNodeEnabledAction action;
  787. action.Define(allNodes[i], oldEnabled);
  788. group.actions.Push(action);
  789. }
  790. }
  791. Array<Component@> allComponents;
  792. allComponents = editorScene.GetComponents();
  793. for (uint i = 0; i < allComponents.length; ++i)
  794. {
  795. // Some components purposefully do not expose the Enabled attribute, and it does not affect them in any way
  796. // (Octree, PhysicsWorld). Check that the first attribute is in fact called "Is Enabled"
  797. if (allComponents[i].numAttributes > 0 && allComponents[i].attributeInfos[0].name == "Is Enabled")
  798. {
  799. bool oldEnabled = allComponents[i].enabled;
  800. allComponents[i].enabled = true;
  801. // Create undo action
  802. EditAttributeAction action;
  803. action.Define(allComponents[i], 0, Variant(oldEnabled));
  804. group.actions.Push(action);
  805. }
  806. }
  807. SaveEditActionGroup(group);
  808. SetSceneModified();
  809. return true;
  810. }
  811. bool SceneChangeParent(Node@ sourceNode, Node@ targetNode, bool createUndoAction = true)
  812. {
  813. // Create undo action if requested
  814. if (createUndoAction)
  815. {
  816. ReparentNodeAction action;
  817. action.Define(sourceNode, targetNode);
  818. SaveEditAction(action);
  819. }
  820. sourceNode.parent = targetNode;
  821. SetSceneModified();
  822. // Return true if success
  823. if (sourceNode.parent is targetNode)
  824. {
  825. UpdateNodeAttributes(); // Parent change may have changed local transform
  826. return true;
  827. }
  828. else
  829. return false;
  830. }
  831. bool SceneChangeParent(Node@ sourceNode, Array<Node@> sourceNodes, Node@ targetNode, bool createUndoAction = true)
  832. {
  833. // Create undo action if requested
  834. if (createUndoAction)
  835. {
  836. ReparentNodeAction action;
  837. action.Define(sourceNodes, targetNode);
  838. SaveEditAction(action);
  839. }
  840. for (uint i = 0; i < sourceNodes.length; ++i)
  841. {
  842. Node@ node = sourceNodes[i];
  843. node.parent = targetNode;
  844. }
  845. SetSceneModified();
  846. // Return true if success
  847. if (sourceNode.parent is targetNode)
  848. {
  849. UpdateNodeAttributes(); // Parent change may have changed local transform
  850. return true;
  851. }
  852. else
  853. return false;
  854. }
  855. bool SceneResetPosition()
  856. {
  857. if (editNode !is null)
  858. {
  859. Transform oldTransform;
  860. oldTransform.Define(editNode);
  861. editNode.position = Vector3(0.0, 0.0, 0.0);
  862. // Create undo action
  863. EditNodeTransformAction action;
  864. action.Define(editNode, oldTransform);
  865. SaveEditAction(action);
  866. SetSceneModified();
  867. UpdateNodeAttributes();
  868. return true;
  869. }
  870. else
  871. return false;
  872. }
  873. bool SceneResetRotation()
  874. {
  875. if (editNode !is null)
  876. {
  877. Transform oldTransform;
  878. oldTransform.Define(editNode);
  879. editNode.rotation = Quaternion();
  880. // Create undo action
  881. EditNodeTransformAction action;
  882. action.Define(editNode, oldTransform);
  883. SaveEditAction(action);
  884. SetSceneModified();
  885. UpdateNodeAttributes();
  886. return true;
  887. }
  888. else
  889. return false;
  890. }
  891. bool SceneResetScale()
  892. {
  893. if (editNode !is null)
  894. {
  895. Transform oldTransform;
  896. oldTransform.Define(editNode);
  897. editNode.scale = Vector3(1.0, 1.0, 1.0);
  898. // Create undo action
  899. EditNodeTransformAction action;
  900. action.Define(editNode, oldTransform);
  901. SaveEditAction(action);
  902. SetSceneModified();
  903. UpdateNodeAttributes();
  904. return true;
  905. }
  906. else
  907. return false;
  908. }
  909. bool SceneResetTransform()
  910. {
  911. if (editNode !is null)
  912. {
  913. Transform oldTransform;
  914. oldTransform.Define(editNode);
  915. editNode.position = Vector3(0.0, 0.0, 0.0);
  916. editNode.rotation = Quaternion();
  917. editNode.scale = Vector3(1.0, 1.0, 1.0);
  918. // Create undo action
  919. EditNodeTransformAction action;
  920. action.Define(editNode, oldTransform);
  921. SaveEditAction(action);
  922. SetSceneModified();
  923. UpdateNodeAttributes();
  924. return true;
  925. }
  926. else
  927. return false;
  928. }
  929. bool SceneSelectAll()
  930. {
  931. BeginSelectionModify();
  932. Array<Node@> rootLevelNodes = editorScene.GetChildren();
  933. Array<uint> indices;
  934. for (uint i = 0; i < rootLevelNodes.length; ++i)
  935. indices.Push(GetListIndex(rootLevelNodes[i]));
  936. hierarchyList.SetSelections(indices);
  937. EndSelectionModify();
  938. return true;
  939. }
  940. bool SceneResetToDefault()
  941. {
  942. ui.cursor.shape = CS_BUSY;
  943. // Group for storing undo actions
  944. EditActionGroup group;
  945. // Reset selected component to their default
  946. if (!selectedComponents.empty)
  947. {
  948. for (uint i = 0; i < selectedComponents.length; ++i)
  949. {
  950. Component@ component = selectedComponents[i];
  951. ResetAttributesAction action;
  952. action.Define(component);
  953. group.actions.Push(action);
  954. component.ResetToDefault();
  955. component.ApplyAttributes();
  956. for (uint j = 0; j < component.numAttributes; ++j)
  957. PostEditAttribute(component, j);
  958. }
  959. }
  960. // OR reset selected nodes to their default
  961. else
  962. {
  963. for (uint i = 0; i < selectedNodes.length; ++i)
  964. {
  965. Node@ node = selectedNodes[i];
  966. ResetAttributesAction action;
  967. action.Define(node);
  968. group.actions.Push(action);
  969. node.ResetToDefault();
  970. node.ApplyAttributes();
  971. for (uint j = 0; j < node.numAttributes; ++j)
  972. PostEditAttribute(node, j);
  973. }
  974. }
  975. SaveEditActionGroup(group);
  976. SetSceneModified();
  977. attributesFullDirty = true;
  978. return true;
  979. }
  980. bool SceneRebuildNavigation()
  981. {
  982. ui.cursor.shape = CS_BUSY;
  983. Array<Component@>@ navMeshes = editorScene.GetComponents("NavigationMesh", true);
  984. if (navMeshes.empty)
  985. {
  986. @navMeshes = editorScene.GetComponents("DynamicNavigationMesh", true);
  987. if (navMeshes.empty)
  988. {
  989. MessageBox("No NavigationMesh components in the scene, nothing to rebuild.");
  990. return false;
  991. }
  992. }
  993. bool success = true;
  994. for (uint i = 0; i < navMeshes.length; ++i)
  995. {
  996. NavigationMesh@ navMesh = navMeshes[i];
  997. if (!navMesh.Build())
  998. success = false;
  999. }
  1000. return success;
  1001. }
  1002. bool SceneRenderZoneCubemaps()
  1003. {
  1004. bool success = false;
  1005. Array<Zone@> capturedThisCall;
  1006. bool alreadyCapturing = activeCubeCapture.length > 0; // May have managed to quickly queue up a second round of zones to render cubemaps for
  1007. for (int i = 0; i < selectedNodes.length; ++i)
  1008. {
  1009. Array<Component@>@ zones = selectedNodes[i].GetComponents("Zone", true);
  1010. for (int z = 0; z < zones.length; ++z)
  1011. {
  1012. Zone@ zone = cast<Zone>(zones[z]);
  1013. if (zone !is null)
  1014. {
  1015. activeCubeCapture.Push(EditorCubeCapture(zone));
  1016. capturedThisCall.Push(zone);
  1017. }
  1018. }
  1019. }
  1020. for (int i = 0; i < selectedComponents.length; ++i)
  1021. {
  1022. Zone@ zone = cast<Zone>(selectedComponents[i]);
  1023. if (zone !is null)
  1024. {
  1025. if (capturedThisCall.FindByRef(zone) < 0)
  1026. {
  1027. activeCubeCapture.Push(EditorCubeCapture(zone));
  1028. capturedThisCall.Push(zone);
  1029. }
  1030. }
  1031. }
  1032. // Start rendering cubemaps if there are any to render and the queue isn't already running
  1033. if (activeCubeCapture.length > 0 && !alreadyCapturing)
  1034. activeCubeCapture[0].Start();
  1035. if (capturedThisCall.length <= 0)
  1036. {
  1037. MessageBox("No zones selected to render cubemaps for/");
  1038. }
  1039. return capturedThisCall.length > 0;
  1040. }
  1041. bool SceneAddChildrenStaticModelGroup()
  1042. {
  1043. StaticModelGroup@ smg = cast<StaticModelGroup>(editComponents.length > 0 ? editComponents[0] : null);
  1044. if (smg is null && editNode !is null)
  1045. smg = editNode.GetComponent("StaticModelGroup");
  1046. if (smg is null)
  1047. {
  1048. MessageBox("Must have a StaticModelGroup component selected.");
  1049. return false;
  1050. }
  1051. uint attrIndex = GetAttributeIndex(smg, "Instance Nodes");
  1052. Variant oldValue = smg.attributes[attrIndex];
  1053. Array<Node@> children = smg.node.GetChildren(true);
  1054. for (uint i = 0; i < children.length; ++i)
  1055. smg.AddInstanceNode(children[i]);
  1056. EditAttributeAction action;
  1057. action.Define(smg, attrIndex, oldValue);
  1058. SaveEditAction(action);
  1059. SetSceneModified();
  1060. FocusComponent(smg);
  1061. return true;
  1062. }
  1063. bool SceneSetChildrenSplinePath(bool makeCycle)
  1064. {
  1065. SplinePath@ sp = cast<SplinePath>(editComponents.length > 0 ? editComponents[0] : null);
  1066. if (sp is null && editNode !is null)
  1067. sp = editNode.GetComponent("SplinePath");
  1068. if (sp is null)
  1069. {
  1070. MessageBox("Must have a SplinePath component selected.");
  1071. return false;
  1072. }
  1073. uint attrIndex = GetAttributeIndex(sp, "Control Points");
  1074. Variant oldValue = sp.attributes[attrIndex];
  1075. Array<Node@> children = sp.node.GetChildren(true);
  1076. if (children.length >= 2)
  1077. {
  1078. sp.ClearControlPoints();
  1079. for (uint i = 0; i < children.length; ++i)
  1080. sp.AddControlPoint(children[i]);
  1081. }
  1082. else
  1083. {
  1084. MessageBox("You must have a minimum two children Nodes in selected Node.");
  1085. return false;
  1086. }
  1087. if (makeCycle)
  1088. sp.AddControlPoint(children[0]);
  1089. EditAttributeAction action;
  1090. action.Define(sp, attrIndex, oldValue);
  1091. SaveEditAction(action);
  1092. SetSceneModified();
  1093. FocusComponent(sp);
  1094. return true;
  1095. }
  1096. void AssignMaterial(StaticModel@ model, String materialPath)
  1097. {
  1098. Material@ material = cache.GetResource("Material", materialPath);
  1099. if (material is null)
  1100. return;
  1101. ResourceRefList materials = model.GetAttribute("Material").GetResourceRefList();
  1102. Array<String> oldMaterials;
  1103. for(uint i = 0; i < materials.length; ++i)
  1104. oldMaterials.Push(materials.names[i]);
  1105. model.material = material;
  1106. AssignMaterialAction action;
  1107. action.Define(model, oldMaterials, material);
  1108. SaveEditAction(action);
  1109. SetSceneModified();
  1110. FocusComponent(model);
  1111. }
  1112. void UpdateSceneMru(String filename)
  1113. {
  1114. while (uiRecentScenes.Find(filename) > -1)
  1115. uiRecentScenes.Erase(uiRecentScenes.Find(filename));
  1116. uiRecentScenes.Insert(0, filename);
  1117. for (uint i = uiRecentScenes.length - 1; i >= maxRecentSceneCount; i--)
  1118. uiRecentScenes.Erase(i);
  1119. PopulateMruScenes();
  1120. }
  1121. Drawable@ GetFirstDrawable(Node@ node)
  1122. {
  1123. Array<Node@> nodes = node.GetChildren(true);
  1124. nodes.Insert(0, node);
  1125. for (uint i = 0; i < nodes.length; ++i)
  1126. {
  1127. Array<Component@> components = nodes[i].GetComponents();
  1128. for (uint j = 0; j < components.length; ++j)
  1129. {
  1130. Drawable@ drawable = cast<Drawable>(components[j]);
  1131. if (drawable !is null)
  1132. return drawable;
  1133. }
  1134. }
  1135. return null;
  1136. }
  1137. void AssignModel(StaticModel@ assignee, String modelPath)
  1138. {
  1139. Model@ model = cache.GetResource("Model", modelPath);
  1140. if (model is null)
  1141. return;
  1142. Model@ oldModel = assignee.model;
  1143. assignee.model = model;
  1144. AssignModelAction action;
  1145. action.Define(assignee, oldModel, model);
  1146. SaveEditAction(action);
  1147. SetSceneModified();
  1148. FocusComponent(assignee);
  1149. }
  1150. void CreateModelWithStaticModel(String filepath, Node@ parent)
  1151. {
  1152. if (parent is null)
  1153. return;
  1154. /// \todo should be able to specify the createmode
  1155. if (parent is editorScene)
  1156. parent = CreateNode(REPLICATED);
  1157. Model@ model = cache.GetResource("Model", filepath);
  1158. if (model is null)
  1159. return;
  1160. StaticModel@ staticModel = parent.GetOrCreateComponent("StaticModel");
  1161. staticModel.model = model;
  1162. if (applyMaterialList)
  1163. staticModel.ApplyMaterialList();
  1164. CreateLoadedComponent(staticModel);
  1165. }
  1166. void CreateModelWithAnimatedModel(String filepath, Node@ parent)
  1167. {
  1168. if (parent is null)
  1169. return;
  1170. /// \todo should be able to specify the createmode
  1171. if (parent is editorScene)
  1172. parent = CreateNode(REPLICATED);
  1173. Model@ model = cache.GetResource("Model", filepath);
  1174. if (model is null)
  1175. return;
  1176. AnimatedModel@ animatedModel = parent.GetOrCreateComponent("AnimatedModel");
  1177. animatedModel.model = model;
  1178. if (applyMaterialList)
  1179. animatedModel.ApplyMaterialList();
  1180. CreateLoadedComponent(animatedModel);
  1181. }
  1182. bool ColorWheelSetupBehaviorForColoring()
  1183. {
  1184. Menu@ menu = GetEventSender();
  1185. if (menu is null)
  1186. return false;
  1187. coloringPropertyName = menu.name;
  1188. if (coloringPropertyName == "menuCancel") return false;
  1189. if (coloringComponent.typeName == "Light")
  1190. {
  1191. Light@ light = cast<Light>(coloringComponent);
  1192. if (light !is null)
  1193. {
  1194. if (coloringPropertyName == "menuLightColor")
  1195. {
  1196. coloringOldColor = light.color;
  1197. ShowColorWheelWithColor(coloringOldColor);
  1198. }
  1199. else if (coloringPropertyName == "menuSpecularIntensity")
  1200. {
  1201. // ColorWheel have only 0-1 range output of V-value(BW), and for huge-range values we devide in and multiply out
  1202. float scaledSpecular = light.specularIntensity * 0.1f;
  1203. coloringOldScalar = scaledSpecular;
  1204. ShowColorWheelWithColor(Color(scaledSpecular,scaledSpecular,scaledSpecular));
  1205. }
  1206. else if (coloringPropertyName == "menuBrightnessMultiplier")
  1207. {
  1208. float scaledBrightness = light.brightness * 0.1f;
  1209. coloringOldScalar = scaledBrightness;
  1210. ShowColorWheelWithColor(Color(scaledBrightness,scaledBrightness,scaledBrightness));
  1211. }
  1212. }
  1213. }
  1214. else if (coloringComponent.typeName == "StaticModel")
  1215. {
  1216. StaticModel@ model = cast<StaticModel>(coloringComponent);
  1217. if (model !is null)
  1218. {
  1219. Material@ mat = model.materials[0];
  1220. if (mat !is null)
  1221. {
  1222. if (coloringPropertyName == "menuDiffuseColor")
  1223. {
  1224. Variant oldValue = mat.shaderParameters["MatDiffColor"];
  1225. Array<String> values = oldValue.ToString().Split(' ');
  1226. coloringOldColor = Color(values[0].ToFloat(),values[1].ToFloat(),values[2].ToFloat(),values[3].ToFloat()); //RGBA
  1227. ShowColorWheelWithColor(coloringOldColor);
  1228. }
  1229. else if (coloringPropertyName == "menuSpecularColor")
  1230. {
  1231. Variant oldValue = mat.shaderParameters["MatSpecColor"];
  1232. Array<String> values = oldValue.ToString().Split(' ');
  1233. coloringOldColor = Color(values[0].ToFloat(),values[1].ToFloat(),values[2].ToFloat());
  1234. coloringOldScalar = values[3].ToFloat();
  1235. ShowColorWheelWithColor(Color(coloringOldColor.r, coloringOldColor.g, coloringOldColor.b, coloringOldScalar/128.0f)); //RGB + shine
  1236. }
  1237. else if (coloringPropertyName == "menuEmissiveColor")
  1238. {
  1239. Variant oldValue = mat.shaderParameters["MatEmissiveColor"];
  1240. Array<String> values = oldValue.ToString().Split(' ');
  1241. coloringOldColor = Color(values[0].ToFloat(),values[1].ToFloat(),values[2].ToFloat()); // RGB
  1242. ShowColorWheelWithColor(coloringOldColor);
  1243. }
  1244. else if (coloringPropertyName == "menuEnvironmentMapColor")
  1245. {
  1246. Variant oldValue = mat.shaderParameters["MatEnvMapColor"];
  1247. Array<String> values = oldValue.ToString().Split(' ');
  1248. coloringOldColor = Color(values[0].ToFloat(),values[1].ToFloat(),values[2].ToFloat()); //RGB
  1249. ShowColorWheelWithColor(coloringOldColor);
  1250. }
  1251. }
  1252. }
  1253. }
  1254. else if (coloringComponent.typeName == "Zone")
  1255. {
  1256. Zone@ zone = cast<Zone>(coloringComponent);
  1257. if (zone !is null)
  1258. {
  1259. if (coloringPropertyName == "menuAmbientColor")
  1260. {
  1261. coloringOldColor = zone.ambientColor;
  1262. }
  1263. else if (coloringPropertyName == "menuFogColor")
  1264. {
  1265. coloringOldColor = zone.fogColor;
  1266. }
  1267. ShowColorWheelWithColor(coloringOldColor);
  1268. }
  1269. }
  1270. return true;
  1271. }