Sfoglia il codice sorgente

Feature: Render Quaternion fields as euler angles in inspector GUI
- Also add AsQuaternion attribute to force quaternion rendering to be displayed as raw quaternion

BearishSun 7 anni fa
parent
commit
e28e33bce6

+ 97 - 0
Source/Scripting/MBansheeEditor/Windows/Inspector/InspectableEuler.cs

@@ -0,0 +1,97 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2019 Marko Pintera ([email protected]). All rights reserved. **********************//
+using BansheeEngine;
+
+namespace BansheeEditor
+{
+    /** @addtogroup Inspector
+     *  @{
+     */
+
+    /// <summary>
+    /// Displays GUI for a serializable property containing a quaternion, displayed as euler angles.
+    /// </summary>
+    public class InspectableEuler : InspectableField
+    {
+        private GUIVector3Field guiField;
+        private InspectableState state;
+
+        private Quaternion quatValue = Quaternion.Identity;
+
+        /// <summary>
+        /// Creates a new inspectable euler angle GUI for the specified property.
+        /// </summary>
+        /// <param name="parent">Parent Inspector this field belongs to.</param>
+        /// <param name="title">Name of the property, or some other value to set as the title.</param>
+        /// <param name="path">Full path to this property (includes name of this property and all parent properties).</param>
+        /// <param name="depth">Determines how deep within the inspector nesting hierarchy is this field. Some fields may
+        ///                     contain other fields, in which case you should increase this value by one.</param>
+        /// <param name="layout">Parent layout that all the field elements will be added to.</param>
+        /// <param name="property">Serializable property referencing the field whose contents to display.</param>
+        public InspectableEuler(Inspector parent, string title, string path, int depth, InspectableFieldLayout layout,
+            SerializableProperty property)
+            : base(parent, title, path, SerializableProperty.FieldType.Quaternion, depth, layout, property)
+        {
+
+        }
+
+        /// <inheritoc/>
+        protected internal override void Initialize(int layoutIndex)
+        {
+            if (property.Type == SerializableProperty.FieldType.Quaternion)
+            {
+                guiField = new GUIVector3Field(new GUIContent(title));
+                guiField.Value = quatValue.ToEuler();
+
+                guiField.OnChanged += OnFieldValueChanged;
+                guiField.OnConfirmed += OnFieldValueConfirm;
+                guiField.OnFocusLost += OnFieldValueConfirm;
+
+                layout.AddElement(layoutIndex, guiField);
+            }
+        }
+
+        /// <inheritdoc/>
+        public override InspectableState Refresh(int layoutIndex)
+        {
+            if (guiField != null && !guiField.HasInputFocus)
+            {
+                Quaternion quaternion = property.GetValue<Quaternion>();
+                if (quaternion != quatValue)
+                {
+                    guiField.Value = quaternion.ToEuler();
+                    quatValue = quaternion;
+                }
+            }
+
+            InspectableState oldState = state;
+            if (state.HasFlag(InspectableState.Modified))
+                state = InspectableState.NotModified;
+
+            return oldState;
+        }
+
+        /// <summary>
+        /// Triggered when the user changes the field value.
+        /// </summary>
+        /// <param name="newValue">New value of the 3D vector field.</param>
+        private void OnFieldValueChanged(Vector3 newValue)
+        {
+            quatValue = Quaternion.FromEuler(newValue);
+
+            property.SetValue(quatValue);
+            state |= InspectableState.ModifyInProgress;
+        }
+
+        /// <summary>
+        /// Triggered when the user confirms input in the 3D vector field.
+        /// </summary>
+        private void OnFieldValueConfirm()
+        {
+            if (state.HasFlag(InspectableState.ModifyInProgress))
+                state |= InspectableState.Modified;
+        }
+    }
+
+    /** @} */
+}

+ 4 - 1
Source/Scripting/MBansheeEditor/Windows/Inspector/InspectableField.cs

@@ -205,7 +205,10 @@ namespace BansheeEditor
                         field = new InspectableVector4(parent, title, path, depth, layout, property);
                         break;
                     case SerializableProperty.FieldType.Quaternion:
