Просмотр исходного кода

Fixed memory corruption issue when reading vertex data from MeshData
Fixed memory corruption issue with tangent generation code
Fixed issue with generation of a spot light mesh geometry
Proper transformation for normals/tangents in FBX importer
Fixed a crash when creating managed MeshData

BearishSun 10 лет назад
Родитель
Сommit
9e47583803

+ 419 - 419
BansheeCore/Source/BsMeshData.cpp

@@ -1,420 +1,420 @@
-#include "BsMeshData.h"
-#include "BsVector2.h"
-#include "BsVector3.h"
-#include "BsSphere.h"
-#include "BsAABox.h"
-#include "BsHardwareBufferManager.h"
-#include "BsMeshDataRTTI.h"
-#include "BsVertexDeclaration.h"
-#include "BsVertexDataDesc.h"
-#include "BsException.h"
-#include "BsDebug.h"
-
-namespace BansheeEngine
-{
-	MeshData::MeshData(UINT32 numVertices, UINT32 numIndexes, const VertexDataDescPtr& vertexData, IndexType indexType)
-	   :mNumVertices(numVertices), mNumIndices(numIndexes), mVertexData(vertexData), mIndexType(indexType)
-	{
-		allocateInternalBuffer();
-	}
-
-	MeshData::MeshData()
-		:mNumVertices(0), mNumIndices(0), mIndexType(IT_32BIT)
-	{ }
-
-	MeshData::~MeshData()
-	{ }
-
-	UINT32 MeshData::getNumIndices() const
-	{
-		return mNumIndices;
-	}
-
-	UINT16* MeshData::getIndices16() const
-	{
-		if(mIndexType != IT_16BIT)
-			BS_EXCEPT(InternalErrorException, "Attempting to get 16bit index buffer, but internally allocated buffer is 32 bit.");
-
-		UINT32 indexBufferOffset = getIndexBufferOffset();
-
-		return (UINT16*)(getData() + indexBufferOffset);
-	}
-
-	UINT32* MeshData::getIndices32() const
-	{
-		if(mIndexType != IT_32BIT)
-			BS_EXCEPT(InternalErrorException, "Attempting to get 32bit index buffer, but internally allocated buffer is 16 bit.");
-
-		UINT32 indexBufferOffset = getIndexBufferOffset();
-
-		return (UINT32*)(getData() + indexBufferOffset);
-	}
-
-	UINT32 MeshData::getInternalBufferSize() const
-	{
-		return getIndexBufferSize() + getStreamSize();
-	}
-
-	// TODO - This doesn't handle the case where multiple elements in same slot have different data types
-	MeshDataPtr MeshData::combine(const Vector<MeshDataPtr>& meshes, const Vector<Vector<SubMesh>>& allSubMeshes, 
-		Vector<SubMesh>& subMeshes)
-	{
-		UINT32 totalVertexCount = 0;
-		UINT32 totalIndexCount = 0;
-		for(auto& meshData : meshes)
-		{
-			totalVertexCount += meshData->getNumVertices();
-			totalIndexCount += meshData->getNumIndices();
-		}
-
-		VertexDataDescPtr vertexData = bs_shared_ptr_new<VertexDataDesc>();
-		
-		Vector<VertexElement> combinedVertexElements;
-		for(auto& meshData : meshes)
-		{
-			for(UINT32 i = 0; i < meshData->getVertexDesc()->getNumElements(); i++)
-			{
-				const VertexElement& newElement = meshData->getVertexDesc()->getElement(i);
-
-				INT32 alreadyExistsIdx = -1;
-				UINT32 idx = 0;
-
-				for(auto& existingElement : combinedVertexElements)
-				{
-					if(newElement.getSemantic() == existingElement.getSemantic() && newElement.getSemanticIdx() == existingElement.getSemanticIdx()
-						&& newElement.getStreamIdx() == existingElement.getStreamIdx())
-					{
-						if(newElement.getType() != existingElement.getType())
-						{
-							BS_EXCEPT(NotImplementedException, "Two elements have same semantics but different types. This is not supported.");
-						}
-
-						alreadyExistsIdx = idx;
-						break;
-					}
-
-					idx++;
-				}
-
-				if(alreadyExistsIdx == -1)
-				{
-					combinedVertexElements.push_back(newElement);
-					vertexData->addVertElem(newElement.getType(), newElement.getSemantic(), newElement.getSemanticIdx(), newElement.getStreamIdx());
-				}
-			}
-		}
-
-		MeshDataPtr combinedMeshData = bs_shared_ptr_new<MeshData>(totalVertexCount, totalIndexCount, vertexData);
-
-		// Copy indices
-		UINT32 vertexOffset = 0;
-		UINT32 indexOffset = 0;
-		UINT32* idxPtr = combinedMeshData->getIndices32();
-		for(auto& meshData : meshes)
-		{
-			UINT32 numIndices = meshData->getNumIndices();
-			UINT32* srcData = meshData->getIndices32();
-
-			for(UINT32 j = 0; j < numIndices; j++)
-				idxPtr[j] = srcData[j] + vertexOffset;
-
-			indexOffset += numIndices;
-			idxPtr += numIndices;
-			vertexOffset += meshData->getNumVertices();
-		}
-
-		// Copy sub-meshes
-		UINT32 meshIdx = 0;
-		indexOffset = 0;
-		for(auto& meshData : meshes)
-		{
-			UINT32 numIndices = meshData->getNumIndices();
-			const Vector<SubMesh> curSubMeshes = allSubMeshes[meshIdx];
-
-			for(auto& subMesh : curSubMeshes)
-			{
-				subMeshes.push_back(SubMesh(subMesh.indexOffset + indexOffset, subMesh.indexCount, subMesh.drawOp));
-			}
-
-			indexOffset += numIndices;
-			meshIdx++;
-		}
-
-		// Copy vertices
-		vertexOffset = 0;
-		for(auto& meshData : meshes)
-		{
-			for(auto& element : combinedVertexElements)
-			{
-				UINT32 dstVertexStride = vertexData->getVertexStride(element.getStreamIdx());
-				UINT8* dstData = combinedMeshData->getElementData(element.getSemantic(), element.getSemanticIdx(), element.getStreamIdx());
-				dstData += vertexOffset * dstVertexStride;
-
-				UINT32 numSrcVertices = meshData->getNumVertices();
-				UINT32 vertexSize = vertexData->getElementSize(element.getSemantic(), element.getSemanticIdx(), element.getStreamIdx());
-
-				if(meshData->getVertexDesc()->hasElement(element.getSemantic(), element.getSemanticIdx(), element.getStreamIdx()))
-				{
-					UINT32 srcVertexStride = vertexData->getVertexStride(element.getStreamIdx());
-					UINT8* srcData = meshData->getElementData(element.getSemantic(), element.getSemanticIdx(), element.getStreamIdx());
-
-					for(UINT32 i = 0; i < numSrcVertices; i++)
-					{
-						memcpy(dstData, srcData, vertexSize);
-						dstData += dstVertexStride;
-						srcData += srcVertexStride;
-					}
-				}
-				else
-				{
-					for(UINT32 i = 0; i < numSrcVertices; i++)
-					{
-						memset(dstData, 0, vertexSize);
-						dstData += dstVertexStride;
-					}
-				}
-			}
-
-			vertexOffset += meshData->getNumVertices();
-		}
-
-		return combinedMeshData;
-	}
-
-	void MeshData::setVertexData(VertexElementSemantic semantic, UINT8* data, UINT32 size, UINT32 semanticIdx, UINT32 streamIdx)
-	{
-		assert(data != nullptr);
-
-		if(!mVertexData->hasElement(semantic, semanticIdx, streamIdx))
-		{
-			LOGWRN("MeshData doesn't contain an element of specified type: Semantic: " + toString(semantic) + ", Semantic index: "
-				+ toString(semanticIdx) + ", Stream index: " + toString(streamIdx));
-			return;
-		}
-
-		UINT32 elementSize = mVertexData->getElementSize(semantic, semanticIdx, streamIdx);
-		UINT32 totalSize = elementSize * mNumVertices;
-
-		if(totalSize != size)
-		{
-			BS_EXCEPT(InvalidParametersException, "Buffer sizes don't match. Expected: " + toString(totalSize) + ". Got: " + toString(size));
-		}
-
-		UINT32 indexBufferOffset = getIndexBufferSize();
-
-		UINT32 elementOffset = getElementOffset(semantic, semanticIdx, streamIdx);
-		UINT32 vertexStride = mVertexData->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;
-		}
-	}
-
-	void MeshData::getVertexData(VertexElementSemantic semantic, UINT8* data, UINT32 size, UINT32 semanticIdx, UINT32 streamIdx)
-	{
-		assert(data != nullptr);
-
-		if (!mVertexData->hasElement(semantic, semanticIdx, streamIdx))
-		{
-			LOGWRN("MeshData doesn't contain an element of specified type: Semantic: " + toString(semantic) + ", Semantic index: "
-				+ toString(semanticIdx) + ", Stream index: " + toString(streamIdx));
-			return;
-		}
-
-		UINT32 elementSize = mVertexData->getElementSize(semantic, semanticIdx, streamIdx);
-		UINT32 totalSize = elementSize * mNumVertices;
-
-		if (totalSize != size)
-		{
-			BS_EXCEPT(InvalidParametersException, "Buffer sizes don't match. Expected: " + toString(totalSize) + ". Got: " + toString(size));
-		}
-
-		UINT32 indexBufferOffset = getIndexBufferSize();
-
-		UINT32 elementOffset = getElementOffset(semantic, semanticIdx, streamIdx);
-		UINT32 vertexStride = mVertexData->getVertexStride(streamIdx);
-
-		UINT8* src = getData() + indexBufferOffset + elementOffset;
-		UINT8* dst = data;
-		for (UINT32 i = 0; i < mNumVertices; i++)
-		{
-			memcpy(dst, src, elementSize);
-			dst += vertexStride;
-			src += elementSize;
-		}
-	}
-
-	VertexElemIter<Vector2> MeshData::getVec2DataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
-	{
-		UINT8* data;
-		UINT32 vertexStride;
-		getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride);
-
-		return VertexElemIter<Vector2>(data, vertexStride, mNumVertices);
-	}
-
-	VertexElemIter<Vector3> MeshData::getVec3DataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
-	{
-		UINT8* data;
-		UINT32 vertexStride;
-		getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride);
-
-		return VertexElemIter<Vector3>(data, vertexStride, mNumVertices);
-	}
-
-	VertexElemIter<Vector4> MeshData::getVec4DataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
-	{
-		UINT8* data;
-		UINT32 vertexStride;
-		getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride);
-
-		return VertexElemIter<Vector4>(data, vertexStride, mNumVertices);
-	}
-
-	VertexElemIter<UINT32> MeshData::getDWORDDataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
-	{
-		UINT8* data;
-		UINT32 vertexStride;
-		getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride);
-
-		return VertexElemIter<UINT32>(data, vertexStride, mNumVertices);
-	}
-
-	void MeshData::getDataForIterator(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx, UINT8*& data, UINT32& stride) const
-	{
-		if(!mVertexData->hasElement(semantic, semanticIdx, streamIdx))
-		{
-			BS_EXCEPT(InvalidParametersException, "MeshData doesn't contain an element of specified type: Semantic: " + toString(semantic) + ", Semantic index: "
-				+ toString(semanticIdx) + ", Stream index: " + toString(streamIdx));
-		}
-
-		UINT32 indexBufferOffset = getIndexBufferSize();
-
-		UINT32 elementOffset = getElementOffset(semantic, semanticIdx, streamIdx);
-
-		data = getData() + indexBufferOffset + elementOffset;
-		stride = mVertexData->getVertexStride(streamIdx);
-	}
-
-	UINT32 MeshData::getIndexBufferOffset() const
-	{
-		return 0;
-	}
-
-	UINT32 MeshData::getStreamOffset(UINT32 streamIdx) const
-	{
-		UINT32 streamOffset = mVertexData->getStreamOffset(streamIdx);
-
-		return streamOffset * mNumVertices;
-	}
-
-	UINT8* MeshData::getElementData(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const
-	{ 
-		return getData() + getIndexBufferSize() + getElementOffset(semantic, semanticIdx, streamIdx); 
-	}
-
-	UINT8* MeshData::getStreamData(UINT32 streamIdx) const
-	{ 
-		return getData() + getIndexBufferSize() + getStreamOffset(streamIdx); 
-	}
-
-	UINT32 MeshData::getIndexElementSize() const
-	{
-		return mIndexType == IT_32BIT ? sizeof(UINT32) : sizeof(UINT16);
-	}
-
-	UINT32 MeshData::getElementOffset(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const
-	{
-		return getStreamOffset(streamIdx) + mVertexData->getElementOffsetFromStream(semantic, semanticIdx, streamIdx);
-	}
-
-	UINT32 MeshData::getIndexBufferSize() const
-	{ 
-		return mNumIndices * getIndexElementSize(); 
-	}
-
-	UINT32 MeshData::getStreamSize(UINT32 streamIdx) const
-	{
-		return mVertexData->getVertexStride(streamIdx) * mNumVertices;
-	}
-
-	UINT32 MeshData::getStreamSize() const
-	{
-		return mVertexData->getVertexStride() * mNumVertices;
-	}
-
-	Bounds MeshData::calculateBounds() const
-	{
-		Bounds bounds;
-
-		VertexDataDescPtr vertexDesc = getVertexDesc();
-		for (UINT32 i = 0; i < vertexDesc->getNumElements(); i++)
-		{
-			const VertexElement& curElement = vertexDesc->getElement(i);
-
-			if (curElement.getSemantic() != VES_POSITION || (curElement.getType() != VET_FLOAT3 && curElement.getType() != VET_FLOAT4))
-				continue;
-
-			UINT8* data = getElementData(curElement.getSemantic(), curElement.getSemanticIdx(), curElement.getStreamIdx());
-			UINT32 stride = vertexDesc->getVertexStride(curElement.getStreamIdx());
-
-			if (getNumVertices() > 0)
-			{
-				Vector3 accum;
-				Vector3 min;
-				Vector3 max;
-
-				Vector3 curPosition = *(Vector3*)data;
-				accum = curPosition;
-				min = curPosition;
-				max = curPosition;
-
-				for (UINT32 i = 1; i < getNumVertices(); i++)
-				{
-					curPosition = *(Vector3*)(data + stride * i);
-					accum += curPosition;
-					min = Vector3::min(min, curPosition);
-					max = Vector3::max(max, curPosition);
-				}
-
-				Vector3 center = accum / (float)getNumVertices();
-				float radiusSqrd = 0.0f;
-
-				for (UINT32 i = 0; i < getNumVertices(); i++)
-				{
-					curPosition = *(Vector3*)(data + stride * i);
-					float dist = center.squaredDistance(curPosition);
-
-					if (dist > radiusSqrd)
-						radiusSqrd = dist;
-				}
-
-				float radius = Math::sqrt(radiusSqrd);
-
-				bounds = Bounds(AABox(min, max), Sphere(center, radius));
-				break;
-			}
-		}
-
-		return bounds;
-	}
-
-	/************************************************************************/
-	/* 								SERIALIZATION                      		*/
-	/************************************************************************/
-
-	RTTITypeBase* MeshData::getRTTIStatic()
-	{
-		return MeshDataRTTI::instance();
-	}
-
-	RTTITypeBase* MeshData::getRTTI() const
-	{
-		return MeshData::getRTTIStatic();
-	}
+#include "BsMeshData.h"
+#include "BsVector2.h"
+#include "BsVector3.h"
+#include "BsSphere.h"
+#include "BsAABox.h"
+#include "BsHardwareBufferManager.h"
+#include "BsMeshDataRTTI.h"
+#include "BsVertexDeclaration.h"
+#include "BsVertexDataDesc.h"
+#include "BsException.h"
+#include "BsDebug.h"
+
+namespace BansheeEngine
+{
+	MeshData::MeshData(UINT32 numVertices, UINT32 numIndexes, const VertexDataDescPtr& vertexData, IndexType indexType)
+	   :mNumVertices(numVertices), mNumIndices(numIndexes), mVertexData(vertexData), mIndexType(indexType)
+	{
+		allocateInternalBuffer();
+	}
+
+	MeshData::MeshData()
+		:mNumVertices(0), mNumIndices(0), mIndexType(IT_32BIT)
+	{ }
+
+	MeshData::~MeshData()
+	{ }
+
+	UINT32 MeshData::getNumIndices() const
+	{
+		return mNumIndices;
+	}
+
+	UINT16* MeshData::getIndices16() const
+	{
+		if(mIndexType != IT_16BIT)
+			BS_EXCEPT(InternalErrorException, "Attempting to get 16bit index buffer, but internally allocated buffer is 32 bit.");
+
+		UINT32 indexBufferOffset = getIndexBufferOffset();
+
+		return (UINT16*)(getData() + indexBufferOffset);
+	}
+
+	UINT32* MeshData::getIndices32() const
+	{
+		if(mIndexType != IT_32BIT)
+			BS_EXCEPT(InternalErrorException, "Attempting to get 32bit index buffer, but internally allocated buffer is 16 bit.");
+
+		UINT32 indexBufferOffset = getIndexBufferOffset();
+
+		return (UINT32*)(getData() + indexBufferOffset);
+	}
+
+	UINT32 MeshData::getInternalBufferSize() const
+	{
+		return getIndexBufferSize() + getStreamSize();
+	}
+
+	// TODO - This doesn't handle the case where multiple elements in same slot have different data types
+	MeshDataPtr MeshData::combine(const Vector<MeshDataPtr>& meshes, const Vector<Vector<SubMesh>>& allSubMeshes, 
+		Vector<SubMesh>& subMeshes)
+	{
+		UINT32 totalVertexCount = 0;
+		UINT32 totalIndexCount = 0;
+		for(auto& meshData : meshes)
+		{
+			totalVertexCount += meshData->getNumVertices();
+			totalIndexCount += meshData->getNumIndices();
+		}
+
+		VertexDataDescPtr vertexData = bs_shared_ptr_new<VertexDataDesc>();
+		
+		Vector<VertexElement> combinedVertexElements;
+		for(auto& meshData : meshes)
+		{
+			for(UINT32 i = 0; i < meshData->getVertexDesc()->getNumElements(); i++)
+			{
+				const VertexElement& newElement = meshData->getVertexDesc()->getElement(i);
+
+				INT32 alreadyExistsIdx = -1;
+				UINT32 idx = 0;
+
+				for(auto& existingElement : combinedVertexElements)
+				{
+					if(newElement.getSemantic() == existingElement.getSemantic() && newElement.getSemanticIdx() == existingElement.getSemanticIdx()
+						&& newElement.getStreamIdx() == existingElement.getStreamIdx())
+					{
+						if(newElement.getType() != existingElement.getType())
+						{
+							BS_EXCEPT(NotImplementedException, "Two elements have same semantics but different types. This is not supported.");
+						}
+
+						alreadyExistsIdx = idx;
+						break;
+					}
+
+					idx++;
+				}
+
+				if(alreadyExistsIdx == -1)
+				{
+					combinedVertexElements.push_back(newElement);
+					vertexData->addVertElem(newElement.getType(), newElement.getSemantic(), newElement.getSemanticIdx(), newElement.getStreamIdx());
+				}
+			}
+		}
+
+		MeshDataPtr combinedMeshData = bs_shared_ptr_new<MeshData>(totalVertexCount, totalIndexCount, vertexData);
+
+		// Copy indices
+		UINT32 vertexOffset = 0;
+		UINT32 indexOffset = 0;
+		UINT32* idxPtr = combinedMeshData->getIndices32();
+		for(auto& meshData : meshes)
+		{
+			UINT32 numIndices = meshData->getNumIndices();
+			UINT32* srcData = meshData->getIndices32();
+
+			for(UINT32 j = 0; j < numIndices; j++)
+				idxPtr[j] = srcData[j] + vertexOffset;
+
+			indexOffset += numIndices;
+			idxPtr += numIndices;
+			vertexOffset += meshData->getNumVertices();
+		}
+
+		// Copy sub-meshes
+		UINT32 meshIdx = 0;
+		indexOffset = 0;
+		for(auto& meshData : meshes)
+		{
+			UINT32 numIndices = meshData->getNumIndices();
+			const Vector<SubMesh> curSubMeshes = allSubMeshes[meshIdx];
+
+			for(auto& subMesh : curSubMeshes)
+			{
+				subMeshes.push_back(SubMesh(subMesh.indexOffset + indexOffset, subMesh.indexCount, subMesh.drawOp));
+			}
+
+			indexOffset += numIndices;
+			meshIdx++;
+		}
+
+		// Copy vertices
+		vertexOffset = 0;
+		for(auto& meshData : meshes)
+		{
+			for(auto& element : combinedVertexElements)
+			{
+				UINT32 dstVertexStride = vertexData->getVertexStride(element.getStreamIdx());
+				UINT8* dstData = combinedMeshData->getElementData(element.getSemantic(), element.getSemanticIdx(), element.getStreamIdx());
+				dstData += vertexOffset * dstVertexStride;
+
+				UINT32 numSrcVertices = meshData->getNumVertices();
+				UINT32 vertexSize = vertexData->getElementSize(element.getSemantic(), element.getSemanticIdx(), element.getStreamIdx());
+
+				if(meshData->getVertexDesc()->hasElement(element.getSemantic(), element.getSemanticIdx(), element.getStreamIdx()))
+				{
+					UINT32 srcVertexStride = vertexData->getVertexStride(element.getStreamIdx());
+					UINT8* srcData = meshData->getElementData(element.getSemantic(), element.getSemanticIdx(), element.getStreamIdx());
+
+					for(UINT32 i = 0; i < numSrcVertices; i++)
+					{
+						memcpy(dstData, srcData, vertexSize);
+						dstData += dstVertexStride;
+						srcData += srcVertexStride;
+					}
+				}
+				else
+				{
+					for(UINT32 i = 0; i < numSrcVertices; i++)
+					{
+						memset(dstData, 0, vertexSize);
+						dstData += dstVertexStride;
+					}
+				}
+			}
+
+			vertexOffset += meshData->getNumVertices();
+		}
+
+		return combinedMeshData;
+	}
+
+	void MeshData::setVertexData(VertexElementSemantic semantic, UINT8* data, UINT32 size, UINT32 semanticIdx, UINT32 streamIdx)
+	{
+		assert(data != nullptr);
+
+		if(!mVertexData->hasElement(semantic, semanticIdx, streamIdx))
+		{
+			LOGWRN("MeshData doesn't contain an element of specified type: Semantic: " + toString(semantic) + ", Semantic index: "
+				+ toString(semanticIdx) + ", Stream index: " + toString(streamIdx));
+			return;
+		}
+
+		UINT32 elementSize = mVertexData->getElementSize(semantic, semanticIdx, streamIdx);
+		UINT32 totalSize = elementSize * mNumVertices;
+
+		if(totalSize != size)
+		{
+			BS_EXCEPT(InvalidParametersException, "Buffer sizes don't match. Expected: " + toString(totalSize) + ". Got: " + toString(size));
+		}
+
+		UINT32 indexBufferOffset = getIndexBufferSize();
+
+		UINT32 elementOffset = getElementOffset(semantic, semanticIdx, streamIdx);
+		UINT32 vertexStride = mVertexData->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;
+		}
+	}
+
+	void MeshData::getVertexData(VertexElementSemantic semantic, UINT8* data, UINT32 size, UINT32 semanticIdx, UINT32 streamIdx)
+	{
+		assert(data != nullptr);
+
+		if (!mVertexData->hasElement(semantic, semanticIdx, streamIdx))
+		{
+			LOGWRN("MeshData doesn't contain an element of specified type: Semantic: " + toString(semantic) + ", Semantic index: "
+				+ toString(semanticIdx) + ", Stream index: " + toString(streamIdx));
+			return;
+		}
+
+		UINT32 elementSize = mVertexData->getElementSize(semantic, semanticIdx, streamIdx);
+		UINT32 totalSize = elementSize * mNumVertices;
+
+		if (totalSize != size)
+		{
+			BS_EXCEPT(InvalidParametersException, "Buffer sizes don't match. Expected: " + toString(totalSize) + ". Got: " + toString(size));
+		}
+
+		UINT32 indexBufferOffset = getIndexBufferSize();
+
+		UINT32 elementOffset = getElementOffset(semantic, semanticIdx, streamIdx);
+		UINT32 vertexStride = mVertexData->getVertexStride(streamIdx);
+
+		UINT8* src = getData() + indexBufferOffset + elementOffset;
+		UINT8* dst = data;
+		for (UINT32 i = 0; i < mNumVertices; i++)
+		{
+			memcpy(dst, src, elementSize);
+			dst += elementSize;
+			src += vertexStride;
+		}
+	}
+
+	VertexElemIter<Vector2> MeshData::getVec2DataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
+	{
+		UINT8* data;
+		UINT32 vertexStride;
+		getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride);
+
+		return VertexElemIter<Vector2>(data, vertexStride, mNumVertices);
+	}
+
+	VertexElemIter<Vector3> MeshData::getVec3DataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
+	{
+		UINT8* data;
+		UINT32 vertexStride;
+		getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride);
+
+		return VertexElemIter<Vector3>(data, vertexStride, mNumVertices);
+	}
+
+	VertexElemIter<Vector4> MeshData::getVec4DataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
+	{
+		UINT8* data;
+		UINT32 vertexStride;
+		getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride);
+
+		return VertexElemIter<Vector4>(data, vertexStride, mNumVertices);
+	}
+
+	VertexElemIter<UINT32> MeshData::getDWORDDataIter(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx)
+	{
+		UINT8* data;
+		UINT32 vertexStride;
+		getDataForIterator(semantic, semanticIdx, streamIdx, data, vertexStride);
+
+		return VertexElemIter<UINT32>(data, vertexStride, mNumVertices);
+	}
+
+	void MeshData::getDataForIterator(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx, UINT8*& data, UINT32& stride) const
+	{
+		if(!mVertexData->hasElement(semantic, semanticIdx, streamIdx))
+		{
+			BS_EXCEPT(InvalidParametersException, "MeshData doesn't contain an element of specified type: Semantic: " + toString(semantic) + ", Semantic index: "
+				+ toString(semanticIdx) + ", Stream index: " + toString(streamIdx));
+		}
+
+		UINT32 indexBufferOffset = getIndexBufferSize();
+
+		UINT32 elementOffset = getElementOffset(semantic, semanticIdx, streamIdx);
+
+		data = getData() + indexBufferOffset + elementOffset;
+		stride = mVertexData->getVertexStride(streamIdx);
+	}
+
+	UINT32 MeshData::getIndexBufferOffset() const
+	{
+		return 0;
+	}
+
+	UINT32 MeshData::getStreamOffset(UINT32 streamIdx) const
+	{
+		UINT32 streamOffset = mVertexData->getStreamOffset(streamIdx);
+
+		return streamOffset * mNumVertices;
+	}
+
+	UINT8* MeshData::getElementData(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const
+	{ 
+		return getData() + getIndexBufferSize() + getElementOffset(semantic, semanticIdx, streamIdx); 
+	}
+
+	UINT8* MeshData::getStreamData(UINT32 streamIdx) const
+	{ 
+		return getData() + getIndexBufferSize() + getStreamOffset(streamIdx); 
+	}
+
+	UINT32 MeshData::getIndexElementSize() const
+	{
+		return mIndexType == IT_32BIT ? sizeof(UINT32) : sizeof(UINT16);
+	}
+
+	UINT32 MeshData::getElementOffset(VertexElementSemantic semantic, UINT32 semanticIdx, UINT32 streamIdx) const
+	{
+		return getStreamOffset(streamIdx) + mVertexData->getElementOffsetFromStream(semantic, semanticIdx, streamIdx);
+	}
+
+	UINT32 MeshData::getIndexBufferSize() const
+	{ 
+		return mNumIndices * getIndexElementSize(); 
+	}
+
+	UINT32 MeshData::getStreamSize(UINT32 streamIdx) const
+	{
+		return mVertexData->getVertexStride(streamIdx) * mNumVertices;
+	}
+
+	UINT32 MeshData::getStreamSize() const
+	{
+		return mVertexData->getVertexStride() * mNumVertices;
+	}
+
+	Bounds MeshData::calculateBounds() const
+	{
+		Bounds bounds;
+
+		VertexDataDescPtr vertexDesc = getVertexDesc();
+		for (UINT32 i = 0; i < vertexDesc->getNumElements(); i++)
+		{
+			const VertexElement& curElement = vertexDesc->getElement(i);
+
+			if (curElement.getSemantic() != VES_POSITION || (curElement.getType() != VET_FLOAT3 && curElement.getType() != VET_FLOAT4))
+				continue;
+
+			UINT8* data = getElementData(curElement.getSemantic(), curElement.getSemanticIdx(), curElement.getStreamIdx());
+			UINT32 stride = vertexDesc->getVertexStride(curElement.getStreamIdx());
+
+			if (getNumVertices() > 0)
+			{
+				Vector3 accum;
+				Vector3 min;
+				Vector3 max;
+
+				Vector3 curPosition = *(Vector3*)data;
+				accum = curPosition;
+				min = curPosition;
+				max = curPosition;
+
+				for (UINT32 i = 1; i < getNumVertices(); i++)
+				{
+					curPosition = *(Vector3*)(data + stride * i);
+					accum += curPosition;
+					min = Vector3::min(min, curPosition);
+					max = Vector3::max(max, curPosition);
+				}
+
+				Vector3 center = accum / (float)getNumVertices();
+				float radiusSqrd = 0.0f;
+
+				for (UINT32 i = 0; i < getNumVertices(); i++)
+				{
+					curPosition = *(Vector3*)(data + stride * i);
+					float dist = center.squaredDistance(curPosition);
+
+					if (dist > radiusSqrd)
+						radiusSqrd = dist;
+				}
+
+				float radius = Math::sqrt(radiusSqrd);
+
+				bounds = Bounds(AABox(min, max), Sphere(center, radius));
+				break;
+			}
+		}
+
+		return bounds;
+	}
+
+	/************************************************************************/
+	/* 								SERIALIZATION                      		*/
+	/************************************************************************/
+
+	RTTITypeBase* MeshData::getRTTIStatic()
+	{
+		return MeshDataRTTI::instance();
+	}
+
+	RTTITypeBase* MeshData::getRTTI() const
+	{
+		return MeshData::getRTTIStatic();
+	}
 }

