Prechádzať zdrojové kódy

Updated MeshData so it is much easier to use

Marko Pintera 12 rokov pred
rodič
commit
15a13feeb0

+ 10 - 21
CamelotClient/CmTestTextSprite.cpp

@@ -34,37 +34,26 @@ namespace CamelotEngine
 		UINT32 numIndices = numTextFaces * 6;
 
 		std::shared_ptr<MeshData> textData(new MeshData());
-		textData->declaration->addElement(0, 0, VET_FLOAT3, VES_POSITION);
-		textData->declaration->addElement(0, 12, VET_FLOAT2, VES_TEXCOORD);
 
-		textData->index = new int[numIndices];
-		textData->indexCount = numIndices;
-		textData->vertexCount = numVertices;
-		
-		std::shared_ptr<MeshData::VertexData> vertData(new MeshData::VertexData(numVertices));
-		vertData->vertex = new Vector3[numVertices];
-		vertData->uv0 = new Vector2[numVertices];
+		auto indices = new UINT32[numIndices];
+		auto vertices = new Vector3[numVertices];
+		auto uvs = new Vector2[numVertices];
 
-		Vector2* vec2Buffer = new Vector2[numVertices];
+		auto vec2Buffer = new Vector2[numVertices];
 
-		mTextSprite->fillBuffer(vec2Buffer, vertData->uv0, (UINT32*)textData->index, 0, numTextFaces);
+		mTextSprite->fillBuffer(vec2Buffer, uvs, indices, 0, numTextFaces);
 
 		for(UINT32 i = 0; i < numVertices; i++)
-		{
-			vertData->vertex[i] = Vector3(vec2Buffer[i].x, vec2Buffer[i].y, 0.0f);
-		}
+			vertices[i] = Vector3(vec2Buffer[i].x, vec2Buffer[i].y, 0.0f);
 
-		textData->vertexBuffers[0] = vertData;
+		delete[] vec2Buffer;
 
-		MeshData::SubMeshData subMeshData;
-		subMeshData.indexOffset = 0;
-		subMeshData.indexCount = numIndices;
-		textData->subMeshes.push_back(subMeshData);
+		textData->setPositions(vertices, numVertices);
+		textData->setUV0(uvs, numVertices);
+		textData->setIndices(indices, numIndices);
 
 		mTextMesh->setMeshData(textData);
 
-		delete[] vec2Buffer;
-
 		mTextRenderable->setMesh(mTextMesh);
 
 		UINT32 nearestSize = font->getClosestAvailableSize(12);

+ 1 - 0
CamelotCore/CamelotCore.vcxproj

@@ -319,6 +319,7 @@
     <ClCompile Include="Source\CmImportOptions.cpp" />
     <ClCompile Include="Source\CmIndexBuffer.cpp" />
     <ClCompile Include="Source\CmIndexData.cpp" />
+    <ClCompile Include="Source\CmMeshDataRTTI.cpp" />
     <ClCompile Include="Source\CmMeshManager.cpp" />
     <ClCompile Include="Source\CmOcclusionQuery.cpp" />
     <ClCompile Include="Source\CmPixelBuffer.cpp" />

+ 3 - 0
CamelotCore/CamelotCore.vcxproj.filters

@@ -662,5 +662,8 @@
     <ClCompile Include="Source\CmTextSprite.cpp">
       <Filter>Source Files\2D</Filter>
     </ClCompile>
+    <ClCompile Include="Source\CmMeshDataRTTI.cpp">
+      <Filter>Source Files\RTTI</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 229 - 26
CamelotCore/Include/CmMeshData.h

@@ -3,58 +3,261 @@
 #include "CmPrerequisites.h"
 #include "CmIReflectable.h"
 #include "CmVertexBuffer.h"
