فهرست منبع

Added animation splits array to the C# mesh import options

BearishSun 9 سال پیش
والد
کامیت
737e9a54b9

+ 5 - 14
Source/BansheeCore/Include/BsMeshImportOptions.h

@@ -19,8 +19,8 @@ namespace BansheeEngine
 		Convex /**< A convex hull will be generated from the source mesh. */
 	};
 
-	/** Contains information about a piece of imported animation that will be used for generating its own AnimationClip. */
-	struct AnimationSplitInfo : IReflectable
+	/** Information about how to split an AnimationClip into multiple separate clips. */
+	struct BS_CORE_EXPORT AnimationSplitInfo : IReflectable
 	{
 		AnimationSplitInfo() { }
 
@@ -101,20 +101,11 @@ namespace BansheeEngine
 		CollisionMeshType getCollisionMeshType() const { return mCollisionMeshType; }
 
 		/** 
-		 * Registers an animation split info that determines how will the source animation clip be split. If not splits
+		 * Registers animation split infos that determine how will the source animation clip be split. If no splits
 		 * are present the data will be imported as one clip, but if splits are present the data will be split according
-		 * to the split infos.
+		 * to the split infos. Split infos only affect the primary animation clip, other clips will not be split.
 		 */
-		void addAnimationClipSplit(const AnimationSplitInfo& splitInfo) { mAnimationSplits.push_back(splitInfo); }
-
-		/** Returns in how many pieces should the imported animation clip be split info. */
-		UINT32 getNumAnimationClipSplits() const { return (UINT32)mAnimationSplits.size(); }
-
-		/** Returns information about an animation split at the specified index. */
-		const AnimationSplitInfo& getAnimationClipSplit(UINT32 idx) const { return mAnimationSplits[idx]; }
-
-		/** Removes an animation split info at the specified index. */
-		void removeAnimationClipSplit(UINT32 idx) { mAnimationSplits.erase(mAnimationSplits.begin() + idx); }
+		void setAnimationClipSplits(const Vector<AnimationSplitInfo>& splitInfos) { mAnimationSplits = splitInfos; }
 
 		/** Returns a copy of the animation splits array. */
 		Vector<AnimationSplitInfo> getAnimationClipSplits() const { return mAnimationSplits; }

+ 2 - 2
Source/MBansheeEditor/Inspectors/FontInspector.cs

@@ -188,7 +188,7 @@ namespace BansheeEditor
             }
 
             /// <inheritdoc/>
-            internal protected override InspectableState Refresh()
+            protected internal override InspectableState Refresh()
             {
                 sizeField.Value = GetValue<int>();
 
@@ -243,7 +243,7 @@ namespace BansheeEditor
             }
 
             /// <inheritdoc/>
