Browse Source

Added import for mesh skeleton

BearishSun 9 years ago
parent
commit
49e269480e

+ 44 - 31
Source/BansheeCore/Include/BsMesh.h

@@ -28,7 +28,7 @@ namespace BansheeEngine
 		virtual ~Mesh();
 
 		/** @copydoc MeshBase::initialize */
-		virtual void initialize() override;
+		void initialize() override;
 
 		/**
 		 * Updates the mesh with new data. The actual write will be queued for later execution on the core thread. Provided 
@@ -95,17 +95,15 @@ namespace BansheeEngine
 		friend class MeshManager;
 
 		Mesh(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
-			int usage = MU_STATIC, DrawOperationType drawOp = DOT_TRIANGLE_LIST,
-			IndexType indexType = IT_32BIT);
+			int usage, DrawOperationType drawOp, IndexType indexType, const SPtr<Skeleton>& skeleton);
 
 		Mesh(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-			const Vector<SubMesh>& subMeshes, int usage = MU_STATIC,
-			IndexType indexType = IT_32BIT);
+			const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton);
 
-		Mesh(const SPtr<MeshData>& initialMeshData, int usage = MU_STATIC,
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST);
+		Mesh(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp, const SPtr<Skeleton>& skeleton);
 
-		Mesh(const SPtr<MeshData>& initialMeshData, const Vector<SubMesh>& subMeshes, int usage = MU_STATIC);
+		Mesh(const SPtr<MeshData>& initialMeshData, const Vector<SubMesh>& subMeshes, int usage, 
+			const SPtr<Skeleton>& skeleton);
 
 		/**	Updates bounds by calculating them from the vertices in the provided mesh data object. */
 		void updateBounds(const MeshData& meshData);
@@ -128,6 +126,7 @@ namespace BansheeEngine
 		SPtr<VertexDataDesc> mVertexDesc;
 		int mUsage;
 		IndexType mIndexType;
+		SPtr<Skeleton> mSkeleton; // Immutable
 
 		/************************************************************************/
 		/* 								SERIALIZATION                      		*/
@@ -138,7 +137,7 @@ namespace BansheeEngine
 	public:
 		friend class MeshRTTI;
 		static RTTITypeBase* getRTTIStatic();
-		virtual RTTITypeBase* getRTTI() const override;
+		RTTITypeBase* getRTTI() const override;
 
 		/************************************************************************/
 		/* 								STATICS		                     		*/
@@ -159,9 +158,10 @@ namespace BansheeEngine
 		 *								option is a triangle list, where three indices represent a single triangle.
 		 * @param[in]	indexType		Size of indices, use smaller size for better performance, however be careful not to
 		 *								go over the number of vertices limited by the size.
+		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
 		 */
 		static HMesh create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, int usage = MU_STATIC,
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT);
+			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT, const SPtr<Skeleton>& skeleton = nullptr);
 
 		/**
 		 * Creates a new empty mesh. Created mesh will have specified sub-meshes you may render independently.
@@ -177,9 +177,10 @@ namespace BansheeEngine
 		 * @param[in]	usage			Optimizes performance depending on planned usage of the mesh.
 		 * @param[in]	indexType		Size of indices, use smaller size for better performance, however be careful not to
 		 *								go over the number of vertices limited by the size.
+		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
 		 */
 		static HMesh create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, const Vector<SubMesh>& subMeshes,
-			int usage = MU_STATIC, IndexType indexType = IT_32BIT);
+			int usage = MU_STATIC, IndexType indexType = IT_32BIT, const SPtr<Skeleton>& skeleton = nullptr);
 
 		/**
 		 * Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described
@@ -189,9 +190,10 @@ namespace BansheeEngine
 		 * @param[in]	usage			Optimizes performance depending on planned usage of the mesh.
 		 * @param[in]	drawOp			Determines how should the provided indices be interpreted by the pipeline. Default 
 		 *								option is a triangle strip, where three indices represent a single triangle.
+		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
 		 */
 		static HMesh create(const SPtr<MeshData>& initialData, int usage = MU_STATIC,
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST);
+			DrawOperationType drawOp = DOT_TRIANGLE_LIST, const SPtr<Skeleton>& skeleton = nullptr);
 
 		/**
 		 * Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described by
@@ -201,8 +203,10 @@ namespace BansheeEngine
 		 * @param[in]	subMeshes		Defines how are indices separated into sub-meshes, and how are those sub-meshes 
 		 *								rendered. Sub-meshes may be rendered independently.
 		 * @param[in]	usage			Optimizes performance depending on planned usage of the mesh.
+		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
 		 */
-		static HMesh create(const SPtr<MeshData>& initialData, const Vector<SubMesh>& subMeshes, int usage = MU_STATIC);
+		static HMesh create(const SPtr<MeshData>& initialData, const Vector<SubMesh>& subMeshes, int usage = MU_STATIC, 
+			const SPtr<Skeleton>& skeleton = nullptr);
 
 		/** @name Internal
 		 *  @{
@@ -213,18 +217,18 @@ namespace BansheeEngine
 		 *
 		 * @note	Internal method. Use create() for normal use.
 		 */