+#include "CmIndexBuffer.h"
+#include "CmVertexDeclaration.h"
 
 namespace CamelotEngine
 {
 	class CM_EXPORT MeshData : public IReflectable
 	{
 	public:
-		struct SubMeshData
+		struct VertexElementData : public IReflectable
 		{
-			SubMeshData():
-				indexOffset(0), indexCount(0)
+			VertexElementData(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx, UINT8* _data, UINT32 numElements)
+				:data(_data), elementCount(numElements), element(streamIdx, 0, type, semantic, semanticIdx)
 			{ }
 
-			int indexOffset;
-			int indexCount;
+			UINT8* data;
+			UINT32 elementCount;
+			VertexElement element;
+
+			/************************************************************************/
+			/* 								SERIALIZATION                      		*/
+			/************************************************************************/
+		public:
+			VertexElementData()
+			:data(nullptr), elementCount(0) 
+			{} // Serialization only constructor
+
+			friend class VertexElementDataRTTI;
+			static RTTITypeBase* getRTTIStatic();
+			virtual RTTITypeBase* getRTTI() const;
 		};
 
-		struct CM_EXPORT VertexData : public IReflectable
+		struct IndexElementData : public IReflectable
 		{
-			VertexData(UINT32 vertexCount, UINT32 streamIdx = 0);
-			~VertexData();
-
-			Vector3* vertex;
-			Color* color;
-			Vector3* normal;
-			Vector3* tangent;
-			Vector3* bitangent;
-			Vector2* uv0;
-			Vector2* uv1;
+			IndexElementData()
+				:numIndices(0), subMesh(0), elementSize(0), indices(nullptr)
+			{ }
 
-			UINT32 vertexCount;
-			UINT32 streamIdx;
+			UINT8* indices;
+			UINT32 numIndices;
+			UINT32 elementSize;
+			UINT32 subMesh;
 
 			/************************************************************************/
 			/* 								SERIALIZATION                      		*/
 			/************************************************************************/
 		public:
-			friend class VertexDataRTTI;
+			friend class IndexElementDataRTTI;
 			static RTTITypeBase* getRTTIStatic();
 			virtual RTTITypeBase* getRTTI() const;
 		};
 
-		MeshData();
+		MeshData(IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 		~MeshData();
 
-		int* index;
+		/**
+		 * @brief	Provides a convenient way of setting mesh positions. 
+		 *
+		 * @param 	elements			Pointer to pre-allocated array of positions. Any previous position data will be deleted.
+		 * @param	numElements			Number of elements in the elements array.
+		 * @param	streamIdx			(optional) Zero-based index of the stream. Each stream will 
+		 * 								internally be represented as a single vertex buffer.
+		 * 								
+		 * @note MeshData will take ownership of the provided memory, and will delete it upon 
+		 * 		 destruction or when you replace it with other data.
+		 */
+		void setPositions(Vector2* elements, UINT32 numElements, UINT32 streamIdx = 0);
+
+		/**
+		 * @brief	Provides a convenient way of setting mesh positions. 
+		 *
+		 * @param 	elements			Pointer to pre-allocated array of positions. Any previous position data will be deleted.
+		 * @param	numElements			Number of elements in the elements array.
+		 * @param	streamIdx			(optional) Zero-based index of the stream. Each stream will 
+		 * 								internally be represented as a single vertex buffer.
+		 * 								
+		 * @note MeshData will take ownership of the provided memory, and will delete it upon 
+		 * 		 destruction or when you replace it with other data.
+		 */
+		void setPositions(Vector3* elements, UINT32 numElements, UINT32 streamIdx = 0);
+
+		/**
+		 * @brief	Provides a convenient way of setting mesh positions. 
+		 *
+		 * @param 	elements			Pointer to pre-allocated array of positions. Any previous position data will be deleted.
+		 * @param	numElements			Number of elements in the elements array.
+		 * @param	streamIdx			(optional) Zero-based index of the stream. Each stream will 
+		 * 								internally be represented as a single vertex buffer.
+		 * 								
+		 * @note MeshData will take ownership of the provided memory, and will delete it upon 
+		 * 		 destruction or when you replace it with other data.
+		 * 		 
+		 */
+		void setPositions(Vector4* elements, UINT32 numElements, UINT32 streamIdx = 0);
+
+		/**
+		 * @brief	Provides a convenient way of setting mesh normals.
+		 *
+		 * @param 	elements			Pointer to pre-allocated array of normals. Any previous normal data will be deleted.
+		 * @param	numElements			Number of elements in the elements array.
+		 * @param	streamIdx			(optional) Zero-based index of the stream. Each stream will 
+		 * 								internally be represented as a single vertex buffer.
+		 * 								
+		 * @note MeshData will take ownership of the provided memory, and will delete it upon 
+		 * 		 destruction or when you replace it with other data.
+		 */
+		void setNormals(Vector3* elements, UINT32 numElements, UINT32 streamIdx = 0);
+
+		/**
+		 * @brief	Provides a convenient way of setting mesh tangents.
+		 *
+		 * @param 	elements			Pointer to pre-allocated array of tangents. Any previous tangent data will be deleted.
+		 * @param	numElements			Number of elements in the elements array.
+		 * @param	streamIdx			(optional) Zero-based index of the stream. Each stream will 
+		 * 								internally be represented as a single vertex buffer.
+		 * 								
+		 * @note MeshData will take ownership of the provided memory, and will delete it upon 
+		 * 		 destruction or when you replace it with other data.
+		 */
+		void setTangents(Vector3* elements, UINT32 numElements, UINT32 streamIdx = 0);
+
+		/**
+		 * @brief	Provides a convenient way of setting mesh tangents.
+		 *
+		 * @param 	elements			Pointer to pre-allocated array of tangents. Any previous tangent data will be deleted.
+		 * @param	numElements			Number of elements in the elements array.
+		 * @param	streamIdx			(optional) Zero-based index of the stream. Each stream will 
+		 * 								internally be represented as a single vertex buffer.
+		 * 								
+		 * @note MeshData will take ownership of the provided memory, and will delete it upon 
+		 * 		 destruction or when you replace it with other data.
+		 */
+		void setTangents(Vector4* elements, UINT32 numElements, UINT32 streamIdx = 0);
+
+		/**
+		 * @brief	Provides a convenient way of setting mesh bitangents. 
+		 *
+		 * @param 	elements			Pointer to pre-allocated array of bitangents. Any previous bitangent data will be deleted.
+		 * @param	numElements			Number of elements in the elements array.
+		 * @param	streamIdx			(optional) Zero-based index of the stream. Each stream will 
+		 * 								internally be represented as a single vertex buffer.
+		 * 								
+		 * @note MeshData will take ownership of the provided memory, and will delete it upon 
+		 * 		 destruction or when you replace it with other data.
+		 */
+		void setBitangents(Vector3* elements, UINT32 numElements, UINT32 streamIdx = 0);
+
+		/**
+		 * @brief	Provides a convenient way of setting mesh texture coordinates.
+		 *
+		 * @param 	elements			Pointer to pre-allocated array of texture coordinates. Any previous uv0 data will be deleted.
+		 * @param	numElements			Number of elements in the elements array.
+		 * @param	streamIdx			(optional) Zero-based index of the stream. Each stream will 
+		 * 								internally be represented as a single vertex buffer.
+		 * 								
+		 * @note MeshData will take ownership of the provided memory, and will delete it upon 
+		 * 		 destruction or when you replace it with other data.
+		 */
+		void setUV0(Vector2* elements, UINT32 numElements, UINT32 streamIdx = 0);
+
+		/**
+		 * @brief	Provides a convenient way of setting mesh texture coordinates. 
+		 *
+		 * @param 	elements			Pointer to pre-allocated array of texture coordinates. Any previous uv1 data will be deleted.
+		 * @param	numElements			Number of elements in the elements array.
+		 * @param	streamIdx			(optional) Zero-based index of the stream. Each stream will 
+		 * 								internally be represented as a single vertex buffer.
+		 * 								
+		 * @note MeshData will take ownership of the provided memory, and will delete it upon 
+		 * 		 destruction or when you replace it with other data.
+		 */
+		void setUV1(Vector2* elements, UINT32 numElements, UINT32 streamIdx = 0);
+
+		/**
+		 * @brief	Provides a convenient way of setting mesh colors. 
+		 *
+		 * @param 	elements			Pointer to pre-allocated array of colors. Any previous color data will be deleted.
+		 * @param	numElements			Number of elements in the elements array.
+		 * @param	streamIdx			(optional) Zero-based index of the stream. Each stream will 
+		 * 								internally be represented as a single vertex buffer.
+		 * 								
+		 * @note MeshData will take ownership of the provided memory, and will delete it upon 
+		 * 		 destruction or when you replace it with other data.
+		 */
+		void setColors(Color* elements, UINT32 numElements, UINT32 streamIdx = 0);
+
+		/**
+		 * @brief	Adds (or replaces) a new set of vertex element data. Anything that was previously
+		 * 			present at the same data slot is removed.
+		 *
+		 * @param	type	   	Type of the vertex element. Determines size.
+		 * @param	semantic   	Semantic that allows the engine to connect the data to a shader input slot.
+		 * @param	elements   	Allocated array of elements. Total size should be size of element type * number of elements. Any previous data at the same slot will be deleted.
+		 * @param	numElements	Number of elements in the array.
+		 * @param	semanticIdx	(optional) If there are multiple semantics with the same name, use different index to differentiate between them.
+		 * @param	streamIdx  	(optional) Zero-based index of the stream. Each stream will internally be represented as a single vertex buffer.
+		 */
+		void setVertexElementData(VertexElementType type, VertexElementSemantic semantic, UINT8* elements, UINT32 numElements, UINT32 semanticIdx = 0, UINT32 streamIdx = 0);
+
+		/**
+		 * @brief	Sets a list of indices for the specified sub mesh. Any indexes previously
+		 * 			set for the sub mesh are deleted.
+		 *
+		 * @param 	indices	If non-null, the indices.
+		 * @param	numIndices	   	Number of indices.
+		 * @param	subMesh		   	(optional) the sub mesh.
+		 */
+		void setIndices(UINT32* indices, UINT32 numIndices, UINT32 subMesh = 0);
+
+		/**
+		 * @brief	Sets a list of indices for the specified sub mesh. Any indexes previously
+		 * 			set for the sub mesh are deleted.
+		 *
+		 * @param 	indices	If non-null, the indices.
+		 * @param	numIndices	   	Number of indices.
+		 * @param	subMesh		   	(optional) the sub mesh.
+		 */
+		void setIndices(UINT16* indices, UINT32 numIndices, UINT32 subMesh = 0);
+
+		/**
+		 * @brief	Query if we have vertex data for the specified semantic.
+		 */
+		bool hasElement(VertexElementSemantic semantic, UINT32 semanticIdx = 0, UINT32 streamIdx = 0) const;
+
+		/**
+		 * @brief	Creates a new vertex declaration based on set vertex elements.
+		 */
+		VertexDeclarationPtr createDeclaration() const;
+
+		UINT32 getNumSubmeshes() const { return (UINT32)mIndices.size(); }
+		UINT32 getNumVertices() const;
+		UINT32 getNumIndices(UINT32 subMesh) const;
+
+		UINT16* getIndices16(UINT32 subMesh) const;
+		UINT32* getIndices32(UINT32 subMesh) const;
+
+		vector<VertexElement>::type getVertexElements() const;
+
+		MeshData::VertexElementData& getVertElemData(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx);
+
+		UINT32 getIndexElementSize()
+		{
+			return mIndexType == IndexBuffer::IT_32BIT ? sizeof(UINT32) : sizeof(UINT16);
+		}
+
+		static MeshDataPtr combine(const vector<MeshDataPtr>::type& elements);
+
+	private:
+		friend class Mesh;
+
+		vector<IndexElementData>::type mIndices;
+		map<UINT32, vector<VertexElementData>::type>::type mVertexData;
 
-		int indexCount;
-		int vertexCount;
+		IndexBuffer::IndexType mIndexType;
 
-		VertexDeclarationPtr declaration;
-		map<int, std::shared_ptr<VertexData>>::type vertexBuffers;
-		vector<SubMeshData>::type subMeshes;
+		void clearIfItExists(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx);
 
 		/************************************************************************/
 		/* 								SERIALIZATION                      		*/

+ 90 - 80
CamelotCore/Include/CmMeshDataRTTI.h

@@ -8,150 +8,160 @@
 
 namespace CamelotEngine
 {
-	class CM_EXPORT VertexDataRTTI : public RTTIType<MeshData::VertexData, IReflectable, VertexDataRTTI>
+	class CM_EXPORT VertexElementDataRTTI : public RTTIType<MeshData::VertexElementData, IReflectable, VertexElementDataRTTI>
 	{
 	private:
-		ManagedDataBlock getVertex(MeshData::VertexData* obj) { return ManagedDataBlock((UINT8*)obj->vertex, obj->vertexCount * sizeof(Vector3), false); }	
-		void setVertex(MeshData::VertexData* obj, ManagedDataBlock val) { obj->vertex = (Vector3*)val.getData(); } 
+		ManagedDataBlock getVertexData(MeshData::VertexElementData* obj) { return ManagedDataBlock(obj->data, obj->elementCount * obj->element.getSize(), false); }	
+		void setVertexData(MeshData::VertexElementData* obj, ManagedDataBlock val) { obj->data = val.getData(); } 
 
-		ManagedDataBlock getColor(MeshData::VertexData* obj) { return ManagedDataBlock((UINT8*)obj->color, obj->vertexCount * sizeof(Color), false); }	
-		void setColor(MeshData::VertexData* obj, ManagedDataBlock val) { obj->color = (Color*)val.getData(); } 
+		UINT32& getNumElements(MeshData::VertexElementData* obj) { return obj->elementCount; }
+		void setNumElements(MeshData::VertexElementData* obj, UINT32& value) { obj->elementCount = value; }
 
-		ManagedDataBlock getNormal(MeshData::VertexData* obj) { return ManagedDataBlock((UINT8*)obj->normal, obj->vertexCount * sizeof(Vector3), false); }	
-		void setNormal(MeshData::VertexData* obj, ManagedDataBlock val) { obj->normal = (Vector3*)val.getData(); } 
+		VertexElement& getVertexElement(MeshData::VertexElementData* obj) { return obj->element; }
+		void setVertexElement(MeshData::VertexElementData* obj, VertexElement& value) { obj->element = value; }
 
-		ManagedDataBlock getTangent(MeshData::VertexData* obj) { return ManagedDataBlock((UINT8*)obj->tangent, obj->vertexCount * sizeof(Vector3), false); }	
-		void setTangent(MeshData::VertexData* obj, ManagedDataBlock val) { obj->tangent = (Vector3*)val.getData(); } 
+	public:
+		VertexElementDataRTTI()
+		{
+			addDataBlockField("data", 0, &VertexElementDataRTTI::getVertexData, &VertexElementDataRTTI::setVertexData);
+			addPlainField("elementCount", 1, &VertexElementDataRTTI::getNumElements, &VertexElementDataRTTI::setNumElements);
+			addPlainField("element", 2, &VertexElementDataRTTI::getVertexElement, &VertexElementDataRTTI::setVertexElement);
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject() 
+		{
+			return std::shared_ptr<MeshData::VertexElementData>(new MeshData::VertexElementData());
+		}
+
+		virtual const String& getRTTIName() 
+		{
+			static String name = "VertexElementData";
+			throw name;
+		}
+
+		virtual UINT32 getRTTIId() 
+		{
+			return TID_VertexElementData;
+		}
+	};
 
-		ManagedDataBlock getBitangent(MeshData::VertexData* obj) { return ManagedDataBlock((UINT8*)obj->bitangent, obj->vertexCount * sizeof(Vector3), false); }	
-		void setBitangent(MeshData::VertexData* obj, ManagedDataBlock val) { obj->bitangent = (Vector3*)val.getData(); } 
+	class CM_EXPORT IndexElementDataRTTI : public RTTIType<MeshData::IndexElementData, IReflectable, IndexElementDataRTTI>
+	{
+	private:
+		ManagedDataBlock getIndexData(MeshData::IndexElementData* obj) { return ManagedDataBlock(obj->indices, obj->numIndices * obj->elementSize, false); }	
+		void setIndexData(MeshData::IndexElementData* obj, ManagedDataBlock val) { obj->indices = val.getData(); } 
 
-		ManagedDataBlock getUV0(MeshData::VertexData* obj) { return ManagedDataBlock((UINT8*)obj->uv0, obj->vertexCount * sizeof(Vector2), false); }	
-		void setUV0(MeshData::VertexData* obj, ManagedDataBlock val) { obj->uv0 = (Vector2*)val.getData(); } 
+		UINT32& getNumIndices(MeshData::IndexElementData* obj) { return obj->numIndices; }
+		void setNumIndices(MeshData::IndexElementData* obj, UINT32& value) { obj->numIndices = value; }
 
-		ManagedDataBlock getUV1(MeshData::VertexData* obj) { return ManagedDataBlock((UINT8*)obj->uv1, obj->vertexCount * sizeof(Vector2), false); }	
-		void setUV1(MeshData::VertexData* obj, ManagedDataBlock val) { obj->uv1 = (Vector2*)val.getData(); } 
+		UINT32& getElementSize(MeshData::IndexElementData* obj) { return obj->elementSize; }
+		void setElementSize(MeshData::IndexElementData* obj, UINT32& value) { obj->elementSize = value; }
 
-		CM_SETGET_MEMBER(vertexCount, UINT32, MeshData::VertexData);
-		CM_SETGET_MEMBER(streamIdx, UINT32, MeshData::VertexData);
+		UINT32& getSubMesh(MeshData::IndexElementData* obj) { return obj->subMesh; }
+		void setSubMesh(MeshData::IndexElementData* obj, UINT32& value) { obj->subMesh = value; }
 	public:
-		VertexDataRTTI()
+		IndexElementDataRTTI()
 		{
-			addDataBlockField("vertex", 0, &VertexDataRTTI::getVertex, &VertexDataRTTI::setVertex);
-			addDataBlockField("color", 1, &VertexDataRTTI::getColor, &VertexDataRTTI::setColor);
-			addDataBlockField("normal", 2, &VertexDataRTTI::getNormal, &VertexDataRTTI::setNormal);
-			addDataBlockField("tangent", 3, &VertexDataRTTI::getTangent, &VertexDataRTTI::setTangent);
-			addDataBlockField("bitangent", 4, &VertexDataRTTI::getBitangent, &VertexDataRTTI::setBitangent);
-			addDataBlockField("uv0", 5, &VertexDataRTTI::getUV0, &VertexDataRTTI::setUV0);
-			addDataBlockField("uv1", 6, &VertexDataRTTI::getUV1, &VertexDataRTTI::setUV1);
-
-			CM_ADD_PLAINFIELD(vertexCount, 7, VertexDataRTTI)
-			CM_ADD_PLAINFIELD(streamIdx, 8, VertexDataRTTI)
+			addDataBlockField("indices", 0, &IndexElementDataRTTI::getIndexData, &IndexElementDataRTTI::setIndexData);
+			addPlainField("numIndices", 1, &IndexElementDataRTTI::getNumIndices, &IndexElementDataRTTI::setNumIndices);
+			addPlainField("elementSize", 2, &IndexElementDataRTTI::getElementSize, &IndexElementDataRTTI::setElementSize);
+			addPlainField("subMesh", 3, &IndexElementDataRTTI::getSubMesh, &IndexElementDataRTTI::setSubMesh);
 		}
 
 		virtual std::shared_ptr<IReflectable> newRTTIObject() 
 		{
-			return std::shared_ptr<MeshData::VertexData>(new MeshData::VertexData(0));
+			return std::shared_ptr<MeshData::IndexElementData>(new MeshData::IndexElementData());
 		}
 
 		virtual const String& getRTTIName() 
 		{
-			static String name = "MeshData::VertexData";
+			static String name = "IndexElementData";
 			throw name;
 		}
 
 		virtual UINT32 getRTTIId() 
 		{
-			return TID_VertexData;
+			return TID_IndexElementData;
 		}
 	};
 
-	CM_ALLOW_MEMCPY_SERIALIZATION(MeshData::SubMeshData);
+	CM_ALLOW_MEMCPY_SERIALIZATION(IndexBuffer::IndexType);
 
 	class CM_EXPORT MeshDataRTTI : public RTTIType<MeshData, IReflectable, MeshDataRTTI>
 	{
 	private:
-		CM_SETGET_MEMBER(indexCount, INT32, MeshData)
-		CM_SETGET_MEMBER(vertexCount, INT32, MeshData);
-
-		ManagedDataBlock getIndex(MeshData* obj) { return ManagedDataBlock((UINT8*)obj->index, obj->indexCount * sizeof(int), false); }	
-		void setIndex(MeshData* obj, ManagedDataBlock val) { obj->index = (int*)val.getData(); } 
+		struct TempMeshData
+		{
+			vector<MeshData::VertexElementData>::type vertexElements;
+		};
 
-		/************************************************************************/
-		/* 								subMeshes                      			*/
-		/************************************************************************/
-		MeshData::SubMeshData& getSubmesh(MeshData* obj, UINT32 idx)
+		MeshData::VertexElementData& getVertexElementData(MeshData* obj, UINT32 arrayIdx)
 		{
-			return obj->subMeshes[idx];
+			auto tempData = boost::any_cast<std::shared_ptr<TempMeshData>>(obj->mRTTIData);
+			return tempData->vertexElements[arrayIdx];
 		}
 
-		void setSubmesh(MeshData* obj, UINT32 idx, MeshData::SubMeshData& data)
+		void setVertexElementData(MeshData* obj, UINT32 arrayIdx, MeshData::VertexElementData& value)
 		{
-			obj->subMeshes[idx] = data;
+			obj->setVertexElementData(value.element.getType(), value.element.getSemantic(), value.data, value.elementCount, value.element.getIndex(), value.element.getSource());
 		}
 
-		UINT32 getSubmeshArraySize(MeshData* obj)
+		UINT32 getNumVertexElementData(MeshData* obj)
 		{
-			return (UINT32)obj->subMeshes.size();
+			auto tempData = boost::any_cast<std::shared_ptr<TempMeshData>>(obj->mRTTIData);
+			return (UINT32)tempData->vertexElements.size();
 		}
 
-		void setSubmeshArraySize(MeshData* obj, UINT32 size)
+		void setNumVertexElementData(MeshData* obj, UINT32 numElements)
 		{
-			obj->subMeshes.resize(size);
+			// Do nothing
 		}
 
-		/************************************************************************/
-		/* 								vertexDeclaration                  		*/
-		/************************************************************************/
-
-		VertexDeclarationPtr getVertexDecl(MeshData* obj) { return obj->declaration; }
-		void setVertexDecl(MeshData* obj, VertexDeclarationPtr vertexDecl) { obj->declaration = vertexDecl; }
-
-		/************************************************************************/
-		/* 								vertexData                      		*/
-		/************************************************************************/
-		std::shared_ptr<MeshData::VertexData> getVertexData(MeshData* obj, UINT32 idx)
+		MeshData::IndexElementData& getIndexElementData(MeshData* obj, UINT32 arrayIdx)
 		{
-			int curIdx = 0;
-			for(auto iter = obj->vertexBuffers.begin(); iter != obj->vertexBuffers.end(); ++iter)
-			{
-				if(curIdx == idx)
-					return iter->second;
+			return obj->mIndices[arrayIdx];
+		}
 
-				curIdx++;
-			}
+		void setIndexElementData(MeshData* obj, UINT32 arrayIdx, MeshData::IndexElementData& value)
+		{
+			obj->mIndices[arrayIdx] = value;
+		}
 
-			CM_EXCEPT(InvalidParametersException, "Invalid index: " + toString(idx));
+		UINT32 getNumIndexElementData(MeshData* obj)
+		{
+			return (UINT32)obj->mIndices.size();
 		}
 
-		void setVertexData(MeshData* obj, UINT32 idx, std::shared_ptr<MeshData::VertexData> data)
+		void setNumIndexElementData(MeshData* obj, UINT32 numElements)
 		{
-			obj->vertexBuffers[data->streamIdx] = data;
+			obj->mIndices.resize(numElements);
 		}
 
-		UINT32 getVertexDataArraySize(MeshData* obj)
+		IndexBuffer::IndexType& getIndexType(MeshData* obj)
 		{
-			return (UINT32)obj->vertexBuffers.size();
+			return obj->mIndexType;
 		}
 
-		void setVertexDataArraySize(MeshData* obj, UINT32 size)
+		void setIndexType(MeshData* obj, IndexBuffer::IndexType& value)
 		{
-			// Do nothing, map will expand as entries are added
+			obj->mIndexType = value;
 		}
+
 	public:
 		MeshDataRTTI()
 		{
-			addDataBlockField("index", 0, &MeshDataRTTI::getIndex, &MeshDataRTTI::setIndex);
+			addReflectableArrayField("mVertexData", 0, &MeshDataRTTI::getVertexElementData, 
+				&MeshDataRTTI::getNumVertexElementData, &MeshDataRTTI::setVertexElementData, &MeshDataRTTI::setNumVertexElementData);
 
-			CM_ADD_PLAINFIELD(indexCount, 1, MeshDataRTTI)
-			CM_ADD_PLAINFIELD(vertexCount, 2, MeshDataRTTI)
+			addReflectableArrayField("mIndexBuffer", 1, &MeshDataRTTI::getIndexElementData, 
+				&MeshDataRTTI::getNumIndexElementData, &MeshDataRTTI::setIndexElementData, &MeshDataRTTI::setNumIndexElementData);
 
-			addPlainArrayField("subMeshes", 3, &MeshDataRTTI::getSubmesh, &MeshDataRTTI::getSubmeshArraySize, &MeshDataRTTI::setSubmesh, &MeshDataRTTI::setSubmeshArraySize);
-			addReflectablePtrField("vertexDeclaration", 4, &MeshDataRTTI::getVertexDecl, &MeshDataRTTI::setVertexDecl);
-			addReflectablePtrArrayField("vertexBuffer", 5, &MeshDataRTTI::getVertexData, &MeshDataRTTI::getVertexDataArraySize, 
-				&MeshDataRTTI::setVertexData, &MeshDataRTTI::setVertexDataArraySize);
+			addPlainField("mIndexType", 2, &MeshDataRTTI::getIndexType, &MeshDataRTTI::setIndexType);
 		}
 
+		virtual void onSerializationStarted(IReflectable* obj);
+		virtual void onSerializationEnded(IReflectable* obj);
+
 		virtual std::shared_ptr<IReflectable> newRTTIObject() 
 		{
 			return std::shared_ptr<MeshData>(new MeshData());

+ 3 - 2
CamelotCore/Include/CmPrerequisites.h

@@ -232,7 +232,7 @@ namespace CamelotEngine
 		TID_Mesh = 1002,
 		TID_MeshData = 1003,
 		TID_VertexDeclaration = 1004,
-		TID_VertexData = 1005,
+		TID_VertexElementData = 1005,
 		TID_Component = 1006,
 		TID_Camera = 1007,
 		TID_Renderable = 1008,
@@ -274,7 +274,8 @@ namespace CamelotEngine
 		TID_STDVECTOR = 1054,
 		TID_STDMAP = 1055,
 		TID_FontImportOptions = 1056,
-		TID_FontData = 1057
+		TID_FontData = 1057,
+		TID_IndexElementData = 1058
 	};
 
 	/**

+ 3 - 0
CamelotCore/Include/CmVertexDeclaration.h

@@ -220,6 +220,9 @@ namespace CamelotEngine
 		size_t calculateHash() const;
 
     };
+
+	CM_ALLOW_MEMCPY_SERIALIZATION(VertexElement);
+
     /** This class declares the format of a set of vertex inputs, which
         can be issued to the rendering API through a RenderOperation.
 	@remarks

+ 0 - 2
CamelotCore/Include/CmVertexDeclarationRTTI.h

@@ -7,8 +7,6 @@
 
 namespace CamelotEngine
 {
-	CM_ALLOW_MEMCPY_SERIALIZATION(VertexElement);
-
 	class VertexDeclarationRTTI : public RTTIType<VertexDeclaration, IReflectable, VertexDeclarationRTTI>
 	{
 	private:

+ 89 - 145
CamelotCore/Source/CmMesh.cpp

@@ -38,7 +38,35 @@ namespace CamelotEngine
 
 		if(meshData == nullptr)
 		{
-			CM_EXCEPT(InternalErrorException, "Cannot load mesh. Mesh data is null.");
+			CM_EXCEPT(InvalidParametersException, "Cannot load mesh. Mesh data is null.");
+		}
+
+		// Ensure all vertex elements are of proper size
+		UINT32 numVertices = 0;
+
+		auto vertElemDataPerStream = meshData->mVertexData;
+		MeshData::VertexElementData* firstElemData = nullptr;
+		if(vertElemDataPerStream.size() > 0)
+		{
+			auto vertElemData = vertElemDataPerStream.begin()->second;
+			auto firstVertElem = vertElemData.begin();
+			if(firstVertElem != vertElemData.end())
+			{
+				numVertices = firstVertElem->elementCount;
+			}
+		}
+
+		for(auto& vertElems : meshData->mVertexData)
+		{
+			for(auto& vertElem : vertElems.second)
+			{
+				if(vertElem.elementCount != numVertices)
+				{
+					CM_EXCEPT(InvalidParametersException, "All vertex element arrays in MeshData need to be of the same size. Found an array with semantic: "
+						+ toString(vertElem.element.getSemantic()) + " and element count: " + toString(vertElem.elementCount) + ". This doesn't match with other "
+						+ "element with semantic: " + toString(firstElemData->element.getSemantic()) + " and element count: " + toString(firstElemData->elementCount));
+				}
+			}
 		}
 
 		mSubMeshes.clear();
@@ -50,23 +78,37 @@ namespace CamelotEngine
 			delete mIndexData;
 
 		// Submeshes
-		for(UINT32 i = 0; i < meshData->subMeshes.size(); i++)
-			mSubMeshes.push_back(SubMesh(meshData->subMeshes[i].indexOffset, meshData->subMeshes[i].indexCount));
+		UINT32 indexOffset = 0;
+		UINT32 totalIndexCount = 0;
+		for(auto& i : meshData->mIndices)
+		{
+			UINT32 numIndices = i.numIndices;
+
+			if(numIndices > 0)
+			{
+				mSubMeshes.push_back(SubMesh(indexOffset, numIndices));
+				indexOffset += numIndices;
+				totalIndexCount += numIndices;
+			}
+		}
 
 		// Indices
 		mIndexData = new IndexData();
 
-		mIndexData->indexCount = meshData->indexCount;
+		mIndexData->indexCount = totalIndexCount;
 		mIndexData->indexBuffer = HardwareBufferManager::instance().createIndexBuffer(
-			IndexBuffer::IT_32BIT,
+			meshData->mIndexType,
 			mIndexData->indexCount, 
 			GBU_STATIC);
 
-		UINT32* idxData = static_cast<UINT32*>(mIndexData->indexBuffer->lock(GBL_WRITE_ONLY_DISCARD));
+		UINT8* idxData = static_cast<UINT8*>(mIndexData->indexBuffer->lock(GBL_WRITE_ONLY));
+		UINT32 idxElementSize = meshData->getIndexElementSize();
 
-		for(UINT32 i = 0; i < mIndexData->indexCount; i++)
+		indexOffset = 0;
+		for(auto& i : meshData->mIndices)
 		{
-			idxData[i] = (UINT32)meshData->index[i];
+			memcpy(&idxData[indexOffset], i.indices, i.numIndices * idxElementSize);
+			indexOffset += i.numIndices;
 		}
 
 		mIndexData->indexBuffer->unlock();
@@ -74,12 +116,15 @@ namespace CamelotEngine
 		// Vertices
 		mVertexData = new VertexData();
 
-		mVertexData->vertexCount = meshData->vertexCount;
-		mVertexData->vertexDeclaration = meshData->declaration->clone();
+		mVertexData->vertexCount = numVertices;
+		mVertexData->vertexDeclaration = meshData->createDeclaration();
 
-		for(auto iter = meshData->vertexBuffers.begin(); iter != meshData->vertexBuffers.end(); ++iter)
+		for(auto& vertElems : meshData->mVertexData)
 		{
-			int streamIdx = iter->first; 
+			UINT32 streamIdx = vertElems.first;
+
+			if(vertElems.second.size() == 0)
+				continue;
 
 			VertexBufferPtr vertexBuffer = HardwareBufferManager::instance().createVertexBuffer(
 				mVertexData->vertexDeclaration->getVertexSize(streamIdx),
@@ -89,75 +134,22 @@ namespace CamelotEngine
 			mVertexData->setBuffer(streamIdx, vertexBuffer);
 
 			UINT32 vertexSize = vertexBuffer->getVertexSize();
-			UINT8* vertBufferData = static_cast<UINT8*>(vertexBuffer->lock(GBL_WRITE_ONLY_DISCARD));
+			UINT8* vertBufferData = static_cast<UINT8*>(vertexBuffer->lock(GBL_WRITE_ONLY));
 
 			UINT32 numElements = mVertexData->vertexDeclaration->getElementCount();
 
 			for(UINT32 j = 0; j < numElements; j++)
 			{
 				const VertexElement* element = mVertexData->vertexDeclaration->getElement(j);
-				VertexElementSemantic semantic = element->getSemantic();
 				UINT32 offset = element->getOffset();
 				UINT32 elemSize = element->getSize();
 
-				std::shared_ptr<MeshData::VertexData> vertexData = meshData->vertexBuffers[streamIdx];
-
-				UINT8* source = nullptr;
-				switch(semantic)
-				{
-				case VES_POSITION:
-					if(vertexData->vertex)
-						source = (UINT8*)vertexData->vertex;
-
-					break;
-				case VES_COLOR:
-					if(vertexData->color)
-						source = (UINT8*)vertexData->color;
-
-					break;
-				case VES_NORMAL:
-					if(vertexData->normal)
-						source = (UINT8*)vertexData->normal;	
-
-					break;
-				case VES_TANGENT:
-					if(vertexData->tangent)
-						source = (UINT8*)vertexData->tangent;	
-
-					break;
-				case VES_BITANGENT:
-					if(vertexData->bitangent)
-						source = (UINT8*)vertexData->bitangent;	
-
-					break;
-				case VES_TEXCOORD:
-					if(element->getIndex() == 0)
-					{
-						if(vertexData->uv0)
-							source = (UINT8*)vertexData->uv0;	
-					}
-					else if(element->getIndex() == 1)
-					{
-						if(vertexData->uv1)
-							source = (UINT8*)vertexData->uv1;	
-					}
-
-					break;
-				default:
-					break;
-				}
+				MeshData::VertexElementData& elemData = meshData->getVertElemData(element->getType(), element->getSemantic(), element->getIndex(), streamIdx);
 
-				if(source != nullptr)
-				{
-					for(UINT32 k = 0; k < mVertexData->vertexCount; k++)
-						memcpy(&vertBufferData[k * vertexSize + offset], &source[k * elemSize], elemSize);
-				}
-				else
+				UINT8* sourceData = elemData.data;
+				for(UINT32 k = 0; k < elemData.elementCount; k++)
 				{
-					LOGWRN("Vertex declaration contains semantic (" + toString(semantic) + ") but mesh doesn't have data for it. Data for the semantic will be zeroed out.");
-
-					for(UINT32 k = 0; k < mVertexData->vertexCount; k++)
-						memset(&vertBufferData[k * vertexSize + offset], 0, elemSize);
+					memcpy(&vertBufferData[k * vertexSize + offset], &sourceData[k * elemSize], elemSize);
 				}
 			}
 
@@ -174,112 +166,64 @@ namespace CamelotEngine
 
 	void Mesh::getMeshData_internal(AsyncOp& asyncOp)
 	{
-		MeshDataPtr meshData(new MeshData());
-
-		meshData->declaration = mVertexData->vertexDeclaration->clone();
-		
-		for(UINT32 i = 0; i < mSubMeshes.size(); i++)
-		{
-			MeshData::SubMeshData subMesh;
-			subMesh.indexCount = mSubMeshes[i].indexCount;
-			subMesh.indexOffset = mSubMeshes[i].indexOffset;
+		IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT;
+		if(mIndexData)
+			indexType = mIndexData->indexBuffer->getType();
 
-			meshData->subMeshes.push_back(subMesh);
-		}
+		MeshDataPtr meshData(new MeshData(indexType));
 
 		if(mIndexData)
 		{
-			meshData->indexCount = mIndexData->indexCount - mIndexData->indexStart;
-			meshData->index = new int[meshData->indexCount];
+			UINT8* idxData = static_cast<UINT8*>(mIndexData->indexBuffer->lock(GBL_READ_ONLY));
+			UINT32 idxElemSize = mIndexData->indexBuffer->getIndexSize();
 
-			UINT32* idxData = static_cast<UINT32*>(mIndexData->indexBuffer->lock(GBL_READ_ONLY));
+			for(UINT32 i = 0; i < mSubMeshes.size(); i++)
+			{
+				UINT8* indices = new UINT8[mSubMeshes[i].indexCount * idxElemSize];
+				memcpy(indices, &idxData[mSubMeshes[i].indexOffset * idxElemSize], mSubMeshes[i].indexCount * idxElemSize);
 
-			for(UINT32 i = 0; i < mIndexData->indexCount; i++)
-				meshData->index[i] = (UINT32)idxData[i];
+				if(indexType == IndexBuffer::IT_16BIT)
+					meshData->setIndices((UINT16*)indices, mSubMeshes[i].indexCount, i);
+				else
+					meshData->setIndices((UINT32*)indices, mSubMeshes[i].indexCount, i);
+			}
 
 			mIndexData->indexBuffer->unlock();
 		}
 
 		if(mVertexData)
 		{
-			meshData->vertexCount = mVertexData->vertexCount;
-			
 			auto vertexBuffers = mVertexData->getBuffers();
 
+			UINT32 streamIdx = 0;
 			for(auto iter = vertexBuffers.begin(); iter != vertexBuffers.end() ; ++iter)
 			{
 				VertexBufferPtr vertexBuffer = iter->second;
 				UINT32 vertexSize = vertexBuffer->getVertexSize();
 				UINT8* vertDataIter = static_cast<UINT8*>(vertexBuffer->lock(GBL_READ_ONLY));
 
-				std::shared_ptr<MeshData::VertexData> vertexData(new MeshData::VertexData(meshData->vertexCount, iter->first));
-				meshData->vertexBuffers[iter->first] = vertexData;
-
 				UINT32 numElements = mVertexData->vertexDeclaration->getElementCount();
 				for(UINT32 j = 0; j < numElements; j++)
 				{
 					const VertexElement* element = mVertexData->vertexDeclaration->getElement(j);
-					VertexElementSemantic semantic = element->getSemantic();
+					VertexElementType type = element->getType();
+					VertexElementSemantic semantic = element->getSemantic(); 
+					UINT32 semanticIdx = element->getIndex();
 					UINT32 offset = element->getOffset();
 					UINT32 elemSize = element->getSize();
 
-					UINT8* dest = nullptr;
-					switch(semantic)
-					{
-					case VES_POSITION:
-						vertexData->vertex = new Vector3[meshData->vertexCount];
-						dest = (UINT8*)vertexData->vertex;
-
-						break;
-					case VES_COLOR:
-						vertexData->color = new Color[meshData->vertexCount];
-						dest = (UINT8*)vertexData->color;
-
-						break;
-					case VES_NORMAL:
-						vertexData->normal = new Vector3[meshData->vertexCount];
-						dest = (UINT8*)vertexData->normal;	
-
-						break;
-					case VES_TANGENT:
-						vertexData->tangent = new Vector3[meshData->vertexCount];
-						dest = (UINT8*)vertexData->tangent;	
-
-						break;
-					case VES_BITANGENT:
-						vertexData->bitangent = new Vector3[meshData->vertexCount];
-						dest = (UINT8*)vertexData->bitangent;	
-
-						break;
-					case VES_TEXCOORD:
-						if(element->getIndex() == 0)
-						{
-							vertexData->uv0 = new Vector2[meshData->vertexCount];
-							dest = (UINT8*)vertexData->uv0;	
-						}
-						else if(element->getIndex() == 1)
-						{
-							vertexData->uv1 = new Vector2[meshData->vertexCount];
-							dest = (UINT8*)vertexData->uv1;	
-						}
-
-						break;
-					default:
-						LOGWRN("Vertex declaration contains semantic (" + toString(semantic) + ") but mesh data can't store it.");
-
-						break;
-					}
-
-					if(dest != nullptr)
-					{
-						for(UINT32 k = 0; k < mVertexData->vertexCount; k++)
-							memcpy(&dest[k * elemSize], &vertDataIter[k * vertexSize + offset], elemSize);
-					}
+					UINT8* dest = new UINT8[elemSize * mVertexData->vertexCount];
+					for(UINT32 k = 0; k < mVertexData->vertexCount; k++)
+						memcpy(&dest[k * elemSize], &vertDataIter[k * vertexSize + offset], elemSize);
+
+					meshData->setVertexElementData(type, semantic, dest, mVertexData->vertexCount, semanticIdx, streamIdx);
 				}
 
 				vertexBuffer->unlock();
+
+				streamIdx++;
 			}
-		}		
+		}
 
 		asyncOp.completeOperation(meshData);
 	}

+ 336 - 32
CamelotCore/Source/CmMeshData.cpp

@@ -3,70 +3,374 @@
 #include "CmVector3.h"
 #include "CmHardwareBufferManager.h"
 #include "CmMeshDataRTTI.h"
+#include "CmVertexDeclaration.h"
+#include "CmException.h"
 
 namespace CamelotEngine
 {
-	MeshData::VertexData::VertexData(UINT32 vertexCount, UINT32 streamIdx)
-		:vertex(nullptr), color(nullptr), normal(nullptr), tangent(nullptr), 
-		bitangent(nullptr), uv0(nullptr), uv1(nullptr), 
-		streamIdx(streamIdx), vertexCount(vertexCount)
+	MeshData::MeshData(IndexBuffer::IndexType indexType)
+	   :mIndexType(indexType)
 	{
+
 	}
 
-	MeshData::VertexData::~VertexData()
+	MeshData::~MeshData()
 	{
-		if(vertex != nullptr)
-			delete [] vertex;
+		for(auto& vertElems : mVertexData)
+		{
+			for(auto& vertElem : vertElems.second)
+			{
+				if(vertElem.data != nullptr)
+					delete[] vertElem.data;
+			}
+		}
 
-		if(color != nullptr)
-			delete [] color;
+		for(auto& indexData : mIndices)
+		{
+			if(indexData.indices != nullptr)
+				delete[] indexData.indices;
+		}
+	}
 
-		if(normal != nullptr)
-			delete [] normal;
+	void MeshData::setPositions(Vector2* elements, UINT32 numElements, UINT32 streamIdx)
+	{
+		setVertexElementData(VET_FLOAT2, VES_POSITION, (UINT8*)(elements), numElements, 0, streamIdx);
+	}
 
-		if(tangent != nullptr)
-			delete [] tangent;
+	void MeshData::setPositions(Vector3* elements, UINT32 numElements, UINT32 streamIdx)
+	{
+		setVertexElementData(VET_FLOAT3, VES_POSITION, (UINT8*)(elements), numElements, 0, streamIdx);
+	}
 
-		if(bitangent != nullptr)
-			delete [] bitangent;
+	void MeshData::setPositions(Vector4* elements, UINT32 numElements, UINT32 streamIdx)
+	{
+		setVertexElementData(VET_FLOAT4, VES_POSITION, (UINT8*)(elements), numElements, 0, streamIdx);
+	}
 
-		if(uv0 != nullptr)
-			delete [] uv0;
+	void MeshData::setNormals(Vector3* elements, UINT32 numElements, UINT32 streamIdx)
+	{
+		setVertexElementData(VET_FLOAT3, VES_NORMAL, (UINT8*)(elements), numElements, 0, streamIdx);
+	}
 
-		if(uv1 != nullptr)
-			delete [] uv1;
+	void MeshData::setTangents(Vector3* elements, UINT32 numElements, UINT32 streamIdx)
+	{
+		setVertexElementData(VET_FLOAT3, VES_TANGENT, (UINT8*)(elements), numElements, 0, streamIdx);
 	}
 
-	RTTITypeBase* MeshData::VertexData::getRTTIStatic()
+	void MeshData::setTangents(Vector4* elements, UINT32 numElements, UINT32 streamIdx)
 	{
-		return VertexDataRTTI::instance();
+		setVertexElementData(VET_FLOAT4, VES_TANGENT, (UINT8*)(elements), numElements, 0, streamIdx);
 	}
 
-	RTTITypeBase* MeshData::VertexData::getRTTI() const
+	void MeshData::setBitangents(Vector3* elements, UINT32 numElements, UINT32 streamIdx)
 	{
-		return getRTTIStatic();
+		setVertexElementData(VET_FLOAT3, VES_BITANGENT, (UINT8*)(elements), numElements, 0, streamIdx);
 	}
 
-	MeshData::MeshData()
-	   :index(nullptr),
-		indexCount(0),
-		vertexCount(0)
+	void MeshData::setUV0(Vector2* elements, UINT32 numElements, UINT32 streamIdx)
 	{
-		declaration = HardwareBufferManager::instance().createVertexDeclaration();
+		setVertexElementData(VET_FLOAT2, VES_TEXCOORD, (UINT8*)(elements), numElements, 0, streamIdx);
 	}
 
-	MeshData::~MeshData()
+	void MeshData::setUV1(Vector2* elements, UINT32 numElements, UINT32 streamIdx)
+	{
+		setVertexElementData(VET_FLOAT2, VES_TEXCOORD, (UINT8*)(elements), numElements, 1, streamIdx);
+	}
+
+	void MeshData::setColors(Color* elements, UINT32 numElements, UINT32 streamIdx)
+	{
+		setVertexElementData(VET_COLOR, VES_COLOR, (UINT8*)(elements), numElements, 0, streamIdx);
+	}
+
+	void MeshData::setVertexElementData(VertexElementType type, VertexElementSemantic semantic, UINT8* elements, UINT32 numElements, UINT32 semanticIdx, UINT32 streamIdx)
+	{
+		clearIfItExists(type, semantic, semanticIdx, streamIdx);
+
+		if(elements != nullptr)
+		{
+			vector<VertexElementData>::type& elemData = mVertexData[streamIdx];
+
+			VertexElementData newElement(type, semantic, semanticIdx, streamIdx, elements, numElements);
+			elemData.push_back(newElement);
+		}
+	}
+
+	void MeshData::setIndices(UINT32* indices, UINT32 numIndices, UINT32 subMesh)
+	{
+		if(mIndexType != IndexBuffer::IT_32BIT)
+			CM_EXCEPT(InvalidParametersException, "Trying to set 32bit indices but the MeshData was initialized as 16bit.");
+
+		if(subMesh >= mIndices.size())
+			mIndices.resize(subMesh + 1);
+
+		IndexElementData indexData = mIndices[subMesh];
+
+		if(indexData.indices != nullptr)
+			delete[] indexData.indices;
+
+		indexData.indices = (UINT8*)indices;
+		indexData.numIndices = numIndices;
+		indexData.elementSize = getIndexElementSize();
+		indexData.subMesh = subMesh;
+
+		mIndices[subMesh] = indexData;
+	}
+
+	void MeshData::setIndices(UINT16* indices, UINT32 numIndices, UINT32 subMesh)
+	{
+		if(mIndexType != IndexBuffer::IT_16BIT)
+			CM_EXCEPT(InvalidParametersException, "Trying to set 16bit indices but the MeshData was initialized as 32bit.");
+
+		if(subMesh >= mIndices.size())
+			mIndices.resize(subMesh + 1);
+
+		IndexElementData indexData = mIndices[subMesh];
+
+		if(indexData.indices != nullptr)
+			delete[] indexData.indices;
+
+		indexData.indices = (UINT8*)indices;
+		indexData.numIndices = numIndices;
+		indexData.elementSize = getIndexElementSize();
+		indexData.subMesh = subMesh;
+
+		mIndices[subMesh] = indexData;
+	}
+
+	VertexDeclarationPtr MeshData::createDeclaration() const
+	{
+		VertexDeclarationPtr declaration = HardwareBufferManager::instance().createVertexDeclaration();
+
+		for(auto& vertElems : mVertexData)
+		{
+			UINT32 offset = 0;
+			for(auto& vertElem : vertElems.second)
+			{
+				declaration->addElement(vertElems.first, offset, vertElem.element.getType(), vertElem.element.getSemantic(), vertElem.element.getIndex());
+				offset += vertElem.element.getSize();
+			}
+		}
+
+		return declaration;
+	}
+
+	UINT32 MeshData::getNumVertices() const
+	{
+		UINT32 numVertices = 0;
+
+		auto vertElemDataPerStream = mVertexData;
+		MeshData::VertexElementData* firstElemData = nullptr;
+		if(vertElemDataPerStream.size() > 0)
+		{
+			auto vertElemData = vertElemDataPerStream.begin()->second;
+			auto firstVertElem = vertElemData.begin();
+			if(firstVertElem != vertElemData.end())
+			{
+				numVertices = firstVertElem->elementCount;
+			}
+		}
+
+		for(auto& vertElems : mVertexData)
+		{
+			for(auto& vertElem : vertElems.second)
+			{
+				if(vertElem.elementCount != numVertices)
+				{
+					CM_EXCEPT(InvalidParametersException, "All vertex element arrays in MeshData need to be of the same size. Found an array with semantic: " \
+						+ toString(vertElem.element.getSemantic()) + " and element count: " + toString(vertElem.elementCount) + ". This doesn't match with other " \
+						+ "element with semantic: " + toString(firstElemData->element.getSemantic()) + " and element count: " + toString(firstElemData->elementCount));
+				}
+			}
+		}
+
+		return numVertices;
+	}
+
+	UINT32 MeshData::getNumIndices(UINT32 subMesh) const
+	{
+		return mIndices.at(subMesh).numIndices;
+	}
+
+	UINT16* MeshData::getIndices16(UINT32 subMesh) const
+	{
+		return (UINT16*)mIndices.at(subMesh).indices;
+	}
+
+	UINT32* MeshData::getIndices32(UINT32 subMesh) const
+	{
+		return (UINT32*)mIndices.at(subMesh).indices;
+	}
+
+	vector<VertexElement>::type MeshData::getVertexElements() const
+	{
+		vector<VertexElement>::type elements;
+		for(auto& vertElems : mVertexData)
+		{
+			UINT32 offset = 0;
+			for(auto& vertElem : vertElems.second)
+			{
+				elements.push_back(vertElem.element);
+			}
+		}
+
+		return elements;
+	}
+
+	MeshDataPtr MeshData::combine(const vector<MeshDataPtr>::type& elements)
 	{
-		if(index != nullptr)
-			delete [] index;
+		MeshDataPtr combinedMeshData(new MeshData());
+
+		UINT32 subMeshIndex = 0;
+		vector<VertexElement>::type combinedVertexElements;
+		vector<UINT8*>::type vertexElemData;
+		UINT32 totalVertexCount = 0;
+
+		UINT32 vertexIndexOffset = 0;
+		for(auto& meshData : elements)
+		{
+			for(UINT32 i = 0; i < meshData->getNumSubmeshes(); i++)
+			{
+				UINT32 numIndices = meshData->getNumIndices(i);
+				UINT32* indices = new UINT32[numIndices];
+
+				UINT32* sourceIndices = meshData->getIndices32(i);
+
+				for(UINT32 j = 0; j < numIndices; j++)
+					indices[j] = sourceIndices[j] + vertexIndexOffset;
+
+				combinedMeshData->setIndices(indices, numIndices, subMeshIndex);
+				subMeshIndex++;
+			}
 
-		vertexBuffers.clear();
+			UINT32 numVertices = meshData->getNumVertices();
+			totalVertexCount += numVertices;
+			vertexIndexOffset += numVertices;
+		}
+
+		UINT32 vertexOffset = 0;
+		for(auto& meshData : elements)
+		{
+			vector<VertexElement>::type vertexElements = meshData->getVertexElements();
+			UINT32 numVertices = meshData->getNumVertices();
+
+			for(auto& newElement : vertexElements)
+			{
+				INT32 alreadyExistsIdx = -1;
+				UINT32 idx = 0;
+				for(auto& existingElement : combinedVertexElements)
+				{
+					if(newElement == existingElement)
+					{
+						alreadyExistsIdx = idx;
+						break;
+					}
+
+					idx++;
+				}
+
+				if(alreadyExistsIdx == -1)
+				{
+					combinedVertexElements.push_back(newElement);
+					UINT32 newBufferSize = totalVertexCount * newElement.getSize();
+					UINT8* newBuffer = new UINT8[newBufferSize];
+					memset(newBuffer, 0, newBufferSize);
+
+					vertexElemData.push_back(newBuffer);
+					alreadyExistsIdx = (UINT32)vertexElemData.size() - 1;
+				}
+
+				UINT8* source = meshData->getVertElemData(newElement.getType(), newElement.getSemantic(), newElement.getIndex(), newElement.getSource()).data;
+				memcpy(&(vertexElemData[alreadyExistsIdx]), source, numVertices * newElement.getSize());
+
+				combinedMeshData->setVertexElementData(newElement.getType(), newElement.getSemantic(), source, numVertices, newElement.getIndex(), newElement.getSource());
+			}
+
+			vertexOffset += meshData->getNumVertices();
+		}
+
+		return combinedMeshData;
+	}
+
+	bool MeshData::hasElement(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const
+	{
+		auto elemDataIter = mVertexData.find(streamIdx);
+
+		if(elemDataIter == mVertexData.end())
+			return false;
+
+		const vector<VertexElementData>::type& elemData = elemDataIter->second;
+
+		auto findIter = std::find_if(elemData.begin(), elemData.end(), 
+			[semantic, semanticIdx] (const VertexElementData& x) 
+		{ 
+			return x.element.getSemantic() == semantic && x.element.getIndex() == semanticIdx; 
+		});
+
+		if(findIter != elemData.end())
+			return true;
+
+		return false;
+	}
+
+	void MeshData::clearIfItExists(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
+	{
+		vector<VertexElementData>::type& elemData = mVertexData[streamIdx];
+
+		auto findIter = std::find_if(elemData.begin(), elemData.end(), 
+			[type, semantic, semanticIdx] (const VertexElementData& x) 
+		{ 
+			return x.element.getSemantic() == semantic && x.element.getIndex() == semanticIdx; 
+		});
+
+		if(findIter != elemData.end())
+		{
+			if(findIter->data != nullptr)
+				delete[] findIter->data;
+
+			elemData.erase(findIter);
+		}
+	}
+
+	MeshData::VertexElementData& MeshData::getVertElemData(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
+	{
+		vector<VertexElementData>::type& elemData = mVertexData[streamIdx];
+
+		auto findIter = std::find_if(elemData.begin(), elemData.end(), 
+			[type, semantic, semanticIdx] (const VertexElementData& x) 
+		{ 
+			return x.element.getSemantic() == semantic && x.element.getIndex() == semanticIdx; 
+		});
+
+		if(findIter == elemData.end())
+			CM_EXCEPT(InvalidParametersException, "No vertex element of specified type exists.");
+
+		return *findIter;
 	}
 
 	/************************************************************************/
 	/* 								SERIALIZATION                      		*/
 	/************************************************************************/
 
+	RTTITypeBase* MeshData::VertexElementData::getRTTIStatic()
+	{
+		return VertexElementDataRTTI::instance();
+	}
+
+	RTTITypeBase* MeshData::VertexElementData::getRTTI() const
+	{
+		return VertexElementData::getRTTIStatic();
+	}
+
+	RTTITypeBase* MeshData::IndexElementData::getRTTIStatic()
+	{
+		return IndexElementDataRTTI::instance();
+	}
+
+	RTTITypeBase* MeshData::IndexElementData::getRTTI() const
+	{
+		return IndexElementData::getRTTIStatic();
+	}
+
 	RTTITypeBase* MeshData::getRTTIStatic()
 	{
 		return MeshDataRTTI::instance();

+ 24 - 0
CamelotCore/Source/CmMeshDataRTTI.cpp

@@ -0,0 +1,24 @@
+#include "CmMeshDataRTTI.h"
+
+namespace CamelotEngine
+{
+	void MeshDataRTTI::onSerializationStarted(IReflectable* obj)
+	{
+		MeshData* meshData = static_cast<MeshData*>(obj);
+
+		auto tempData = std::make_shared<TempMeshData>();
+		for(auto vertElems : meshData->mVertexData)
+		{
+			for(auto vertElem : vertElems.second)
+				tempData->vertexElements.push_back(vertElem);
+		}
+
+		meshData->mRTTIData = tempData;
+	}
+
+	void MeshDataRTTI::onSerializationEnded(IReflectable* obj)
+	{
+		MeshData* meshData = static_cast<MeshData*>(obj);
+		meshData->mRTTIData = nullptr;
+	}
+}

+ 8 - 17
CamelotCore/Source/CmMeshManager.cpp

@@ -8,25 +8,16 @@ namespace CamelotEngine
 	{
 		mNullMeshData = MeshDataPtr(new MeshData());
 
-		mNullMeshData->indexCount = 3;
-		mNullMeshData->vertexCount = 1;
+		auto indices = new UINT32[3];
+		indices[0] = 0;
+		indices[1] = 0;
+		indices[2] = 0;
 
-		mNullMeshData->index = new int[3];
-		mNullMeshData->index[0] = 0;
-		mNullMeshData->index[1] = 0;
-		mNullMeshData->index[2] = 0;
+		auto vertices = new Vector3[1];
+		vertices[0] = Vector3(0, 0, 0);
 
-		std::shared_ptr<MeshData::VertexData> vertexData = std::shared_ptr<MeshData::VertexData>(new MeshData::VertexData(1));
-		mNullMeshData->vertexBuffers.insert(std::make_pair(0, vertexData));
-		vertexData->vertex = new Vector3[1];
-		vertexData->vertex[0] = Vector3(0, 0, 0);
-
-		mNullMeshData->declaration->addElement(0, 0, VET_FLOAT3, VES_POSITION);
-
-		MeshData::SubMeshData subMesh;
-		subMesh.indexOffset = 0;
-		subMesh.indexCount = 3;
-		mNullMeshData->subMeshes.push_back(subMesh);
+		mNullMeshData->setPositions(vertices, 3);
+		mNullMeshData->setIndices(indices, 3);
 	}
 
 	MeshManager::~MeshManager()

+ 0 - 3
CamelotFBXImporter/Include/CmFBXImporter.h

@@ -46,8 +46,5 @@ namespace CamelotEngine
 		MeshDataPtr parseScene(FbxManager* manager, FbxScene* scene);
 
 		MeshDataPtr parseMesh(FbxMesh* mesh, bool createTangentsIfMissing = true);
-		MeshDataPtr mergeMeshData(vector<MeshDataPtr>::type meshes);
-
-		void initDeclarationForMeshData(MeshDataPtr meshData);
 	};
 }

+ 97 - 288
CamelotFBXImporter/Source/CmFBXImporter.cpp

@@ -170,7 +170,7 @@ namespace CamelotEngine
 		else if(allMeshes.size() == 1)
 			return allMeshes[0];
 		else
-			return mergeMeshData(allMeshes);
+			return MeshData::combine(allMeshes);
 	}
 
 	MeshDataPtr FBXImporter::parseMesh(FbxMesh* mesh, bool createTangentsIfMissing)
@@ -188,6 +188,8 @@ namespace CamelotEngine
 		// Count the polygon count of each material
 		FbxLayerElementArrayTemplate<int>* lMaterialIndice = NULL;
 		FbxGeometryElement::EMappingMode lMaterialMappingMode = FbxGeometryElement::eNone;
+		vector<SubMesh>::type subMeshes;
+		vector<UINT32*>::type indices;
 		if (mesh->GetElementMaterial())
 		{
 			lMaterialIndice = &mesh->GetElementMaterial()->GetIndexArray();
@@ -201,23 +203,23 @@ namespace CamelotEngine
 					for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex)
 					{
 						const UINT32 lMaterialIndex = (UINT32)lMaterialIndice->GetAt(lPolygonIndex);
-						if (meshData->subMeshes.size() < lMaterialIndex + 1)
+						if (subMeshes.size() < lMaterialIndex + 1)
 						{
-							meshData->subMeshes.resize(lMaterialIndex + 1);
+							subMeshes.resize(lMaterialIndex + 1);
 						}
 
-						meshData->subMeshes[lMaterialIndex].indexCount += 3;
+						subMeshes[lMaterialIndex].indexCount += 3;
 					}
 
-					// Record the offset (how many vertex)
-					const int lMaterialCount = (const int)meshData->subMeshes.size();
+					// Record the offsets and allocate index arrays
+					indices.resize(subMeshes.size());
+					const int lMaterialCount = (const int)subMeshes.size();
 					int lOffset = 0;
 					for (int lIndex = 0; lIndex < lMaterialCount; ++lIndex)
 					{
-						meshData->subMeshes[lIndex].indexOffset = lOffset;
-						lOffset += meshData->subMeshes[lIndex].indexCount;
-						// This will be used as counter in the following procedures, reset to zero
-						meshData->subMeshes[lIndex].indexCount = 0;
+						subMeshes[lIndex].indexOffset = lOffset;
+						lOffset += subMeshes[lIndex].indexCount;
+						indices[lIndex] = new UINT32[subMeshes[lIndex].indexCount];
 					}
 					FBX_ASSERT(lOffset == lPolygonCount * 3);
 				}
@@ -225,8 +227,13 @@ namespace CamelotEngine
 		}
 
 		// All faces will use the same material.
-		if (meshData->subMeshes.size() == 0)
-			meshData->subMeshes.resize(1);
+		if (subMeshes.size() == 0)
+		{
+			subMeshes.resize(1);
+			indices.resize(1);
+			subMeshes[0].indexCount = lPolygonCount * 3;
+			indices[0] = new UINT32[subMeshes[0].indexCount];
+		}
 
 		// Find out which vertex attributes exist
 		bool allByControlPoint = true;
@@ -324,40 +331,40 @@ namespace CamelotEngine
 		if (!allByControlPoint)
 			lPolygonVertexCount = lPolygonCount * 3;
 
-		meshData->indexCount = lPolygonCount * 3;
-		meshData->vertexCount = lPolygonVertexCount;
-		
-		meshData->index = new int[lPolygonCount * 3];
-
-		std::shared_ptr<MeshData::VertexData> vertexData = std::shared_ptr<MeshData::VertexData>(new MeshData::VertexData(lPolygonVertexCount));
-		meshData->vertexBuffers.insert(std::make_pair(0, vertexData));
-		vertexData->vertex = new Vector3[lPolygonVertexCount];
+		UINT32 vertexCount = lPolygonVertexCount;
+		Vector3* vertex = new Vector3[vertexCount];
 
+		Color* color = nullptr;
 		if(hasColor)
-			vertexData->color = new Color[lPolygonVertexCount];
+			color = new Color[vertexCount];
 
+		Vector3* normal = nullptr;
 		if (hasNormal)
-			vertexData->normal = new Vector3[lPolygonVertexCount];
+			normal = new Vector3[vertexCount];
 
+		Vector3* tangent = nullptr;
 		if (hasTangent)
-			vertexData->tangent = new Vector3[lPolygonVertexCount];
+			tangent = new Vector3[vertexCount];
 
+		Vector3* bitangent = nullptr;
 		if (hasBitangent)
-			vertexData->bitangent = new Vector3[lPolygonVertexCount];
+			bitangent = new Vector3[vertexCount];
 
 		FbxStringList lUVNames;
 		mesh->GetUVSetNames(lUVNames);
 		const char * lUVName0 = NULL;
+		Vector2* uv0 = nullptr;
 		if (hasUV0 && lUVNames.GetCount() > 0)
 		{
-			vertexData->uv0 = new Vector2[lPolygonVertexCount];
+			uv0 = new Vector2[vertexCount];
 			lUVName0 = lUVNames[0];
 		}
 
 		const char * lUVName1 = NULL;
+		Vector2* uv1 = nullptr;
 		if (hasUV1 && lUVNames.GetCount() > 1)
 		{
-			vertexData->uv1 = new Vector2[lPolygonVertexCount];
+			uv1 = new Vector2[vertexCount];
 			lUVName1 = lUVNames[1];
 		}
 
@@ -397,9 +404,9 @@ namespace CamelotEngine
 			{
 				// Save the vertex position.
 				lCurrentVertex = lControlPoints[lIndex];
-				vertexData->vertex[lIndex][0] = static_cast<float>(lCurrentVertex[0]);
-				vertexData->vertex[lIndex][1] = static_cast<float>(lCurrentVertex[1]);
-				vertexData->vertex[lIndex][2] = static_cast<float>(lCurrentVertex[2]);
+				vertex[lIndex][0] = static_cast<float>(lCurrentVertex[0]);
+				vertex[lIndex][1] = static_cast<float>(lCurrentVertex[1]);
+				vertex[lIndex][2] = static_cast<float>(lCurrentVertex[2]);
 
 				// Save vertex color
 				if(hasColor)
@@ -409,10 +416,10 @@ namespace CamelotEngine
 						lColorIndex = lColorElement->GetIndexArray().GetAt(lIndex);
 
 					FbxColor lCurrentColor = lColorElement->GetDirectArray().GetAt(lColorIndex);
-					vertexData->color[lIndex][0] = static_cast<float>(lCurrentColor[0]);
-					vertexData->color[lIndex][1] = static_cast<float>(lCurrentColor[1]);
-					vertexData->color[lIndex][2] = static_cast<float>(lCurrentColor[2]);
-					vertexData->color[lIndex][3] = static_cast<float>(lCurrentColor[3]);
+					color[lIndex][0] = static_cast<float>(lCurrentColor[0]);
+					color[lIndex][1] = static_cast<float>(lCurrentColor[1]);
+					color[lIndex][2] = static_cast<float>(lCurrentColor[2]);
+					color[lIndex][3] = static_cast<float>(lCurrentColor[3]);
 				}
 
 				// Save the normal.
@@ -423,9 +430,9 @@ namespace CamelotEngine
 						lNormalIndex = lNormalElement->GetIndexArray().GetAt(lIndex);
 
 					lCurrentNormal = lNormalElement->GetDirectArray().GetAt(lNormalIndex);
-					vertexData->normal[lIndex][0] = static_cast<float>(lCurrentNormal[0]);
-					vertexData->normal[lIndex][1] = static_cast<float>(lCurrentNormal[1]);
-					vertexData->normal[lIndex][2] = static_cast<float>(lCurrentNormal[2]);
+					normal[lIndex][0] = static_cast<float>(lCurrentNormal[0]);
+					normal[lIndex][1] = static_cast<float>(lCurrentNormal[1]);
+					normal[lIndex][2] = static_cast<float>(lCurrentNormal[2]);
 				}
 
 				// Save the tangent.
@@ -436,12 +443,12 @@ namespace CamelotEngine
 						lTangentIndex = lTangentElement->GetIndexArray().GetAt(lIndex);
 
 					FbxVector4 lCurrentTangent = lTangentElement->GetDirectArray().GetAt(lTangentIndex);
-					vertexData->tangent[lIndex][0] = static_cast<float>(lCurrentTangent[0]);
-					vertexData->tangent[lIndex][1] = static_cast<float>(lCurrentTangent[1]);
-					vertexData->tangent[lIndex][2] = static_cast<float>(lCurrentTangent[2]);
+					tangent[lIndex][0] = static_cast<float>(lCurrentTangent[0]);
+					tangent[lIndex][1] = static_cast<float>(lCurrentTangent[1]);
+					tangent[lIndex][2] = static_cast<float>(lCurrentTangent[2]);
 				}
 
