Browse Source

Added Animation component
Hooked up Animatiom to Renderable

BearishSun 9 years ago
parent
commit
fb1ff68fa2

+ 1 - 1
Source/BansheeCore/CMakeSources.cmake

@@ -247,7 +247,7 @@ set(BS_BANSHEECORE_SRC_COMPONENTS
 	"Source/BsCD6Joint.cpp"
 	"Source/BsCCharacterController.cpp"
 	"Source/BsCAudioSource.cpp"
-	"Source/BsCAudioListener.cpp"	
+	"Source/BsCAudioListener.cpp"
 )
 
 set(BS_BANSHEECORE_SRC_PLATFORM

+ 8 - 0
Source/BansheeCore/Include/BsAnimation.h

@@ -220,6 +220,14 @@ namespace BansheeEngine
 		/** Creates a new empty Animation object. */
 		static SPtr<Animation> create();
 
+		/** @name Internal 
+		 *  @{
+		 */
+
+		/** Returns the unique ID for this animation object. */
+		UINT64 _getId() const { return mId; }
+
+		/** @} */
 	private:
 		friend class AnimationManager;
 

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

@@ -363,6 +363,7 @@ namespace BansheeEngine
 	template <class T> class TAnimationCurve;
 	struct AnimationCurves;
 	class Skeleton;
+	class Animation;
 	// Asset import
 	class SpecificImporter;
 	class Importer;
@@ -520,7 +521,8 @@ namespace BansheeEngine
 		TID_NamedAnimationCurve = 1118,
 		TID_Skeleton = 1119,
 		TID_SkeletonBoneInfo = 1120,
-		TID_AnimationSplitInfo = 1121
+		TID_AnimationSplitInfo = 1121,
+		TID_CAnimation = 1122
 	};
 }
 

+ 3 - 0
Source/BansheeCore/Include/BsMesh.h

@@ -85,6 +85,9 @@ namespace BansheeEngine
 		 */
 		void readData(MeshData& dest);
 
+		/** Gets the skeleton required for animation of this mesh, if any is available. */
+		SPtr<Skeleton> getSkeleton() const { return mSkeleton; }
+
 		/** Retrieves a core implementation of a mesh usable only from the core thread. */
 		SPtr<MeshCore> getCore() const;
 

+ 3 - 0
Source/BansheeEngine/CMakeSources.cmake