-		static SPtr<Mesh> _createPtr(UINT32 numVertices, UINT32 numIndices, 
-			const SPtr<VertexDataDesc>& vertexDesc, int usage = MU_STATIC,
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT);
+		static SPtr<Mesh> _createPtr(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
+			int usage = MU_STATIC, DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT, 
+			const SPtr<Skeleton>& skeleton = nullptr);
 
 		/**
 		 * @copydoc	create(UINT32, UINT32, const SPtr<VertexDataDesc>&, const Vector<SubMesh>&, int, IndexType)
 		 *
 		 * @note	Internal method. Use create() for normal use.
 		 */
-		static SPtr<Mesh> _createPtr(UINT32 numVertices, UINT32 numIndices, 
-			const SPtr<VertexDataDesc>& vertexDesc, const Vector<SubMesh>& subMeshes,
-			int usage = MU_STATIC, IndexType indexType = IT_32BIT);
+		static SPtr<Mesh> _createPtr(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
+			const Vector<SubMesh>& subMeshes, int usage = MU_STATIC, IndexType indexType = IT_32BIT, 
+			const SPtr<Skeleton>& skeleton = nullptr);
 
 		/**
 		 * @copydoc	create(const SPtr<MeshData>&, int, DrawOperationType)
@@ -232,7 +236,7 @@ namespace BansheeEngine
 		 * @note	Internal method. Use create() for normal use.
 		 */
 		static SPtr<Mesh> _createPtr(const SPtr<MeshData>& initialData, int usage = MU_STATIC,
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST);
+			DrawOperationType drawOp = DOT_TRIANGLE_LIST, const SPtr<Skeleton>& skeleton = nullptr);
 
 		/**
 		 * @copydoc	create(const SPtr<MeshData>&, const Vector<SubMesh>&, int)
@@ -240,7 +244,7 @@ namespace BansheeEngine
 		 * @note	Internal method. Use create() for normal use.
 		 */
 		static SPtr<Mesh> _createPtr(const SPtr<MeshData>& initialData, const Vector<SubMesh>& subMeshes,
-			int usage = MU_STATIC);
+			int usage = MU_STATIC, const SPtr<Skeleton>& skeleton = nullptr);
 
 		/** @} */
 	};
@@ -260,22 +264,25 @@ namespace BansheeEngine
 	{
 	public:
 		MeshCore(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-			const Vector<SubMesh>& subMeshes, int usage, IndexType indexType,
-			SPtr<MeshData> initialMeshData);
+			const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton,
+			const SPtr<MeshData>& initialMeshData);
 
 		~MeshCore();
 
 		/** @copydoc CoreObjectCore::initialize */
-		virtual void initialize() override;
+		void initialize() override;
 
 		/** @copydoc MeshCoreBase::getVertexData */
-		virtual SPtr<VertexData> getVertexData() const override;
+		SPtr<VertexData> getVertexData() const override;
 
 		/** @copydoc MeshCoreBase::getIndexBuffer */
-		virtual SPtr<IndexBufferCore> getIndexBuffer() const override;
+		SPtr<IndexBufferCore> getIndexBuffer() const override;
 
 		/** @copydoc MeshCoreBase::getVertexDesc */
-		virtual SPtr<VertexDataDesc> getVertexDesc() const override;
+		SPtr<VertexDataDesc> getVertexDesc() const override;
+
+		/** Returns a skeleton that can be used for animating the mesh. */
+		SPtr<Skeleton> getSkeleton() const { return mSkeleton; }
 
 		/**
 		 * Updates a part of the current mesh with the provided data.
@@ -314,9 +321,10 @@ namespace BansheeEngine
 		 *								option is a triangle list, where three indices represent a single triangle.
 		 * @param[in]	indexType		Size of indices, use smaller size for better performance, however be careful not to
 		 *								go over the number of vertices limited by the size.
+		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
 		 */
 		static SPtr<MeshCore> create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, int usage = MU_STATIC,
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT);
+			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT, const SPtr<Skeleton>& skeleton = nullptr);
 
 		/**
 		 * Creates a new empty mesh. Created mesh will have specified sub-meshes you may render independently.
@@ -332,9 +340,10 @@ namespace BansheeEngine
 		 * @param[in]	usage			Optimizes performance depending on planned usage of the mesh.
 		 * @param[in]	indexType		Size of indices, use smaller size for better performance, however be careful not 
 		 *								to go over the number of vertices limited by the size.
+		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
 		 */
 		static SPtr<MeshCore> create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, const Vector<SubMesh>& subMeshes,