-				// Save the tangent.
+				// Save the bitangent.
 				if (hasBitangent)
 				{
 					int lBitangentIndex = lIndex;
@@ -449,9 +456,9 @@ namespace CamelotEngine
 						lBitangentIndex = lBitangentElement->GetIndexArray().GetAt(lIndex);
 
 					FbxVector4 lCurrentBitangent = lBitangentElement->GetDirectArray().GetAt(lBitangentIndex);
-					vertexData->bitangent[lIndex][0] = static_cast<float>(lCurrentBitangent[0]);
-					vertexData->bitangent[lIndex][1] = static_cast<float>(lCurrentBitangent[1]);
-					vertexData->bitangent[lIndex][2] = static_cast<float>(lCurrentBitangent[2]);
+					bitangent[lIndex][0] = static_cast<float>(lCurrentBitangent[0]);
+					bitangent[lIndex][1] = static_cast<float>(lCurrentBitangent[1]);
+					bitangent[lIndex][2] = static_cast<float>(lCurrentBitangent[2]);
 				}
 
 				// Save the UV.
@@ -462,8 +469,8 @@ namespace CamelotEngine
 						lUVIndex = lUVElement0->GetIndexArray().GetAt(lIndex);
 
 					lCurrentUV = lUVElement0->GetDirectArray().GetAt(lUVIndex);