-            internal protected override InspectableState Refresh()
+            protected internal override InspectableState Refresh()
             {
                 CharRange newValue = GetValue<CharRange>();
                 rangeStartField.Value = newValue.start;

+ 163 - 34
Source/MBansheeEditor/Inspectors/MeshInspector.cs

@@ -15,15 +15,16 @@ namespace BansheeEditor
     [CustomInspector(typeof(Mesh))]
     internal class MeshInspector : Inspector
     {
-        private GUIToggleField normalsField = new GUIToggleField(new LocEdString("Import Normals"));
-        private GUIToggleField tangentsField = new GUIToggleField(new LocEdString("Import Tangents"));
-        private GUIToggleField skinField = new GUIToggleField(new LocEdString("Import Skin"));
-        private GUIToggleField blendShapesField = new GUIToggleField(new LocEdString("Import Blend Shapes"));
-        private GUIToggleField animationField = new GUIToggleField(new LocEdString("Import Animation"));
-        private GUIFloatField scaleField = new GUIFloatField(new LocEdString("Scale"));
-        private GUIToggleField cpuReadableField = new GUIToggleField(new LocEdString("CPU readable"));
-        private GUIEnumField collisionMeshTypeField = new GUIEnumField(typeof(CollisionMeshType), new LocEdString("Collision mesh"));
-        private GUIButton reimportButton = new GUIButton(new LocEdString("Reimport"));
+        private GUIToggleField normalsField;
+        private GUIToggleField tangentsField;
+        private GUIToggleField skinField;
+        private GUIToggleField blendShapesField;
+        private GUIToggleField animationField;
+        private GUIFloatField scaleField;
+        private GUIToggleField cpuReadableField;
+        private GUIEnumField collisionMeshTypeField;
+        private GUIArrayField<AnimationSplitInfo, AnimSplitArrayRow> animSplitInfoField;
+        private GUIButton reimportButton;
 
         private MeshImportOptions importOptions;
 
@@ -33,31 +34,7 @@ namespace BansheeEditor
             if (InspectedObject != null)
             {
                 importOptions = GetImportOptions();
-
-                normalsField.OnChanged += x => importOptions.ImportNormals = x;
-                tangentsField.OnChanged += x => importOptions.ImportTangents = x;
-                skinField.OnChanged += x => importOptions.ImportSkin = x;
-                blendShapesField.OnChanged += x => importOptions.ImportBlendShapes = x;
-                animationField.OnChanged += x => importOptions.ImportAnimation = x;
-                scaleField.OnChanged += x => importOptions.Scale = x;
-                cpuReadableField.OnChanged += x => importOptions.CPUReadable = x;
-                collisionMeshTypeField.OnSelectionChanged += x => importOptions.CollisionMeshType = (CollisionMeshType)x;
-
-                reimportButton.OnClick += TriggerReimport;
-
-                Layout.AddElement(normalsField);
-                Layout.AddElement(tangentsField);
-                Layout.AddElement(skinField);
-                Layout.AddElement(blendShapesField);
-                Layout.AddElement(animationField);
-                Layout.AddElement(scaleField);
-                Layout.AddElement(cpuReadableField);
-                Layout.AddElement(collisionMeshTypeField);
-                Layout.AddSpace(10);
-
-                GUILayout reimportButtonLayout = Layout.AddLayoutX();
-                reimportButtonLayout.AddFlexibleSpace();
-                reimportButtonLayout.AddElement(reimportButton);
+                BuildGUI();
             }
         }
 
@@ -66,6 +43,24 @@ namespace BansheeEditor
         {
             MeshImportOptions newImportOptions = GetImportOptions();
 
+            bool rebuildGUI = false;
+
+            AnimationSplitInfo[] splitInfos = newImportOptions.AnimationClipSplits;
+            if (splitInfos == null)
+                rebuildGUI |= animSplitInfoField.Array != null;
+            else
+            {
+                if (animSplitInfoField.Array == null)
+                    rebuildGUI = true;
+                else
+                    rebuildGUI |= splitInfos.Length != animSplitInfoField.Array.GetLength(0);
+            }
+
+            if (rebuildGUI)
+                BuildGUI();
+
+            animSplitInfoField.Refresh();
+
             normalsField.Value = newImportOptions.ImportNormals;
             tangentsField.Value = newImportOptions.ImportTangents;
             skinField.Value = newImportOptions.ImportSkin;
@@ -80,6 +75,55 @@ namespace BansheeEditor
             return InspectableState.NotModified;
         }
 
+        /// <summary>
+        /// Recreates all the GUI elements used by this inspector.
+        /// </summary>
+        private void BuildGUI()
+        {
+            Layout.Clear();
+
+            normalsField = new GUIToggleField(new LocEdString("Import Normals"));
+            tangentsField = new GUIToggleField(new LocEdString("Import Tangents"));
+            skinField = new GUIToggleField(new LocEdString("Import Skin"));
+            blendShapesField = new GUIToggleField(new LocEdString("Import Blend Shapes"));
+            animationField = new GUIToggleField(new LocEdString("Import Animation"));
+            scaleField = new GUIFloatField(new LocEdString("Scale"));
+            cpuReadableField = new GUIToggleField(new LocEdString("CPU readable"));
+            collisionMeshTypeField = new GUIEnumField(typeof(CollisionMeshType), new LocEdString("Collision mesh"));
+            reimportButton = new GUIButton(new LocEdString("Reimport"));
+
+            normalsField.OnChanged += x => importOptions.ImportNormals = x;
+            tangentsField.OnChanged += x => importOptions.ImportTangents = x;
+            skinField.OnChanged += x => importOptions.ImportSkin = x;
+            blendShapesField.OnChanged += x => importOptions.ImportBlendShapes = x;
+            animationField.OnChanged += x => importOptions.ImportAnimation = x;
+            scaleField.OnChanged += x => importOptions.Scale = x;
+            cpuReadableField.OnChanged += x => importOptions.CPUReadable = x;
+            collisionMeshTypeField.OnSelectionChanged += x => importOptions.CollisionMeshType = (CollisionMeshType)x;
+
+            reimportButton.OnClick += TriggerReimport;
+
+            Layout.AddElement(normalsField);
+            Layout.AddElement(tangentsField);
+            Layout.AddElement(skinField);
+            Layout.AddElement(blendShapesField);
+            Layout.AddElement(animationField);
+            Layout.AddElement(scaleField);
+            Layout.AddElement(cpuReadableField);
+            Layout.AddElement(collisionMeshTypeField);
+
+            animSplitInfoField = GUIArrayField<AnimationSplitInfo, AnimSplitArrayRow>.Create(
+                new LocEdString("Animation splits"), importOptions.AnimationClipSplits, Layout);
+            animSplitInfoField.OnChanged += x => importOptions.AnimationClipSplits = x;
+            animSplitInfoField.IsExpanded = Persistent.GetBool("animSplitInfos_Expanded");
+            animSplitInfoField.OnExpand += x => Persistent.SetBool("animSplitInfos_Expanded", x);
+
+            Layout.AddSpace(10);
+
+            GUILayout reimportButtonLayout = Layout.AddLayoutX();
+            reimportButtonLayout.AddFlexibleSpace();
+            reimportButtonLayout.AddElement(reimportButton); 
+        }
 
         /// <summary>
         /// Retrieves import options for the mesh we're currently inspecting.
@@ -121,6 +165,91 @@ namespace BansheeEditor
 
             ProjectLibrary.Reimport(resourcePath, importOptions, true);
         }