-			int usage = MU_STATIC, IndexType indexType = IT_32BIT);
+			int usage = MU_STATIC, IndexType indexType = IT_32BIT, const SPtr<Skeleton>& skeleton = nullptr);
 
 		/**
 		 * Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described
@@ -344,9 +353,10 @@ namespace BansheeEngine
 		 * @param[in]	usage			Optimizes performance depending on planned usage of the mesh.
 		 * @param[in]	drawOp			Determines how should the provided indices be interpreted by the pipeline. Default 
 		 *								option is a triangle strip, where three indices represent a single triangle.
+		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
 		 */
 		static SPtr<MeshCore> create(const SPtr<MeshData>& initialData, int usage = MU_STATIC,
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST);
+			DrawOperationType drawOp = DOT_TRIANGLE_LIST, const SPtr<Skeleton>& skeleton = nullptr);
 
 		/**
 		 * Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described
@@ -356,8 +366,10 @@ namespace BansheeEngine
 		 * @param[in]	subMeshes		Defines how are indices separated into sub-meshes, and how are those sub-meshes 
 		 *								rendered. Sub-meshes may be rendered independently.
 		 * @param[in]	usage			Optimizes performance depending on planned usage of the mesh.
+		 * @param[in]	skeleton		Optional skeleton that can be used for skeletal animation of the mesh.
 		 */
-		static SPtr<MeshCore> create(const SPtr<MeshData>& initialData, const Vector<SubMesh>& subMeshes, int usage = MU_STATIC);
+		static SPtr<MeshCore> create(const SPtr<MeshData>& initialData, const Vector<SubMesh>& subMeshes, 
+			int usage = MU_STATIC, const SPtr<Skeleton>& skeleton = nullptr);
 
 	protected:
 		friend class Mesh;
@@ -371,6 +383,7 @@ namespace BansheeEngine
 		SPtr<VertexDataDesc> mVertexDesc;
 		int mUsage;
 		IndexType mIndexType;
+		SPtr<Skeleton> mSkeleton;
 		SPtr<MeshData> mTempInitialMeshData;
 	};
 

+ 6 - 4
Source/BansheeCore/Include/BsMeshManager.h

@@ -21,17 +21,19 @@ namespace BansheeEngine
 
 		/** @copydoc Mesh::create(UINT32, UINT32, const SPtr<VertexDataDesc>&, int, DrawOperationType, IndexType) */
 		SPtr<Mesh> create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, int usage = MU_STATIC, 
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT);
+			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT, const SPtr<Skeleton>& skeleton = nullptr);
 
 		/** @copydoc Mesh::create(UINT32, UINT32, const SPtr<VertexDataDesc>&, const Vector<SubMesh>&, int, IndexType) */
 		SPtr<Mesh> create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, const Vector<SubMesh>& subMeshes, 
-			int usage = MU_STATIC, IndexType indexType = IT_32BIT);
+			int usage = MU_STATIC, IndexType indexType = IT_32BIT, const SPtr<Skeleton>& skeleton = nullptr);
 
 		/** @copydoc Mesh::create(const SPtr<MeshData>&, int, DrawOperationType) */
-		SPtr<Mesh> create(const SPtr<MeshData>& initialData, int usage = MU_STATIC, DrawOperationType drawOp = DOT_TRIANGLE_LIST);
+		SPtr<Mesh> create(const SPtr<MeshData>& initialData, int usage = MU_STATIC, DrawOperationType drawOp = DOT_TRIANGLE_LIST, 
+			const SPtr<Skeleton>& skeleton = nullptr);
 
 		/** @copydoc Mesh::create(const SPtr<MeshData>&, const Vector<SubMesh>&, int) */