-					vertexData->uv0[lIndex][0] = static_cast<float>(lCurrentUV[0]);
-					vertexData->uv0[lIndex][1] = static_cast<float>(lCurrentUV[1]);
+					uv0[lIndex][0] = static_cast<float>(lCurrentUV[0]);
+					uv0[lIndex][1] = static_cast<float>(lCurrentUV[1]);
 				}
 
 				if (hasUV1)
@@ -473,13 +480,16 @@ namespace CamelotEngine
 						lUVIndex = lUVElement1->GetIndexArray().GetAt(lIndex);
 
 					lCurrentUV = lUVElement1->GetDirectArray().GetAt(lUVIndex);
-					vertexData->uv1[lIndex][0] = static_cast<float>(lCurrentUV[0]);
-					vertexData->uv1[lIndex][1] = static_cast<float>(lCurrentUV[1]);
+					uv1[lIndex][0] = static_cast<float>(lCurrentUV[0]);
+					uv1[lIndex][1] = static_cast<float>(lCurrentUV[1]);
 				}
 			}
 		}
 
 		int lVertexCount = 0;
+		vector<UINT32>::type indexOffsetPerSubmesh;
+		indexOffsetPerSubmesh.resize(subMeshes.size(), 0);
+
 		for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex)
 		{
 			// The material for current face.
@@ -490,24 +500,24 @@ namespace CamelotEngine
 			}
 
 			// Where should I save the vertex attribute index, according to the material
