Josh Engebretson 10 anni fa
parent
commit
82fb3b0c14

+ 297 - 4
Source/AtomicEditor/Source/Editors/SceneEditor3D/Gizmo3D.cpp

@@ -8,8 +8,12 @@
 
 #include <Atomic/Graphics/Model.h>
 #include <Atomic/Graphics/Material.h>
+#include <Atomic/Graphics/Octree.h>
 #include <Atomic/Resource/ResourceCache.h>
 
+#include <Atomic/UI/UI.h>
+#include <Atomic/Input/Input.h>
+
 #include "Gizmo3D.h"
 
 namespace AtomicEditor
@@ -23,20 +27,23 @@ Gizmo3D::Gizmo3D(Context* context) : Object(context)
     gizmoNode_ = new Node(context_);
     gizmo_ = gizmoNode_->CreateComponent<StaticModel>();
     gizmo_->SetModel(cache->GetResource<Model>("AtomicEditor/Models/Axes.mdl"));
-    gizmo_->SetMaterial(0, cache->GetResource<Material>("Materials/Editor/RedUnlit.xml"));
-    gizmo_->SetMaterial(1, cache->GetResource<Material>("Materials/Editor/GreenUnlit.xml"));
-    gizmo_->SetMaterial(2, cache->GetResource<Material>("Materials/Editor/BlueUnlit.xml"));
+    gizmo_->SetMaterial(0, cache->GetResource<Material>("AtomicEditor/Materials/RedUnlit.xml"));
+    gizmo_->SetMaterial(1, cache->GetResource<Material>("AtomicEditor/Materials/GreenUnlit.xml"));
+    gizmo_->SetMaterial(2, cache->GetResource<Material>("AtomicEditor/Materials/BlueUnlit.xml"));
 
 
     gizmo_->SetEnabled(false);
     gizmo_->SetViewMask(0x80000000); // Editor raycasts use viewmask 0x7fffffff
     gizmo_->SetOccludee(false);
 
+    axisMode_ = AXIS_LOCAL;
+
     gizmoAxisX_.lastSelected_ = false;
     gizmoAxisY_.lastSelected_ = false;
     gizmoAxisZ_.lastSelected_ = false;
-    lastGizmoMode_ = EDIT_MOVE;
 
+    editMode_ = EDIT_MOVE;
+    lastEditMode_ = EDIT_MOVE;
 }
 
 Gizmo3D::~Gizmo3D()
@@ -44,4 +51,290 @@ Gizmo3D::~Gizmo3D()
 
 }
 
