Browse Source

Better sub-mesh handling for Meshes

Marko Pintera 12 years ago
parent
commit
9392e45805

+ 4 - 4
BansheeEngine/Source/BsDrawHelper2D.cpp

@@ -126,7 +126,7 @@ namespace BansheeEngine
 		DebugDrawCommand& dbgCmd = commands.back();
 		DebugDrawCommand& dbgCmd = commands.back();
 		dbgCmd.endTime = gTime().getTime() + timeout;
 		dbgCmd.endTime = gTime().getTime() + timeout;
 
 
-		MeshDataPtr meshData = cm_shared_ptr<MeshData, ScratchAlloc>(2, 2, mVertexDesc, DOT_LINE_LIST);
+		MeshDataPtr meshData = cm_shared_ptr<MeshData, ScratchAlloc>(2, 2, mVertexDesc);
 
 
 		Vector2 actualA = a;
 		Vector2 actualA = a;
 		Vector2 actualB = b;
 		Vector2 actualB = b;
@@ -138,7 +138,7 @@ namespace BansheeEngine
 
 
 		line_Pixel(actualA, actualB, color, meshData, 0, 0);
 		line_Pixel(actualA, actualB, color, meshData, 0, 0);
 
 
-		HMesh mesh = Mesh::create(meshData);
+		HMesh mesh = Mesh::create(meshData, MeshBufferType::Static, DOT_LINE_LIST);
 
 
 		dbgCmd.mesh = mesh;
 		dbgCmd.mesh = mesh;
 		dbgCmd.worldCenter = Vector3::ZERO;
 		dbgCmd.worldCenter = Vector3::ZERO;
@@ -206,7 +206,7 @@ namespace BansheeEngine
 		dbgCmd.endTime = gTime().getTime() + timeout;
 		dbgCmd.endTime = gTime().getTime() + timeout;
 
 
 		MeshDataPtr meshData = cm_shared_ptr<MeshData, ScratchAlloc>(
 		MeshDataPtr meshData = cm_shared_ptr<MeshData, ScratchAlloc>(
-			(UINT32)(linePoints.size() * 2), (UINT32)(linePoints.size() * 2), mVertexDesc, DOT_LINE_LIST);
+			(UINT32)(linePoints.size() * 2), (UINT32)(linePoints.size() * 2), mVertexDesc);
 
 
 		if(coordType == DebugDrawCoordType::Normalized)
 		if(coordType == DebugDrawCoordType::Normalized)
 		{
 		{
@@ -222,7 +222,7 @@ namespace BansheeEngine
 			lineList_Pixel(linePoints, color, meshData, 0, 0);
 			lineList_Pixel(linePoints, color, meshData, 0, 0);
 		}		
 		}		
 
 
-		HMesh mesh = Mesh::create(meshData);
+		HMesh mesh = Mesh::create(meshData, MeshBufferType::Static, DOT_LINE_LIST);
 
 
 		dbgCmd.mesh = mesh;
 		dbgCmd.mesh = mesh;
 		dbgCmd.worldCenter = Vector3::ZERO;
 		dbgCmd.worldCenter = Vector3::ZERO;

+ 5 - 4
BansheeEngine/Source/BsDrawHelper3D.cpp

@@ -68,14 +68,14 @@ namespace BansheeEngine
 		DebugDrawCommand& dbgCmd = commands.back();
 		DebugDrawCommand& dbgCmd = commands.back();
 		dbgCmd.endTime = gTime().getTime() + timeout;
 		dbgCmd.endTime = gTime().getTime() + timeout;
 
 
-		MeshDataPtr meshData = cm_shared_ptr<MeshData, ScratchAlloc>(2, 2, mVertexDesc, DOT_LINE_LIST);
+		MeshDataPtr meshData = cm_shared_ptr<MeshData, ScratchAlloc>(2, 2, mVertexDesc);
 
 
 		line_Pixel(a, b, color, meshData, 0, 0);
 		line_Pixel(a, b, color, meshData, 0, 0);
 
 
 		UINT8* positionData = meshData->getElementData(VES_POSITION);
 		UINT8* positionData = meshData->getElementData(VES_POSITION);
 		dbgCmd.worldCenter = calcCenter(positionData, meshData->getNumVertices(), mVertexDesc->getVertexStride());
 		dbgCmd.worldCenter = calcCenter(positionData, meshData->getNumVertices(), mVertexDesc->getVertexStride());
 
 
-		HMesh mesh = Mesh::create(meshData);
+		HMesh mesh = Mesh::create(meshData, MeshBufferType::Static, DOT_LINE_LIST);
 
 
 		dbgCmd.mesh = mesh;
 		dbgCmd.mesh = mesh;
 		dbgCmd.type = DebugDrawType::WorldSpace;
 		dbgCmd.type = DebugDrawType::WorldSpace;
@@ -116,14 +116,15 @@ namespace BansheeEngine
 		DebugDrawCommand& dbgCmd = commands.back();
 		DebugDrawCommand& dbgCmd = commands.back();
 		dbgCmd.endTime = gTime().getTime() + timeout;
 		dbgCmd.endTime = gTime().getTime() + timeout;
 
 
-		MeshDataPtr meshData = cm_shared_ptr<MeshData, ScratchAlloc>((UINT32)(linePoints.size() * 2), (UINT32)(linePoints.size() * 2), mVertexDesc, DOT_LINE_LIST);
+		MeshDataPtr meshData = cm_shared_ptr<MeshData, ScratchAlloc>(
+			(UINT32)(linePoints.size() * 2), (UINT32)(linePoints.size() * 2), mVertexDesc);
 
 
 		lineList_Pixel(linePoints, color, meshData, 0, 0);
 		lineList_Pixel(linePoints, color, meshData, 0, 0);
 
 
 		UINT8* positionData = meshData->getElementData(VES_POSITION);
 		UINT8* positionData = meshData->getElementData(VES_POSITION);
 		dbgCmd.worldCenter = calcCenter(positionData, meshData->getNumVertices(), mVertexDesc->getVertexStride());
 		dbgCmd.worldCenter = calcCenter(positionData, meshData->getNumVertices(), mVertexDesc->getVertexStride());
 
 
-		HMesh mesh = Mesh::create(meshData);
+		HMesh mesh = Mesh::create(meshData, MeshBufferType::Static, DOT_LINE_LIST);
 
 
 		dbgCmd.mesh = mesh;
 		dbgCmd.mesh = mesh;
 		dbgCmd.type = DebugDrawType::WorldSpace;
 		dbgCmd.type = DebugDrawType::WorldSpace;

+ 6 - 0
BansheeEngine/Source/BsGUIManager.cpp

@@ -516,6 +516,9 @@ namespace BansheeEngine
 
 
 					renderData.cachedMeshes.push_back(Mesh::create(bufferNumQuads * 4, bufferNumQuads * 6, mVertexDesc, meshData, MeshBufferType::Dynamic));
 					renderData.cachedMeshes.push_back(Mesh::create(bufferNumQuads * 4, bufferNumQuads * 6, mVertexDesc, meshData, MeshBufferType::Dynamic));
 					renderData.meshBufferSizes.push_back(bufferNumQuads);
 					renderData.meshBufferSizes.push_back(bufferNumQuads);
+
+					renderData.cachedMeshes.back()->clearSubMeshes();
+					renderData.cachedMeshes.back()->addSubMesh(0, group->numQuads * 6);
 				}
 				}
 				else
 				else
 				{
 				{
@@ -529,6 +532,9 @@ namespace BansheeEngine
 					}
 					}
 
 
 					gMainCA().writeSubresource(renderData.cachedMeshes[groupIdx].getInternalPtr(), 0, meshData, true);
 					gMainCA().writeSubresource(renderData.cachedMeshes[groupIdx].getInternalPtr(), 0, meshData, true);
+
+					renderData.cachedMeshes[groupIdx]->clearSubMeshes();
+					renderData.cachedMeshes[groupIdx]->addSubMesh(0, group->numQuads * 6);
 				}
 				}
 
 
 				groupIdx++;
 				groupIdx++;

+ 2 - 1
BansheeForwardRenderer/Source/BsForwardRenderer.cpp

@@ -199,7 +199,8 @@ namespace BansheeEngine
 			gProfiler().endSample("renderH");
 			gProfiler().endSample("renderH");
 			gProfiler().beginSample("renderI");
 			gProfiler().beginSample("renderI");
 
 
-			coreAccessor.render(renderOp.mesh.getInternalPtr(), renderOp.submeshIdx);
+			const SubMesh& subMesh = renderOp.mesh->getSubMesh(renderOp.submeshIdx);
+			coreAccessor.render(renderOp.mesh.getInternalPtr(), subMesh.indexOffset, subMesh.indexCount, true, subMesh.drawOp);
 
 
 			gProfiler().endSample("renderI");
 			gProfiler().endSample("renderI");
 		}
 		}

+ 1 - 0
CamelotCore/CamelotCore.vcxproj

@@ -341,6 +341,7 @@
     <ClInclude Include="Include\CmOcclusionQuery.h" />
     <ClInclude Include="Include\CmOcclusionQuery.h" />
     <ClInclude Include="Include\CmPixelBuffer.h" />
     <ClInclude Include="Include\CmPixelBuffer.h" />
     <ClInclude Include="Include\CmGpuProgIncludeImporter.h" />
     <ClInclude Include="Include\CmGpuProgIncludeImporter.h" />
+    <ClInclude Include="Include\CmSubMesh.h" />
     <ClInclude Include="Include\CmTextureView.h" />
     <ClInclude Include="Include\CmTextureView.h" />
     <ClInclude Include="Include\CmTextData.h" />
     <ClInclude Include="Include\CmTextData.h" />
     <ClInclude Include="Include\CmVertexBuffer.h" />
     <ClInclude Include="Include\CmVertexBuffer.h" />

+ 3 - 0
CamelotCore/CamelotCore.vcxproj.filters

@@ -498,6 +498,9 @@
     <ClInclude Include="Include\CmVertexDataDescRTTI.h">
     <ClInclude Include="Include\CmVertexDataDescRTTI.h">
       <Filter>Header Files\RTTI</Filter>
       <Filter>Header Files\RTTI</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\CmSubMesh.h">