-			const int lIndexOffset = meshData->subMeshes[lMaterialIndex].indexOffset + meshData->subMeshes[lMaterialIndex].indexCount;
+			int lIndexOffset = subMeshes[lMaterialIndex].indexOffset + indexOffsetPerSubmesh[lMaterialIndex];
 			for (int lVerticeIndex = 0; lVerticeIndex < 3; ++lVerticeIndex)
 			{
 				const int lControlPointIndex = mesh->GetPolygonVertex(lPolygonIndex, lVerticeIndex);
 
 				if (allByControlPoint)
 				{
-					meshData->index[lIndexOffset + lVerticeIndex] = static_cast<unsigned int>(lControlPointIndex);
+					indices[lMaterialIndex][lIndexOffset + lVerticeIndex] = static_cast<unsigned int>(lControlPointIndex);
 				}
 				// Populate the array with vertex attribute, if by polygon vertex.
 				else
 				{
-					meshData->index[lIndexOffset + lVerticeIndex] = static_cast<unsigned int>(lVertexCount);
+					indices[lMaterialIndex][lIndexOffset + lVerticeIndex] = static_cast<unsigned int>(lVertexCount);
 
 					lCurrentVertex = lControlPoints[lControlPointIndex];
-					vertexData->vertex[lVertexCount][0] = static_cast<float>(lCurrentVertex[0]);
-					vertexData->vertex[lVertexCount][1] = static_cast<float>(lCurrentVertex[1]);
-					vertexData->vertex[lVertexCount][2] = static_cast<float>(lCurrentVertex[2]);
+					vertex[lVertexCount][0] = static_cast<float>(lCurrentVertex[0]);
+					vertex[lVertexCount][1] = static_cast<float>(lCurrentVertex[1]);
+					vertex[lVertexCount][2] = static_cast<float>(lCurrentVertex[2]);
 
 					if(hasColor)
 					{
@@ -516,18 +526,18 @@ namespace CamelotEngine
 							lColorIndex = lColorElement->GetIndexArray().GetAt(lColorIndex);
 
 						FbxColor lCurrentColor = lColorElement->GetDirectArray().GetAt(lColorIndex);
-						vertexData->color[lVertexCount][0] = static_cast<float>(lCurrentColor[0]);
-						vertexData->color[lVertexCount][1] = static_cast<float>(lCurrentColor[1]);
-						vertexData->color[lVertexCount][2] = static_cast<float>(lCurrentColor[2]);
-						vertexData->color[lVertexCount][3] = static_cast<float>(lCurrentColor[3]);
+						color[lVertexCount][0] = static_cast<float>(lCurrentColor[0]);
+						color[lVertexCount][1] = static_cast<float>(lCurrentColor[1]);
+						color[lVertexCount][2] = static_cast<float>(lCurrentColor[2]);
+						color[lVertexCount][3] = static_cast<float>(lCurrentColor[3]);
 					}
 
 					if (hasNormal)
 					{
 						mesh->GetPolygonVertexNormal(lPolygonIndex, lVerticeIndex, lCurrentNormal);
-						vertexData->normal[lVertexCount][0] = static_cast<float>(lCurrentNormal[0]);
-						vertexData->normal[lVertexCount][1] = static_cast<float>(lCurrentNormal[1]);
-						vertexData->normal[lVertexCount][2] = static_cast<float>(lCurrentNormal[2]);
+						normal[lVertexCount][0] = static_cast<float>(lCurrentNormal[0]);
+						normal[lVertexCount][1] = static_cast<float>(lCurrentNormal[1]);
+						normal[lVertexCount][2] = static_cast<float>(lCurrentNormal[2]);
 					}
 
 					if (hasTangent)
@@ -537,9 +547,9 @@ namespace CamelotEngine
 							lTangentIndex = lTangentElement->GetIndexArray().GetAt(lTangentIndex);
 
 						FbxVector4 lCurrentTangent = lTangentElement->GetDirectArray().GetAt(lTangentIndex);
-						vertexData->tangent[lVertexCount][0] = static_cast<float>(lCurrentTangent[0]);
-						vertexData->tangent[lVertexCount][1] = static_cast<float>(lCurrentTangent[1]);
-						vertexData->tangent[lVertexCount][2] = static_cast<float>(lCurrentTangent[2]);
+						tangent[lVertexCount][0] = static_cast<float>(lCurrentTangent[0]);
+						tangent[lVertexCount][1] = static_cast<float>(lCurrentTangent[1]);
+						tangent[lVertexCount][2] = static_cast<float>(lCurrentTangent[2]);
 					}
 
 					if (hasBitangent)
@@ -549,257 +559,56 @@ namespace CamelotEngine
 							lBitangentIndex = lBitangentElement->GetIndexArray().GetAt(lBitangentIndex);
 
 						FbxVector4 lCurrentBitangent = lBitangentElement->GetDirectArray().GetAt(lBitangentIndex);
-						vertexData->bitangent[lVertexCount][0] = static_cast<float>(lCurrentBitangent[0]);
-						vertexData->bitangent[lVertexCount][1] = static_cast<float>(lCurrentBitangent[1]);
-						vertexData->bitangent[lVertexCount][2] = static_cast<float>(lCurrentBitangent[2]);
+						bitangent[lVertexCount][0] = static_cast<float>(lCurrentBitangent[0]);
+						bitangent[lVertexCount][1] = static_cast<float>(lCurrentBitangent[1]);
+						bitangent[lVertexCount][2] = static_cast<float>(lCurrentBitangent[2]);
 					}
 
 					if (hasUV0)
 					{
 						mesh->GetPolygonVertexUV(lPolygonIndex, lVerticeIndex, lUVName0, lCurrentUV);
-						vertexData->uv0[lVertexCount][0] = static_cast<float>(lCurrentUV[0]);
-						vertexData->uv0[lVertexCount][1] = static_cast<float>(lCurrentUV[1]);
+						uv0[lVertexCount][0] = static_cast<float>(lCurrentUV[0]);
+						uv0[lVertexCount][1] = static_cast<float>(lCurrentUV[1]);
 					}
 
 					if (hasUV1)
 					{
 						mesh->GetPolygonVertexUV(lPolygonIndex, lVerticeIndex, lUVName1, lCurrentUV);
-						vertexData->uv1[lVertexCount][0] = static_cast<float>(lCurrentUV[0]);
-						vertexData->uv1[lVertexCount][1] = static_cast<float>(lCurrentUV[1]);
+						uv1[lVertexCount][0] = static_cast<float>(lCurrentUV[0]);
+						uv1[lVertexCount][1] = static_cast<float>(lCurrentUV[1]);
 					}
 				}
 				++lVertexCount;
 			}
 