+void Gizmo3D::SetView(SceneView3D* view3D)
+{
+    view3D_ = view3D;
+    scene_ = view3D->GetScene();
+    camera_ = view3D->GetCameraNode()->GetComponent<Camera>();
+    assert(camera_.NotNull());
+}
+
+void Gizmo3D::Position()
+{
+    Vector3 center(0, 0, 0);
+    bool containsScene = false;
+
+    for (unsigned i = 0; i < editNodes_->Size(); ++i)
+    {
+        // Scene's transform should not be edited, so hide gizmo if it is included
+        if (editNodes_->At(i) == scene_)
+        {
+            containsScene = true;
+            break;
+        }
+        center += editNodes_->At(i)->GetWorldPosition();
+    }
+
+    if (editNodes_->Empty() || containsScene)
+    {
+        //HideGizmo();
+        return;
+    }
+
+    center /= editNodes_->Size();
+    gizmoNode_->SetPosition(center);
+
+    if (axisMode_ == AXIS_WORLD || editNodes_->Size() > 1)
+        gizmoNode_->SetRotation(Quaternion());
+    else
+        gizmoNode_->SetRotation(editNodes_->At(0)->GetWorldRotation());
+
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+
+    if (editMode_ != lastEditMode_)
+    {
+        switch (editMode_)
+        {
+        case EDIT_MOVE:
+            gizmo_->SetModel(cache->GetResource<Model>("AtomicEditor/Models/Axes.mdl"));
+            break;
+
+        case EDIT_ROTATE:
+            gizmo_->SetModel(cache->GetResource<Model>("AtomicEditor/Models/RotateAxes.mdl"));
+            break;
+
+        case EDIT_SCALE:
+            gizmo_->SetModel(cache->GetResource<Model>("AtomicEditor/Models/ScaleAxes.mdl"));
+            break;
+
+        default:
+            break;
+        }
+
+        lastEditMode_ = editMode_;
+    }
+
+    bool orbiting = false;
+    if ((editMode_ != EDIT_SELECT && !orbiting) && !gizmo_->IsEnabled())
+        Show();
+    else if ((editMode_ == EDIT_SELECT || orbiting) && gizmo_->IsEnabled())
+        Hide();
+
+    if (gizmo_->IsEnabled())
+    {
+        float scale = 0.1f / camera_->GetZoom();
+
+        if (camera_->IsOrthographic())
+            scale *= camera_->GetOrthoSize();
+        else
+            scale *= (camera_->GetView() * gizmoNode_->GetPosition()).z_;
+
+        gizmoNode_->SetScale(Vector3(scale, scale, scale));
+
+    }
+}
+
+void Gizmo3D::Update(Vector<Node *> &editNodes)
+{
+    editNodes_ = &editNodes;
+
+    Use();
+    Position();
+
+
+}
+
+void Gizmo3D::CalculateGizmoAxes()
+{
+    gizmoAxisX_.axisRay_ = Ray(gizmoNode_->GetPosition(), gizmoNode_->GetRotation() * Vector3(1, 0, 0));
+    gizmoAxisY_.axisRay_ = Ray(gizmoNode_->GetPosition(), gizmoNode_->GetRotation() * Vector3(0, 1, 0));
+    gizmoAxisZ_.axisRay_ = Ray(gizmoNode_->GetPosition(), gizmoNode_->GetRotation() * Vector3(0, 0, 1));
+}
+
+void Gizmo3D::Use()
+{
+    if (gizmo_.Null() || !gizmo_->IsEnabled() || editMode_ == EDIT_SELECT)
+    {
+        //StoreGizmoEditActions();
+        //previousGizmoDrag = false;
+        return;
+    }
+
+    ResourceCache* cache = GetSubsystem<ResourceCache>();
+    Input* input = GetSubsystem<Input>();
+
+    Ray cameraRay = view3D_->GetCameraRay();
+    float scale = gizmoNode_->GetScale().x_;
+
+    // Recalculate axes only when not left-dragging
+    bool drag = input->GetMouseButtonDown(MOUSEB_LEFT);
+    if (!drag)
+        CalculateGizmoAxes();
+
+    gizmoAxisX_.Update(cameraRay, scale, drag, camera_->GetNode());
+    gizmoAxisY_.Update(cameraRay, scale, drag, camera_->GetNode());
+    gizmoAxisZ_.Update(cameraRay, scale, drag, camera_->GetNode());
+
+    if (gizmoAxisX_.selected_ != gizmoAxisX_.lastSelected_)
+    {
+        gizmo_->SetMaterial(0, cache->GetResource<Material>(
+                                gizmoAxisX_.selected_ ?
+                                    "AtomicEditor/Materials/BrightRedUnlit.xml" : "AtomicEditor/Materials/RedUnlit.xml"));
+
+        gizmoAxisX_.lastSelected_ = gizmoAxisX_.selected_;
+    }
+
+    if (gizmoAxisY_.selected_ != gizmoAxisY_.lastSelected_)
+    {
+        gizmo_->SetMaterial(1, cache->GetResource<Material>(
+                                gizmoAxisY_.selected_ ?
+                                    "AtomicEditor/Materials/BrightGreenUnlit.xml" : "AtomicEditor/Materials/GreenUnlit.xml"));
+
+        gizmoAxisY_.lastSelected_ = gizmoAxisY_.selected_;
+    }
+    if (gizmoAxisZ_.selected_ != gizmoAxisZ_.lastSelected_)
+    {
+        gizmo_->SetMaterial(2, cache->GetResource<Material>(
+                                gizmoAxisZ_.selected_ ?
+                                    "AtomicEditor/Materials/BrightBlueUnlit.xml" : "AtomicEditor/Materials/BlueUnlit.xml"));
+
+        gizmoAxisZ_.lastSelected_ = gizmoAxisZ_.selected_;
+    }
+
+    if (drag)
+        Drag();
+
+}
+
+bool Gizmo3D::MoveEditNodes(Vector3 adjust)
+{
+    bool moved = false;
+
+    if (adjust.Length() > M_EPSILON)
+    {
+        for (unsigned i = 0; i < editNodes_->Size(); ++i)
+        {
+            /*
+            if (moveSnap)
+            {
+                float moveStepScaled = moveStep * snapScale;
+                adjust.x = Floor(adjust.x / moveStepScaled + 0.5) * moveStepScaled;
+                adjust.y = Floor(adjust.y / moveStepScaled + 0.5) * moveStepScaled;
+                adjust.z = Floor(adjust.z / moveStepScaled + 0.5) * moveStepScaled;
+            }
+            */
+
+            Node* node = editNodes_->At(i);
+            Vector3 nodeAdjust = adjust;
+            if (axisMode_ == AXIS_LOCAL && editNodes_->Size() == 1)
+                nodeAdjust = node->GetWorldRotation() * nodeAdjust;
+
+            Vector3 worldPos = node->GetWorldPosition();
+            Vector3 oldPos = node->GetPosition();
+
+            worldPos += nodeAdjust;
+
+            if (!node->GetParent())
+                node->SetPosition(worldPos);
+            else
+                node->SetPosition(node->GetParent()->WorldToLocal(worldPos));
+
+            if (node->GetPosition() != oldPos)
+                moved = true;
+        }
+    }
+
+    return moved;
+
+
+}
+
+void Gizmo3D::Moved()
+{
+    gizmoAxisX_.Moved();
+    gizmoAxisY_.Moved();
+    gizmoAxisZ_.Moved();
+}
+
+
+void Gizmo3D::Drag()
+{
+    bool moved = false;
+
+    if (editMode_ == EDIT_MOVE)
+    {
+        Vector3 adjust(0, 0, 0);
+        if (gizmoAxisX_.selected_)
+            adjust += Vector3(1, 0, 0) * (gizmoAxisX_.t_ - gizmoAxisX_.lastT_);
+        if (gizmoAxisY_.selected_)
+            adjust += Vector3(0, 1, 0) * (gizmoAxisY_.t_ - gizmoAxisY_.lastT_);
+        if (gizmoAxisZ_.selected_)
+            adjust += Vector3(0, 0, 1) * (gizmoAxisZ_.t_ - gizmoAxisZ_.lastT_);
+
+        moved = MoveEditNodes(adjust);
+    }
+    /*
+    else if (editMode == EDIT_ROTATE)
+    {
+        Vector3 adjust(0, 0, 0);
+        if (gizmoAxisX.selected)
+            adjust.x = (gizmoAxisX.d - gizmoAxisX.lastD) * rotSensitivity / scale;
+        if (gizmoAxisY.selected)
+            adjust.y = -(gizmoAxisY.d - gizmoAxisY.lastD) * rotSensitivity / scale;
+        if (gizmoAxisZ.selected)
+            adjust.z = (gizmoAxisZ.d - gizmoAxisZ.lastD) * rotSensitivity / scale;
+
+        moved = RotateNodes(adjust);
+    }
+    else if (editMode == EDIT_SCALE)
+    {
+        Vector3 adjust(0, 0, 0);
+        if (gizmoAxisX.selected)
+            adjust += Vector3(1, 0, 0) * (gizmoAxisX.t - gizmoAxisX.lastT);
+        if (gizmoAxisY.selected)
+            adjust += Vector3(0, 1, 0) * (gizmoAxisY.t - gizmoAxisY.lastT);
+        if (gizmoAxisZ.selected)
+            adjust += Vector3(0, 0, 1) * (gizmoAxisZ.t - gizmoAxisZ.lastT);
+
+        // Special handling for uniform scale: use the unmodified X-axis movement only
+        if (editMode == EDIT_SCALE && gizmoAxisX.selected && gizmoAxisY.selected && gizmoAxisZ.selected)
+        {
+            float x = gizmoAxisX.t - gizmoAxisX.lastT;
+            adjust = Vector3(x, x, x);
+        }
+
+        moved = ScaleNodes(adjust);
+    }
+    */
+
+    if (moved)
+    {
+        Moved();
+        //UpdateNodeAttributes();
+        //needGizmoUndo = true;
+    }
+
+}
+
+
+void Gizmo3D::Hide()
+{
+    gizmo_->SetEnabled(false);
+}
+
+void Gizmo3D::Show()
+{
+    if (scene_.Null())
+        return;
+
+    gizmo_->SetEnabled(true);
+
+    Octree* octree = scene_->GetComponent<Octree>();
+    if (!octree)
+        return;
+
+    octree->AddManualDrawable(gizmo_);
+
+}
+
 }