+ 203 - 202
BansheeCore/Source/BsMeshUtility.cpp

@@ -1,203 +1,204 @@
-#include "BsMeshUtility.h"
-#include "BsVector3.h"
-#include "BsVector2.h"
-
-namespace BansheeEngine
-{
-	struct VertexFaces
-	{
-		UINT32* faces;
-		UINT32 numFaces = 0;
-	};
-
-	struct VertexConnectivity
-	{
-		VertexConnectivity(UINT8* indices, UINT32 numVertices, UINT32 numFaces, UINT32 indexSize)
-			:vertexFaces(nullptr), mMaxFacesPerVertex(0), mFaces(nullptr), mNumVertices(numVertices)
-		{
-			vertexFaces = bs_newN<VertexFaces>(numVertices);
-
-			resizeFaceArray(10);
-
-			for (UINT32 i = 0; i < numFaces; i++)
-			{
-				for (UINT32 j = 0; j < 3; j++)
-				{
-					UINT32 idx = i * 3 + j;
-					UINT32 vertexIdx = 0;
-					memcpy(&vertexIdx, indices + idx * indexSize, indexSize);
-
-					VertexFaces& faces = vertexFaces[vertexIdx];
-					if (faces.numFaces >= mMaxFacesPerVertex)
-						resizeFaceArray(mMaxFacesPerVertex * 2);
-
-					faces.faces[faces.numFaces] = i;
-					faces.numFaces++;
-				}
-			}
-		}
-
-		~VertexConnectivity()
-		{
-			if (vertexFaces != nullptr)
-				bs_deleteN(vertexFaces, mNumVertices);
-
-			if (mFaces != nullptr)
-				bs_free(mFaces);
-		}
-
-		VertexFaces* vertexFaces;
-
-	private:
-		void resizeFaceArray(UINT32 numFaces)
-		{
-			UINT32* newFaces = (UINT32*)bs_alloc(numFaces * mNumVertices);
-
-			if (mFaces != nullptr)
-			{
-				for (UINT32 i = 0; i < mNumVertices; i++)
-					memcpy(newFaces + (i * numFaces), mFaces + (i * mMaxFacesPerVertex), mMaxFacesPerVertex * sizeof(UINT32));
-
-				bs_free(mFaces);
-			}
-
-			for (UINT32 i = 0; i < mNumVertices; i++)
-				vertexFaces[i].faces = newFaces + (i * numFaces);
-
-			mFaces = newFaces;
-			mMaxFacesPerVertex = numFaces;
-		}
-
-		UINT32 mMaxFacesPerVertex;
-		UINT32 mNumVertices;
-		UINT32* mFaces;
-	};
-
-	void MeshUtility::calculateNormals(Vector3* vertices, UINT8* indices, UINT32 numVertices,
-		UINT32 numIndices, Vector3* normals, UINT32 indexSize)
-	{
-		UINT32 numFaces = numIndices / 3;
-
-		Vector3* faceNormals = bs_newN<Vector3>(numFaces);
-		for (UINT32 i = 0; i < numFaces; i++)
-		{
-			UINT32 triangle[3];
-			memcpy(&triangle[0], indices + (i * 3 + 0) * indexSize, indexSize);
-			memcpy(&triangle[1], indices + (i * 3 + 1) * indexSize, indexSize);
-			memcpy(&triangle[2], indices + (i * 3 + 2) * indexSize, indexSize);
-
-			Vector3 edgeA = vertices[triangle[1]] - vertices[triangle[0]];
-			Vector3 edgeB = vertices[triangle[2]] - vertices[triangle[0]];
-			faceNormals[i] = Vector3::normalize(Vector3::cross(edgeA, edgeB));
-
-			// Note: Potentially don't normalize here in order to weigh the normals
-			// by triangle size
-		}
-
-		VertexConnectivity connectivity(indices, numVertices, numFaces, indexSize);
-		for (UINT32 i = 0; i < numVertices; i++)
-		{
-			VertexFaces& faces = connectivity.vertexFaces[i];
-
-			for (UINT32 j = 0; j < faces.numFaces; j++)
-			{
-				UINT32 faceIdx = faces.faces[j];
-				normals[i] += faceNormals[faceIdx];
-			}
-
-			normals[i].normalize();
-		}
-
-		bs_deleteN(faceNormals, numFaces);
-	}
-
-	void MeshUtility::calculateTangents(Vector3* vertices, Vector3* normals, Vector2* uv, UINT8* indices, UINT32 numVertices,
-		UINT32 numIndices, Vector3* tangents, Vector3* bitangents, UINT32 indexSize)
-	{
-		UINT32 numFaces = numIndices / 3;
-
-		Vector3* faceTangents = bs_newN<Vector3>(numFaces);
-		Vector3* faceBitangents = bs_newN<Vector3>(numFaces);
-		for (UINT32 i = 0; i < numFaces; i++)
-		{
-			UINT32 triangle[3];
-			memcpy(&triangle[0], indices + (i * 3 + 0) * indexSize, indexSize);
-			memcpy(&triangle[1], indices + (i * 3 + 1) * indexSize, indexSize);
-			memcpy(&triangle[2], indices + (i * 3 + 2) * indexSize, indexSize);
-
-			Vector3 p0 = vertices[triangle[0]];
-			Vector3 p1 = vertices[triangle[1]];
-			Vector3 p2 = vertices[triangle[2]];
-
-			Vector2 uv0 = uv[triangle[0]];
-			Vector2 uv1 = uv[triangle[1]];
-			Vector2 uv2 = uv[triangle[2]];
-
-			Vector3 q0 = p1 - p0;
-			Vector3 q1 = p2 - p0;
-
-			Vector2 s;
-			s.x = uv1.x - uv0.x;
-			s.y = uv2.x - uv0.x;
-
-			Vector2 t;
-			t.x = uv1.y - uv0.y;
-			t.y = uv2.y - uv0.y;
-
-			float denom = s.x*t.y - s.y * t.x;
-			if (fabs(denom) >= 0e-8f)
-			{
-				float r = 1.0f / denom;
-				s *= r;
-				t *= r;
-
-				faceTangents[i] = t.y * q0 - t.x * q1;
-				faceBitangents[i] = s.x * q0 - s.y * q1;
-
-				faceTangents[i].normalize();
-				faceBitangents[i].normalize();
-			}
-
-			// Note: Potentially don't normalize here in order to weigh the normals
-			// by triangle size
-		}
-
-		VertexConnectivity connectivity(indices, numVertices, numFaces, indexSize);
-		for (UINT32 i = 0; i < numVertices; i++)
-		{
-			VertexFaces& faces = connectivity.vertexFaces[i];
-
-			for (UINT32 j = 0; j < faces.numFaces; j++)
-			{
-				UINT32 faceIdx = faces.faces[j];
-				tangents[i] += faceTangents[faceIdx];
-				bitangents[i] += faceBitangents[faceIdx];
-			}
-
-			tangents[i].normalize();
-			bitangents[i].normalize();
-
-			// Orthonormalize
-			float dot0 = normals[i].dot(tangents[i]);
-			tangents[i] -= dot0*normals[i];
-			tangents[i].normalize();
-
-			float dot1 = tangents[i].dot(bitangents[i]);
-			dot0 = normals[i].dot(bitangents[i]);
-			bitangents[i] -= dot0*normals[i] + dot1*tangents[i];
-			bitangents[i].normalize();
-		}
-
-		bs_deleteN(faceTangents, numFaces);
-		bs_deleteN(faceBitangents, numFaces);
-
-		// TODO - Consider weighing tangents by triangle size and/or edge angles
-	}
-
-	void MeshUtility::calculateTangentSpace(Vector3* vertices, Vector2* uv, UINT8* indices, UINT32 numVertices,
-		UINT32 numIndices, Vector3* normals, Vector3* tangents, Vector3* bitangents, UINT32 indexSize)
-	{
-		calculateNormals(vertices, indices, numVertices, numIndices, normals, indexSize);
-		calculateTangents(vertices, normals, uv, indices, numVertices, numIndices, tangents, bitangents, indexSize);
-	}
+#include "BsMeshUtility.h"
+#include "BsVector3.h"
+#include "BsVector2.h"
+
+namespace BansheeEngine
+{
+	struct VertexFaces
+	{
+		UINT32* faces;
+		UINT32 numFaces = 0;
+	};
+
+	struct VertexConnectivity
+	{
+		VertexConnectivity(UINT8* indices, UINT32 numVertices, UINT32 numFaces, UINT32 indexSize)
+			:vertexFaces(nullptr), mMaxFacesPerVertex(0), mFaces(nullptr), mNumVertices(numVertices)
+		{
+			vertexFaces = bs_newN<VertexFaces>(numVertices);
+
+			resizeFaceArray(10);
+
+			for (UINT32 i = 0; i < numFaces; i++)
+			{
+				for (UINT32 j = 0; j < 3; j++)
+				{
+					UINT32 idx = i * 3 + j;
+					UINT32 vertexIdx = 0;
+					memcpy(&vertexIdx, indices + idx * indexSize, indexSize);
+
+					assert(vertexIdx < mNumVertices);
+					VertexFaces& faces = vertexFaces[vertexIdx];
+					if (faces.numFaces >= mMaxFacesPerVertex)
+						resizeFaceArray(mMaxFacesPerVertex * 2);
+
+					faces.faces[faces.numFaces] = i;
+					faces.numFaces++;
+				}
+			}
+		}
+
+		~VertexConnectivity()
+		{
+			if (vertexFaces != nullptr)
+				bs_deleteN(vertexFaces, mNumVertices);
+
+			if (mFaces != nullptr)
+				bs_free(mFaces);
+		}
+
+		VertexFaces* vertexFaces;
+
+	private:
+		void resizeFaceArray(UINT32 numFaces)
+		{
+			UINT32* newFaces = (UINT32*)bs_alloc(numFaces * mNumVertices * sizeof(UINT32));
+
+			if (mFaces != nullptr)
+			{
+				for (UINT32 i = 0; i < mNumVertices; i++)
+					memcpy(newFaces + (i * numFaces), mFaces + (i * mMaxFacesPerVertex), mMaxFacesPerVertex * sizeof(UINT32));
+
+				bs_free(mFaces);
+			}
+
+			for (UINT32 i = 0; i < mNumVertices; i++)
+				vertexFaces[i].faces = newFaces + (i * numFaces);
+
+			mFaces = newFaces;
+			mMaxFacesPerVertex = numFaces;
+		}
+
+		UINT32 mMaxFacesPerVertex;
+		UINT32 mNumVertices;
+		UINT32* mFaces;
+	};
+
+	void MeshUtility::calculateNormals(Vector3* vertices, UINT8* indices, UINT32 numVertices,
+		UINT32 numIndices, Vector3* normals, UINT32 indexSize)
+	{
+		UINT32 numFaces = numIndices / 3;
+
+		Vector3* faceNormals = bs_newN<Vector3>(numFaces);
+		for (UINT32 i = 0; i < numFaces; i++)
+		{
+			UINT32 triangle[3];
+			memcpy(&triangle[0], indices + (i * 3 + 0) * indexSize, indexSize);
+			memcpy(&triangle[1], indices + (i * 3 + 1) * indexSize, indexSize);
+			memcpy(&triangle[2], indices + (i * 3 + 2) * indexSize, indexSize);
+
+			Vector3 edgeA = vertices[triangle[1]] - vertices[triangle[0]];
+			Vector3 edgeB = vertices[triangle[2]] - vertices[triangle[0]];
+			faceNormals[i] = Vector3::normalize(Vector3::cross(edgeA, edgeB));
+
+			// Note: Potentially don't normalize here in order to weigh the normals
+			// by triangle size
+		}
+
+		VertexConnectivity connectivity(indices, numVertices, numFaces, indexSize);
+		for (UINT32 i = 0; i < numVertices; i++)
+		{
+			VertexFaces& faces = connectivity.vertexFaces[i];
+
+			for (UINT32 j = 0; j < faces.numFaces; j++)
+			{
+				UINT32 faceIdx = faces.faces[j];
+				normals[i] += faceNormals[faceIdx];
+			}
+
+			normals[i].normalize();
+		}
+
+		bs_deleteN(faceNormals, numFaces);
+	}
+
+	void MeshUtility::calculateTangents(Vector3* vertices, Vector3* normals, Vector2* uv, UINT8* indices, UINT32 numVertices,
+		UINT32 numIndices, Vector3* tangents, Vector3* bitangents, UINT32 indexSize)
+	{
+		UINT32 numFaces = numIndices / 3;
+
+		Vector3* faceTangents = bs_newN<Vector3>(numFaces);
+		Vector3* faceBitangents = bs_newN<Vector3>(numFaces);
+		for (UINT32 i = 0; i < numFaces; i++)
+		{
+			UINT32 triangle[3];
+			memcpy(&triangle[0], indices + (i * 3 + 0) * indexSize, indexSize);
+			memcpy(&triangle[1], indices + (i * 3 + 1) * indexSize, indexSize);
+			memcpy(&triangle[2], indices + (i * 3 + 2) * indexSize, indexSize);
+
+			Vector3 p0 = vertices[triangle[0]];
+			Vector3 p1 = vertices[triangle[1]];
+			Vector3 p2 = vertices[triangle[2]];
+
+			Vector2 uv0 = uv[triangle[0]];
+			Vector2 uv1 = uv[triangle[1]];
+			Vector2 uv2 = uv[triangle[2]];
+
+			Vector3 q0 = p1 - p0;
+			Vector3 q1 = p2 - p0;
+
+			Vector2 s;
+			s.x = uv1.x - uv0.x;
+			s.y = uv2.x - uv0.x;
+
+			Vector2 t;
+			t.x = uv1.y - uv0.y;
+			t.y = uv2.y - uv0.y;
+
+			float denom = s.x*t.y - s.y * t.x;
+			if (fabs(denom) >= 0e-8f)
+			{
+				float r = 1.0f / denom;
+				s *= r;
+				t *= r;
+
+				faceTangents[i] = t.y * q0 - t.x * q1;
+				faceBitangents[i] = s.x * q0 - s.y * q1;
+
+				faceTangents[i].normalize();
+				faceBitangents[i].normalize();
+			}
+
+			// Note: Potentially don't normalize here in order to weigh the normals
+			// by triangle size
+		}
+
+		VertexConnectivity connectivity(indices, numVertices, numFaces, indexSize);
+		for (UINT32 i = 0; i < numVertices; i++)
+		{
+			VertexFaces& faces = connectivity.vertexFaces[i];
+
+			for (UINT32 j = 0; j < faces.numFaces; j++)
+			{
+				UINT32 faceIdx = faces.faces[j];
+				tangents[i] += faceTangents[faceIdx];
+				bitangents[i] += faceBitangents[faceIdx];
+			}
+
+			tangents[i].normalize();
+			bitangents[i].normalize();
+
+			// Orthonormalize
+			float dot0 = normals[i].dot(tangents[i]);
+			tangents[i] -= dot0*normals[i];
+			tangents[i].normalize();
+
+			float dot1 = tangents[i].dot(bitangents[i]);
+			dot0 = normals[i].dot(bitangents[i]);
+			bitangents[i] -= dot0*normals[i] + dot1*tangents[i];
+			bitangents[i].normalize();
+		}
+
+		bs_deleteN(faceTangents, numFaces);
+		bs_deleteN(faceBitangents, numFaces);
+
+		// TODO - Consider weighing tangents by triangle size and/or edge angles
+	}
+
+	void MeshUtility::calculateTangentSpace(Vector3* vertices, Vector2* uv, UINT8* indices, UINT32 numVertices,
+		UINT32 numIndices, Vector3* normals, Vector3* tangents, Vector3* bitangents, UINT32 indexSize)
+	{
+		calculateNormals(vertices, indices, numVertices, numIndices, normals, indexSize);
+		calculateTangents(vertices, normals, uv, indices, numVertices, numIndices, tangents, bitangents, indexSize);
+	}
 }

+ 1 - 2
BansheeEngine/Source/BsLight.cpp

@@ -12,7 +12,7 @@ namespace BansheeEngine
 {
 	LightBase::LightBase()
 		:mType(LightType::Point), mCastsShadows(false), mRange(10.0f),
-		mIntensity(100.0f), mSpotAngle(45), mColor(Color::White), mIsActive(true)
+		mIntensity(5.0f), mSpotAngle(45), mColor(Color::White), mIsActive(true)
 	{
 		mBounds = Sphere(mPosition, mRange);
 	}
@@ -195,7 +195,6 @@ namespace BansheeEngine
 			UINT32 numVertices = LIGHT_CONE_NUM_SIDES * LIGHT_CONE_NUM_SLICES * 2;
 			UINT32 numIndices = ((LIGHT_CONE_NUM_SIDES * 2) * LIGHT_CONE_NUM_SLICES * 2) * 3;
 
-			ShapeMeshes3D::getNumElementsCone(1, numVertices, numIndices);
 			MeshDataPtr meshData = bs_shared_ptr_new<MeshData>(numVertices, numIndices, vertexDesc);
 
 			UINT32* indexData = meshData->getIndices32();

+ 7 - 4
BansheeFBXImporter/Source/BsFBXImporter.cpp

@@ -447,13 +447,14 @@ namespace BansheeEngine
 						for (UINT32 i = 0; i < (UINT32)numVertices; i++)
 						{
 							Vector3 normal = (Vector3)mesh->normals[i];
-							transformedNormals[i] = worldTransformIT.multiplyAffine(normal);
+							normal = worldTransformIT.multiplyDirection(normal);
+							transformedNormals[i] = Vector3::normalize(normal);
 
 							Vector3 tangent = (Vector3)mesh->tangents[i];
-							tangent = worldTransformIT.multiplyAffine(tangent);
+							tangent = Vector3::normalize(worldTransformIT.multiplyDirection(tangent));
 
 							Vector3 bitangent = (Vector3)mesh->bitangents[i];
-							bitangent = worldTransformIT.multiplyAffine(bitangent);
+							bitangent = worldTransformIT.multiplyDirection(bitangent);
 
 							Vector3 engineBitangent = Vector3::cross(normal, tangent);
 							float sign = Vector3::dot(engineBitangent, bitangent);
@@ -467,7 +468,7 @@ namespace BansheeEngine
 					else // Just normals
 					{
 						for (UINT32 i = 0; i < (UINT32)numVertices; i++)
-							transformedNormals[i] = worldTransformIT.multiplyAffine((Vector3)mesh->normals[i]);
+							transformedNormals[i] = Vector3::normalize(worldTransformIT.multiplyDirection((Vector3)mesh->normals[i]));
 					}
 
 					meshData->setNormals(transformedNormals, normalsSize);
@@ -509,6 +510,8 @@ namespace BansheeEngine
 					}
 				}
 
+				// TODO - Transform blend shapes?
+
 				allMeshData.push_back(meshData->getData());
 				allSubMeshes.push_back(subMeshes);
 			}