+      <Filter>Header Files\RenderSystem</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CmApplication.cpp">
     <ClCompile Include="Source\CmApplication.cpp">

+ 7 - 0
CamelotCore/Include/CmCoreThread.h

@@ -133,9 +133,16 @@ private:
 		*/
 		*/
 	CM_EXPORT void throwIfNotCoreThread();
 	CM_EXPORT void throwIfNotCoreThread();
 
 
+	/**
+		* @brief	Throws an exception if current thread is the core thread;
+		*/
+	CM_EXPORT void throwIfCoreThread();
+
 #if CM_DEBUG_MODE
 #if CM_DEBUG_MODE
 #define THROW_IF_NOT_CORE_THREAD throwIfNotCoreThread();
 #define THROW_IF_NOT_CORE_THREAD throwIfNotCoreThread();
+#define THROW_IF_CORE_THREAD throwIfCoreThread();
 #else
 #else
 #define THROW_IF_NOT_CORE_THREAD 
 #define THROW_IF_NOT_CORE_THREAD 
+#define THROW_IF_CORE_THREAD
 #endif
 #endif
 }
 }

+ 2 - 2
CamelotCore/Include/CmCoreThreadAccessor.h

@@ -180,9 +180,9 @@ namespace CamelotFramework
 
 
 
 
 		/** @copydoc RenderSystem::render() */
 		/** @copydoc RenderSystem::render() */
-		void render(const MeshPtr& mesh, UINT32 submeshIdx)
+		void render(const MeshPtr& mesh, UINT32 indexOffset = 0, UINT32 indexCount = 0, bool useIndices = true, DrawOperationType drawOp = DOT_TRIANGLE_LIST)
 		{
 		{
-			mCommandQueue->queue(boost::bind(&RenderSystem::render, RenderSystem::instancePtr(), mesh, submeshIdx));
+			mCommandQueue->queue(boost::bind(&RenderSystem::render, RenderSystem::instancePtr(), mesh, indexOffset, indexCount, useIndices, drawOp));
 		}
 		}
 
 
 		/** @copydoc RenderSystem::draw() */
 		/** @copydoc RenderSystem::draw() */

+ 62 - 40
CamelotCore/Include/CmMesh.h

@@ -6,6 +6,7 @@
 #include "CmVertexData.h"
 #include "CmVertexData.h"
 #include "CmIndexData.h"
 #include "CmIndexData.h"
 #include "CmDrawOps.h"
 #include "CmDrawOps.h"
+#include "CmSubMesh.h"
 
 
 namespace CamelotFramework
 namespace CamelotFramework
 {
 {
@@ -15,29 +16,6 @@ namespace CamelotFramework
 		Dynamic
 		Dynamic
 	};
 	};
 
 
