Browse Source

Merge remote-tracking branch 'monkeyfirst/hotkeys-smg-instances'

Conflicts:
	bin/Data/EditorStrings.json
Lasse Öörni 10 years ago
parent
commit
50013c85d4

+ 2 - 0
Docs/GettingStarted.dox

@@ -790,6 +790,8 @@ Z                  - Cycle through solid, wireframe and point rendering
 M                  - Show/Hide LayerEditor
 F                  - Focus on selected object (LookAt)               
 X                  - Delete node or component
+Alt+D              - Smart Duplicate (note: select one of axises on gizmo to show direction for next instance)
+Key "." or Del     - View Closer selected node(s)  
 \endverbatim
 
 Press right mouse button in the 3D view if you want to defocus the active window without changing the object selection.

+ 6 - 0
Source/Urho3D/Scene/Node.cpp

@@ -289,6 +289,12 @@ void Node::SetScale(float scale)
 
 void Node::SetScale(const Vector3& scale)
 {
+    if (Urho3D::IsNaN(scale.x_) || Urho3D::IsNaN(scale.y_) || Urho3D::IsNaN(scale.z_))
+    {
+        LOGWARNING("Attempt to set NaN node scale " + scale.ToString() + ", disregarding");
+        return;
+    }
+
     scale_ = scale;
     MarkDirty();
 

+ 8 - 2
bin/Data/EditorStrings.json

@@ -854,7 +854,13 @@
 	"Renderer":{
 		"en":"Renderer",
 		"ru":"Рендерер"
+	},
+	"Please, use only nodes with one StaticModel for instansing":{
+		"en":"Please, use only nodes with one StaticModel for instansing",
+		"ru":"Пожалуйста, используйте только ноду с одной статической моделью для инстансинга"
+	},
+	"  CameraFlyMode: ":{
+		"en":"  CameraFlyMode: ",
+		"ru":"  Камера в режиме полета: "
 	}
 }
-
-	

+ 22 - 3
bin/Data/Scripts/Editor/EditorHierarchyWindow.as

@@ -496,7 +496,7 @@ void SelectNode(Node@ node, bool multiselect)
         hierarchyList.ClearSelection();
         return;
     }
-
+    
     lastSelectedNode = node;
     uint index = GetListIndex(node);
     uint numItems = hierarchyList.numItems;
@@ -626,7 +626,7 @@ void HandleHierarchyListSelectionChange()
         else if (type == ITEM_NODE)
         {
             Node@ node = GetListNode(index);
-            if (node !is null)
+            if (node !is null) 
                 selectedNodes.Push(node);
         }
         else if (type == ITEM_UI_ELEMENT)
@@ -636,7 +636,7 @@ void HandleHierarchyListSelectionChange()
                 selectedUIElements.Push(element);
         }
     }
-
+    
     // If only one node/UIElement selected, use it for editing
     if (selectedNodes.length == 1)
         editNode = selectedNodes[0];
@@ -1530,6 +1530,20 @@ bool Paste()
     return false;
 }
 
+bool BlenderModeDelete() 
+{
+    // In this place maybe placed avoidance flags that not allow delete in some cases
+    
+    Array<UIElement@> actions;
+    actions.Push(CreateContextMenuItem("Delete?", "HandleBlenderModeDelete"));
+    if (actions.length > 0) {
+        ActivateContextMenu(actions);
+        return true;
+    }
+
+    return false;
+}
+
 bool Delete()
 {
     if (CheckHierarchyWindowFocus())
@@ -1667,6 +1681,11 @@ void HandleHierarchyContextDelete()
     Delete();
 }
 
