Explorar el Código

Ported mesh data so it uses a single data buffer, so I can more easily port it to GpuResourceData

Marko Pintera hace 12 años
padre
commit
7e4a997a35

+ 13 - 8
BansheeEngine/Include/BsGUIElement.h

@@ -45,19 +45,24 @@ namespace BansheeEngine
 		virtual UINT32 getNumQuads(UINT32 renderElementIdx) const = 0;
 
 		/**
-		 * @brief	Fill the pre-allocated vertex, uv and index buffers with the mesh data for the specified render element.
-		 *
+		 * @brief	Fill the pre-allocated vertex, uv and index buffers with the mesh data for the
+		 * 			specified render element.
+		 * 			
 		 * @see getNumRenderElements()
 		 * @see	getNumQuads()
-		 * 		
-		 * @param   vertices			Previously allocated buffer where to store the vertices.
-		 * @param   uv					Previously allocated buffer where to store the uv coordinates.
-		 * @param   indices 			Previously allocated buffer where to store the indices.
+		 *
+		 * @param	vertices			Previously allocated buffer where to store the vertices.
+		 * @param	uv					Previously allocated buffer where to store the uv coordinates.
+		 * @param	indices				Previously allocated buffer where to store the indices.
 		 * @param	startingQuad		At which quad should the method start filling the buffer.
-		 * @param	maxNumQuads			Total number of quads the buffers were allocated for. Used only for memory safety.
+		 * @param	maxNumQuads			Total number of quads the buffers were allocated for. Used only
+		 * 								for memory safety.
+		 * @param	vertexStride		Number of bytes between of vertices in the provided vertex and uv data.
+		 * @param	indexStride			Number of bytes between two indexes in the provided index data.
 		 * @param	renderElementIdx	Zero-based index of the render element.
 		 */
-		virtual void fillBuffer(CM::Vector2* vertices, CM::Vector2* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 renderElementIdx) const = 0;
+		virtual void fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, 
+			UINT32 maxNumQuads, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const = 0;
 
 		const CM::Rect& getBounds() const { return mBounds; }
 

+ 2 - 1
BansheeEngine/Include/BsGUILabel.h

@@ -37,7 +37,8 @@ namespace BansheeEngine
 		/**
 		 * @copydoc GUIElement::fillBuffer()
 		 */
-		virtual void fillBuffer(CM::Vector2* vertices, CM::Vector2* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 renderElementIdx) const;
+		virtual void fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, 
+			UINT32 maxNumQuads, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const;
 	private:
 		TextSprite* mTextSprite;
 		CM::String mText;

+ 2 - 1
BansheeEngine/Include/BsGUIWindowFrame.h

@@ -33,7 +33,8 @@ namespace BansheeEngine
 		/**
 		 * @copydoc GUIElement::fillBuffer()
 		 */
-		virtual void fillBuffer(CM::Vector2* vertices, CM::Vector2* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 renderElementIdx) const;
+		virtual void fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, 
+			UINT32 maxNumQuads, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const;
 	private:
 		ImageSprite* mImageSprite;
 		SpriteTexturePtr mTexture;

+ 12 - 8
BansheeEngine/Include/BsSprite.h

@@ -72,19 +72,23 @@ namespace BansheeEngine
 		UINT32 getNumQuads(UINT32 renderElementIdx) const;
 
 		/**
-		 * @brief	Fill the pre-allocated vertex, uv and index buffers with the mesh data for the specified render element.
-		 *
+		 * @brief	Fill the pre-allocated vertex, uv and index buffers with the mesh data for the
+		 * 			specified render element.
+		 * 			
 		 * @see getNumRenderElements()
 		 * @see	getNumQuads()
-		 * 		
-		 * @param   vertices			Previously allocated buffer where to store the vertices.
-		 * @param   uv					Previously allocated buffer where to store the uv coordinates.
-		 * @param   indices 			Previously allocated buffer where to store the indices.
+		 *
+		 * @param	vertices			Previously allocated buffer where to store the vertices.
+		 * @param	uv					Previously allocated buffer where to store the uv coordinates.
+		 * @param	indices				Previously allocated buffer where to store the indices.
 		 * @param	startingQuad		At which quad should the method start filling the buffer.
-		 * @param	maxNumQuads			Total number of quads the buffers were allocated for. Used only for memory safety.
+		 * @param	maxNumQuads			Total number of quads the buffers were allocated for. Used only
+		 * 								for memory safety.
+		 * @param	vertexStride		Number of bytes between of vertices in the provided vertex and uv data.
+		 * @param	indexStride			Number of bytes between two indexes in the provided index data.
 		 * @param	renderElementIdx	Zero-based index of the render element.
 		 */
-		UINT32 fillBuffer(CM::Vector2* vertices, CM::Vector2* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 renderElementIdx) const;
+		UINT32 fillBuffer(CM::UINT8* vertices, CM::UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const;
 
 	protected:
 		mutable CM::Rect mBounds;

+ 3 - 2
BansheeEngine/Source/BsGUILabel.cpp

@@ -53,9 +53,10 @@ namespace BansheeEngine
 		return mTextSprite->getNumQuads(renderElementIdx);
 	}
 
-	void GUILabel::fillBuffer(Vector2* vertices, Vector2* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 renderElementIdx) const
+	void GUILabel::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
+		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 	{
-		mTextSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, renderElementIdx);
+		mTextSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx);
 	}
 
 	GUILabel* GUILabel::create(GUIWidget* parent, const String& text)

+ 17 - 13
BansheeEngine/Source/BsGUIWidget.cpp

@@ -62,15 +62,11 @@ namespace BansheeEngine
 		struct TempMeshData
 		{
 			TempMeshData()
-				:numQuads(0), quadOffset(0), vertices(nullptr),
-				uvs(nullptr), indices(nullptr)
+				:numQuads(0), quadOffset(0)
 			{ }
 
 			UINT32 numQuads;
 			UINT32 quadOffset;
-			Vector2* vertices;
-			Vector2* uvs;
-			UINT32* indices;
 			HMaterial material;
 			std::shared_ptr<MeshData> meshData;
 		};
@@ -100,11 +96,16 @@ namespace BansheeEngine
 		UINT32 numMeshes = 0;
 		for(auto& renderElem : meshDataPerRenderElement)
 		{
-			renderElem.second.meshData = std::shared_ptr<MeshData>(CM_NEW(MeshData, PoolAlloc) MeshData(),
+			MeshDataPtr meshData = std::shared_ptr<MeshData>(CM_NEW(MeshData, PoolAlloc) MeshData(renderElem.second.numQuads * 4),
 				&MemAllocDeleter<MeshData, PoolAlloc>::deleter);
-			renderElem.second.vertices = renderElem.second.meshData->addPositionsVec2(renderElem.second.numQuads * 4);
-			renderElem.second.uvs = renderElem.second.meshData->addUV0(renderElem.second.numQuads * 4);
-			renderElem.second.indices = renderElem.second.meshData->addIndices32(renderElem.second.numQuads * 6);
+
+			meshData->beginDesc();
+			meshData->addVertElem(VET_FLOAT2, VES_POSITION);
+			meshData->addVertElem(VET_FLOAT2, VES_TEXCOORD);
+			meshData->addSubMesh(renderElem.second.numQuads * 6);
+			meshData->endDesc();
+
+			renderElem.second.meshData = meshData;
 			numMeshes++;
 		}
 
@@ -127,14 +128,17 @@ namespace BansheeEngine
 			{
 				const HMaterial& mat = elem->getMaterial(i);
 				UINT64 meshGroup = mat->getInternalID(); 
+				MeshDataPtr meshData = meshDataPerRenderElement[meshGroup].meshData;
 
-				Vector2* vertices = meshDataPerRenderElement[meshGroup].vertices;
-				Vector2* uvs = meshDataPerRenderElement[meshGroup].uvs;
-				UINT32* indices = meshDataPerRenderElement[meshGroup].indices;
+				UINT8* vertices = meshData->getElementData(VES_POSITION);
+				UINT8* uvs = meshData->getElementData(VES_TEXCOORD);
+				UINT32* indices = meshData->getIndices32();
 				UINT32 startingQuad = meshDataPerRenderElement[meshGroup].quadOffset;
 				UINT32 maxNumQuads = meshDataPerRenderElement[meshGroup].numQuads;
+				UINT32 vertexStride = meshData->getVertexStride();
+				UINT32 indexStride = meshData->getIndexElementSize();
 
-				elem->fillBuffer(vertices, uvs, indices, startingQuad, maxNumQuads, i);
+				elem->fillBuffer(vertices, uvs, indices, startingQuad, maxNumQuads, vertexStride, indexStride, i);
 
 				UINT32 numQuads = elem->getNumQuads(i);
 				meshDataPerRenderElement[meshGroup].quadOffset += numQuads;

+ 3 - 2
BansheeEngine/Source/BsGUIWindowFrame.cpp

@@ -57,8 +57,9 @@ namespace BansheeEngine
 		return mImageSprite->getNumQuads(renderElementIdx);
 	}
 
-	void GUIWindowFrame::fillBuffer(CM::Vector2* vertices, CM::Vector2* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 renderElementIdx) const
+	void GUIWindowFrame::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
+		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 	{
-		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, renderElementIdx);
+		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx);
 	}
 }

+ 13 - 4
BansheeEngine/Source/BsSprite.cpp

@@ -31,12 +31,12 @@ namespace BansheeEngine
 		return mCachedRenderElements.at(renderElementIdx).numQuads;
 	}
 