+
+        /// <summary>
+        /// Row element used for displaying GUI for animation clip split information.
+        /// </summary>
+        private class AnimSplitArrayRow : GUIListFieldRow
+        {
+            private GUITextField nameField;
+            private GUIIntField startFrameField;
+            private GUIIntField endFrameField;
+            private GUIToggleField isAdditiveField;
+
+            /// <inheritdoc/>
+            protected override GUILayoutX CreateGUI(GUILayoutY layout)
+            {
+                GUILayoutX titleLayout = layout.AddLayoutX();
+                nameField = new GUITextField(new LocEdString("Name"));
+                startFrameField = new GUIIntField(new LocEdString("Start"));
+                endFrameField = new GUIIntField(new LocEdString("End"));
+                isAdditiveField = new GUIToggleField(new LocEdString("Is additive"));
+
+                startFrameField.SetRange(0, int.MaxValue);
+                endFrameField.SetRange(0, int.MaxValue);
+
+                titleLayout.AddElement(nameField);
+                titleLayout.AddElement(startFrameField);
+                titleLayout.AddElement(endFrameField);
+                titleLayout.AddElement(isAdditiveField);
+
+                nameField.OnChanged += x =>
+                {
+                    AnimationSplitInfo splitInfo = GetValue<AnimationSplitInfo>();
+                    splitInfo.name = x;
+ 
+                    MarkAsModified();
+                };
+
+                nameField.OnFocusLost += ConfirmModify;
+                nameField.OnConfirmed += ConfirmModify;
+
+                startFrameField.OnChanged += x =>
+                {
+                    AnimationSplitInfo splitInfo = GetValue<AnimationSplitInfo>();
+                    splitInfo.startFrame = x;
+
+                    MarkAsModified();
+                };
+
+                startFrameField.OnFocusLost += ConfirmModify;
+                startFrameField.OnConfirmed += ConfirmModify;
+
+                endFrameField.OnChanged += x =>
+                {
+                    AnimationSplitInfo splitInfo = GetValue<AnimationSplitInfo>();
+                    splitInfo.endFrame = x;
+
+                    MarkAsModified();
+                };
+
+                endFrameField.OnFocusLost += ConfirmModify;
+                endFrameField.OnConfirmed += ConfirmModify;
+
+                isAdditiveField.OnChanged += x =>
+                {
+                    AnimationSplitInfo splitInfo = GetValue<AnimationSplitInfo>();
+                    splitInfo.isAdditive = x;
+
+                    MarkAsModified();
+                    ConfirmModify();
+                };
+
+                return titleLayout;
+            }
+
+            /// <inheritdoc/>
+            protected internal override InspectableState Refresh()
+            {
+                AnimationSplitInfo splitInfo = GetValue<AnimationSplitInfo>();
+                nameField.Value = splitInfo.name;
+                startFrameField.Value = splitInfo.startFrame;
+                endFrameField.Value = splitInfo.endFrame;
+                isAdditiveField.Value = splitInfo.isAdditive;
+
+                return base.Refresh();
+            }
+        }
     }
 
     /** @} */