@@ -2,6 +2,7 @@ set(BS_BANSHEEENGINE_INC_COMPONENTS
 	"Include/BsCCamera.h"
 	"Include/BsCRenderable.h"
 	"Include/BsCLight.h"
+	"Include/BsCAnimation.h"
 )
 
 set(BS_BANSHEEENGINE_SRC_RESOURCES
@@ -151,6 +152,7 @@ set(BS_BANSHEEENGINE_INC_RTTI
 	"Include/BsCGUIWidgetRTTI.h"
 	"Include/BsGameSettingsRTTI.h"
 	"Include/BsResourceMappingRTTI.h"
+	"Include/BsCAnimationRTTI.h"
 )
 
 set(BS_BANSHEEENGINE_INC_NOFILTER
@@ -173,6 +175,7 @@ set(BS_BANSHEEENGINE_SRC_COMPONENTS
 	"Source/BsCCamera.cpp"
 	"Source/BsCRenderable.cpp"
 	"Source/BsCLight.cpp"
+	"Source/BsCAnimation.cpp"
 )
 
 set(BS_BANSHEEENGINE_INC_SCRIPT

+ 118 - 0
Source/BansheeEngine/Include/BsCAnimation.h

@@ -0,0 +1,118 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsAnimation.h"
+#include "BsComponent.h"
+
+namespace BansheeEngine 
+{
+	/** @addtogroup Components
+	 *  @{
+	 */
+
+	/**
+	 * @copydoc	Animation
+	 *
+	 * Wraps Animation as a Component.
+	 */
+    class BS_EXPORT CAnimation : public Component
+    {
+    public:
+		CAnimation(const HSceneObject& parent);
+		virtual ~CAnimation() {}
+		
+		/** 
+		 * Sets the default clip to play as soon as the component is enabled. If more control over playing clips is needed
+		 * use the play(), blend() and crossFade() methods to queue clips for playback manually, and setState() method for
+		 * modify their states individually.
+		 */
+		void setDefaultClip(const HAnimationClip& clip);
+
+		/** @copydoc Animation::setWrapMode */
+		void setWrapMode(AnimWrapMode wrapMode);
+
+		/** @copydoc Animation::setSpeed */
+		void setSpeed(float speed);
+
+		/** @copydoc Animation::play */
+		void play(const HAnimationClip& clip, UINT32 layer = 0, AnimPlayMode playMode = AnimPlayMode::StopLayer);
+
+		/** @copydoc Animation::blend */
+		void blend(const HAnimationClip& clip, float weight, float fadeLength = 0.0f, UINT32 layer = 0);
+
+		/** @copydoc Animation::crossFade */
+		void crossFade(const HAnimationClip& clip, float fadeLength, UINT32 layer = 0, 
+			AnimPlayMode playMode = AnimPlayMode::StopLayer);
+
+		/** @copydoc Animation::stop */
+		void stop(UINT32 layer);
+
+		/** @copydoc Animation::stopAll */
+		void stopAll();
+		
+		/** @copydoc Animation::isPlaying */
+		bool isPlaying() const;
+
+		/** @copydoc Animation::getState */
+		bool getState(const HAnimationClip& clip, AnimationClipState& state);
+
+		/** @copydoc Animation::setState */
+		void setState(const HAnimationClip& clip, AnimationClipState state);
+
+		/** @name Internal
+		 *  @{
+		 */
+
+		/** Returns the Animation implementation wrapped by this component. */
+		SPtr<Animation> _getInternal() const { return mInternal; }
+
+		/** @} */
+
+		/************************************************************************/
+		/* 						COMPONENT OVERRIDES                      		*/
+		/************************************************************************/
+	protected:
+		friend class SceneObject;
+
+		/** @copydoc Component::onInitialized() */
+		void onInitialized() override;
+
+		/** @copydoc Component::onDestroyed() */
+		void onDestroyed() override;
+
+		/** @copydoc Component::onDisabled() */
+		void onDisabled() override;
+
+		/** @copydoc Component::onEnabled() */
+		void onEnabled() override;
+    protected:
+		using Component::destroyInternal;
+
+		/** Creates the internal representation of the Animation and restores the values saved by the Component. */
+		void restoreInternal();
+
+		/** Destroys the internal Animation representation. */
+		void destroyInternal();
+
+		SPtr<Animation> mInternal;
+
+		HAnimationClip mDefaultClip;
+		AnimWrapMode mWrapMode;
+		float mSpeed;
+
+		/************************************************************************/
+		/* 								RTTI		                     		*/
+		/************************************************************************/
+	public:
+		friend class CAnimationRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		RTTITypeBase* getRTTI() const override;
+
+	protected:
+		CAnimation() {} // Serialization only
+     };
+
+	 /** @} */
+}

+ 48 - 0
Source/BansheeEngine/Include/BsCAnimationRTTI.h

@@ -0,0 +1,48 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsRTTIType.h"
+#include "BsCAnimation.h"
+#include "BsGameObjectRTTI.h"
+
+namespace BansheeEngine
+{
+	/** @cond RTTI */
+	/** @addtogroup RTTI-Impl-Engine
+	 *  @{
+	 */
+
+	class BS_EXPORT CAnimationRTTI : public RTTIType<CAnimation, Component, CAnimationRTTI>
+	{
+		BS_BEGIN_RTTI_MEMBERS
+			BS_RTTI_MEMBER_REFL(mDefaultClip, 0)
+			BS_RTTI_MEMBER_PLAIN(mWrapMode, 1)
+			BS_RTTI_MEMBER_PLAIN(mSpeed, 2)
+		BS_END_RTTI_MEMBERS
+	public:
+		CAnimationRTTI()
+			:mInitMembers(this)
+		{ }
+
+		const String& getRTTIName() override
+		{
+			static String name = "CAnimation";
+			return name;
+		}
+
+		UINT32 getRTTIId() override
+		{
+			return TID_CAnimation;
+		}
+
+		SPtr<IReflectable> newRTTIObject() override
+		{
+			return GameObjectRTTI::createGameObject<CAnimation>();
+		}
+	};
+
+	/** @} */
+	/** @endcond */
+}

+ 2 - 2
Source/BansheeEngine/Include/BsCRenderable.h

@@ -80,7 +80,7 @@ namespace BansheeEngine
 
 	public:
 		/** @copydoc Component::update */
-		virtual void update() override;
+		void update() override;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -88,7 +88,7 @@ namespace BansheeEngine
 	public:
 		friend class CRenderableRTTI;
 		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
+		RTTITypeBase* getRTTI() const override;
 
 	protected:
 		CRenderable() {} // Serialization only

+ 2 - 0
Source/BansheeEngine/Include/BsPrerequisites.h

@@ -194,10 +194,12 @@ namespace BansheeEngine
 	class CRenderable;
 	class CCamera;
 	class CLight;
+	class CAnimation;
 
 	typedef GameObjectHandle<CGUIWidget> HGUIWidget;
 	typedef GameObjectHandle<CCamera> HCamera;
 	typedef GameObjectHandle<CRenderable> HRenderable;
+	typedef GameObjectHandle<CAnimation> HAnimation;
 	typedef GameObjectHandle<ProfilerOverlay> HProfilerOverlay;
 
 	typedef ResourceHandle<SpriteTexture> HSpriteTexture;

+ 18 - 1
Source/BansheeEngine/Include/BsRenderable.h

@@ -133,6 +133,9 @@ namespace BansheeEngine
 		/**	Marks the resource dependencies list as dirty and schedules it for rebuild. */
 		virtual void _markResourcesDirty() { }
 
+		/** Triggered whenever the renderable's mesh changes. */
+		virtual void onMeshChanged() { }
+
 		MeshType mMesh;
 		Vector<MaterialType> mMaterials;
 		UINT64 mLayer;
@@ -167,6 +170,12 @@ namespace BansheeEngine
 		/**	Retrieves an ID that can be used for uniquely identifying this handler by the renderer. */
 		UINT32 getRendererId() const { return mRendererId; }
 
+		/** Checks is the mesh geometry rendered by this renderable animated using skeleton or blend shape animation. */
+		bool isAnimated() const { return mAnimationId != (UINT32)-1; }
+
+		/** Returns the identifier of the animation, if this object is animated using skeleton or blend shape animation. */
+		UINT64 getAnimationId() const { return mAnimationId; }
+
 	protected:
 		friend class Renderable;
 
@@ -179,6 +188,7 @@ namespace BansheeEngine
 		void syncToCore(const CoreSyncData& data) override;
 
 		UINT32 mRendererId;
+		UINT64 mAnimationId;
 	};
 
 	/** @copydoc TRenderable */
@@ -188,6 +198,9 @@ namespace BansheeEngine
 		/**	Gets world bounds of the mesh rendered by this object. */
 		Bounds getBounds() const;
 
+		/** Sets the animation that will be used for animating the attached mesh. */
+		void setAnimation(const SPtr<Animation>& animation);
+
 		/**	Retrieves an implementation of a renderable handler usable only from the core thread. */
 		SPtr<RenderableCore> getCore() const;
 
@@ -206,6 +219,9 @@ namespace BansheeEngine
 		/** @copydoc CoreObject::createCore */
 		SPtr<CoreObjectCore> createCore() const override;
 
+		/** @copydoc TRenderable::onMeshChanged */
+		void onMeshChanged() override;
+
 		/** @copydoc TRenderable::_markCoreDirty */
 		void _markCoreDirty(RenderableDirtyFlag flag = RenderableDirtyFlag::Everything) override;
 
@@ -234,6 +250,7 @@ namespace BansheeEngine
 		static SPtr<Renderable> createEmpty();
 
 		UINT32 mLastUpdateHash;
+		SPtr<Animation> mAnimation;
 
 		/************************************************************************/
 		/* 								RTTI		                     		*/
@@ -241,7 +258,7 @@ namespace BansheeEngine
 	public:
 		friend class RenderableRTTI;
 		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
+		RTTITypeBase* getRTTI() const override;
 	};
 
 	/** @} */

+ 161 - 0
Source/BansheeEngine/Source/BsCAnimation.cpp

@@ -0,0 +1,161 @@
+//********************************** Banshee Engine (www.banshee3d.com) **************************************************//
+//**************** Copyright (c) 2016 Marko Pintera ([email protected]). All rights reserved. **********************//
+#include "BsCAnimation.h"
+#include "BsSceneObject.h"
+#include "BsCRenderable.h"
+#include "BsCAnimationRTTI.h"
+
+using namespace std::placeholders;
+
+namespace BansheeEngine
+{
+	CAnimation::CAnimation(const HSceneObject& parent)
+		: Component(parent), mWrapMode(AnimWrapMode::Loop), mSpeed(1.0f)
+	{
+		setName("Animation");
+	}
+
+	void CAnimation::setDefaultClip(const HAnimationClip& clip)
+	{
+		mDefaultClip = clip;
+
+		if(clip.isLoaded() && mInternal != nullptr)
+		{
+			mInternal->play(clip);
+		}
+	}
+
+	void CAnimation::setWrapMode(AnimWrapMode wrapMode)
+	{
+		mWrapMode = wrapMode;
+
+		if (mInternal != nullptr)
+			mInternal->setWrapMode(wrapMode);
+	}
+
+	void CAnimation::setSpeed(float speed)
+	{
+		mSpeed = speed;
+
+		if (mInternal != nullptr)
+			mInternal->setSpeed(speed);
+	}
+
+	void CAnimation::play(const HAnimationClip& clip, UINT32 layer, AnimPlayMode playMode)
+	{
+		if (mInternal != nullptr)
+			mInternal->play(clip, layer, playMode);
+	}
+
+	void CAnimation::blend(const HAnimationClip& clip, float weight, float fadeLength, UINT32 layer)
+	{
+		if (mInternal != nullptr)
+			mInternal->blend(clip, weight, fadeLength, layer);
+	}
+
+	void CAnimation::crossFade(const HAnimationClip& clip, float fadeLength, UINT32 layer, AnimPlayMode playMode)
+	{
+		if (mInternal != nullptr)
+			mInternal->crossFade(clip, fadeLength, layer, playMode);
+	}
+
+	void CAnimation::stop(UINT32 layer)
+	{
+		if (mInternal != nullptr)
+			mInternal->stop(layer);
+	}
+
+	void CAnimation::stopAll()
+	{
+		if (mInternal != nullptr)
+			mInternal->stopAll();
+	}
+
+	bool CAnimation::isPlaying() const
+	{
+		if (mInternal != nullptr)
+			return mInternal->isPlaying();
+
+		return false;
+	}
+
+	bool CAnimation::getState(const HAnimationClip& clip, AnimationClipState& state)
+	{
+		if (mInternal != nullptr)
+			return mInternal->getState(clip, state);
+
+		return false;
+	}
+
+	void CAnimation::setState(const HAnimationClip& clip, AnimationClipState state)
+	{
+		if (mInternal != nullptr)
+			return mInternal->setState(clip, state);
+	}
+
+	void CAnimation::onInitialized()
+	{
+		
+	}
+
+	void CAnimation::onDestroyed()
+	{
+		destroyInternal();
+	}
+
+	void CAnimation::onDisabled()
+	{
+		destroyInternal();
+	}
+
+	void CAnimation::onEnabled()
+	{
+		restoreInternal();
+	}
+
+	void CAnimation::restoreInternal()
+	{
+		if (mInternal == nullptr)
+			mInternal = Animation::create();
+
+		mInternal->setWrapMode(mWrapMode);
+		mInternal->setSpeed(mSpeed);
+
+		if (mDefaultClip.isLoaded())
+			mInternal->play(mDefaultClip);
+
+		HRenderable renderableComponent = SO()->getComponent<CRenderable>();
+		if (renderableComponent == nullptr)
+			return;
+
+		SPtr<Renderable> renderable = renderableComponent->_getRenderable();
+
+		if(renderable != nullptr)
+			renderable->setAnimation(mInternal);
+	}
+
+	void CAnimation::destroyInternal()
+	{
+		HRenderable renderableComponent = SO()->getComponent<CRenderable>();
+		if (renderableComponent == nullptr)
+			return;
+
+		SPtr<Renderable> renderable = renderableComponent->_getRenderable();
+
+		if (renderable != nullptr)
+			renderable->setAnimation(nullptr);
+
+		// This should release the last reference and destroy the internal listener
+		mInternal = nullptr;
+	}
+
+	RTTITypeBase* CAnimation::getRTTIStatic()
+	{
+		return CAnimationRTTI::instance();
+	}
+
+	RTTITypeBase* CAnimation::getRTTI() const
+	{
+		return CAnimation::getRTTIStatic();
+	}
+}

+ 5 - 2
Source/BansheeEngine/Source/BsCRenderable.cpp

@@ -3,10 +3,9 @@
 #include "BsCRenderable.h"
 #include "BsCRenderableRTTI.h"
 #include "BsSceneObject.h"
-#include "BsBuiltinResources.h"
 #include "BsMesh.h"
 #include "BsMaterial.h"
-#include "BsRenderQueue.h"
+#include "BsCAnimation.h"
 #include "BsBounds.h"
 #include "BsSceneManager.h"
 
@@ -28,6 +27,10 @@ namespace BansheeEngine
 			mInternal = Renderable::create();
 
 		gSceneManager()._registerRenderable(mInternal, sceneObject());
+
+		HAnimation animationComponent = SO()->getComponent<CAnimation>();
+		if(animationComponent != nullptr)
+			mInternal->setAnimation(animationComponent->_getInternal());
 	}
 
 	Bounds CRenderable::getBounds() const