-		SPtr<Mesh> create(const SPtr<MeshData>& initialData, const Vector<SubMesh>& subMeshes, int usage = MU_STATIC);
+		SPtr<Mesh> create(const SPtr<MeshData>& initialData, const Vector<SubMesh>& subMeshes, int usage = MU_STATIC, 
+			const SPtr<Skeleton>& skeleton = nullptr);
 
 		/**
 		 * Creates a new empty and uninitialized mesh. You will need to manually initialize the mesh before using it.

+ 8 - 13
Source/BansheeCore/Include/BsMeshRTTI.h

@@ -6,6 +6,7 @@
 #include "BsRTTIType.h"
 #include "BsCoreApplication.h"
 #include "BsMesh.h"
+#include "BsSkeleton.h"
 #include "BsMeshManager.h"
 #include "BsCoreThread.h"
 
@@ -18,14 +19,12 @@ namespace BansheeEngine
 
 	class MeshRTTI : public RTTIType<Mesh, MeshBase, MeshRTTI>
 	{
-		SPtr<VertexDataDesc> getVertexDesc(Mesh* obj) { return obj->mVertexDesc; }
-		void setVertexDesc(Mesh* obj, SPtr<VertexDataDesc> value) { obj->mVertexDesc = value; }
-
-		IndexType& getIndexType(Mesh* obj) { return obj->mIndexType; }
-		void setIndexType(Mesh* obj, IndexType& value) { obj->mIndexType = value; }
-
-		int& getBufferType(Mesh* obj) { return (int&)obj->mUsage; }
-		void setBufferType(Mesh* obj, int& value) { obj->mUsage = value; }
+		BS_BEGIN_RTTI_MEMBERS
+			BS_RTTI_MEMBER_REFLPTR(mVertexDesc, 0)
+			BS_RTTI_MEMBER_PLAIN(mIndexType, 1)
+			BS_RTTI_MEMBER_PLAIN(mUsage, 2)
+			BS_RTTI_MEMBER_REFLPTR(mSkeleton, 4)
+		BS_END_RTTI_MEMBERS
 
 		SPtr<MeshData> getMeshData(Mesh* obj) 
 		{ 
@@ -44,12 +43,8 @@ namespace BansheeEngine
 
 	public:
 		MeshRTTI()
+			:mInitMembers(this)
 		{
-			addReflectablePtrField("mVertexDesc", 0, &MeshRTTI::getVertexDesc, &MeshRTTI::setVertexDesc);
-
-			addPlainField("mIndexType", 1, &MeshRTTI::getIndexType, &MeshRTTI::setIndexType);
-			addPlainField("mUsage", 2, &MeshRTTI::getBufferType, &MeshRTTI::setBufferType);
-
 			addReflectablePtrField("mMeshData", 3, &MeshRTTI::getMeshData, &MeshRTTI::setMeshData);
 		}
 

+ 40 - 36
Source/BansheeCore/Source/BsMesh.cpp

@@ -15,9 +15,11 @@
 namespace BansheeEngine
 {
 	MeshCore::MeshCore(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, SPtr<MeshData> initialMeshData)
-		:MeshCoreBase(numVertices, numIndices, subMeshes), mVertexData(nullptr), mIndexBuffer(nullptr), 
-		mVertexDesc(vertexDesc), mUsage(usage), mIndexType(indexType), mTempInitialMeshData(initialMeshData)
+		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton, 
+		const SPtr<MeshData>& initialMeshData)
+		: MeshCoreBase(numVertices, numIndices, subMeshes), mVertexData(nullptr), mIndexBuffer(nullptr)
+		, mVertexDesc(vertexDesc), mUsage(usage), mIndexType(indexType), mSkeleton(skeleton)
+		, mTempInitialMeshData(initialMeshData)
 	{ }
 
 	MeshCore::~MeshCore()
@@ -276,12 +278,12 @@ namespace BansheeEngine
 	}
 
 	SPtr<MeshCore> MeshCore::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-		int usage, DrawOperationType drawOp, IndexType indexType)
+		int usage, DrawOperationType drawOp, IndexType indexType, const SPtr<Skeleton>& skeleton)
 	{
 		SubMesh subMesh(0, numIndices, drawOp);
 
 		SPtr<MeshCore> mesh = bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(numVertices, numIndices, 
-			vertexDesc, { subMesh }, usage, indexType, nullptr));
+			vertexDesc, { subMesh }, usage, indexType, skeleton, nullptr));
 		mesh->_setThisPtr(mesh);
 		mesh->initialize();
 
@@ -289,10 +291,10 @@ namespace BansheeEngine
 	}
 
 	SPtr<MeshCore> MeshCore::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType)
+		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton)
 	{
 		SPtr<MeshCore> mesh = bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(numVertices, numIndices,
-			vertexDesc, subMeshes, usage, indexType, nullptr));
+			vertexDesc, subMeshes, usage, indexType, skeleton, nullptr));
 
 		mesh->_setThisPtr(mesh);
 		mesh->initialize();
@@ -300,7 +302,8 @@ namespace BansheeEngine
 		return mesh;
 	}
 
-	SPtr<MeshCore> MeshCore::create(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp)
+	SPtr<MeshCore> MeshCore::create(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp, 
+		const SPtr<Skeleton>& skeleton)
 	{
 		UINT32 numVertices = initialMeshData->getNumVertices();
 		UINT32 numIndices = initialMeshData->getNumIndices();
@@ -309,7 +312,7 @@ namespace BansheeEngine
 		IndexType indexType = initialMeshData->getIndexType();
 		
 		SPtr<MeshCore> mesh = bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(numVertices, numIndices,
-			vertexDesc, { subMesh }, usage, indexType, initialMeshData));
+			vertexDesc, { subMesh }, usage, indexType, skeleton, initialMeshData));
 
 		mesh->_setThisPtr(mesh);
 		mesh->initialize();
@@ -317,7 +320,8 @@ namespace BansheeEngine
 		return mesh;
 	}
 
-	SPtr<MeshCore> MeshCore::create(const SPtr<MeshData>& initialMeshData, const Vector<SubMesh>& subMeshes, int usage)
+	SPtr<MeshCore> MeshCore::create(const SPtr<MeshData>& initialMeshData, const Vector<SubMesh>& subMeshes, int usage, 
+		const SPtr<Skeleton>& skeleton)
 	{
 		UINT32 numVertices = initialMeshData->getNumVertices();
 		UINT32 numIndices = initialMeshData->getNumIndices();
@@ -325,7 +329,7 @@ namespace BansheeEngine
 		IndexType indexType = initialMeshData->getIndexType();
 
 		SPtr<MeshCore> mesh = bs_shared_ptr<MeshCore>(new (bs_alloc<MeshCore>()) MeshCore(numVertices, numIndices,
-			vertexDesc, subMeshes, usage, indexType, initialMeshData));
+			vertexDesc, subMeshes, usage, indexType, skeleton, initialMeshData));
 
 		mesh->_setThisPtr(mesh);
 		mesh->initialize();
@@ -334,33 +338,33 @@ namespace BansheeEngine
 	}
 
 	Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
-		int usage, DrawOperationType drawOp, IndexType indexType)
+		int usage, DrawOperationType drawOp, IndexType indexType, const SPtr<Skeleton>& skeleton)
 		:MeshBase(numVertices, numIndices, drawOp), mVertexDesc(vertexDesc), mUsage(usage),
-		mIndexType(indexType)
+		mIndexType(indexType), mSkeleton(skeleton)
 	{
 
 	}
 
 	Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType)
+		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton)
 		:MeshBase(numVertices, numIndices, subMeshes), mVertexDesc(vertexDesc), mUsage(usage), 
-		mIndexType(indexType)
+		mIndexType(indexType), mSkeleton(skeleton)
 	{
 
 	}
 
-	Mesh::Mesh(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp)
+	Mesh::Mesh(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp, const SPtr<Skeleton>& skeleton)
 		:MeshBase(initialMeshData->getNumVertices(), initialMeshData->getNumIndices(), drawOp), 
 		mCPUData(initialMeshData), mVertexDesc(initialMeshData->getVertexDesc()),
-		mUsage(usage), mIndexType(initialMeshData->getIndexType())
+		mUsage(usage), mIndexType(initialMeshData->getIndexType()), mSkeleton(skeleton)
 	{
 
 	}
 
-	Mesh::Mesh(const SPtr<MeshData>& initialMeshData, const Vector<SubMesh>& subMeshes, int usage)
+	Mesh::Mesh(const SPtr<MeshData>& initialMeshData, const Vector<SubMesh>& subMeshes, int usage, const SPtr<Skeleton>& skeleton)
 		:MeshBase(initialMeshData->getNumVertices(), initialMeshData->getNumIndices(), subMeshes),
 		mCPUData(initialMeshData), mVertexDesc(initialMeshData->getVertexDesc()), 
-		mUsage(usage), mIndexType(initialMeshData->getIndexType())
+		mUsage(usage), mIndexType(initialMeshData->getIndexType()), mSkeleton(skeleton)
 	{
 
 	}
@@ -445,7 +449,7 @@ namespace BansheeEngine
 	SPtr<CoreObjectCore> Mesh::createCore() const
 	{
 		MeshCore* obj = new (bs_alloc<MeshCore>()) MeshCore(mProperties.mNumVertices, mProperties.mNumIndices, 
-			mVertexDesc, mProperties.mSubMeshes, mUsage, mIndexType, mCPUData);
+			mVertexDesc, mProperties.mSubMeshes, mUsage, mIndexType, mSkeleton, mCPUData);
 
 		SPtr<CoreObjectCore> meshCore = bs_shared_ptr<MeshCore>(obj);
 		meshCore->_setThisPtr(meshCore);
@@ -540,54 +544,54 @@ namespace BansheeEngine
 	/************************************************************************/
 
 	HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
