| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047 |
- /// Urho3D editor scene handling
- #include "Scripts/Editor/EditorHierarchyWindow.as"
- #include "Scripts/Editor/EditorInspectorWindow.as"
- const int PICK_GEOMETRIES = 0;
- const int PICK_LIGHTS = 1;
- const int PICK_ZONES = 2;
- const int PICK_RIGIDBODIES = 3;
- const int PICK_UI_ELEMENTS = 4;
- const int MAX_PICK_MODES = 5;
- const int MAX_UNDOSTACK_SIZE = 256;
- Scene@ editorScene;
- String instantiateFileName;
- CreateMode instantiateMode = REPLICATED;
- bool sceneModified = false;
- bool runUpdate = false;
- Array<Node@> selectedNodes;
- Array<Component@> selectedComponents;
- Node@ editNode;
- Array<Node@> editNodes;
- Array<Component@> editComponents;
- uint numEditableComponentsPerNode = 1;
- Array<XMLFile@> sceneCopyBuffer;
- bool suppressSceneChanges = false;
- bool inSelectionModify = false;
- bool skipMruScene = false;
- Array<EditActionGroup> undoStack;
- uint undoStackPos = 0;
- bool revertOnPause = false;
- XMLFile@ revertData;
- void ClearSceneSelection()
- {
- selectedNodes.Clear();
- selectedComponents.Clear();
- editNode = null;
- editNodes.Clear();
- editComponents.Clear();
- numEditableComponentsPerNode = 1;
- HideGizmo();
- }
- void CreateScene()
- {
- // Create a scene only once here
- editorScene = Scene();
- // Allow access to the scene from the console
- script.defaultScene = editorScene;
- // Always pause the scene, and do updates manually
- editorScene.updateEnabled = false;
- }
- bool ResetScene()
- {
- ui.cursor.shape = CS_BUSY;
- if (messageBoxCallback is null && sceneModified)
- {
- MessageBox@ messageBox = MessageBox("Scene has been modified.\nContinue to reset?", "Warning");
- if (messageBox.window !is null)
- {
- Button@ cancelButton = messageBox.window.GetChild("CancelButton", true);
- cancelButton.visible = true;
- cancelButton.focus = true;
- SubscribeToEvent(messageBox, "MessageACK", "HandleMessageAcknowledgement");
- messageBoxCallback = @ResetScene;
- return false;
- }
- }
- else
- messageBoxCallback = null;
- suppressSceneChanges = true;
- // Create a scene with default values, these will be overridden when loading scenes
- editorScene.Clear();
- editorScene.CreateComponent("Octree");
- editorScene.CreateComponent("DebugRenderer");
- // Release resources that became unused after the scene clear
- cache.ReleaseAllResources(false);
- sceneModified = false;
- revertData = null;
- StopSceneUpdate();
- UpdateWindowTitle();
- UpdateHierarchyItem(editorScene, true);
- ClearEditActions();
- suppressSceneChanges = false;
- ResetCamera();
- CreateGizmo();
- CreateGrid();
- SetActiveViewport(viewports[0]);
- return true;
- }
- void SetResourcePath(String newPath, bool usePreferredDir = true, bool additive = false)
- {
- if (newPath.empty)
- return;
- if (usePreferredDir)
- newPath = AddTrailingSlash(cache.GetPreferredResourceDir(newPath));
- else
- newPath = AddTrailingSlash(newPath);
- if (newPath == sceneResourcePath)
- return;
- // Remove the old scene resource path if any. However make sure that the default data paths do not get removed
- if (!additive)
- {
- cache.ReleaseAllResources(false);
- renderer.ReloadShaders();
- String check = AddTrailingSlash(sceneResourcePath);
- bool isDefaultResourcePath = check.Compare(fileSystem.programDir + "Data/", false) == 0 ||
- check.Compare(fileSystem.programDir + "CoreData/", false) == 0;
- if (!sceneResourcePath.empty && !isDefaultResourcePath)
- cache.RemoveResourceDir(sceneResourcePath);
- }
- // Add resource path as first priority so that it takes precedence over the default data paths
- cache.AddResourceDir(newPath, 0);
- RebuildResourceDatabase();
- if (!additive)
- {
- sceneResourcePath = newPath;
- uiScenePath = GetResourceSubPath(newPath, "Scenes");
- uiElementPath = GetResourceSubPath(newPath, "UI");
- uiNodePath = GetResourceSubPath(newPath, "Objects");
- uiScriptPath = GetResourceSubPath(newPath, "Scripts");
- uiParticlePath = GetResourceSubPath(newPath, "Particle");
- }
- }
- String GetResourceSubPath(String basePath, const String&in subPath)
- {
- basePath = AddTrailingSlash(basePath);
- if (fileSystem.DirExists(basePath + subPath))
- return AddTrailingSlash(basePath + subPath);
- else
- return basePath;
- }
- bool LoadScene(const String&in fileName)
- {
- if (fileName.empty)
- return false;
- ui.cursor.shape = CS_BUSY;
- // Always load the scene from the filesystem, not from resource paths
- if (!fileSystem.FileExists(fileName))
- {
- MessageBox("No such scene.\n" + fileName);
- return false;
- }
- File file(fileName, FILE_READ);
- if (!file.open)
- {
- MessageBox("Could not open file.\n" + fileName);
- return false;
- }
- // Add the scene's resource path in case it's necessary
- String newScenePath = GetPath(fileName);
- if (!rememberResourcePath || !sceneResourcePath.StartsWith(newScenePath, false))
- SetResourcePath(newScenePath);
- suppressSceneChanges = true;
- sceneModified = false;
- revertData = null;
- StopSceneUpdate();
- String extension = GetExtension(fileName);
- bool loaded;
- if (extension != ".xml")
- loaded = editorScene.Load(file);
- else
- loaded = editorScene.LoadXML(file);
- // Release resources which are not used by the new scene
- cache.ReleaseAllResources(false);
- // Always pause the scene, and do updates manually
- editorScene.updateEnabled = false;
- UpdateWindowTitle();
- UpdateHierarchyItem(editorScene, true);
- ClearEditActions();
- suppressSceneChanges = false;
- // global variable to mostly bypass adding mru upon importing tempscene
- if (!skipMruScene)
- UpdateSceneMru(fileName);
- skipMruScene = false;
- ResetCamera();
- CreateGizmo();
- CreateGrid();
- SetActiveViewport(viewports[0]);
- return loaded;
- }
- bool SaveScene(const String&in fileName)
- {
- if (fileName.empty)
- return false;
- ui.cursor.shape = CS_BUSY;
- // Unpause when saving so that the scene will work properly when loaded outside the editor
- editorScene.updateEnabled = true;
- MakeBackup(fileName);
- File file(fileName, FILE_WRITE);
- String extension = GetExtension(fileName);
- bool success = (extension != ".xml" ? editorScene.Save(file) : editorScene.SaveXML(file));
- RemoveBackup(success, fileName);
- editorScene.updateEnabled = false;
- if (success)
- {
- UpdateSceneMru(fileName);
- sceneModified = false;
- UpdateWindowTitle();
- }
- else
- MessageBox("Could not save scene successfully!\nSee Urho3D.log for more detail.");
- return success;
- }
- bool SaveSceneWithExistingName()
- {
- if (editorScene.fileName.empty || editorScene.fileName == TEMP_SCENE_NAME)
- return PickFile();
- else
- return SaveScene(editorScene.fileName);
- }
- Node@ CreateNode(CreateMode mode)
- {
- Node@ newNode = null;
- if (editNode !is null)
- newNode = editNode.CreateChild("", mode);
- else
- newNode = editorScene.CreateChild("", mode);
- // Set the new node a certain distance from the camera
- newNode.position = GetNewNodePosition();
- // Create an undo action for the create
- CreateNodeAction action;
- action.Define(newNode);
- SaveEditAction(action);
- SetSceneModified();
- FocusNode(newNode);
- return newNode;
- }
- void CreateComponent(const String&in componentType)
- {
- // If this is the root node, do not allow to create duplicate scene-global components
- if (editNode is editorScene && CheckForExistingGlobalComponent(editNode, componentType))
- return;
- // Group for storing undo actions
- EditActionGroup group;
- // For now, make a local node's all components local
- /// \todo Allow to specify the createmode
- for (uint i = 0; i < editNodes.length; ++i)
- {
- Component@ newComponent = editNodes[i].CreateComponent(componentType, editNodes[i].id < FIRST_LOCAL_ID ? REPLICATED : LOCAL);
- if (newComponent !is null)
- {
- // Some components such as CollisionShape do not create their internal object before the first call to ApplyAttributes()
- // to prevent unnecessary initialization with default values. Call now
- newComponent.ApplyAttributes();
- CreateComponentAction action;
- action.Define(newComponent);
- group.actions.Push(action);
- }
- }
- SaveEditActionGroup(group);
- SetSceneModified();
- // Although the edit nodes selection are not changed, call to ensure attribute inspector notices new components of the edit nodes
- HandleHierarchyListSelectionChange();
- }
- void CreateLoadedComponent(Component@ component)
- {
- if (component is null) return;
- CreateComponentAction action;
- action.Define(component);
- SaveEditAction(action);
- SetSceneModified();
- FocusComponent(component);
- }
- Node@ LoadNode(const String&in fileName, Node@ parent = null)
- {
- if (fileName.empty)
- return null;
- if (!fileSystem.FileExists(fileName))
- {
- MessageBox("No such node file.\n" + fileName);
- return null;
- }
- File file(fileName, FILE_READ);
- if (!file.open)
- {
- MessageBox("Could not open file.\n" + fileName);
- return null;
- }
- ui.cursor.shape = CS_BUSY;
- // Before instantiating, add object's resource path if necessary
- SetResourcePath(GetPath(fileName), true, true);
- Ray cameraRay = camera.GetScreenRay(0.5, 0.5); // Get ray at view center
- Vector3 position, normal;
- GetSpawnPosition(cameraRay, newNodeDistance, position, normal, 0, true);
- Node@ newNode = InstantiateNodeFromFile(file, position, Quaternion(), 1, parent, instantiateMode);
- if (newNode !is null)
- {
- FocusNode(newNode);
- instantiateFileName = fileName;
- }
- return newNode;
- }
- Node@ InstantiateNodeFromFile(File@ file, const Vector3& position, const Quaternion& rotation, float scaleMod = 1.0f, Node@ parent = null, CreateMode mode = REPLICATED)
- {
- if (file is null)
- return null;
- Node@ newNode;
- uint numSceneComponent = editorScene.numComponents;
- suppressSceneChanges = true;
- String extension = GetExtension(file.name);
- if (extension != ".xml")
- newNode = editorScene.Instantiate(file, position, rotation, mode);
- else
- newNode = editorScene.InstantiateXML(file, position, rotation, mode);
- suppressSceneChanges = false;
- if (parent !is null)
- newNode.parent = parent;
-
- if (newNode !is null)
- {
- newNode.scale = newNode.scale * scaleMod;
- if (alignToAABBBottom)
- {
- Drawable@ drawable = GetFirstDrawable(newNode);
- if (drawable !is null)
- {
- BoundingBox aabb = drawable.worldBoundingBox;
- Vector3 aabbBottomCenter(aabb.center.x, aabb.min.y, aabb.center.z);
- Vector3 offset = aabbBottomCenter - newNode.worldPosition;
- newNode.worldPosition = newNode.worldPosition - offset;
- }
- }
- // Create an undo action for the load
- CreateNodeAction action;
- action.Define(newNode);
- SaveEditAction(action);
- SetSceneModified();
- if (numSceneComponent != editorScene.numComponents)
- UpdateHierarchyItem(editorScene);
- else
- UpdateHierarchyItem(newNode);
- }
- return newNode;
- }
- bool SaveNode(const String&in fileName)
- {
- if (fileName.empty)
- return false;
- ui.cursor.shape = CS_BUSY;
- MakeBackup(fileName);
- File file(fileName, FILE_WRITE);
- if (!file.open)
- {
- MessageBox("Could not open file.\n" + fileName);
- return false;
- }
- String extension = GetExtension(fileName);
- bool success = (extension != ".xml" ? editNode.Save(file) : editNode.SaveXML(file));
- RemoveBackup(success, fileName);
- if (success)
- instantiateFileName = fileName;
- else
- MessageBox("Could not save node successfully!\nSee Urho3D.log for more detail.");
- return success;
- }
- void UpdateScene(float timeStep)
- {
- if (runUpdate)
- editorScene.Update(timeStep);
- }
- void StopSceneUpdate()
- {
- runUpdate = false;
- audio.Stop();
- toolBarDirty = true;
- // If scene should revert on update stop, load saved data now
- if (revertOnPause && revertData !is null)
- {
- suppressSceneChanges = true;
- editorScene.Clear();
- editorScene.LoadXML(revertData.GetRoot());
- UpdateHierarchyItem(editorScene, true);
- ClearEditActions();
- suppressSceneChanges = false;
- }
- revertData = null;
- }
- void StartSceneUpdate()
- {
- runUpdate = true;
- // Run audio playback only when scene is updating, so that audio components' time-dependent attributes stay constant when
- // paused (similar to physics)
- audio.Play();
- toolBarDirty = true;
- // Save scene data for reverting if enabled
- if (revertOnPause)
- {
- revertData = XMLFile();
- XMLElement root = revertData.CreateRoot("scene");
- editorScene.SaveXML(root);
- }
- else
- revertData = null;
- }
- bool ToggleSceneUpdate()
- {
- if (!runUpdate)
- StartSceneUpdate();
- else
- StopSceneUpdate();
- return true;
- }
- void SetSceneModified()
- {
- if (!sceneModified)
- {
- sceneModified = true;
- UpdateWindowTitle();
- }
- }
- bool SceneDelete()
- {
- ui.cursor.shape = CS_BUSY;
- BeginSelectionModify();
- // Clear the selection now to prevent repopulation of selectedNodes and selectedComponents combo
- hierarchyList.ClearSelection();
- // Group for storing undo actions
- EditActionGroup group;
- // Remove nodes
- for (uint i = 0; i < selectedNodes.length; ++i)
- {
- Node@ node = selectedNodes[i];
- if (node.parent is null || node.scene is null)
- continue; // Root or already deleted
- uint nodeIndex = GetListIndex(node);
- // Create undo action
- DeleteNodeAction action;
- action.Define(node);
- group.actions.Push(action);
- node.Remove();
- SetSceneModified();
- // If deleting only one node, select the next item in the same index
- if (selectedNodes.length == 1 && selectedComponents.empty)
- hierarchyList.selection = nodeIndex;
- }
- // Then remove components, if they still remain
- for (uint i = 0; i < selectedComponents.length; ++i)
- {
- Component@ component = selectedComponents[i];
- Node@ node = component.node;
- if (node is null)
- continue; // Already deleted
- uint index = GetComponentListIndex(component);
- uint nodeIndex = GetListIndex(node);
- if (index == NO_ITEM || nodeIndex == NO_ITEM)
- continue;
- // Do not allow to remove the Octree, DebugRenderer or MaterialCache2D or DrawableProxy2D from the root node
- if (node is editorScene && (component.typeName == "Octree" || component.typeName == "DebugRenderer" ||
- component.typeName == "MaterialCache2D" || component.typeName == "DrawableProxy2D"))
- continue;
- // Create undo action
- DeleteComponentAction action;
- action.Define(component);
- group.actions.Push(action);
- node.RemoveComponent(component);
- SetSceneModified();
- // If deleting only one component, select the next item in the same index
- if (selectedComponents.length == 1 && selectedNodes.empty)
- hierarchyList.selection = index;
- }
- SaveEditActionGroup(group);
- EndSelectionModify();
- return true;
- }
- bool SceneCut()
- {
- return SceneCopy() && SceneDelete();
- }
- bool SceneCopy()
- {
- ui.cursor.shape = CS_BUSY;
- sceneCopyBuffer.Clear();
- // Copy components
- if (!selectedComponents.empty)
- {
- for (uint i = 0; i < selectedComponents.length; ++i)
- {
- XMLFile@ xml = XMLFile();
- XMLElement rootElem = xml.CreateRoot("component");
- selectedComponents[i].SaveXML(rootElem);
- rootElem.SetBool("local", selectedComponents[i].id >= FIRST_LOCAL_ID);
- sceneCopyBuffer.Push(xml);
- }
- }
- // Copy nodes.
- else
- {
- for (uint i = 0; i < selectedNodes.length; ++i)
- {
- // Skip the root scene node as it cannot be copied
- if (selectedNodes[i] is editorScene)
- continue;
- XMLFile@ xml = XMLFile();
- XMLElement rootElem = xml.CreateRoot("node");
- selectedNodes[i].SaveXML(rootElem);
- rootElem.SetBool("local", selectedNodes[i].id >= FIRST_LOCAL_ID);
- sceneCopyBuffer.Push(xml);
- }
- }
- return true;
- }
- bool ScenePaste()
- {
- ui.cursor.shape = CS_BUSY;
- // Group for storing undo actions
- EditActionGroup group;
- for (uint i = 0; i < sceneCopyBuffer.length; ++i)
- {
- XMLElement rootElem = sceneCopyBuffer[i].root;
- String mode = rootElem.name;
- if (mode == "component")
- {
- // If this is the root node, do not allow to create duplicate scene-global components
- if (editNode is editorScene && CheckForExistingGlobalComponent(editNode, rootElem.GetAttribute("type")))
- return false;
- // If copied component was local, make the new local too
- Component@ newComponent = editNode.CreateComponent(rootElem.GetAttribute("type"), rootElem.GetBool("local") ? LOCAL :
- REPLICATED);
- if (newComponent is null)
- return false;
- newComponent.LoadXML(rootElem);
- newComponent.ApplyAttributes();
- // Create an undo action
- CreateComponentAction action;
- action.Define(newComponent);
- group.actions.Push(action);
- }
- else if (mode == "node")
- {
- // Make the paste go always to the root node, no matter of the selected node
- // If copied node was local, make the new local too
- Node@ newNode = editorScene.CreateChild("", rootElem.GetBool("local") ? LOCAL : REPLICATED);
- newNode.LoadXML(rootElem);
- // Create an undo action
- CreateNodeAction action;
- action.Define(newNode);
- group.actions.Push(action);
- }
- }
- SaveEditActionGroup(group);
- SetSceneModified();
- return true;
- }
- bool SceneUnparent()
- {
- if (!CheckHierarchyWindowFocus() || !selectedComponents.empty || selectedNodes.empty)
- return false;
- ui.cursor.shape = CS_BUSY;
- // Group for storing undo actions
- EditActionGroup group;
- // Parent selected nodes to root
- Array<Node@> changedNodes;
- for (uint i = 0; i < selectedNodes.length; ++i)
- {
- Node@ sourceNode = selectedNodes[i];
- if (sourceNode.parent is null || sourceNode.parent is editorScene)
- continue; // Root or already parented to root
- // Perform the reparenting, continue loop even if action fails
- ReparentNodeAction action;
- action.Define(sourceNode, editorScene);
- group.actions.Push(action);
- SceneChangeParent(sourceNode, editorScene, false);
- changedNodes.Push(sourceNode);
- }
- // Reselect the changed nodes at their new position in the list
- for (uint i = 0; i < changedNodes.length; ++i)
- hierarchyList.AddSelection(GetListIndex(changedNodes[i]));
- SaveEditActionGroup(group);
- SetSceneModified();
- return true;
- }
- bool SceneToggleEnable()
- {
- if (!CheckHierarchyWindowFocus())
- return false;
- ui.cursor.shape = CS_BUSY;
- EditActionGroup group;
- // Toggle enabled state of nodes recursively
- for (uint i = 0; i < selectedNodes.length; ++i)
- {
- // Do not attempt to disable the Scene
- if (selectedNodes[i].typeName == "Node")
- {
- bool oldEnabled = selectedNodes[i].enabled;
- selectedNodes[i].SetEnabledRecursive(!oldEnabled);
- // Create undo action
- ToggleNodeEnabledAction action;
- action.Define(selectedNodes[i], oldEnabled);
- group.actions.Push(action);
- }
- }
- for (uint i = 0; i < selectedComponents.length; ++i)
- {
- // Some components purposefully do not expose the Enabled attribute, and it does not affect them in any way
- // (Octree, PhysicsWorld). Check that the first attribute is in fact called "Is Enabled"
- if (selectedComponents[i].numAttributes > 0 && selectedComponents[i].attributeInfos[0].name == "Is Enabled")
- {
- bool oldEnabled = selectedComponents[i].enabled;
- selectedComponents[i].enabled = !oldEnabled;
- // Create undo action
- EditAttributeAction action;
- action.Define(selectedComponents[i], 0, Variant(oldEnabled));
- group.actions.Push(action);
- }
- }
- SaveEditActionGroup(group);
- SetSceneModified();
- return true;
- }
- bool SceneChangeParent(Node@ sourceNode, Node@ targetNode, bool createUndoAction = true)
- {
- // Create undo action if requested
- if (createUndoAction)
- {
- ReparentNodeAction action;
- action.Define(sourceNode, targetNode);
- SaveEditAction(action);
- }
- sourceNode.parent = targetNode;
- SetSceneModified();
- // Return true if success
- if (sourceNode.parent is targetNode)
- {
- UpdateNodeAttributes(); // Parent change may have changed local transform
- return true;
- }
- else
- return false;
- }
- bool SceneChangeParent(Node@ sourceNode, Array<Node@> sourceNodes, Node@ targetNode, bool createUndoAction = true)
- {
- // Create undo action if requested
- if (createUndoAction)
- {
- ReparentNodeAction action;
- action.Define(sourceNodes, targetNode);
- SaveEditAction(action);
- }
- for (uint i = 0; i < sourceNodes.length; ++i)
- {
- Node@ node = sourceNodes[i];
- node.parent = targetNode;
- }
- SetSceneModified();
- // Return true if success
- if (sourceNode.parent is targetNode)
- {
- UpdateNodeAttributes(); // Parent change may have changed local transform
- return true;
- }
- else
- return false;
- }
- bool SceneResetPosition()
- {
- if (editNode !is null)
- {
- Transform oldTransform;
- oldTransform.Define(editNode);
- editNode.position = Vector3(0.0, 0.0, 0.0);
- // Create undo action
- EditNodeTransformAction action;
- action.Define(editNode, oldTransform);
- SaveEditAction(action);
- SetSceneModified();
- UpdateNodeAttributes();
- return true;
- }
- else
- return false;
- }
- bool SceneResetRotation()
- {
- if (editNode !is null)
- {
- Transform oldTransform;
- oldTransform.Define(editNode);
- editNode.rotation = Quaternion();
- // Create undo action
- EditNodeTransformAction action;
- action.Define(editNode, oldTransform);
- SaveEditAction(action);
- SetSceneModified();
- UpdateNodeAttributes();
- return true;
- }
- else
- return false;
- }
- bool SceneResetScale()
- {
- if (editNode !is null)
- {
- Transform oldTransform;
- oldTransform.Define(editNode);
- editNode.scale = Vector3(1.0, 1.0, 1.0);
- // Create undo action
- EditNodeTransformAction action;
- action.Define(editNode, oldTransform);
- SaveEditAction(action);
- SetSceneModified();
- UpdateNodeAttributes();
- return true;
- }
- else
- return false;
- }
- bool SceneSelectAll()
- {
- BeginSelectionModify();
- Array<Node@> rootLevelNodes = editorScene.GetChildren();
- Array<uint> indices;
- for (uint i = 0; i < rootLevelNodes.length; ++i)
- indices.Push(GetListIndex(rootLevelNodes[i]));
- hierarchyList.SetSelections(indices);
- EndSelectionModify();
- return true;
- }
- bool SceneResetToDefault()
- {
- ui.cursor.shape = CS_BUSY;
- // Group for storing undo actions
- EditActionGroup group;
- // Reset selected component to their default
- if (!selectedComponents.empty)
- {
- for (uint i = 0; i < selectedComponents.length; ++i)
- {
- Component@ component = selectedComponents[i];
- ResetAttributesAction action;
- action.Define(component);
- group.actions.Push(action);
- component.ResetToDefault();
- component.ApplyAttributes();
- for (uint j = 0; j < component.numAttributes; ++j)
- PostEditAttribute(component, j);
- }
- }
- // OR reset selected nodes to their default
- else
- {
- for (uint i = 0; i < selectedNodes.length; ++i)
- {
- Node@ node = selectedNodes[i];
- ResetAttributesAction action;
- action.Define(node);
- group.actions.Push(action);
- node.ResetToDefault();
- node.ApplyAttributes();
- for (uint j = 0; j < node.numAttributes; ++j)
- PostEditAttribute(node, j);
- }
- }
- SaveEditActionGroup(group);
- SetSceneModified();
- attributesFullDirty = true;
- return true;
- }
- bool SceneRebuildNavigation()
- {
- ui.cursor.shape = CS_BUSY;
- Array<Component@>@ navMeshes = editorScene.GetComponents("NavigationMesh", true);
- if (navMeshes.empty)
- {
- MessageBox("No NavigationMesh components in the scene, nothing to rebuild.");
- return false;
- }
- bool success = true;
- for (uint i = 0; i < navMeshes.length; ++i)
- {
- NavigationMesh@ navMesh = navMeshes[i];
- if (!navMesh.Build())
- success = false;
- }
- return success;
- }
- void AssignMaterial(StaticModel@ model, String materialPath)
- {
- Material@ material = cache.GetResource("Material", materialPath);
- if (material is null)
- return;
- ResourceRefList materials = model.GetAttribute("Material").GetResourceRefList();
- Array<String> oldMaterials;
- for(uint i = 0; i < materials.length; ++i)
- oldMaterials.Push(materials.names[i]);
- model.material = material;
- AssignMaterialAction action;
- action.Define(model, oldMaterials, material);
- SaveEditAction(action);
- SetSceneModified();
- FocusComponent(model);
- }
- void UpdateSceneMru(String filename)
- {
- while (uiRecentScenes.Find(filename) > -1)
- uiRecentScenes.Erase(uiRecentScenes.Find(filename));
- uiRecentScenes.Insert(0, filename);
- for (uint i = uiRecentScenes.length - 1; i >= maxRecentSceneCount; i--)
- uiRecentScenes.Erase(i);
- PopulateMruScenes();
- }
- Drawable@ GetFirstDrawable(Node@ node)
- {
- Array<Node@> nodes = node.GetChildren(true);
- nodes.Insert(0, node);
- for (uint i = 0; i < nodes.length; ++i)
- {
- Array<Component@> components = nodes[i].GetComponents();
- for (uint j = 0; j < components.length; ++j)
- {
- Drawable@ drawable = cast<Drawable>(components[j]);
- if (drawable !is null)
- return drawable;
- }
- }
-
- return null;
- }
- void AssignModel(StaticModel@ assignee, String modelPath)
- {
- Model@ model = cache.GetResource("Model", modelPath);
- if (model is null)
- return;
- Model@ oldModel = assignee.model;
- assignee.model = model;
- AssignModelAction action;
- action.Define(assignee, oldModel, model);
- SaveEditAction(action);
- SetSceneModified();
- FocusComponent(assignee);
- }
- void CreateModelWithStaticModel(String filepath, Node@ parent)
- {
- if (parent is null)
- return;
- Model@ model = cache.GetResource("Model", filepath);
- if (model is null)
- return;
- StaticModel@ staticModel = cast<StaticModel>(editNode.CreateComponent("StaticModel"));
- staticModel.model = model;
- CreateLoadedComponent(staticModel);
- }
- void CreateModelWithAnimatedModel(String filepath, Node@ parent)
- {
- if (parent is null)
- return;
- Model@ model = cache.GetResource("Model", filepath);
- if (model is null)
- return;
- AnimatedModel@ animatedModel = cast<StaticModel>(editNode.CreateComponent("AnimatedModel"));
- animatedModel.model = model;
- CreateLoadedComponent(animatedModel);
- }
|