Bläddra i källkod

Added SceneObject inspector fields
Fixed a bug in euler angle -> quaternion conversion

Marko Pintera 10 år sedan
förälder
incheckning
f3b2014804

+ 3 - 0
BansheeEngine/Source/BsGUIInputBox.cpp

@@ -64,6 +64,9 @@ namespace BansheeEngine
 
 	void GUIInputBox::setText(const WString& text)
 	{
+		if (mText == text)
+			return;
+
 		bool filterOkay = true;
 		if(mFilter != nullptr)
 		{

+ 6 - 14
BansheeUtility/Source/BsQuaternion.cpp

@@ -93,24 +93,16 @@ namespace BansheeEngine
 
 	void Quaternion::fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle)
 	{
-		Quaternion quats[3];
-		quats[0].fromAxisAngle(Vector3::UNIT_X, xAngle);
-		quats[1].fromAxisAngle(Vector3::UNIT_Y, yAngle);
-		quats[2].fromAxisAngle(Vector3::UNIT_Z, zAngle);
-
-		*this = quats[2]*(quats[0] * quats[1]);
+		Matrix3 mat;
+		mat.fromEulerAngles(xAngle, yAngle, zAngle);
+		mat.toQuaternion(*this);
 	}
 
 	void Quaternion::fromEulerAngles(const Radian& xAngle, const Radian& yAngle, const Radian& zAngle, EulerAngleOrder order)
 	{
-		const EulerAngleOrderData& l = EA_LOOKUP[(int)order];
-
-		Quaternion quats[3];
-		quats[0].fromAxisAngle(Vector3::UNIT_X, xAngle);
-		quats[1].fromAxisAngle(Vector3::UNIT_Y, yAngle);
-		quats[2].fromAxisAngle(Vector3::UNIT_Z, zAngle);
-
-		*this = quats[l.c]*(quats[l.a] * quats[l.b]);
+		Matrix3 mat;
+		mat.fromEulerAngles(xAngle, yAngle, zAngle, order);
+		mat.toQuaternion(*this);
 	}
 
 	void Quaternion::toRotationMatrix(Matrix3& mat) const

+ 234 - 3
MBansheeEditor/Inspector/InspectorWindow.cs

@@ -18,6 +18,20 @@ namespace BansheeEditor
         private GUIScrollArea inspectorScrollArea;
         private GUILayout inspectorLayout;
 
+        private SceneObject activeSO;
+        private GUITextBox soNameInput;
+        private GUILayout soPrefabLayout;
+        private bool soHasPrefab;
+        private GUIFloatField soPosX;
+        private GUIFloatField soPosY;
+        private GUIFloatField soPosZ;
+        private GUIFloatField soRotX;
+        private GUIFloatField soRotY;
+        private GUIFloatField soRotZ;
+        private GUIFloatField soScaleX;
+        private GUIFloatField soScaleY;
+        private GUIFloatField soScaleZ;
+
         [MenuItem("Windows/Inspector", ButtonModifier.CtrlAlt, ButtonCode.I)]
         private static void OpenHierarchyWindow()
         {
@@ -28,12 +42,20 @@ namespace BansheeEditor
         {
             Clear();
 
-            // TODO - Create SceneObject gui elements (name + transform)
+            activeSO = so;
+
+            if (activeSO == null)
+                return;
 
             inspectorScrollArea = new GUIScrollArea();
             GUI.AddElement(inspectorScrollArea);
             inspectorLayout = inspectorScrollArea.Layout;
 
+            // SceneObject fields
+            CreateSceneObjectFields();
+            RefreshSceneObjectFields(true);
+
+            // Components
             Component[] allComponents = so.GetComponents();
             for (int i = 0; i < allComponents.Length; i++)
             {
@@ -63,8 +85,150 @@ namespace BansheeEditor
             inspectorData.inspector.SetVisible(expanded);
         }
 
+        private void CreateSceneObjectFields()
+        {
+            GUIPanel sceneObjectPanel = inspectorLayout.AddPanel();
+            GUILayoutY sceneObjectLayout = sceneObjectPanel.AddLayoutY();
+
+            GUILayoutX nameLayout = sceneObjectLayout.AddLayoutX();
+            GUILabel nameLbl = new GUILabel("Name", GUIOption.FixedWidth(70));
+            soNameInput = new GUITextBox(false, GUIOption.FlexibleWidth(200));
+            soNameInput.Text = activeSO.Name;
+            soNameInput.OnChanged += (x) => { if (activeSO != null) activeSO.Name = x; };
+
+            nameLayout.AddElement(nameLbl);
+            nameLayout.AddElement(soNameInput);
+            nameLayout.AddFlexibleSpace();
+
+            soPrefabLayout = sceneObjectLayout.AddLayoutX();
+
+            GUILayoutX positionLayout = sceneObjectLayout.AddLayoutX();
+            GUILabel positionLbl = new GUILabel("Position", GUIOption.FixedWidth(70));
+            soPosX = new GUIFloatField(new GUIContent("X"), 10, "", GUIOption.FlexibleWidth(50));
+            soPosY = new GUIFloatField(new GUIContent("Y"), 10, "", GUIOption.FlexibleWidth(50));
+            soPosZ = new GUIFloatField(new GUIContent("Z"), 10, "", GUIOption.FlexibleWidth(50));
+
+            soPosX.OnChanged += (x) => OnPositionChanged(0, x);
+            soPosY.OnChanged += (y) => OnPositionChanged(1, y);
+            soPosZ.OnChanged += (z) => OnPositionChanged(2, z);
+
+            positionLayout.AddElement(positionLbl);
+            positionLayout.AddElement(soPosX);
+            positionLayout.AddSpace(10);
+            positionLayout.AddElement(soPosY);
+            positionLayout.AddSpace(10);
+            positionLayout.AddElement(soPosZ);
+            positionLayout.AddFlexibleSpace();
+
+            GUILayoutX rotationLayout = sceneObjectLayout.AddLayoutX();
+            GUILabel rotationLbl = new GUILabel("Rotation", GUIOption.FixedWidth(70));
+            soRotX = new GUIFloatField(new GUIContent("X"), 10, "", GUIOption.FlexibleWidth(50));
+            soRotY = new GUIFloatField(new GUIContent("Y"), 10, "", GUIOption.FlexibleWidth(50));
+            soRotZ = new GUIFloatField(new GUIContent("Z"), 10, "", GUIOption.FlexibleWidth(50));
+
+            soRotX.OnChanged += (x) => OnRotationChanged(0, x);
+            soRotY.OnChanged += (y) => OnRotationChanged(1, y);
+            soRotZ.OnChanged += (z) => OnRotationChanged(2, z);
+
+            rotationLayout.AddElement(rotationLbl);
+            rotationLayout.AddElement(soRotX);
+            rotationLayout.AddSpace(10);
+            rotationLayout.AddElement(soRotY);
+            rotationLayout.AddSpace(10);
+            rotationLayout.AddElement(soRotZ);
+            rotationLayout.AddFlexibleSpace();
+
+            GUILayoutX scaleLayout = sceneObjectLayout.AddLayoutX();
+            GUILabel scaleLbl = new GUILabel("Scale", GUIOption.FixedWidth(70));
+            soScaleX = new GUIFloatField(new GUIContent("X"), 10, "", GUIOption.FlexibleWidth(50));
+            soScaleY = new GUIFloatField(new GUIContent("Y"), 10, "", GUIOption.FlexibleWidth(50));
+            soScaleZ = new GUIFloatField(new GUIContent("Z"), 10, "", GUIOption.FlexibleWidth(50));
+
+            soScaleX.OnChanged += (x) => OnScaleChanged(0, x);
+            soScaleY.OnChanged += (y) => OnScaleChanged(1, y);
+            soScaleX.OnChanged += (z) => OnScaleChanged(2, z);
+
+            scaleLayout.AddElement(scaleLbl);
+            scaleLayout.AddElement(soScaleX);
+            scaleLayout.AddSpace(10);
+            scaleLayout.AddElement(soScaleY);
+            scaleLayout.AddSpace(10);
+            scaleLayout.AddElement(soScaleZ);
+            scaleLayout.AddFlexibleSpace();
+        }
+
+        private void RefreshSceneObjectFields(bool forceUpdate)
+        {
+            if (activeSO == null)
+                return;
+
+            soNameInput.Text = activeSO.Name;
+
+            bool hasPrefab = PrefabUtility.HasPrefabLink(activeSO);
+            if (soHasPrefab != hasPrefab || forceUpdate)
+            {
+                int numChildren = soPrefabLayout.GetNumChildren();
+                for (int i = 0; i < numChildren; i++)
+                    soPrefabLayout.GetChild(0).Destroy();
+
+                GUILabel prefabLabel =new GUILabel("Prefab", GUIOption.FixedWidth(70));
+                soPrefabLayout.AddElement(prefabLabel);
+
+                //if (hasPrefab) // TODO - Disabled check for preview purposes
+                {
+                    GUIButton btnApplyPrefab = new GUIButton("Apply");
+                    GUIButton btnRevertPrefab = new GUIButton("Revert");
+                    GUIButton btnBreakPrefab = new GUIButton("Break");
+
+                    btnApplyPrefab.OnClick += () => PrefabUtility.ApplyPrefab(activeSO);
+                    btnRevertPrefab.OnClick += () => PrefabUtility.RevertPrefab(activeSO);
+                    btnBreakPrefab.OnClick += () => PrefabUtility.BreakPrefab(activeSO);
+
+                    soPrefabLayout.AddElement(btnApplyPrefab);
+                    soPrefabLayout.AddElement(btnRevertPrefab);
+                    soPrefabLayout.AddElement(btnBreakPrefab);
+                }
+                //else
+                //{
+                //    GUILabel noPrefabLabel = new GUILabel("None");
+                //    soPrefabLayout.AddElement(noPrefabLabel);
+                //}
+
+                soHasPrefab = hasPrefab;
+            }
+
+            Vector3 position;
+            Vector3 angles;
+            if (EditorApplication.ActiveCoordinateMode == HandleCoordinateMode.World)
+            {
+                position = activeSO.Position;
+                angles = activeSO.Rotation.ToEuler();
+            }
+            else
+            {
+                position = activeSO.LocalPosition;
+                angles = activeSO.LocalRotation.ToEuler();
+            }
+
+            Vector3 scale = activeSO.LocalScale;
+
+            soPosX.Value = position.x;
+            soPosY.Value = position.y;
+            soPosZ.Value = position.z;
+
+            soRotX.Value = angles.x;
+            soRotY.Value = angles.y;
+            soRotZ.Value = angles.z;
+
+            soScaleX.Value = scale.x;
+            soScaleY.Value = scale.y;
+            soScaleZ.Value = scale.z;
+        }
+
         private void OnEditorUpdate()
         {
+            RefreshSceneObjectFields(false);
+
             for (int i = 0; i < inspectorData.Count; i++)
             {
                 inspectorData[i].inspector.Refresh();
@@ -73,8 +237,6 @@ namespace BansheeEditor
 
         internal void Destroy()
         {
-            // TODO - Destroy SceneObject GUI elements
-
             Clear();
         }
 
@@ -93,6 +255,75 @@ namespace BansheeEditor
                 inspectorScrollArea.Destroy();
                 inspectorScrollArea = null;
             }
+
+            activeSO = null;
+            soNameInput = null;
+            soPrefabLayout = null;
+            soHasPrefab = false;
+            soPosX = null;
+            soPosY = null;
+            soPosZ = null;
+            soRotX = null;
+            soRotY = null;
+            soRotZ = null;
+            soScaleX = null;
+            soScaleY = null;
+            soScaleZ = null;
+        }
+
+        private void OnPositionChanged(int idx, float value)
+        {
+            if (activeSO == null)
+                return;
+
+            if (EditorApplication.ActiveCoordinateMode == HandleCoordinateMode.World)
+            {
+                Vector3 position = activeSO.Position;
+                position[idx] = value;
+                activeSO.Position = position;
+            }
+            else
+            {
+                Vector3 position = activeSO.LocalPosition;
+                position[idx] = value;
+                activeSO.LocalPosition = position;
+            }
+        }
+
+        private void OnRotationChanged(int idx, float value)
+        {
+            if (activeSO == null)
+                return;
+
+            if (EditorApplication.ActiveCoordinateMode == HandleCoordinateMode.World)
+            {
+                Vector3 angles = activeSO.Rotation.ToEuler();
+                angles[idx] = value;
+                activeSO.Rotation = Quaternion.FromEuler(angles);
+            }
+            else
+            {
+                Vector3 angles = activeSO.LocalRotation.ToEuler();
+                angles[idx] = value;
+                activeSO.LocalRotation = Quaternion.FromEuler(angles);
+
+                Debug.Log("ROTATION CHANGED: " + idx + " - " + value + " - " + angles + " - " + activeSO.LocalRotation + " - " + activeSO.LocalRotation.ToEuler());
+
+                Quaternion dbg = Quaternion.FromEuler(angles);
+
+                Debug.Log("LOCAL CHECK: " + angles + " - " + dbg + " - " + dbg.ToEuler());
+                
+            }
+        }
+
+        private void OnScaleChanged(int idx, float value)
+        {
+            if (activeSO == null)
+                return;
+
+            Vector3 scale = activeSO.LocalScale;
+            scale[idx] = value;
+            activeSO.LocalScale = scale;
         }
 
         private Inspector GetInspector(Type type)

+ 12 - 0
MBansheeEditor/PrefabUtility.cs

@@ -37,6 +37,15 @@ namespace BansheeEditor
             Internal_RevertPrefab(objPtr);
         }
 
+        public static bool HasPrefabLink(SceneObject obj)
+        {
+            if (obj == null)
+                return false;
+
+            IntPtr objPtr = obj.GetCachedPtr();
+            return Internal_HasPrefabLink(objPtr);
+        }
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_BreakPrefab(IntPtr nativeInstance);
 
@@ -45,5 +54,8 @@ namespace BansheeEditor
 
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_RevertPrefab(IntPtr nativeInstance);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern bool Internal_HasPrefabLink(IntPtr nativeInstance);
     }
 }