+ 51 - 21
Source/AtomicEditor/Source/Editors/SceneEditor3D/Gizmo3D.h

@@ -8,10 +8,15 @@
 #pragma once
 
 #include <Atomic/Core/Object.h>
+#include <Atomic/Math/MathDefs.h>
 #include <Atomic/Math/Ray.h>
 #include <Atomic/Scene/Scene.h>
 
 #include <Atomic/Graphics/StaticModel.h>
+#include <Atomic/Graphics/Camera.h>
+
+
+#include "SceneView3D.h"
 
 using namespace Atomic;
 
@@ -45,35 +50,29 @@ public:
         lastD_ = 0.0;
     }
 
-    /*
-    void Update(Ray cameraRay, float scale, bool drag)
+    void Update(Ray cameraRay, float scale, bool drag, Node* cameraNode)
     {
-        // Do not select when UI has modal element
-        if (ui.HasModalElement())
-        {
-            selected = false;
-            return;
-        }
+        const float axisMaxD = 0.1f;
+        const float axisMaxT = 1.0f;
 
-        Vector3 closest = cameraRay.ClosestPoint(axisRay);
-        Vector3 projected = axisRay.Project(closest);
-        d = axisRay.Distance(closest);
-        t = (projected - axisRay.origin).DotProduct(axisRay.direction);
+        Vector3 closest = cameraRay.ClosestPoint(axisRay_);
+        Vector3 projected = axisRay_.Project(closest);
+        d_ = axisRay_.Distance(closest);
+        t_ = (projected - axisRay_.origin_).DotProduct(axisRay_.direction_);
 
         // Determine the sign of d from a plane that goes through the camera position to the axis
-        Plane axisPlane(cameraNode.position, axisRay.origin, axisRay.origin + axisRay.direction);
+        Plane axisPlane(cameraNode->GetPosition(), axisRay_.origin_, axisRay_.origin_ + axisRay_.direction_);
         if (axisPlane.Distance(closest) < 0.0)
-            d = -d;
+            d_ = -d_;
 
         // Update selected status only when not dragging
         if (!drag)
         {
-            selected = Abs(d) < axisMaxD * scale && t >= -axisMaxD * scale && t <= axisMaxT * scale;
-            lastT = t;
-            lastD = d;
+            selected_ = Abs(d_) < axisMaxD * scale && t_ >= -axisMaxD * scale && t_ <= axisMaxT * scale;
+            lastT_ = t_;
+            lastD_ = d_;
         }
     }
-    */
 
     void Moved()
     {
@@ -88,27 +87,58 @@ class Gizmo3D: public Object
 
 public:
 
-    enum GizmoMode
+    enum EditMode
+    {
+        EDIT_SELECT,
+        EDIT_MOVE,
+        EDIT_ROTATE,
+        EDIT_SCALE
+    };
+
+    enum AxisMode
     {
-        EDIT_MOVE
+        AXIS_WORLD = 0,
+        AXIS_LOCAL
     };
 
     Gizmo3D(Context* context);
     virtual ~Gizmo3D();
 
+    void SetView(SceneView3D* view3D);
+
+    void Show();
+    void Hide();
+    void Update(Vector<Node*>& editNodes);
+
     Node* GetGizmoNode() { return gizmoNode_; }
 
 private:
 
+    void Position();
+    void Use();
+    void Drag();
+    void Moved();
+    void CalculateGizmoAxes();
+
+    bool MoveEditNodes(Vector3 adjust);
+
     SharedPtr<Node> gizmoNode_;
 
+    WeakPtr<SceneView3D> view3D_;
+    WeakPtr<Scene> scene_;
+    WeakPtr<Camera> camera_;
     WeakPtr<StaticModel> gizmo_;
 
     Gizmo3DAxis gizmoAxisX_;
     Gizmo3DAxis gizmoAxisY_;
     Gizmo3DAxis gizmoAxisZ_;
 
-    GizmoMode lastGizmoMode_;
+    EditMode editMode_;
+    EditMode lastEditMode_;
+
+    AxisMode axisMode_;
+
+    Vector<Node *> *editNodes_;
 
 };
 