+ 142 - 142
MBansheeEngine/Light.cs

@@ -1,142 +1,142 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Runtime.CompilerServices;
-using System.Text;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Component that illuminates a portion of the scene covered by the light.
-    /// </summary>
-    [RunInEditor]
-    public sealed class Light : Component
-    {
-        private NativeLight _nativeLight;
-
-        [SerializeField]
-        private SerializableData serializableData = new SerializableData();
-
-        /// <summary>
-        /// Returns the non-component version of Light that is wrapped by this component. 
-        /// </summary>
-        internal NativeLight Native
-        {
-            get { return _nativeLight; }
-        }
-
-        /// <summary>
-        /// Light type that determines how are elements near it illuminated.
-        /// </summary>
-        public LightType Type
-        {
-            get { return _nativeLight.Type; }
-            set { _nativeLight.Type = value; serializableData.type = value; }
-        }
-
-        /// <summary>
-        /// Color emitted from the light.
-        /// </summary>
-        public Color Color
-        {
-            get { return _nativeLight.Color; }
-            set { _nativeLight.Color = value; serializableData.color = value; }
-        }
-
-        /// <summary>
-        /// Maximum range of the light. Light will not affect any geometry past that point.
-        /// </summary>
-        public float Range
-        {
-            get { return _nativeLight.Range; }
-            set { _nativeLight.Range = value; serializableData.range = value; }
-        }
-
-        /// <summary>
-        /// Power of the light source. This is luminous flux for point & spot lights, and radiance for directional lights.
-        /// </summary>
-        public float Intensity
-        {
-            get { return _nativeLight.Intensity; }
-            set { _nativeLight.Intensity = value; serializableData.intensity = value; }
-        }
-
-        /// <summary>
-        /// Total angle covered by a spot light. Ignored by other light types.
-        /// </summary>
-        public Degree SpotAngle
-        {
-            get { return _nativeLight.SpotAngle; }
-            set { _nativeLight.SpotAngle = value; serializableData.spotAngle = value; }
-        }
-
-        /// <summary>
-        /// Falloff angle covered by a spot light. Falloff angle determines at what point does light intensity starts 
-        /// linearly falling off as the angle approaches the total spot angle. Ignored by other light types.
-        /// </summary>
-        public Degree SpotFalloffAngle
-        {
-            get { return _nativeLight.SpotFalloffAngle; }
-            set { _nativeLight.SpotFalloffAngle = value; serializableData.spotFalloffAngle = value; }
-        }
-
-        /// <summary>
-        /// Determines does this light cast a shadow when rendered.
-        /// </summary>
-        public bool CastsShadow
-        {
-            get { return _nativeLight.CastsShadow; }
-            set { _nativeLight.CastsShadow = value; serializableData.castShadows = value; }
-        }
-
-        /// <summary>
-        /// Returns world space bounds that completely encompass the light's area of influence.
-        /// </summary>
-        public Sphere Bounds
-        {
-            get { Native.UpdateTransform(SceneObject); return Native.Bounds; }
-        }
-
-        private void OnReset()
-        {
-            if (_nativeLight != null)
-                _nativeLight.OnDestroy();
-
-            _nativeLight = new NativeLight(SceneObject);
-
-            // Restore saved values after reset
-            _nativeLight.Color = serializableData.color;
-            _nativeLight.SpotAngle = serializableData.spotAngle;
-            _nativeLight.SpotFalloffAngle = serializableData.spotFalloffAngle;
-            _nativeLight.Range = serializableData.range;
-            _nativeLight.Intensity = serializableData.intensity;
-            _nativeLight.Type = serializableData.type;
-            _nativeLight.CastsShadow = serializableData.castShadows;
-        }
-
-        private void OnUpdate()
-        {
-            _nativeLight.UpdateTransform(SceneObject);
-        }
-
-        private void OnDestroy()
-        {
-            _nativeLight.OnDestroy();
-        }
-
-        /// <summary>
-        /// Holds all data the light component needs to persist through serialization.
-        /// </summary>
-        [SerializeObject]
-        private class SerializableData
-        {
-            public Color color = Color.White;
-            public Degree spotAngle = new Degree(45);
-            public Degree spotFalloffAngle = new Degree(40);
-            public float range = 10.0f;
-            public float intensity = 100.0f;
-            public LightType type = LightType.Point;
-            public bool castShadows = false;
-        }
-    }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.CompilerServices;
+using System.Text;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Component that illuminates a portion of the scene covered by the light.
+    /// </summary>
+    [RunInEditor]
+    public sealed class Light : Component
+    {
+        private NativeLight _nativeLight;
+
+        [SerializeField]
+        private SerializableData serializableData = new SerializableData();
+
+        /// <summary>
+        /// Returns the non-component version of Light that is wrapped by this component. 
+        /// </summary>
+        internal NativeLight Native
+        {
+            get { return _nativeLight; }
+        }
+
+        /// <summary>
+        /// Light type that determines how are elements near it illuminated.
+        /// </summary>
+        public LightType Type
+        {
+            get { return _nativeLight.Type; }
+            set { _nativeLight.Type = value; serializableData.type = value; }
+        }
+
+        /// <summary>
+        /// Color emitted from the light.
+        /// </summary>
+        public Color Color
+        {
+            get { return _nativeLight.Color; }
+            set { _nativeLight.Color = value; serializableData.color = value; }
+        }
+
+        /// <summary>
+        /// Maximum range of the light. Light will not affect any geometry past that point.
+        /// </summary>
+        public float Range
+        {
+            get { return _nativeLight.Range; }
+            set { _nativeLight.Range = value; serializableData.range = value; }
+        }
+
+        /// <summary>
+        /// Power of the light source. This is luminous flux for point & spot lights, and radiance for directional lights.
+        /// </summary>
+        public float Intensity
+        {
+            get { return _nativeLight.Intensity; }
+            set { _nativeLight.Intensity = value; serializableData.intensity = value; }
+        }
+
+        /// <summary>
+        /// Total angle covered by a spot light. Ignored by other light types.
+        /// </summary>
+        public Degree SpotAngle
+        {
+            get { return _nativeLight.SpotAngle; }
+            set { _nativeLight.SpotAngle = value; serializableData.spotAngle = value; }
+        }
+
+        /// <summary>
+        /// Falloff angle covered by a spot light. Falloff angle determines at what point does light intensity starts 
+        /// linearly falling off as the angle approaches the total spot angle. Ignored by other light types.
+        /// </summary>
+        public Degree SpotFalloffAngle
+        {
+            get { return _nativeLight.SpotFalloffAngle; }
+            set { _nativeLight.SpotFalloffAngle = value; serializableData.spotFalloffAngle = value; }
+        }
+
+        /// <summary>
+        /// Determines does this light cast a shadow when rendered.
+        /// </summary>
+        public bool CastsShadow
+        {
+            get { return _nativeLight.CastsShadow; }
+            set { _nativeLight.CastsShadow = value; serializableData.castShadows = value; }
+        }
+
+        /// <summary>
+        /// Returns world space bounds that completely encompass the light's area of influence.
+        /// </summary>
+        public Sphere Bounds
+        {
+            get { Native.UpdateTransform(SceneObject); return Native.Bounds; }
+        }
+
+        private void OnReset()
+        {
+            if (_nativeLight != null)
+                _nativeLight.OnDestroy();
+
+            _nativeLight = new NativeLight(SceneObject);
+
+            // Restore saved values after reset
+            _nativeLight.Color = serializableData.color;
+            _nativeLight.SpotAngle = serializableData.spotAngle;
+            _nativeLight.SpotFalloffAngle = serializableData.spotFalloffAngle;
+            _nativeLight.Range = serializableData.range;
+            _nativeLight.Intensity = serializableData.intensity;
+            _nativeLight.Type = serializableData.type;
+            _nativeLight.CastsShadow = serializableData.castShadows;
+        }
+
+        private void OnUpdate()
+        {
+            _nativeLight.UpdateTransform(SceneObject);
+        }
+
+        private void OnDestroy()
+        {
+            _nativeLight.OnDestroy();
+        }
+
+        /// <summary>
+        /// Holds all data the light component needs to persist through serialization.
+        /// </summary>
+        [SerializeObject]
+        private class SerializableData
+        {
+            public Color color = Color.White;
+            public Degree spotAngle = new Degree(45);
+            public Degree spotFalloffAngle = new Degree(40);
+            public float range = 10.0f;
+            public float intensity = 5.0f;
+            public LightType type = LightType.Point;
+            public bool castShadows = false;
+        }
+    }
+}