-	struct CM_EXPORT SubMesh
-	{
-		SubMesh()
-			: indexOffset(0), indexCount(0), drawOp(DOT_TRIANGLE_LIST), 
-			vertexData(nullptr), indexData(nullptr), useIndexes(true)
-		{ }
-
-		SubMesh(UINT32 indexOffset, UINT32 indexCount, DrawOperationType drawOp, 
-			std::shared_ptr<VertexData> vertexData, std::shared_ptr<IndexData> indexData, bool useIndexes):
-			indexOffset(indexOffset), indexCount(indexCount), drawOp(drawOp),
-			vertexData(vertexData), indexData(indexData), useIndexes(useIndexes)
-		{ }
-
-		UINT32 indexOffset;
-		UINT32 indexCount;
-		DrawOperationType drawOp;
-
-		std::shared_ptr<VertexData> vertexData;
-		std::shared_ptr<IndexData> indexData;
-
-		bool useIndexes;
-	};
-
 	class CM_EXPORT Mesh : public GpuResource
 	class CM_EXPORT Mesh : public GpuResource
 	{
 	{
 	public:
 	public:
@@ -73,12 +51,50 @@ namespace CamelotFramework
 		 */
 		 */
 		UINT32 mapToSubresourceIdx() const { return 0; }
 		UINT32 mapToSubresourceIdx() const { return 0; }
 
 
+		void clearSubMeshes();
+
+		void addSubMesh(UINT32 indexOffset, UINT32 indexCount, DrawOperationType drawOp = DOT_TRIANGLE_LIST);
+
+		/**
+		 * @brief	Sets a set of sub-meshes containing data used for rendering a 
+		 * 			certain portion of this mesh. Overwrites any previous sub-meshes.
+		 * 			
+		 * @note	Sim thread only.
+		 */
+		void setSubMeshes(const Vector<SubMesh>::type& subMeshes);
+
+		/**
+		 * @brief	Retrieves a sub-mesh containing data used for rendering a
+		 * 			certain portion of this mesh.
+		 * 			
+		 * @note	Sim thread only.
+		 */
 		const SubMesh& getSubMesh(UINT32 subMeshIdx = 0) const;
 		const SubMesh& getSubMesh(UINT32 subMeshIdx = 0) const;
-		UINT32 getNumSubMeshes() const { return mNumSubMeshes.load(); }
+
+		/**
+		 * @brief	Retrieves a total number of sub-meshes in this mesh.
+		 * 			
+		 * @note	Sim thread only.
+		 */
+		UINT32 getNumSubMeshes() const;
 
 
 		const AABox& getBounds() const;
 		const AABox& getBounds() const;
 		const AABox& getBounds(UINT32 submeshIdx) const;
 		const AABox& getBounds(UINT32 submeshIdx) const;
 
 
+		/**
+		 * @brief	Get vertex data used for rendering.
+		 *  
+		 * @note	Core thread only.
+		 */
+		std::shared_ptr<VertexData> getVertexData() const;
+
+		/**
+		 * @brief	Get index data used for rendering.
+		 *  
+		 * @note	Core thread only.
+		 */
+		std::shared_ptr<IndexData> getIndexData() const;
+
 		/**
 		/**
 		 * @brief	Returns a dummy mesh, containing just one triangle. Don't modify the returned mesh.
 		 * @brief	Returns a dummy mesh, containing just one triangle. Don't modify the returned mesh.
 		 */
 		 */
@@ -88,26 +104,29 @@ namespace CamelotFramework
 		friend class MeshManager;
 		friend class MeshManager;
 
 
 		Mesh(UINT32 numVertices, UINT32 numIndices, 
 		Mesh(UINT32 numVertices, UINT32 numIndices, 
-			const VertexDataDescPtr& vertexDesc, MeshBufferType bufferType = MeshBufferType::Static, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
+			const VertexDataDescPtr& vertexDesc, MeshBufferType bufferType = MeshBufferType::Static, 
+			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 
 
 		Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, const MeshDataPtr& initialMeshData, 
 		Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, const MeshDataPtr& initialMeshData, 
-			MeshBufferType bufferType = MeshBufferType::Static, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
+			MeshBufferType bufferType = MeshBufferType::Static, DrawOperationType drawOp = DOT_TRIANGLE_LIST, 
+			IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 
 
-		Mesh(const MeshDataPtr& initialMeshData, MeshBufferType bufferType = MeshBufferType::Static);
+		Mesh(const MeshDataPtr& initialMeshData, 
+			MeshBufferType bufferType = MeshBufferType::Static, DrawOperationType drawOp = DOT_TRIANGLE_LIST);
 
 
-		std::shared_ptr<VertexData> mVertexData;
-		std::shared_ptr<IndexData> mIndexData;
+		std::shared_ptr<VertexData> mVertexData; // Core thread
+		std::shared_ptr<IndexData> mIndexData; // Core thread
 
 
-		Vector<SubMesh>::type mSubMeshes;
-		std::atomic<UINT32> mNumSubMeshes;
+		Vector<SubMesh>::type mSubMeshes; // Sim thread
+		SubMesh mDefaultSubMesh; // Immutable
 
 
-		UINT32 mNumVertices;
-		UINT32 mNumIndices;
-		VertexDataDescPtr mVertexDesc;
-		MeshBufferType mBufferType;
-		IndexBuffer::IndexType mIndexType;
+		UINT32 mNumVertices; // Immutable
+		UINT32 mNumIndices; // Immutable
+		VertexDataDescPtr mVertexDesc; // Immutable
+		MeshBufferType mBufferType; // Immutable
+		IndexBuffer::IndexType mIndexType; // Immutable
 
 
-		MeshDataPtr mTempInitialMeshData;
+		MeshDataPtr mTempInitialMeshData; // Immutable
 
 
 		/**
 		/**
 		 * @copydoc Resource::initialize_internal()
 		 * @copydoc Resource::initialize_internal()
@@ -136,11 +155,14 @@ namespace CamelotFramework
 		
 		
 	public:
 	public:
 		static HMesh create(UINT32 numVertices, UINT32 numIndices, 
 		static HMesh create(UINT32 numVertices, UINT32 numIndices, 
-			const VertexDataDescPtr& vertexDesc, MeshBufferType bufferType = MeshBufferType::Static, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
+			const VertexDataDescPtr& vertexDesc, MeshBufferType bufferType = MeshBufferType::Static, 
+			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 
 
 		static HMesh create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, const MeshDataPtr& initialMeshData, 
 		static HMesh create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, const MeshDataPtr& initialMeshData, 
-			MeshBufferType bufferType = MeshBufferType::Static, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
+			MeshBufferType bufferType = MeshBufferType::Static, DrawOperationType drawOp = DOT_TRIANGLE_LIST, 
+			IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 
 
-		static HMesh create(const MeshDataPtr& initialMeshData, MeshBufferType bufferType = MeshBufferType::Static);
+		static HMesh create(const MeshDataPtr& initialMeshData, MeshBufferType bufferType = MeshBufferType::Static, 
+			DrawOperationType drawOp = DOT_TRIANGLE_LIST);
 	};
 	};
 }
 }

+ 7 - 36
CamelotCore/Include/CmMeshData.h

@@ -6,6 +6,7 @@
 #include "CmIndexBuffer.h"
 #include "CmIndexBuffer.h"
 #include "CmVertexDeclaration.h"
 #include "CmVertexDeclaration.h"
 #include "CmDrawOps.h"
 #include "CmDrawOps.h"
+#include "CmSubMesh.h"
 
 
 namespace CamelotFramework
 namespace CamelotFramework
 {
 {
@@ -65,19 +66,7 @@ namespace CamelotFramework
 	class CM_EXPORT MeshData : public GpuResourceData
 	class CM_EXPORT MeshData : public GpuResourceData
 	{
 	{
 	public:
 	public:
-		struct IndexElementData
-		{
-			IndexElementData()
-				:numIndices(0), subMesh(0), elementSize(0), drawOp(DOT_TRIANGLE_LIST)
-			{ }
-
-			UINT32 numIndices;
-			UINT32 elementSize;
-			UINT32 subMesh;
-			DrawOperationType drawOp;
-		};
-
-		MeshData(UINT32 numVertices, UINT32 numIndexes, const VertexDataDescPtr& vertexData, DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
+		MeshData(UINT32 numVertices, UINT32 numIndexes, const VertexDataDescPtr& vertexData, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 		~MeshData();
 		~MeshData();
 
 
 		/**
 		/**
@@ -109,19 +98,6 @@ namespace CamelotFramework
 		 */
 		 */
 		UINT32 getResourceIndexOffset() const { return mResourceIndexOffset; }
 		UINT32 getResourceIndexOffset() const { return mResourceIndexOffset; }
 
 
-		/**
-		 * @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. 
-		 *
-		 * @param	numIndices	Number of indices.
-		 * @param	subMesh   	(optional) Index of the sub-mesh to add/update.
-		 * @param	drawOp	  	(optional) Specifies the primitive type contained by the mesh.
-		 * 						
-		 * @note	When updating a Mesh with MeshData, even if just a portion of it,
-		 * 			all sub-mesh information will be replaced with the one from MeshData.
-		 */
-		void addSubMesh(UINT32 numIndices, UINT32 subMesh = 0, DrawOperationType drawOp = DOT_TRIANGLE_LIST);
-
 		/**
 		/**
 		 * @brief	Copies data from "data" parameter into the internal buffer for the specified semantic.
 		 * @brief	Copies data from "data" parameter into the internal buffer for the specified semantic.
 		 *
 		 *
@@ -165,15 +141,11 @@ namespace CamelotFramework
 		 */
 		 */
 		VertexElemIter<UINT32> getDWORDDataIter(VertexElementSemantic semantic, UINT32 semanticIdx = 0, UINT32 streamIdx = 0);
 		VertexElemIter<UINT32> getDWORDDataIter(VertexElementSemantic semantic, UINT32 semanticIdx = 0, UINT32 streamIdx = 0);
 
 
-		UINT32 getNumSubmeshes() const { return (UINT32)mSubMeshes.size(); }
 		UINT32 getNumVertices() const { return mNumVertices; }
 		UINT32 getNumVertices() const { return mNumVertices; }
-		UINT32 getNumIndices(UINT32 subMesh) const;
 		UINT32 getNumIndices() const;
 		UINT32 getNumIndices() const;
-		DrawOperationType getDrawOp(UINT32 subMesh) const;
-		DrawOperationType getDrawOp() const;
 
 
-		UINT16* getIndices16(UINT32 subMesh = 0) const;
-		UINT32* getIndices32(UINT32 subMesh = 0) const;
+		UINT16* getIndices16() const;
+		UINT32* getIndices32() const;
 		UINT32 getIndexElementSize() const;
 		UINT32 getIndexElementSize() const;
 		IndexBuffer::IndexType getIndexType() const { return mIndexType; }
 		IndexBuffer::IndexType getIndexType() const { return mIndexType; }
 
 
@@ -193,7 +165,8 @@ namespace CamelotFramework
 
 
 		const VertexDataDescPtr& getVertexDesc() const { return mVertexData; }
 		const VertexDataDescPtr& getVertexDesc() const { return mVertexData; }
 
 
-		static MeshDataPtr combine(const Vector<MeshDataPtr>::type& elements);
+		static MeshDataPtr combine(const Vector<MeshDataPtr>::type& elements, const Vector<Vector<SubMesh>::type>::type& allSubMeshes,
+			Vector<SubMesh>::type& subMeshes);
 
 
 	protected:
 	protected:
 		UINT32 getInternalBufferSize();
 		UINT32 getInternalBufferSize();
@@ -210,16 +183,14 @@ namespace CamelotFramework
 
 
 		UINT32 mNumVertices;
 		UINT32 mNumVertices;
 		UINT32 mNumIndices;
 		UINT32 mNumIndices;
-		DrawOperationType mDrawOp;
 		IndexBuffer::IndexType mIndexType;
 		IndexBuffer::IndexType mIndexType;
 
 
-		Vector<IndexElementData>::type mSubMeshes;
 		VertexDataDescPtr mVertexData;
 		VertexDataDescPtr mVertexData;
 
 
 		UINT8* getIndexData() const { return getData(); }
 		UINT8* getIndexData() const { return getData(); }
 		UINT8* getStreamData(UINT32 streamIdx) const;
 		UINT8* getStreamData(UINT32 streamIdx) const;
 
 
-		UINT32 getIndexBufferOffset(UINT32 subMesh) const;
+		UINT32 getIndexBufferOffset() const;
 		UINT32 getStreamOffset(UINT32 streamIdx = 0) const;
 		UINT32 getStreamOffset(UINT32 streamIdx = 0) const;
 
 
 		UINT32 getIndexBufferSize() const;
 		UINT32 getIndexBufferSize() const;

+ 4 - 32
CamelotCore/Include/CmMeshDataRTTI.h

@@ -8,7 +8,6 @@
 
 
 namespace CamelotFramework
 namespace CamelotFramework
 {
 {
-	CM_ALLOW_MEMCPY_SERIALIZATION(MeshData::IndexElementData);
 	CM_ALLOW_MEMCPY_SERIALIZATION(IndexBuffer::IndexType);
 	CM_ALLOW_MEMCPY_SERIALIZATION(IndexBuffer::IndexType);
 
 
 	class CM_EXPORT MeshDataRTTI : public RTTIType<MeshData, GpuResourceData, MeshDataRTTI>
 	class CM_EXPORT MeshDataRTTI : public RTTIType<MeshData, GpuResourceData, MeshDataRTTI>
@@ -17,26 +16,6 @@ namespace CamelotFramework
 		VertexDataDescPtr getVertexData(MeshData* obj) { return obj->mVertexData; }
 		VertexDataDescPtr getVertexData(MeshData* obj) { return obj->mVertexData; }
 		void setVertexData(MeshData* obj, VertexDataDescPtr value) { obj->mVertexData = value; }
 		void setVertexData(MeshData* obj, VertexDataDescPtr value) { obj->mVertexData = value; }
 
 
-		MeshData::IndexElementData& getIndexElementData(MeshData* obj, UINT32 arrayIdx)
-		{
-			return obj->mSubMeshes[arrayIdx];
-		}
-
-		void setIndexElementData(MeshData* obj, UINT32 arrayIdx, MeshData::IndexElementData& value)
-		{
-			obj->mSubMeshes[arrayIdx] = value;
-		}
-
-		UINT32 getNumIndexElementData(MeshData* obj)
-		{
-			return (UINT32)obj->mSubMeshes.size();
-		}
-
-		void setNumIndexElementData(MeshData* obj, UINT32 numElements)
-		{
-			obj->mSubMeshes.resize(numElements);
-		}
-
 		IndexBuffer::IndexType& getIndexType(MeshData* obj) { return obj->mIndexType; }
 		IndexBuffer::IndexType& getIndexType(MeshData* obj) { return obj->mIndexType; }
 		void setIndexType(MeshData* obj, IndexBuffer::IndexType& value) { obj->mIndexType = value; }
 		void setIndexType(MeshData* obj, IndexBuffer::IndexType& value) { obj->mIndexType = value; }
 
 
@@ -46,9 +25,6 @@ namespace CamelotFramework
 		UINT32& getNumIndices(MeshData* obj) { return obj->mNumIndices; }
 		UINT32& getNumIndices(MeshData* obj) { return obj->mNumIndices; }
 		void setNumIndices(MeshData* obj, UINT32& value) { obj->mNumIndices = value; }
 		void setNumIndices(MeshData* obj, UINT32& value) { obj->mNumIndices = value; }
 
 
-		UINT32& getDrawOp(MeshData* obj) { return (UINT32&)obj->mDrawOp; }
-		void setDrawOp(MeshData* obj, UINT32& value) { obj->mDrawOp = (DrawOperationType)value; }
-
 		ManagedDataBlock getData(MeshData* obj) 
 		ManagedDataBlock getData(MeshData* obj) 
 		{ 
 		{ 
 			ManagedDataBlock dataBlock((UINT8*)obj->getData(), obj->getInternalBufferSize());
 			ManagedDataBlock dataBlock((UINT8*)obj->getData(), obj->getInternalBufferSize());
@@ -73,15 +49,11 @@ namespace CamelotFramework
 		{
 		{
 			addReflectablePtrField("mVertexData", 0, &MeshDataRTTI::getVertexData, &MeshDataRTTI::setVertexData);
 			addReflectablePtrField("mVertexData", 0, &MeshDataRTTI::getVertexData, &MeshDataRTTI::setVertexData);
 
 
-			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);
-			addPlainField("mNumIndices", 4, &MeshDataRTTI::getNumIndices, &MeshDataRTTI::setNumIndices);
-			addPlainField("mDrawOp", 5, &MeshDataRTTI::getDrawOp, &MeshDataRTTI::setDrawOp);
+			addPlainField("mIndexType", 1, &MeshDataRTTI::getIndexType, &MeshDataRTTI::setIndexType);
+			addPlainField("mNumVertices", 2, &MeshDataRTTI::getNumVertices, &MeshDataRTTI::setNumVertices);
+			addPlainField("mNumIndices", 3, &MeshDataRTTI::getNumIndices, &MeshDataRTTI::setNumIndices);
 
 
-			addDataBlockField("data", 6, &MeshDataRTTI::getData, &MeshDataRTTI::setData, 0, &MeshDataRTTI::allocateData);
+			addDataBlockField("data", 4, &MeshDataRTTI::getData, &MeshDataRTTI::setData, 0, &MeshDataRTTI::allocateData);
 		}
 		}
 
 
 		virtual std::shared_ptr<IReflectable> newRTTIObject() 
 		virtual std::shared_ptr<IReflectable> newRTTIObject() 

+ 6 - 3
CamelotCore/Include/CmMeshManager.h

@@ -13,10 +13,13 @@ namespace CamelotFramework
 		~MeshManager();
 		~MeshManager();
 
 
 		MeshPtr create(UINT32 numVertices, UINT32 numIndices, 
 		MeshPtr create(UINT32 numVertices, UINT32 numIndices, 
-			const VertexDataDescPtr& vertexDesc, MeshBufferType bufferType = MeshBufferType::Static, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
+			const VertexDataDescPtr& vertexDesc, MeshBufferType bufferType = MeshBufferType::Static, 
+			 DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 		MeshPtr create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, const MeshDataPtr& initialData, 
 		MeshPtr create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, const MeshDataPtr& initialData, 
-			MeshBufferType bufferType = MeshBufferType::Static, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
-		MeshPtr create(const MeshDataPtr& initialData, MeshBufferType bufferType = MeshBufferType::Static);
+			MeshBufferType bufferType = MeshBufferType::Static, DrawOperationType drawOp = DOT_TRIANGLE_LIST, 
+			IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
+		MeshPtr create(const MeshDataPtr& initialData, MeshBufferType bufferType = MeshBufferType::Static,
+			DrawOperationType drawOp = DOT_TRIANGLE_LIST);
 		MeshPtr createEmpty();
 		MeshPtr createEmpty();
 
 
 		/**
 		/**

+ 10 - 4
CamelotCore/Include/CmRenderSystem.h

@@ -181,11 +181,17 @@ namespace CamelotFramework
 		virtual void setDrawOperation(DrawOperationType op) = 0;
 		virtual void setDrawOperation(DrawOperationType op) = 0;
 
 
 		/**
 		/**
-		 * @brief	A helper method that provides a simple way of rendering a single object. 
-		 * 			It will automatically set up vertex declaration, draw operation, 
-		 * 			vertex and index buffers and draw them.
+		 * @brief	A helper method that provides a simple way of rendering a single object. It will
+		 * 			automatically set up vertex declaration, draw operation, vertex and index buffers and
+		 * 			draw them.
+		 *
+		 * @param	mesh	   	The mesh.
+		 * @param	indexOffset	(optional) Offset into the mesh buffer to start drawing from.
+		 * @param	indexCount 	(optional) Number of indexes to draw, starting at the offset. Ignored if "drawIndexed" is false. If 0 all indices in the mesh will be drawn.
+		 * @param	useIndices	(optional) If true, drawing is done using the index buffer on the mesh and the provided offset and size, otherwise all mesh vertices are drawn sequentially.
+		 * @param	drawOp	   	(optional) Draw operation to use when rendering.
 		 */
 		 */
-		virtual void render(const MeshPtr& mesh, UINT32 submeshIdx);
+		virtual void render(const MeshPtr& mesh, UINT32 indexOffset = 0, UINT32 indexCount = 0, bool useIndices = true, DrawOperationType drawOp = DOT_TRIANGLE_LIST);
 
 
 		/**
 		/**
 		 * @brief	Draw an object based on currently set
 		 * @brief	Draw an object based on currently set

+ 22 - 0
CamelotCore/Include/CmSubMesh.h

@@ -0,0 +1,22 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+#include "CmDrawOps.h"
+
+namespace CamelotFramework
+{
+	struct CM_EXPORT SubMesh
+	{
+		SubMesh()
+			: indexOffset(0), indexCount(0), drawOp(DOT_TRIANGLE_LIST)
+		{ }
+
+		SubMesh(UINT32 indexOffset, UINT32 indexCount, DrawOperationType drawOp):
+			indexOffset(indexOffset), indexCount(indexCount), drawOp(drawOp)
+		{ }
+
+		UINT32 indexOffset;
+		UINT32 indexCount;
+		DrawOperationType drawOp;
+	};
+}

+ 8 - 0
CamelotCore/Source/CmCoreThread.cpp

@@ -243,6 +243,14 @@ namespace CamelotFramework
 #endif
 #endif
 	}
 	}
 
 
+	void throwIfCoreThread()
+	{
+#if !CM_FORCE_SINGLETHREADED_RENDERING
+		if(CM_THREAD_CURRENT_ID == CoreThread::instance().getCoreThreadId())
+			CM_EXCEPT(InternalErrorException, "This method cannot be accessed from the core thread.");
+#endif
+	}
+
 	/************************************************************************/
 	/************************************************************************/
 	/* 								THREAD WORKER                      		*/
 	/* 								THREAD WORKER                      		*/
 	/************************************************************************/
 	/************************************************************************/

+ 134 - 85
CamelotCore/Source/CmMesh.cpp

@@ -16,27 +16,39 @@
 namespace CamelotFramework
 namespace CamelotFramework
 {
 {
 	Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
 	Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
-		MeshBufferType bufferType, IndexBuffer::IndexType indexType)
+		MeshBufferType bufferType, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
 		:mVertexData(nullptr), mIndexData(nullptr), mNumVertices(numVertices), mNumIndices(numIndices), 
 		:mVertexData(nullptr), mIndexData(nullptr), mNumVertices(numVertices), mNumIndices(numIndices), 
-		mVertexDesc(vertexDesc), mBufferType(bufferType), mIndexType(indexType), mNumSubMeshes(0)
-	{ }
+		mVertexDesc(vertexDesc), mBufferType(bufferType), mIndexType(indexType),
+		mDefaultSubMesh(0, numIndices, drawOp)
+	{
+		mSubMeshes.reserve(10);
+	}
 
 
 	Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
 	Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
-		const MeshDataPtr& initialMeshData, MeshBufferType bufferType, IndexBuffer::IndexType indexType)
+		const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
 		:mVertexData(nullptr), mIndexData(nullptr), mNumVertices(numVertices), mNumIndices(numIndices), 
 		:mVertexData(nullptr), mIndexData(nullptr), mNumVertices(numVertices), mNumIndices(numIndices), 
-		mVertexDesc(vertexDesc), mBufferType(bufferType), mIndexType(indexType), mTempInitialMeshData(initialMeshData), mNumSubMeshes(0)
-	{ }
+		mVertexDesc(vertexDesc), mBufferType(bufferType), mIndexType(indexType), 
+		mTempInitialMeshData(initialMeshData), mDefaultSubMesh(0, numIndices, drawOp)
+	{
+		mSubMeshes.reserve(10);
+	}
 
 
-	Mesh::Mesh(const MeshDataPtr& initialMeshData, MeshBufferType bufferType)
+	Mesh::Mesh(const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp)
 		:mVertexData(nullptr), mIndexData(nullptr), mNumVertices(initialMeshData->getNumVertices()), 
 		:mVertexData(nullptr), mIndexData(nullptr), mNumVertices(initialMeshData->getNumVertices()), 
 		mNumIndices(initialMeshData->getNumIndices()), mBufferType(bufferType), mIndexType(initialMeshData->getIndexType()),
 		mNumIndices(initialMeshData->getNumIndices()), mBufferType(bufferType), mIndexType(initialMeshData->getIndexType()),
-		mVertexDesc(initialMeshData->getVertexDesc()), mTempInitialMeshData(initialMeshData), mNumSubMeshes(0)
-	{ }
+		mVertexDesc(initialMeshData->getVertexDesc()), mTempInitialMeshData(initialMeshData),
+		mDefaultSubMesh(0, initialMeshData->getNumIndices(), drawOp)
+	{
+		mSubMeshes.reserve(10);
+	}
 
 
 	Mesh::Mesh()
 	Mesh::Mesh()
 		:mVertexData(nullptr), mIndexData(nullptr), mNumVertices(0), mNumIndices(0), 
 		:mVertexData(nullptr), mIndexData(nullptr), mNumVertices(0), mNumIndices(0), 
-		mBufferType(MeshBufferType::Static), mIndexType(IndexBuffer::IT_32BIT), mNumSubMeshes(0)
-	{ }
+		mBufferType(MeshBufferType::Static), mIndexType(IndexBuffer::IT_32BIT),
+		mDefaultSubMesh(0, 0, DOT_TRIANGLE_LIST)
+	{
+		mSubMeshes.reserve(10);
+	}
 
 
 	Mesh::~Mesh()
 	Mesh::~Mesh()
 	{
 	{
@@ -127,33 +139,6 @@ namespace CamelotFramework
 				vertexBuffer->writeData(bufferOffset, bufferSize, srcVertBufferData, discardEntireBuffer);
 				vertexBuffer->writeData(bufferOffset, bufferSize, srcVertBufferData, discardEntireBuffer);
 			}
 			}
 		}
 		}
-
-		// Submeshes
-		mSubMeshes.clear();
-
-		if(meshData.getNumSubmeshes() > 0)
-		{
-			for(UINT32 i = 0; i < meshData.getNumSubmeshes(); i++)
-			{
-				UINT32 numIndices = meshData.getNumIndices(i);
-
-				if(numIndices > 0)
-				{
-					mSubMeshes.push_back(SubMesh(meshData.getIndexBufferOffset(i), numIndices, meshData.getDrawOp(i), mVertexData, mIndexData, true));
-				}
-			}
-		}
-		else // Read it all as one mesh
-		{
-			UINT32 numIndices = meshData.getNumIndices();
-
-			if(numIndices > 0)
-			{
-				mSubMeshes.push_back(SubMesh(0, numIndices, meshData.getDrawOp(), mVertexData, mIndexData, true));
-			}
-		}
-
-		mNumSubMeshes.store((UINT32)mSubMeshes.size());
 	}
 	}
 
 
 	void Mesh::readSubresource(UINT32 subresourceIdx, GpuResourceData& data)
 	void Mesh::readSubresource(UINT32 subresourceIdx, GpuResourceData& data)
@@ -173,26 +158,24 @@ namespace CamelotFramework
 		{
 		{
 			UINT8* idxData = static_cast<UINT8*>(mIndexData->indexBuffer->lock(GBL_READ_ONLY));
 			UINT8* idxData = static_cast<UINT8*>(mIndexData->indexBuffer->lock(GBL_READ_ONLY));
 			UINT32 idxElemSize = mIndexData->indexBuffer->getIndexSize();
 			UINT32 idxElemSize = mIndexData->indexBuffer->getIndexSize();
-			UINT32 indexResourceOffset = meshData.getResourceIndexOffset() * meshData.getIndexElementSize();
+			UINT32 indexResourceOffset = meshData.getResourceIndexOffset();
 
 
-			for(UINT32 i = 0; i < mSubMeshes.size(); i++)
-			{
-				UINT8* indices = nullptr;
+			UINT8* indices = nullptr;
+
+			if(indexType == IndexBuffer::IT_16BIT)
+				indices = (UINT8*)meshData.getIndices16();
+			else
+				indices = (UINT8*)meshData.getIndices32();
 
 
-				if(indexType == IndexBuffer::IT_16BIT)
-					indices = (UINT8*)meshData.getIndices16(i);
-				else
-					indices = (UINT8*)meshData.getIndices32(i);
+			UINT32 remainingNumIndices = (UINT32)std::max(0, (INT32)(mNumIndices - indexResourceOffset));
+			UINT32 numIndicesToCopy = std::min(remainingNumIndices, meshData.getNumIndices());
 
 
-				UINT32 indicesSize = mSubMeshes[i].indexCount * idxElemSize;
-				UINT32 indicesOffset = meshData.getIndexBufferOffset(i) + indexResourceOffset;
-				
-				if((indicesOffset + indicesSize) > meshData.getIndexBufferSize())
-					CM_EXCEPT(InvalidParametersException, "Provided buffer doesn't have enough space to store mesh indices.");
+			UINT32 indicesSize = numIndicesToCopy * idxElemSize;
+			if(indicesSize > meshData.getIndexBufferSize())
+				CM_EXCEPT(InvalidParametersException, "Provided buffer doesn't have enough space to store mesh indices.");
 
 
-				indices += indexResourceOffset;
-				memcpy(indices, &idxData[mSubMeshes[i].indexOffset * idxElemSize], mSubMeshes[i].indexCount * idxElemSize);
-			}
+			idxData += indexResourceOffset * idxElemSize;
+			memcpy(indices, idxData, numIndicesToCopy * idxElemSize);
 
 
 			mIndexData->indexBuffer->unlock();
 			mIndexData->indexBuffer->unlock();
 		}
 		}
@@ -207,18 +190,20 @@ namespace CamelotFramework
 				if(streamIdx > meshData.getVertexDesc()->getMaxStreamIdx())
 				if(streamIdx > meshData.getVertexDesc()->getMaxStreamIdx())
 					continue;
 					continue;
 
 
+				UINT32 vertexResourceOffset = meshData.getResourceVertexOffset();
+
+				UINT32 remainingNumVertices = (UINT32)std::max(0, (INT32)(mNumVertices - vertexResourceOffset));
+				UINT32 numVerticesToCopy = std::min(remainingNumVertices, meshData.getNumVertices());
+
 				VertexBufferPtr vertexBuffer = iter->second;
 				VertexBufferPtr vertexBuffer = iter->second;
-				UINT32 bufferSize = vertexBuffer->getVertexSize() * vertexBuffer->getNumVertices();
+				UINT32 bufferSize = vertexBuffer->getVertexSize() * numVerticesToCopy;
 				
 				
-				UINT32 vertexResourceOffset = meshData.getResourceVertexOffset() * meshData.getVertexDesc()->getVertexStride(streamIdx);
-				UINT32 vertexOffset = meshData.getStreamOffset(streamIdx) + vertexResourceOffset;
-
-				UINT8* vertDataPtr = static_cast<UINT8*>(vertexBuffer->lock(GBL_READ_ONLY));
+				UINT8* vertDataPtr = static_cast<UINT8*>(vertexBuffer->lock(GBL_READ_ONLY)) + vertexResourceOffset * meshData.getVertexDesc()->getVertexStride(streamIdx);
 
 
-				if((vertexOffset + bufferSize) > meshData.getStreamSize(streamIdx))
+				if(bufferSize > meshData.getStreamSize(streamIdx))
 					CM_EXCEPT(InvalidParametersException, "Provided buffer doesn't have enough space to store mesh vertices.");
 					CM_EXCEPT(InvalidParametersException, "Provided buffer doesn't have enough space to store mesh vertices.");
 
 
-				UINT8* dest = meshData.getStreamData(streamIdx) + vertexResourceOffset;
+				UINT8* dest = meshData.getStreamData(streamIdx);
 				memcpy(dest, vertDataPtr, bufferSize);
 				memcpy(dest, vertDataPtr, bufferSize);
 
 
 				vertexBuffer->unlock();
 				vertexBuffer->unlock();
@@ -234,27 +219,85 @@ namespace CamelotFramework
 		if(mIndexData)
 		if(mIndexData)
 			indexType = mIndexData->indexBuffer->getType();
 			indexType = mIndexData->indexBuffer->getType();
 
 
-		UINT32 numIndices = 0;
-		if(mIndexData)
+		MeshDataPtr meshData = cm_shared_ptr<MeshData>(mVertexData->vertexCount, mNumIndices, mVertexDesc, indexType);
+
+		return meshData;
+	}
+
+	const AABox& Mesh::getBounds() const
+	{
+		// TODO - Retrieve bounds for entire mesh (need to calculate them during creation)
+		return AABox::BOX_EMPTY;
+	}
+
+	const AABox& Mesh::getBounds(UINT32 submeshIdx) const
+	{
+		// TODO - Retrieve bounds a specific sub-mesh (need to calculate them during creation)
+		return AABox::BOX_EMPTY;
+	}
+
+	std::shared_ptr<VertexData> Mesh::getVertexData() const
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		return mVertexData;
+	}
+
+	std::shared_ptr<IndexData> Mesh::getIndexData() const
+	{
+		THROW_IF_NOT_CORE_THREAD;
+
+		return mIndexData;
+	}
+
+	void Mesh::clearSubMeshes()
+	{
+		THROW_IF_CORE_THREAD;
+
+		mSubMeshes.clear();
+	}
+
+	void Mesh::addSubMesh(UINT32 indexOffset, UINT32 indexCount, DrawOperationType drawOp)
+	{
+		if((indexOffset + indexCount) >= mNumIndices)
 		{
 		{
-			for(UINT32 i = 0; i < mSubMeshes.size(); i++)
-				numIndices += mSubMeshes[i].indexCount;
+			LOGWRN("Provided sub-mesh references indexes out of range. Sub-mesh range: " 
+				+ toString(indexOffset) + " .. " + toString(indexOffset + indexCount) + "." \
+				"Valid range is: 0 .. " + toString(mNumIndices) + ". Ignoring command.");
+
+			return;
 		}
 		}
 
 
-		MeshDataPtr meshData = cm_shared_ptr<MeshData>(mVertexData->vertexCount, numIndices, mVertexDesc, DOT_TRIANGLE_LIST, indexType);
+		mSubMeshes.push_back(SubMesh(indexOffset, indexCount, drawOp));
+	}
 
 
-		if(mIndexData)
+	void Mesh::setSubMeshes(const Vector<SubMesh>::type& subMeshes)
+	{
+		THROW_IF_CORE_THREAD;
+
+		for(auto& subMesh : subMeshes)
 		{
 		{
-			for(UINT32 i = 0; i < mSubMeshes.size(); i++)
-				meshData->addSubMesh(mSubMeshes[i].indexCount, i);
+			if((subMesh.indexOffset + subMesh.indexCount) >= mNumIndices)
+			{
+				LOGWRN("Provided sub-mesh references indexes out of range. Sub-mesh range: " 
+					+ toString(subMesh.indexOffset) + " .. " + toString(subMesh.indexOffset + subMesh.indexCount) + "." \
+					"Valid range is: 0 .. " + toString(mNumIndices) + ". Ignoring command.");
+
+				return;
+			}
 		}
 		}
 
 
-		return meshData;
+		mSubMeshes = subMeshes;
 	}
 	}
 
 
 	const SubMesh& Mesh::getSubMesh(UINT32 subMeshIdx) const
 	const SubMesh& Mesh::getSubMesh(UINT32 subMeshIdx) const
 	{
 	{
-		THROW_IF_NOT_CORE_THREAD;
+		THROW_IF_CORE_THREAD;
+
+		if(mSubMeshes.size() == 0 && subMeshIdx == 0)
+		{
+			return mDefaultSubMesh;
+		}
 
 
 		if(subMeshIdx < 0 || subMeshIdx >= mSubMeshes.size())
 		if(subMeshIdx < 0 || subMeshIdx >= mSubMeshes.size())
 		{
 		{
@@ -265,16 +308,19 @@ namespace CamelotFramework
 		return mSubMeshes[subMeshIdx];
 		return mSubMeshes[subMeshIdx];
 	}
 	}
 
 
-	const AABox& Mesh::getBounds() const
+	UINT32 Mesh::getNumSubMeshes() const
 	{
 	{
-		// TODO - Retrieve bounds for entire mesh (need to calculate them during creation)
-		return AABox::BOX_EMPTY;
-	}
+		THROW_IF_CORE_THREAD;
 
 
-	const AABox& Mesh::getBounds(UINT32 submeshIdx) const
-	{
-		// TODO - Retrieve bounds a specific sub-mesh (need to calculate them during creation)
-		return AABox::BOX_EMPTY;
+		if(mSubMeshes.size() > 0)
+			return (UINT32)mSubMeshes.size();
+		else
+		{
+			if(mDefaultSubMesh.indexCount > 0)
+				return 1;
+			else
+				return 0;
+		}
 	}
 	}
 
 
 	void Mesh::initialize_internal()
 	void Mesh::initialize_internal()
@@ -349,23 +395,26 @@ namespace CamelotFramework
 	/* 								STATICS		                     		*/
 	/* 								STATICS		                     		*/
 	/************************************************************************/
 	/************************************************************************/
 
 
-	HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, MeshBufferType bufferType, IndexBuffer::IndexType indexType)
+	HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
+		MeshBufferType bufferType, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
 	{
 	{
-		MeshPtr meshPtr = MeshManager::instance().create(numVertices, numIndices, vertexDesc, bufferType, indexType);
+		MeshPtr meshPtr = MeshManager::instance().create(numVertices, numIndices, vertexDesc, bufferType, drawOp, indexType);
 
 
 		return static_resource_cast<Mesh>(Resource::_createResourceHandle(meshPtr));
 		return static_resource_cast<Mesh>(Resource::_createResourceHandle(meshPtr));
 	}
 	}
 
 
-	HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, const MeshDataPtr& initialMeshData, MeshBufferType bufferType, IndexBuffer::IndexType indexType)
+	HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
+		const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
 	{
 	{
-		MeshPtr meshPtr = MeshManager::instance().create(numVertices, numIndices, vertexDesc, initialMeshData, bufferType, indexType);
+		MeshPtr meshPtr = MeshManager::instance().create(numVertices, numIndices, vertexDesc, 
+			initialMeshData, bufferType, drawOp, indexType);
 
 
 		return static_resource_cast<Mesh>(Resource::_createResourceHandle(meshPtr));
 		return static_resource_cast<Mesh>(Resource::_createResourceHandle(meshPtr));
 	}
 	}
 
 
-	HMesh Mesh::create(const MeshDataPtr& initialMeshData, MeshBufferType bufferType)
+	HMesh Mesh::create(const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp)
 	{
 	{
-		MeshPtr meshPtr = MeshManager::instance().create(initialMeshData, bufferType);
+		MeshPtr meshPtr = MeshManager::instance().create(initialMeshData, bufferType, drawOp);
 
 
 		return static_resource_cast<Mesh>(Resource::_createResourceHandle(meshPtr));
 		return static_resource_cast<Mesh>(Resource::_createResourceHandle(meshPtr));
 	}
 	}

+ 37 - 95
CamelotCore/Source/CmMeshData.cpp

@@ -9,90 +9,42 @@
 
 
 namespace CamelotFramework
 namespace CamelotFramework
 {
 {
-	MeshData::MeshData(UINT32 numVertices, UINT32 numIndexes, const VertexDataDescPtr& vertexData, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
-	   :mNumVertices(numVertices), mNumIndices(numIndexes), mVertexData(vertexData), mIndexType(indexType), mDrawOp(drawOp), mData(nullptr), mResourceIndexOffset(0),
+	MeshData::MeshData(UINT32 numVertices, UINT32 numIndexes, const VertexDataDescPtr& vertexData, IndexBuffer::IndexType indexType)
+	   :mNumVertices(numVertices), mNumIndices(numIndexes), mVertexData(vertexData), mIndexType(indexType), mData(nullptr), mResourceIndexOffset(0),
 	   mResourceVertexOffset(0)
 	   mResourceVertexOffset(0)
 	{
 	{
 		allocateInternalBuffer();
 		allocateInternalBuffer();
 	}
 	}
 
 
 	MeshData::MeshData()
 	MeshData::MeshData()
-		:mNumVertices(0), mNumIndices(0), mIndexType(IndexBuffer::IT_32BIT), mDrawOp(DOT_TRIANGLE_LIST), mData(nullptr), 
+		:mNumVertices(0), mNumIndices(0), mIndexType(IndexBuffer::IT_32BIT), mData(nullptr), 
 		mResourceIndexOffset(0), mResourceVertexOffset(0)
 		mResourceIndexOffset(0), mResourceVertexOffset(0)
 	{ }
 	{ }
 
 
 	MeshData::~MeshData()
 	MeshData::~MeshData()
 	{ }
 	{ }
 
 
-	void MeshData::addSubMesh(UINT32 numIndices, UINT32 subMesh, DrawOperationType drawOp)
-	{
-		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;
-		indexData.drawOp = drawOp;
-
-		mSubMeshes[subMesh] = indexData;
-	}
-
-	UINT32 MeshData::getNumIndices(UINT32 subMesh) const
-	{
-		if(mSubMeshes.size() == 0)
-			return mNumIndices;
-
-		return mSubMeshes.at(subMesh).numIndices;
-	}
-
-	DrawOperationType MeshData::getDrawOp(UINT32 subMesh) const
-	{
-		if(mSubMeshes.size() == 0)
-			return mDrawOp;
-
-		return mSubMeshes.at(subMesh).drawOp;
-	}
-
 	UINT32 MeshData::getNumIndices() const
 	UINT32 MeshData::getNumIndices() const
 	{
 	{
-		if(mSubMeshes.size() == 0)
-			return mNumIndices;
-
-		UINT32 count = 0;
-		for(UINT32 i = 0; i < getNumSubmeshes(); i++)
-		{
-			count += mSubMeshes[i].numIndices;
-		}
-
-		return count;
+		return mNumIndices;
 	}
 	}
 
 
-	DrawOperationType MeshData::getDrawOp() const
-	{
-		return mDrawOp;
-	}
-
-	UINT16* MeshData::getIndices16(UINT32 subMesh) const
+	UINT16* MeshData::getIndices16() const
 	{
 	{
 		if(mIndexType != IndexBuffer::IT_16BIT)
 		if(mIndexType != IndexBuffer::IT_16BIT)
 			CM_EXCEPT(InternalErrorException, "Attempting to get 16bit index buffer, but internally allocated buffer is 32 bit.");
 			CM_EXCEPT(InternalErrorException, "Attempting to get 16bit index buffer, but internally allocated buffer is 32 bit.");
 
 
-		UINT32 indexBufferOffset = getIndexBufferOffset(subMesh);
+		UINT32 indexBufferOffset = getIndexBufferOffset();
 
 
 		return (UINT16*)(getData() + indexBufferOffset);
 		return (UINT16*)(getData() + indexBufferOffset);
 	}
 	}
 
 
-	UINT32* MeshData::getIndices32(UINT32 subMesh) const
+	UINT32* MeshData::getIndices32() const
 	{
 	{
 		if(mIndexType != IndexBuffer::IT_32BIT)
 		if(mIndexType != IndexBuffer::IT_32BIT)
 			CM_EXCEPT(InternalErrorException, "Attempting to get 32bit index buffer, but internally allocated buffer is 16 bit.");
 			CM_EXCEPT(InternalErrorException, "Attempting to get 32bit index buffer, but internally allocated buffer is 16 bit.");
 
 
-		UINT32 indexBufferOffset = getIndexBufferOffset(subMesh);
+		UINT32 indexBufferOffset = getIndexBufferOffset();
 
 
 		return (UINT32*)(getData() + indexBufferOffset);
 		return (UINT32*)(getData() + indexBufferOffset);
 	}
 	}
@@ -104,7 +56,8 @@ namespace CamelotFramework
 
 
 	// TODO - This doesn't handle the case where multiple elements in same slot have different data types
 	// TODO - This doesn't handle the case where multiple elements in same slot have different data types
 	//  - actually it will likely corrupt memory in that case
 	//  - actually it will likely corrupt memory in that case
-	MeshDataPtr MeshData::combine(const Vector<MeshDataPtr>::type& meshes)
+	MeshDataPtr MeshData::combine(const Vector<MeshDataPtr>::type& meshes, const Vector<Vector<SubMesh>::type>::type& allSubMeshes, 
+		Vector<SubMesh>::type& subMeshes)
 	{
 	{
 		UINT32 totalVertexCount = 0;
 		UINT32 totalVertexCount = 0;
 		UINT32 totalIndexCount = 0;
 		UINT32 totalIndexCount = 0;
@@ -117,18 +70,6 @@ namespace CamelotFramework
 		VertexDataDescPtr combinedVertexData = cm_shared_ptr<VertexDataDesc, PoolAlloc>();
 		VertexDataDescPtr combinedVertexData = cm_shared_ptr<VertexDataDesc, PoolAlloc>();
 		MeshDataPtr combinedMeshData = cm_shared_ptr<MeshData, PoolAlloc>(totalVertexCount, totalIndexCount, combinedVertexData);
 		MeshDataPtr combinedMeshData = cm_shared_ptr<MeshData, PoolAlloc>(totalVertexCount, totalIndexCount, combinedVertexData);
 
 
-		UINT32 subMeshIndex = 0;
-		for(auto& meshData : meshes)
-		{
-			for(UINT32 i = 0; i < meshData->getNumSubmeshes(); i++)
-			{
-				UINT32 numIndices = meshData->getNumIndices(i);
-				combinedMeshData->addSubMesh(numIndices, subMeshIndex);
-
-				subMeshIndex++;
-			}
-		}
-
 		Vector<VertexElement>::type combinedVertexElements;
 		Vector<VertexElement>::type combinedVertexElements;
 		for(auto& meshData : meshes)
 		for(auto& meshData : meshes)
 		{
 		{
@@ -167,24 +108,39 @@ namespace CamelotFramework
 		VertexDataDescPtr vertexData = combinedMeshData->getVertexDesc();
 		VertexDataDescPtr vertexData = combinedMeshData->getVertexDesc();
 
 
 		// Copy indices
 		// Copy indices
-		subMeshIndex = 0;
 		UINT32 vertexOffset = 0;
 		UINT32 vertexOffset = 0;
+		UINT32 indexOffset = 0;
+		UINT32* idxPtr = combinedMeshData->getIndices32();
 		for(auto& meshData : meshes)
 		for(auto& meshData : meshes)
 		{
 		{
-			for(UINT32 i = 0; i < meshData->getNumSubmeshes(); i++)
-			{
-				UINT32 numIndices = meshData->getNumIndices(i);
-				UINT32* srcData = meshData->getIndices32(i);
+			UINT32 numIndices = meshData->getNumIndices();
+			UINT32* srcData = meshData->getIndices32();
+
+			for(UINT32 j = 0; j < numIndices; j++)
+				idxPtr[j] = srcData[j] + vertexOffset;
+
+			subMeshes.push_back(SubMesh(indexOffset, numIndices, DOT_TRIANGLE_LIST));
 
 
-				UINT32* dstData = combinedMeshData->getIndices32(subMeshIndex);
+			indexOffset += numIndices;
+			idxPtr += numIndices;
+			vertexOffset += meshData->getNumVertices();
+		}
 
 
-				for(UINT32 j = 0; j < numIndices; j++)
-					dstData[j] = srcData[j] + vertexOffset;
+		// Copy sub-meshes
+		UINT32 meshIdx = 0;
+		indexOffset = 0;
+		for(auto& meshData : meshes)
+		{
+			UINT32 numIndices = meshData->getNumIndices();
+			const Vector<SubMesh>::type curSubMeshes = allSubMeshes[meshIdx];
 
 
-				subMeshIndex++;
+			for(auto& subMesh : curSubMeshes)
+			{
+				subMeshes.push_back(SubMesh(subMesh.indexOffset + indexOffset, subMesh.indexCount, subMesh.drawOp));
 			}
 			}
 
 
-			vertexOffset += meshData->getNumVertices();
+			indexOffset += numIndices;
+			meshIdx++;
 		}
 		}
 
 
 		// Copy vertices
 		// Copy vertices
@@ -313,23 +269,9 @@ namespace CamelotFramework
 		stride = mVertexData->getVertexStride(streamIdx);
 		stride = mVertexData->getVertexStride(streamIdx);
 	}
 	}
 
 
-	UINT32 MeshData::getIndexBufferOffset(UINT32 subMesh) const
+	UINT32 MeshData::getIndexBufferOffset() const
 	{
 	{
-		if(mSubMeshes.size() == 0) // No submeshes, we assume all is one big mesh
-			return 0;
-
-		if(subMesh < 0 || (subMesh > (UINT32)mSubMeshes.size()))
-		{
-			CM_EXCEPT(InvalidParametersException, "Submesh out of range: " + toString(subMesh) + ". Allowed range: 0 .. " + toString((UINT32)mSubMeshes.size()));
-		}
-
-		UINT32 offset = 0;
-		for(UINT32 i = 0; i < subMesh; i++)
-		{
-			offset += mSubMeshes[i].numIndices * getIndexElementSize();
-		}
-
-		return offset;
+		return 0;
 	}
 	}
 
 
 	UINT32 MeshData::getStreamOffset(UINT32 streamIdx) const
 	UINT32 MeshData::getStreamOffset(UINT32 streamIdx) const

+ 11 - 8
CamelotCore/Source/CmMeshManager.cpp

@@ -17,28 +17,31 @@ namespace CamelotFramework
 
 
 	}
 	}
 
 
-	MeshPtr MeshManager::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, MeshBufferType bufferType, IndexBuffer::IndexType indexType)
+	MeshPtr MeshManager::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
+		MeshBufferType bufferType, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
 	{
 	{
-		MeshPtr mesh = cm_core_ptr<Mesh, PoolAlloc>(new (cm_alloc<Mesh, PoolAlloc>()) Mesh(numVertices, numIndices, vertexDesc, bufferType, indexType));
+		MeshPtr mesh = cm_core_ptr<Mesh, PoolAlloc>(new (cm_alloc<Mesh, PoolAlloc>()) 
+			Mesh(numVertices, numIndices, vertexDesc, bufferType, drawOp, indexType));
 		mesh->setThisPtr(mesh);
 		mesh->setThisPtr(mesh);
 		mesh->initialize();
 		mesh->initialize();
 
 
 		return mesh;
 		return mesh;
 	}
 	}
 
 
-	MeshPtr MeshManager::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, const MeshDataPtr& initialData, 
-		MeshBufferType bufferType, IndexBuffer::IndexType indexType)
+	MeshPtr MeshManager::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
+		const MeshDataPtr& initialData, MeshBufferType bufferType, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
 	{
 	{
-		MeshPtr mesh = cm_core_ptr<Mesh, PoolAlloc>(new (cm_alloc<Mesh, PoolAlloc>()) Mesh(numVertices, numIndices, vertexDesc, initialData, bufferType, indexType));
+		MeshPtr mesh = cm_core_ptr<Mesh, PoolAlloc>(new (cm_alloc<Mesh, PoolAlloc>()) 
+			Mesh(numVertices, numIndices, vertexDesc, initialData, bufferType, drawOp, indexType));
 		mesh->setThisPtr(mesh);
 		mesh->setThisPtr(mesh);
 		mesh->initialize();
 		mesh->initialize();
 
 
 		return mesh;
 		return mesh;
 	}
 	}
 
 
-	MeshPtr MeshManager::create(const MeshDataPtr& initialData, MeshBufferType bufferType)
+	MeshPtr MeshManager::create(const MeshDataPtr& initialData, MeshBufferType bufferType, DrawOperationType drawOp)
 	{
 	{
-		MeshPtr mesh = cm_core_ptr<Mesh, PoolAlloc>(new (cm_alloc<Mesh, PoolAlloc>()) Mesh(initialData, bufferType));
+		MeshPtr mesh = cm_core_ptr<Mesh, PoolAlloc>(new (cm_alloc<Mesh, PoolAlloc>()) Mesh(initialData, bufferType, drawOp));
 		mesh->setThisPtr(mesh);
 		mesh->setThisPtr(mesh);
 		mesh->initialize();
 		mesh->initialize();
 
 
@@ -63,7 +66,7 @@ namespace CamelotFramework
 		auto vecIter = mDummyMeshData->getVec3DataIter(VES_POSITION);
 		auto vecIter = mDummyMeshData->getVec3DataIter(VES_POSITION);
 		vecIter.setValue(Vector3(0, 0, 0));
 		vecIter.setValue(Vector3(0, 0, 0));
 
 
-		auto indices = mDummyMeshData->getIndices32(0);
+		auto indices = mDummyMeshData->getIndices32();
 		indices[0] = 0;
 		indices[0] = 0;
 		indices[1] = 0;
 		indices[1] = 0;
 		indices[2] = 0;
 		indices[2] = 0;

+ 15 - 0
CamelotCore/Source/CmMeshRTTI.h

@@ -8,8 +8,18 @@
 
 
 namespace CamelotFramework
 namespace CamelotFramework
 {
 {
+	CM_ALLOW_MEMCPY_SERIALIZATION(SubMesh);
+
 	class MeshRTTI : public RTTIType<Mesh, GpuResource, MeshRTTI>
 	class MeshRTTI : public RTTIType<Mesh, GpuResource, MeshRTTI>
 	{
 	{
+		SubMesh& getSubMesh(Mesh* obj, UINT32 arrayIdx) { return obj->mSubMeshes[arrayIdx]; }
+		void setSubMesh(Mesh* obj, UINT32 arrayIdx, SubMesh& value) { obj->mSubMeshes[arrayIdx] = value; }
+		UINT32 getNumSubmeshes(Mesh* obj) { return (UINT32)obj->mSubMeshes.size(); }
+		void setNumSubmeshes(Mesh* obj, UINT32 numElements) { obj->mSubMeshes.resize(numElements); }
+
+		SubMesh& getDefaultSubMesh(Mesh* obj) { return obj->mDefaultSubMesh; }
+		void setDefaultSubMesh(Mesh* obj, SubMesh& value) { obj->mDefaultSubMesh = value; }
+
 		VertexDataDescPtr getVertexDesc(Mesh* obj) { return obj->mVertexDesc; }
 		VertexDataDescPtr getVertexDesc(Mesh* obj) { return obj->mVertexDesc; }
 		void setVertexDesc(Mesh* obj, VertexDataDescPtr value) { obj->mVertexDesc = value; }
 		void setVertexDesc(Mesh* obj, VertexDataDescPtr value) { obj->mVertexDesc = value; }
 
 
@@ -53,6 +63,11 @@ namespace CamelotFramework
 			addPlainField("mBufferType", 4, &MeshRTTI::getBufferType, &MeshRTTI::setBufferType);
 			addPlainField("mBufferType", 4, &MeshRTTI::getBufferType, &MeshRTTI::setBufferType);
 
 
 			addReflectablePtrField("mMeshData", 5, &MeshRTTI::getMeshData, &MeshRTTI::setMeshData);
 			addReflectablePtrField("mMeshData", 5, &MeshRTTI::getMeshData, &MeshRTTI::setMeshData);
+
+			addPlainArrayField("mSubMeshes", 6, &MeshRTTI::getSubMesh, 
+				&MeshRTTI::getNumSubmeshes, &MeshRTTI::setSubMesh, &MeshRTTI::setNumSubmeshes);
+
+			addPlainField("mDefaultSubMesh", 7, &MeshRTTI::getDefaultSubMesh, &MeshRTTI::setDefaultSubMesh);
 		}
 		}
 
 
 		virtual void onDeserializationEnded(IReflectable* obj)
 		virtual void onDeserializationEnded(IReflectable* obj)

+ 14 - 9
CamelotCore/Source/CmRenderSystem.cpp

@@ -210,7 +210,7 @@ namespace CamelotFramework {
         return false;
         return false;
 	}
 	}
 
 
-	void RenderSystem::render(const MeshPtr& mesh, UINT32 submeshIdx)
+	void RenderSystem::render(const MeshPtr& mesh, UINT32 indexOffset, UINT32 indexCount, bool useIndices, DrawOperationType drawOp)
 	{
 	{
 		THROW_IF_NOT_CORE_THREAD;
 		THROW_IF_NOT_CORE_THREAD;
 
 
@@ -224,10 +224,10 @@ namespace CamelotFramework {
 			mClipPlanesDirty = false;
 			mClipPlanesDirty = false;
 		}
 		}
 
 
-		const SubMesh& subMesh = mesh->getSubMesh(submeshIdx);
+		std::shared_ptr<VertexData> vertexData = mesh->getVertexData();
 
 
-		setVertexDeclaration(subMesh.vertexData->vertexDeclaration);
-		auto vertexBuffers = subMesh.vertexData->getBuffers();
+		setVertexDeclaration(vertexData->vertexDeclaration);
+		auto vertexBuffers = vertexData->getBuffers();
 
 
 		if(vertexBuffers.size() > 0)
 		if(vertexBuffers.size() > 0)
 		{
 		{
@@ -252,15 +252,20 @@ namespace CamelotFramework {
 			setVertexBuffers(startSlot, buffers, endSlot - startSlot + 1);
 			setVertexBuffers(startSlot, buffers, endSlot - startSlot + 1);
 		}
 		}
 
 
-		setDrawOperation(subMesh.drawOp);
+		setDrawOperation(drawOp);
 
 
-		if (subMesh.useIndexes)
+		if (useIndices)
 		{
 		{
-			setIndexBuffer(subMesh.indexData->indexBuffer);
-			drawIndexed(subMesh.indexOffset, subMesh.indexCount, subMesh.vertexData->vertexCount);
+			std::shared_ptr<IndexData> indexData = mesh->getIndexData();
+
+			if(indexCount == 0)
+				indexCount = indexData->indexCount;
+
+			setIndexBuffer(indexData->indexBuffer);
+			drawIndexed(indexOffset, indexCount, vertexData->vertexCount);
 		}
 		}
 		else
 		else
-			draw(subMesh.vertexData->vertexCount);
+			draw(vertexData->vertexCount);
 
 
 		gProfiler().endSample("render");
 		gProfiler().endSample("render");
 	}
 	}

+ 3 - 2
CamelotFBXImporter/Include/CmFBXImporter.h

@@ -3,6 +3,7 @@
 #include "CmFBXPrerequisites.h"
 #include "CmFBXPrerequisites.h"
 #include "CmSpecificImporter.h"
 #include "CmSpecificImporter.h"
 #include "CmImporter.h"
 #include "CmImporter.h"
+#include "CmSubMesh.h"
 
 
 #define FBXSDK_NEW_API
 #define FBXSDK_NEW_API
 #include <fbxsdk.h>
 #include <fbxsdk.h>
@@ -43,8 +44,8 @@ namespace CamelotFramework
 		void shutDownSdk(FbxManager* manager);
 		void shutDownSdk(FbxManager* manager);
 
 
 		void loadScene(FbxManager* manager, FbxScene* scene, const String& filePath);
 		void loadScene(FbxManager* manager, FbxScene* scene, const String& filePath);
-		MeshDataPtr parseScene(FbxManager* manager, FbxScene* scene);
+		MeshDataPtr parseScene(FbxManager* manager, FbxScene* scene, Vector<SubMesh>::type& subMeshes);
 
 
-		MeshDataPtr parseMesh(FbxMesh* mesh, bool createTangentsIfMissing = true);
+		MeshDataPtr parseMesh(FbxMesh* mesh, Vector<SubMesh>::type& subMeshes, bool createTangentsIfMissing = true);
 	};
 	};
 }
 }

+ 14 - 10
CamelotFBXImporter/Source/CmFBXImporter.cpp

@@ -45,11 +45,13 @@ namespace CamelotFramework
 		startUpSdk(fbxManager, fbxScene);
 		startUpSdk(fbxManager, fbxScene);
 		loadScene(fbxManager, fbxScene, filePath);
 		loadScene(fbxManager, fbxScene, filePath);
 
 
-		MeshDataPtr meshData = parseScene(fbxManager, fbxScene);	
+		Vector<SubMesh>::type subMeshes;
+		MeshDataPtr meshData = parseScene(fbxManager, fbxScene, subMeshes);	
 
 
 		shutDownSdk(fbxManager);
 		shutDownSdk(fbxManager);
 
 
 		HMesh mesh = Mesh::create(meshData);
 		HMesh mesh = Mesh::create(meshData);
+		mesh->setSubMeshes(subMeshes);
 
 
 		return mesh;
 		return mesh;
 	}
 	}