-                        field = new InspectableQuaternion(parent, title, path, depth, layout, property);
+                        if (style != null && style.StyleFlags.HasFlag(InspectableFieldStyleFlags.AsQuaternion))
+                            field = new InspectableQuaternion(parent, title, path, depth, layout, property);
+                        else
+                            field = new InspectableEuler(parent, title, path, depth, layout, property);
                         break;
                     case SerializableProperty.FieldType.Resource:
                         field = new InspectableResource(parent, title, path, depth, layout, property);

+ 4 - 0
Source/Scripting/MBansheeEditor/Windows/Inspector/Style/InspectableFieldStyle.cs

@@ -39,6 +39,10 @@ namespace BansheeEditor
                 ? InspectableFieldStyleFlags.ApplyOnDirty
                 : 0;
 
+            styleInfo.StyleFlags |= field.Flags.HasFlag(SerializableFieldAttributes.DisplayAsQuaternion)
+                ? InspectableFieldStyleFlags.AsQuaternion
+                : 0;
+
             return styleInfo;
         }
     }

+ 7 - 1
Source/Scripting/MBansheeEditor/Windows/Inspector/Style/InspectableFieldStyleInfo.cs

@@ -46,7 +46,13 @@ namespace BansheeEditor
         /// When a field changes those changes need to be applied to the parent object by calling the field setter. Only
         /// applicable to properties containing reference types.
         /// </summary>
-        ApplyOnDirty = 1 << 5
+        ApplyOnDirty = 1 << 5,
+
+        /// <summary>
+        /// When a quaternion is displayed in the inspector, by default it will be displayed as converted into euler angles.
+        /// Use this flag to force it to be displayed as a quaternion (4D value) with no conversion instead.
+        /// </summary>
+        AsQuaternion = 1 << 6,
     }
 
     /// <summary>

+ 19 - 0
Source/Scripting/MBansheeEngine/Serialization/AsQuaternion.cs

@@ -0,0 +1,19 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2010 Marko Pintera ([email protected]). All rights reserved. **********************//
+using System;
+
+namespace BansheeEngine
+{
+    /** @addtogroup Serialization
+     *  @{
+     */
+
+    /// <summary>
+    /// When a quaternion is displayed in the inspector, by default it will be displayed as converted into euler angles.
+    /// Use this attribute to force it to be displayed as a quaternion (4D value) with no conversion instead.
+    /// </summary>
+    [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)]
+    public sealed class AsQuaternion : Attribute { }
+
+    /** @} */
+}

+ 16 - 10
Source/Scripting/MBansheeEngine/Serialization/SerializableField.cs

@@ -17,54 +17,60 @@ namespace BansheeEngine
         /// <summary>
         /// Field will be automatically serialized.
         /// </summary>
-        Serializable  = 1 << 0,
+        Serializable        = 1 << 0,
 
         /// <summary>
         /// Field will be visible in the default inspector.
         /// </summary>
-        Inspectable   = 1 << 1,
+        Inspectable         = 1 << 1,
 
         /// <summary>
         /// Integer or floating point field with min/max range.
         /// </summary>
-        Ranged        = 1 << 2,
+        Ranged              = 1 << 2,
 
         /// <summary>
         /// Integer or floating point field with a minimum increment/decrement step.
         /// </summary>
-        Stepped       = 1 << 3,
+        Stepped             = 1 << 3,
 
         /// <summary>
         /// Field can be animated through the animation window.
         /// </summary>
-        Animable      = 1 << 4,
+        Animable            = 1 << 4,
 
         /// <summary>
         /// Integer field rendered as a layer selection dropdown.
         /// </summary>
-        LayerMask     = 1 << 5,
+        LayerMask           = 1 << 5,
 
         /// <summary>
         /// Field containing a reference type being passed by copy instead of by reference.
         /// </summary>
-        PassByCopy    = 1 << 6,
+        PassByCopy          = 1 << 6,
 
         /// <summary>
         /// Field containing a reference type that should never be null.
         /// </summary>
-        NotNull       = 1 << 7,
+        NotNull             = 1 << 7,
 
         /// <summary>
         /// Field represents a property that wraps a native object. Getters and setters of such a property issue calls into
         /// native code to update the native object.
         /// </summary>