+ 38 - 0
Source/MBansheeEditor/Windows/Library/ImportOptions.cs

@@ -111,6 +111,27 @@ namespace BansheeEditor
         private static extern void Internal_SetIsSRGB(IntPtr thisPtr, bool value);
     }
 
+    /// <summary>
+    /// Information about how to split an AnimationClip into multiple separate clips.
+    /// </summary>
+    public class AnimationSplitInfo
+    {
+        public AnimationSplitInfo() { }
+
+        public AnimationSplitInfo(string name, int startFrame, int endFrame, bool isAdditive)
+        {
+            this.name = name;
+            this.startFrame = startFrame;
+            this.endFrame = endFrame;
+            this.isAdditive = isAdditive;
+        }
+
+        public string name;
+        public int startFrame = 0;
+        public int endFrame = 0;
+        public bool isAdditive = false;
+    }
+    
     /// <summary>
     /// Provides options for controlling how is a mesh resource imported.
     /// </summary>
@@ -196,6 +217,17 @@ namespace BansheeEditor
             set { Internal_SetCollisionMeshType(mCachedPtr, (int)value); }
         }
 
+        /// <summary>
+        /// Split information that allows you to split the animation clip contained in the mesh file into multiple separate
+        /// clips. The split always applies to the first clip in the file (if the file contains multiple), other clips are
+        /// imported as is.
+        /// </summary>
+        public AnimationSplitInfo[] AnimationClipSplits
+        {
+            get { return Internal_GetAnimationClipSplits(mCachedPtr); }
+            set { Internal_SetAnimationClipSplits(mCachedPtr, value); }
+        }
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_CreateInstance(MeshImportOptions instance);
 
