Эх сурвалжийг харах

Merge pull request #431 from AtomicGameEngine/JME-ATOMIC-314

Selection framing, orbit, zoom, additional camera translation and hotkeys
JoshEngebretson 10 жил өмнө
parent
commit
3d46d0fe1a

+ 20 - 4
Script/AtomicEditor/ui/MainToolbar.ts

@@ -12,6 +12,7 @@ class MainToolbar extends Atomic.UIWidget {
     translateButton: Atomic.UIButton;
     rotateButton: Atomic.UIButton;
     scaleButton: Atomic.UIButton;
+    axisButton: Atomic.UIButton;
 
     constructor(parent: Atomic.UIWidget) {
 
@@ -23,15 +24,32 @@ class MainToolbar extends Atomic.UIWidget {
         this.rotateButton = <Atomic.UIButton>this.getWidget("3d_rotate");
         this.scaleButton = <Atomic.UIButton>this.getWidget("3d_scale");
 
+        this.axisButton = <Atomic.UIButton>this.getWidget("3d_axismode");
+
         this.translateButton.value = 1;
 
         parent.addChild(this);
 
+        this.subscribeToEvent("GizmoAxisModeChanged", (ev) => this.handleGizmoAxisModeChanged(ev));
         this.subscribeToEvent("GizmoEditModeChanged", (ev) => this.handleGizmoEditModeChanged(ev));
         this.subscribeToEvent(this, "WidgetEvent", (data) => this.handleWidgetEvent(data));
     }
 
-    handleGizmoEditModeChanged(ev) {
+    handleGizmoAxisModeChanged(ev: Editor.GizmoAxisModeChangedEvent) {
+
+        if (ev.toggle) return;
+
+        if (ev.mode == Editor.AXIS_WORLD) {
+            this.axisButton.value = 1;
+            this.axisButton.text = "World";
+        } else {
+            this.axisButton.value = 0;
+            this.axisButton.text = "Local";
+        }
+
+    }
+
+    handleGizmoEditModeChanged(ev: Editor.GizmoEditModeChangedEvent) {
 
         this.translateButton.value = 0;
         this.rotateButton.value = 0;
@@ -69,9 +87,7 @@ class MainToolbar extends Atomic.UIWidget {
 
             } else if (ev.target.id == "3d_axismode") {
 
-                ev.target.text = ev.target.value ? "World" : "Local";
-
-                EditorUI.getShortcuts().invokeGizmoAxisModeChanged( ev.target.value ? Editor.AXIS_WORLD :  Editor.AXIS_LOCAL);
+                EditorUI.getShortcuts().invokeGizmoAxisModeChanged(ev.target.value ? Editor.AXIS_WORLD : Editor.AXIS_LOCAL);
                 return true;
 
             } else if (ev.target.id == "maintoolbar_play") {

+ 4 - 2
Script/AtomicEditor/ui/Shortcuts.ts

@@ -86,9 +86,9 @@ class Shortcuts extends Atomic.ScriptObject {
 
     }
 
-    invokeGizmoAxisModeChanged(mode:Editor.AxisMode) {
+    invokeGizmoAxisModeChanged(mode:Editor.AxisMode, toggle:boolean = false) {
 
-        this.sendEvent("GizmoAxisModeChanged", { mode: mode });
+        this.sendEvent("GizmoAxisModeChanged", { mode: mode, toggle: toggle });
 
     }
 
@@ -113,6 +113,8 @@ class Shortcuts extends Atomic.ScriptObject {
               this.invokeGizmoEditModeChanged(Editor.EDIT_ROTATE);
             } else if (ev.key == Atomic.KEY_R) {
                 this.invokeGizmoEditModeChanged(Editor.EDIT_SCALE);
+            } else if (ev.key == Atomic.KEY_X) {
+                this.invokeGizmoAxisModeChanged(Editor.AXIS_WORLD, true);
             }
 
         }

+ 1 - 0
Script/TypeScript/AtomicWork.d.ts

@@ -255,6 +255,7 @@ declare module Editor {
 
   export interface GizmoAxisModeChangedEvent {
     mode:AxisMode;
+    toggle:boolean;
   }
 
 }

+ 2 - 0
Source/AtomicEditor/Editors/SceneEditor3D/Gizmo3D.h

@@ -110,6 +110,8 @@ public:
     void SetView(SceneView3D* view3D);
 
     void SetAxisMode(AxisMode mode);
+    AxisMode GetAxisMode() const { return axisMode_; }
+
     void SetEditMode(EditMode mode);
 
     bool Selected()

+ 41 - 4
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditor3D.cpp

@@ -260,15 +260,24 @@ void SceneEditor3D::HandlePlayStopped(StringHash eventType, VariantMap& eventDat
 }
 
 void SceneEditor3D::HandleGizmoEditModeChanged(StringHash eventType, VariantMap& eventData)
-{
-    EditMode mode = (EditMode) ((int)eventData[GizmoEditModeChanged::P_MODE].GetFloat());
+{    
+    EditMode mode = (EditMode) (eventData[GizmoEditModeChanged::P_MODE].GetInt());
     gizmo3D_->SetEditMode(mode);
 }
 
 void SceneEditor3D::HandleGizmoAxisModeChanged(StringHash eventType, VariantMap& eventData)
 {
-    AxisMode mode = (AxisMode) ((int)eventData[GizmoEditModeChanged::P_MODE].GetFloat());
-    gizmo3D_->SetAxisMode(mode);
+    AxisMode mode = (AxisMode) (eventData[GizmoAxisModeChanged::P_MODE].GetInt());
+    bool toggle = eventData[GizmoAxisModeChanged::P_TOGGLE].GetBool();
+    if (toggle)
+    {
+        AxisMode mode = gizmo3D_->GetAxisMode() == AXIS_WORLD ? AXIS_LOCAL : AXIS_WORLD;
+        VariantMap neventData;
+        neventData[GizmoAxisModeChanged::P_MODE] = (int) mode;
+        SendEvent(E_GIZMOAXISMODECHANGED, neventData);
+    }
+    else
+        gizmo3D_->SetAxisMode(mode);
 }
 
 
@@ -313,4 +322,32 @@ void SceneEditor3D::HandleSceneEditSceneModified(StringHash eventType, VariantMa
     SetModified(true);    
 }
 
+void SceneEditor3D::GetSelectionBoundingBox(BoundingBox& bbox)
+{
+    bbox.Clear();
+
+    if (selectedNode_.Null())
+        return;
+
+    // TODO: Adjust once multiple selection is in
+    if (selectedNode_.Null())
+        return;
+
+    // Get all the drawables, which define the bounding box of the selection
+    PODVector<Drawable*> drawables;
+    selectedNode_->GetDerivedComponents<Drawable>(drawables, true);
+
+    if (!drawables.Size())
+        return;
+
+    // Calculate the combined bounding box of all drawables
+    for (unsigned i = 0; i < drawables.Size(); i++  )
+    {
+        Drawable* drawable = drawables[i];
+        bbox.Merge(drawable->GetWorldBoundingBox());
+    }
+
+
+}
+
 }

+ 1 - 0
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditor3D.h

@@ -45,6 +45,7 @@ public:
     bool OnEvent(const TBWidgetEvent &ev);
 
     void SelectNode(Node* node);
+    void GetSelectionBoundingBox(BoundingBox& bbox);
 
     Scene* GetScene() { return scene_; }
     Gizmo3D* GetGizmo() { return gizmo3D_; }

+ 4 - 2
Source/AtomicEditor/Editors/SceneEditor3D/SceneEditor3DEvents.h

@@ -15,12 +15,14 @@ namespace AtomicEditor
 /// Variable timestep scene update.
 EVENT(E_GIZMOEDITMODECHANGED, GizmoEditModeChanged)
 {
-    PARAM(P_MODE, MODE);            // int
+    PARAM(P_MODE, Mode);            // int
 }
 
 EVENT(E_GIZMOAXISMODECHANGED, GizmoAxisModeChanged)
 {
-    PARAM(P_MODE, MODE);            // int
+    PARAM(P_MODE, Mode);            // int
+    PARAM(P_TOGGLE, Toggle);            // bool
+
 }
 
 EVENT(E_GIZMOMOVED, GizmoMoved)

+ 110 - 14
Source/AtomicEditor/Editors/SceneEditor3D/SceneView3D.cpp

@@ -57,7 +57,8 @@ SceneView3D ::SceneView3D(Context* context, SceneEditor3D *sceneEditor) :
     pitch_(0.0f),
     mouseLeftDown_(false),
     mouseMoved_(false),
-    enabled_(true)
+    enabled_(true),
+    cameraMove_(false)
 {
 
     sceneEditor_ = sceneEditor;
@@ -140,25 +141,44 @@ void SceneView3D::Disable()
 
 }
 
-void SceneView3D::MoveCamera(float timeStep)
+bool SceneView3D::GetOrbitting()
 {
+    Input* input = GetSubsystem<Input>();
+    return framedNode_.NotNull() && MouseInView() && input->GetKeyDown(KEY_ALT) && input->GetMouseButtonDown(MOUSEB_LEFT);
+}
+
+bool SceneView3D::GetZooming()
+{
+    Input* input = GetSubsystem<Input>();
+    return MouseInView() && input->GetKeyDown(KEY_ALT) && input->GetMouseMoveWheel();
+}
+
+
+void SceneView3D::MoveCamera(float timeStep)
+{    
     if (!enabled_ && !GetFocus())
         return;
 
     Input* input = GetSubsystem<Input>();
+    bool shiftDown = false;
+    if (input->GetKeyDown(KEY_LSHIFT) || input->GetKeyDown(KEY_RSHIFT))
+        shiftDown = true;
+
+    bool mouseInView = MouseInView();
+    bool orbitting = GetOrbitting();
+    bool zooming = GetZooming();
 
     // Movement speed as world units per second
     float MOVE_SPEED = 20.0f;
     // Mouse sensitivity as degrees per pixel
     const float MOUSE_SENSITIVITY = 0.2f;
 
-    if (input->GetKeyDown(KEY_LSHIFT) || input->GetKeyDown(KEY_RSHIFT))
+    if (shiftDown)
         MOVE_SPEED *= 3.0f;
 
     // Use this frame's mouse motion to adjust camera node yaw and pitch. Clamp the pitch between -90 and 90 degrees
-    if (input->GetMouseButtonDown(MOUSEB_RIGHT))
+    if ((mouseInView && input->GetMouseButtonDown(MOUSEB_RIGHT)) || orbitting)
     {
-
         SetFocus();
         IntVector2 mouseMove = input->GetMouseMove();
         yaw_ += MOUSE_SENSITIVITY * mouseMove.x_;
@@ -167,7 +187,32 @@ void SceneView3D::MoveCamera(float timeStep)
     }
 
     // Construct new orientation for the camera scene node from yaw and pitch. Roll is fixed to zero
-    cameraNode_->SetRotation(Quaternion(pitch_, yaw_, 0.0f));
+    Quaternion q(pitch_, yaw_, 0.0f);
+
+    if (!zooming)
+        cameraNode_->SetRotation(q);
+
+    if (orbitting)
+    {
+        BoundingBox bbox;
+        sceneEditor_->GetSelectionBoundingBox(bbox);
+        if (bbox.defined_)
+        {
+            Vector3 centerPoint = bbox.Center();
+            Vector3 d = cameraNode_->GetWorldPosition() - centerPoint;
+            cameraNode_->SetWorldPosition(centerPoint - q * Vector3(0.0, 0.0, d.Length()));
+
+        }
+    }
+
+    if (zooming)
+    {
+        Ray ray = GetCameraRay();
+        Vector3 wpos = cameraNode_->GetWorldPosition();
+        wpos += ray.direction_ * (float (input->GetMouseMoveWheel()) * (shiftDown ? 0.6f : 0.2f));
+        cameraNode_->SetWorldPosition(wpos);
+    }
+
 
 #ifdef ATOMIC_PLATFORM_WINDOWS
     bool superdown = input->GetKeyDown(KEY_LCTRL) || input->GetKeyDown(KEY_RCTRL);
@@ -175,29 +220,61 @@ void SceneView3D::MoveCamera(float timeStep)
     bool superdown = input->GetKeyDown(KEY_LGUI) || input->GetKeyDown(KEY_RGUI);
 #endif
 
-    if (!superdown && input->GetMouseButtonDown(MOUSEB_RIGHT)) {
+    if (!orbitting && mouseInView && !superdown && input->GetMouseButtonDown(MOUSEB_RIGHT)) {
 
         // Read WASD keys and move the camera scene node to the corresponding direction if they are pressed
         // Use the Translate() function (default local space) to move relative to the node's orientation.
-        if (input->GetKeyDown('W'))
+        if (input->GetKeyDown(KEY_W))
         {
             SetFocus();
             cameraNode_->Translate(Vector3::FORWARD * MOVE_SPEED * timeStep);
         }
-        if (input->GetKeyDown('S'))
+        if (input->GetKeyDown(KEY_S))
         {
             SetFocus();
             cameraNode_->Translate(Vector3::BACK * MOVE_SPEED * timeStep);
         }
-        if (input->GetKeyDown('A'))
+        if (input->GetKeyDown(KEY_A))
         {   SetFocus();
             cameraNode_->Translate(Vector3::LEFT * MOVE_SPEED * timeStep);
         }
-        if (input->GetKeyDown('D'))
+        if (input->GetKeyDown(KEY_D))
         {
             SetFocus();
             cameraNode_->Translate(Vector3::RIGHT * MOVE_SPEED * timeStep);
         }
+        if (input->GetKeyDown(KEY_Q))
+        {
+            SetFocus();
+            cameraNode_->Translate(Vector3::UP * MOVE_SPEED * timeStep);
+        }
+        if (input->GetKeyDown(KEY_E))
+        {
+            SetFocus();
+            cameraNode_->Translate(Vector3::DOWN * MOVE_SPEED * timeStep);
+        }
+    }
+    else if (!superdown)
+    {
+        if (input->GetKeyPress(KEY_F))
+        {
+            FrameSelection();
+        }
+    }
+
+    if (cameraMove_)
+    {
+
+        cameraMoveTime_ += timeStep * 3.0f;
+
+        if (cameraMoveTime_ > 1.0f)
+        {
+            cameraMove_ = false;
+            cameraMoveTime_ = 1.0f;
+        }
+
+        Vector3 pos = cameraMoveStart_.Lerp(cameraMoveTarget_, cameraMoveTime_);
+        cameraNode_->SetWorldPosition(pos);
 
     }
 }
@@ -297,7 +374,7 @@ void SceneView3D::HandlePostRenderUpdate(StringHash eventType, VariantMap& event
 
     }
 
-    if (!MouseInView())
+    if (!MouseInView() || GetOrbitting())
         return;
 
     Input* input = GetSubsystem<Input>();
@@ -406,8 +483,7 @@ void SceneView3D::HandleUpdate(StringHash eventType, VariantMap& eventData)
     // Timestep parameter is same no matter what event is being listened to
     float timeStep = eventData[Update::P_TIMESTEP].GetFloat();
 
-    if (MouseInView())
-        MoveCamera(timeStep);
+    MoveCamera(timeStep);
 
     QueueUpdate();
 
@@ -597,6 +673,26 @@ void SceneView3D::HandleDragEnded(StringHash eventType, VariantMap& eventData)
     dragNode_ = 0;
 }
 
+void SceneView3D::FrameSelection()
+{
+    BoundingBox bbox;
+
+    sceneEditor_->GetSelectionBoundingBox(bbox);
 
+    if (!bbox.defined_)
+        return;
+
+    Sphere sphere(bbox);
+
+    if (sphere.radius_ < .01f || sphere.radius_ > 512)
+        return;
+
+    framedNode_ = selectedNode_;
+    cameraMoveStart_ = cameraNode_->GetWorldPosition();
+    cameraMoveTarget_ = bbox.Center() - (cameraNode_->GetWorldDirection() * sphere.radius_ * 3);
+    cameraMoveTime_ = 0.0f;
+    cameraMove_ = true;
+
+}
 
 }

+ 11 - 1
Source/AtomicEditor/Editors/SceneEditor3D/SceneView3D.h

@@ -46,6 +46,8 @@ public:
     void SetPitch(float pitch) { pitch_ = pitch; }
     void SetYaw(float yaw) { yaw_ = yaw; }
 
+    void FrameSelection();
+
     void Enable();
     void Disable();
     bool IsEnabled() { return enabled_; }
@@ -53,6 +55,8 @@ public:
 private:
 
     bool MouseInView();
+    bool GetOrbitting();
+    bool GetZooming();
 
     void HandleMouseMove(StringHash eventType, VariantMap& eventData);
 
@@ -82,12 +86,18 @@ private:
     bool mouseLeftDown_;
     bool mouseMoved_;
 
-    bool enabled_;
+    bool enabled_;    
+
+    bool cameraMove_;
+    float cameraMoveTime_;
+    Vector3 cameraMoveStart_;
+    Vector3 cameraMoveTarget_;
 
     SharedPtr<Camera> camera_;
     SharedPtr<DebugRenderer> debugRenderer_;
     SharedPtr<Octree> octree_;
     SharedPtr<Node> selectedNode_;
+    WeakPtr<Node> framedNode_;
 
     SharedPtr<Scene> preloadResourceScene_;
     String dragAssetGUID_;