EditorScene.as 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547
  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, paste into the selected nodes parent
  564. if (duplication)
  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. CreateLoadedComponent(staticModel);
  1163. }
  1164. void CreateModelWithAnimatedModel(String filepath, Node@ parent)
  1165. {
  1166. if (parent is null)
  1167. return;
  1168. /// \todo should be able to specify the createmode
  1169. if (parent is editorScene)
  1170. parent = CreateNode(REPLICATED);
  1171. Model@ model = cache.GetResource("Model", filepath);
  1172. if (model is null)
  1173. return;
  1174. AnimatedModel@ animatedModel = parent.GetOrCreateComponent("AnimatedModel");
  1175. animatedModel.model = model;
  1176. CreateLoadedComponent(animatedModel);
  1177. }
  1178. bool ColorWheelSetupBehaviorForColoring()
  1179. {
  1180. Menu@ menu = GetEventSender();
  1181. if (menu is null)
  1182. return false;
  1183. coloringPropertyName = menu.name;
  1184. if (coloringPropertyName == "menuCancel") return false;
  1185. if (coloringComponent.typeName == "Light")
  1186. {
  1187. Light@ light = cast<Light>(coloringComponent);
  1188. if (light !is null)
  1189. {
  1190. if (coloringPropertyName == "menuLightColor")
  1191. {
  1192. coloringOldColor = light.color;
  1193. ShowColorWheelWithColor(coloringOldColor);
  1194. }
  1195. else if (coloringPropertyName == "menuSpecularIntensity")
  1196. {
  1197. // ColorWheel have only 0-1 range output of V-value(BW), and for huge-range values we devide in and multiply out
  1198. float scaledSpecular = light.specularIntensity * 0.1f;
  1199. coloringOldScalar = scaledSpecular;
  1200. ShowColorWheelWithColor(Color(scaledSpecular,scaledSpecular,scaledSpecular));
  1201. }
  1202. else if (coloringPropertyName == "menuBrightnessMultiplier")
  1203. {
  1204. float scaledBrightness = light.brightness * 0.1f;
  1205. coloringOldScalar = scaledBrightness;
  1206. ShowColorWheelWithColor(Color(scaledBrightness,scaledBrightness,scaledBrightness));
  1207. }
  1208. }
  1209. }
  1210. else if (coloringComponent.typeName == "StaticModel")
  1211. {
  1212. StaticModel@ model = cast<StaticModel>(coloringComponent);
  1213. if (model !is null)
  1214. {
  1215. Material@ mat = model.materials[0];
  1216. if (mat !is null)
  1217. {
  1218. if (coloringPropertyName == "menuDiffuseColor")
  1219. {
  1220. Variant oldValue = mat.shaderParameters["MatDiffColor"];
  1221. Array<String> values = oldValue.ToString().Split(' ');
  1222. coloringOldColor = Color(values[0].ToFloat(),values[1].ToFloat(),values[2].ToFloat(),values[3].ToFloat()); //RGBA
  1223. ShowColorWheelWithColor(coloringOldColor);
  1224. }
  1225. else if (coloringPropertyName == "menuSpecularColor")
  1226. {
  1227. Variant oldValue = mat.shaderParameters["MatSpecColor"];
  1228. Array<String> values = oldValue.ToString().Split(' ');
  1229. coloringOldColor = Color(values[0].ToFloat(),values[1].ToFloat(),values[2].ToFloat());
  1230. coloringOldScalar = values[3].ToFloat();
  1231. ShowColorWheelWithColor(Color(coloringOldColor.r, coloringOldColor.g, coloringOldColor.b, coloringOldScalar/128.0f)); //RGB + shine
  1232. }
  1233. else if (coloringPropertyName == "menuEmissiveColor")
  1234. {
  1235. Variant oldValue = mat.shaderParameters["MatEmissiveColor"];
  1236. Array<String> values = oldValue.ToString().Split(' ');
  1237. coloringOldColor = Color(values[0].ToFloat(),values[1].ToFloat(),values[2].ToFloat()); // RGB
  1238. ShowColorWheelWithColor(coloringOldColor);
  1239. }
  1240. else if (coloringPropertyName == "menuEnvironmentMapColor")
  1241. {
  1242. Variant oldValue = mat.shaderParameters["MatEnvMapColor"];
  1243. Array<String> values = oldValue.ToString().Split(' ');
  1244. coloringOldColor = Color(values[0].ToFloat(),values[1].ToFloat(),values[2].ToFloat()); //RGB
  1245. ShowColorWheelWithColor(coloringOldColor);
  1246. }
  1247. }
  1248. }
  1249. }
  1250. else if (coloringComponent.typeName == "Zone")
  1251. {
  1252. Zone@ zone = cast<Zone>(coloringComponent);
  1253. if (zone !is null)
  1254. {
  1255. if (coloringPropertyName == "menuAmbientColor")
  1256. {
  1257. coloringOldColor = zone.ambientColor;
  1258. }
  1259. else if (coloringPropertyName == "menuFogColor")
  1260. {
  1261. coloringOldColor = zone.fogColor;
  1262. }
  1263. ShowColorWheelWithColor(coloringOldColor);
  1264. }
  1265. }
  1266. return true;
  1267. }