@@ -235,6 +267,12 @@ namespace BansheeEditor
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetImportBlendShapes(IntPtr thisPtr, bool value);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern AnimationSplitInfo[] Internal_GetAnimationClipSplits(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetAnimationClipSplits(IntPtr thisPtr, AnimationSplitInfo[] value);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern float Internal_GetScale(IntPtr thisPtr);
 

+ 27 - 0
Source/SBansheeEditor/Include/BsScriptImportOptions.h

@@ -6,6 +6,7 @@
 #include "BsScriptObject.h"
 #include "BsPixelData.h"
 #include "BsAudioClipImportOptions.h"
+#include "BsMeshImportOptions.h"
 #include "BsGpuProgram.h"
 
 namespace BansheeEngine
@@ -115,6 +116,8 @@ namespace BansheeEngine
 		static void internal_SetScale(ScriptMeshImportOptions* thisPtr, float value);
 		static int internal_GetCollisionMeshType(ScriptMeshImportOptions* thisPtr);
 		static void internal_SetCollisionMeshType(ScriptMeshImportOptions* thisPtr, int value);
+		static MonoArray* internal_GetAnimationClipSplits(ScriptMeshImportOptions* thisPtr);
+		static void internal_SetAnimationClipSplits(ScriptMeshImportOptions* thisPtr, MonoArray* value);
 	};
 
 	/**	Interop class between C++ & CLR for FontImportOptions. */
@@ -214,5 +217,29 @@ namespace BansheeEngine
 		static void internal_SetBitDepth(ScriptAudioClipImportOptions* thisPtr, UINT32 bitDepth);
 	};
 
+	/** Helper class for dealing with AnimationSplitInfo structure. */
+	class ScriptAnimationSplitInfo : public ScriptObject<ScriptAnimationSplitInfo>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "AnimationSplitInfo")
+
+		/** Converts managed split info to its native counterpart. */
+		static AnimationSplitInfo fromManaged(MonoObject* object);
+
+		/** Converts native split info to its managed counterpart. */
+		static MonoObject* toManaged(const AnimationSplitInfo& splitInfo);
+
+	private:
+		ScriptAnimationSplitInfo(MonoObject* instance);
+
+		/************************************************************************/
+		/* 								CLR HOOKS						   		*/
+		/************************************************************************/
+		static MonoField* nameField;
+		static MonoField* startFrameField;
+		static MonoField* endFrameField;
+		static MonoField* isAdditiveField;
+	};
+
 	/** @} */
 }

+ 76 - 3
Source/SBansheeEditor/Source/BsScriptImportOptions.cpp

@@ -28,7 +28,7 @@ namespace BansheeEngine
 		:ScriptObjectBase(instance)
 	{ }
 
-	void ScriptImportOptions::initRuntimeData() 
+	void ScriptImportOptions::initRuntimeData()
 	{ }
 
 	MonoObject* ScriptImportOptions::create(const SPtr<ImportOptions>& importOptions)
@@ -57,12 +57,12 @@ namespace BansheeEngine
 
 	ScriptImportOptions::ScriptImportOptions(MonoObject* instance)
 		:ScriptObject(instance)
-	{ 
+	{
 		mImportOptions = bs_shared_ptr_new<ImportOptions>();
 	}
 
 	ScriptTextureImportOptions::ScriptTextureImportOptions(MonoObject* instance)
-		:ScriptObject(instance)
+		: ScriptObject(instance)
 	{
 		mImportOptions = bs_shared_ptr_new<TextureImportOptions>();
 	}
@@ -181,6 +181,8 @@ namespace BansheeEngine
 		metaData.scriptClass->addInternalCall("Internal_SetScale", &ScriptMeshImportOptions::internal_SetScale);
 		metaData.scriptClass->addInternalCall("Internal_GetCollisionMeshType", &ScriptMeshImportOptions::internal_GetCollisionMeshType);
 		metaData.scriptClass->addInternalCall("Internal_SetCollisionMeshType", &ScriptMeshImportOptions::internal_SetCollisionMeshType);
+		metaData.scriptClass->addInternalCall("Internal_GetAnimationClipSplits", &ScriptMeshImportOptions::internal_GetAnimationClipSplits);
+		metaData.scriptClass->addInternalCall("Internal_SetAnimationClipSplits", &ScriptMeshImportOptions::internal_SetAnimationClipSplits);
 	}
 
 	SPtr<MeshImportOptions> ScriptMeshImportOptions::getMeshImportOptions()
