Sfoglia il codice sorgente

Added a way to attach animation events to imported animation clips

BearishSun 9 anni fa
parent
commit
17bd614ff6

+ 2 - 1
Source/BansheeCore/Include/BsCorePrerequisites.h

@@ -528,7 +528,8 @@ namespace BansheeEngine
 		TID_SkeletonBoneInfo = 1120,
 		TID_AnimationSplitInfo = 1121,
 		TID_CAnimation = 1122,
-		TID_AnimationEvent = 1123
+		TID_AnimationEvent = 1123,
+		TID_ImportedAnimationEvents = 1124
 	};
 }
 

+ 26 - 1
Source/BansheeCore/Include/BsMeshImportOptions.h

@@ -4,6 +4,7 @@
 
 #include "BsCorePrerequisites.h"
 #include "BsImportOptions.h"
+#include "BsAnimationClip.h"
 
 namespace BansheeEngine
 {
@@ -38,6 +39,23 @@ namespace BansheeEngine
 		RTTITypeBase* getRTTI() const override;
 	};
 
+	/** A set of animation events that will be added to an animation clip during animation import. */
+	struct BS_CORE_EXPORT ImportedAnimationEvents : IReflectable
+	{
+		ImportedAnimationEvents() { }
+
+		String name;
+		Vector<AnimationEvent> events;
+
+		/************************************************************************/
+		/* 								SERIALIZATION                      		*/
+		/************************************************************************/
+	public:
+		friend class ImportedAnimationEventsRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		RTTITypeBase* getRTTI() const override;
+	};
+
 	/**
 	 * Contains import options you may use to control how is a mesh imported from some external format into engine format.
 	 */
@@ -107,9 +125,15 @@ namespace BansheeEngine
 		 */
 		void setAnimationClipSplits(const Vector<AnimationSplitInfo>& splitInfos) { mAnimationSplits = splitInfos; }
 
-		/** Returns a copy of the animation splits array. */
+		/** Returns a copy of the animation splits array. @see setAnimationClipSplits. */
 		Vector<AnimationSplitInfo> getAnimationClipSplits() const { return mAnimationSplits; }
 
+		/** Assigns a set of events that will be added to the animation clip, if animation import is enabled. */
+		void setAnimationEvents(const Vector<ImportedAnimationEvents>& events) { mAnimationEvents = events; }
+
+		/** Returns a copy of the animation events array. @see setAnimationEvents. */
+		Vector<ImportedAnimationEvents> getAnimationEvents() const { return mAnimationEvents; }
+
 		/**	
 		 * Enables or disabled keyframe reduction. Keyframe reduction will reduce the number of key-frames in an animation
 		 * clip by removing identical keyframes, and therefore reducing the size of the clip.
@@ -134,6 +158,7 @@ namespace BansheeEngine
 		float mImportScale;
 		CollisionMeshType mCollisionMeshType;
 		Vector<AnimationSplitInfo> mAnimationSplits;
+		Vector<ImportedAnimationEvents> mAnimationEvents;
 
 		/************************************************************************/
 		/* 								SERIALIZATION                      		*/

+ 32 - 1
Source/BansheeCore/Include/BsMeshImportOptionsRTTI.h

@@ -5,6 +5,7 @@
 #include "BsCorePrerequisites.h"
 #include "BsRTTIType.h"
 #include "BsMeshImportOptions.h"
+#include "BsAnimationClipRTTI.h"
 
 namespace BansheeEngine
 {
@@ -27,6 +28,7 @@ namespace BansheeEngine
 			BS_RTTI_MEMBER_PLAIN(mCollisionMeshType, 7)
 			BS_RTTI_MEMBER_REFL_ARRAY(mAnimationSplits, 8)
 			BS_RTTI_MEMBER_PLAIN(mReduceKeyFrames, 9)
+			BS_RTTI_MEMBER_REFL_ARRAY(mAnimationEvents, 10)
 		BS_END_RTTI_MEMBERS
 	public:
 		MeshImportOptionsRTTI()
@@ -50,6 +52,35 @@ namespace BansheeEngine
 		}
 	};
 