-			meshData->subMeshes[lMaterialIndex].indexCount += 3;
+			indexOffsetPerSubmesh[lMaterialIndex] += 3;
 		}
 
-		initDeclarationForMeshData(meshData);
+		if(vertex != nullptr)
+			meshData->setPositions(vertex, vertexCount);
 
-		return meshData;
-	}
+		if(color != nullptr)
+			meshData->setColors(color, vertexCount);
 
-	void FBXImporter::initDeclarationForMeshData(MeshDataPtr meshData)
-	{
-		std::shared_ptr<MeshData::VertexData> vertexData = meshData->vertexBuffers[0];
+		if(normal != nullptr)
+			meshData->setNormals(normal, vertexCount);
 
-		UINT32 offset = 0;
-		if(vertexData->vertex)
-		{
-			meshData->declaration->addElement(0, offset, VET_FLOAT3, VES_POSITION, 0);
-			offset += VertexElement::getTypeSize(VET_FLOAT3);
-		}
+		if(tangent != nullptr)
+			meshData->setTangents(tangent, vertexCount);
 
-		if(vertexData->color)
-		{
-			meshData->declaration->addElement(0, offset, VET_COLOR, VES_COLOR, 0);
-			offset += VertexElement::getTypeSize(VET_COLOR);
-		}
+		if(bitangent != nullptr)
+			meshData->setBitangents(bitangent, vertexCount);
 
-		if(vertexData->normal)
-		{
-			meshData->declaration->addElement(0, offset, VET_FLOAT3, VES_NORMAL, 0);
-			offset += VertexElement::getTypeSize(VET_FLOAT3);
-		}
-
-		if(vertexData->tangent)
-		{
-			meshData->declaration->addElement(0, offset, VET_FLOAT3, VES_TANGENT, 0);
-			offset += VertexElement::getTypeSize(VET_FLOAT3);
-		}
-
-		// TODO - Storing bitangents with the mesh is probably not a good idea. It's likely cheaper to recreate them in the shader
-		if(vertexData->bitangent)
-		{
-			meshData->declaration->addElement(0, offset, VET_FLOAT3, VES_BITANGENT, 0);
-			offset += VertexElement::getTypeSize(VET_FLOAT3);
-		}
+		if(uv0 != nullptr)
+			meshData->setUV0(uv0, vertexCount);
 
-		if(vertexData->uv0)
-		{
-			meshData->declaration->addElement(0, offset, VET_FLOAT2, VES_TEXCOORD, 0);
-			offset += VertexElement::getTypeSize(VET_FLOAT2);
-		}
+		if(uv1 != nullptr)
+			meshData->setUV1(uv1, vertexCount);
 
-		if(vertexData->uv1)
+		for(size_t i = 0; i < subMeshes.size(); i++)
 		{
-			meshData->declaration->addElement(0, offset, VET_FLOAT2, VES_TEXCOORD, 1);
-			offset += VertexElement::getTypeSize(VET_FLOAT2);
+			meshData->setIndices(indices[i], subMeshes[i].indexCount, (UINT32)i);
 		}
-	}
-
-	MeshDataPtr FBXImporter::mergeMeshData(vector<MeshDataPtr>::type meshes)
-	{
-		// TODO Low priority - Throughout this method we're assuming mesh data only has a single stream, which is a fair assumption now, but that might change later.
-
-		MeshDataPtr meshData = MeshDataPtr(new MeshData());
-
-		bool hasPosition = false;
-		bool hasColors = false;
-		bool hasNormals = false;
-		bool hasTangents = false;
-		bool hasBitangents = false;
-		bool hasUV0 = false;
-		bool hasUV1 = false;
-
-		// Count all vertices and indexes. And determine all data types.
-		for(auto iter = meshes.begin(); iter != meshes.end(); ++iter)
-		{
-			meshData->indexCount += (*iter)->indexCount;
-			meshData->vertexCount += (*iter)->vertexCount;
-
-			std::shared_ptr<MeshData::VertexData> vertData = (*iter)->vertexBuffers[0];
-			if(vertData)
-			{
-				if(vertData->vertex)
-					hasPosition = true;
-
-				if(vertData->color)
-					hasColors = true;
-
-				if(vertData->normal)
-					hasNormals = true;
-
-				if(vertData->tangent)
-					hasTangents = true;
-
-				if(vertData->bitangent)
-					hasBitangents = true;
-
-				if(vertData->uv0)
-					hasUV0 = true;
-
-				if(vertData->uv1)
-					hasUV1 = true;
-			}
-		}
-
-		// Copy indices
-		meshData->index = new int[meshData->indexCount];
-
-		int currentIndexIdx = 0;
-		int currentVertIdx = 0;
-		for(auto iter = meshes.begin(); iter != meshes.end(); ++iter)
-		{
-			int indexCount = (*iter)->indexCount;
-
-			for(int i = 0; i < indexCount; i++)
-				meshData->index[currentIndexIdx + i] = (*iter)->index[i] + currentVertIdx;
-
-			currentIndexIdx += indexCount;
-			currentVertIdx += (*iter)->vertexCount;
-		}
-
-		// Copy vertex data
-		std::shared_ptr<MeshData::VertexData> combinedVertData(new MeshData::VertexData(meshData->vertexCount, 0));
-		meshData->vertexBuffers[0] = combinedVertData;
-
-		if(hasPosition)
-			combinedVertData->vertex = new Vector3[meshData->vertexCount];
-
-		if(hasColors)
-			combinedVertData->color = new Color[meshData->vertexCount];
-
-		if(hasNormals)
-			combinedVertData->normal = new Vector3[meshData->vertexCount];
-
-		if(hasTangents)
-			combinedVertData->tangent = new Vector3[meshData->vertexCount];
-
-		if(hasBitangents)
-			combinedVertData->bitangent = new Vector3[meshData->vertexCount];
-
-		if(hasUV0)
-			combinedVertData->uv0 = new Vector2[meshData->vertexCount];
-
-		if(hasUV1)
-			combinedVertData->uv1 = new Vector2[meshData->vertexCount];
-
-		currentVertIdx = 0;
-		for(auto iter = meshes.begin(); iter != meshes.end(); ++iter)
-		{
-			int indexCount = (*iter)->indexCount;
-
-			std::shared_ptr<MeshData::VertexData> vertData = (*iter)->vertexBuffers[0];
-
-			if(hasPosition)
-			{
-				if(vertData && vertData->vertex)
-					memcpy(&combinedVertData->vertex[currentVertIdx], vertData->vertex, (*iter)->vertexCount * sizeof(Vector3));
-				else
-					memset(&combinedVertData->vertex[currentVertIdx], 0, (*iter)->vertexCount * sizeof(Vector3));
-			}
-
-			if(hasColors)
-			{
-				if(vertData && vertData->color)
-					memcpy(&combinedVertData->color[currentVertIdx], vertData->color, (*iter)->vertexCount * sizeof(Color));
-				else
-					memset(&combinedVertData->color[currentVertIdx], 0, (*iter)->vertexCount * sizeof(Color));
-			}
-
-			if(hasNormals)
-			{
-				if(vertData && vertData->normal)
-					memcpy(&combinedVertData->normal[currentVertIdx], vertData->normal, (*iter)->vertexCount * sizeof(Vector3));
-				else
-					memset(&combinedVertData->normal[currentVertIdx], 0, (*iter)->vertexCount * sizeof(Vector3));
-			}
-
-			if(hasTangents)
-			{
-				if(vertData && vertData->tangent)
-					memcpy(&combinedVertData->tangent[currentVertIdx], vertData->tangent, (*iter)->vertexCount * sizeof(Vector3));
-				else
-					memset(&combinedVertData->tangent[currentVertIdx], 0, (*iter)->vertexCount * sizeof(Vector3));
-			}
-
-			if(hasBitangents)
-			{
-				if(vertData && vertData->bitangent)
-					memcpy(&combinedVertData->bitangent[currentVertIdx], vertData->bitangent, (*iter)->vertexCount * sizeof(Vector3));
-				else
-					memset(&combinedVertData->bitangent[currentVertIdx], 0, (*iter)->vertexCount * sizeof(Vector3));
-			}
-
-			if(hasUV0)
-			{
-				if(vertData && vertData->uv0)
-					memcpy(&combinedVertData->uv0[currentVertIdx], vertData->uv0, (*iter)->vertexCount * sizeof(Vector2));
-				else
-					memset(&combinedVertData->uv0[currentVertIdx], 0, (*iter)->vertexCount * sizeof(Vector2));
-			}
-
-			if(hasUV1)
-			{
-				if(vertData && vertData->uv1)
-					memcpy(&combinedVertData->uv1[currentVertIdx], vertData->uv1, (*iter)->vertexCount * sizeof(Vector2));
-				else
-					memset(&combinedVertData->uv1[currentVertIdx], 0, (*iter)->vertexCount * sizeof(Vector2));
-			}
-
-			currentVertIdx += (*iter)->vertexCount;
-		}
-
-		// Copy submesh data
-		currentIndexIdx = 0;
-		for(auto iter = meshes.begin(); iter != meshes.end(); ++iter)
-		{
-			UINT32 subMeshCount = (UINT32)(*iter)->subMeshes.size();
-
-			for(UINT32 i = 0; i < subMeshCount; i++)
-			{
-				MeshData::SubMeshData newSubMesh;
-				newSubMesh.indexCount = (*iter)->subMeshes[i].indexCount;
-				newSubMesh.indexOffset = (*iter)->subMeshes[i].indexOffset + currentIndexIdx;
-
-				meshData->subMeshes.push_back(newSubMesh);
-			}
-
-			currentIndexIdx += (*iter)->indexCount;
-		}
-
-		initDeclarationForMeshData(meshData);
 
 		return meshData;
 	}