+void HandleBlenderModeDelete() 
+{
+    Delete();
+}
+
 void HandleHierarchyContextPaste()
 {
     Paste();

+ 4 - 2
bin/Data/Scripts/Editor/EditorLayers.as

@@ -47,10 +47,12 @@ void CreateLayerEditor()
 bool ShowLayerEditor()
 {
     // avoid to show layer window when we type text in LineEdit
-    if (ui.focusElement !is null && ui.focusElement.type == lineEditType) return false;
+    if (ui.focusElement !is null && ui.focusElement.type == lineEditType && lastSelectedNode.Get() is null) 
+        return false;
     
     // to avoid when we close dialog with selected other node
-    patternMaskNode = lastSelectedNode;
+    Node@ node = lastSelectedNode.Get(); 
+    patternMaskNode = node;
     
     // just change position if already opened
     if ( layerWindow.visible == true )

+ 81 - 3
bin/Data/Scripts/Editor/EditorScene.as

@@ -18,7 +18,6 @@ CreateMode instantiateMode = REPLICATED;
 bool sceneModified = false;
 bool runUpdate = false;
 
-Node@ lastSelectedNode;
 Array<Node@> selectedNodes;
 Array<Component@> selectedComponents;
 Node@ editNode;
@@ -38,6 +37,8 @@ uint undoStackPos = 0;
 bool revertOnPause = false;
 XMLFile@ revertData;
 
+Vector3 lastOffsetForSmartDuplicate;
+
 void ClearSceneSelection()
 {
     selectedNodes.Clear();
@@ -774,7 +775,7 @@ bool SceneUnparent()
 
 bool NodesParentToLastSelected()
 {
-    if (lastSelectedNode is null)
+    if (lastSelectedNode.Get() is null)
         return false;
         
     if (!CheckHierarchyWindowFocus() || !selectedComponents.empty || selectedNodes.empty)
@@ -789,7 +790,7 @@ bool NodesParentToLastSelected()
     Array<Node@> changedNodes;
     
     // Find new parent node it selected last
-    Node@ lastNode = lastSelectedNode;
+    Node@ lastNode = lastSelectedNode.Get(); //GetListNode(hierarchyList.selection);
     
     for (uint i = 0; i < selectedNodes.length; ++i)
     {
@@ -820,6 +821,83 @@ bool NodesParentToLastSelected()
     return true;
 }
 
+bool SceneSmartDuplicateNode() 
+{       
+    const float minOffset = 0.1;
+    
+    if (!CheckHierarchyWindowFocus() || !selectedComponents.empty 
+        || selectedNodes.empty || lastSelectedNode.Get() is null)
+        return false;
+    
+    
+    Node@ node = lastSelectedNode.Get();
+    Node@ parent = node.parent;
+    Vector3 offset = Vector3(1,0,0); // default offset
+    
+    if (parent is editorScene) // if parent of selected node is Scene make empty parent for it and place in same position; 
+    {
+        parent = CreateNode(LOCAL);
+        SceneChangeParent(parent, editorScene, false);
+        parent.worldPosition = node.worldPosition;
+        parent.name = node.name + "Group";
+        node.name = parent.name + "Instance" + String(parent.numChildren);
+        SceneChangeParent(node, parent, false);
+        parent = node.parent;
+        SelectNode(node, false);
+    } 
+    
+    Vector3 size;
+    BoundingBox bb;
+    
+    // get bb for offset  
+    Drawable@ drawable = GetFirstDrawable(node);
+    if (drawable !is null) 
+    {
+        bb = drawable.boundingBox;
+        size =  bb.size * drawable.node.worldScale;
+        offset = Vector3(size.x, 0, 0); 
+    } 
+    
+    // make offset on axis that select user by mouse
+    if (gizmoAxisX.selected)
+    {
+        if (size.x < minOffset) size.x = minOffset;
+        offset = node.worldRotation * Vector3(size.x,0,0);
+    }
+    else if (gizmoAxisY.selected)
+    {
+        if (size.y < minOffset) size.y = minOffset;
+        offset = node.worldRotation * Vector3(0,size.y,0);
+    }
+    else if (gizmoAxisZ.selected)
+    {
+        if (size.z < minOffset) size.z = minOffset;
+        offset = node.worldRotation * Vector3(0,0,size.z);
+    }
+    else
+        offset = lastOffsetForSmartDuplicate;    
+    
+    Vector3 lastInstancePosition = node.worldPosition;
+    
+    SelectNode(node, false);
+    SceneDuplicate();
+    Node@ newInstance = parent.children[parent.numChildren-1];
+    SelectNode(newInstance, false);
+    newInstance.worldPosition = lastInstancePosition;
+    newInstance.Translate(offset, TS_WORLD);
+    newInstance.name = parent.name + "Instance" + String(parent.numChildren-1);
+    
+    lastOffsetForSmartDuplicate = offset;
+    UpdateNodeAttributes();
+    return true;
+}
+
+bool ViewCloser()
+{
+    return (viewCloser = true);
+}
+
+
 bool SceneToggleEnable()
 {
     if (!CheckHierarchyWindowFocus())

+ 24 - 10
bin/Data/Scripts/Editor/EditorUI.as

@@ -336,7 +336,7 @@ void CreateMenuBar()
         if ( hotKeyMode == HOTKEYS_MODE_STANDARD )
             popup.AddChild(CreateMenuItem("Delete", @Delete, KEY_DELETE, QUAL_ANY));
         else if ( hotKeyMode == HOTKEYS_MODE_BLENDER )
-            popup.AddChild(CreateMenuItem("Delete", @Delete, 'X', QUAL_ANY));
+            popup.AddChild(CreateMenuItem("Delete", @BlenderModeDelete, 'X', QUAL_ANY));
         
         popup.AddChild(CreateMenuItem("Select all", @SelectAll, 'A', QUAL_CTRL));
         popup.AddChild(CreateMenuItem("Deselect all", @DeselectAll, 'A', QUAL_SHIFT | QUAL_CTRL));
@@ -386,8 +386,14 @@ void CreateMenuBar()
         //else if ( hotKeyMode == HOT_KEYS_MODE_BLENDER )
         //    popup.AddChild(CreateMenuItem("Toggle update", @ToggleSceneUpdate, 'P', QUAL_CTRL));
         
-        if ( hotKeyMode == HOTKEYS_MODE_BLENDER )
+        if ( hotKeyMode == HOTKEYS_MODE_BLENDER ) 
+        {
              popup.AddChild(CreateMenuItem("Move to layer", @ShowLayerMover, 'M'));
+             popup.AddChild(CreateMenuItem("Smart Duplicate", @SceneSmartDuplicateNode, 'D', QUAL_ALT));
+             popup.AddChild(CreateMenuItem("View closer", @ViewCloser, KEY_KP_PERIOD));                     
+        }
+        
+        CreateChildDivider(popup);
         
         popup.AddChild(CreateMenuItem("Stop test animation", @StopTestAnimation));
         CreateChildDivider(popup);
@@ -1255,6 +1261,7 @@ void HandleHotKeysBlender( VariantMap& eventData )
     }
     else if (key == KEY_KP_5 && ui.focusElement is null)
     {
+        activeViewport.camera.zoom = 1;
         activeViewport.ToggleOrthographic();
     }
     else if (key == '4')
@@ -1334,13 +1341,20 @@ void HandleHotKeysBlender( VariantMap& eventData )
                 }
                 else if (key == KEY_F) 
                 {
-                    Vector3 center = Vector3(0,0,0);
-                    
-                    if (selectedNodes.length > 0)
-                        center = SelectedNodesCenterPoint(); 
-                    
-                    cameraNode.LookAt(center);
-                    ReacquireCameraYawPitch(); 
+                    if (camera.orthographic) 
+                    {
+                        viewCloser = true;
+                    }
+                    else
+                    {
+                        Vector3 center = Vector3(0,0,0);
+                        
+                        if (selectedNodes.length > 0)
+                            center = SelectedNodesCenterPoint(); 
+                        
+                        cameraNode.LookAt(center);
+                        ReacquireCameraYawPitch();
+                    } 
                 }
          }  
     }
@@ -1496,7 +1510,7 @@ void HandleKeyDown(StringHash eventType, VariantMap& eventData)
 }
 
 void UnfadeUI()