+ 216 - 230
MBansheeEngine/Mesh.cs

@@ -1,230 +1,216 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Primary class for holding geometry. Stores data in the form of a vertex buffers and optionally index buffer, 
-    /// which may be bound to the pipeline for drawing. May contain multiple sub-meshes.
-    /// </summary>
-    public class Mesh : Resource
-    {
-        /// <summary>
-        /// Constructor for internal use by the runtime.
-        /// </summary>
-        private Mesh()
-        { }
-
-        /// <summary>
-        /// Creates a new mesh with enough space to hold the a number of primitives using the specified layout. All indices
-        /// will be part of a single sub-mesh.
-        /// </summary>
-        /// <param name="numVertices">Number of vertices in the mesh.</param>
-        /// <param name="numIndices">Number of indices in the mesh. </param>
-        /// <param name="topology">Determines how should the provided indices be interpreted by the pipeline. Default option
-        ///                        is a triangle list, where three indices represent a single triangle.</param>
-        /// <param name="usage">Optimizes performance depending on planned usage of the mesh.</param>
-        /// <param name="vertex">Controls how are vertices organized in the vertex buffer and what data they contain.</param>
-        /// <param name="index">Size of indices, use smaller size for better performance, however be careful not to go over
-        ///                     the number of vertices limited by the size.</param>
-        public Mesh(int numVertices, int numIndices, MeshTopology topology = MeshTopology.TriangleList,
-            MeshUsage usage = MeshUsage.Default, VertexType vertex = VertexType.Position, 
-            IndexType index = IndexType.Index32)
-        {
-            SubMesh[] subMeshes = {new SubMesh(0, numIndices, topology)};
-
-            Internal_CreateInstance(this, numVertices, numIndices, subMeshes, usage, vertex, index);
-        }
-
-        /// <summary>
-        /// Creates a new mesh with enough space to hold the a number of primitives using the specified layout. Indices can
-        /// be references by multiple sub-meshes.
-        /// </summary>
-        /// <param name="numVertices">Number of vertices in the mesh.</param>
-        /// <param name="numIndices">Number of indices in the mesh. </param>
-        /// <param name="subMeshes">Defines how are indices separated into sub-meshes, and how are those sub-meshes rendered.
-        ///                         Sub-meshes may be rendered independently.</param>
-        /// <param name="usage">Optimizes performance depending on planned usage of the mesh.</param>
-        /// <param name="vertex">Controls how are vertices organized in the vertex buffer and what data they contain.</param>
-        /// <param name="index">Size of indices, use smaller size for better performance, however be careful not to go over
-        ///                     the number of vertices limited by the size.</param>
-        public Mesh(int numVertices, int numIndices, SubMesh[] subMeshes, MeshUsage usage = MeshUsage.Default,
-            VertexType vertex = VertexType.Position, IndexType index = IndexType.Index32)
-        {
-            Internal_CreateInstance(this, numVertices, numIndices, subMeshes, usage, vertex, index);
-        }
-
-        /// <summary>
-        /// Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described
-        /// by the mesh data exactly. Mesh will have no sub-meshes.
-        /// </summary>
-        /// <param name="data">Vertex and index data to initialize the mesh with.</param>
-        /// <param name="topology">Determines how should the provided indices be interpreted by the pipeline. Default option
-        ///                        is a triangle list, where three indices represent a single triangle.</param>
-        /// <param name="usage">Optimizes performance depending on planned usage of the mesh.</param>
-        public Mesh(MeshData data, MeshTopology topology = MeshTopology.TriangleList, MeshUsage usage = MeshUsage.Default)
-        {
-            int numIndices = 0;
-            IntPtr dataPtr = IntPtr.Zero;
-
-            if (data != null)
-            {
-                numIndices = data.IndexCount;
-                dataPtr = data.GetCachedPtr();
-            }
-
-            SubMesh[] subMeshes = { new SubMesh(0, numIndices, topology) };
-
-            Internal_CreateInstanceMeshData(this, dataPtr, subMeshes, usage);
-        }
-
-        /// <summary>
-        /// Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described
-        /// by the mesh data exactly. Mesh will have specified the sub-meshes.
-        /// </summary>
-        /// <param name="data">Vertex and index data to initialize the mesh with.</param>
-        /// <param name="subMeshes">Defines how are indices separated into sub-meshes, and how are those sub-meshes rendered.
-        ///                         Sub-meshes may be rendered independently.</param>
-        /// <param name="usage">Optimizes performance depending on planned usage of the mesh.</param>
-        public Mesh(MeshData data, SubMesh[] subMeshes, MeshUsage usage = MeshUsage.Default)
-        {
-            IntPtr dataPtr = IntPtr.Zero;
-            if (data != null)
-                dataPtr = data.GetCachedPtr();
-
-            Internal_CreateInstanceMeshData(this, dataPtr, subMeshes, usage);
-        }
-
-        /// <summary>
-        /// Returns the number of sub-meshes contained in the mesh.
-        /// </summary>
-        public int SubMeshCount
-        {
-            get { return Internal_GetSubMeshCount(mCachedPtr); }
-        }
-
-        /// <summary>
-        /// Returns all sub-meshes contained in the mesh.
-        /// </summary>
-        public SubMesh[] SubMeshes
-        {
-            get { return Internal_GetSubMeshes(mCachedPtr); }
-        }
-
-        /// <summary>
-        /// Returns local bounds of the geometry contained in the vertex buffers for all sub-meshes.
-        /// </summary>
-        public Bounds Bounds
-        {
-            get
-            {
-                AABox box;
-                Sphere sphere;
-
-                Internal_GetBounds(mCachedPtr, out box, out sphere);
-
-                return new Bounds(box, sphere);
-            }
-        }
-
-        /// <summary>
-        /// Returns the vertex and index data contained in the mesh. Mesh must have been created with a 
-        /// <see cref="MeshUsage.CPUCached"/> flag.
-        /// </summary>
-        /// <returns>Vertex and index data contained in the mesh</returns>
-        public MeshData GetMeshData()
-        {
-            return Internal_GetMeshData(mCachedPtr);
-        }
-
-        /// <summary>
-        /// Updates the vertex and index data contained in the mesh.
-        /// </summary>
-        /// <param name="data">Vertex and index data. Data must match mesh vertex/index counts, vertex layout and index 
-        ///                    format.</param>
-        public void SetMeshData(MeshData data)
-        {
-            IntPtr dataPtr = IntPtr.Zero;
-            if (data != null)
-                dataPtr = data.GetCachedPtr();
-
-            Internal_SetMeshData(mCachedPtr, dataPtr);
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CreateInstance(Mesh instance, int numVertices,
-            int numIndices, SubMesh[] subMeshes, MeshUsage usage, VertexType vertex, IndexType index);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CreateInstanceMeshData(Mesh instance, IntPtr data, SubMesh[] subMeshes, 
-            MeshUsage usage);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern SubMesh[] Internal_GetSubMeshes(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern int Internal_GetSubMeshCount(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_GetBounds(IntPtr thisPtr, out AABox box, out Sphere sphere);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern MeshData Internal_GetMeshData(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetMeshData(IntPtr thisPtr, IntPtr value);
-    }
-
-    /// <summary>
-    /// Data about a sub-mesh range and the type of primitives contained in the range.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
-    public struct SubMesh // Note: Must match C++ class SubMesh
-    {
-        public SubMesh(int indexOffset, int indexCount, MeshTopology topology = MeshTopology.TriangleList)
-        {
-            IndexOffset = indexOffset;
-            IndexCount = indexCount;
-            Topology = topology;
-        }
-
-        public int IndexOffset;
-        public int IndexCount;
-        public MeshTopology Topology;
-    }
-
-    /// <summary>
-    /// Determines how are mesh indices interpreted by the renderer.
-    /// </summary>
-    public enum MeshTopology // Note: Must match C++ class MeshTopology
-    {
-        PointList = 1,
-        LineList = 2,
-        LineStrip = 3,
-        TriangleList = 4,
-        TriangleStrip = 5,
-        TriangleFan = 6
-    }
-
-    /// <summary>
-    /// Planned usage for the mesh that allow various optimizations.
-    /// </summary>
-    public enum MeshUsage // Note: Must match C++ enum MeshUsage
-    {
-        /// <summary>
-        /// Specify for a mesh that is not often updated from the CPU.
-        /// </summary>
-        Default = 0x1,
-
-        /// <summary>
-        /// Specify for a mesh that is often updated from the CPU.
-        /// </summary>
-        Dynamic = 0x2,
-
-        /// <summary>
-        /// All mesh data will also be cached in CPU memory allowing the mesh data to be read.
-        /// </summary>
-        CPUCached = 0x1000
-    }
-}
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Primary class for holding geometry. Stores data in the form of a vertex buffers and optionally index buffer, 
+    /// which may be bound to the pipeline for drawing. May contain multiple sub-meshes.
+    /// </summary>
+    public class Mesh : Resource
+    {
+        /// <summary>
+        /// Constructor for internal use by the runtime.
+        /// </summary>
+        private Mesh()
+        { }
+
+        /// <summary>
+        /// Creates a new mesh with enough space to hold the a number of primitives using the specified layout. All indices
+        /// will be part of a single sub-mesh.
+        /// </summary>
+        /// <param name="numVertices">Number of vertices in the mesh.</param>
+        /// <param name="numIndices">Number of indices in the mesh. </param>
+        /// <param name="topology">Determines how should the provided indices be interpreted by the pipeline. Default option
+        ///                        is a triangle list, where three indices represent a single triangle.</param>
+        /// <param name="usage">Optimizes performance depending on planned usage of the mesh.</param>
+        /// <param name="vertex">Controls how are vertices organized in the vertex buffer and what data they contain.</param>
+        /// <param name="index">Size of indices, use smaller size for better performance, however be careful not to go over
+        ///                     the number of vertices limited by the size.</param>
+        public Mesh(int numVertices, int numIndices, MeshTopology topology = MeshTopology.TriangleList,
+            MeshUsage usage = MeshUsage.Default, VertexType vertex = VertexType.Position, 
+            IndexType index = IndexType.Index32)
+        {
+            SubMesh[] subMeshes = {new SubMesh(0, numIndices, topology)};
+
+            Internal_CreateInstance(this, numVertices, numIndices, subMeshes, usage, vertex, index);
+        }
+
+        /// <summary>
+        /// Creates a new mesh with enough space to hold the a number of primitives using the specified layout. Indices can
+        /// be references by multiple sub-meshes.
+        /// </summary>
+        /// <param name="numVertices">Number of vertices in the mesh.</param>
+        /// <param name="numIndices">Number of indices in the mesh. </param>
+        /// <param name="subMeshes">Defines how are indices separated into sub-meshes, and how are those sub-meshes rendered.
+        ///                         Sub-meshes may be rendered independently.</param>
+        /// <param name="usage">Optimizes performance depending on planned usage of the mesh.</param>
+        /// <param name="vertex">Controls how are vertices organized in the vertex buffer and what data they contain.</param>
+        /// <param name="index">Size of indices, use smaller size for better performance, however be careful not to go over
+        ///                     the number of vertices limited by the size.</param>
+        public Mesh(int numVertices, int numIndices, SubMesh[] subMeshes, MeshUsage usage = MeshUsage.Default,
+            VertexType vertex = VertexType.Position, IndexType index = IndexType.Index32)
+        {
+            Internal_CreateInstance(this, numVertices, numIndices, subMeshes, usage, vertex, index);
+        }
+
+        /// <summary>
+        /// Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described
+        /// by the mesh data exactly. Mesh will have no sub-meshes.
+        /// </summary>
+        /// <param name="data">Vertex and index data to initialize the mesh with.</param>
+        /// <param name="topology">Determines how should the provided indices be interpreted by the pipeline. Default option
+        ///                        is a triangle list, where three indices represent a single triangle.</param>
+        /// <param name="usage">Optimizes performance depending on planned usage of the mesh.</param>
+        public Mesh(MeshData data, MeshTopology topology = MeshTopology.TriangleList, MeshUsage usage = MeshUsage.Default)
+        {
+            int numIndices = 0;
+            IntPtr dataPtr = IntPtr.Zero;
+
+            if (data != null)
+            {
+                numIndices = data.IndexCount;
+                dataPtr = data.GetCachedPtr();
+            }
+
+            SubMesh[] subMeshes = { new SubMesh(0, numIndices, topology) };
+
+            Internal_CreateInstanceMeshData(this, dataPtr, subMeshes, usage);
+        }
+
+        /// <summary>
+        /// Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described
+        /// by the mesh data exactly. Mesh will have specified the sub-meshes.
+        /// </summary>
+        /// <param name="data">Vertex and index data to initialize the mesh with.</param>
+        /// <param name="subMeshes">Defines how are indices separated into sub-meshes, and how are those sub-meshes rendered.
+        ///                         Sub-meshes may be rendered independently.</param>
+        /// <param name="usage">Optimizes performance depending on planned usage of the mesh.</param>
+        public Mesh(MeshData data, SubMesh[] subMeshes, MeshUsage usage = MeshUsage.Default)
+        {
+            IntPtr dataPtr = IntPtr.Zero;
+            if (data != null)
+                dataPtr = data.GetCachedPtr();
+
+            Internal_CreateInstanceMeshData(this, dataPtr, subMeshes, usage);
+        }
+
+        /// <summary>
+        /// Returns the number of sub-meshes contained in the mesh.
+        /// </summary>
+        public int SubMeshCount
+        {
+            get { return Internal_GetSubMeshCount(mCachedPtr); }
+        }
+
+        /// <summary>
+        /// Returns all sub-meshes contained in the mesh.
+        /// </summary>
+        public SubMesh[] SubMeshes
+        {
+            get { return Internal_GetSubMeshes(mCachedPtr); }
+        }
+
+        /// <summary>
+        /// Returns local bounds of the geometry contained in the vertex buffers for all sub-meshes.
+        /// </summary>
+        public Bounds Bounds
+        {
+            get
+            {
+                AABox box;
+                Sphere sphere;
+
+                Internal_GetBounds(mCachedPtr, out box, out sphere);
+
+                return new Bounds(box, sphere);
+            }
+        }
+
+        /// <summary>
+        /// Accesses the vertex and index data of the mesh. If reading, mesh must have been created with the 
+        /// <see cref="MeshUsage.CPUCached"/> flag. If writing the caller must ensure the data matches mesh's vertex/index
+        /// counts, vertex layout and index format.
+        /// </summary>
+        public MeshData MeshData
+        {
+            get { return Internal_GetMeshData(mCachedPtr); }
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(Mesh instance, int numVertices,
+            int numIndices, SubMesh[] subMeshes, MeshUsage usage, VertexType vertex, IndexType index);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstanceMeshData(Mesh instance, IntPtr data, SubMesh[] subMeshes, 
+            MeshUsage usage);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern SubMesh[] Internal_GetSubMeshes(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern int Internal_GetSubMeshCount(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetBounds(IntPtr thisPtr, out AABox box, out Sphere sphere);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern MeshData Internal_GetMeshData(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMeshData(IntPtr thisPtr, IntPtr value);
+    }
+
+    /// <summary>
+    /// Data about a sub-mesh range and the type of primitives contained in the range.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    public struct SubMesh // Note: Must match C++ class SubMesh
+    {
+        public SubMesh(int indexOffset, int indexCount, MeshTopology topology = MeshTopology.TriangleList)
+        {
+            IndexOffset = indexOffset;
+            IndexCount = indexCount;
+            Topology = topology;
+        }
+
+        public int IndexOffset;
+        public int IndexCount;
+        public MeshTopology Topology;
+    }
+
+    /// <summary>
+    /// Determines how are mesh indices interpreted by the renderer.
+    /// </summary>
+    public enum MeshTopology // Note: Must match C++ class MeshTopology
+    {
+        PointList = 1,
+        LineList = 2,
+        LineStrip = 3,
+        TriangleList = 4,
+        TriangleStrip = 5,
+        TriangleFan = 6
+    }
+
+    /// <summary>
+    /// Planned usage for the mesh that allow various optimizations.
+    /// </summary>
+    public enum MeshUsage // Note: Must match C++ enum MeshUsage
+    {
+        /// <summary>
+        /// Specify for a mesh that is not often updated from the CPU.
+        /// </summary>
+        Default = 0x1,
+
+        /// <summary>
+        /// Specify for a mesh that is often updated from the CPU.
+        /// </summary>
+        Dynamic = 0x2,
+
+        /// <summary>
+        /// All mesh data will also be cached in CPU memory allowing the mesh data to be read.
+        /// </summary>
+        CPUCached = 0x1000
+    }
+}

+ 244 - 238
MBansheeEngine/MeshData.cs

@@ -1,238 +1,244 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace BansheeEngine
-{
-    /// <summary>
-    /// Contains mesh vertex and index data used for initializing, updating and reading mesh data from Mesh.
-    /// </summary>
-    public class MeshData : ScriptObject
-    {
-        /// <summary>
-        /// Creates a new mesh data that can hold number of vertices described by the provided vertex layout as well as a 
-        /// number of indices of the provided type.
-        /// </summary>
-        /// <param name="numVertices">Number of vertices in the mesh.</param>
-        /// <param name="numIndices">Number of indices in the mesh. </param>
-        /// <param name="vertex">Controls how are vertices organized in the vertex buffer and what data they contain.</param>
-        /// <param name="index">Size of indices, use smaller size for better performance, however be careful not to go over
-        ///                     the number of vertices limited by the size.</param>
-        public MeshData(int numVertices, int numIndices, VertexType vertex = VertexType.Position,
-            IndexType index = IndexType.Index32)
-        {
-            Internal_CreateInstance(this, numVertices, numIndices, vertex, index);
-        }
-
-        /// <summary>
-        /// An array of all vertex positions. Only valid if the vertex layout contains vertex positions.
-        /// </summary>
-        public Vector3[] Positions
-        {
-            get { return Internal_GetPositions(mCachedPtr); }
-            set { Internal_SetPositions(mCachedPtr, value); }
-        }
-
-        /// <summary>
-        /// An array of all vertex normals. Only valid if the vertex layout contains vertex normals.
-        /// </summary>
-        public Vector3[] Normals
-        {
-            get { return Internal_GetNormals(mCachedPtr); }
-            set { Internal_SetNormals(mCachedPtr, value); }
-        }
-
-        /// <summary>
-        /// An array of all vertex tangents. Only valid if the vertex layout contains vertex tangents.
-        /// </summary>
-        public Vector4[] Tangents
-        {
-            get { return Internal_GetTangents(mCachedPtr); }
-            set { Internal_SetTangents(mCachedPtr, value); }
-        }
-
-        /// <summary>
-        /// An array of all vertex colors. Only valid if the vertex layout contains vertex colors.
-        /// </summary>
-        public Color[] Colors
-        {
-            get { return Internal_GetColors(mCachedPtr); }
-            set { Internal_SetColors(mCachedPtr, value); }
-        }
-
-        /// <summary>
-        /// An array of all vertex texture coordinates in the UV0 channel. Only valid if the vertex layout contains UV0 
-        /// coordinates.
-        /// </summary>
-        public Vector2[] UV
-        {
-            get { return UV0; }
-            set { UV0 = value; }
-        }
-
-        /// <summary>
-        /// An array of all vertex texture coordinates in the UV0 channel. Only valid if the vertex layout contains UV0 
-        /// coordinates.
-        /// </summary>
-        public Vector2[] UV0
-        {
-            get { return Internal_GetUV0(mCachedPtr); }
-            set { Internal_SetUV0(mCachedPtr, value); }
-        }
-
-        /// <summary>
-        /// An array of all vertex texture coordinates in the UV1 channel. Only valid if the vertex layout contains UV1
-        /// coordinates.
-        /// </summary>
-        public Vector2[] UV1
-        {
-            get { return Internal_GetUV1(mCachedPtr); }
-            set { Internal_SetUV0(mCachedPtr, value); }
-        }
-
-        /// <summary>
-        /// An array of all vertex bone weights. Only valid if the vertex layout contains bone weights.
-        /// </summary>
-        public BoneWeight[] BoneWeights
-        {
-            get { return Internal_GetBoneWeights(mCachedPtr); }
-            set { Internal_SetBoneWeights(mCachedPtr, value); }
-        }
-
-        /// <summary>
-        /// An array of all indices. Make sure that individual entries do not go over the index count as required by
-        /// active index type.
-        /// </summary>
-        public int[] Indices
-        {
-            get { return Internal_GetIndices(mCachedPtr); }
-            set { Internal_SetIndices(mCachedPtr, value); }
-        }
-
-        /// <summary>
-        /// Number of vertices contained by this object.
-        /// </summary>
-        public int VertexCount
-        {
-            get { return Internal_GetVertexCount(mCachedPtr); }
-        }
-
-        /// <summary>
-        /// Number of indices contained by this object.
-        /// </summary>
-        public int IndexCount
-        {
-            get { return Internal_GetIndexCount(mCachedPtr); }
-        }
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_CreateInstance(MeshData instance, int numVertices, 
-            int numIndices, VertexType vertex, IndexType index);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern Vector3[] Internal_GetPositions(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetPositions(IntPtr thisPtr, Vector3[] value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern Vector3[] Internal_GetNormals(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetNormals(IntPtr thisPtr, Vector3[] value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern Vector4[] Internal_GetTangents(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetTangents(IntPtr thisPtr, Vector4[] value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern Color[] Internal_GetColors(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetColors(IntPtr thisPtr, Color[] value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern Vector2[] Internal_GetUV0(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetUV0(IntPtr thisPtr, Vector2[] value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern Vector2[] Internal_GetUV1(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetUV1(IntPtr thisPtr, Vector2[] value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern BoneWeight[] Internal_GetBoneWeights(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetBoneWeights(IntPtr thisPtr, BoneWeight[] value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern int[] Internal_GetIndices(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern void Internal_SetIndices(IntPtr thisPtr, int[] value);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern int Internal_GetVertexCount(IntPtr thisPtr);
-
-        [MethodImpl(MethodImplOptions.InternalCall)]
-        private static extern int Internal_GetIndexCount(IntPtr thisPtr);
-    }
-
-    /// <summary>
-    /// Available vertex layouts that specify what data is provided per-vertex in a mesh. Combinations other than those 
-    /// provided are allowed.
-    /// </summary>
-    public enum VertexType // Note: Must match C++ enum VertexLayout
-    {
-        Position = 0x01,
-        Color = 0x02,
-        Normal = 0x04,
-        Tangent = 0x08,
-        BlendWeights = 0x10,
-        UV0 = 0x20,
-        UV1 = 0x40,
-        PC = Position | Color,
-        PU = Position | UV0,
-        PCU = Position | Color | UV0,
-        PCN = Position | Color | Normal,
-        PCNU = Position | Color | Normal | UV0,
-        PCNT = Position | Color | Normal | Tangent,
-        PCNTU = Position | Color | Normal | Tangent | UV0,
-        PN = Position | Normal,
-        PNU = Position | Normal | UV0,
-        PNT = Position | Normal | Tangent,
-        PNTU = Position | Normal | Tangent | UV0,
-    }
-
-    /// <summary>
-    /// Determines the size of a single index in a mesh.
-    /// </summary>
-    public enum IndexType // Note: Must match C++ enum ScriptIndexType
-    {
-        Index16,
-        Index32
-    }
-
-    /// <summary>
-    /// Contains per-vertex bone weights and indexes used for skinning, for up to four bones.
-    /// </summary>
-    [StructLayout(LayoutKind.Sequential)]
-    public struct BoneWeight // Note: Must match C++ class BoneWeight
-    {
-        public int index0;
-        public int index1;
-        public int index2;
-        public int index3;
-
-        public float weight0;
-        public float weight1;
-        public float weight2;
-        public float weight3;
-    }
-}
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace BansheeEngine
+{
+    /// <summary>
+    /// Contains mesh vertex and index data used for initializing, updating and reading mesh data from Mesh.
+    /// </summary>
+    public class MeshData : ScriptObject
+    {
+        /// <summary>
+        /// Constructor for internal runtime use only.
+        /// </summary>
+        private MeshData()
+        { }
+
+        /// <summary>
+        /// Creates a new mesh data that can hold number of vertices described by the provided vertex layout as well as a 
+        /// number of indices of the provided type.
+        /// </summary>
+        /// <param name="numVertices">Number of vertices in the mesh.</param>
+        /// <param name="numIndices">Number of indices in the mesh. </param>
+        /// <param name="vertex">Controls how are vertices organized in the vertex buffer and what data they contain.</param>
+        /// <param name="index">Size of indices, use smaller size for better performance, however be careful not to go over
+        ///                     the number of vertices limited by the size.</param>
+        public MeshData(int numVertices, int numIndices, VertexType vertex = VertexType.Position,
+            IndexType index = IndexType.Index32)
+        {
+            Internal_CreateInstance(this, numVertices, numIndices, vertex, index);
+        }
+
+        /// <summary>
+        /// An array of all vertex positions. Only valid if the vertex layout contains vertex positions.
+        /// </summary>
+        public Vector3[] Positions
+        {
+            get { return Internal_GetPositions(mCachedPtr); }
+            set { Internal_SetPositions(mCachedPtr, value); }
+        }
+
+        /// <summary>
+        /// An array of all vertex normals. Only valid if the vertex layout contains vertex normals.
+        /// </summary>
+        public Vector3[] Normals
+        {
+            get { return Internal_GetNormals(mCachedPtr); }
+            set { Internal_SetNormals(mCachedPtr, value); }
+        }
+
+        /// <summary>
+        /// An array of all vertex tangents. Only valid if the vertex layout contains vertex tangents.
+        /// </summary>
+        public Vector4[] Tangents
+        {
+            get { return Internal_GetTangents(mCachedPtr); }
+            set { Internal_SetTangents(mCachedPtr, value); }
+        }
+
+        /// <summary>
+        /// An array of all vertex colors. Only valid if the vertex layout contains vertex colors.
+        /// </summary>
+        public Color[] Colors
+        {
+            get { return Internal_GetColors(mCachedPtr); }
+            set { Internal_SetColors(mCachedPtr, value); }
+        }
+
+        /// <summary>
+        /// An array of all vertex texture coordinates in the UV0 channel. Only valid if the vertex layout contains UV0 
+        /// coordinates.
+        /// </summary>
+        public Vector2[] UV
+        {
+            get { return UV0; }
+            set { UV0 = value; }
+        }
+
+        /// <summary>
+        /// An array of all vertex texture coordinates in the UV0 channel. Only valid if the vertex layout contains UV0 
+        /// coordinates.
+        /// </summary>
+        public Vector2[] UV0
+        {
+            get { return Internal_GetUV0(mCachedPtr); }
+            set { Internal_SetUV0(mCachedPtr, value); }
+        }
+
+        /// <summary>
+        /// An array of all vertex texture coordinates in the UV1 channel. Only valid if the vertex layout contains UV1
+        /// coordinates.
+        /// </summary>
+        public Vector2[] UV1
+        {
+            get { return Internal_GetUV1(mCachedPtr); }
+            set { Internal_SetUV0(mCachedPtr, value); }
+        }
+
+        /// <summary>
+        /// An array of all vertex bone weights. Only valid if the vertex layout contains bone weights.
+        /// </summary>
+        public BoneWeight[] BoneWeights
+        {
+            get { return Internal_GetBoneWeights(mCachedPtr); }
+            set { Internal_SetBoneWeights(mCachedPtr, value); }
+        }
+
+        /// <summary>
+        /// An array of all indices. Make sure that individual entries do not go over the index count as required by
+        /// active index type.
+        /// </summary>
+        public int[] Indices
+        {
+            get { return Internal_GetIndices(mCachedPtr); }
+            set { Internal_SetIndices(mCachedPtr, value); }
+        }
+
+        /// <summary>
+        /// Number of vertices contained by this object.
+        /// </summary>
+        public int VertexCount
+        {
+            get { return Internal_GetVertexCount(mCachedPtr); }
+        }
+
+        /// <summary>
+        /// Number of indices contained by this object.
+        /// </summary>
+        public int IndexCount
+        {
+            get { return Internal_GetIndexCount(mCachedPtr); }
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_CreateInstance(MeshData instance, int numVertices, 
+            int numIndices, VertexType vertex, IndexType index);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern Vector3[] Internal_GetPositions(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetPositions(IntPtr thisPtr, Vector3[] value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern Vector3[] Internal_GetNormals(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetNormals(IntPtr thisPtr, Vector3[] value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern Vector4[] Internal_GetTangents(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetTangents(IntPtr thisPtr, Vector4[] value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern Color[] Internal_GetColors(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetColors(IntPtr thisPtr, Color[] value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern Vector2[] Internal_GetUV0(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetUV0(IntPtr thisPtr, Vector2[] value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern Vector2[] Internal_GetUV1(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetUV1(IntPtr thisPtr, Vector2[] value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern BoneWeight[] Internal_GetBoneWeights(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetBoneWeights(IntPtr thisPtr, BoneWeight[] value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern int[] Internal_GetIndices(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetIndices(IntPtr thisPtr, int[] value);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern int Internal_GetVertexCount(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern int Internal_GetIndexCount(IntPtr thisPtr);
+    }
+
+    /// <summary>
+    /// Available vertex layouts that specify what data is provided per-vertex in a mesh. Combinations other than those 
+    /// provided are allowed.
+    /// </summary>
+    public enum VertexType // Note: Must match C++ enum VertexLayout
+    {
+        Position = 0x01,
+        Color = 0x02,
+        Normal = 0x04,
+        Tangent = 0x08,
+        BlendWeights = 0x10,
+        UV0 = 0x20,
+        UV1 = 0x40,
+        PC = Position | Color,
+        PU = Position | UV0,
+        PCU = Position | Color | UV0,
+        PCN = Position | Color | Normal,
+        PCNU = Position | Color | Normal | UV0,
+        PCNT = Position | Color | Normal | Tangent,
+        PCNTU = Position | Color | Normal | Tangent | UV0,
+        PN = Position | Normal,
+        PNU = Position | Normal | UV0,
+        PNT = Position | Normal | Tangent,
+        PNTU = Position | Normal | Tangent | UV0,
+    }
+
+    /// <summary>
+    /// Determines the size of a single index in a mesh.
+    /// </summary>
+    public enum IndexType // Note: Must match C++ enum ScriptIndexType
+    {
+        Index16,
+        Index32
+    }
+
+    /// <summary>
+    /// Contains per-vertex bone weights and indexes used for skinning, for up to four bones.
+    /// </summary>
+    [StructLayout(LayoutKind.Sequential)]
+    public struct BoneWeight // Note: Must match C++ class BoneWeight
+    {
+        public int index0;
+        public int index1;
+        public int index2;
+        public int index3;
+
+        public float weight0;
+        public float weight1;
+        public float weight2;
+        public float weight3;
+    }
+}

+ 306 - 306
SBansheeEngine/Source/BsScriptMeshData.cpp

@@ -1,307 +1,307 @@
-#include "BsScriptMeshData.h"
-#include "BsScriptMeta.h"
-#include "BsMonoField.h"
-#include "BsMonoClass.h"
-#include "BsMonoManager.h"
-#include "BsMonoUtil.h"
-#include "BsScriptColor.h"
-#include "BsScriptVector.h"
-#include "BsScriptBoneWeight.h"
-#include "BsVertexDataDesc.h"
-#include "BsPixelUtil.h"
-
-namespace BansheeEngine
-{
-	template<int Semantic>
-	struct TVertexDataAccessor
-	{
-		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size) { }
-		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size) { }
-	};
-
-	template<>
-	struct TVertexDataAccessor < (int)VertexLayout::Position >
-	{
-		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
-		{ meshData->getPositions((Vector3*)buffer, size); }
-
-		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
-		{ meshData->setPositions((Vector3*)buffer, size); }
-	};
-
-	template<>
-	struct TVertexDataAccessor < (int)VertexLayout::Normal >
-	{
-		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
-		{ meshData->getNormals((Vector3*)buffer, size); }
-
-		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
-		{ meshData->setNormals((Vector3*)buffer, size); }
-	};
-
-	template<>
-	struct TVertexDataAccessor < (int)VertexLayout::Tangent >
-	{
-		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
-		{ meshData->getTangents((Vector4*)buffer, size); }
-
-		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
-		{ meshData->setTangents((Vector4*)buffer, size); }
-	};
-
-	template<>
-	struct TVertexDataAccessor < (int)VertexLayout::Color >
-	{
-		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
-		{ meshData->getColors((Color*)buffer, size); }
-
-		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
-		{ meshData->setColors((Color*)buffer, size); }
-	};
-
-	template<>
-	struct TVertexDataAccessor < (int)VertexLayout::UV0 >
-	{
-		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
-		{ meshData->getUV0((Vector2*)buffer, size); }
-
-		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
-		{ meshData->setUV0((Vector2*)buffer, size); }
-	};
-
-	template<>
-	struct TVertexDataAccessor < (int)VertexLayout::UV1 >
-	{
-		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
-		{ meshData->getUV1((Vector2*)buffer, size); }
-
-		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
-		{ meshData->setUV1((Vector2*)buffer, size); }
-	};
-
-	template<>
-	struct TVertexDataAccessor < (int)VertexLayout::BoneWeights >
-	{
-		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
-		{ meshData->getBoneWeights((BoneWeight*)buffer, size); }
-
-		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
-		{ meshData->setBoneWeights((BoneWeight*)buffer, size); }
-	};
-
-	template<int Semantic, class TNative, class TScript>
-	MonoArray* getVertexDataArray(ScriptMeshData* scriptMeshData)
-	{
-		RendererMeshDataPtr meshData = scriptMeshData->getInternalValue();
-		UINT32 numElements = meshData->getData()->getNumVertices();
-
-		ScriptArray outArray = ScriptArray::create<TScript>(numElements);
-		TVertexDataAccessor<Semantic>::get(meshData, (UINT8*)outArray.getRawPtr<TNative>(), numElements * sizeof(TNative));
-
-		return outArray.getInternal();
-	}
-
-	template<int Semantic, class TNative, class TScript>
-	void setVertexDataArray(ScriptMeshData* scriptMeshData, MonoArray* array)
-	{
-		if (array == nullptr)
-			return;
-
-		RendererMeshDataPtr meshData = scriptMeshData->getInternalValue();
-		UINT32 numElements = meshData->getData()->getNumVertices();
-
-		ScriptArray inArray(array);
-		TVertexDataAccessor<Semantic>::set(meshData, (UINT8*)inArray.getRawPtr<TNative>(), numElements * sizeof(TNative));
-	}
-
-	ScriptMeshData::ScriptMeshData(MonoObject* managedInstance)
-		:ScriptObject(managedInstance)
-	{
-
-	}
-
-	ScriptMeshData::~ScriptMeshData()
-	{
-
-	}
-
-	void ScriptMeshData::initRuntimeData()
-	{
-		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptMeshData::internal_CreateInstance);
-		metaData.scriptClass->addInternalCall("Internal_GetPositions", &ScriptMeshData::internal_GetPositions);
-		metaData.scriptClass->addInternalCall("Internal_SetPositions", &ScriptMeshData::internal_SetPositions);
-		metaData.scriptClass->addInternalCall("Internal_GetNormals", &ScriptMeshData::internal_GetNormals);
-		metaData.scriptClass->addInternalCall("Internal_SetNormals", &ScriptMeshData::internal_SetNormals);
-		metaData.scriptClass->addInternalCall("Internal_GetTangents", &ScriptMeshData::internal_GetTangents);
-		metaData.scriptClass->addInternalCall("Internal_SetTangents", &ScriptMeshData::internal_SetTangents);
-		metaData.scriptClass->addInternalCall("Internal_GetColors", &ScriptMeshData::internal_GetColors);
-		metaData.scriptClass->addInternalCall("Internal_SetColors", &ScriptMeshData::internal_SetColors);
-		metaData.scriptClass->addInternalCall("Internal_GetUV0", &ScriptMeshData::internal_GetUV0);
-		metaData.scriptClass->addInternalCall("Internal_SetUV0", &ScriptMeshData::internal_SetUV0);
-		metaData.scriptClass->addInternalCall("Internal_GetUV1", &ScriptMeshData::internal_GetUV1);
-		metaData.scriptClass->addInternalCall("Internal_SetUV1", &ScriptMeshData::internal_SetUV1);
-		metaData.scriptClass->addInternalCall("Internal_GetBoneWeights", &ScriptMeshData::internal_GetBoneWeights);
-		metaData.scriptClass->addInternalCall("Internal_SetBoneWeights", &ScriptMeshData::internal_SetBoneWeights);
-		metaData.scriptClass->addInternalCall("Internal_GetIndices", &ScriptMeshData::internal_GetIndices);
-		metaData.scriptClass->addInternalCall("Internal_SetIndices", &ScriptMeshData::internal_SetIndices);
-		metaData.scriptClass->addInternalCall("Internal_GetVertexCount", &ScriptMeshData::internal_GetVertexCount);
-		metaData.scriptClass->addInternalCall("Internal_GetIndexCount", &ScriptMeshData::internal_GetIndexCount);
-	}
-
-	void ScriptMeshData::initialize(const RendererMeshDataPtr& meshData)
-	{
-		mMeshData = meshData;
-	}
-
-	MonoObject* ScriptMeshData::create(const RendererMeshDataPtr& meshData)
-	{
-		MonoObject* meshDataObj = metaData.scriptClass->createInstance();
-
-		ScriptMeshData* scriptMeshData = ScriptMeshData::toNative(meshDataObj);
-		scriptMeshData->initialize(meshData);
-
-		return meshDataObj;
-	}
-
-	MonoObject* ScriptMeshData::create(const MeshDataPtr& meshData)
-	{
-		MonoObject* meshDataObj = metaData.scriptClass->createInstance();
-
-		RendererMeshDataPtr defaultMeshData = RendererMeshData::create(meshData);
-		ScriptMeshData* scriptMeshData = ScriptMeshData::toNative(meshDataObj);
-		scriptMeshData->initialize(defaultMeshData);
-
-		return meshDataObj;
-	}
-
-	void ScriptMeshData::internal_CreateInstance(MonoObject* instance, int numVertices,
-		int numIndices, VertexLayout vertex, ScriptIndexType index)
-	{
-		IndexType indexType = IT_16BIT;
-		if (index == ScriptIndexType::Index32)
-			indexType = IT_32BIT;
-
-		RendererMeshDataPtr meshData = RendererMeshData::create(numVertices, numIndices, vertex, indexType);
-
-		ScriptMeshData* scriptMeshData = new (bs_alloc<ScriptMeshData>()) ScriptMeshData(instance);
-		scriptMeshData->initialize(meshData);
-	}
-
-	MonoArray* ScriptMeshData::internal_GetPositions(ScriptMeshData* thisPtr)
-	{
-		return getVertexDataArray<(int)VertexLayout::Position, Vector3, ScriptVector3>(thisPtr);
-	}
-
-	void ScriptMeshData::internal_SetPositions(ScriptMeshData* thisPtr, MonoArray* value)
-	{
-		setVertexDataArray<(int)VertexLayout::Position, Vector3, ScriptVector3>(thisPtr, value);
-	}
-
-	MonoArray* ScriptMeshData::internal_GetNormals(ScriptMeshData* thisPtr)
-	{
-		return getVertexDataArray<(int)VertexLayout::Normal, Vector3, ScriptVector3>(thisPtr);
-	}
-
-	void ScriptMeshData::internal_SetNormals(ScriptMeshData* thisPtr, MonoArray* value)
-	{
-		setVertexDataArray<(int)VertexLayout::Normal, Vector3, ScriptVector3>(thisPtr, value);
-	}
-
-	MonoArray* ScriptMeshData::internal_GetTangents(ScriptMeshData* thisPtr)
-	{
-		return getVertexDataArray<(int)VertexLayout::Tangent, Vector4, ScriptVector4>(thisPtr);
-	}
-
-	void ScriptMeshData::internal_SetTangents(ScriptMeshData* thisPtr, MonoArray* value)
-	{
-		setVertexDataArray<(int)VertexLayout::Tangent, Vector4, ScriptVector4>(thisPtr, value);
-	}
-
-	MonoArray* ScriptMeshData::internal_GetColors(ScriptMeshData* thisPtr)
-	{
-		return getVertexDataArray<(int)VertexLayout::Color, Color, ScriptColor>(thisPtr);
-	}
-
-	void ScriptMeshData::internal_SetColors(ScriptMeshData* thisPtr, MonoArray* value)
-	{
-		setVertexDataArray<(int)VertexLayout::Color, Color, ScriptColor>(thisPtr, value);
-	}
-
-	MonoArray* ScriptMeshData::internal_GetUV0(ScriptMeshData* thisPtr)
-	{
-		return getVertexDataArray<(int)VertexLayout::UV0, Vector2, ScriptVector2>(thisPtr);
-	}
-
-	void ScriptMeshData::internal_SetUV0(ScriptMeshData* thisPtr, MonoArray* value)
-	{
-		setVertexDataArray<(int)VertexLayout::UV0, Vector2, ScriptVector2>(thisPtr, value);
-	}
-
-	MonoArray* ScriptMeshData::internal_GetUV1(ScriptMeshData* thisPtr)
-	{
-		return getVertexDataArray<(int)VertexLayout::UV1, Vector2, ScriptVector2>(thisPtr);
-	}
-
-	void ScriptMeshData::internal_SetUV1(ScriptMeshData* thisPtr, MonoArray* value)
-	{
-		setVertexDataArray<(int)VertexLayout::UV1, Vector2, ScriptVector2>(thisPtr, value);
-	}
-
-	MonoArray* ScriptMeshData::internal_GetBoneWeights(ScriptMeshData* thisPtr)
-	{
-		return getVertexDataArray<(int)VertexLayout::BoneWeights, BoneWeight, ScriptBoneWeight>(thisPtr);
-	}
-
-	void ScriptMeshData::internal_SetBoneWeights(ScriptMeshData* thisPtr, MonoArray* value)
-	{
-		setVertexDataArray<(int)VertexLayout::BoneWeights, BoneWeight, ScriptBoneWeight>(thisPtr, value);
-	}
-
-	MonoArray* ScriptMeshData::internal_GetIndices(ScriptMeshData* thisPtr)
-	{
-		RendererMeshDataPtr meshData = thisPtr->getInternalValue();
-		UINT32 numElements = meshData->getData()->getNumIndices();
-
-		ScriptArray outArray = ScriptArray::create<UINT32>(numElements);
-		meshData->getIndices(outArray.getRawPtr<UINT32>(), numElements * sizeof(UINT32));
-
-		return outArray.getInternal();
-	}
-
-	void ScriptMeshData::internal_SetIndices(ScriptMeshData* thisPtr, MonoArray* value)
-	{
-		if (value == nullptr)
-			return;
-
-		RendererMeshDataPtr meshData = thisPtr->getInternalValue();
-		UINT32 numElements = meshData->getData()->getNumIndices();
-
-		ScriptArray inArray(value);
-		meshData->setIndices(inArray.getRawPtr<UINT32>(), numElements * sizeof(UINT32));
-	}
-
-	int ScriptMeshData::internal_GetVertexCount(ScriptMeshData* thisPtr)
-	{
-		RendererMeshDataPtr meshData = thisPtr->getInternalValue();
-
-		return (int)meshData->getData()->getNumVertices();
-	}
-
-	int ScriptMeshData::internal_GetIndexCount(ScriptMeshData* thisPtr)
-	{
-		RendererMeshDataPtr meshData = thisPtr->getInternalValue();
-
-		return (int)meshData->getData()->getNumIndices();
-	}
-
-	bool ScriptMeshData::checkIsLocked(ScriptMeshData* thisPtr)
-	{
-		if (thisPtr->mMeshData->getData()->isLocked())
-		{
-			LOGWRN("Attempting to access a locked mesh data buffer.");
-			return true;
-		}
-
-		return false;
-	}
+#include "BsScriptMeshData.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoManager.h"
+#include "BsMonoUtil.h"
+#include "BsScriptColor.h"
+#include "BsScriptVector.h"
+#include "BsScriptBoneWeight.h"
+#include "BsVertexDataDesc.h"
+#include "BsPixelUtil.h"
+
+namespace BansheeEngine
+{
+	template<int Semantic>
+	struct TVertexDataAccessor
+	{
+		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size) { }
+		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size) { }
+	};
+
+	template<>
+	struct TVertexDataAccessor < (int)VertexLayout::Position >
+	{
+		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->getPositions((Vector3*)buffer, size); }
+
+		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->setPositions((Vector3*)buffer, size); }
+	};
+
+	template<>
+	struct TVertexDataAccessor < (int)VertexLayout::Normal >
+	{
+		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->getNormals((Vector3*)buffer, size); }
+
+		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->setNormals((Vector3*)buffer, size); }
+	};
+
+	template<>
+	struct TVertexDataAccessor < (int)VertexLayout::Tangent >
+	{
+		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->getTangents((Vector4*)buffer, size); }
+
+		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->setTangents((Vector4*)buffer, size); }
+	};
+
+	template<>
+	struct TVertexDataAccessor < (int)VertexLayout::Color >
+	{
+		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->getColors((Color*)buffer, size); }
+
+		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->setColors((Color*)buffer, size); }
+	};
+
+	template<>
+	struct TVertexDataAccessor < (int)VertexLayout::UV0 >
+	{
+		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->getUV0((Vector2*)buffer, size); }
+
+		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->setUV0((Vector2*)buffer, size); }
+	};
+
+	template<>
+	struct TVertexDataAccessor < (int)VertexLayout::UV1 >
+	{
+		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->getUV1((Vector2*)buffer, size); }
+
+		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->setUV1((Vector2*)buffer, size); }
+	};
+
+	template<>
+	struct TVertexDataAccessor < (int)VertexLayout::BoneWeights >
+	{
+		static void get(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->getBoneWeights((BoneWeight*)buffer, size); }
+
+		static void set(const RendererMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->setBoneWeights((BoneWeight*)buffer, size); }
+	};
+
+	template<int Semantic, class TNative, class TScript>
+	MonoArray* getVertexDataArray(ScriptMeshData* scriptMeshData)
+	{
+		RendererMeshDataPtr meshData = scriptMeshData->getInternalValue();
+		UINT32 numElements = meshData->getData()->getNumVertices();
+
+		ScriptArray outArray = ScriptArray::create<TScript>(numElements);
+		TVertexDataAccessor<Semantic>::get(meshData, (UINT8*)outArray.getRawPtr<TNative>(), numElements * sizeof(TNative));
+
+		return outArray.getInternal();
+	}
+
+	template<int Semantic, class TNative, class TScript>
+	void setVertexDataArray(ScriptMeshData* scriptMeshData, MonoArray* array)
+	{
+		if (array == nullptr)
+			return;
+
+		RendererMeshDataPtr meshData = scriptMeshData->getInternalValue();
+		UINT32 numElements = meshData->getData()->getNumVertices();
+
+		ScriptArray inArray(array);
+		TVertexDataAccessor<Semantic>::set(meshData, (UINT8*)inArray.getRawPtr<TNative>(), numElements * sizeof(TNative));
+	}
+
+	ScriptMeshData::ScriptMeshData(MonoObject* managedInstance)
+		:ScriptObject(managedInstance)
+	{
+
+	}
+
+	ScriptMeshData::~ScriptMeshData()
+	{
+
+	}
+
+	void ScriptMeshData::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptMeshData::internal_CreateInstance);
+		metaData.scriptClass->addInternalCall("Internal_GetPositions", &ScriptMeshData::internal_GetPositions);
+		metaData.scriptClass->addInternalCall("Internal_SetPositions", &ScriptMeshData::internal_SetPositions);
+		metaData.scriptClass->addInternalCall("Internal_GetNormals", &ScriptMeshData::internal_GetNormals);
+		metaData.scriptClass->addInternalCall("Internal_SetNormals", &ScriptMeshData::internal_SetNormals);
+		metaData.scriptClass->addInternalCall("Internal_GetTangents", &ScriptMeshData::internal_GetTangents);
+		metaData.scriptClass->addInternalCall("Internal_SetTangents", &ScriptMeshData::internal_SetTangents);
+		metaData.scriptClass->addInternalCall("Internal_GetColors", &ScriptMeshData::internal_GetColors);
+		metaData.scriptClass->addInternalCall("Internal_SetColors", &ScriptMeshData::internal_SetColors);
+		metaData.scriptClass->addInternalCall("Internal_GetUV0", &ScriptMeshData::internal_GetUV0);
+		metaData.scriptClass->addInternalCall("Internal_SetUV0", &ScriptMeshData::internal_SetUV0);
+		metaData.scriptClass->addInternalCall("Internal_GetUV1", &ScriptMeshData::internal_GetUV1);
+		metaData.scriptClass->addInternalCall("Internal_SetUV1", &ScriptMeshData::internal_SetUV1);
+		metaData.scriptClass->addInternalCall("Internal_GetBoneWeights", &ScriptMeshData::internal_GetBoneWeights);
+		metaData.scriptClass->addInternalCall("Internal_SetBoneWeights", &ScriptMeshData::internal_SetBoneWeights);
+		metaData.scriptClass->addInternalCall("Internal_GetIndices", &ScriptMeshData::internal_GetIndices);
+		metaData.scriptClass->addInternalCall("Internal_SetIndices", &ScriptMeshData::internal_SetIndices);
+		metaData.scriptClass->addInternalCall("Internal_GetVertexCount", &ScriptMeshData::internal_GetVertexCount);
+		metaData.scriptClass->addInternalCall("Internal_GetIndexCount", &ScriptMeshData::internal_GetIndexCount);
+	}
+
+	void ScriptMeshData::initialize(const RendererMeshDataPtr& meshData)
+	{
+		mMeshData = meshData;
+	}
+
+	MonoObject* ScriptMeshData::create(const RendererMeshDataPtr& meshData)
+	{
+		MonoObject* meshDataObj = metaData.scriptClass->createInstance();
+
+		ScriptMeshData* scriptMeshData = new (bs_alloc<ScriptMeshData>()) ScriptMeshData(meshDataObj);
+		scriptMeshData->initialize(meshData);
+
+		return meshDataObj;
+	}
+
+	MonoObject* ScriptMeshData::create(const MeshDataPtr& meshData)
+	{
+		MonoObject* meshDataObj = metaData.scriptClass->createInstance();
+
+		RendererMeshDataPtr defaultMeshData = RendererMeshData::create(meshData);
+		ScriptMeshData* scriptMeshData = new (bs_alloc<ScriptMeshData>()) ScriptMeshData(meshDataObj);
+		scriptMeshData->initialize(defaultMeshData);
+
+		return meshDataObj;
+	}
+
+	void ScriptMeshData::internal_CreateInstance(MonoObject* instance, int numVertices,
+		int numIndices, VertexLayout vertex, ScriptIndexType index)
+	{
+		IndexType indexType = IT_16BIT;
+		if (index == ScriptIndexType::Index32)
+			indexType = IT_32BIT;
+
+		RendererMeshDataPtr meshData = RendererMeshData::create(numVertices, numIndices, vertex, indexType);
+
+		ScriptMeshData* scriptMeshData = new (bs_alloc<ScriptMeshData>()) ScriptMeshData(instance);
+		scriptMeshData->initialize(meshData);
+	}
+
+	MonoArray* ScriptMeshData::internal_GetPositions(ScriptMeshData* thisPtr)
+	{
+		return getVertexDataArray<(int)VertexLayout::Position, Vector3, ScriptVector3>(thisPtr);
+	}
+
+	void ScriptMeshData::internal_SetPositions(ScriptMeshData* thisPtr, MonoArray* value)
+	{
+		setVertexDataArray<(int)VertexLayout::Position, Vector3, ScriptVector3>(thisPtr, value);
+	}
+
+	MonoArray* ScriptMeshData::internal_GetNormals(ScriptMeshData* thisPtr)
+	{
+		return getVertexDataArray<(int)VertexLayout::Normal, Vector3, ScriptVector3>(thisPtr);
+	}
+
+	void ScriptMeshData::internal_SetNormals(ScriptMeshData* thisPtr, MonoArray* value)
+	{
+		setVertexDataArray<(int)VertexLayout::Normal, Vector3, ScriptVector3>(thisPtr, value);
+	}
+
+	MonoArray* ScriptMeshData::internal_GetTangents(ScriptMeshData* thisPtr)
+	{
+		return getVertexDataArray<(int)VertexLayout::Tangent, Vector4, ScriptVector4>(thisPtr);
+	}
+
+	void ScriptMeshData::internal_SetTangents(ScriptMeshData* thisPtr, MonoArray* value)
+	{
+		setVertexDataArray<(int)VertexLayout::Tangent, Vector4, ScriptVector4>(thisPtr, value);
+	}
+
+	MonoArray* ScriptMeshData::internal_GetColors(ScriptMeshData* thisPtr)
+	{
+		return getVertexDataArray<(int)VertexLayout::Color, Color, ScriptColor>(thisPtr);
+	}
+
+	void ScriptMeshData::internal_SetColors(ScriptMeshData* thisPtr, MonoArray* value)
+	{
+		setVertexDataArray<(int)VertexLayout::Color, Color, ScriptColor>(thisPtr, value);
+	}
+
+	MonoArray* ScriptMeshData::internal_GetUV0(ScriptMeshData* thisPtr)
+	{
+		return getVertexDataArray<(int)VertexLayout::UV0, Vector2, ScriptVector2>(thisPtr);
+	}
+
+	void ScriptMeshData::internal_SetUV0(ScriptMeshData* thisPtr, MonoArray* value)
+	{
+		setVertexDataArray<(int)VertexLayout::UV0, Vector2, ScriptVector2>(thisPtr, value);
+	}
+
+	MonoArray* ScriptMeshData::internal_GetUV1(ScriptMeshData* thisPtr)
+	{
+		return getVertexDataArray<(int)VertexLayout::UV1, Vector2, ScriptVector2>(thisPtr);
+	}
+
+	void ScriptMeshData::internal_SetUV1(ScriptMeshData* thisPtr, MonoArray* value)
+	{
+		setVertexDataArray<(int)VertexLayout::UV1, Vector2, ScriptVector2>(thisPtr, value);
+	}
+
+	MonoArray* ScriptMeshData::internal_GetBoneWeights(ScriptMeshData* thisPtr)
+	{
+		return getVertexDataArray<(int)VertexLayout::BoneWeights, BoneWeight, ScriptBoneWeight>(thisPtr);
+	}
+
+	void ScriptMeshData::internal_SetBoneWeights(ScriptMeshData* thisPtr, MonoArray* value)
+	{
+		setVertexDataArray<(int)VertexLayout::BoneWeights, BoneWeight, ScriptBoneWeight>(thisPtr, value);
+	}
+
+	MonoArray* ScriptMeshData::internal_GetIndices(ScriptMeshData* thisPtr)
+	{
+		RendererMeshDataPtr meshData = thisPtr->getInternalValue();
+		UINT32 numElements = meshData->getData()->getNumIndices();
+
+		ScriptArray outArray = ScriptArray::create<UINT32>(numElements);
+		meshData->getIndices(outArray.getRawPtr<UINT32>(), numElements * sizeof(UINT32));
+
+		return outArray.getInternal();
+	}
+
+	void ScriptMeshData::internal_SetIndices(ScriptMeshData* thisPtr, MonoArray* value)
+	{
+		if (value == nullptr)
+			return;
+
+		RendererMeshDataPtr meshData = thisPtr->getInternalValue();
+		UINT32 numElements = meshData->getData()->getNumIndices();
+
+		ScriptArray inArray(value);
+		meshData->setIndices(inArray.getRawPtr<UINT32>(), numElements * sizeof(UINT32));
+	}
+
+	int ScriptMeshData::internal_GetVertexCount(ScriptMeshData* thisPtr)
+	{
+		RendererMeshDataPtr meshData = thisPtr->getInternalValue();
+
+		return (int)meshData->getData()->getNumVertices();
+	}
+
+	int ScriptMeshData::internal_GetIndexCount(ScriptMeshData* thisPtr)
+	{
+		RendererMeshDataPtr meshData = thisPtr->getInternalValue();
+
+		return (int)meshData->getData()->getNumIndices();
+	}
+
+	bool ScriptMeshData::checkIsLocked(ScriptMeshData* thisPtr)
+	{
+		if (thisPtr->mMeshData->getData()->isLocked())
+		{
+			LOGWRN("Attempting to access a locked mesh data buffer.");
+			return true;
+		}
+
+		return false;
+	}
 }