+ 1 - 0
CamelotUtility/Include/CmStdHeaders.h

@@ -27,6 +27,7 @@
 #include <cmath>
 
 #include <memory>
+#include <boost/shared_array.hpp>
 
 // STL containers
 #include <vector>

+ 0 - 12
TODO.txt

@@ -27,22 +27,10 @@ Add 0.5 offset to GUI shader (depending on render system)
 Add transparency to GUI shader
 TextSprite needs to return multiple buffers in case characters are from different pages
 
-
 Mesh usability overhaul:
- I need to be able to initialize Mesh without manually populating MeshData because it's very inconvenient
- I need to be able to provide non-fixed vertex data. Right now for example VertexData only accepts Vector3 as vertex data. While for UI stuff I need Vector2.
  A way to clear a mesh  (Mesh.Clear)
  A way to update mesh buffers without recreating vertex/index buffers (Setting data currently does exactly that)
 
-Mesh
- -> Make sure MeshData can use 16bit index buffers, and variable size elements (not just limited for Vector3 for position for example)
- -> Make sure buffers aren't re-created each time SetMeshData is called. Instead clear existing buffers and update them. Possibly delete extra sub-mesh buffers.
- -> setVertices(data, num, stream = 0, submesh = 0)
- -> setVertices2D(data, num, stream = 0, submesh = 0)
- -> setUV(data, num, stream = 0, submesh = 0)
- - > similar methods for Normal, Color, Tangent Bitangent, UV1 and indices
- -> make MeshData.index a UINT32* ptr
-
  Names: TextMesh & SpriteMesh instead of 2DText and 2DSprite!
 
 -----------------------IMMEDIATE TODO---------------------------------------------------------------