@@ -287,6 +289,33 @@ namespace BansheeEngine
 		thisPtr->getMeshImportOptions()->setCollisionMeshType((CollisionMeshType)value);
 	}
 
+	MonoArray* ScriptMeshImportOptions::internal_GetAnimationClipSplits(ScriptMeshImportOptions* thisPtr)
+	{
+		SPtr<MeshImportOptions> io = thisPtr->getMeshImportOptions();
+
+		Vector<AnimationSplitInfo> splitInfos = io->getAnimationClipSplits();
+		UINT32 numSplitInfos = (UINT32)splitInfos.size();
+		ScriptArray outputArray = ScriptArray::create<ScriptAnimationSplitInfo>(numSplitInfos);
+		for(UINT32 i = 0; i < numSplitInfos; i++)
+			outputArray.set(i, ScriptAnimationSplitInfo::toManaged(splitInfos[i]));
+
+		return outputArray.getInternal();
+	}
+
+	void ScriptMeshImportOptions::internal_SetAnimationClipSplits(ScriptMeshImportOptions* thisPtr, MonoArray* value)
+	{
+		ScriptArray inputArray(value);
+
+		SPtr<MeshImportOptions> io = thisPtr->getMeshImportOptions();
+
+		UINT32 numSplits = inputArray.size();
+		Vector<AnimationSplitInfo> splitInfos(numSplits);
+		for (UINT32 i = 0; i < numSplits; i++)
+			splitInfos[i] = ScriptAnimationSplitInfo::fromManaged(inputArray.get<MonoObject*>(i));
+
+		io->setAnimationClipSplits(splitInfos);
+	}
+
 	ScriptFontImportOptions::ScriptFontImportOptions(MonoObject* instance)
 		:ScriptObject(instance)
 	{
@@ -561,4 +590,48 @@ namespace BansheeEngine
 		auto io = thisPtr->getClipImportOptions();
 		io->setBitDepth(bitDepth);
 	}
+
+	MonoField* ScriptAnimationSplitInfo::nameField = nullptr;
+	MonoField* ScriptAnimationSplitInfo::startFrameField = nullptr;
+	MonoField* ScriptAnimationSplitInfo::endFrameField = nullptr;
+	MonoField* ScriptAnimationSplitInfo::isAdditiveField = nullptr;
+
+	ScriptAnimationSplitInfo::ScriptAnimationSplitInfo(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptAnimationSplitInfo::initRuntimeData()
+	{
+		nameField = metaData.scriptClass->getField("name");
+		startFrameField = metaData.scriptClass->getField("startFrame");
+		endFrameField = metaData.scriptClass->getField("endFrame");
+		isAdditiveField = metaData.scriptClass->getField("isAdditive");
+	}
+
+	AnimationSplitInfo ScriptAnimationSplitInfo::fromManaged(MonoObject* instance)
+	{
+		AnimationSplitInfo output;
+
+		MonoString* monoName = nullptr;
+		nameField->getValue(instance, &monoName);
+
+		output.name = MonoUtil::monoToString(monoName);
+
+		startFrameField->getValue(instance, &output.startFrame);
+		endFrameField->getValue(instance, &output.endFrame);
+		isAdditiveField->getValue(instance, &output.isAdditive);
+
+		return output;
+	}
+
+	MonoObject* ScriptAnimationSplitInfo::toManaged(const AnimationSplitInfo& splitInfo)
+	{
+		MonoString* monoString = MonoUtil::stringToMono(splitInfo.name);
+		UINT32 startFrame = splitInfo.startFrame;
+		UINT32 endFrame = splitInfo.endFrame;
+		bool isAdditive = splitInfo.isAdditive;
+
+		void* params[4] = { monoString, &startFrame, &endFrame, &isAdditive };
+		return metaData.scriptClass->createInstance("string, int, int, bool", params);
+	}
 }