-        NativeWrapper = 1 << 8,
+        NativeWrapper       = 1 << 8,
 
         /// <summary>
         /// When a field changes those changes need to be applied to the parent object by calling the field setter. Only
         /// applicable to properties containing reference types.
         /// </summary>
-        ApplyOnDirty = 1 << 9
+        ApplyOnDirty        = 1 << 9,
+
+        /// <summary>
+        /// When a quaternion is displayed in the inspector, by default it will be displayed as converted into euler angles.
+        /// Use this flag to force it to be displayed as a quaternion (4D value) with no conversion instead.
+        /// </summary>
+        DisplayAsQuaternion = 1 << 10
     }
 
     /// <summary>

+ 11 - 10
Source/Scripting/SBansheeEngine/Serialization/BsManagedSerializableObjectInfo.h

@@ -48,16 +48,17 @@ namespace bs
 	/**	Flags that are used to further define a field in a managed serializable object. */
 	enum class ScriptFieldFlag
 	{
-		Serializable  = 1 << 0,
-		Inspectable   = 1 << 1,
-		Range         = 1 << 2,
-		Step          = 1 << 3,
-		Animable      = 1 << 4,
-		LayerMask     = 1 << 5,
-		PassByCopy    = 1 << 6,
-		NotNull       = 1 << 7,
-		NativeWrapper = 1 << 8,
-		ApplyOnDirty  = 1 << 9
+		Serializable        = 1 << 0,
+		Inspectable         = 1 << 1,
+		Range               = 1 << 2,
+		Step                = 1 << 3,
+		Animable            = 1 << 4,
+		LayerMask           = 1 << 5,
+		PassByCopy          = 1 << 6,
+		NotNull             = 1 << 7,
+		NativeWrapper       = 1 << 8,
+		ApplyOnDirty        = 1 << 9,
+		DisplayAsQuaternion = 1 << 10
 	};
 
 	typedef Flags<ScriptFieldFlag> ScriptFieldFlags;

+ 10 - 0
Source/Scripting/SBansheeEngine/Serialization/BsScriptAssemblyManager.cpp

@@ -225,6 +225,9 @@ namespace bs
 					}
 				}
 
+				if (field->hasAttribute(mBuiltin.asQuaternionAttribute))
+					fieldInfo->mFlags |= ScriptFieldFlag::DisplayAsQuaternion;
+
 				if(field->hasAttribute(mBuiltin.notNullAttribute))
 					fieldInfo->mFlags |= ScriptFieldFlag::NotNull;
 
@@ -286,6 +289,9 @@ namespace bs
 						}
 					}
 
+					if (property->hasAttribute(mBuiltin.asQuaternionAttribute))
+						propertyInfo->mFlags |= ScriptFieldFlag::DisplayAsQuaternion;
+
 					if (property->hasAttribute(mBuiltin.notNullAttribute))
 						propertyInfo->mFlags |= ScriptFieldFlag::NotNull;
 
@@ -643,6 +649,10 @@ namespace bs
 		if (mBuiltin.layerMaskAttribute == nullptr)
 			BS_EXCEPT(InvalidStateException, "Cannot find LayerMask managed class.");
 
+		mBuiltin.asQuaternionAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "AsQuaternion");
+		if (mBuiltin.asQuaternionAttribute == nullptr)
+			BS_EXCEPT(InvalidStateException, "Cannot find AsQuaternion managed class.");
+
 		mBuiltin.nativeWrapperAttribute = bansheeEngineAssembly->getClass("BansheeEngine", "NativeWrapper");
 		if (mBuiltin.nativeWrapperAttribute == nullptr)
 			BS_EXCEPT(InvalidStateException, "Cannot find NativeWrapper managed class.");

+ 1 - 0
Source/Scripting/SBansheeEngine/Serialization/BsScriptAssemblyManager.h

@@ -42,6 +42,7 @@ namespace bs
 		MonoClass* notNullAttribute = nullptr;
 		MonoClass* passByCopyAttribute = nullptr;
 		MonoClass* applyOnDirtyAttribute = nullptr;
+		MonoClass* asQuaternionAttribute = nullptr;
 	};
 
 	/**	Stores data about managed serializable objects in specified assemblies. */