-		int usage, DrawOperationType drawOp, IndexType indexType)
+		int usage, DrawOperationType drawOp, IndexType indexType, const SPtr<Skeleton>& skeleton)
 	{
-		SPtr<Mesh> meshPtr = _createPtr(numVertices, numIndices, vertexDesc, usage, drawOp, indexType);
+		SPtr<Mesh> meshPtr = _createPtr(numVertices, numIndices, vertexDesc, usage, drawOp, indexType, skeleton);
 
 		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
 	}
 
 	HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType)
+		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton)
 	{
-		SPtr<Mesh> meshPtr = _createPtr(numVertices, numIndices, vertexDesc, subMeshes, usage, indexType);
+		SPtr<Mesh> meshPtr = _createPtr(numVertices, numIndices, vertexDesc, subMeshes, usage, indexType, skeleton);
 
 		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
 	}
 
-	HMesh Mesh::create(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp)
+	HMesh Mesh::create(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp, const SPtr<Skeleton>& skeleton)
 	{
-		SPtr<Mesh> meshPtr = _createPtr(initialMeshData, usage, drawOp);
+		SPtr<Mesh> meshPtr = _createPtr(initialMeshData, usage, drawOp, skeleton);
 
 		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
 	}
 
-	HMesh Mesh::create(const SPtr<MeshData>& initialMeshData, const Vector<SubMesh>& subMeshes, int usage)
+	HMesh Mesh::create(const SPtr<MeshData>& initialMeshData, const Vector<SubMesh>& subMeshes, int usage, const SPtr<Skeleton>& skeleton)
 	{
-		SPtr<Mesh> meshPtr = _createPtr(initialMeshData, subMeshes, usage);
+		SPtr<Mesh> meshPtr = _createPtr(initialMeshData, subMeshes, usage, skeleton);
 
 		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
 	}
 
 	SPtr<Mesh> Mesh::_createPtr(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
-		int usage, DrawOperationType drawOp, IndexType indexType)
+		int usage, DrawOperationType drawOp, IndexType indexType, const SPtr<Skeleton>& skeleton)
 	{
-		return MeshManager::instance().create(numVertices, numIndices, vertexDesc, usage, drawOp, indexType);
+		return MeshManager::instance().create(numVertices, numIndices, vertexDesc, usage, drawOp, indexType, skeleton);
 	}
 
 	SPtr<Mesh> Mesh::_createPtr(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc,
-		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType)
+		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton)
 	{
-		return MeshManager::instance().create(numVertices, numIndices, vertexDesc, subMeshes, usage, indexType);
+		return MeshManager::instance().create(numVertices, numIndices, vertexDesc, subMeshes, usage, indexType, skeleton);
 	}
 