-{
+{    
     FadeUI(false);
 }
 

+ 110 - 17
bin/Data/Scripts/Editor/EditorView.as

@@ -22,7 +22,10 @@ bool contextMenuActionWaitFrame = false;
 bool cameraFlyMode = true;
 int hotKeyMode = 0; // used for checking that kind of style manipulation user are prefer ( see HotKeysMode )
 Vector3 lastSelectedNodesCenterPoint = Vector3(0,0,0); // for Blender mode to avoid own origin rotation when no nodes are selected. preserve last center for this
-
+WeakHandle lastSelectedNode = null;
+WeakHandle lastSelectedDrawable = null;
+WeakHandle lastSelectedComponent = null;
+bool viewCloser = false;
 
 const uint VIEWPORT_BORDER_H     = 0x00000001;
 const uint VIEWPORT_BORDER_H1    = 0x00000002;
@@ -1137,7 +1140,7 @@ void UpdateStats(float timeStep)
     String adding = "";
     // Todo: add localization
     if (hotKeyMode == HOTKEYS_MODE_BLENDER)
-       adding = "  CameraFlyMode: " + (cameraFlyMode ? "True" : "False");
+        adding = localization.Get("  CameraFlyMode: ") + (cameraFlyMode ? "True" : "False");
     
     editorModeText.text = String(
         localization.Get("Mode: ") + localization.Get(editModeText[editMode]) +
@@ -1278,7 +1281,7 @@ void UpdateView(float timeStep)
             if (mouseWheelCameraPosition && !camera.orthographic )
             {   
                 if (input.keyDown[KEY_LSHIFT])
-                    cameraNode.Translate(Vector3(0, -cameraBaseSpeed, 0) * -input.mouseMoveWheel*5* timeStep * speedMultiplier);
+                    cameraNode.Translate(Vector3(0, -cameraBaseSpeed, 0) * -input.mouseMoveWheel*20* timeStep * speedMultiplier);
                 else if (input.keyDown[KEY_LCTRL])
                     cameraNode.Translate(Vector3(-cameraBaseSpeed,0, 0) * -input.mouseMoveWheel*20 * timeStep * speedMultiplier);
                 else
@@ -1286,21 +1289,30 @@ void UpdateView(float timeStep)
             }
             else
             {   
-                if (input.keyDown[KEY_LSHIFT])
-                    cameraNode.Translate(Vector3(0, -cameraBaseSpeed, 0) * -input.mouseMoveWheel*5* timeStep * speedMultiplier);
-                else if (input.keyDown[KEY_LCTRL])
+                if (input.keyDown[KEY_LSHIFT]) 
+                {
+                    cameraNode.Translate(Vector3(0, -cameraBaseSpeed, 0) * -input.mouseMoveWheel*20* timeStep * speedMultiplier);
+                }
+                else if (input.keyDown[KEY_LCTRL]) 
+                {
                     cameraNode.Translate(Vector3(-cameraBaseSpeed,0, 0) * -input.mouseMoveWheel*20 * timeStep * speedMultiplier);
+                }
                 else 
                 {
-                    float zoom = camera.zoom + -input.mouseMoveWheel *.1 * speedMultiplier;
-                    camera.zoom = Clamp(zoom, .1, 30);
+                    if (input.qualifierDown[QUAL_ALT]) 
+                    {
+                        float zoom = camera.zoom + -input.mouseMoveWheel *.1 * speedMultiplier;
+                        camera.zoom = Clamp(zoom, .1, 30);
+                    }
+                    else 
+                    {
+                        cameraNode.Translate(Vector3(0, 0, -cameraBaseSpeed) * -input.mouseMoveWheel*20 * timeStep * speedMultiplier);
+                    }    
                 }
             }
-        }
-        
+        }       
     }
 