+ 9 - 1
Source/AtomicEditor/Source/Editors/SceneEditor3D/SceneEditor3D.cpp

@@ -66,6 +66,10 @@ SceneEditor3D ::SceneEditor3D(Context* context, const String &fullpath, TBTabCon
 
     container_->GetContentRoot()->AddChild(layout_);
 
+    gizmo3D_ = new Gizmo3D(context_);
+    gizmo3D_->SetView(sceneView_);
+    gizmo3D_->Show();
+
     SubscribeToEvent(E_UPDATE, HANDLER(SceneEditor3D, HandleUpdate));
     SubscribeToEvent(E_EDITORACTIVENODECHANGE, HANDLER(SceneEditor3D, HandleEditorActiveNodeChange));
 
@@ -78,6 +82,7 @@ SceneEditor3D ::SceneEditor3D(Context* context, const String &fullpath, TBTabCon
 
 SceneEditor3D::~SceneEditor3D()
 {
+
 }
 
 bool SceneEditor3D::OnEvent(const TBWidgetEvent &ev)
@@ -87,11 +92,14 @@ bool SceneEditor3D::OnEvent(const TBWidgetEvent &ev)
 
 void SceneEditor3D::SelectNode(Node* node)
 {
-
+    selectedNode_ = node;
 }
 
 void SceneEditor3D::HandleUpdate(StringHash eventType, VariantMap& eventData)
 {    
+    Vector<Node*> editNodes;
+    editNodes.Push(selectedNode_);
+    gizmo3D_->Update(editNodes);
 }
 
 void SceneEditor3D::HandleEditorActiveNodeChange(StringHash eventType, VariantMap& eventData)

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

@@ -8,6 +8,7 @@
 
 #include "../ResourceEditor.h"
 #include "SceneView3D.h"
+#include "Gizmo3D.h"
 
 using namespace Atomic;
 using namespace tb;
@@ -52,6 +53,8 @@ private:
     // TODO: multiple views
     SharedPtr<SceneView3D> sceneView_;
 
+    SharedPtr<Gizmo3D> gizmo3D_;
+
     TBLayout* layout_;
     TBContainer* view3DContainer_;
 

+ 12 - 8
Source/AtomicEditor/Source/Editors/SceneEditor3D/SceneView3D.cpp

@@ -125,23 +125,28 @@ void SceneView3D::MoveCamera(float timeStep)
         cameraNode_->Translate(Vector3::RIGHT * MOVE_SPEED * timeStep);
 }
 
-void SceneView3D::HandlePostRenderUpdate(StringHash eventType, VariantMap& eventData)
+Ray SceneView3D::GetCameraRay()
 {
+    Ray camRay;
 
-    /*
     UI* ui = GetSubsystem<UI>();
 
     IntVector2 cpos = ui->GetCursorPosition();
 
-    TBRect rect = widget_->GetRect();
+    TBRect rect = GetWidgetDelegate()->GetRect();
 
     if (!rect.w || !rect.h)
-        return;
+        return camRay;
+
+    GetWidgetDelegate()->ConvertToRoot(rect.x, rect.y);
 
-    widget_->ConvertToRoot(rect.x, rect.y);
+    return  camera_->GetScreenRay(float(cpos.x_ - rect.x) / rect.w,
+                                       float(cpos.y_ - rect.y) /rect.h);
+}
 
-    Ray camRay = camera_->GetScreenRay(float(cpos.x_ - rect.x) / rect.w,
-                          float(cpos.y_ - rect.y) /rect.h);
+void SceneView3D::HandlePostRenderUpdate(StringHash eventType, VariantMap& eventData)
+{
+    Ray camRay  = GetCameraRay();
 
     PODVector<RayQueryResult> result;
     RayOctreeQuery query(result, camRay, RAY_TRIANGLE, camera_->GetFarClip(), DRAWABLE_ANY, DEFAULT_VIEWMASK);
@@ -158,7 +163,6 @@ void SceneView3D::HandlePostRenderUpdate(StringHash eventType, VariantMap& event
         }
 
     }
-    */
 
 }
 

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

@@ -34,6 +34,8 @@ public:
     virtual ~SceneView3D();
     void SelectNode(Node* node);
 
+    Ray GetCameraRay();
+
 private:
 
     void HandleUpdate(StringHash eventType, VariantMap& eventData);