-	SPtr<Mesh> Mesh::_createPtr(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp)
+	SPtr<Mesh> Mesh::_createPtr(const SPtr<MeshData>& initialMeshData, int usage, DrawOperationType drawOp, const SPtr<Skeleton>& skeleton)
 	{
-		return MeshManager::instance().create(initialMeshData, usage, drawOp);
+		return MeshManager::instance().create(initialMeshData, usage, drawOp, skeleton);
 	}
 
-	SPtr<Mesh> Mesh::_createPtr(const SPtr<MeshData>& initialMeshData, const Vector<SubMesh>& subMeshes, int usage)
+	SPtr<Mesh> Mesh::_createPtr(const SPtr<MeshData>& initialMeshData, const Vector<SubMesh>& subMeshes, int usage, const SPtr<Skeleton>& skeleton)
 	{
-		return MeshManager::instance().create(initialMeshData, subMeshes, usage);
+		return MeshManager::instance().create(initialMeshData, subMeshes, usage, skeleton);
 	}
 }

+ 10 - 8
Source/BansheeCore/Source/BsMeshManager.cpp

@@ -20,10 +20,10 @@ namespace BansheeEngine
 	}
 
 	SPtr<Mesh> MeshManager::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
-		int usage, DrawOperationType drawOp, IndexType indexType)
+		int usage, DrawOperationType drawOp, IndexType indexType, const SPtr<Skeleton>& skeleton)
 	{
 		SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) 
-			Mesh(numVertices, numIndices, vertexDesc, usage, drawOp, indexType));
+			Mesh(numVertices, numIndices, vertexDesc, usage, drawOp, indexType, skeleton));
 		mesh->_setThisPtr(mesh);
 		mesh->initialize();
 
@@ -31,28 +31,30 @@ namespace BansheeEngine
 	}
 
 	SPtr<Mesh> MeshManager::create(UINT32 numVertices, UINT32 numIndices, const SPtr<VertexDataDesc>& vertexDesc, 
-		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType)
+		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, const SPtr<Skeleton>& skeleton)
 	{
 		SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>())
-			Mesh(numVertices, numIndices, vertexDesc, subMeshes, usage, indexType));
+			Mesh(numVertices, numIndices, vertexDesc, subMeshes, usage, indexType, skeleton));
 		mesh->_setThisPtr(mesh);
 		mesh->initialize();
 
 		return mesh;
 	}
 
-	SPtr<Mesh> MeshManager::create(const SPtr<MeshData>& initialData, int usage, DrawOperationType drawOp)
+	SPtr<Mesh> MeshManager::create(const SPtr<MeshData>& initialData, int usage, DrawOperationType drawOp, 
+		const SPtr<Skeleton>& skeleton)
 	{
-		SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh(initialData, usage, drawOp));
+		SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh(initialData, usage, drawOp, skeleton));
 		mesh->_setThisPtr(mesh);
 		mesh->initialize();
 
 		return mesh;
 	}
 
-	SPtr<Mesh> MeshManager::create(const SPtr<MeshData>& initialData, const Vector<SubMesh>& subMeshes, int usage)
+	SPtr<Mesh> MeshManager::create(const SPtr<MeshData>& initialData, const Vector<SubMesh>& subMeshes, int usage, 
+		const SPtr<Skeleton>& skeleton)
 	{
-		SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh(initialData, subMeshes, usage));
+		SPtr<Mesh> mesh = bs_core_ptr<Mesh>(new (bs_alloc<Mesh>()) Mesh(initialData, subMeshes, usage, skeleton));
 		mesh->_setThisPtr(mesh);
 		mesh->initialize();
 

+ 4 - 3
Source/BansheeFBXImporter/Include/BsFBXImporter.h