@@ -116,12 +118,13 @@ namespace CamelotFramework
 		importer->Destroy();
 		importer->Destroy();
 	}
 	}
 
 
-	MeshDataPtr FBXImporter::parseScene(FbxManager* manager, FbxScene* scene)
+	MeshDataPtr FBXImporter::parseScene(FbxManager* manager, FbxScene* scene, Vector<SubMesh>::type& subMeshes)
 	{
 	{
 		Stack<FbxNode*>::type todo;
 		Stack<FbxNode*>::type todo;
 		todo.push(scene->GetRootNode());
 		todo.push(scene->GetRootNode());
 
 
 		Vector<MeshDataPtr>::type allMeshes;
 		Vector<MeshDataPtr>::type allMeshes;
+		Vector<Vector<SubMesh>::type>::type allSubMeshes;
 
 
 		while(!todo.empty())
 		while(!todo.empty())
 		{
 		{
@@ -148,7 +151,9 @@ namespace CamelotFramework
 							mesh = static_cast<FbxMesh*>(attrib);
 							mesh = static_cast<FbxMesh*>(attrib);
 						}
 						}
 
 
-						MeshDataPtr meshData = parseMesh(mesh); 
+						allSubMeshes.push_back(Vector<SubMesh>::type());
+
+						MeshDataPtr meshData = parseMesh(mesh, allSubMeshes.back()); 
 						allMeshes.push_back(meshData);
 						allMeshes.push_back(meshData);
 
 
 						// TODO - Transform meshes based on node transform
 						// TODO - Transform meshes based on node transform
@@ -167,12 +172,15 @@ namespace CamelotFramework
 		if(allMeshes.size() == 0)
 		if(allMeshes.size() == 0)
 			return nullptr;
 			return nullptr;
 		else if(allMeshes.size() == 1)
 		else if(allMeshes.size() == 1)
+		{
+			subMeshes = allSubMeshes[0];
 			return allMeshes[0];
 			return allMeshes[0];
+		}
 		else
 		else
-			return MeshData::combine(allMeshes);
+			return MeshData::combine(allMeshes, allSubMeshes, subMeshes);
 	}
 	}
 
 