+	class BS_CORE_EXPORT ImportedAnimationEventsRTTI : public RTTIType <ImportedAnimationEvents, IReflectable, ImportedAnimationEventsRTTI>
+	{
+	private:
+		BS_BEGIN_RTTI_MEMBERS
+			BS_RTTI_MEMBER_PLAIN(name, 0)
+			BS_RTTI_MEMBER_PLAIN(events, 1)
+		BS_END_RTTI_MEMBERS
+	public:
+		ImportedAnimationEventsRTTI()
+			:mInitMembers(this)
+		{ }
+
+		const String& getRTTIName() override
+		{
+			static String name = "ImportedAnimationEvents";
+			return name;
+		}
+
+		UINT32 getRTTIId() override
+		{
+			return TID_ImportedAnimationEvents;
+		}
+
+		SPtr<IReflectable> newRTTIObject() override
+		{
+			return bs_shared_ptr_new<ImportedAnimationEvents>();
+		}
+	};
+
 	class BS_CORE_EXPORT AnimationSplitInfoRTTI : public RTTIType <AnimationSplitInfo, IReflectable, AnimationSplitInfoRTTI>
 	{
 	private:
@@ -58,7 +89,7 @@ namespace BansheeEngine
 			BS_RTTI_MEMBER_PLAIN(startFrame, 1)
 			BS_RTTI_MEMBER_PLAIN(endFrame, 2)
 			BS_RTTI_MEMBER_PLAIN(isAdditive, 3)
-		BS_END_RTTI_MEMBERS
+			BS_END_RTTI_MEMBERS
 	public:
 		AnimationSplitInfoRTTI()
 			:mInitMembers(this)

+ 10 - 6
Source/BansheeCore/Source/BsMeshImportOptions.cpp

@@ -5,9 +5,6 @@
 
 namespace BansheeEngine
 {
-	/************************************************************************/
-	/* 								SERIALIZATION                      		*/
-	/************************************************************************/
 	RTTITypeBase* AnimationSplitInfo::getRTTIStatic()
 	{
 		return AnimationSplitInfoRTTI::instance();
@@ -18,14 +15,21 @@ namespace BansheeEngine
 		return AnimationSplitInfo::getRTTIStatic();
 	}
 
+	RTTITypeBase* ImportedAnimationEvents::getRTTIStatic()
+	{
+		return ImportedAnimationEventsRTTI::instance();
+	}
+
+	RTTITypeBase* ImportedAnimationEvents::getRTTI() const
+	{
+		return ImportedAnimationEvents::getRTTIStatic();
+	}
+
 	MeshImportOptions::MeshImportOptions()
 		: mCPUReadable(false), mImportNormals(true), mImportTangents(true), mImportBlendShapes(false), mImportSkin(false)
 		, mImportAnimation(false), mReduceKeyFrames(true), mImportScale(1.0f), mCollisionMeshType(CollisionMeshType::None)
 	{ }
 
-	/************************************************************************/
-	/* 								SERIALIZATION                      		*/
-	/************************************************************************/
 	RTTITypeBase* MeshImportOptions::getRTTIStatic()
 	{
 		return MeshImportOptionsRTTI::instance();

+ 10 - 0
Source/BansheeFBXImporter/Source/BsFBXImporter.cpp

@@ -175,9 +175,19 @@ namespace BansheeEngine
 				}
 			}
 
+			Vector<ImportedAnimationEvents> events = meshImportOptions->getAnimationEvents();
 			for(auto& entry : animationClips)
 			{
 				SPtr<AnimationClip> clip = AnimationClip::_createPtr(entry.curves, entry.isAdditive);
+				
+				for(auto& eventsEntry : events)
+				{
+					if(entry.name == eventsEntry.name)
+					{
+						clip->setEvents(eventsEntry.events);
+						break;
+					}
+				}
 
 				output.push_back({ toWString(entry.name), clip });
 			}

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

@@ -131,6 +131,15 @@ namespace BansheeEditor
         public int endFrame = 0;
         public bool isAdditive = false;
     }