+ 34 - 1
Source/BansheeEngine/Source/BsRenderable.cpp

@@ -9,6 +9,7 @@
 #include "BsRenderQueue.h"
 #include "BsBounds.h"
 #include "BsRenderer.h"
+#include "BsAnimation.h"
 #include "BsFrameAlloc.h"
 #include "BsDebug.h"
 
@@ -47,6 +48,8 @@ namespace BansheeEngine
 
 		mMaterials.resize(numSubMeshes);
 
+		onMeshChanged();
+
 		_markDependenciesDirty();
 		_markResourcesDirty();
 		_markCoreDirty();
@@ -124,7 +127,7 @@ namespace BansheeEngine
 	template class TRenderable < true >;
 
 	RenderableCore::RenderableCore() 
-		:mRendererId(0)
+		:mRendererId(0), mAnimationId((UINT64)-1)
 	{
 	}
 
@@ -179,6 +182,7 @@ namespace BansheeEngine
 		dataPtr = rttiReadElem(mTransformNoScale, dataPtr);
 		dataPtr = rttiReadElem(mPosition, dataPtr);
 		dataPtr = rttiReadElem(mIsActive, dataPtr);
+		dataPtr = rttiReadElem(mAnimationId, dataPtr);
 		dataPtr = rttiReadElem(dirtyFlags, dataPtr);
 
 		SPtr<MeshCore>* mesh = (SPtr<MeshCore>*)dataPtr;