@@ -50,7 +50,7 @@ namespace BansheeEngine
 		 * Reads the FBX file and outputs mesh data from the read file. Sub-mesh information will be output in @p subMeshes.
 		 */
 		SPtr<RendererMeshData> importMeshData(const Path& filePath, SPtr<const ImportOptions> importOptions, 
-			Vector<SubMesh>& subMeshes, UnorderedMap<String, SPtr<AnimationCurves>>& animationClips);
+			Vector<SubMesh>& subMeshes, UnorderedMap<String, SPtr<AnimationCurves>>& animationClips, SPtr<Skeleton>& skeleton);
 
 		/**
 		 * Loads the data from the file at the provided path into the provided FBX scene. Returns false if the file
@@ -120,8 +120,9 @@ namespace BansheeEngine
 		 */
 		void generateMissingTangentSpace(FBXImportScene& scene, const FBXImportOptions& options);
 
-		/**Converts the mesh data from the imported FBX scene into mesh data that can be used for initializing a mesh. */
-		SPtr<RendererMeshData> generateMeshData(const FBXImportScene& scene, const FBXImportOptions& options, Vector<SubMesh>& subMeshes);
+		/** Converts the mesh data from the imported FBX scene into mesh data that can be used for initializing a mesh. */
+		SPtr<RendererMeshData> generateMeshData(const FBXImportScene& scene, const FBXImportOptions& options, 
+			Vector<SubMesh>& outputSubMeshes, SPtr<Skeleton>& outputSkeleton);
 
 		/**	Creates an internal representation of an FBX node from an FbxNode object. */
 		FBXImportNode* createImportNode(FBXImportScene& scene, FbxNode* fbxNode, FBXImportNode* parent);

+ 88 - 11
Source/BansheeFBXImporter/Source/BsFBXImporter.cpp

@@ -19,6 +19,7 @@
 #include "BsPhysicsMesh.h"
 #include "BsAnimationCurve.h"
 #include "BsAnimationClip.h"
+#include "BsSkeleton.h"
 #include "BsPhysics.h"
 
 namespace BansheeEngine
@@ -116,7 +117,8 @@ namespace BansheeEngine
 	{
 		Vector<SubMesh> subMeshes;
 		UnorderedMap<String, SPtr<AnimationCurves>> dummy;
-		SPtr<RendererMeshData> rendererMeshData = importMeshData(filePath, importOptions, subMeshes, dummy);
+		SPtr<Skeleton> skeleton;
+		SPtr<RendererMeshData> rendererMeshData = importMeshData(filePath, importOptions, subMeshes, dummy, skeleton);
 
 		const MeshImportOptions* meshImportOptions = static_cast<const MeshImportOptions*>(importOptions.get());
 
@@ -124,7 +126,7 @@ namespace BansheeEngine
 		if (meshImportOptions->getCPUReadable())
 			usage |= MU_CPUCACHED;
 
-		SPtr<Mesh> mesh = Mesh::_createPtr(rendererMeshData->getData(), subMeshes, usage);
+		SPtr<Mesh> mesh = Mesh::_createPtr(rendererMeshData->getData(), subMeshes, usage, skeleton);
 
 		WString fileName = filePath.getWFilename(false);
 		mesh->setName(fileName);
@@ -136,7 +138,8 @@ namespace BansheeEngine
 	{
 		Vector<SubMesh> subMeshes;
 		UnorderedMap<String, SPtr<AnimationCurves>> animationClips;
-		SPtr<RendererMeshData> rendererMeshData = importMeshData(filePath, importOptions, subMeshes, animationClips);
+		SPtr<Skeleton> skeleton;
+		SPtr<RendererMeshData> rendererMeshData = importMeshData(filePath, importOptions, subMeshes, animationClips, skeleton);
 
 		const MeshImportOptions* meshImportOptions = static_cast<const MeshImportOptions*>(importOptions.get());
 
@@ -144,7 +147,7 @@ namespace BansheeEngine
 		if (meshImportOptions->getCPUReadable())
 			usage |= MU_CPUCACHED;
 
-		SPtr<Mesh> mesh = Mesh::_createPtr(rendererMeshData->getData(), subMeshes, usage);
+		SPtr<Mesh> mesh = Mesh::_createPtr(rendererMeshData->getData(), subMeshes, usage, skeleton);
 
 		WString fileName = filePath.getWFilename(false);
 		mesh->setName(fileName);
@@ -184,7 +187,7 @@ namespace BansheeEngine
 	}
 
 	SPtr<RendererMeshData> FBXImporter::importMeshData(const Path& filePath, SPtr<const ImportOptions> importOptions, 
-		Vector<SubMesh>& subMeshes, UnorderedMap<String, SPtr<AnimationCurves>>& animation)
+		Vector<SubMesh>& subMeshes, UnorderedMap<String, SPtr<AnimationCurves>>& animation, SPtr<Skeleton>& skeleton)
 	{
 		FbxScene* fbxScene = nullptr;
 
@@ -218,7 +221,7 @@ namespace BansheeEngine
 		splitMeshVertices(importedScene);
 		generateMissingTangentSpace(importedScene, fbxImportOptions);
 
-		SPtr<RendererMeshData> rendererMeshData = generateMeshData(importedScene, fbxImportOptions, subMeshes);
+		SPtr<RendererMeshData> rendererMeshData = generateMeshData(importedScene, fbxImportOptions, subMeshes, skeleton);
 
 		// Import animation clips
 		if (!importedScene.clips.empty())
@@ -503,12 +506,16 @@ namespace BansheeEngine
 		}
 	}
 