+
+    /// <summary>
+    /// A set of animation events that will be added to an animation clip during animation import.
+    /// </summary>
+    public class ImportedAnimationEvents
+    {
+        public string name;
+        public AnimationEvent[] events;
+    }
     
     /// <summary>
     /// Provides options for controlling how is a mesh resource imported.
@@ -238,6 +247,15 @@ namespace BansheeEditor
             set { Internal_SetAnimationClipSplits(mCachedPtr, value); }
         }
 
+        /// <summary>
+        /// A set of events that will be added to the animation clip, if animation import is enabled.
+        /// </summary>
+        public ImportedAnimationEvents[] AnimationEvents
+        {
+            get { return Internal_GetAnimationEvents(mCachedPtr); }
+            set { Internal_SetAnimationEvents(mCachedPtr, value); }
+        }
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_CreateInstance(MeshImportOptions instance);
 
@@ -289,6 +307,12 @@ namespace BansheeEditor
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern void Internal_SetAnimationClipSplits(IntPtr thisPtr, AnimationSplitInfo[] value);
 
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern ImportedAnimationEvents[] Internal_GetAnimationEvents(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetAnimationEvents(IntPtr thisPtr, ImportedAnimationEvents[] value);
+
         [MethodImpl(MethodImplOptions.InternalCall)]
         private static extern float Internal_GetScale(IntPtr thisPtr);
 

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

@@ -120,6 +120,8 @@ namespace BansheeEngine
 		static void internal_SetCollisionMeshType(ScriptMeshImportOptions* thisPtr, int value);
 		static MonoArray* internal_GetAnimationClipSplits(ScriptMeshImportOptions* thisPtr);
 		static void internal_SetAnimationClipSplits(ScriptMeshImportOptions* thisPtr, MonoArray* value);
+		static MonoArray* internal_GetAnimationEvents(ScriptMeshImportOptions* thisPtr);
+		static void internal_SetAnimationEvents(ScriptMeshImportOptions* thisPtr, MonoArray* value);
 	};
 
 	/**	Interop class between C++ & CLR for FontImportOptions. */
@@ -243,5 +245,27 @@ namespace BansheeEngine
 		static MonoField* isAdditiveField;
 	};
 
+	/** Helper class for dealing with ImportedAnimationEvents structure. */
+	class BS_SCR_BED_EXPORT ScriptImportedAnimationEvents : public ScriptObject<ScriptImportedAnimationEvents>
+	{
+	public:
+		SCRIPT_OBJ(EDITOR_ASSEMBLY, "BansheeEditor", "ImportedAnimationEvents")
+
+		/** Converts managed events info to its native counterpart. */
+		static ImportedAnimationEvents fromManaged(MonoObject* object);
+
+		/** Converts native events info to its managed counterpart. */
+		static MonoObject* toManaged(const ImportedAnimationEvents& events);
+
+	private:
+		ScriptImportedAnimationEvents(MonoObject* instance);
+
+		/************************************************************************/
+		/* 								CLR HOOKS						   		*/
+		/************************************************************************/
+		static MonoField* nameField;
+		static MonoField* eventsField;
+	};
+
 	/** @} */
 }

+ 88 - 0
Source/SBansheeEditor/Source/BsScriptImportOptions.cpp

@@ -14,6 +14,7 @@
 #include "BsRenderer.h"
 #include "BsScriptFont.h"
 #include "BsRTTIType.h"
+#include "BsScriptAnimationClip.h"
 
 using namespace std::placeholders;
 
@@ -328,6 +329,33 @@ namespace BansheeEngine
 		io->setAnimationClipSplits(splitInfos);
 	}
 