@@ -222,6 +226,16 @@ namespace BansheeEngine
 		
 	}
 
+	void Renderable::setAnimation(const SPtr<Animation>& animation)
+	{
+		mAnimation = animation;
+
+		if (mAnimation != nullptr && mMesh.isLoaded(false))
+			mAnimation->setSkeleton(mMesh->getSkeleton());
+
+		_markCoreDirty();
+	}
+
 	Bounds Renderable::getBounds() const
 	{
 		HMesh mesh = getMesh();
@@ -256,6 +270,17 @@ namespace BansheeEngine
 		return handlerPtr;
 	}
 
+	void Renderable::onMeshChanged()
+	{
+		if(mAnimation != nullptr)
+		{
+			if (mMesh.isLoaded(false))
+				mAnimation->setSkeleton(mMesh->getSkeleton());
+			else
+				mAnimation->setSkeleton(nullptr);
+		}
+	}
+
 	void Renderable::_markCoreDirty(RenderableDirtyFlag flag)
 	{
 		markCoreDirty((UINT32)flag);
@@ -275,6 +300,12 @@ namespace BansheeEngine
 	{
 		UINT32 numMaterials = (UINT32)mMaterials.size();
 
+		UINT64 animationId;
+		if (mAnimation != nullptr)
+			animationId = mAnimation->_getId();
+		else
+			animationId = (UINT64)-1;
+
 		UINT32 size = rttiGetElemSize(mLayer) + 
 			rttiGetElemSize(mWorldBounds) + 
 			rttiGetElemSize(numMaterials) + 
@@ -282,6 +313,7 @@ namespace BansheeEngine
 			rttiGetElemSize(mTransformNoScale) +
 			rttiGetElemSize(mPosition) +
 			rttiGetElemSize(mIsActive) +
+			rttiGetElemSize(animationId) + 
 			rttiGetElemSize(getCoreDirtyFlags()) +
 			sizeof(SPtr<MeshCore>) + 
 			numMaterials * sizeof(SPtr<MaterialCore>);
@@ -295,6 +327,7 @@ namespace BansheeEngine
 		dataPtr = rttiWriteElem(mTransformNoScale, dataPtr);
 		dataPtr = rttiWriteElem(mPosition, dataPtr);
 		dataPtr = rttiWriteElem(mIsActive, dataPtr);
+		dataPtr = rttiWriteElem(animationId, dataPtr);
 		dataPtr = rttiWriteElem(getCoreDirtyFlags(), dataPtr);
 
 		SPtr<MeshCore>* mesh = new (dataPtr) SPtr<MeshCore>();