+ 5 - 11
MBansheeEngine/Math/Quaternion.cs

@@ -360,7 +360,7 @@ namespace BansheeEngine
         }
 
         // Returns angles in degrees
-        public Vector3 ToEulerAngles(EulerAngleOrder order = EulerAngleOrder.XYZ)
+        public Vector3 ToEuler(EulerAngleOrder order = EulerAngleOrder.XYZ)
         {
             Matrix3 matRot = ToRotationMatrix();
             return matRot.ToEulerAngles(order);
@@ -426,9 +426,9 @@ namespace BansheeEngine
             return quat;
         }
 
-        public static Vector3 ToEulerAngles(Quaternion rotation, EulerAngleOrder order = EulerAngleOrder.XYZ)
+        public static Vector3 ToEuler(Quaternion rotation, EulerAngleOrder order = EulerAngleOrder.XYZ)
         {
-            return rotation.ToEulerAngles(order);
+            return rotation.ToEuler(order);
         }
 
         public static void ToAxisAngle(Quaternion rotation, out Vector3 axis, out Degree angleDeg)
@@ -501,14 +501,8 @@ namespace BansheeEngine
 
         public static Quaternion FromEuler(float xDeg, float yDeg, float zDeg, EulerAngleOrder order = EulerAngleOrder.XYZ)
         {
-            EulerAngleOrderData l = EA_LOOKUP[(int)order];
-
-            Quaternion[] quats = new Quaternion[3];
-		    quats[0] = FromAxisAngle(Vector3.xAxis, xDeg);
-		    quats[1] = FromAxisAngle(Vector3.yAxis, yDeg);
-		    quats[2] = FromAxisAngle(Vector3.zAxis, zDeg);
-
-            return quats[l.c]*(quats[l.a] * quats[l.b]);
+            Matrix3 mat = Matrix3.FromEuler(new Vector3(xDeg, yDeg, zDeg), order);
+            return mat.ToQuaternion();
         }
 
         /**

+ 1 - 0
SBansheeEditor/Include/BsScriptPrefabUtility.h

@@ -14,6 +14,7 @@ namespace BansheeEngine
 		static void internal_breakPrefab(ScriptSceneObject* nativeInstance);
 		static void internal_applyPrefab(ScriptSceneObject* nativeInstance);
 		static void internal_revertPrefab(ScriptSceneObject* nativeInstance);
+		static bool internal_hasPrefabLink(ScriptSceneObject* nativeInstance);
 
 		ScriptPrefabUtility(MonoObject* instance);
 	};

+ 9 - 0
SBansheeEditor/Source/BsScriptPrefabUtility.cpp

@@ -20,6 +20,7 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_BreakPrefab", &ScriptPrefabUtility::internal_breakPrefab);
 		metaData.scriptClass->addInternalCall("Internal_ApplyPrefab", &ScriptPrefabUtility::internal_applyPrefab);
 		metaData.scriptClass->addInternalCall("Internal_RevertPrefab", &ScriptPrefabUtility::internal_revertPrefab);
+		metaData.scriptClass->addInternalCall("Internal_HasPrefabLink", &ScriptPrefabUtility::internal_hasPrefabLink);
 	}
 
 	void ScriptPrefabUtility::internal_breakPrefab(ScriptSceneObject* nativeInstance)
@@ -51,4 +52,12 @@ namespace BansheeEngine
 
 		PrefabUtility::revertToPrefab(nativeInstance->getNativeSceneObject());
 	}
+
+	bool ScriptPrefabUtility::internal_hasPrefabLink(ScriptSceneObject* nativeInstance)
+	{
+		if (ScriptSceneObject::checkIfDestroyed(nativeInstance))
+			return false;
+
+		return !nativeInstance->getNativeSceneObject()->getPrefabLink().empty();
+	}
 }

+ 7 - 0
TODO.txt

@@ -56,15 +56,19 @@ Code quality improvements:
 ----------------------------------------------------------------------
 Polish stage 1
 
+Int/Float field mouse scrolling doesn't work
 Fix DX11 (and possibly DX9) rendering
 After undocking ProjectWindow the auto-scroll seems to be stuck in up position
 Decent looking default layout
 When selecting an gizmo icon the selection seems delayed and its gizmos flash for a frame before hiding
 Make sure that scene camera controls only work when scene view is in focus
+Make proper window names instead of InspectorWindow
+Selection wireframe seems to render in front of handles
 
 Fix handles
  - Some handle functionality is unfinished
  - Handles look too large when scene view is enlarged
+ - Moving around XZ plane seems to be wrong (it doesn't move as fast as the mouse)
 
 Add ping to SceneTreeView
  - Hook up ping effect so it triggers when I select a resource or sceneobject
@@ -84,6 +88,9 @@ For later: I could record undo/redo per-property using the new diff system
 Remember: Record all portions where objects & components get modified so I can mark them dirty, will likely need
  to use those some points for undo/redo
 
+UndoRedo reminders:
+ - When breaking or reverting a scene object
+
 ----------------------------------------------------------------------
 Project window