-	SPtr<RendererMeshData> FBXImporter::generateMeshData(const FBXImportScene& scene, const FBXImportOptions& options, Vector<SubMesh>& outputSubMeshes)
+	SPtr<RendererMeshData> FBXImporter::generateMeshData(const FBXImportScene& scene, const FBXImportOptions& options, 
+		Vector<SubMesh>& outputSubMeshes, SPtr<Skeleton>& outputSkeleton)
 	{
 		Matrix4 importScale = Matrix4::scaling(options.importScale);
 
 		Vector<SPtr<MeshData>> allMeshData;
 		Vector<Vector<SubMesh>> allSubMeshes;
+		Vector<BONE_DESC> allBones;
+		UnorderedMap<FBXImportNode*, UINT32> boneMap;
+		UINT32 boneIndexOffset = 0;
 
 		for (auto& mesh : scene.meshes)
 		{
@@ -680,10 +687,10 @@ namespace BansheeEngine
 					BoneWeight* weights = (BoneWeight*)bs_stack_alloc(bufferSize);
 					for(UINT32 i = 0; i < (UINT32)numVertices; i++)
 					{
-						weights[i].index0 = mesh->boneInfluences[i].indices[0];
-						weights[i].index1 = mesh->boneInfluences[i].indices[1];
-						weights[i].index2 = mesh->boneInfluences[i].indices[2];
-						weights[i].index3 = mesh->boneInfluences[i].indices[3];
+						weights[i].index0 = mesh->boneInfluences[i].indices[0] + boneIndexOffset;
+						weights[i].index1 = mesh->boneInfluences[i].indices[1] + boneIndexOffset;
+						weights[i].index2 = mesh->boneInfluences[i].indices[2] + boneIndexOffset;
+						weights[i].index3 = mesh->boneInfluences[i].indices[3] + boneIndexOffset;
 
 						weights[i].weight0 = mesh->boneInfluences[i].weights[0];
 						weights[i].weight1 = mesh->boneInfluences[i].weights[1];
@@ -700,6 +707,76 @@ namespace BansheeEngine
 				allMeshData.push_back(meshData->getData());
 				allSubMeshes.push_back(subMeshes);
 			}
+
+			// Create bones
+			UINT32 numBones = (UINT32)mesh->bones.size();
+			for(auto& fbxBone : mesh->bones)
+			{
+				UINT32 boneIdx = (UINT32)allBones.size();
+				boneMap[fbxBone.node] = boneIdx;
+
+				allBones.push_back(BONE_DESC());
+				BONE_DESC& bone = allBones.back();
+
+				bone.name = fbxBone.node->name;
+				bone.invBindPose = fbxBone.bindPose;
+			}
+
+			boneIndexOffset += numBones;
+		}
+
+		// Generate skeleton
+		if (allBones.size() > 0)
+		{
+			// Find bone parents
+			UINT32 numProcessedBones = 0;
+
+			// Generate common root bone for all meshes
+			UINT32 rootBoneIdx = (UINT32)-1;
+			if(allMeshData.size() > 1)
+			{
+				rootBoneIdx = (UINT32)allBones.size();
+
+				allBones.push_back(BONE_DESC());
+				BONE_DESC& bone = allBones.back();
+
+				bone.name = "MultiMeshRoot";
+				bone.invBindPose = Matrix4::IDENTITY;
+				bone.parent = (UINT32)-1;
+
+				numProcessedBones++;
+			}
+
+			Stack<std::pair<FBXImportNode*, UINT32>> todo;
+			todo.push({ scene.rootNode, rootBoneIdx });
+
+			while(!todo.empty())
+			{
+				auto entry = todo.top();
+				todo.pop();
+
+				FBXImportNode* node = entry.first;
+				UINT32 parentBoneIdx = entry.second;
+
+				auto boneIter = boneMap.find(node);
+				if (boneIter != boneMap.end())
+				{
+					UINT32 boneIdx = boneIter->second;
+					allBones[boneIdx].parent = parentBoneIdx;
+					numProcessedBones++;
+
+					parentBoneIdx = boneIdx;
+				}
+
+				for (auto& child : node->children)
+					todo.push({ child, parentBoneIdx });
+			}
+
+			UINT32 numAllBones = (UINT32)allBones.size();
+			if (numProcessedBones == numAllBones)
+				outputSkeleton = Skeleton::create(allBones.data(), numAllBones);
+			else
+				LOGERR("Not all bones were found in the node hierarchy. Skeleton invalid.");
 		}
 
 		if (allMeshData.size() > 1)