-
     if (input.keyDown[KEY_HOME])
     {
         if (selectedNodes.length > 0 || selectedComponents.length > 0)
@@ -1333,14 +1345,24 @@ void UpdateView(float timeStep)
         if (mouseMove.x != 0 || mouseMove.y != 0)
         {
             bool panTheCamera = false;
+            
             if(mmbPanMode || (hotKeyMode == HOTKEYS_MODE_BLENDER))
                 if ( hotKeyMode == HOTKEYS_MODE_STANDARD) 
                     panTheCamera = !(changeCamViewButton && input.keyDown[KEY_LSHIFT]);
-                else if (hotKeyMode == HOTKEYS_MODE_BLENDER && cameraFlyMode == true )
+                else if (hotKeyMode == HOTKEYS_MODE_BLENDER && cameraFlyMode) 
+                {
                     panTheCamera = false;
-            else
-                panTheCamera = (changeCamViewButton && input.keyDown[KEY_LSHIFT]);
-
+                    //else if (camera.orthographic)
+                    //    panTheCamera = true;     
+                }
+            else 
+            {
+                if (!camera.orthographic)
+                    panTheCamera = changeCamViewButton && input.keyDown[KEY_LSHIFT];
+                else
+                    panTheCamera = changeCamViewButton && !input.keyDown[KEY_LSHIFT];
+            }
+                
             if (panTheCamera)
                 cameraNode.Translate(Vector3(-mouseMove.x, mouseMove.y, 0) * timeStep * cameraBaseSpeed * 0.5);
             else
@@ -1388,8 +1410,59 @@ void UpdateView(float timeStep)
 
     if (orbiting && !input.mouseButtonDown[MOUSEB_MIDDLE])
         orbiting = false;
-
+        
+    if ( hotKeyMode == HOTKEYS_MODE_BLENDER )
+    if ( viewCloser && lastSelectedDrawable.Get() !is null) 
+    {
+        SetMouseLock();
+        BoundingBox bb;
+        Vector3 centerPoint;
+        
+        if ( selectedNodes.length <= 1 )
+        {
+            Drawable@ drawable = lastSelectedDrawable.Get();
+            if (drawable !is null) 
+            {  
+                bb = drawable.boundingBox;
+                centerPoint = drawable.node.worldPosition;
+            }
+        }
+        else 
+        {
+            for (int i = 0; i < selectedNodes.length; i++) 
+            {
+                bb.Merge(selectedNodes[i].position);
+            }
+                  
+            centerPoint = SelectedNodesCenterPoint();
+        }
+        
+        float distance = bb.size.length;
+        if (camera.orthographic) // if we use viewCloser for 2D get current distance to avoid near clip
+            distance = cameraNode.worldPosition.length;
+        
+        Quaternion q = Quaternion(activeViewport.cameraPitch, activeViewport.cameraYaw, 0);
+        cameraNode.rotation = q;
+        cameraNode.worldPosition = centerPoint -  cameraNode.worldDirection * distance;
+        // ReacquireCameraYawPitch();
+        viewCloser =  false;
+    }
+    else 
+        viewCloser =  false;
+    
     // Move/rotate/scale object
+    if ( hotKeyMode == HOTKEYS_MODE_BLENDER) // force to select component node for manipulation if selected only component and not his node
+    {   
+        if ((editMode != EDIT_SELECT && editNodes.empty) && lastSelectedComponent.Get() !is null )
+        {   
+            if (lastSelectedComponent.Get() !is null) 
+            {
+                Component@ component  = lastSelectedComponent.Get();
+                SelectNode(component.node, false);
+            }
+        }   
+    }
+    
     if (!editNodes.empty && editMode != EDIT_SELECT && input.keyDown[KEY_LCTRL])
     {
         Vector3 adjust(0, 0, 0);
@@ -1683,9 +1756,29 @@ void ViewRaycast(bool mouseClick)
 
         RayQueryResult result = editorScene.octree.RaycastSingle(cameraRay, RAY_TRIANGLE, camera.farClip,
             pickModeDrawableFlags[pickMode], 0x7fffffff);
+        
         if (result.drawable !is null)
-        {
+        {            
             Drawable@ drawable = result.drawable;
+            
+            // for actual last selected node or component in both modes
+            if ( hotKeyMode == HOTKEYS_MODE_STANDARD ) {
+                if (input.mouseButtonDown[MOUSEB_LEFT]) 
+                {
+                    lastSelectedNode = drawable.node;
+                    lastSelectedDrawable = drawable;
+                    lastSelectedComponent = drawable;
+                }
+            }
+            else if ( hotKeyMode == HOTKEYS_MODE_BLENDER ) {
+                if (input.mouseButtonDown[MOUSEB_RIGHT]) 
+                {
+                    lastSelectedNode = drawable.node;
+                    lastSelectedDrawable = drawable;
+                    lastSelectedComponent = drawable;
+                }
+            }
+             
             // If selecting a terrain patch, select the parent terrain instead
             if (drawable.typeName != "TerrainPatch")
             {