-	UINT32 Sprite::fillBuffer(Vector2* vertices, Vector2* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 renderElementIdx) const
+	UINT32 Sprite::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 	{
 		auto renderElem = mCachedRenderElements.at(renderElementIdx);
 
 		UINT32 startVert = startingQuad * 4;
-		UINT32 startIndex = startingQuad * 4;
+		UINT32 startIndex = startingQuad * 6;
 
 		UINT32 maxVertIdx = maxNumQuads * 4;
 		UINT32 maxIndexIdx = maxNumQuads * 6;
@@ -47,8 +47,17 @@ namespace BansheeEngine
 		assert((startVert + mNumVertices) <= maxVertIdx);
 		assert((startIndex + mNumIndices) <= maxIndexIdx);
 
-		memcpy(&vertices[startVert], renderElem.vertices, mNumVertices * sizeof(Vector2));
-		memcpy(&uv[startVert], renderElem.uvs, mNumVertices * sizeof(Vector2));
+		UINT8* vertDst = &vertices[startVert];
+		UINT8* uvDst = &uv[startVert];
+		for(UINT32 i = 0; i < mNumVertices; i++)
+		{
+			memcpy(vertDst, &renderElem.vertices[i], sizeof(Vector2));
+			memcpy(uvDst, &renderElem.uvs[i], sizeof(Vector2));
+
+			vertDst += vertexStride;
+			uvDst += vertexStride;
+		}
+
 		memcpy(&indices[startIndex], renderElem.indexes, mNumIndices * sizeof(UINT32));
 
 		return renderElem.numQuads;

+ 2 - 2
CamelotClient/CamelotClient.cpp

@@ -28,9 +28,9 @@
 #include "CmTestTextSprite.h"
 #include "CmEditorWindow.h"
 
-//#define DX11
+#define DX11
 //#define DX9
-#define GL
+//#define GL
 
 using namespace CamelotFramework;
 using namespace CamelotEditor;

+ 0 - 1
CamelotCore/CamelotCore.vcxproj

@@ -328,7 +328,6 @@
     <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" />

+ 0 - 3
CamelotCore/CamelotCore.vcxproj.filters

@@ -653,9 +653,6 @@
     <ClCompile Include="Source\CmFontImportOptions.cpp">
       <Filter>Source Files\Text</Filter>
     </ClCompile>
-    <ClCompile Include="Source\CmMeshDataRTTI.cpp">
-      <Filter>Source Files\RTTI</Filter>
-    </ClCompile>
     <ClCompile Include="Source\CmGameObjectHandle.cpp">
       <Filter>Source Files\Scene</Filter>
     </ClCompile>

+ 156 - 165
CamelotCore/Include/CmMeshData.h

@@ -8,250 +8,241 @@
 
 namespace CamelotFramework
 {
-	class CM_EXPORT MeshData : public IReflectable
+	template<class T>
+	class VertexElemIter
 	{
 	public:
-		struct VertexElementData : public IReflectable
+		VertexElemIter()
+			:mData(nullptr), mEnd(nullptr), mByteStride(0), mNumElements(0)
 		{
-			VertexElementData(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx, UINT8* _data, UINT32 numElements)
-				:data(_data), elementCount(numElements), element(streamIdx, 0, type, semantic, semanticIdx)
-			{ }
 
-			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;
-		};
+		}
+
+		VertexElemIter(UINT8* data, UINT32 byteStride, UINT32 numElements)
+			:mData(data), mByteStride(byteStride), mNumElements(numElements)
+		{
+			mEnd = mData + byteStride * numElements;
+		}
+
+		void addValue(T& value)
+		{
+			setValue(value);
+			moveNext();
+		}
 
-		struct IndexElementData : public IReflectable
+		void setValue(T& value)
+		{
+			memcpy(mData, &value, sizeof(T));
+		}
+
+		T& getValue()
+		{
+			return *((T*)mData);
+		}
+
+		void moveNext()
+		{
+#ifdef CM_DEBUG_MODE
+			if(mData >= mEnd)
+			{
+				CM_EXCEPT(InternalErrorException, "Vertex element iterator out of buffer bounds.");
+			}
+#endif
+
+			mData += mByteStride;
+		}
+
+		UINT32 getNumElements() const { return mNumElements; }
+
+	private:
+		UINT8* mData;
+		UINT8* mEnd;
+		UINT32 mByteStride;
+		UINT32 mNumElements;
+	};
+
+	class CM_EXPORT MeshData : public IReflectable
+	{
+	public:
+		struct IndexElementData
 		{
 			IndexElementData()
-				:numIndices(0), subMesh(0), elementSize(0), indices(nullptr)
+				:numIndices(0), subMesh(0), elementSize(0)
 			{ }
 
-			UINT8* indices;
 			UINT32 numIndices;
 			UINT32 elementSize;
 			UINT32 subMesh;
-
-			/************************************************************************/
-			/* 								SERIALIZATION                      		*/
-			/************************************************************************/
-		public:
-			friend class IndexElementDataRTTI;
-			static RTTITypeBase* getRTTIStatic();
-			virtual RTTITypeBase* getRTTI() const;
 		};
 
-		MeshData(IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
+		MeshData(UINT32 numVertices, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 		~MeshData();
 
 		/**
-		 * @brief	Allocates a buffer for holding a specified amount of vertex positions, and returns a
-		 * 			pointer the user can use to populate the buffer. If a previous set of data exists 
-		 * 			in this same stream slot, it 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.
+		 * @brief	Begins the mesh data definition. After this call you may call various add* methods to inform
+		 * 			the internal buffer which data it will need to hold. Each beginDesc() call needs to be followed with
+		 * 			an endDesc().
 		 */
-		Vector2* addPositionsVec2(UINT32 numElements, UINT32 streamIdx = 0);
+		void beginDesc();
 
 		/**
-		 * @brief	Allocates a buffer for holding a specified amount of vertex positions, and returns a
-		 * 			pointer the user can use to populate the buffer. If a previous set of data exists 
-		 * 			in this same stream slot, it 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.
+		 * @brief	Call after you are done defining data to actually allocate the internal buffer. Any previous buffer will be overwritten.
+		 * 			Must be called after beginDesc().
 		 */
-		Vector3* addPositionsVec3(UINT32 numElements, UINT32 streamIdx = 0);
+		void endDesc();
 
 		/**
-		 * @brief	Allocates a buffer for holding a specified amount of vertex positions, and returns a
-		 * 			pointer the user can use to populate the buffer. If a previous set of data exists 
-		 * 			in this same stream slot, it will be deleted.
+		* @brief	Informs the internal buffer that it needs to make room for the specified vertex element. If a vertex
+		* 			with same stream and semantics already exists it will just be updated. This must be called between beginDesc and endDesc.
 		 *
-		 * @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.
+		 * @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	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.
 		 */
-		Vector4* addPositionsVec4(UINT32 numElements, UINT32 streamIdx = 0);
+		void addVertElem(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx = 0, UINT32 streamIdx = 0);
 
 		/**
-		 * @brief	Allocates a buffer for holding a specified amount of vertex normals, and returns a
-		 * 			pointer the user can use to populate the buffer. If a previous set of data exists 
-		 * 			in this same stream slot, it will be deleted.
+		* @brief	Informs the internal buffer that it needs to make room for an index buffer of the specified size. If specified submesh
+		* 			already exists it will just be updated. This must be called between beginDesc and endDesc.
 		 *
-		 * @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.
+		 * @param	numIndices	   	Number of indices.
+		 * @param	subMesh		   	(optional) the sub mesh.
 		 */
-		Vector3* addNormals(UINT32 numElements, UINT32 streamIdx = 0);
+		void addSubMesh(UINT32 numIndices, UINT32 subMesh = 0);
 
 		/**
-		 * @brief	Allocates a buffer for holding a specified amount of vertex tangents, and returns a
-		 * 			pointer the user can use to populate the buffer. If a previous set of data exists 
-		 * 			in this same stream slot, it 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.
+		 * @brief	Query if we have vertex data for the specified semantic.
 		 */
-		Vector3* addTangentsVec3(UINT32 numElements, UINT32 streamIdx = 0);
+		bool hasElement(VertexElementSemantic semantic, UINT32 semanticIdx = 0, UINT32 streamIdx = 0) const;
 
 		/**
-		 * @brief	Allocates a buffer for holding a specified amount of vertex tangents, and returns a
-		 * 			pointer the user can use to populate the buffer. If a previous set of data exists 
-		 * 			in this same stream slot, it will be deleted.
+		 * @brief	Copies data from "data" parameter into the internal buffer for the specified semantic.
 		 *
-		 * @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.
+		 * @param	semantic   		Semantic that allows the engine to connect the data to a shader input slot.
+		 * @param	data			Vertex data, containing at least "size" bytes.
+		 * @param	size			The size of the data. Must be the size of the vertex element type * number of vertices.
+		 * @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.
 		 */
-		Vector4* addTangentsVec4(UINT32 numElements, UINT32 streamIdx = 0);
+		void setVertexData(VertexElementSemantic semantic, UINT8* data, UINT32 size, UINT32 semanticIdx = 0, UINT32 streamIdx = 0);
 
 		/**
-		 * @brief	Allocates a buffer for holding a specified amount of vertex bitangents, and returns a
-		 * 			pointer the user can use to populate the buffer. If a previous set of data exists 
-		 * 			in this same stream slot, it 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.
+		 * @brief	Returns an iterator you can use for easily retrieving or setting Vector2 vertex elements. This is the preferred
+		 * 			method of assigning or reading vertex data. 
+		 * 			
+		 * @note	If vertex data of this type/semantic/index/stream doesn't exist and exception will be thrown.
 		 */
-		Vector3* addBitangents(UINT32 numElements, UINT32 streamIdx = 0);
+		VertexElemIter<Vector2> getVec2DataIter(VertexElementSemantic semantic, UINT32 semanticIdx = 0, UINT32 streamIdx = 0);
 
 		/**
-		 * @brief	Allocates a buffer for holding a specified amount of vertex texture coordinates, 
-		 * 			and returns a pointer the user can use to populate the buffer. If a previous set 
-		 * 			of data exists in this same stream slot, it 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.
+		 * @brief	Returns an iterator you can use for easily retrieving or setting Vector3 vertex elements. This is the preferred
+		 * 			method of assigning or reading vertex data. 
+		 * 			
+		 * @note	If vertex data of this type/semantic/index/stream doesn't exist and exception will be thrown.
 		 */
-		Vector2* addUV0(UINT32 numElements, UINT32 streamIdx = 0);
+		VertexElemIter<Vector3> getVec3DataIter(VertexElementSemantic semantic, UINT32 semanticIdx = 0, UINT32 streamIdx = 0);
 
 		/**
-		 * @brief	Allocates a buffer for holding a specified amount of vertex texture coordinates, 
-		 * 			and returns a pointer the user can use to populate the buffer. If a previous set 
-		 * 			of data exists in this same stream slot, it 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.
+		 * @brief	Returns an iterator you can use for easily retrieving or setting Vector4 vertex elements. This is the preferred
+		 * 			method of assigning or reading vertex data. 
+		 * 			
+		 * @note	If vertex data of this type/semantic/index/stream doesn't exist and exception will be thrown.
 		 */
-		Vector2* addUV1(UINT32 numElements, UINT32 streamIdx = 0);
+		VertexElemIter<Vector4> getVec4DataIter(VertexElementSemantic semantic, UINT32 semanticIdx = 0, UINT32 streamIdx = 0);
 
 		/**
-		 * @brief	Allocates a buffer for holding a specified amount of vertex colors, and returns a
-		 * 			pointer the user can use to populate the buffer. If a previous set of data exists 
-		 * 			in this same stream slot, it 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.
+		 * @brief	Returns an iterator you can use for easily retrieving or setting Color vertex elements. This is the preferred
+		 * 			method of assigning or reading vertex data. 
+		 * 			
+		 * @note	If vertex data of this type/semantic/index/stream doesn't exist and exception will be thrown.
 		 */
-		Color* addColorsFloat(UINT32 numElements, UINT32 streamIdx = 0);
+		VertexElemIter<Color> getColorDataIter(VertexElementSemantic semantic, UINT32 semanticIdx = 0, UINT32 streamIdx = 0);
 
 		/**
-		 * @brief	Allocates a buffer for holding a specified amount of vertex colors, and returns a
-		 * 			pointer the user can use to populate the buffer. If a previous set of data exists 
-		 * 			in this same stream slot, it 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.
+		 * @brief	Returns an iterator you can use for easily retrieving or setting DWORD vertex elements. This is the preferred
+		 * 			method of assigning or reading vertex data. 
+		 * 			
+		 * @note	If vertex data of this type/semantic/index/stream doesn't exist and exception will be thrown.
 		 */
-		UINT32* addColorsDWORD(UINT32 numElements, UINT32 streamIdx = 0);
+		VertexElemIter<UINT32> getDWORDDataIter(VertexElementSemantic semantic, UINT32 semanticIdx = 0, UINT32 streamIdx = 0);
 
 		/**
-		* @brief	Allocates a buffer for holding a specified amount of vertex data, and returns a
-		* 			pointer the user can use to populate the buffer. 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	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.
+		 * @brief	Creates a new vertex declaration based on set vertex elements.
 		 */
-		UINT8* addVertexElementData(VertexElementType type, VertexElementSemantic semantic, UINT32 numElements, UINT32 semanticIdx = 0, UINT32 streamIdx = 0);
+		VertexDeclarationPtr createDeclaration() const;
 
-		/**
-		* @brief	Allocates buffer for the indices for the specified sub mesh, and returns a
-		* 			pointer the user can use to populate the buffer. Any indexes previously
-		 * 			set for the sub mesh are deleted.
-		 *
-		 * @param	numIndices	   	Number of indices.
-		 * @param	subMesh		   	(optional) the sub mesh.
-		 */
-		UINT32* addIndices32(UINT32 numIndices, UINT32 subMesh = 0);
+		UINT32 getNumSubmeshes() const { return (UINT32)mSubMeshes.size(); }
+		UINT32 getNumVertices() const { return mNumVertices; }
+		UINT32 getNumIndices(UINT32 subMesh) const;
+		UINT32 getNumIndices() const;
 
-		/**
-		* @brief	Allocates buffer for the indices for the specified sub mesh, and returns a
-		* 			pointer the user can use to populate the buffer. Any indexes previously
-		 * 			set for the sub mesh are deleted.
-		 *
-		 * @param	numIndices	   	Number of indices.
-		 * @param	subMesh		   	(optional) the sub mesh.
-		 */
-		UINT16* addIndices16(UINT32 numIndices, UINT32 subMesh = 0);
+		UINT16* getIndices16(UINT32 subMesh = 0) const;
+		UINT32* getIndices32(UINT32 subMesh = 0) const;
+		IndexBuffer::IndexType getIndexType() const { return mIndexType; }
 
-		/**
-		 * @brief	Query if we have vertex data for the specified semantic.
-		 */
-		bool hasElement(VertexElementSemantic semantic, UINT32 semanticIdx = 0, UINT32 streamIdx = 0) const;
+		UINT8* getIndexData() const { return getData(); }
+		UINT8* getStreamData(UINT32 streamIdx) const;
 
 		/**
-		 * @brief	Creates a new vertex declaration based on set vertex elements.
+		 * @brief	Returns the pointer to the first element of the specified type. If you want to
+		 * 			iterate over all elements you need to call getVertexStride() to get the number
+		 * 			of bytes you need to advance between each element.
+		 *
+		 * @param	semantic   		Semantic that allows the engine to connect the data to a shader input slot.
+		 * @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.
+		 *
+		 * @return	null if it fails, else the element data.
 		 */
-		VertexDeclarationPtr createDeclaration() const;
+		UINT8* getElementData(VertexElementSemantic semantic, UINT32 semanticIdx = 0, UINT32 streamIdx = 0) const;
 
-		UINT32 getNumSubmeshes() const { return (UINT32)mIndices.size(); }
-		UINT32 getNumVertices() const;
-		UINT32 getNumIndices(UINT32 subMesh) const;
+		UINT32 getIndexBufferSize() const { return getIndexBufferOffset(getNumSubmeshes()); }
+		UINT32 getStreamSize(UINT32 streamIdx) const;
+		UINT32 getStreamSize() const;
+		UINT32 getIndexElementSize() const;
+
+		UINT32 getIndexBufferOffset(UINT32 subMesh) const;
+		UINT32 getStreamOffset(UINT32 streamIdx = 0) const;
+		UINT32 getElementSize(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const;
+		UINT32 getElementOffset(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const;
+		UINT32 getVertexStride(UINT32 streamIdx = 0) const;
 
-		UINT16* getIndices16(UINT32 subMesh) const;
-		UINT32* getIndices32(UINT32 subMesh) const;
+		UINT32 getMaxStreamIdx() const;
+		bool hasStream(UINT32 streamIdx) const;
 
 		vector<VertexElement>::type getVertexElements() const;
 
-		MeshData::VertexElementData& getVertElemData(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx);
+		void allocateInternalBuffer();
+		void allocateInternalBuffer(UINT32 numBytes);
 
-		UINT32 getIndexElementSize()
-		{
-			return mIndexType == IndexBuffer::IT_32BIT ? sizeof(UINT32) : sizeof(UINT16);
-		}
+		UINT8* getData() const { return mData; }
 
 		static MeshDataPtr combine(const vector<MeshDataPtr>::type& elements);
 
+	protected:
+		UINT32 getInternalBufferSize();
+
 	private:
-		friend class Mesh;
+		UINT32 mDescBuilding;
 
-		vector<IndexElementData>::type mIndices;
-		map<UINT32, vector<VertexElementData>::type>::type mVertexData;
+		UINT8* mData;
 
+		UINT32 mNumVertices;
 		IndexBuffer::IndexType mIndexType;
 
+		vector<IndexElementData>::type mSubMeshes;
+		vector<VertexElement>::type mVertexElements;
+
+		void getDataForIterator(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx, UINT8*& data, UINT32& stride) const;
 		void clearIfItExists(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx);
 
 		/************************************************************************/
 		/* 								SERIALIZATION                      		*/
 		/************************************************************************/
+	private:
+		MeshData() {} // Serialization only
+
 	public:
 		friend class MeshDataRTTI;
 		static RTTITypeBase* getRTTIStatic();

+ 44 - 102
CamelotCore/Include/CmMeshDataRTTI.h

@@ -8,163 +8,105 @@
 
 namespace CamelotFramework
 {
-	class CM_EXPORT VertexElementDataRTTI : public RTTIType<MeshData::VertexElementData, IReflectable, VertexElementDataRTTI>
+	CM_ALLOW_MEMCPY_SERIALIZATION(MeshData::IndexElementData);
+	CM_ALLOW_MEMCPY_SERIALIZATION(IndexBuffer::IndexType);
+
+	class CM_EXPORT MeshDataRTTI : public RTTIType<MeshData, IReflectable, MeshDataRTTI>
 	{
 	private:
-		ManagedDataBlock getVertexData(MeshData::VertexElementData* obj) { return ManagedDataBlock(obj->data, obj->elementCount * obj->element.getSize()); }	
-		void setVertexData(MeshData::VertexElementData* obj, ManagedDataBlock val) { obj->data = val.getData(); } 
-
-		UINT32& getNumElements(MeshData::VertexElementData* obj) { return obj->elementCount; }
-		void setNumElements(MeshData::VertexElementData* obj, UINT32& value) { obj->elementCount = value; }
-
-		VertexElement& getVertexElement(MeshData::VertexElementData* obj) { return obj->element; }
-		void setVertexElement(MeshData::VertexElementData* obj, VertexElement& value) { obj->element = value; }
-
-	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() 
+		VertexElement& getVertexElementData(MeshData* obj, UINT32 arrayIdx)
 		{
-			return std::shared_ptr<MeshData::VertexElementData>(CM_NEW(MeshData::VertexElementData, PoolAlloc) MeshData::VertexElementData(),
-				&MemAllocDeleter<MeshData::VertexElementData, PoolAlloc>::deleter);
+			return obj->mVertexElements[arrayIdx];
 		}
 
-		virtual const String& getRTTIName() 
+		void setVertexElementData(MeshData* obj, UINT32 arrayIdx, VertexElement& value)
 		{
-			static String name = "VertexElementData";
-			throw name;
+			obj->mVertexElements[arrayIdx] = value;
 		}
 
-		virtual UINT32 getRTTIId() 
+		UINT32 getNumVertexElementData(MeshData* obj)
 		{
-			return TID_VertexElementData;
+			return (UINT32)obj->mVertexElements.size();
 		}
-	};
 
-	class CM_EXPORT IndexElementDataRTTI : public RTTIType<MeshData::IndexElementData, IReflectable, IndexElementDataRTTI>
-	{
-	private:
-		ManagedDataBlock getIndexData(MeshData::IndexElementData* obj) { return ManagedDataBlock(obj->indices, obj->numIndices * obj->elementSize); }	
-		void setIndexData(MeshData::IndexElementData* obj, ManagedDataBlock val) { obj->indices = val.getData(); } 
-
-		UINT32& getNumIndices(MeshData::IndexElementData* obj) { return obj->numIndices; }
-		void setNumIndices(MeshData::IndexElementData* obj, UINT32& value) { obj->numIndices = value; }
-
-		UINT32& getElementSize(MeshData::IndexElementData* obj) { return obj->elementSize; }
-		void setElementSize(MeshData::IndexElementData* obj, UINT32& value) { obj->elementSize = value; }
-
-		UINT32& getSubMesh(MeshData::IndexElementData* obj) { return obj->subMesh; }
-		void setSubMesh(MeshData::IndexElementData* obj, UINT32& value) { obj->subMesh = value; }
-	public:
-		IndexElementDataRTTI()
+		void setNumVertexElementData(MeshData* obj, UINT32 numElements)
 		{
-			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);
+			obj->mVertexElements.resize(numElements);
 		}
 
-		virtual std::shared_ptr<IReflectable> newRTTIObject() 
+		MeshData::IndexElementData& getIndexElementData(MeshData* obj, UINT32 arrayIdx)
 		{
-			return std::shared_ptr<MeshData::IndexElementData>(CM_NEW(MeshData::IndexElementData, PoolAlloc) MeshData::IndexElementData(),
-				&MemAllocDeleter<MeshData::IndexElementData, PoolAlloc>::deleter);
+			return obj->mSubMeshes[arrayIdx];
 		}
 
-		virtual const String& getRTTIName() 
+		void setIndexElementData(MeshData* obj, UINT32 arrayIdx, MeshData::IndexElementData& value)
 		{
-			static String name = "IndexElementData";
-			throw name;
+			obj->mSubMeshes[arrayIdx] = value;
 		}
 
-		virtual UINT32 getRTTIId() 
-		{
-			return TID_IndexElementData;
-		}
-	};
-
-	CM_ALLOW_MEMCPY_SERIALIZATION(IndexBuffer::IndexType);
-
-	class CM_EXPORT MeshDataRTTI : public RTTIType<MeshData, IReflectable, MeshDataRTTI>
-	{
-	private:
-		struct TempMeshData
-		{
-			vector<MeshData::VertexElementData>::type vertexElements;
-		};
-
-		MeshData::VertexElementData& getVertexElementData(MeshData* obj, UINT32 arrayIdx)
+		UINT32 getNumIndexElementData(MeshData* obj)
 		{
-			auto tempData = boost::any_cast<std::shared_ptr<TempMeshData>>(obj->mRTTIData);
-			return tempData->vertexElements[arrayIdx];
+			return (UINT32)obj->mSubMeshes.size();
 		}
 
-		void setVertexElementData(MeshData* obj, UINT32 arrayIdx, MeshData::VertexElementData& value)
+		void setNumIndexElementData(MeshData* obj, UINT32 numElements)
 		{
-			obj->clearIfItExists(value.element.getType(), value.element.getSemantic(), value.element.getIndex(), value.element.getSource());
-
-			obj->mVertexData[value.element.getSource()].push_back(value);
+			obj->mSubMeshes.resize(numElements);
 		}
 
-		UINT32 getNumVertexElementData(MeshData* obj)
+		IndexBuffer::IndexType& getIndexType(MeshData* obj)
 		{
-			auto tempData = boost::any_cast<std::shared_ptr<TempMeshData>>(obj->mRTTIData);
-			return (UINT32)tempData->vertexElements.size();
+			return obj->mIndexType;
 		}
 
-		void setNumVertexElementData(MeshData* obj, UINT32 numElements)
+		void setIndexType(MeshData* obj, IndexBuffer::IndexType& value)
 		{
-			// Do nothing
+			obj->mIndexType = value;
 		}
 
-		MeshData::IndexElementData& getIndexElementData(MeshData* obj, UINT32 arrayIdx)
+		UINT32& getNumVertices(MeshData* obj)
 		{
-			return obj->mIndices[arrayIdx];
+			return obj->mNumVertices;
 		}
 
-		void setIndexElementData(MeshData* obj, UINT32 arrayIdx, MeshData::IndexElementData& value)
+		void setNumVertices(MeshData* obj, UINT32& value)
 		{
-			obj->mIndices[arrayIdx] = value;
+			obj->mNumVertices = value;
 		}
 
-		UINT32 getNumIndexElementData(MeshData* obj)
-		{
-			return (UINT32)obj->mIndices.size();
+		ManagedDataBlock getData(MeshData* obj) 
+		{ 
+			ManagedDataBlock dataBlock((UINT8*)obj->getData(), obj->getInternalBufferSize());
+			return dataBlock; 
 		}
 
-		void setNumIndexElementData(MeshData* obj, UINT32 numElements)
-		{
-			obj->mIndices.resize(numElements);
+		void setData(MeshData* obj, ManagedDataBlock val) 
+		{ 
+			// Nothing to do here, the pointer we provided already belongs to PixelData
+			// so the data is already written
 		}
 
-		IndexBuffer::IndexType& getIndexType(MeshData* obj)
+		static UINT8* allocateData(MeshData* obj, UINT32 numBytes)
 		{
-			return obj->mIndexType;
-		}
+			obj->allocateInternalBuffer(numBytes);
 
-		void setIndexType(MeshData* obj, IndexBuffer::IndexType& value)
-		{
-			obj->mIndexType = value;
+			return obj->getData();
 		}
 
 	public:
 		MeshDataRTTI()
 		{
-			addReflectableArrayField("mVertexData", 0, &MeshDataRTTI::getVertexElementData, 
+			addPlainArrayField("mVertexData", 0, &MeshDataRTTI::getVertexElementData, 
 				&MeshDataRTTI::getNumVertexElementData, &MeshDataRTTI::setVertexElementData, &MeshDataRTTI::setNumVertexElementData);
 
-			addReflectableArrayField("mIndexBuffer", 1, &MeshDataRTTI::getIndexElementData, 
+			addPlainArrayField("mIndexBuffer", 1, &MeshDataRTTI::getIndexElementData, 
 				&MeshDataRTTI::getNumIndexElementData, &MeshDataRTTI::setIndexElementData, &MeshDataRTTI::setNumIndexElementData);
 
 			addPlainField("mIndexType", 2, &MeshDataRTTI::getIndexType, &MeshDataRTTI::setIndexType);
-		}
+			addPlainField("mNumVertices", 3, &MeshDataRTTI::getNumVertices, &MeshDataRTTI::setNumVertices);
 
-		virtual void onSerializationStarted(IReflectable* obj);
-		virtual void onSerializationEnded(IReflectable* obj);
+			addDataBlockField("data", 4, &MeshDataRTTI::getData, &MeshDataRTTI::setData, 0, &MeshDataRTTI::allocateData);
+		}
 
 		virtual std::shared_ptr<IReflectable> newRTTIObject() 
 		{

+ 0 - 1
CamelotCore/Include/CmPrerequisites.h

@@ -274,7 +274,6 @@ namespace CamelotFramework
 		TID_STDMAP = 1055,
 		TID_FontImportOptions = 1056,
 		TID_FontData = 1057,
-		TID_IndexElementData = 1058,
 		TID_SceneObject = 1059,
 		TID_GameObject = 1060,
 		TID_GpuResource = 1061,

+ 2 - 2
CamelotCore/Include/CmVertexDeclaration.h

@@ -83,7 +83,7 @@ namespace CamelotFramework
         VertexElement(unsigned short source, UINT32 offset, VertexElementType theType,
             VertexElementSemantic semantic, unsigned short index = 0);
         /// Gets the vertex buffer index from where this element draws it's values
-        unsigned short getSource(void) const { return mSource; }
+        unsigned short getStreamIdx(void) const { return mSource; }
         /// Gets the offset into the buffer where this element starts
         UINT32 getOffset(void) const { return mOffset; }
         /// Gets the data format of this element
@@ -91,7 +91,7 @@ namespace CamelotFramework
         /// Gets the meaning of this element
         VertexElementSemantic getSemantic(void) const { return mSemantic; }
         /// Gets the index of this element, only applicable for repeating elements
-        unsigned short getIndex(void) const { return mIndex; }
+        unsigned short getSemanticIdx(void) const { return mIndex; }
 		/// Gets the size of this element in bytes
 		UINT32 getSize(void) const;
 		/// Utility method for helping to calculate offsets

+ 65 - 84
CamelotCore/Source/CmMesh.cpp

@@ -41,34 +41,6 @@ namespace CamelotFramework
 			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();
 
 		if(mVertexData != nullptr)
@@ -78,80 +50,61 @@ namespace CamelotFramework
 			CM_DELETE(mIndexData, IndexData, PoolAlloc);
 
 		// Submeshes
-		UINT32 indexOffset = 0;
-		UINT32 totalIndexCount = 0;
-		for(auto& i : meshData->mIndices)
+		for(UINT32 i = 0; i < meshData->getNumSubmeshes(); i++)
 		{
-			UINT32 numIndices = i.numIndices;
+			UINT32 numIndices = meshData->getNumIndices(i);
 
 			if(numIndices > 0)
 			{
-				mSubMeshes.push_back(SubMesh(indexOffset, numIndices));
-				indexOffset += numIndices;
-				totalIndexCount += numIndices;
+				mSubMeshes.push_back(SubMesh(meshData->getIndexBufferOffset(i), numIndices));
 			}
 		}
 
 		// Indices
 		mIndexData = CM_NEW(IndexData, PoolAlloc) IndexData();
 
-		mIndexData->indexCount = totalIndexCount;
+		mIndexData->indexCount = meshData->getNumIndices();
 		mIndexData->indexBuffer = HardwareBufferManager::instance().createIndexBuffer(
-			meshData->mIndexType,
+			meshData->getIndexType(),
 			mIndexData->indexCount, 
 			GBU_STATIC);
 
-		UINT8* idxData = static_cast<UINT8*>(mIndexData->indexBuffer->lock(GBL_WRITE_ONLY));
+		UINT8* idxData = static_cast<UINT8*>(mIndexData->indexBuffer->lock(GBL_WRITE_ONLY_DISCARD));
 		UINT32 idxElementSize = meshData->getIndexElementSize();
 
-		indexOffset = 0;
-		for(auto& i : meshData->mIndices)
-		{
-			memcpy(&idxData[indexOffset], i.indices, i.numIndices * idxElementSize);
-			indexOffset += i.numIndices;
-		}
+		UINT32 indicesSize = meshData->getIndexBufferSize();
+		UINT8* srcIdxData = meshData->getIndexData(); 
+
+		memcpy(idxData, srcIdxData, indicesSize);
 
 		mIndexData->indexBuffer->unlock();
 
 		// Vertices
 		mVertexData = CM_NEW(VertexData, PoolAlloc) VertexData();
 
-		mVertexData->vertexCount = numVertices;
+		mVertexData->vertexCount = meshData->getNumVertices();
 		mVertexData->vertexDeclaration = meshData->createDeclaration();
 
-		for(auto& vertElems : meshData->mVertexData)
+		for(UINT32 i = 0; i <= meshData->getMaxStreamIdx(); i++)
 		{
-			UINT32 streamIdx = vertElems.first;
-
-			if(vertElems.second.size() == 0)
+			if(!meshData->hasStream(i))
 				continue;
 
+			UINT32 streamSize = meshData->getStreamSize(i);
+
 			VertexBufferPtr vertexBuffer = HardwareBufferManager::instance().createVertexBuffer(
-				mVertexData->vertexDeclaration->getVertexSize(streamIdx),
+				mVertexData->vertexDeclaration->getVertexSize(i),
 				mVertexData->vertexCount,
 				GBU_STATIC);
 
-			mVertexData->setBuffer(streamIdx, vertexBuffer);
-
-			UINT32 vertexSize = vertexBuffer->getVertexSize();
-			UINT8* vertBufferData = static_cast<UINT8*>(vertexBuffer->lock(GBL_WRITE_ONLY));
-
-			UINT32 numElements = mVertexData->vertexDeclaration->getElementCount();
+			mVertexData->setBuffer(i, vertexBuffer);
 
-			for(UINT32 j = 0; j < numElements; j++)
-			{
-				const VertexElement* element = mVertexData->vertexDeclaration->getElement(j);
-				UINT32 offset = element->getOffset();
-				UINT32 elemSize = element->getSize();
+			UINT8* srcVertBufferData = meshData->getStreamData(i);
+			UINT8* vertBufferData = static_cast<UINT8*>(vertexBuffer->lock(GBL_WRITE_ONLY_DISCARD));
 
-				MeshData::VertexElementData& elemData = meshData->getVertElemData(element->getType(), element->getSemantic(), element->getIndex(), streamIdx);
+			UINT32 bufferSize = meshData->getStreamSize(i);
 
-				UINT8* sourceData = elemData.data;
-				for(UINT32 k = 0; k < elemData.elementCount; k++)
-				{
-					memcpy(&vertBufferData[k * vertexSize + offset], &sourceData[k * elemSize], elemSize);
-				}
-			}
+			memcpy(vertBufferData, srcVertBufferData, bufferSize);
 
 			vertexBuffer->unlock();
 		}
@@ -170,25 +123,17 @@ namespace CamelotFramework
 		if(mIndexData)
 			indexType = mIndexData->indexBuffer->getType();
 
-		MeshDataPtr meshData(CM_NEW(MeshData, PoolAlloc) MeshData(indexType),
+		MeshDataPtr meshData(CM_NEW(MeshData, PoolAlloc) MeshData(mVertexData->vertexCount, indexType),
 			&MemAllocDeleter<MeshData, PoolAlloc>::deleter);
 
+		meshData->beginDesc();
 		if(mIndexData)
 		{
 			UINT8* idxData = static_cast<UINT8*>(mIndexData->indexBuffer->lock(GBL_READ_ONLY));
 			UINT32 idxElemSize = mIndexData->indexBuffer->getIndexSize();
 
 			for(UINT32 i = 0; i < mSubMeshes.size(); i++)
-			{
-				UINT8* indices = nullptr;
-				
-				if(indexType == IndexBuffer::IT_16BIT)
-					indices = (UINT8*)meshData->addIndices16(mSubMeshes[i].indexCount, i);
-				else
-					indices = (UINT8*)meshData->addIndices32(mSubMeshes[i].indexCount, i);
-				
-				memcpy(indices, &idxData[mSubMeshes[i].indexOffset * idxElemSize], mSubMeshes[i].indexCount * idxElemSize);
-			}
+				meshData->addSubMesh(mSubMeshes[i].indexCount, i);
 
 			mIndexData->indexBuffer->unlock();
 		}
@@ -202,7 +147,6 @@ namespace CamelotFramework
 			{
 				VertexBufferPtr vertexBuffer = iter->second;
 				UINT32 vertexSize = vertexBuffer->getVertexSize();
-				UINT8* vertDataIter = static_cast<UINT8*>(vertexBuffer->lock(GBL_READ_ONLY));
 
 				UINT32 numElements = mVertexData->vertexDeclaration->getElementCount();
 				for(UINT32 j = 0; j < numElements; j++)
@@ -210,15 +154,52 @@ namespace CamelotFramework
 					const VertexElement* element = mVertexData->vertexDeclaration->getElement(j);
 					VertexElementType type = element->getType();
 					VertexElementSemantic semantic = element->getSemantic(); 
-					UINT32 semanticIdx = element->getIndex();
+					UINT32 semanticIdx = element->getSemanticIdx();
 					UINT32 offset = element->getOffset();
 					UINT32 elemSize = element->getSize();
 
-					UINT8* dest = meshData->addVertexElementData(type, semantic, mVertexData->vertexCount, semanticIdx, streamIdx);
-					for(UINT32 k = 0; k < mVertexData->vertexCount; k++)
-						memcpy(&dest[k * elemSize], &vertDataIter[k * vertexSize + offset], elemSize);
+					meshData->addVertElem(type, semantic, semanticIdx, streamIdx);
 				}
 
+				streamIdx++;
+			}
+		}
+		meshData->endDesc();
+
+		if(mIndexData)
+		{
+			UINT8* idxData = static_cast<UINT8*>(mIndexData->indexBuffer->lock(GBL_READ_ONLY));
+			UINT32 idxElemSize = mIndexData->indexBuffer->getIndexSize();
+
+			for(UINT32 i = 0; i < mSubMeshes.size(); i++)
+			{
+				UINT8* indices = nullptr;
+
+				if(indexType == IndexBuffer::IT_16BIT)
+					indices = (UINT8*)meshData->getIndices16(i);
+				else
+					indices = (UINT8*)meshData->getIndices32(i);
+
+				memcpy(indices, &idxData[mSubMeshes[i].indexOffset * idxElemSize], mSubMeshes[i].indexCount * idxElemSize);
+			}
+
+			mIndexData->indexBuffer->unlock();
+		}
+
+		if(mVertexData)
+		{
+			auto vertexBuffers = mVertexData->getBuffers();
+
+			UINT32 streamIdx = 0;
+			for(auto iter = vertexBuffers.begin(); iter != vertexBuffers.end() ; ++iter)
+			{
+				VertexBufferPtr vertexBuffer = iter->second;
+				UINT32 bufferSize = vertexBuffer->getVertexSize() * vertexBuffer->getNumVertices();
+				UINT8* vertDataPtr = static_cast<UINT8*>(vertexBuffer->lock(GBL_READ_ONLY));
+
+				UINT8* dest = meshData->getStreamData(streamIdx);
+				memcpy(dest, vertDataPtr, bufferSize);
+
 				vertexBuffer->unlock();
 
 				streamIdx++;

+ 380 - 246
CamelotCore/Source/CmMeshData.cpp

@@ -8,388 +8,522 @@
 
 namespace CamelotFramework
 {
-	MeshData::MeshData(IndexBuffer::IndexType indexType)
-	   :mIndexType(indexType)
+	MeshData::MeshData(UINT32 numVertices, IndexBuffer::IndexType indexType)
+	   :mNumVertices(numVertices), mIndexType(indexType), mData(nullptr), mDescBuilding(false)
 	{
 
 	}
 
 	MeshData::~MeshData()
 	{
-		for(auto& vertElems : mVertexData)
-		{
-			for(auto& vertElem : vertElems.second)
-			{
-				if(vertElem.data != nullptr)
-					CM_DELETE_BYTES(vertElem.data, ScratchAlloc);
-			}
-		}
 
-		for(auto& indexData : mIndices)
-		{
-			if(indexData.indices != nullptr)
-				CM_DELETE_BYTES(indexData.indices, ScratchAlloc);
-		}
 	}
 
-	Vector2* MeshData::addPositionsVec2(UINT32 numElements, UINT32 streamIdx)
+	void MeshData::beginDesc()
 	{
-		return reinterpret_cast<Vector2*>(addVertexElementData(VET_FLOAT2, VES_POSITION, numElements, 0, streamIdx));
-	}
+		if(mDescBuilding)
+			CM_EXCEPT(InternalErrorException, "beginDesc() but description building has already began.");
 
-	Vector3* MeshData::addPositionsVec3(UINT32 numElements, UINT32 streamIdx)
-	{
-		return reinterpret_cast<Vector3*>(addVertexElementData(VET_FLOAT3, VES_POSITION, numElements, 0, streamIdx));
-	}
+		mVertexElements.clear();
+		mSubMeshes.clear();
 
-	Vector4* MeshData::addPositionsVec4(UINT32 numElements, UINT32 streamIdx)
-	{
-		return reinterpret_cast<Vector4*>(addVertexElementData(VET_FLOAT4, VES_POSITION, numElements, 0, streamIdx));
+		mDescBuilding = true;
 	}
 
-	Vector3* MeshData::addNormals(UINT32 numElements, UINT32 streamIdx)
+	void MeshData::endDesc()
 	{
-		return reinterpret_cast<Vector3*>(addVertexElementData(VET_FLOAT3, VES_NORMAL, numElements, 0, streamIdx));
-	}
+		if(!mDescBuilding)
+			CM_EXCEPT(InternalErrorException, "endDesc() called without beginDesc().");
 
-	Vector3* MeshData::addTangentsVec3(UINT32 numElements, UINT32 streamIdx)
-	{
-		return reinterpret_cast<Vector3*>(addVertexElementData(VET_FLOAT3, VES_TANGENT, numElements, 0, streamIdx));
-	}
+		allocateInternalBuffer();
 
-	Vector4* MeshData::addTangentsVec4(UINT32 numElements, UINT32 streamIdx)
-	{
-		return reinterpret_cast<Vector4*>(addVertexElementData(VET_FLOAT4, VES_TANGENT, numElements, 0, streamIdx));
+		mDescBuilding = false;
 	}
 
-	Vector3* MeshData::addBitangents(UINT32 numElements, UINT32 streamIdx)
+	void MeshData::addVertElem(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
 	{
-		return reinterpret_cast<Vector3*>(addVertexElementData(VET_FLOAT3, VES_BITANGENT, numElements, 0, streamIdx));
-	}
+		if(!mDescBuilding)
+			CM_EXCEPT(InternalErrorException, "Cannot add vertex element when not building description. Call beginDesc() first.");
 
-	Vector2* MeshData::addUV0(UINT32 numElements, UINT32 streamIdx)
-	{
-		return reinterpret_cast<Vector2*>(addVertexElementData(VET_FLOAT2, VES_TEXCOORD, numElements, 0, streamIdx));
+		clearIfItExists(type, semantic, semanticIdx, streamIdx);
+
+		VertexElement newElement(streamIdx, 0, type, semantic, semanticIdx);
+
+		// Insert it so it is sorted by stream
+		UINT32 insertToIndex = (UINT32)mVertexElements.size();
+		UINT32 idx = 0;
+		for(auto& elem : mVertexElements)
+		{
+			if(elem.getStreamIdx() > streamIdx)
+			{
+				insertToIndex = idx;
+				break;
+			}
+
+			idx++;
+		}
+
+		mVertexElements.insert(mVertexElements.begin() + insertToIndex, newElement);
 	}
 
-	Vector2* MeshData::addUV1(UINT32 numElements, UINT32 streamIdx)
+	void MeshData::addSubMesh(UINT32 numIndices, UINT32 subMesh)
 	{
-		return reinterpret_cast<Vector2*>(addVertexElementData(VET_FLOAT2, VES_TEXCOORD, numElements, 1, streamIdx));
+		if(!mDescBuilding)
+			CM_EXCEPT(InternalErrorException, "Cannot add indices when not building description. Call beginDesc() first.");
+
+		if(subMesh >= mSubMeshes.size())
+			mSubMeshes.resize(subMesh + 1);
+
+		IndexElementData indexData = mSubMeshes[subMesh];
+
+		indexData.numIndices = numIndices;
+		indexData.elementSize = getIndexElementSize();
+		indexData.subMesh = subMesh;
+
+		mSubMeshes[subMesh] = indexData;
 	}
 
-	Color* MeshData::addColorsFloat(UINT32 numElements, UINT32 streamIdx)
+	VertexDeclarationPtr MeshData::createDeclaration() const
 	{
-		return reinterpret_cast<Color*>(addVertexElementData(VET_FLOAT4, VES_COLOR, numElements, 0, streamIdx));
+		VertexDeclarationPtr declaration = HardwareBufferManager::instance().createVertexDeclaration();
+
+		UINT32 maxStreamIdx = getMaxStreamIdx();
+
+		UINT32 numStreams = maxStreamIdx + 1;
+		UINT32* streamOffsets = CM_NEW_ARRAY(UINT32, numStreams, ScratchAlloc);
+		for(UINT32 i = 0; i < numStreams; i++)
+			streamOffsets[i] = 0;
+
+		for(auto& vertElem : mVertexElements)
+		{
+			UINT32 streamIdx = vertElem.getStreamIdx();
+			declaration->addElement(streamIdx, streamOffsets[streamIdx], vertElem.getType(), vertElem.getSemantic(), vertElem.getSemanticIdx());
+			streamOffsets[streamIdx] += vertElem.getSize();
+		}
+
+		CM_DELETE_ARRAY(streamOffsets, UINT32, numStreams,ScratchAlloc);
+
+		return declaration;
 	}
 
-	UINT32* MeshData::addColorsDWORD(UINT32 numElements, UINT32 streamIdx)
+	UINT32 MeshData::getNumIndices(UINT32 subMesh) const
 	{
-		return reinterpret_cast<UINT32*>(addVertexElementData(VET_COLOR, VES_COLOR, numElements, 0, streamIdx));
+		return mSubMeshes.at(subMesh).numIndices;
 	}
 
-	UINT8* MeshData::addVertexElementData(VertexElementType type, VertexElementSemantic semantic, UINT32 numElements, UINT32 semanticIdx, UINT32 streamIdx)
+	UINT32 MeshData::getNumIndices() const
 	{
-		clearIfItExists(type, semantic, semanticIdx, streamIdx);
+		UINT32 count = 0;
+		for(UINT32 i = 0; i < getNumSubmeshes(); i++)
+		{
+			count += mSubMeshes[i].numIndices;
+		}
 
-		UINT32 elemSize = VertexElement::getTypeSize(type);
-		UINT8* elements = CM_NEW_BYTES(elemSize * numElements, ScratchAlloc);
+		return count;
+	}
 
-		vector<VertexElementData>::type& elemData = mVertexData[streamIdx];
+	UINT16* MeshData::getIndices16(UINT32 subMesh) const
+	{
+		if(mIndexType != IndexBuffer::IT_16BIT)
+			CM_EXCEPT(InternalErrorException, "Attempting to get 16bit index buffer, but internally allocated buffer is 32 bit.");
 
-		VertexElementData newElement(type, semantic, semanticIdx, streamIdx, elements, numElements);
-		elemData.push_back(newElement);
+		UINT32 indexBufferOffset = getIndexBufferOffset(subMesh);
 
-		return elements;
+		return (UINT16*)(getData() + indexBufferOffset);
 	}
 
-	UINT32* MeshData::addIndices32(UINT32 numIndices, UINT32 subMesh)
+	UINT32* MeshData::getIndices32(UINT32 subMesh) const
 	{
 		if(mIndexType != IndexBuffer::IT_32BIT)
-			CM_EXCEPT(InvalidParametersException, "Trying to set 32bit indices but the MeshData was initialized as 16bit.");
+			CM_EXCEPT(InternalErrorException, "Attempting to get 32bit index buffer, but internally allocated buffer is 16 bit.");
 
-		if(subMesh >= mIndices.size())
-			mIndices.resize(subMesh + 1);
+		UINT32 indexBufferOffset = getIndexBufferOffset(subMesh);
 
-		IndexElementData indexData = mIndices[subMesh];
+		return (UINT32*)(getData() + indexBufferOffset);
+	}
 
-		if(indexData.indices != nullptr)
-			CM_DELETE_BYTES(indexData.indices, ScratchAlloc);
+	vector<VertexElement>::type MeshData::getVertexElements() const
+	{
+		return mVertexElements;
+	}
 
-		UINT32* indices = (UINT32*)CM_NEW_BYTES(numIndices * sizeof(UINT32), ScratchAlloc);
+	UINT32 MeshData::getMaxStreamIdx() const
+	{
+		UINT32 maxStreamIdx = 0;
+		for(auto& vertElems : mVertexElements)
+		{
+			UINT32 offset = 0;
+			for(auto& vertElem : mVertexElements)
+			{
+				maxStreamIdx = std::max((UINT32)maxStreamIdx, (UINT32)vertElem.getStreamIdx());
+			}
+		}
 
-		indexData.indices = (UINT8*)indices;
-		indexData.numIndices = numIndices;
-		indexData.elementSize = getIndexElementSize();
-		indexData.subMesh = subMesh;
+		return maxStreamIdx;
+	}
 
-		mIndices[subMesh] = indexData;
+	bool MeshData::hasStream(UINT32 streamIdx) const
+	{
+		for(auto& vertElem : mVertexElements)
+		{
+			if(vertElem.getStreamIdx() == streamIdx)
+				return true;
+		}
 
-		return indices;
+		return false;
 	}
 
-	UINT16* MeshData::addIndices16(UINT32 numIndices, UINT32 subMesh)
+	void MeshData::allocateInternalBuffer()
 	{
-		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);
+		mData = CM_NEW_BYTES(getInternalBufferSize(), ScratchAlloc); // TODO! - Not cleaned anywhere, because I won't be using this in the end
+	}
 
-		IndexElementData indexData = mIndices[subMesh];
+	void MeshData::allocateInternalBuffer(UINT32 numBytes)
+	{
+		mData = CM_NEW_BYTES(numBytes, ScratchAlloc); // TODO! - Not cleaned anywhere, because I won't be using this in the end
+	}
 
-		if(indexData.indices != nullptr)
-			CM_DELETE_BYTES(indexData.indices, ScratchAlloc);
+	UINT32 MeshData::getInternalBufferSize()
+	{
+		return getIndexBufferSize() + getStreamSize();
+	}
 
-		UINT16* indices = (UINT16*)CM_NEW_BYTES(numIndices * sizeof(UINT16), ScratchAlloc);
+	MeshDataPtr MeshData::combine(const vector<MeshDataPtr>::type& meshes)
+	{
+		UINT32 totalVertexCount = 0;
+		for(auto& meshData : meshes)
+		{
+			UINT32 numVertices = meshData->getNumVertices();
+			totalVertexCount += numVertices;
+		}
 
-		indexData.indices = (UINT8*)indices;
-		indexData.numIndices = numIndices;
-		indexData.elementSize = getIndexElementSize();
-		indexData.subMesh = subMesh;
+		MeshDataPtr combinedMeshData(CM_NEW(MeshData, PoolAlloc) MeshData(totalVertexCount),
+			&MemAllocDeleter<MeshData, PoolAlloc>::deleter);
 
-		mIndices[subMesh] = indexData;
+		//UINT32 subMeshIndex = 0;
+		//UINT32 vertexIndexOffset = 0;
+		//for(auto& meshData : meshes)
+		//{
+		//	for(UINT32 i = 0; i < meshData->getNumSubmeshes(); i++)
+		//	{
+		//		UINT32 numIndices = meshData->getNumIndices(i);
+		//		UINT32* indices = combinedMeshData->addSubMesh(numIndices, subMeshIndex);
+
+		//		UINT32* sourceIndices = meshData->getIndices32(i);
+
+		//		for(UINT32 j = 0; j < numIndices; j++)
+		//			indices[j] = sourceIndices[j] + vertexIndexOffset;
+
+		//		subMeshIndex++;
+		//	}
+
+		//	UINT32 numVertices = meshData->getNumVertices();
+		//	vertexIndexOffset += numVertices;
+		//}
+
+		//vector<VertexElement>::type combinedVertexElements;
+		//for(auto& meshData : meshes)
+		//{
+		//	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);
+		//			combinedMeshData->addVertElem(newElement.getType(), newElement.getSemantic(), newElement.getSemanticIdx(), newElement.getStreamIdx());
+		//		}
+		//	}
+		//}
+
+		//combinedMeshData->allocateInternalBuffer();
+
+		//UINT32 vertexOffset = 0;
+		//for(auto& element : combinedVertexElements)
+		//{
+		//	for(auto& meshData : meshes)
+		//	{
+		//		if(meshData->hasElement(element.getSemantic(), element.getSemanticIdx(), element.getStreamIdx()))
+		//		{
+
+		//		}
+		//	}
+
+		//	vector<VertexElement>::type vertexElements = meshData->getVertexElements();
+		//	UINT32 numVertices = meshData->getNumVertices();
+
+		//	for(auto& newElement : vertexElements)
+		//	{
+		//		// TODO
+
+
+		//	}
+
+		//	vertexOffset += meshData->getNumVertices();
+		//}
 
-		return indices;
+		return combinedMeshData;
 	}
 
-	VertexDeclarationPtr MeshData::createDeclaration() const
+	bool MeshData::hasElement(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const
 	{
-		VertexDeclarationPtr declaration = HardwareBufferManager::instance().createVertexDeclaration();
+		auto findIter = std::find_if(mVertexElements.begin(), mVertexElements.end(), 
+			[semantic, semanticIdx, streamIdx] (const VertexElement& x) 
+		{ 
+			return x.getSemantic() == semantic && x.getSemanticIdx() == semanticIdx && x.getStreamIdx() == streamIdx; 
+		});
 
-		for(auto& vertElems : mVertexData)
+		if(findIter != mVertexElements.end())
 		{
-			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 true;
 		}
 
-		return declaration;
+		return false;
 	}
 
-	UINT32 MeshData::getNumVertices() const
+	void MeshData::setVertexData(VertexElementSemantic semantic, UINT8* data, UINT32 size, UINT32 semanticIdx, UINT32 streamIdx)
 	{
-		UINT32 numVertices = 0;
+		assert(data != nullptr);
 
-		auto vertElemDataPerStream = mVertexData;
-		MeshData::VertexElementData* firstElemData = nullptr;
-		if(vertElemDataPerStream.size() > 0)
+		if(!hasElement(semantic, semanticIdx, streamIdx))
 		{
-			auto vertElemData = vertElemDataPerStream.begin()->second;
-			auto firstVertElem = vertElemData.begin();
-			if(firstVertElem != vertElemData.end())
-			{
-				numVertices = firstVertElem->elementCount;
-			}
+			CM_EXCEPT(InvalidParametersException, "MeshData doesn't contain an element of specified type: Semantic: " + toString(semantic) + ", Semantic index: "
+				+ toString(semanticIdx) + ", Stream index: " + toString(streamIdx));
 		}
 
-		for(auto& vertElems : mVertexData)
+		UINT32 elementSize = getElementSize(semantic, semanticIdx, streamIdx);
+		UINT32 totalSize = elementSize * mNumVertices;
+
+		if(totalSize != size)
 		{
-			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));
-				}
-			}
+			CM_EXCEPT(InvalidParametersException, "Buffer sizes don't match. Expected: " + toString(totalSize) + ". Got: " + toString(size));
 		}
 
-		return numVertices;
+		UINT32 indexBufferOffset = getIndexBufferSize();
+
+		UINT32 elementOffset = getElementOffset(semantic, semanticIdx, streamIdx);
+		UINT32 vertexStride = getVertexStride(streamIdx);
+
+		UINT8* dst = getData() + indexBufferOffset + elementOffset;
+		UINT8* src = data;
+		for(UINT32 i = 0; i < mNumVertices; i++)
+		{
+			memcpy(dst, src, elementSize);
+			dst += vertexStride;
+			src += elementSize;
+		}
 	}
 
-	UINT32 MeshData::getNumIndices(UINT32 subMesh) const
+	VertexElemIter<Vector2> MeshData::getVec2DataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
 	{
-		return mIndices.at(subMesh).numIndices;
+		UINT8* data;
+		UINT32 vertexStride;
+		getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride);
+
+		return VertexElemIter<Vector2>(data, vertexStride, mNumVertices);
 	}
 
-	UINT16* MeshData::getIndices16(UINT32 subMesh) const
+	VertexElemIter<Vector3> MeshData::getVec3DataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
 	{
-		return (UINT16*)mIndices.at(subMesh).indices;
+		UINT8* data;
+		UINT32 vertexStride;
+		getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride);
+
+		return VertexElemIter<Vector3>(data, vertexStride, mNumVertices);
 	}
 
-	UINT32* MeshData::getIndices32(UINT32 subMesh) const
+	VertexElemIter<Vector4> MeshData::getVec4DataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
 	{
-		return (UINT32*)mIndices.at(subMesh).indices;
+		UINT8* data;
+		UINT32 vertexStride;
+		getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride);
+
+		return VertexElemIter<Vector4>(data, vertexStride, mNumVertices);
 	}
 
-	vector<VertexElement>::type MeshData::getVertexElements() const
+	VertexElemIter<Color> MeshData::getColorDataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
 	{
-		vector<VertexElement>::type elements;
-		for(auto& vertElems : mVertexData)
-		{
-			UINT32 offset = 0;
-			for(auto& vertElem : vertElems.second)
-			{
-				elements.push_back(vertElem.element);
-			}
-		}
+		UINT8* data;
+		UINT32 vertexStride;
+		getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride);
 
-		return elements;
+		return VertexElemIter<Color>(data, vertexStride, mNumVertices);
 	}
 
-	MeshDataPtr MeshData::combine(const vector<MeshDataPtr>::type& elements)
+	VertexElemIter<UINT32> MeshData::getDWORDDataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
 	{
-		MeshDataPtr combinedMeshData(CM_NEW(MeshData, PoolAlloc) MeshData(),
-			&MemAllocDeleter<MeshData, PoolAlloc>::deleter);
+		UINT8* data;
+		UINT32 vertexStride;
+		getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride);
 
-		UINT32 subMeshIndex = 0;
-		vector<VertexElement>::type combinedVertexElements;
-		vector<UINT8*>::type vertexElemData;
-		vector<UINT32>::type bufferOffsets;
-		UINT32 totalVertexCount = 0;
+		return VertexElemIter<UINT32>(data, vertexStride, mNumVertices);
+	}
 
-		UINT32 vertexIndexOffset = 0;
-		for(auto& meshData : elements)
+	void MeshData::getDataForIterator(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx, UINT8*& data, UINT32& stride) const
+	{
+		if(!hasElement(semantic, semanticIdx, streamIdx))
 		{
-			for(UINT32 i = 0; i < meshData->getNumSubmeshes(); i++)
-			{
-				UINT32 numIndices = meshData->getNumIndices(i);
-				UINT32* indices = combinedMeshData->addIndices32(numIndices, subMeshIndex);
+			CM_EXCEPT(InvalidParametersException, "MeshData doesn't contain an element of specified type: Semantic: " + toString(semantic) + ", Semantic index: "
+				+ toString(semanticIdx) + ", Stream index: " + toString(streamIdx));
+		}
 
-				UINT32* sourceIndices = meshData->getIndices32(i);
+		UINT32 indexBufferOffset = getIndexBufferSize();
 
-				for(UINT32 j = 0; j < numIndices; j++)
-					indices[j] = sourceIndices[j] + vertexIndexOffset;
+		UINT32 elementOffset = getElementOffset(semantic, semanticIdx, streamIdx);
 
-				subMeshIndex++;
-			}
+		data = getData() + indexBufferOffset + elementOffset;
+		stride = getVertexStride(streamIdx);
+	}
 
-			UINT32 numVertices = meshData->getNumVertices();
-			totalVertexCount += numVertices;
-			vertexIndexOffset += numVertices;
+	UINT32 MeshData::getIndexBufferOffset(UINT32 subMesh) const
+	{
+		if(subMesh < 0 || (subMesh > (UINT32)mSubMeshes.size()))
+		{
+			CM_EXCEPT(InvalidParametersException, "Submesh out of range: " + toString(subMesh) + ". Allowed range: 0 .. " + toString((UINT32)mSubMeshes.size()));
 		}
 
-		UINT32 vertexOffset = 0;
-		for(auto& meshData : elements)
+		UINT32 offset = 0;
+		for(UINT32 i = 0; i < subMesh; i++)
 		{
-			vector<VertexElement>::type vertexElements = meshData->getVertexElements();
-			UINT32 numVertices = meshData->getNumVertices();
+			offset += mSubMeshes[i].numIndices * getIndexElementSize();
+		}
 
-			for(auto& newElement : vertexElements)
+		return offset;
+	}
+
+	UINT32 MeshData::getStreamOffset(UINT32 streamIdx) const
+	{
+		UINT32 streamOffset = 0;
+		bool found = false;
+		for(auto& element : mVertexElements)
+		{
+			if(element.getStreamIdx() == streamIdx)
 			{
-				INT32 alreadyExistsIdx = -1;
-				UINT32 idx = 0;
-				for(auto& existingElement : combinedVertexElements)
-				{
-					if(newElement == existingElement)
-					{
-						alreadyExistsIdx = idx;
-						break;
-					}
-
-					idx++;
-				}
-
-				if(alreadyExistsIdx == -1)
-				{
-					combinedVertexElements.push_back(newElement);
-					
-					UINT8* newBuffer = combinedMeshData->addVertexElementData(newElement.getType(), newElement.getSemantic(), totalVertexCount, newElement.getIndex(), newElement.getSource());
-					
-					UINT32 newBufferSize = totalVertexCount * newElement.getSize();
-					memset(newBuffer, 0, newBufferSize);
-
-					vertexElemData.push_back(newBuffer);
-					bufferOffsets.push_back(0);
-					alreadyExistsIdx = (UINT32)vertexElemData.size() - 1;
-				}
-
-				UINT8* source = meshData->getVertElemData(newElement.getType(), newElement.getSemantic(), newElement.getIndex(), newElement.getSource()).data;
-				UINT32 offset = vertexOffset * newElement.getSize();
-
-				memcpy(&(vertexElemData[alreadyExistsIdx]) + offset, source, numVertices * newElement.getSize());
+				found = true;
+				break;
 			}
 
-			vertexOffset += meshData->getNumVertices();
+			streamOffset += element.getSize();
 		}
 
-		return combinedMeshData;
+		if(!found)
+			CM_EXCEPT(InternalErrorException, "Cannot find the specified stream: " + toString(streamIdx));
+
+		return streamOffset * mNumVertices;
 	}
 
-	bool MeshData::hasElement(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const
+	UINT32 MeshData::getElementSize(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;
+		for(auto& element : mVertexElements)
+		{
+			if(element.getSemantic() == semantic && element.getSemanticIdx() == semanticIdx && element.getStreamIdx() == streamIdx)
+				return element.getSize();
+		}
 
-		auto findIter = std::find_if(elemData.begin(), elemData.end(), 
-			[semantic, semanticIdx] (const VertexElementData& x) 
-		{ 
-			return x.element.getSemantic() == semantic && x.element.getIndex() == semanticIdx; 
-		});
+		return -1;
+	}
 
-		if(findIter != elemData.end())
-			return true;
+	UINT8* MeshData::getElementData(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const
+	{ 
+		return getData() + getIndexBufferSize() + getElementOffset(semantic, semanticIdx, streamIdx); 
+	}
 
-		return false;
+	UINT8* MeshData::getStreamData(UINT32 streamIdx) const
+	{ 
+		return getData() + getIndexBufferSize() + getStreamOffset(streamIdx); 
 	}
 
-	void MeshData::clearIfItExists(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
+	UINT32 MeshData::getIndexElementSize() const
 	{
-		vector<VertexElementData>::type& elemData = mVertexData[streamIdx];
+		return mIndexType == IndexBuffer::IT_32BIT ? sizeof(UINT32) : sizeof(UINT16);
+	}
 
-		auto findIter = std::find_if(elemData.begin(), elemData.end(), 
-			[type, semantic, semanticIdx] (const VertexElementData& x) 
-		{ 
-			return x.element.getSemantic() == semantic && x.element.getIndex() == semanticIdx; 
-		});
+	UINT32 MeshData::getElementOffset(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const
+	{
+		UINT32 streamOffset = getStreamOffset(streamIdx);
 
-		if(findIter != elemData.end())
+		UINT32 vertexOffset = 0;
+		for(auto& element : mVertexElements)
 		{
-			if(findIter->data != nullptr)
-				CM_DELETE_BYTES(findIter->data, ScratchAlloc);
+			if(element.getStreamIdx() != streamIdx)
+				continue;
+
+			if(element.getSemantic() == semantic && element.getSemanticIdx() == semanticIdx)
+				break;
 
-			elemData.erase(findIter);
+			vertexOffset += element.getSize();
 		}
+
+		return streamOffset * mNumVertices + vertexOffset;
 	}
 
-	MeshData::VertexElementData& MeshData::getVertElemData(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
+	UINT32 MeshData::getStreamSize(UINT32 streamIdx) const
 	{
-		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.");
+		UINT32 vertexStride = 0;
+		for(auto& element : mVertexElements)
+		{
+			if(element.getStreamIdx() == streamIdx)
+				vertexStride += element.getSize();
+		}
 
-		return *findIter;
+		return vertexStride * mNumVertices;
 	}
 
-	/************************************************************************/
-	/* 								SERIALIZATION                      		*/
-	/************************************************************************/
-
-	RTTITypeBase* MeshData::VertexElementData::getRTTIStatic()
+	UINT32 MeshData::getStreamSize() const
 	{
-		return VertexElementDataRTTI::instance();
-	}
+		UINT32 vertexStride = 0;
+		for(auto& element : mVertexElements)
+		{
+			vertexStride += element.getSize();
+		}
 
-	RTTITypeBase* MeshData::VertexElementData::getRTTI() const
-	{
-		return VertexElementData::getRTTIStatic();
+		return vertexStride * mNumVertices;
 	}
 
-	RTTITypeBase* MeshData::IndexElementData::getRTTIStatic()
+	UINT32 MeshData::getVertexStride(UINT32 streamIdx) const
 	{
-		return IndexElementDataRTTI::instance();
+		UINT32 vertexStride = 0;
+		for(auto& element : mVertexElements)
+		{
+			if(element.getStreamIdx() == streamIdx)
+				vertexStride += element.getSize();
+		}
+
+		return vertexStride;
 	}
 
-	RTTITypeBase* MeshData::IndexElementData::getRTTI() const
+	void MeshData::clearIfItExists(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
 	{
-		return IndexElementData::getRTTIStatic();
+		auto findIter = std::find_if(mVertexElements.begin(), mVertexElements.end(), 
+			[semantic, semanticIdx, streamIdx] (const VertexElement& x) 
+		{ 
+			return x.getSemantic() == semantic && x.getSemanticIdx() == semanticIdx && x.getStreamIdx() == streamIdx; 
+		});
+
+		if(findIter != mVertexElements.end())
+		{
+			mVertexElements.erase(findIter);
+		}
 	}
 
+	/************************************************************************/
+	/* 								SERIALIZATION                      		*/
+	/************************************************************************/
+
 	RTTITypeBase* MeshData::getRTTIStatic()
 	{
 		return MeshDataRTTI::instance();

+ 0 - 24
CamelotCore/Source/CmMeshDataRTTI.cpp

@@ -1,24 +0,0 @@
-#include "CmMeshDataRTTI.h"
-
-namespace CamelotFramework
-{
-	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;
-	}
-}

+ 10 - 5
CamelotCore/Source/CmMeshManager.cpp

@@ -6,15 +6,20 @@ namespace CamelotFramework
 {
 	MeshManager::MeshManager()
 	{
-		mNullMeshData = MeshDataPtr(CM_NEW(MeshData, GenAlloc) MeshData(), &MemAllocDeleter<MeshData, GenAlloc>::deleter);
+		mNullMeshData = MeshDataPtr(CM_NEW(MeshData, GenAlloc) MeshData(1), &MemAllocDeleter<MeshData, GenAlloc>::deleter);
 
-		auto indices = mNullMeshData->addIndices32(3);
+		mNullMeshData->beginDesc();
+		mNullMeshData->addVertElem(VET_FLOAT3, VES_POSITION);
+		mNullMeshData->addSubMesh(3);
+		mNullMeshData->endDesc();
+
+		auto vecIter = mNullMeshData->getVec3DataIter(VES_POSITION);
+		vecIter.setValue(Vector3(0, 0, 0));
+
+		auto indices = mNullMeshData->getIndices32(0);
 		indices[0] = 0;
 		indices[1] = 0;
 		indices[2] = 0;
-
-		auto vertices = mNullMeshData->addPositionsVec3(1);
-		vertices[0] = Vector3(0, 0, 0);
 	}
 
 	MeshManager::~MeshManager()

+ 2 - 2
CamelotCore/Source/CmVertexData.cpp

@@ -156,8 +156,8 @@ namespace CamelotFramework
 						&& elem.getType() != destType))
 					{
 						vertexDeclaration->modifyElement(elemIndex, 
-							elem.getSource(), elem.getOffset(), destType, 
-							elem.getSemantic(), elem.getIndex());
+							elem.getStreamIdx(), elem.getOffset(), destType, 
+							elem.getSemantic(), elem.getSemanticIdx());
 					}
 				}
 			}

+ 15 - 15
CamelotCore/Source/CmVertexDeclaration.cpp

@@ -291,7 +291,7 @@ namespace CamelotFramework
 		eiend = mElementList.end();
 		for (ei = mElementList.begin(); ei != eiend; ++ei)
 		{
-			if (ei->getSemantic() == semantic && ei->getIndex() == index)
+			if (ei->getSemantic() == semantic && ei->getSemanticIdx() == index)
 			{
 				mElementList.erase(ei);
 				break;
@@ -327,7 +327,7 @@ namespace CamelotFramework
 		eiend = mElementList.end();
 		for (ei = mElementList.begin(); ei != eiend; ++ei)
 		{
-			if (ei->getSemantic() == sem && ei->getIndex() == index)
+			if (ei->getSemantic() == sem && ei->getSemanticIdx() == index)
 			{
 				return &(*ei);
 			}
@@ -344,7 +344,7 @@ namespace CamelotFramework
 		eiend = mElementList.end();
 		for (ei = mElementList.begin(); ei != eiend; ++ei)
 		{
-			if (ei->getSource() == source)
+			if (ei->getStreamIdx() == source)
 			{
 				retList.push_back(*ei);
 			}
@@ -360,7 +360,7 @@ namespace CamelotFramework
 
 		for (i = mElementList.begin(); i != iend; ++i)
 		{
-			if (i->getSource() == source)
+			if (i->getStreamIdx() == source)
 			{
 				sz += i->getSize();
 
@@ -378,7 +378,7 @@ namespace CamelotFramework
 		iend = mElementList.end();
 		for (i = mElementList.begin(); i != iend; ++i)
 		{
-			ret->addElement(i->getSource(), i->getOffset(), i->getType(), i->getSemantic(), i->getIndex());
+			ret->addElement(i->getStreamIdx(), i->getOffset(), i->getType(), i->getSemantic(), i->getSemanticIdx());
 		}
 
 		ret->mHash = mHash;
@@ -389,11 +389,11 @@ namespace CamelotFramework
 	bool VertexDeclaration::vertexElementLess(const VertexElement& e1, const VertexElement& e2)
 	{
 		// Sort by source first
-		if (e1.getSource() < e2.getSource())
+		if (e1.getStreamIdx() < e2.getStreamIdx())
 		{
 			return true;
 		}
-		else if (e1.getSource() == e2.getSource())
+		else if (e1.getStreamIdx() == e2.getStreamIdx())
 		{
 			// Use ordering of semantics to sort
 			if (e1.getSemantic() < e2.getSemantic())
@@ -403,7 +403,7 @@ namespace CamelotFramework
 			else if (e1.getSemantic() == e2.getSemantic())
 			{
 				// Use index to sort
-				if (e1.getIndex() < e2.getIndex())
+				if (e1.getSemanticIdx() < e2.getSemanticIdx())
 				{
 					return true;
 				}
@@ -427,20 +427,20 @@ namespace CamelotFramework
 		VertexElementList::iterator i, iend;
 		iend = mElementList.end();
 		unsigned short targetIdx = 0;
-		unsigned short lastIdx = getElement(0)->getSource();
+		unsigned short lastIdx = getElement(0)->getStreamIdx();
 		unsigned short c = 0;
 		for (i = mElementList.begin(); i != iend; ++i, ++c)
 		{
 			VertexElement& elem = *i;
-			if (lastIdx != elem.getSource())
+			if (lastIdx != elem.getStreamIdx())
 			{
 				targetIdx++;
-				lastIdx = elem.getSource();
+				lastIdx = elem.getStreamIdx();
 			}
-			if (targetIdx != elem.getSource())
+			if (targetIdx != elem.getStreamIdx())
 			{
 				modifyElement(c, targetIdx, elem.getOffset(), elem.getType(), 
-					elem.getSemantic(), elem.getIndex());
+					elem.getSemantic(), elem.getSemanticIdx());
 			}
 
 		}
@@ -453,9 +453,9 @@ namespace CamelotFramework
 		unsigned short ret = 0;
 		for (i = mElementList.begin(); i != iend; ++i)
 		{
-			if (i->getSource() > ret)
+			if (i->getStreamIdx() > ret)
 			{
-				ret = i->getSource();
+				ret = i->getStreamIdx();
 			}
 
 		}

+ 4 - 4
CamelotD3D11RenderSystem/Source/CmD3D11InputLayoutManager.cpp

@@ -101,9 +101,9 @@ namespace CamelotFramework
 		for(auto iter = vertexBufferDecl->getElements().begin(); iter != vertexBufferDecl->getElements().end(); ++iter)
 		{
 			declElements[idx].SemanticName			= D3D11Mappings::get(iter->getSemantic());
-			declElements[idx].SemanticIndex			= iter->getIndex();
+			declElements[idx].SemanticIndex			= iter->getSemanticIdx();
 			declElements[idx].Format				= D3D11Mappings::get(iter->getType());
-			declElements[idx].InputSlot				= iter->getSource();
+			declElements[idx].InputSlot				= iter->getStreamIdx();
 			declElements[idx].AlignedByteOffset		= static_cast<WORD>(iter->getOffset());
 			declElements[idx].InputSlotClass		= D3D11_INPUT_PER_VERTEX_DATA;
 			declElements[idx].InstanceDataStepRate	= 0;
@@ -185,7 +185,7 @@ namespace CamelotFramework
 			const VertexElement* foundElement = nullptr;
 			for(auto bufferIter = vertexBufferDecl->getElements().begin(); bufferIter != vertexBufferDecl->getElements().end(); ++bufferIter)
 			{
-				if(shaderIter->getSemantic() == bufferIter->getSemantic() && shaderIter->getIndex() == bufferIter->getIndex())
+				if(shaderIter->getSemantic() == bufferIter->getSemantic() && shaderIter->getSemanticIdx() == bufferIter->getSemanticIdx())
 				{
 					foundElement = &(*bufferIter);
 					break;
@@ -194,7 +194,7 @@ namespace CamelotFramework
 
 			if(foundElement == nullptr)
 			{
-				LOGWRN("Provided vertex buffer doesn't have a required input attribute: " + toString(shaderIter->getSemantic()) + toString(shaderIter->getIndex()));
+				LOGWRN("Provided vertex buffer doesn't have a required input attribute: " + toString(shaderIter->getSemantic()) + toString(shaderIter->getSemanticIdx()));
 				return false;
 			}
 		}

+ 2 - 2
CamelotD3D9Renderer/Source/CmD3D9VertexDeclaration.cpp

@@ -130,7 +130,7 @@ namespace CamelotFramework {
 			{
 				d3delems[idx].Method = D3DDECLMETHOD_DEFAULT;
 				d3delems[idx].Offset = static_cast<WORD>(i->getOffset());
-				d3delems[idx].Stream = i->getSource();
+				d3delems[idx].Stream = i->getStreamIdx();
 				d3delems[idx].Type = D3D9Mappings::get(i->getType());
 				d3delems[idx].Usage = D3D9Mappings::get(i->getSemantic());
 				// NB force index if colours since D3D uses the same usage for 
@@ -145,7 +145,7 @@ namespace CamelotFramework {
 				}
 				else
 				{
-					d3delems[idx].UsageIndex = static_cast<BYTE>(i->getIndex());
+					d3delems[idx].UsageIndex = static_cast<BYTE>(i->getSemanticIdx());
 				}
 			}
 			// Add terminator

+ 212 - 117
CamelotFBXImporter/Source/CmFBXImporter.cpp

@@ -175,65 +175,8 @@ namespace CamelotFramework
 
 	MeshDataPtr FBXImporter::parseMesh(FbxMesh* mesh, bool createTangentsIfMissing)
 	{
-		MeshDataPtr meshData = MeshDataPtr(CM_NEW(MeshData, ScratchAlloc) MeshData(), &MemAllocDeleter<MeshData, ScratchAlloc>::deleter);
-
 		if (!mesh->GetNode())
-			return meshData;
-		
-		if(createTangentsIfMissing && mesh->GetElementUVCount() > 0)
-			mesh->GenerateTangentsData(0, false);
-
-		const int lPolygonCount = mesh->GetPolygonCount();
-
-		// 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();
-			lMaterialMappingMode = mesh->GetElementMaterial()->GetMappingMode();
-			if (lMaterialIndice && lMaterialMappingMode == FbxGeometryElement::eByPolygon)
-			{
-				FBX_ASSERT(lMaterialIndice->GetCount() == lPolygonCount);
-				if (lMaterialIndice->GetCount() == lPolygonCount)
-				{
-					// Count the faces of each material
-					for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex)
-					{
-						const UINT32 lMaterialIndex = (UINT32)lMaterialIndice->GetAt(lPolygonIndex);
-						if (subMeshes.size() < lMaterialIndex + 1)
-						{
-							subMeshes.resize(lMaterialIndex + 1);
-						}
-
-						subMeshes[lMaterialIndex].indexCount += 3;
-					}
-
-					// 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)
-					{
-						subMeshes[lIndex].indexOffset = lOffset;
-						lOffset += subMeshes[lIndex].indexCount;
-						indices[lIndex] = meshData->addIndices32(subMeshes[lIndex].indexCount, lIndex);
-					}
-					FBX_ASSERT(lOffset == lPolygonCount * 3);
-				}
-			}
-		}
-
-		// All faces will use the same material.
-		if (subMeshes.size() == 0)
-		{
-			subMeshes.resize(1);
-			indices.resize(1);
-			subMeshes[0].indexCount = lPolygonCount * 3;
-			indices[0] = meshData->addIndices32(subMeshes[0].indexCount);
-		}
+			return MeshDataPtr(CM_NEW(MeshData, ScratchAlloc) MeshData(0), &MemAllocDeleter<MeshData, ScratchAlloc>::deleter);
 
 		// Find out which vertex attributes exist
 		bool allByControlPoint = true;
@@ -256,7 +199,7 @@ namespace CamelotFramework
 
 		bool hasNormal = mesh->GetElementNormalCount() > 0;
 		FbxGeometryElement::EMappingMode lNormalMappingMode = FbxGeometryElement::eNone;
-		
+
 		if (hasNormal)
 		{
 			lNormalMappingMode = mesh->GetElementNormal(0)->GetMappingMode();
@@ -326,45 +269,132 @@ namespace CamelotFramework
 				allByControlPoint = false;
 		}
 
-		// Allocate the array memory, by control point or by polygon vertex.
+		// Create tangents if needed
+		if(createTangentsIfMissing && mesh->GetElementUVCount() > 0)
+			mesh->GenerateTangentsData(0, false);
+
+		// Calculate number of vertices and indexes
+		const int lPolygonCount = mesh->GetPolygonCount();
+
 		int lPolygonVertexCount = mesh->GetControlPointsCount();
 		if (!allByControlPoint)
 			lPolygonVertexCount = lPolygonCount * 3;
 
 		UINT32 vertexCount = lPolygonVertexCount;
-		Vector3* vertex = meshData->addPositionsVec3(vertexCount);
 
-		Color* color = nullptr;
+		MeshDataPtr meshData = MeshDataPtr(CM_NEW(MeshData, ScratchAlloc) MeshData(vertexCount), &MemAllocDeleter<MeshData, ScratchAlloc>::deleter);
+		
+		meshData->beginDesc();
+		meshData->addVertElem(VET_FLOAT3, VES_POSITION);
+
 		if(hasColor)
-			color = meshData->addColorsFloat(vertexCount);
+			meshData->addVertElem(VET_COLOR, VES_COLOR);
 
-		Vector3* normal = nullptr;
-		if (hasNormal)
-			normal = meshData->addNormals(vertexCount);
+		if(hasNormal)
+			meshData->addVertElem(VET_FLOAT3, VES_NORMAL);
 
-		Vector3* tangent = nullptr;
-		if (hasTangent)
-			tangent = meshData->addTangentsVec3(vertexCount);
+		if(hasTangent)
+			meshData->addVertElem(VET_FLOAT3, VES_TANGENT);
 
-		Vector3* bitangent = nullptr;
-		if (hasBitangent)
-			bitangent = meshData->addBitangents(vertexCount);
+		if(hasBitangent)
+			meshData->addVertElem(VET_FLOAT3, VES_BITANGENT);
 
 		FbxStringList lUVNames;
 		mesh->GetUVSetNames(lUVNames);
 		const char * lUVName0 = NULL;
-		Vector2* uv0 = nullptr;
 		if (hasUV0 && lUVNames.GetCount() > 0)
 		{
-			uv0 = meshData->addUV0(vertexCount);
+			meshData->addVertElem(VET_FLOAT2, VES_TEXCOORD, 0);
 			lUVName0 = lUVNames[0];
 		}
 
 		const char * lUVName1 = NULL;
-		Vector2* uv1 = nullptr;
 		if (hasUV1 && lUVNames.GetCount() > 1)
 		{
-			uv1 = meshData->addUV1(vertexCount);
+			meshData->addVertElem(VET_FLOAT2, VES_TEXCOORD, 1);
+			lUVName1 = lUVNames[1];
+		}
+
+		// Count the polygon count of each material
+		FbxLayerElementArrayTemplate<int>* lMaterialIndice = NULL;
+		FbxGeometryElement::EMappingMode lMaterialMappingMode = FbxGeometryElement::eNone;
+		vector<SubMesh>::type subMeshes;
+
+		if (mesh->GetElementMaterial())
+		{
+			lMaterialIndice = &mesh->GetElementMaterial()->GetIndexArray();
+			lMaterialMappingMode = mesh->GetElementMaterial()->GetMappingMode();
+			if (lMaterialIndice && lMaterialMappingMode == FbxGeometryElement::eByPolygon)
+			{
+				FBX_ASSERT(lMaterialIndice->GetCount() == lPolygonCount);
+				if (lMaterialIndice->GetCount() == lPolygonCount)
+				{
+					// Count the faces of each material
+					for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex)
+					{
+						const UINT32 lMaterialIndex = (UINT32)lMaterialIndice->GetAt(lPolygonIndex);
+						if (subMeshes.size() < lMaterialIndex + 1)
+						{
+							subMeshes.resize(lMaterialIndex + 1);
+						}
+
+						subMeshes[lMaterialIndex].indexCount += 3;
+					}
+
+					// Record the offsets and allocate index arrays
+					const int lMaterialCount = (const int)subMeshes.size();
+					int lOffset = 0;
+					for (int lIndex = 0; lIndex < lMaterialCount; ++lIndex)
+					{
+						subMeshes[lIndex].indexOffset = lOffset;
+						lOffset += subMeshes[lIndex].indexCount;
+						meshData->addSubMesh(subMeshes[lIndex].indexCount, lIndex);
+					}
+					FBX_ASSERT(lOffset == lPolygonCount * 3);
+				}
+			}
+		}
+
+		// All faces will use the same material.
+		if (subMeshes.size() == 0)
+		{
+			subMeshes.resize(1);
+			subMeshes[0].indexCount = lPolygonCount * 3;
+			meshData->addSubMesh(subMeshes[0].indexCount);
+		}
+
+		meshData->endDesc();
+
+		// Allocate the array memory, by control point or by polygon vertex.
+		VertexElemIter<Vector3> positions = meshData->getVec3DataIter(VES_POSITION);
+
+		VertexElemIter<Color> colors;
+		if(hasColor)
+			colors = meshData->getColorDataIter(VES_COLOR);
+
+		VertexElemIter<Vector3> normals;
+		if (hasNormal)
+			normals = meshData->getVec3DataIter(VES_NORMAL);
+
+		VertexElemIter<Vector3> tangents;
+		if (hasTangent)
+			tangents = meshData->getVec3DataIter(VES_TANGENT);
+
+		VertexElemIter<Vector3> bitangents;
+		if (hasBitangent)
+			bitangents = meshData->getVec3DataIter(VES_BITANGENT);
+
+		VertexElemIter<Vector2> uv0;
+		if (hasUV0 && lUVNames.GetCount() > 0)
+		{
+			uv0 = meshData->getVec2DataIter(VES_TEXCOORD, 0);
+			lUVName0 = lUVNames[0];
+		}
+
+		VertexElemIter<Vector2> uv1;
+		if (hasUV1 && lUVNames.GetCount() > 1)
+		{
+			uv1 = meshData->getVec2DataIter(VES_TEXCOORD, 1);
 			lUVName1 = lUVNames[1];
 		}
 
@@ -404,9 +434,13 @@ namespace CamelotFramework
 			{
 				// Save the vertex position.
 				lCurrentVertex = lControlPoints[lIndex];
-				vertex[lIndex][0] = static_cast<float>(lCurrentVertex[0]);
-				vertex[lIndex][1] = static_cast<float>(lCurrentVertex[1]);
-				vertex[lIndex][2] = static_cast<float>(lCurrentVertex[2]);
+
+				Vector3 curPosValue;
+				curPosValue[0] = static_cast<float>(lCurrentVertex[0]);
+				curPosValue[1] = static_cast<float>(lCurrentVertex[1]);
+				curPosValue[2] = static_cast<float>(lCurrentVertex[2]);
+
+				positions.addValue(curPosValue);
 
 				// Save vertex color
 				if(hasColor)
@@ -416,10 +450,14 @@ namespace CamelotFramework
 						lColorIndex = lColorElement->GetIndexArray().GetAt(lIndex);
 
 					FbxColor lCurrentColor = lColorElement->GetDirectArray().GetAt(lColorIndex);
-					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]);
+
+					Color curColorValue;
+					curColorValue[0] = static_cast<float>(lCurrentColor[0]);
+					curColorValue[1] = static_cast<float>(lCurrentColor[1]);
+					curColorValue[2] = static_cast<float>(lCurrentColor[2]);
+					curColorValue[3] = static_cast<float>(lCurrentColor[3]);
+
+					colors.addValue(curColorValue);
 				}
 
 				// Save the normal.
@@ -430,9 +468,13 @@ namespace CamelotFramework
 						lNormalIndex = lNormalElement->GetIndexArray().GetAt(lIndex);
 
 					lCurrentNormal = lNormalElement->GetDirectArray().GetAt(lNormalIndex);
-					normal[lIndex][0] = static_cast<float>(lCurrentNormal[0]);
-					normal[lIndex][1] = static_cast<float>(lCurrentNormal[1]);
-					normal[lIndex][2] = static_cast<float>(lCurrentNormal[2]);
+
+					Vector3 curNormalValue;
+					curNormalValue[0] = static_cast<float>(lCurrentNormal[0]);
+					curNormalValue[1] = static_cast<float>(lCurrentNormal[1]);
+					curNormalValue[2] = static_cast<float>(lCurrentNormal[2]);
+
+					normals.addValue(curNormalValue);
 				}
 
 				// Save the tangent.
@@ -443,9 +485,13 @@ namespace CamelotFramework
 						lTangentIndex = lTangentElement->GetIndexArray().GetAt(lIndex);
 
 					FbxVector4 lCurrentTangent = lTangentElement->GetDirectArray().GetAt(lTangentIndex);
-					tangent[lIndex][0] = static_cast<float>(lCurrentTangent[0]);
-					tangent[lIndex][1] = static_cast<float>(lCurrentTangent[1]);
-					tangent[lIndex][2] = static_cast<float>(lCurrentTangent[2]);
+
+					Vector3 curTangentValue;
+					curTangentValue[0] = static_cast<float>(lCurrentTangent[0]);
+					curTangentValue[1] = static_cast<float>(lCurrentTangent[1]);
+					curTangentValue[2] = static_cast<float>(lCurrentTangent[2]);
+
+					tangents.addValue(curTangentValue);
 				}
 
 				// Save the bitangent.
@@ -456,9 +502,13 @@ namespace CamelotFramework
 						lBitangentIndex = lBitangentElement->GetIndexArray().GetAt(lIndex);
 
 					FbxVector4 lCurrentBitangent = lBitangentElement->GetDirectArray().GetAt(lBitangentIndex);
-					bitangent[lIndex][0] = static_cast<float>(lCurrentBitangent[0]);
-					bitangent[lIndex][1] = static_cast<float>(lCurrentBitangent[1]);
-					bitangent[lIndex][2] = static_cast<float>(lCurrentBitangent[2]);
+
+					Vector3 curBitangentValue;
+					curBitangentValue[0] = static_cast<float>(lCurrentBitangent[0]);
+					curBitangentValue[1] = static_cast<float>(lCurrentBitangent[1]);
+					curBitangentValue[2] = static_cast<float>(lCurrentBitangent[2]);
+
+					bitangents.addValue(curBitangentValue);
 				}
 
 				// Save the UV.
@@ -469,8 +519,12 @@ namespace CamelotFramework
 						lUVIndex = lUVElement0->GetIndexArray().GetAt(lIndex);
 
 					lCurrentUV = lUVElement0->GetDirectArray().GetAt(lUVIndex);
-					uv0[lIndex][0] = static_cast<float>(lCurrentUV[0]);
-					uv0[lIndex][1] = static_cast<float>(lCurrentUV[1]);
+
+					Vector2 curUV0Value;
+					curUV0Value[0] = static_cast<float>(lCurrentUV[0]);
+					curUV0Value[1] = static_cast<float>(lCurrentUV[1]);
+
+					uv0.addValue(curUV0Value);
 				}
 
 				if (hasUV1)
@@ -480,16 +534,28 @@ namespace CamelotFramework
 						lUVIndex = lUVElement1->GetIndexArray().GetAt(lIndex);
 
 					lCurrentUV = lUVElement1->GetDirectArray().GetAt(lUVIndex);
-					uv1[lIndex][0] = static_cast<float>(lCurrentUV[0]);
-					uv1[lIndex][1] = static_cast<float>(lCurrentUV[1]);
+
+					Vector2 curUV1Value;
+					curUV1Value[0] = static_cast<float>(lCurrentUV[0]);
+					curUV1Value[1] = static_cast<float>(lCurrentUV[1]);
+
+					uv1.addValue(curUV1Value);
 				}
 			}
 		}
 
-		int lVertexCount = 0;
 		vector<UINT32>::type indexOffsetPerSubmesh;
 		indexOffsetPerSubmesh.resize(subMeshes.size(), 0);
 
+		vector<UINT32*>::type indices;
+		indices.resize(subMeshes.size());
+
+		for(UINT32 i = 0; i < (UINT32)indices.size(); i++)
+		{
+			indices[i] = meshData->getIndices32(i);
+		}
+
+		UINT32 lVertexCount = 0;
 		for (int lPolygonIndex = 0; lPolygonIndex < lPolygonCount; ++lPolygonIndex)
 		{
 			// The material for current face.
@@ -515,9 +581,13 @@ namespace CamelotFramework
 					indices[lMaterialIndex][lIndexOffset + lVerticeIndex] = static_cast<unsigned int>(lVertexCount);
 
 					lCurrentVertex = lControlPoints[lControlPointIndex];
-					vertex[lVertexCount][0] = static_cast<float>(lCurrentVertex[0]);
-					vertex[lVertexCount][1] = static_cast<float>(lCurrentVertex[1]);
-					vertex[lVertexCount][2] = static_cast<float>(lCurrentVertex[2]);
+
+					Vector3 curPosValue;
+					curPosValue[0] = static_cast<float>(lCurrentVertex[0]);
+					curPosValue[1] = static_cast<float>(lCurrentVertex[1]);
+					curPosValue[2] = static_cast<float>(lCurrentVertex[2]);
+
+					positions.addValue(curPosValue);
 
 					if(hasColor)
 					{
@@ -526,18 +596,26 @@ namespace CamelotFramework
 							lColorIndex = lColorElement->GetIndexArray().GetAt(lColorIndex);
 
 						FbxColor lCurrentColor = lColorElement->GetDirectArray().GetAt(lColorIndex);
-						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]);
+
+						Color curColorValue;
+						curColorValue[0] = static_cast<float>(lCurrentColor[0]);
+						curColorValue[1] = static_cast<float>(lCurrentColor[1]);
+						curColorValue[2] = static_cast<float>(lCurrentColor[2]);
+						curColorValue[3] = static_cast<float>(lCurrentColor[3]);
+
+						colors.addValue(curColorValue);
 					}
 
 					if (hasNormal)
 					{
 						mesh->GetPolygonVertexNormal(lPolygonIndex, lVerticeIndex, lCurrentNormal);
-						normal[lVertexCount][0] = static_cast<float>(lCurrentNormal[0]);
-						normal[lVertexCount][1] = static_cast<float>(lCurrentNormal[1]);
-						normal[lVertexCount][2] = static_cast<float>(lCurrentNormal[2]);
+
+						Vector3 curNormalValue;
+						curNormalValue[0] = static_cast<float>(lCurrentNormal[0]);
+						curNormalValue[1] = static_cast<float>(lCurrentNormal[1]);
+						curNormalValue[2] = static_cast<float>(lCurrentNormal[2]);
+
+						normals.addValue(curNormalValue);
 					}
 
 					if (hasTangent)
@@ -547,9 +625,13 @@ namespace CamelotFramework
 							lTangentIndex = lTangentElement->GetIndexArray().GetAt(lTangentIndex);
 
 						FbxVector4 lCurrentTangent = lTangentElement->GetDirectArray().GetAt(lTangentIndex);
-						tangent[lVertexCount][0] = static_cast<float>(lCurrentTangent[0]);
-						tangent[lVertexCount][1] = static_cast<float>(lCurrentTangent[1]);
-						tangent[lVertexCount][2] = static_cast<float>(lCurrentTangent[2]);
+
+						Vector3 curTangentValue;
+						curTangentValue[0] = static_cast<float>(lCurrentTangent[0]);
+						curTangentValue[1] = static_cast<float>(lCurrentTangent[1]);
+						curTangentValue[2] = static_cast<float>(lCurrentTangent[2]);
+
+						tangents.addValue(curTangentValue);
 					}
 
 					if (hasBitangent)
@@ -559,25 +641,38 @@ namespace CamelotFramework
 							lBitangentIndex = lBitangentElement->GetIndexArray().GetAt(lBitangentIndex);
 
 						FbxVector4 lCurrentBitangent = lBitangentElement->GetDirectArray().GetAt(lBitangentIndex);
-						bitangent[lVertexCount][0] = static_cast<float>(lCurrentBitangent[0]);
-						bitangent[lVertexCount][1] = static_cast<float>(lCurrentBitangent[1]);
-						bitangent[lVertexCount][2] = static_cast<float>(lCurrentBitangent[2]);
+
+						Vector3 curBitangentValue;
+						curBitangentValue[0] = static_cast<float>(lCurrentBitangent[0]);
+						curBitangentValue[1] = static_cast<float>(lCurrentBitangent[1]);
+						curBitangentValue[2] = static_cast<float>(lCurrentBitangent[2]);
+
+						bitangents.addValue(curBitangentValue);
 					}
 
 					if (hasUV0)
 					{
 						mesh->GetPolygonVertexUV(lPolygonIndex, lVerticeIndex, lUVName0, lCurrentUV);
-						uv0[lVertexCount][0] = static_cast<float>(lCurrentUV[0]);
-						uv0[lVertexCount][1] = static_cast<float>(lCurrentUV[1]);
+
+						Vector2 curUV0Value;
+						curUV0Value[0] = static_cast<float>(lCurrentUV[0]);
+						curUV0Value[1] = static_cast<float>(lCurrentUV[1]);
+
+						uv0.addValue(curUV0Value);
 					}
 
 					if (hasUV1)
 					{
 						mesh->GetPolygonVertexUV(lPolygonIndex, lVerticeIndex, lUVName1, lCurrentUV);
-						uv1[lVertexCount][0] = static_cast<float>(lCurrentUV[0]);
-						uv1[lVertexCount][1] = static_cast<float>(lCurrentUV[1]);
+
+						Vector2 curUV1Value;
+						curUV1Value[0] = static_cast<float>(lCurrentUV[0]);
+						curUV1Value[1] = static_cast<float>(lCurrentUV[1]);
+
+						uv1.addValue(curUV1Value);
 					}
 				}
+
 				++lVertexCount;
 			}
 

+ 2 - 2
CamelotGLRenderer/Source/CmGLRenderSystem.cpp

@@ -1610,7 +1610,7 @@ namespace CamelotFramework
 
 		for (elem = decl.begin(); elem != elemEnd; ++elem)
 		{
-			auto iterFind = mBoundVertexBuffers.find(elem->getSource());
+			auto iterFind = mBoundVertexBuffers.find(elem->getStreamIdx());
 
 			if(iterFind == mBoundVertexBuffers.end() || iterFind->second == nullptr)
 				continue; // skip unbound elements
@@ -1621,7 +1621,7 @@ namespace CamelotFramework
 			GLint attribLocation = 0;
 			for(auto iter = inputAttributes.begin(); iter != inputAttributes.end(); ++iter)
 			{
-				if(iter->getSemantic() == elem->getSemantic() && iter->getIndex() == elem->getIndex())
+				if(iter->getSemantic() == elem->getSemantic() && iter->getSemanticIdx() == elem->getSemanticIdx())
 				{
 					foundSemantic = true;
 					attribLocation = iter->getOffset();

+ 3 - 1
TODO.txt

@@ -17,7 +17,9 @@ RenderSystem does syncing external to CommandQueue
 
 MeshData needs to be ported to GpuResourceData format
  - I don't want to give up the current MeshData interface as it's easy to use. Anything lower level and I might just be using vertex/index buffers directly
-
+ - PixelDataRTTI needs to be modified so it allocates buffer on deserialization end
+   - not possible though
+   - keep both versions for now. Later maybe create GpuResourceDataRTTI where it can only use custom-size method when deserializing
 --------
 
  - My test model is rendering back faces. I need to flip them.