+	MonoArray* ScriptMeshImportOptions::internal_GetAnimationEvents(ScriptMeshImportOptions* thisPtr)
+	{
+		SPtr<MeshImportOptions> io = thisPtr->getMeshImportOptions();
+
+		Vector<ImportedAnimationEvents> animationEvents = io->getAnimationEvents();
+		UINT32 count = (UINT32)animationEvents.size();
+		ScriptArray outputArray = ScriptArray::create<ScriptImportedAnimationEvents>(count);
+		for (UINT32 i = 0; i < count; i++)
+			outputArray.set(i, ScriptImportedAnimationEvents::toManaged(animationEvents[i]));
+
+		return outputArray.getInternal();
+	}
+
+	void ScriptMeshImportOptions::internal_SetAnimationEvents(ScriptMeshImportOptions* thisPtr, MonoArray* value)
+	{
+		ScriptArray inputArray(value);
+
+		SPtr<MeshImportOptions> io = thisPtr->getMeshImportOptions();
+
+		UINT32 count = inputArray.size();
+		Vector<ImportedAnimationEvents> animationEvents(count);
+		for (UINT32 i = 0; i < count; i++)
+			animationEvents[i] = ScriptImportedAnimationEvents::fromManaged(inputArray.get<MonoObject*>(i));
+
+		io->setAnimationEvents(animationEvents);
+	}
+
 	ScriptFontImportOptions::ScriptFontImportOptions(MonoObject* instance)
 		:ScriptObject(instance)
 	{
@@ -646,4 +674,64 @@ namespace BansheeEngine
 		void* params[4] = { monoString, &startFrame, &endFrame, &isAdditive };
 		return metaData.scriptClass->createInstance("string, int, int, bool", params);
 	}
+
+	MonoField* ScriptImportedAnimationEvents::nameField = nullptr;
+	MonoField* ScriptImportedAnimationEvents::eventsField = nullptr;
+
+	ScriptImportedAnimationEvents::ScriptImportedAnimationEvents(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptImportedAnimationEvents::initRuntimeData()
+	{
+		nameField = metaData.scriptClass->getField("name");
+		eventsField = metaData.scriptClass->getField("events");
+	}
+
+	ImportedAnimationEvents ScriptImportedAnimationEvents::fromManaged(MonoObject* instance)
+	{
+		ImportedAnimationEvents output;
+
+		MonoString* monoName = nullptr;
+		nameField->getValue(instance, &monoName);
+
+		output.name = MonoUtil::monoToString(monoName);
+
+		MonoArray* monoEvents;
+		eventsField->getValue(instance, &monoEvents);
+
+		if (monoEvents != nullptr)
+		{
+			ScriptArray scriptEvents(monoEvents);
+			for (UINT32 i = 0; i < scriptEvents.size(); i++)
+			{
+				MonoObject* monoEvent = scriptEvents.get<MonoObject*>(i);
+				AnimationEvent event = ScriptAnimationEvent::toNative(monoEvent);
+
+				output.events.push_back(event);
+			}
+		}
+
+		return output;
+	}
+
+	MonoObject* ScriptImportedAnimationEvents::toManaged(const ImportedAnimationEvents& events)
+	{
+		MonoString* monoString = MonoUtil::stringToMono(events.name);
+		
+		UINT32 numEvents = (UINT32)events.events.size();
+		ScriptArray scriptEvents = ScriptArray::create<ScriptAnimationEvent>(numEvents);
+
+		for (UINT32 i = 0; i < numEvents; i++)
+		{
+			MonoObject* monoEvent = ScriptAnimationEvent::toManaged(events.events[i]);
+			scriptEvents.set(i, monoEvent);
+		}
+
+		MonoObject* instance = metaData.scriptClass->createInstance();
+		nameField->setValue(instance, monoString);
+		eventsField->setValue(instance, scriptEvents.getInternal());
+
+		return instance;
+	}
 }