-	MeshDataPtr FBXImporter::parseMesh(FbxMesh* mesh, bool createTangentsIfMissing)
+	MeshDataPtr FBXImporter::parseMesh(FbxMesh* mesh, Vector<SubMesh>::type& subMeshes, bool createTangentsIfMissing)
 	{
 	{
 		if (!mesh->GetNode())
 		if (!mesh->GetNode())
 		{
 		{
@@ -319,7 +327,6 @@ namespace CamelotFramework
 		// Count the polygon count of each material
 		// Count the polygon count of each material
 		FbxLayerElementArrayTemplate<int>* lMaterialIndice = NULL;
 		FbxLayerElementArrayTemplate<int>* lMaterialIndice = NULL;
 		FbxGeometryElement::EMappingMode lMaterialMappingMode = FbxGeometryElement::eNone;
 		FbxGeometryElement::EMappingMode lMaterialMappingMode = FbxGeometryElement::eNone;
-		Vector<SubMesh>::type subMeshes;
 
 
 		UINT32 numIndices = 0;
 		UINT32 numIndices = 0;
 		if (mesh->GetElementMaterial())
 		if (mesh->GetElementMaterial())
@@ -369,9 +376,6 @@ namespace CamelotFramework
 
 
 		MeshDataPtr meshData = cm_shared_ptr<MeshData, ScratchAlloc>(vertexCount, numIndices, vertexDesc);
 		MeshDataPtr meshData = cm_shared_ptr<MeshData, ScratchAlloc>(vertexCount, numIndices, vertexDesc);
 
 
-		for(UINT32 i = 0; i < (UINT32)subMeshes.size(); i++)
-			meshData->addSubMesh(subMeshes[i].indexCount, i);
-
 		// Allocate the array memory, by control point or by polygon vertex.
 		// Allocate the array memory, by control point or by polygon vertex.
 		VertexElemIter<Vector3> positions = meshData->getVec3DataIter(VES_POSITION);
 		VertexElemIter<Vector3> positions = meshData->getVec3DataIter(VES_POSITION);
 
 
@@ -560,7 +564,7 @@ namespace CamelotFramework
 
 
 		for(UINT32 i = 0; i < (UINT32)indices.size(); i++)
 		for(UINT32 i = 0; i < (UINT32)indices.size(); i++)
 		{
 		{
-			indices[i] = meshData->getIndices32(i);
+			indices[i] = meshData->getIndices32() + subMeshes[i].indexOffset;
 		}
 		}
 
 
 		UINT32 lVertexCount = 0;
 		UINT32 lVertexCount = 0;

+ 4 - 2
Opts.txt

@@ -23,8 +23,6 @@ When optimizing UpdateLayout make sure to mark elements that are fully culled as
 
 
  -------------
  -------------
 
 
- Check OpenGL - There was a heap corruption the last time I tested it
-
 TransientMesh
 TransientMesh
  - Only used for writing, only dynamic, and only MAP_NO_OVERWRITE writing
  - Only used for writing, only dynamic, and only MAP_NO_OVERWRITE writing
  - Accepts starting buffer sizes, and will enlarge them as needed
  - Accepts starting buffer sizes, and will enlarge them as needed
@@ -43,6 +41,10 @@ Other possible improvements:
    sequential.
    sequential.
  - When writing to mesh vertex buffer that requires a color flip I need to create a temporary copy of the entire buffer. It would be better to handle this differently. 
  - When writing to mesh vertex buffer that requires a color flip I need to create a temporary copy of the entire buffer. It would be better to handle this differently. 
 
 
+SubMesh
+ - Needs default submesh for when the user doesn't set any (just returns entire index range). Needs to be added to RTTI as well
+ - Remove draw op from MeshData and add it to Mesh constructor
+
  Problem with Texture::allocateSubresourceBuffer
  Problem with Texture::allocateSubresourceBuffer
  - It relies on format being accurate, however it is only accurate after texture has been created on the core thread. Which means if I call that before texture is created I will get a buffer of incorrect size.
  - It relies on format being accurate, however it is only accurate after texture has been created on the core thread. Which means if I call that before texture is created I will get a buffer of incorrect size.
    - I should probably ensure that parameters provided to Texture are accurate and don't change while on core thread. Probably deal with them inside TextureManager.
    - I should probably ensure that parameters provided to Texture are accurate and don't change while on core thread. Probably deal with them inside TextureManager.