Browse Source

Added C# Renderable and Mesh interfaces

Marko Pintera 10 years ago
parent
commit
42f50ced62
61 changed files with 2810 additions and 124 deletions
  1. 3 0
      BansheeCore/BansheeCore.vcxproj
  2. 9 0
      BansheeCore/BansheeCore.vcxproj.filters
  3. 1 0
      BansheeCore/Include/BsCorePrerequisites.h
  4. 1 1
      BansheeCore/Include/BsGpuResourceData.h
  5. 50 28
      BansheeCore/Include/BsMesh.h
  6. 5 14
      BansheeCore/Include/BsMeshBase.h
  7. 34 1
      BansheeCore/Include/BsMeshData.h
  8. 101 0
      BansheeCore/Include/BsMeshImportOptions.h
  9. 57 0
      BansheeCore/Include/BsMeshImportOptionsRTTI.h
  10. 8 8
      BansheeCore/Include/BsMeshManager.h
  11. 1 1
      BansheeCore/Include/BsPixelData.h
  12. 24 0
      BansheeCore/Include/BsTextureImportOptions.h
  13. 8 0
      BansheeCore/Include/BsTextureImportOptionsRTTI.h
  14. 6 0
      BansheeCore/Include/BsVertexDataDesc.h
  15. 103 38
      BansheeCore/Source/BsMesh.cpp
  16. 38 2
      BansheeCore/Source/BsMeshData.cpp
  17. 23 0
      BansheeCore/Source/BsMeshImportOptions.cpp
  18. 8 8
      BansheeCore/Source/BsMeshManager.cpp
  19. 4 4
      BansheeCore/Source/BsMeshRTTI.h
  20. 1 1
      BansheeCore/Source/BsPixelData.cpp
  21. 1 1
      BansheeCore/Source/BsTexture.cpp
  22. 2 1
      BansheeCore/Source/BsTextureImportOptions.cpp
  23. 5 0
      BansheeCore/Source/BsVertexDataDesc.cpp
  24. 2 0
      BansheeEngine/BansheeEngine.vcxproj
  25. 6 0
      BansheeEngine/BansheeEngine.vcxproj.filters
  26. 237 0
      BansheeEngine/Include/BsDefaultMeshData.h
  27. 2 0
      BansheeEngine/Include/BsPrerequisites.h
  28. 349 0
      BansheeEngine/Source/BsDefaultMeshData.cpp
  29. 8 1
      BansheeEngine/Source/BsRenderableHandler.cpp
  30. 7 1
      BansheeFreeImgImporter/Source/BsFreeImgImporter.cpp
  31. 16 0
      BansheeMono/Include/BsMonoArray.h
  32. 14 0
      MBansheeEngine/Bounds.cs
  33. 3 0
      MBansheeEngine/Camera.cs
  34. 6 0
      MBansheeEngine/MBansheeEngine.csproj
  35. 143 0
      MBansheeEngine/Mesh.cs
  36. 181 0
      MBansheeEngine/MeshData.cs
  37. 104 0
      MBansheeEngine/Renderable.cs
  38. 110 0
      MBansheeEngine/RenderableHandler.cs
  39. 29 0
      MBansheeEngine/Sphere.cs
  40. 9 0
      SBansheeEditor/Source/BsGUIResourceField.cpp
  41. 1 0
      SBansheeEngine/Include/BsManagedSerializableObjectInfo.h
  42. 2 0
      SBansheeEngine/Include/BsScriptAssemblyManager.h
  43. 20 0
      SBansheeEngine/Include/BsScriptBoneWeight.h
  44. 2 0
      SBansheeEngine/Include/BsScriptEnginePrerequisites.h
  45. 71 0
      SBansheeEngine/Include/BsScriptMesh.h
  46. 56 0
      SBansheeEngine/Include/BsScriptMeshData.h
  47. 33 0
      SBansheeEngine/Include/BsScriptRenderableHandler.h
  48. 17 0
      SBansheeEngine/Include/BsScriptResourceManager.h
  49. 46 0
      SBansheeEngine/Include/BsScriptVector.h
  50. 10 0
      SBansheeEngine/SBansheeEngine.vcxproj
  51. 30 0
      SBansheeEngine/SBansheeEngine.vcxproj.filters
  52. 28 0
      SBansheeEngine/Source/BsManagedSerializableField.cpp
  53. 2 0
      SBansheeEngine/Source/BsManagedSerializableObjectInfo.cpp
  54. 12 1
      SBansheeEngine/Source/BsScriptAssemblyManager.cpp
  55. 26 0
      SBansheeEngine/Source/BsScriptBoneWeight.cpp
  56. 213 0
      SBansheeEngine/Source/BsScriptMesh.cpp
  57. 307 0
      SBansheeEngine/Source/BsScriptMeshData.cpp
  58. 116 0
      SBansheeEngine/Source/BsScriptRenderableHandler.cpp
  59. 29 0
      SBansheeEngine/Source/BsScriptResourceManager.cpp
  60. 64 0
      SBansheeEngine/Source/BsScriptVector.cpp
  61. 6 13
      TODO.txt

+ 3 - 0
BansheeCore/BansheeCore.vcxproj

@@ -280,6 +280,8 @@
   <ItemGroup>
     <ClInclude Include="Include\BsCoreObjectCore.h" />
     <ClInclude Include="Include\BsDrawList.h" />
+    <ClInclude Include="Include\BsMeshImportOptions.h" />
+    <ClInclude Include="Include\BsMeshImportOptionsRTTI.h" />
     <ClInclude Include="Include\BsShaderIncludeRTTI.h" />
     <ClInclude Include="Include\BsIResourceListener.h" />
     <ClInclude Include="Include\BsMaterialParam.h" />
@@ -431,6 +433,7 @@
     <ClCompile Include="Source\BsDrawList.cpp" />
     <ClCompile Include="Source\BsIResourceListener.cpp" />
     <ClCompile Include="Source\BsMaterialParam.cpp" />
+    <ClCompile Include="Source\BsMeshImportOptions.cpp" />
     <ClCompile Include="Source\BsProfilerCPU.cpp" />
     <ClCompile Include="Source\BsDeferredCallManager.cpp" />
     <ClCompile Include="Source\BsDrawOps.cpp" />

+ 9 - 0
BansheeCore/BansheeCore.vcxproj.filters

@@ -524,6 +524,12 @@
     <ClInclude Include="Include\BsShaderManager.h">
       <Filter>Header Files\Material</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsMeshImportOptions.h">
+      <Filter>Header Files\Importer</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsMeshImportOptionsRTTI.h">
+      <Filter>Header Files\RTTI</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsCoreApplication.cpp">
@@ -829,5 +835,8 @@
     <ClCompile Include="Source\BsShaderManager.cpp">
       <Filter>Source Files\Material</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsMeshImportOptions.cpp">
+      <Filter>Source Files\Importer</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 1 - 0
BansheeCore/Include/BsCorePrerequisites.h

@@ -328,6 +328,7 @@ namespace BansheeEngine
 		TID_Viewport = 1073,
 		TID_ResourceDependencies = 1074,
 		TID_ShaderMetaData = 1075,
+		TID_MeshImportOptions = 1076
 	};
 }
 

+ 1 - 1
BansheeCore/Include/BsGpuResourceData.h

@@ -88,7 +88,7 @@ namespace BansheeEngine
 		 * @brief	Returns the size of the internal buffer in bytes. This is calculated based
 		 *			on parameters provided upon construction and specific implementation details.
 		 */
-		virtual UINT32 getInternalBufferSize() = 0;
+		virtual UINT32 getInternalBufferSize() const = 0;
 
 	private:
 		UINT8* mData;

+ 50 - 28
BansheeCore/Include/BsMesh.h

@@ -21,7 +21,7 @@ namespace BansheeEngine
 	{
 	public:
 		MeshCore(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc,
-			const Vector<SubMesh>& subMeshes, MeshBufferType bufferType, IndexType indexType,
+			const Vector<SubMesh>& subMeshes, int usage, IndexType indexType,
 			MeshDataPtr initialMeshData);
 
 		~MeshCore();
@@ -75,7 +75,7 @@ namespace BansheeEngine
 		SPtr<IndexBufferCore> mIndexBuffer;
 
 		VertexDataDescPtr mVertexDesc;
-		MeshBufferType mBufferType;
+		int mUsage;
 		IndexType mIndexType;
 		MeshDataPtr mTempInitialMeshData;
 	};
@@ -132,6 +132,20 @@ namespace BansheeEngine
 		 */
 		MeshDataPtr allocateSubresourceBuffer(UINT32 subresourceIdx) const;
 
+		/**
+		 * @brief	Reads data from the cached system memory mesh buffer into the provided buffer. 
+		 * 		  
+		 * @param	dest		Previously allocated buffer to read data into.
+		 *
+		 * @note	The data read is the cached mesh data. Any data written to the mesh from the GPU 
+		 *			or core thread will not be reflected in this data. Use "readSubresource" if you require
+		 *			those changes.
+		 *
+		 *			The mesh must have been created with MU_CPUCACHED usage otherwise this method
+		 *			will not return any data.
+		 */
+		void readData(MeshData& dest);
+
 		/**
 		 * @brief	Retrieves a core implementation of a mesh usable only from the
 		 *			core thread.
@@ -147,17 +161,17 @@ namespace BansheeEngine
 		friend class MeshManager;
 
 		Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
-			MeshBufferType bufferType = MeshBufferType::Static, DrawOperationType drawOp = DOT_TRIANGLE_LIST,
+			int usage = MU_STATIC, DrawOperationType drawOp = DOT_TRIANGLE_LIST,
 			IndexType indexType = IT_32BIT);
 
 		Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc,
-			const Vector<SubMesh>& subMeshes, MeshBufferType bufferType = MeshBufferType::Static,
+			const Vector<SubMesh>& subMeshes, int usage = MU_STATIC,
 			IndexType indexType = IT_32BIT);
 
-		Mesh(const MeshDataPtr& initialMeshData, MeshBufferType bufferType = MeshBufferType::Static, 
+		Mesh(const MeshDataPtr& initialMeshData, int usage = MU_STATIC,
 			DrawOperationType drawOp = DOT_TRIANGLE_LIST);
 
-		Mesh(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes, MeshBufferType bufferType = MeshBufferType::Static);
+		Mesh(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes, int usage = MU_STATIC);
 
 		/**
 		 * @brief	Updates bounds by calculating them from the vertices in the provided mesh data object.
@@ -169,10 +183,22 @@ namespace BansheeEngine
 		 */
 		SPtr<CoreObjectCore> createCore() const;
 
-		mutable MeshDataPtr mTempInitialMeshData;
+		/**
+		 * @brief	Creates buffers used for caching of CPU mesh data.
+		 *
+		 * @note	Make sure to initialize all mesh properties before calling this.
+		 */
+		void createCPUBuffer();
+
+		/**
+		 * @brief	Updates the cached CPU buffers with new data.
+		 */
+		void updateCPUBuffer(UINT32 subresourceIdx, const MeshData& data);
+
+		mutable MeshDataPtr mCPUData;
 
 		VertexDataDescPtr mVertexDesc;
-		MeshBufferType mBufferType;
+		int mUsage;
 		IndexType mIndexType;
 
 		/************************************************************************/
@@ -199,14 +225,13 @@ namespace BansheeEngine
 		 * @param	vertexDesc		Vertex description structure that describes how are vertices organized in the
 		 *							vertex buffer. When binding a mesh to the pipeline you must ensure vertex description
 		 *							at least partially matches the input description of the currently bound vertex GPU program.
-		 * @param	bufferType		Specify static for buffers you don't plan on updating other reading from often. Otherwise specify
-		 *							dynamic. This parameter affects performance.
+		 * @param	usage			Optimizes performance depending on planned usage of the mesh.
 		 * @param	drawOp			Determines how should the provided indices be interpreted by the pipeline. Default option is triangles,
 		 *							where three indices represent a single triangle.
 		 * @param	indexType		Size of indices, use smaller size for better performance, however be careful not to go over
 		 *							the number of vertices limited by the size.
 		 */
-		static HMesh create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, MeshBufferType bufferType = MeshBufferType::Static,
+		static HMesh create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, int usage = MU_STATIC,
 			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT);
 
 		/**
@@ -219,25 +244,23 @@ namespace BansheeEngine
 		 *							at least partially matches the input description of the currently bound vertex GPU program.
 		 * @param	subMeshes		Defines how are indices separated into sub-meshes, and how are those sub-meshes rendered.
 		 *							Sub-meshes may be rendered independently.
-		 * @param	bufferType		Specify static for buffers you don't plan on updating other reading from often. Otherwise specify
-		 *							dynamic. This parameter affects performance.
+		 * @param	usage			Optimizes performance depending on planned usage of the mesh.
 		 * @param	indexType		Size of indices, use smaller size for better performance, however be careful not to go over
 		 *							the number of vertices limited by the size.
 		 */
 		static HMesh create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, const Vector<SubMesh>& subMeshes,
-			MeshBufferType bufferType = MeshBufferType::Static, IndexType indexType = IT_32BIT);
+			int usage = MU_STATIC, IndexType indexType = IT_32BIT);
 
 		/**
 		 * @brief	Creates a new mesh from an existing mesh data. Created mesh will match the vertex and index buffers described
 		 *			by the mesh data exactly. Created mesh will have no sub-meshes.
 		 *
 		 * @param	initialMeshData	Vertex and index data used for initializing the mesh. 
-		 * @param	bufferType		Specify static for buffers you don't plan on updating other reading from often. Otherwise specify
-		 *							dynamic. This parameter affects performance.
+		 * @param	usage			Optimizes performance depending on planned usage of the mesh.
 		 * @param	drawOp			Determines how should the provided indices be interpreted by the pipeline. Default option is triangles,
 		 *							where three indices represent a single triangle.
 		 */
-		static HMesh create(const MeshDataPtr& initialMeshData, MeshBufferType bufferType = MeshBufferType::Static, 
+		static HMesh create(const MeshDataPtr& initialMeshData, int usage = MU_STATIC,
 			DrawOperationType drawOp = DOT_TRIANGLE_LIST);
 
 		/**
@@ -247,43 +270,42 @@ namespace BansheeEngine
 		 * @param	initialMeshData	Vertex and index data used for initializing the mesh. 
 		 * @param	subMeshes		Defines how are indices separated into sub-meshes, and how are those sub-meshes rendered.
 		 *							Sub-meshes may be rendered independently.
-		 * @param	bufferType		Specify static for buffers you don't plan on updating other reading from often. Otherwise specify
-		 *							dynamic. This parameter affects performance.
+		 * @param	usage			Optimizes performance depending on planned usage of the mesh.
 		 */
-		static HMesh create(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes, MeshBufferType bufferType = MeshBufferType::Static);
+		static HMesh create(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes, int usage = MU_STATIC);
 
 		/**
-		 * @copydoc	create(UINT32, UINT32, const VertexDataDescPtr&, MeshBufferType, DrawOperationType, IndexType)
+		 * @copydoc	create(UINT32, UINT32, const VertexDataDescPtr&, int, DrawOperationType, IndexType)
 		 *
 		 * @note	Internal method. Use "create" for normal use.
 		 */
 		static MeshPtr _createPtr(UINT32 numVertices, UINT32 numIndices, 
-			const VertexDataDescPtr& vertexDesc, MeshBufferType bufferType = MeshBufferType::Static,
+			const VertexDataDescPtr& vertexDesc, int usage = MU_STATIC,
 			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT);
 
 		/**
-		 * @copydoc	create(UINT32, UINT32, const VertexDataDescPtr&, const Vector<SubMesh>&, MeshBufferType, IndexType)
+		 * @copydoc	create(UINT32, UINT32, const VertexDataDescPtr&, const Vector<SubMesh>&, int, IndexType)
 		 *
 		 * @note	Internal method. Use "create" for normal use.
 		 */
 		static MeshPtr _createPtr(UINT32 numVertices, UINT32 numIndices, 
 			const VertexDataDescPtr& vertexDesc, const Vector<SubMesh>& subMeshes,
-			MeshBufferType bufferType = MeshBufferType::Static, IndexType indexType = IT_32BIT);
+			int usage = MU_STATIC, IndexType indexType = IT_32BIT);
 
 		/**
-		 * @copydoc	create(const MeshDataPtr&, MeshBufferType, DrawOperationType)
+		 * @copydoc	create(const MeshDataPtr&, int, DrawOperationType)
 		 *
 		 * @note	Internal method. Use "create" for normal use.
 		 */
-		static MeshPtr _createPtr(const MeshDataPtr& initialMeshData, MeshBufferType bufferType = MeshBufferType::Static,
+		static MeshPtr _createPtr(const MeshDataPtr& initialMeshData, int usage = MU_STATIC,
 			DrawOperationType drawOp = DOT_TRIANGLE_LIST);
 
 		/**
-		 * @copydoc	create(const MeshDataPtr&, const Vector<SubMesh>&, MeshBufferType)
+		 * @copydoc	create(const MeshDataPtr&, const Vector<SubMesh>&, int)
 		 *
 		 * @note	Internal method. Use "create" for normal use.
 		 */
 		static MeshPtr _createPtr(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes,
-			MeshBufferType bufferType = MeshBufferType::Static);
+			int usage = MU_STATIC);
 	};
 }

+ 5 - 14
BansheeCore/Include/BsMeshBase.h

@@ -9,24 +9,15 @@
 namespace BansheeEngine
 {
 	/**
-	 * @brief	Type of mesh dirty flags
-	 */
-	enum class MeshDirtyFlag
-	{
-		Mesh = 0x01, /**< Internal mesh data is dirty. */
-		Proxy = 0x02 /**< Active proxy needs to be updated. */
-	};
-
-
-	/**
-	 * @brief	Type of buffers used by a mesh. These options usually affect performance and 
+	 * @brief	Planned usage for the mesh. These options usually affect performance and 
 	 *			you should specify static if you don't plan on modifying the mesh often,
 	 *			otherwise specify dynamic.
 	 */
-	enum class MeshBufferType
+	enum MeshUsage
 	{
-		Static,
-		Dynamic
+		MU_STATIC, /**< A mesh that is not often updated from the CPU. */
+		MU_DYNAMIC, /**< A mesh that is often updated from the CPU. */
+		MU_CPUCACHED = 0x1000 /**< All mesh data will also be cached in CPU memory. */
 	};
 
 	/**

+ 34 - 1
BansheeCore/Include/BsMeshData.h

@@ -87,6 +87,23 @@ namespace BansheeEngine
 		UINT32 mNumElements;
 	};
 
+	/**
+	 * @brief	Contains per-vertex bone weights and indexes used 
+	 *			for skinning, for up to four bones.
+	 */
+	struct BoneWeight
+	{
+		int index0;
+		int index1;
+		int index2;
+		int index3;
+
+		float weight0;
+		float weight1;
+		float weight2;
+		float weight3;
+	};
+
 	/**
 	 * @brief	Used for initializing, updating and reading mesh data from Meshes.
 	 */
@@ -111,6 +128,17 @@ namespace BansheeEngine
 		 */
 		void setVertexData(VertexElementSemantic semantic, UINT8* data, UINT32 size, UINT32 semanticIdx = 0, UINT32 streamIdx = 0);
 
+		/**
+		 * @brief	Copies data from the internal buffer to the pre-allocated buffer for the specified semantic.
+		 *
+		 * @param	semantic   		Semantic that allows the engine to connect the data to a shader input slot.
+		 * @param	data			Buffer that will receive vertex data, of at least "size" bytes.
+		 * @param	size			The size of the data. Must be the size of the vertex element type * number of vertices.
+		 * @param	semanticIdx 	(optional) If there are multiple semantics with the same name, use different index to differentiate between them.
+		 * @param	streamIdx   	(optional) Zero-based index of the stream. Each stream will internally be represented as a single vertex buffer.
+		 */
+		void getVertexData(VertexElementSemantic semantic, UINT8* data, UINT32 size, UINT32 semanticIdx = 0, UINT32 streamIdx = 0);
+
 		/**
 		 * @brief	Returns an iterator you can use for easily retrieving or setting Vector2 vertex elements. This is the preferred
 		 * 			method of assigning or reading vertex data. 
@@ -201,6 +229,11 @@ namespace BansheeEngine
 		 */
 		const VertexDataDescPtr& getVertexDesc() const { return mVertexData; }
 
+		/**
+		 * @brief	Return the size (in bytes) of the entire buffer.
+		 */
+		UINT32 getSize() const { return getInternalBufferSize(); }
+
 		/**
 		 * @brief	Calculates the bounds of all vertices stored in the internal buffer.
 		 */
@@ -225,7 +258,7 @@ namespace BansheeEngine
 		/**
 		 * @brief	Returns the size of the internal buffer in bytes.
 		 */
-		UINT32 getInternalBufferSize();
+		UINT32 getInternalBufferSize() const;
 
 	private:
 		/**

+ 101 - 0
BansheeCore/Include/BsMeshImportOptions.h

@@ -0,0 +1,101 @@
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsImportOptions.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Contains import options you may use to control how is a mesh imported
+	 *			from some external format into engine format.
+	 */
+	class BS_CORE_EXPORT MeshImportOptions : public ImportOptions
+	{
+	public:
+		MeshImportOptions();
+
+		/**
+		 * @brief	Sets whether the texture data is also stored in CPU memory.
+		 */
+		void setCPUReadable(bool readable) { mCPUReadable = readable; }
+		
+		/**
+		 * @brief	Retrieves whether the texture data is also stored in CPU memory.
+		 */
+		bool getCPUReadable() const { return mCPUReadable; }
+
+		/**
+		 * @brief	Sets a value that controls should mesh normals be imported
+		 *			if available.
+		 */
+		void setImportNormals(bool import) { mImportNormals = import; }
+
+		/**
+		 * @brief	Retrieves a value that controls should mesh normals be imported
+		 *			if available.
+		 */
+		bool getImportNormals() const { return mImportNormals; }
+
+		/**
+		 * @brief	Sets a value that controls should mesh tangent/bitangent be imported
+		 *			if available.
+		 */
+		void setImportTangents(bool import) { mImportTangents = import; }
+
+		/**
+		 * @brief	Retrieves a value that controls should mesh tangent/bitangent be imported
+		 *			if available.
+		 */
+		bool getImportTangents() const { return mImportTangents; }
+
+		/**
+		 * @brief	Sets a value that controls should mesh blend shapes be imported
+		 *			if available.
+		 */
+		void setImportBlendShapes(bool import) { mImportBlendShapes = import; }
+
+		/**
+		 * @brief	Retrieves a value that controls should mesh blend shapes be imported
+		 *			if available.
+		 */
+		bool getImportBlendShapes() const { return mImportBlendShapes; }
+
+		/**
+		 * @brief	Sets a value that controls should mesh skin data like bone weights, 
+		 *			indices and bind poses be imported if available.
+		 */
+		void setImportSkin(bool import) { mImportSkin = import; }
+
+		/**
+		 * @brief	Retrieves a value that controls should mesh skin data like bone weights, 
+		 *			indices and bind poses be imported if available.
+		 */
+		bool getImportSkin() const { return mImportSkin; }
+
+		/**
+		 * @brief	Sets a value that controls should animation clips be imported if available.
+		 */
+		void setImportAnimation(bool import) { mImportAnimation = import; }
+
+		/**
+		 * @brief	Retrieves a value that controls should animation clips be imported if available.
+		 */
+		bool getImportAnimation() const { return mImportAnimation; }
+
+		/************************************************************************/
+		/* 								SERIALIZATION                      		*/
+		/************************************************************************/
+	public:
+		friend class MeshImportOptionsRTTI;
+		static RTTITypeBase* getRTTIStatic();
+		virtual RTTITypeBase* getRTTI() const;
+
+	private:
+		bool mCPUReadable;
+		bool mImportNormals;
+		bool mImportTangents;
+		bool mImportBlendShapes;
+		bool mImportSkin;
+		bool mImportAnimation;
+	};
+}

+ 57 - 0
BansheeCore/Include/BsMeshImportOptionsRTTI.h

@@ -0,0 +1,57 @@
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsRTTIType.h"
+#include "BsMeshImportOptions.h"
+
+namespace BansheeEngine
+{
+	class BS_CORE_EXPORT MeshImportOptionsRTTI : public RTTIType < MeshImportOptions, ImportOptions, MeshImportOptionsRTTI >
+	{
+	private:
+		bool& getCPUReadable(MeshImportOptions* obj) { return obj->mCPUReadable; }
+		void setCPUReadable(MeshImportOptions* obj, bool& value) { obj->mCPUReadable = value; }
+		
+		bool& getImportNormals(MeshImportOptions* obj) { return obj->mImportNormals; }
+		void setImportNormals(MeshImportOptions* obj, bool& value) { obj->mImportNormals = value; }
+		
+		bool& getImportTangents(MeshImportOptions* obj) { return obj->mImportTangents; }
+		void setImportTangents(MeshImportOptions* obj, bool& value) { obj->mImportTangents = value; }
+		
+		bool& getImportBlendShapes(MeshImportOptions* obj) { return obj->mImportBlendShapes; }
+		void setImportBlendShapes(MeshImportOptions* obj, bool& value) { obj->mImportBlendShapes = value; }
+		
+		bool& getImportSkin(MeshImportOptions* obj) { return obj->mImportSkin; }
+		void setImportSkin(MeshImportOptions* obj, bool& value) { obj->mImportSkin = value; }
+		
+		bool& getImportAnimation(MeshImportOptions* obj) { return obj->mImportAnimation; }
+		void setImportAnimation(MeshImportOptions* obj, bool& value) { obj->mImportAnimation = value; }
+
+	public:
+		MeshImportOptionsRTTI()
+		{
+			addPlainField("mCPUReadable", 0, &MeshImportOptionsRTTI::getCPUReadable, &MeshImportOptionsRTTI::setCPUReadable);
+			addPlainField("mImportNormals", 1, &MeshImportOptionsRTTI::getImportNormals, &MeshImportOptionsRTTI::setImportNormals);
+			addPlainField("mImportTangents", 2, &MeshImportOptionsRTTI::getImportTangents, &MeshImportOptionsRTTI::setImportTangents);
+			addPlainField("mImportBlendShapes", 3, &MeshImportOptionsRTTI::getImportBlendShapes, &MeshImportOptionsRTTI::setImportBlendShapes);
+			addPlainField("mImportSkin", 4, &MeshImportOptionsRTTI::getImportSkin, &MeshImportOptionsRTTI::setImportSkin);
+			addPlainField("mImportAnimation", 5, &MeshImportOptionsRTTI::getImportAnimation, &MeshImportOptionsRTTI::setImportAnimation);
+		}
+
+		virtual const String& getRTTIName()
+		{
+			static String name = "MeshImportOptions";
+			return name;
+		}
+
+		virtual UINT32 getRTTIId()
+		{
+			return TID_MeshImportOptions;
+		}
+
+		virtual std::shared_ptr<IReflectable> newRTTIObject()
+		{
+			return bs_shared_ptr<MeshImportOptions, PoolAlloc>();
+		}
+	};
+}

+ 8 - 8
BansheeCore/Include/BsMeshManager.h

@@ -16,26 +16,26 @@ namespace BansheeEngine
 		~MeshManager();
 
 		/**
-		 * @copydoc	Mesh::create(UINT32, UINT32, const VertexDataDescPtr&, MeshBufferType, DrawOperationType, IndexType)
+		 * @copydoc	Mesh::create(UINT32, UINT32, const VertexDataDescPtr&, int, DrawOperationType, IndexType)
 		 */
-		MeshPtr create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, MeshBufferType bufferType = MeshBufferType::Static, 
+		MeshPtr create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, int usage = MU_STATIC, 
 			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexType indexType = IT_32BIT);
 
 		/**
-		 * @copydoc	Mesh::create(UINT32, UINT32, const VertexDataDescPtr&, const Vector<SubMesh>&, MeshBufferType, IndexType)
+		 * @copydoc	Mesh::create(UINT32, UINT32, const VertexDataDescPtr&, const Vector<SubMesh>&, int, IndexType)
 		 */
 		MeshPtr create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, const Vector<SubMesh>& subMeshes, 
-			MeshBufferType bufferType = MeshBufferType::Static, IndexType indexType = IT_32BIT);
+			int usage = MU_STATIC, IndexType indexType = IT_32BIT);
 
 		/**
-		 * @copyodc	Mesh::create(const MeshDataPtr&, MeshBufferType, DrawOperationType)
+		 * @copyodc	Mesh::create(const MeshDataPtr&, int, DrawOperationType)
 		 */
-		MeshPtr create(const MeshDataPtr& initialData, MeshBufferType bufferType = MeshBufferType::Static, DrawOperationType drawOp = DOT_TRIANGLE_LIST);
+		MeshPtr create(const MeshDataPtr& initialData, int usage = MU_STATIC, DrawOperationType drawOp = DOT_TRIANGLE_LIST);
 
 		/**
-		 * @copyodc	Mesh::create(const MeshDataPtr&, const Vector<SubMesh>&, MeshBufferType)
+		 * @copyodc	Mesh::create(const MeshDataPtr&, const Vector<SubMesh>&, int)
 		 */
-		MeshPtr create(const MeshDataPtr& initialData, const Vector<SubMesh>& subMeshes, MeshBufferType bufferType = MeshBufferType::Static);
+		MeshPtr create(const MeshDataPtr& initialData, const Vector<SubMesh>& subMeshes, int usage = MU_STATIC);
 
 		/**
 		 * @brief	Creates a new empty and uninitialized mesh. You will need to manually initialize the mesh before using it.

+ 1 - 1
BansheeCore/Include/BsPixelData.h

@@ -347,7 +347,7 @@ namespace BansheeEngine
 		/**
 		 * @brief	Returns the needed size of the internal buffer, in bytes.
 		 */
-		UINT32 getInternalBufferSize();
+		UINT32 getInternalBufferSize() const;
 
 	private:
 		PixelVolume mExtents;

+ 24 - 0
BansheeCore/Include/BsTextureImportOptions.h

@@ -31,6 +31,17 @@ namespace BansheeEngine
 		 */
 		void setMaxMip(UINT32 maxMip) { mMaxMip = maxMip; }
 
+		/**
+		 * @brief	Sets whether the texture data is also stored in CPU memory.
+		 */
+		void setCPUReadable(bool readable) { mCPUReadable = readable; }
+
+		/**
+		 * @brief	Sets whether the texture data should be treated as if its in sRGB (gamma) space.
+		 *			Such texture will be converted by hardware to linear space before use.
+		 */
+		void setSRGB(bool sRGB) { mSRGB = sRGB; }
+
 		/**
 		 * @brief	Gets the pixel format that the imported texture will have.
 		 */
@@ -47,6 +58,17 @@ namespace BansheeEngine
 		 */
 		UINT32 getMaxMip() const { return mMaxMip; }
 
+		/**
+		 * @brief	Retrieves whether the texture data is also stored in CPU memory.
+		 */
+		bool getCPUReadable() const { return mCPUReadable; }
+
+		/**
+		 * @brief	Retrieves whether the texture data should be treated as if its in sRGB (gamma) space.
+		 *			Such texture will be converted by hardware to linear space before use.
+		 */
+		bool getSRGB() const { return mSRGB; }
+
 		/************************************************************************/
 		/* 								SERIALIZATION                      		*/
 		/************************************************************************/
@@ -59,5 +81,7 @@ namespace BansheeEngine
 		PixelFormat mFormat;
 		bool mGenerateMips;
 		UINT32 mMaxMip;
+		bool mCPUReadable;
+		bool mSRGB;
 	};
 }

+ 8 - 0
BansheeCore/Include/BsTextureImportOptionsRTTI.h

@@ -18,12 +18,20 @@ namespace BansheeEngine
 		UINT32& getMaxMip(TextureImportOptions* obj) { return obj->mMaxMip; }
 		void setMaxMip(TextureImportOptions* obj, UINT32& value) { obj->mMaxMip = value; }
 
+		bool& getCPUReadable(TextureImportOptions* obj) { return obj->mCPUReadable; }
+		void setCPUReadable(TextureImportOptions* obj, bool& value) { obj->mCPUReadable = value; }
+
+		bool& getSRGB(TextureImportOptions* obj) { return obj->mSRGB; }
+		void setSRGB(TextureImportOptions* obj, bool& value) { obj->mSRGB = value; }
+
 	public:
 		TextureImportOptionsRTTI()
 		{
 			addPlainField("mPixelFormat", 0, &TextureImportOptionsRTTI::getPixelFormat, &TextureImportOptionsRTTI::setPixelFormat);
 			addPlainField("mGenerateMips", 1, &TextureImportOptionsRTTI::getGenerateMips, &TextureImportOptionsRTTI::setGenerateMips);
 			addPlainField("mMaxMip", 2, &TextureImportOptionsRTTI::getMaxMip, &TextureImportOptionsRTTI::setMaxMip);
+			addPlainField("mCPUReadable", 3, &TextureImportOptionsRTTI::getCPUReadable, &TextureImportOptionsRTTI::setCPUReadable);
+			addPlainField("mSRGB", 4, &TextureImportOptionsRTTI::getSRGB, &TextureImportOptionsRTTI::setSRGB);
 		}
 
 		virtual const String& getRTTIName()

+ 6 - 0
BansheeCore/Include/BsVertexDataDesc.h

@@ -70,6 +70,12 @@ namespace BansheeEngine
 		 * @brief	Creates a list of vertex elements from internal data.
 		 */
 		List<VertexElement> createElements() const;
+
+		/**
+		 * @brief	Creates a new empty vertex data descriptor.
+		 */
+		static VertexDataDescPtr create();
+
 	private:
 		friend class Mesh;
 		friend class MeshCore;

+ 103 - 38
BansheeCore/Source/BsMesh.cpp

@@ -16,9 +16,9 @@
 namespace BansheeEngine
 {
 	MeshCore::MeshCore(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc,
-		const Vector<SubMesh>& subMeshes, MeshBufferType bufferType, IndexType indexType, MeshDataPtr initialMeshData)
+		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType, MeshDataPtr initialMeshData)
 		:MeshCoreBase(numVertices, numIndices, subMeshes), mVertexData(nullptr), mIndexBuffer(nullptr), 
-		mVertexDesc(vertexDesc), mBufferType(bufferType), mIndexType(indexType), mTempInitialMeshData(initialMeshData)
+		mVertexDesc(vertexDesc), mUsage(usage), mIndexType(indexType), mTempInitialMeshData(initialMeshData)
 	{ }
 
 	MeshCore::~MeshCore()
@@ -35,8 +35,10 @@ namespace BansheeEngine
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
+		bool isDynamic = (mUsage & MU_DYNAMIC) != 0;
+
 		mIndexBuffer = HardwareBufferCoreManager::instance().createIndexBuffer(mIndexType,
-			mProperties.mNumIndices, mBufferType == MeshBufferType::Dynamic ? GBU_DYNAMIC : GBU_STATIC);
+			mProperties.mNumIndices, isDynamic ? GBU_DYNAMIC : GBU_STATIC);
 
 		mVertexData = std::shared_ptr<VertexData>(bs_new<VertexData, PoolAlloc>());
 
@@ -53,7 +55,7 @@ namespace BansheeEngine
 			SPtr<VertexBufferCore> vertexBuffer = HardwareBufferCoreManager::instance().createVertexBuffer(
 				mVertexData->vertexDeclaration->getProperties().getVertexSize(i),
 				mVertexData->vertexCount,
-				mBufferType == MeshBufferType::Dynamic ? GBU_DYNAMIC : GBU_STATIC);
+				isDynamic ? GBU_DYNAMIC : GBU_STATIC);
 
 			mVertexData->setBuffer(i, vertexBuffer);
 		}
@@ -62,7 +64,7 @@ namespace BansheeEngine
 		// buffer data upon buffer construction, instead of setting it in a second step like I do here
 		if (mTempInitialMeshData != nullptr)
 		{
-			writeSubresource(0, *mTempInitialMeshData, mBufferType == MeshBufferType::Dynamic);
+			writeSubresource(0, *mTempInitialMeshData, isDynamic);
 			mTempInitialMeshData = nullptr;
 		}
 
@@ -89,7 +91,7 @@ namespace BansheeEngine
 
 		if (discardEntireBuffer)
 		{
-			if (mBufferType == MeshBufferType::Static)
+			if ((mUsage & MU_STATIC) != 0)
 			{
 				LOGWRN("Buffer discard is enabled but buffer was not created as dynamic. Disabling discard.");
 				discardEntireBuffer = false;
@@ -97,7 +99,7 @@ namespace BansheeEngine
 		}
 		else
 		{
-			if (mBufferType == MeshBufferType::Dynamic)
+			if ((mUsage & MU_DYNAMIC) != 0)
 			{
 				LOGWRN("Buffer discard is not enabled but buffer was created as dynamic. Enabling discard.");
 				discardEntireBuffer = true;
@@ -271,39 +273,39 @@ namespace BansheeEngine
 	}
 
 	Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
-		MeshBufferType bufferType, DrawOperationType drawOp, IndexType indexType)
-		:MeshBase(numVertices, numIndices, drawOp), mVertexDesc(vertexDesc), mBufferType(bufferType), 
+		int usage, DrawOperationType drawOp, IndexType indexType)
+		:MeshBase(numVertices, numIndices, drawOp), mVertexDesc(vertexDesc), mUsage(usage),
 		mIndexType(indexType)
 	{
 
 	}
 
 	Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc,
-		const Vector<SubMesh>& subMeshes, MeshBufferType bufferType, IndexType indexType)
-		:MeshBase(numVertices, numIndices, subMeshes), mVertexDesc(vertexDesc), mBufferType(bufferType), 
+		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType)
+		:MeshBase(numVertices, numIndices, subMeshes), mVertexDesc(vertexDesc), mUsage(usage), 
 		mIndexType(indexType)
 	{
 
 	}
 
-	Mesh::Mesh(const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp)
+	Mesh::Mesh(const MeshDataPtr& initialMeshData, int usage, DrawOperationType drawOp)
 		:MeshBase(initialMeshData->getNumVertices(), initialMeshData->getNumIndices(), drawOp), 
 		mIndexType(initialMeshData->getIndexType()), mVertexDesc(initialMeshData->getVertexDesc()), 
-		mTempInitialMeshData(initialMeshData)
+		mCPUData(initialMeshData), mUsage(usage)
 	{
 
 	}
 
-	Mesh::Mesh(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes, MeshBufferType bufferType)
+	Mesh::Mesh(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes, int usage)
 		:MeshBase(initialMeshData->getNumVertices(), initialMeshData->getNumIndices(), subMeshes),
 		mIndexType(initialMeshData->getIndexType()), mVertexDesc(initialMeshData->getVertexDesc()), 
-		mTempInitialMeshData(initialMeshData)
+		mCPUData(initialMeshData), mUsage(usage)
 	{
 
 	}
 
 	Mesh::Mesh()
-		:MeshBase(0, 0, DOT_TRIANGLE_LIST), mBufferType(MeshBufferType::Static), mIndexType(IT_32BIT)
+		:MeshBase(0, 0, DOT_TRIANGLE_LIST), mUsage(MU_STATIC), mIndexType(IT_32BIT)
 	{
 
 	}
@@ -316,6 +318,7 @@ namespace BansheeEngine
 	AsyncOp Mesh::writeSubresource(CoreAccessor& accessor, UINT32 subresourceIdx, const MeshDataPtr& data, bool discardEntireBuffer)
 	{
 		updateBounds(*data);
+		updateCPUBuffer(subresourceIdx, *data);
 
 		data->_lock();
 
@@ -358,12 +361,13 @@ namespace BansheeEngine
 
 	void Mesh::initialize()
 	{
-		if (mTempInitialMeshData != nullptr)
-		{
-			updateBounds(*mTempInitialMeshData);
-		}
+		if (mCPUData != nullptr)
+			updateBounds(*mCPUData);
 
 		MeshBase::initialize();
+
+		if ((mUsage & MU_CPUCACHED) != 0 && mCPUData == nullptr)
+			createCPUBuffer();
 	}
 
 	void Mesh::updateBounds(const MeshData& meshData)
@@ -380,16 +384,77 @@ namespace BansheeEngine
 	SPtr<CoreObjectCore> Mesh::createCore() const
 	{
 		MeshCore* obj = new (bs_alloc<MeshCore>()) MeshCore(mProperties.mNumVertices, mProperties.mNumIndices, 
-			mVertexDesc, mProperties.mSubMeshes, mBufferType, mIndexType, mTempInitialMeshData);
+			mVertexDesc, mProperties.mSubMeshes, mUsage, mIndexType, mCPUData);
 
 		SPtr<CoreObjectCore> meshCore = bs_shared_ptr<MeshCore, GenAlloc>(obj);
 		meshCore->_setThisPtr(meshCore);
 
-		mTempInitialMeshData = nullptr;
+		if ((mUsage & MU_CPUCACHED) == 0)
+			mCPUData = nullptr;
 
 		return meshCore;
 	}
 
+	void Mesh::updateCPUBuffer(UINT32 subresourceIdx, const MeshData& pixelData)
+	{
+		if ((mUsage & MU_CPUCACHED) == 0)
+			return;
+
+		if (subresourceIdx > 0)
+		{
+			LOGERR("Invalid subresource index: " + toString(subresourceIdx) + ". Supported range: 0 .. 1.");
+			return;
+		}
+
+		if (pixelData.getNumIndices() != mProperties.getNumIndices() ||
+			pixelData.getNumVertices() != mProperties.getNumVertices() ||
+			pixelData.getIndexType() != mIndexType ||
+			pixelData.getVertexDesc()->getVertexStride() != mVertexDesc->getVertexStride())
+		{
+			LOGERR("Provided buffer is not of valid dimensions or format in order to update this mesh.");
+			return;
+		}
+
+		if (mCPUData->getSize() != pixelData.getSize())
+			BS_EXCEPT(InternalErrorException, "Buffer sizes don't match.");
+
+		UINT8* dest = mCPUData->getData();
+		UINT8* src = pixelData.getData();
+
+		memcpy(dest, src, pixelData.getSize());
+	}
+
+	void Mesh::readData(MeshData& dest)
+	{
+		if ((mUsage & MU_CPUCACHED) == 0)
+		{
+			LOGERR("Attempting to read CPU data from a mesh that is created without CPU caching.");
+			return;
+		}
+
+		if (dest.getNumIndices() != mProperties.getNumIndices() ||
+			dest.getNumVertices() != mProperties.getNumVertices() ||
+			dest.getIndexType() != mIndexType ||
+			dest.getVertexDesc()->getVertexStride() != mVertexDesc->getVertexStride())
+		{
+			LOGERR("Provided buffer is not of valid dimensions or format in order to read from this mesh.");
+			return;
+		}
+		
+		if (mCPUData->getSize() != dest.getSize())
+			BS_EXCEPT(InternalErrorException, "Buffer sizes don't match.");
+
+		UINT8* srcPtr = mCPUData->getData();
+		UINT8* destPtr = dest.getData();
+
+		memcpy(destPtr, srcPtr, dest.getSize());
+	}
+
+	void Mesh::createCPUBuffer()
+	{
+		mCPUData = allocateSubresourceBuffer(0);
+	}
+
 	HMesh Mesh::dummy()
 	{
 		return MeshManager::instance().getDummyMesh();
@@ -414,54 +479,54 @@ namespace BansheeEngine
 	/************************************************************************/
 
 	HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
-		MeshBufferType bufferType, DrawOperationType drawOp, IndexType indexType)
+		int usage, DrawOperationType drawOp, IndexType indexType)
 	{
-		MeshPtr meshPtr = _createPtr(numVertices, numIndices, vertexDesc, bufferType, drawOp, indexType);
+		MeshPtr meshPtr = _createPtr(numVertices, numIndices, vertexDesc, usage, drawOp, indexType);
 
 		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
 	}
 
 	HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc,
-		const Vector<SubMesh>& subMeshes, MeshBufferType bufferType, IndexType indexType)
+		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType)
 	{
-		MeshPtr meshPtr = _createPtr(numVertices, numIndices, vertexDesc, subMeshes, bufferType, indexType);
+		MeshPtr meshPtr = _createPtr(numVertices, numIndices, vertexDesc, subMeshes, usage, indexType);
 
 		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
 	}
 
-	HMesh Mesh::create(const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp)
+	HMesh Mesh::create(const MeshDataPtr& initialMeshData, int usage, DrawOperationType drawOp)
 	{
-		MeshPtr meshPtr = _createPtr(initialMeshData, bufferType, drawOp);
+		MeshPtr meshPtr = _createPtr(initialMeshData, usage, drawOp);
 
 		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
 	}
 
-	HMesh Mesh::create(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes, MeshBufferType bufferType)
+	HMesh Mesh::create(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes, int usage)
 	{
-		MeshPtr meshPtr = _createPtr(initialMeshData, subMeshes, bufferType);
+		MeshPtr meshPtr = _createPtr(initialMeshData, subMeshes, usage);
 
 		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
 	}
 
 	MeshPtr Mesh::_createPtr(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
-		MeshBufferType bufferType, DrawOperationType drawOp, IndexType indexType)
+		int usage, DrawOperationType drawOp, IndexType indexType)
 	{
-		return MeshManager::instance().create(numVertices, numIndices, vertexDesc, bufferType, drawOp, indexType);
+		return MeshManager::instance().create(numVertices, numIndices, vertexDesc, usage, drawOp, indexType);
 	}
 
 	MeshPtr Mesh::_createPtr(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc,
-		const Vector<SubMesh>& subMeshes, MeshBufferType bufferType, IndexType indexType)
+		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType)
 	{
-		return MeshManager::instance().create(numVertices, numIndices, vertexDesc, subMeshes, bufferType, indexType);
+		return MeshManager::instance().create(numVertices, numIndices, vertexDesc, subMeshes, usage, indexType);
 	}
 
-	MeshPtr Mesh::_createPtr(const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp)
+	MeshPtr Mesh::_createPtr(const MeshDataPtr& initialMeshData, int usage, DrawOperationType drawOp)
 	{
-		return MeshManager::instance().create(initialMeshData, bufferType, drawOp);
+		return MeshManager::instance().create(initialMeshData, usage, drawOp);
 	}
 
-	MeshPtr Mesh::_createPtr(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes, MeshBufferType bufferType)
+	MeshPtr Mesh::_createPtr(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes, int usage)
 	{
-		return MeshManager::instance().create(initialMeshData, subMeshes, bufferType);
+		return MeshManager::instance().create(initialMeshData, subMeshes, usage);
 	}
 }

+ 38 - 2
BansheeCore/Source/BsMeshData.cpp

@@ -8,6 +8,7 @@
 #include "BsVertexDeclaration.h"
 #include "BsVertexDataDesc.h"
 #include "BsException.h"
+#include "BsDebug.h"
 
 namespace BansheeEngine
 {
@@ -49,7 +50,7 @@ namespace BansheeEngine
 		return (UINT32*)(getData() + indexBufferOffset);
 	}
 
-	UINT32 MeshData::getInternalBufferSize()
+	UINT32 MeshData::getInternalBufferSize() const
 	{
 		return getIndexBufferSize() + getStreamSize();
 	}
@@ -186,8 +187,9 @@ namespace BansheeEngine
 
 		if(!mVertexData->hasElement(semantic, semanticIdx, streamIdx))
 		{
-			BS_EXCEPT(InvalidParametersException, "MeshData doesn't contain an element of specified type: Semantic: " + toString(semantic) + ", Semantic index: "
+			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);
@@ -213,6 +215,40 @@ namespace BansheeEngine
 		}
 	}
 
+	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;

+ 23 - 0
BansheeCore/Source/BsMeshImportOptions.cpp

@@ -0,0 +1,23 @@
+#include "BsMeshImportOptions.h"
+#include "BsMeshImportOptionsRTTI.h"
+
+namespace BansheeEngine
+{
+	MeshImportOptions::MeshImportOptions()
+		:mCPUReadable(false), mImportNormals(false), mImportTangents(false), 
+		mImportBlendShapes(false), mImportSkin(false), mImportAnimation(false)
+	{ }
+
+	/************************************************************************/
+	/* 								SERIALIZATION                      		*/
+	/************************************************************************/
+	RTTITypeBase* MeshImportOptions::getRTTIStatic()
+	{
+		return MeshImportOptionsRTTI::instance();
+	}
+
+	RTTITypeBase* MeshImportOptions::getRTTI() const
+	{
+		return MeshImportOptions::getRTTIStatic();
+	}
+}

+ 8 - 8
BansheeCore/Source/BsMeshManager.cpp

@@ -18,10 +18,10 @@ namespace BansheeEngine
 	}
 
 	MeshPtr MeshManager::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
-		MeshBufferType bufferType, DrawOperationType drawOp, IndexType indexType)
+		int usage, DrawOperationType drawOp, IndexType indexType)
 	{
 		MeshPtr mesh = bs_core_ptr<Mesh, PoolAlloc>(new (bs_alloc<Mesh, PoolAlloc>()) 
-			Mesh(numVertices, numIndices, vertexDesc, bufferType, drawOp, indexType));
+			Mesh(numVertices, numIndices, vertexDesc, usage, drawOp, indexType));
 		mesh->_setThisPtr(mesh);
 		mesh->initialize();
 
@@ -29,28 +29,28 @@ namespace BansheeEngine
 	}
 
 	MeshPtr MeshManager::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
-		const Vector<SubMesh>& subMeshes, MeshBufferType bufferType, IndexType indexType)
+		const Vector<SubMesh>& subMeshes, int usage, IndexType indexType)
 	{
 		MeshPtr mesh = bs_core_ptr<Mesh, PoolAlloc>(new (bs_alloc<Mesh, PoolAlloc>())
-			Mesh(numVertices, numIndices, vertexDesc, subMeshes, bufferType, indexType));
+			Mesh(numVertices, numIndices, vertexDesc, subMeshes, usage, indexType));
 		mesh->_setThisPtr(mesh);
 		mesh->initialize();
 
 		return mesh;
 	}
 
-	MeshPtr MeshManager::create(const MeshDataPtr& initialData, MeshBufferType bufferType, DrawOperationType drawOp)
+	MeshPtr MeshManager::create(const MeshDataPtr& initialData, int usage, DrawOperationType drawOp)
 	{
-		MeshPtr mesh = bs_core_ptr<Mesh, PoolAlloc>(new (bs_alloc<Mesh, PoolAlloc>()) Mesh(initialData, bufferType, drawOp));
+		MeshPtr mesh = bs_core_ptr<Mesh, PoolAlloc>(new (bs_alloc<Mesh, PoolAlloc>()) Mesh(initialData, usage, drawOp));
 		mesh->_setThisPtr(mesh);
 		mesh->initialize();
 
 		return mesh;
 	}
 
-	MeshPtr MeshManager::create(const MeshDataPtr& initialData, const Vector<SubMesh>& subMeshes, MeshBufferType bufferType)
+	MeshPtr MeshManager::create(const MeshDataPtr& initialData, const Vector<SubMesh>& subMeshes, int usage)
 	{
-		MeshPtr mesh = bs_core_ptr<Mesh, PoolAlloc>(new (bs_alloc<Mesh, PoolAlloc>()) Mesh(initialData, subMeshes, bufferType));
+		MeshPtr mesh = bs_core_ptr<Mesh, PoolAlloc>(new (bs_alloc<Mesh, PoolAlloc>()) Mesh(initialData, subMeshes, usage));
 		mesh->_setThisPtr(mesh);
 		mesh->initialize();
 

+ 4 - 4
BansheeCore/Source/BsMeshRTTI.h

@@ -17,8 +17,8 @@ namespace BansheeEngine
 		IndexType& getIndexType(Mesh* obj) { return obj->mIndexType; }
 		void setIndexType(Mesh* obj, IndexType& value) { obj->mIndexType = value; }
 
-		UINT32& getBufferType(Mesh* obj) { return (UINT32&)obj->mBufferType; }
-		void setBufferType(Mesh* obj, UINT32& value) { obj->mBufferType = (MeshBufferType)value; }
+		int& getBufferType(Mesh* obj) { return (int&)obj->mUsage; }
+		void setBufferType(Mesh* obj, int& value) { obj->mUsage = value; }
 
 		MeshDataPtr getMeshData(Mesh* obj) 
 		{ 
@@ -32,7 +32,7 @@ namespace BansheeEngine
 
 		void setMeshData(Mesh* obj, MeshDataPtr meshData) 
 		{ 
-			obj->mTempInitialMeshData = meshData;
+			obj->mCPUData = meshData;
 		}
 
 	public:
@@ -41,7 +41,7 @@ namespace BansheeEngine
 			addReflectablePtrField("mVertexDesc", 0, &MeshRTTI::getVertexDesc, &MeshRTTI::setVertexDesc);
 
 			addPlainField("mIndexType", 1, &MeshRTTI::getIndexType, &MeshRTTI::setIndexType);
-			addPlainField("mBufferType", 2, &MeshRTTI::getBufferType, &MeshRTTI::setBufferType);
+			addPlainField("mUsage", 2, &MeshRTTI::getBufferType, &MeshRTTI::setBufferType);
 
 			addReflectablePtrField("mMeshData", 3, &MeshRTTI::getMeshData, &MeshRTTI::setMeshData);
 		}

+ 1 - 1
BansheeCore/Source/BsPixelData.cpp

@@ -174,7 +174,7 @@ namespace BansheeEngine
 		setColorsInternal(colors, numElements);
 	}
 
-	UINT32 PixelData::getInternalBufferSize()
+	UINT32 PixelData::getInternalBufferSize() const
 	{
 		return getSize();
 	}

+ 1 - 1
BansheeCore/Source/BsTexture.cpp

@@ -365,7 +365,7 @@ namespace BansheeEngine
 		if (pixelData.getWidth() != mipWidth || pixelData.getHeight() != mipHeight ||
 			pixelData.getDepth() != mipDepth || pixelData.getFormat() != mProperties.getFormat())
 		{
-			LOGERR("Provided buffer is not of valid dimensions or format in order to read from this texture.");
+			LOGERR("Provided buffer is not of valid dimensions or format in order to update this texture.");
 			return;
 		}
 

+ 2 - 1
BansheeCore/Source/BsTextureImportOptions.cpp

@@ -4,7 +4,8 @@
 namespace BansheeEngine
 {
 	TextureImportOptions::TextureImportOptions()
-		:mFormat(PF_B8G8R8A8), mGenerateMips(false), mMaxMip(0)
+		:mFormat(PF_B8G8R8A8), mGenerateMips(false), mMaxMip(0), 
+		mCPUReadable(false), mSRGB(false)
 	{ }
 
 	/************************************************************************/

+ 5 - 0
BansheeCore/Source/BsVertexDataDesc.cpp

@@ -174,6 +174,11 @@ namespace BansheeEngine
 		}
 	}
 
+	VertexDataDescPtr VertexDataDesc::create()
+	{
+		return bs_shared_ptr<VertexDataDesc>();
+	}
+
 	/************************************************************************/
 	/* 								SERIALIZATION                      		*/
 	/************************************************************************/

+ 2 - 0
BansheeEngine/BansheeEngine.vcxproj

@@ -234,6 +234,7 @@
   <ItemGroup>
     <ClCompile Include="Source\BsCameraHandler.cpp" />
     <ClCompile Include="Source\BsCursor.cpp" />
+    <ClCompile Include="Source\BsDefaultMeshData.cpp" />
     <ClCompile Include="Source\BsDrawHelper.cpp" />
     <ClCompile Include="Source\BsGUIDropDownContent.cpp" />
     <ClCompile Include="Source\BsGUIElementStyle.cpp" />
@@ -260,6 +261,7 @@
     <ClInclude Include="Include\BsCameraHandler.h" />
     <ClInclude Include="Include\BsCameraHandlerRTTI.h" />
     <ClInclude Include="Include\BsCursor.h" />
+    <ClInclude Include="Include\BsDefaultMeshData.h" />
     <ClInclude Include="Include\BsDrawHelper.h" />
     <ClInclude Include="Include\BsGUIDropDownContent.h" />
     <ClInclude Include="Include\BsGUIElementStyleRTTI.h" />

+ 6 - 0
BansheeEngine/BansheeEngine.vcxproj.filters

@@ -332,6 +332,9 @@
     <ClInclude Include="Include\BsGUILayoutData.h">
       <Filter>Header Files\GUI</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsDefaultMeshData.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsGUIElement.cpp">
@@ -574,5 +577,8 @@
     <ClCompile Include="Source\BsGUIPanel.cpp">
       <Filter>Source Files\GUI</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsDefaultMeshData.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 237 - 0
BansheeEngine/Include/BsDefaultMeshData.h

@@ -0,0 +1,237 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+#include "BsMeshData.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Available vertex layouts (Combinations other than those provided are allowed).
+	 */
+	enum class VertexLayout
+	{
+		Position = 0x01,
+		Color = 0x02,
+		Normal = 0x04,
+		Tangent = 0x08,
+		BoneWeights = 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,
+	};
+
+
+	/**
+	 * @brief	Wrapper around MeshData that constructs the default mesh data structure 
+	 *			expected by the renderer and other engine systems. Data will be compressed and
+	 *			uncompressed when written to and read to as needed to comply with wanted format.
+	 */
+	// TODO: Allow the Renderer plugin to override how is data packed.
+	class BS_EXPORT DefaultMeshData
+	{
+	public:
+		DefaultMeshData(UINT32 numVertices, UINT32 numIndices, VertexLayout layout, IndexType indexType = IT_32BIT);
+		DefaultMeshData(const MeshDataPtr& meshData);
+
+		/**
+		 * @brief	Reads the vertex positions into the provided output buffer.
+		 *			Data will be copied and potentially uncompressed to fit the output
+		 *			format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to output the position data to.
+		 * @param	size	Size of the pre-allocated buffer. Must be big enough to fit
+		 *					all contents (numVertices * sizeof(Vector3)).
+		 */
+		void getPositions(Vector3* buffer, UINT32 size);
+
+		/**
+		 * @brief	Writes the vertex positions from the provided output buffer.
+		 *			Data will be copied and potentially compressed to fit the internal 
+		 *			mesh data format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to read the position data from.
+		 * @param	size	Size of the input buffer. Must be (numVertices * sizeof(Vector3)).
+		 */
+		void setPositions(Vector3* buffer, UINT32 size);
+
+		/**
+		 * @brief	Reads the vertex normals into the provided output buffer.
+		 *			Data will be copied and potentially uncompressed to fit the output
+		 *			format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to output the normal data to.
+		 * @param	size	Size of the pre-allocated buffer. Must be big enough to fit
+		 *					all contents (numVertices * sizeof(Vector3)).
+		 */
+		void getNormals(Vector3* buffer, UINT32 size);
+
+		/**
+		 * @brief	Writes the vertex normals from the provided output buffer.
+		 *			Data will be copied and potentially compressed to fit the internal 
+		 *			mesh data format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to read the normal data from.
+		 * @param	size	Size of the input buffer. Must be (numVertices * sizeof(Vector3)).
+		 */
+		void setNormals(Vector3* buffer, UINT32 size);
+
+		/**
+		 * @brief	Reads the vertex tangents into the provided output buffer.
+		 *			Data will be copied and potentially uncompressed to fit the output
+		 *			format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to output the tangent data to.
+		 * @param	size	Size of the pre-allocated buffer. Must be big enough to fit
+		 *					all contents (numVertices * sizeof(Vector4)).
+		 */
+		void getTangents(Vector4* buffer, UINT32 size);
+
+		/**
+		 * @brief	Writes the vertex tangents from the provided output buffer.
+		 *			Data will be copied and potentially compressed to fit the internal 
+		 *			mesh data format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to read the tangent data from.
+		 * @param	size	Size of the input buffer. Must be (numVertices * sizeof(Vector4)).
+		 */
+		void setTangents(Vector4* buffer, UINT32 size);
+
+		/**
+		 * @brief	Reads the vertex colors into the provided output buffer.
+		 *			Data will be copied and potentially uncompressed to fit the output
+		 *			format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to output the color data to.
+		 * @param	size	Size of the pre-allocated buffer. Must be big enough to fit
+		 *					all contents (numVertices * sizeof(Color)).
+		 */
+		void getColors(Color* buffer, UINT32 size);
+
+		/**
+		 * @brief	Writes the vertex colors from the provided output buffer.
+		 *			Data will be copied and potentially compressed to fit the internal 
+		 *			mesh data format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to read the color data from.
+		 * @param	size	Size of the input buffer. Must be (numVertices * sizeof(Color)).
+		 */
+		void setColors(Color* buffer, UINT32 size);
+
+		/**
+		 * @brief	Reads the first UV channel coordinates into the provided output buffer.
+		 *			Data will be copied and potentially uncompressed to fit the output
+		 *			format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to output the coordinate data to.
+		 * @param	size	Size of the pre-allocated buffer. Must be big enough to fit
+		 *					all contents (numVertices * sizeof(Vector2)).
+		 */
+		void getUV0(Vector2* buffer, UINT32 size);
+
+		/**
+		 * @brief	Writes the first UV channel coordinates from the provided output buffer.
+		 *			Data will be copied and potentially compressed to fit the internal 
+		 *			mesh data format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to read the coordinate data from.
+		 * @param	size	Size of the input buffer. Must be (numVertices * sizeof(Vector2)).
+		 */
+		void setUV0(Vector2* buffer, UINT32 size);
+
+		/**
+		 * @brief	Reads the second UV channel coordinates into the provided output buffer.
+		 *			Data will be copied and potentially uncompressed to fit the output
+		 *			format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to output the coordinate data to.
+		 * @param	size	Size of the pre-allocated buffer. Must be big enough to fit
+		 *					all contents (numVertices * sizeof(Vector2)).
+		 */
+		void getUV1(Vector2* buffer, UINT32 size);
+
+		/**
+		 * @brief	Writes the second UV channel coordinates from the provided output buffer.
+		 *			Data will be copied and potentially compressed to fit the internal 
+		 *			mesh data format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to read the coordinate data from.
+		 * @param	size	Size of the input buffer. Must be (numVertices * sizeof(Vector2)).
+		 */
+		void setUV1(Vector2* buffer, UINT32 size);
+
+		/**
+		 * @brief	Reads the bone weights and indices into the provided output buffer.
+		 *			Data will be copied and potentially uncompressed to fit the output
+		 *			format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to output the bone weight data to.
+		 * @param	size	Size of the pre-allocated buffer. Must be big enough to fit
+		 *					all contents (numVertices * sizeof(BoneWeight)).
+		 */
+		void getBoneWeights(BoneWeight* buffer, UINT32 size);
+
+		/**
+		 * @brief	Writes the bone weights and indices from the provided output buffer.
+		 *			Data will be copied and potentially compressed to fit the internal 
+		 *			mesh data format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to read the bone weight data from.
+		 * @param	size	Size of the input buffer. Must be (numVertices * sizeof(BoneWeight)).
+		 */
+		void setBoneWeights(BoneWeight* buffer, UINT32 size);
+
+		/**
+		 * @brief	Reads the indices into the provided output buffer.
+		 *			Data will be copied and potentially uncompressed to fit the output
+		 *			format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to output the index data to.
+		 * @param	size	Size of the pre-allocated buffer. Must be big enough to fit
+		 *					all contents (numVertices * sizeof(INT32)).
+		 */
+		void getIndices(UINT32* buffer, UINT32 size);
+
+		/**
+		 * @brief	Writes the indices from the provided output buffer.
+		 *			Data will be copied and potentially compressed to fit the internal 
+		 *			mesh data format as needed.
+		 *			
+		 * @param	buffer	Pre-allocated buffer to read the index data from.
+		 * @param	size	Size of the input buffer. Must be (numVertices * sizeof(INT32)).
+		 */
+		void setIndices(UINT32* buffer, UINT32 size);
+
+		/**
+		 * @brief	Returns the underlying MeshData structure.
+		 */
+		MeshDataPtr getData() const { return mMeshData; }
+
+		/**
+		 * @brief	Creates a new empty mesh data structure.
+		 */
+		static DefaultMeshDataPtr create(UINT32 numVertices, UINT32 numIndices, VertexLayout layout, IndexType indexType = IT_32BIT);
+
+		/**
+		 * @brief	Creates a new mesh data structure using an existing mesh data buffer.
+		 */
+		static DefaultMeshDataPtr create(const MeshDataPtr& meshData);
+
+		/**
+		 * @brief	Creates a vertex descriptor from a vertex layout enum.
+		 */
+		static VertexDataDescPtr vertexLayoutVertexDesc(VertexLayout type);
+
+	private:
+		MeshDataPtr mMeshData;
+	};
+}

+ 2 - 0
BansheeEngine/Include/BsPrerequisites.h

@@ -92,6 +92,7 @@ namespace BansheeEngine
 	class PlainText;
 	class ScriptCode;
 	class ScriptCodeImportOptions;
+	class DefaultMeshData;
 
 	// 2D
 	class TextSprite;
@@ -116,6 +117,7 @@ namespace BansheeEngine
 	typedef std::shared_ptr<PlainText> PlainTextPtr;
 	typedef std::shared_ptr<ScriptCode> ScriptCodePtr;
 	typedef std::shared_ptr<GUISkin> GUISkinPtr;
+	typedef std::shared_ptr<DefaultMeshData> DefaultMeshDataPtr;
 
 	typedef GameObjectHandle<GUIWidget> HGUIWidget;
 	typedef GameObjectHandle<Camera> HCamera;

+ 349 - 0
BansheeEngine/Source/BsDefaultMeshData.cpp

@@ -0,0 +1,349 @@
+#include "BsDefaultMeshData.h"
+#include "BsVertexDataDesc.h"
+#include "BsVector2.h"
+#include "BsVector3.h"
+#include "BsVector4.h"
+#include "BsColor.h"
+#include "BsPixelUtil.h"
+
+namespace BansheeEngine
+{
+	DefaultMeshData::DefaultMeshData(UINT32 numVertices, UINT32 numIndices, VertexLayout layout, IndexType indexType)
+	{
+		VertexDataDescPtr vertexDesc = vertexLayoutVertexDesc(layout);
+
+		mMeshData = bs_shared_ptr<MeshData>(numVertices, numIndices, vertexDesc, indexType);
+	}
+
+	DefaultMeshData::DefaultMeshData(const MeshDataPtr& meshData)
+		:mMeshData(meshData)
+	{
+
+	}
+
+	void DefaultMeshData::getPositions(Vector3* buffer, UINT32 size)
+	{
+		if (!mMeshData->getVertexDesc()->hasElement(VES_POSITION))
+			return;
+
+		UINT32 numElements = mMeshData->getNumVertices();
+		assert(numElements * sizeof(Vector3) == size);
+
+		mMeshData->getVertexData(VES_POSITION, (UINT8*)buffer, size);
+	}
+
+	void DefaultMeshData::setPositions(Vector3* buffer, UINT32 size)
+	{
+		if (!mMeshData->getVertexDesc()->hasElement(VES_POSITION))
+			return;
+
+		UINT32 numElements = mMeshData->getNumVertices();
+		assert(numElements * sizeof(Vector3) == size);
+
+		mMeshData->setVertexData(VES_POSITION, (UINT8*)buffer, size);
+	}
+
+	void DefaultMeshData::getNormals(Vector3* buffer, UINT32 size)
+	{
+		if (!mMeshData->getVertexDesc()->hasElement(VES_NORMAL))
+			return;
+
+		UINT32 numElements = mMeshData->getNumVertices();
+		assert(numElements * sizeof(Vector3) == size);
+
+		mMeshData->getVertexData(VES_NORMAL, (UINT8*)buffer, size);
+	}
+
+	void DefaultMeshData::setNormals(Vector3* buffer, UINT32 size)
+	{
+		if (!mMeshData->getVertexDesc()->hasElement(VES_NORMAL))
+			return;
+
+		UINT32 numElements = mMeshData->getNumVertices();
+		assert(numElements * sizeof(Vector3) == size);
+
+		mMeshData->setVertexData(VES_NORMAL, (UINT8*)buffer, size);
+	}
+
+	void DefaultMeshData::getTangents(Vector4* buffer, UINT32 size)
+	{
+		if (!mMeshData->getVertexDesc()->hasElement(VES_TANGENT))
+			return;
+
+		UINT32 numElements = mMeshData->getNumVertices();
+		assert(numElements * sizeof(Vector4) == size);
+
+		mMeshData->getVertexData(VES_TANGENT, (UINT8*)buffer, size);
+	}
+
+	void DefaultMeshData::setTangents(Vector4* buffer, UINT32 size)
+	{
+		if (!mMeshData->getVertexDesc()->hasElement(VES_TANGENT))
+			return;
+
+		UINT32 numElements = mMeshData->getNumVertices();
+		assert(numElements * sizeof(Vector4) == size);
+
+		mMeshData->setVertexData(VES_TANGENT, (UINT8*)buffer, size);
+	}
+
+	void DefaultMeshData::getColors(Color* buffer, UINT32 size)
+	{
+		if (!mMeshData->getVertexDesc()->hasElement(VES_COLOR))
+			return;
+
+		UINT32 numElements = mMeshData->getNumVertices();
+		assert(numElements * sizeof(Vector4) == size);
+
+		UINT8* colorSrc = mMeshData->getElementData(VES_COLOR);
+		UINT32 stride = mMeshData->getVertexDesc()->getVertexStride(0);
+
+		Color* colorDst = buffer;
+		for (UINT32 i = 0; i < numElements; i++)
+		{
+			PixelUtil::unpackColor(colorDst, PF_R8G8B8A8, (void*)colorSrc);
+
+			colorSrc += stride;
+			colorDst++;
+		}
+	}
+
+	void DefaultMeshData::setColors(Color* buffer, UINT32 size)
+	{
+		if (!mMeshData->getVertexDesc()->hasElement(VES_COLOR))
+			return;
+
+		UINT32 numElements = mMeshData->getNumVertices();
+		assert(numElements * sizeof(Vector4) == size);
+
+		UINT8* colorDst = mMeshData->getElementData(VES_COLOR);
+		UINT32 stride = mMeshData->getVertexDesc()->getVertexStride(0);
+
+		Color* colorSrc = buffer;
+		for (UINT32 i = 0; i < numElements; i++)
+		{
+			PixelUtil::packColor(*colorSrc, PF_R8G8B8A8, (void*)colorDst);
+
+			colorSrc++;
+			colorDst += stride;
+		}
+	}
+
+	void DefaultMeshData::getUV0(Vector2* buffer, UINT32 size)
+	{
+		if (!mMeshData->getVertexDesc()->hasElement(VES_TEXCOORD, 0))
+			return;
+
+		UINT32 numElements = mMeshData->getNumVertices();
+		assert(numElements * sizeof(Vector2) == size);
+
+		mMeshData->getVertexData(VES_TEXCOORD, (UINT8*)buffer, size, 0);
+	}
+
+	void DefaultMeshData::setUV0(Vector2* buffer, UINT32 size)
+	{
+		if (!mMeshData->getVertexDesc()->hasElement(VES_TEXCOORD, 0))
+			return;
+
+		UINT32 numElements = mMeshData->getNumVertices();
+		assert(numElements * sizeof(Vector2) == size);
+
+		mMeshData->setVertexData(VES_TEXCOORD, (UINT8*)buffer, size, 0);
+	}
+
+	void DefaultMeshData::getUV1(Vector2* buffer, UINT32 size)
+	{
+		if (!mMeshData->getVertexDesc()->hasElement(VES_TEXCOORD, 1))
+			return;
+
+		UINT32 numElements = mMeshData->getNumVertices();
+		assert(numElements * sizeof(Vector2) == size);
+
+		mMeshData->getVertexData(VES_TEXCOORD, (UINT8*)buffer, size, 1);
+	}
+
+	void DefaultMeshData::setUV1(Vector2* buffer, UINT32 size)
+	{
+		if (!mMeshData->getVertexDesc()->hasElement(VES_TEXCOORD, 1))
+			return;
+
+		UINT32 numElements = mMeshData->getNumVertices();
+		assert(numElements * sizeof(Vector2) == size);
+
+		mMeshData->setVertexData(VES_TEXCOORD, (UINT8*)buffer, size, 1);
+	}
+
+	void DefaultMeshData::getBoneWeights(BoneWeight* buffer, UINT32 size)
+	{
+		VertexDataDescPtr vertexDesc = mMeshData->getVertexDesc();
+
+		if (!vertexDesc->hasElement(VES_BLEND_WEIGHTS) ||
+			!vertexDesc->hasElement(VES_BLEND_INDICES))
+			return;
+
+		UINT32 numElements = mMeshData->getNumVertices();
+		assert(numElements * sizeof(BoneWeight) == size);
+
+		UINT8* weightPtr = mMeshData->getElementData(VES_BLEND_WEIGHTS);
+		UINT8* indexPtr = mMeshData->getElementData(VES_BLEND_INDICES);
+
+		UINT32 stride = vertexDesc->getVertexStride(0);
+
+		BoneWeight* weightDst = buffer;
+		for (UINT32 i = 0; i < numElements; i++)
+		{
+			int* indices = (int*)indexPtr;
+			float* weights = (float*)weightPtr;
+
+			weightDst->index0 = indices[0];
+			weightDst->index1 = indices[1];
+			weightDst->index2 = indices[2];
+			weightDst->index3 = indices[3];
+
+			weightDst->weight0 = weights[0];
+			weightDst->weight1 = weights[1];
+			weightDst->weight2 = weights[2];
+			weightDst->weight3 = weights[3];
+
+			weightDst++;
+			indexPtr += stride;
+			weightPtr += stride;
+		}
+	}
+
+	void DefaultMeshData::setBoneWeights(BoneWeight* buffer, UINT32 size)
+	{
+		VertexDataDescPtr vertexDesc = mMeshData->getVertexDesc();
+
+		if (!vertexDesc->hasElement(VES_BLEND_WEIGHTS) ||
+			!vertexDesc->hasElement(VES_BLEND_INDICES))
+			return;
+
+		UINT32 numElements = mMeshData->getNumVertices();
+		assert(numElements * sizeof(BoneWeight) == size);
+
+		UINT8* weightPtr = mMeshData->getElementData(VES_BLEND_WEIGHTS);
+		UINT8* indexPtr = mMeshData->getElementData(VES_BLEND_INDICES);
+
+		UINT32 stride = vertexDesc->getVertexStride(0);
+
+		BoneWeight* weightSrc = buffer;
+		for (UINT32 i = 0; i < numElements; i++)
+		{
+			int* indices = (int*)indexPtr;
+			float* weights = (float*)weightPtr;
+
+			indices[0] = weightSrc->index0;
+			indices[1] = weightSrc->index1;
+			indices[2] = weightSrc->index2;
+			indices[3] = weightSrc->index3;
+
+			weights[0] = weightSrc->weight0;
+			weights[1] = weightSrc->weight1;
+			weights[2] = weightSrc->weight2;
+			weights[3] = weightSrc->weight3;
+
+			weightSrc++;
+			indexPtr += stride;
+			weightPtr += stride;
+		}
+	}
+
+	void DefaultMeshData::getIndices(UINT32* buffer, UINT32 size)
+	{
+		UINT32 indexSize = mMeshData->getIndexElementSize();
+		UINT32 numIndices = mMeshData->getNumIndices();
+
+		assert(numIndices * indexSize == size);
+
+		if (mMeshData->getIndexType() == IT_16BIT)
+		{
+			UINT16* src = mMeshData->getIndices16();
+			UINT32* dest = buffer;
+			
+			for (UINT32 i = 0; i < numIndices; i++)
+			{
+				*dest = *src;
+
+				src++;
+				dest++;
+			}
+		}
+		else
+		{
+			memcpy(buffer, mMeshData->getIndices32(), size);
+		}
+	}
+
+	void DefaultMeshData::setIndices(UINT32* buffer, UINT32 size)
+	{
+		UINT32 indexSize = mMeshData->getIndexElementSize();
+		UINT32 numIndices = mMeshData->getNumIndices();
+
+		assert(numIndices * indexSize == size);
+
+		if (mMeshData->getIndexType() == IT_16BIT)
+		{
+			UINT16* dest = mMeshData->getIndices16();
+			UINT32* src = buffer;
+
+			for (UINT32 i = 0; i < numIndices; i++)
+			{
+				*dest = *src;
+
+				src++;
+				dest++;
+			}
+		}
+		else
+		{
+			memcpy(mMeshData->getIndices32(), buffer, size);
+		}
+	}
+
+	DefaultMeshDataPtr DefaultMeshData::create(UINT32 numVertices, UINT32 numIndices, VertexLayout layout, IndexType indexType)
+	{
+		return bs_shared_ptr<DefaultMeshData>(numVertices, numIndices, layout, indexType);
+	}
+
+	DefaultMeshDataPtr DefaultMeshData::create(const MeshDataPtr& meshData)
+	{
+		return bs_shared_ptr<DefaultMeshData>(meshData);
+	}
+
+	VertexDataDescPtr DefaultMeshData::vertexLayoutVertexDesc(VertexLayout type)
+	{
+		VertexDataDescPtr vertexDesc = VertexDataDesc::create();
+
+		INT32 intType = (INT32)type;
+
+		if (intType == 0)
+			type = VertexLayout::Position;
+
+		if ((intType & (INT32)VertexLayout::Position) != 0)
+			vertexDesc->addVertElem(VET_FLOAT3, VES_POSITION);
+
+		if ((intType & (INT32)VertexLayout::Normal) != 0)
+			vertexDesc->addVertElem(VET_FLOAT3, VES_NORMAL);
+
+		if ((intType & (INT32)VertexLayout::Tangent) != 0)
+			vertexDesc->addVertElem(VET_FLOAT4, VES_TANGENT);
+
+		if ((intType & (INT32)VertexLayout::UV0) != 0)
+			vertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD, 0);
+
+		if ((intType & (INT32)VertexLayout::UV1) != 0)
+			vertexDesc->addVertElem(VET_FLOAT2, VES_TEXCOORD, 1);
+
+		if ((intType & (INT32)VertexLayout::Color) != 0)
+			vertexDesc->addVertElem(VET_FLOAT4, VES_COLOR);
+
+		if ((intType & (INT32)VertexLayout::BoneWeights) != 0)
+		{
+			vertexDesc->addVertElem(VET_UBYTE4, VES_BLEND_INDICES);
+			vertexDesc->addVertElem(VET_FLOAT4, VES_BLEND_WEIGHTS);
+		}
+
+		return vertexDesc;
+	}
+}

+ 8 - 1
BansheeEngine/Source/BsRenderableHandler.cpp

@@ -8,6 +8,7 @@
 #include "BsBounds.h"
 #include "BsRenderer.h"
 #include "BsFrameAlloc.h"
+#include "BsDebug.h"
 
 namespace BansheeEngine
 {
@@ -37,6 +38,9 @@ namespace BansheeEngine
 	template<bool Core>
 	void TRenderableHandler<Core>::setMaterial(UINT32 idx, const MaterialType& material)
 	{
+		if (idx >= (UINT32)mMaterials.size())
+			return;
+
 		mMaterials[idx] = material;
 
 		_markResourcesDirty();
@@ -55,7 +59,10 @@ namespace BansheeEngine
 		bool isPow2 = layer && !((layer - 1) & layer);
 
 		if (!isPow2)
-			BS_EXCEPT(InvalidParametersException, "Invalid layer provided. Only one layer bit may be set.");
+		{
+			LOGWRN("Invalid layer provided. Only one layer bit may be set. Ignoring.");
+			return;
+		}
 
 		mLayer = layer;
 		_markCoreDirty();

+ 7 - 1
BansheeFreeImgImporter/Source/BsFreeImgImporter.cpp

@@ -148,8 +148,14 @@ namespace BansheeEngine
 			}
 		}
 
+		int usage = TU_DEFAULT;
+		if (textureImportOptions->getCPUReadable())
+			usage |= TU_CPUCACHED;
+
+		bool sRGB = textureImportOptions->getSRGB();
+
 		TexturePtr newTexture = Texture::_createPtr(TEX_TYPE_2D, 
-			imgData->getWidth(), imgData->getHeight(), numMips, textureImportOptions->getFormat());
+			imgData->getWidth(), imgData->getHeight(), numMips, textureImportOptions->getFormat(), usage, sRGB);
 
 		Vector<PixelDataPtr> mipLevels;
 		if (numMips > 0)

+ 16 - 0
BansheeMono/Include/BsMonoArray.h

@@ -26,6 +26,22 @@ namespace BansheeEngine
 			mono_array_set(mInternal, T, idx, value);
 		}
 
+		template<class T>
+		T* getRawPtr(UINT32 offset = 0)
+		{
+#if BS_DEBUG_MODE
+			int nativeSize = sizeof(T);
+
+			::MonoClass* arrayClass = mono_object_get_class((MonoObject*)(mInternal));
+			::MonoClass* elementClass = mono_class_get_element_class(arrayClass);
+
+			int monoSize = mono_class_array_element_size(elementClass);
+			assert(nativeSize == monoSize);
+#endif
+
+			return (T*)mono_array_addr(mInternal, T, offset);
+		}
+
 		template<class T>
 		static ScriptArray create(UINT32 size)
 		{

+ 14 - 0
MBansheeEngine/Bounds.cs

@@ -0,0 +1,14 @@
+namespace BansheeEngine
+{
+    public struct Bounds
+    {
+        public Bounds(AABox box, Sphere sphere)
+        {
+            Box = box;
+            Sphere = sphere;
+        }
+
+        public AABox Box;
+        public Sphere Sphere;
+    }
+}

+ 3 - 0
MBansheeEngine/Camera.cs

@@ -173,6 +173,9 @@ namespace BansheeEngine
 
         private void OnReset()
         {
+            if (handler != null)
+                handler.OnDestroy();
+
             handler = new CameraHandler(sceneObject);
 
             // Restore saved values after reset

+ 6 - 0
MBansheeEngine/MBansheeEngine.csproj

@@ -43,6 +43,7 @@
   </ItemGroup>
   <ItemGroup>
     <Compile Include="AsyncOp.cs" />
+    <Compile Include="Bounds.cs" />
     <Compile Include="Builtin.cs" />
     <Compile Include="Camera.cs" />
     <Compile Include="CameraHandler.cs" />
@@ -97,6 +98,8 @@
     <Compile Include="Math\Rect2.cs" />
     <Compile Include="Math\Rect2I.cs" />
     <Compile Include="Math\Vector2I.cs" />
+    <Compile Include="Mesh.cs" />
+    <Compile Include="MeshData.cs" />
     <Compile Include="MissingComponent.cs" />
     <Compile Include="PixelData.cs" />
     <Compile Include="PixelUtility.cs" />
@@ -104,6 +107,8 @@
     <Compile Include="Program.cs" />
     <Compile Include="Properties\AssemblyInfo.cs" />
     <Compile Include="Math\Quaternion.cs" />
+    <Compile Include="Renderable.cs" />
+    <Compile Include="RenderableHandler.cs" />
     <Compile Include="RenderTarget.cs" />
     <Compile Include="RenderTexture.cs" />
     <Compile Include="RenderTexture2D.cs" />
@@ -120,6 +125,7 @@
     <Compile Include="SerializeObject.cs" />
     <Compile Include="SerializeField.cs" />
     <Compile Include="Shader.cs" />
+    <Compile Include="Sphere.cs" />
     <Compile Include="SpriteTexture.cs" />
     <Compile Include="StringTable.cs" />
     <Compile Include="Texture.cs" />

+ 143 - 0
MBansheeEngine/Mesh.cs

@@ -0,0 +1,143 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace BansheeEngine
+{
+    public class Mesh : Resource
+    {
+        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);
+        }
+
+        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);
+        }
+
+        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);
+        }
+
+        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);
+        }
+
+        public int SubMeshCount
+        {
+            get { return Internal_GetSubMeshCount(mCachedPtr); }
+        }
+
+        public SubMesh[] SubMeshes
+        {
+            get { return Internal_GetSubMeshes(mCachedPtr); }
+        }
+
+        public Bounds Bounds
+        {
+            get
+            {
+                AABox box;
+                Sphere sphere;
+
+                Internal_GetBounds(mCachedPtr, out box, out sphere);
+
+                return new Bounds(box, sphere);
+            }
+        }
+
+        public MeshData GetMeshData()
+        {
+            return Internal_GetMeshData(mCachedPtr);
+        }
+
+        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);
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    public struct 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;
+    }
+
+    // Note: Values must match C++ enum MeshTopology
+    public enum MeshTopology
+    {
+        PointList = 1,
+        LineList = 2,
+        LineStrip = 3,
+        TriangleList = 4,
+        TriangleStrip = 5,
+        TriangleFan = 6
+    }
+
+    // Note: Do not modify IDs as they must match TextureUsage C++ enum
+    public enum MeshUsage
+    {
+        Default = 0x1,
+        Dynamic = 0x2,
+        CPUCached = 0x1000
+    }
+}

+ 181 - 0
MBansheeEngine/MeshData.cs

@@ -0,0 +1,181 @@
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+namespace BansheeEngine
+{
+    public class MeshData : ScriptObject
+    {
+        public MeshData(int numVertices, int numIndices, VertexType vertex = VertexType.Position,
+            IndexType index = IndexType.Index32)
+        {
+            Internal_CreateInstance(this, numVertices, numIndices, vertex, index);
+        }
+
+        public Vector3[] Positions
+        {
+            get { return Internal_GetPositions(mCachedPtr); }
+            set { Internal_SetPositions(mCachedPtr, value); }
+        }
+
+        public Vector3[] Normals
+        {
+            get { return Internal_GetNormals(mCachedPtr); }
+            set { Internal_SetNormals(mCachedPtr, value); }
+        }
+
+        public Vector4[] Tangents
+        {
+            get { return Internal_GetTangents(mCachedPtr); }
+            set { Internal_SetTangents(mCachedPtr, value); }
+        }
+
+        public Color[] Colors
+        {
+            get { return Internal_GetColors(mCachedPtr); }
+            set { Internal_SetColors(mCachedPtr, value); }
+        }
+
+        public Vector2[] UV
+        {
+            get { return UV0; }
+            set { UV0 = value; }
+        }
+
+        public Vector2[] UV0
+        {
+            get { return Internal_GetUV0(mCachedPtr); }
+            set { Internal_SetUV0(mCachedPtr, value); }
+        }
+
+        public Vector2[] UV1
+        {
+            get { return Internal_GetUV1(mCachedPtr); }
+            set { Internal_SetUV0(mCachedPtr, value); }
+        }
+
+        public BoneWeight[] BoneWeights
+        {
+            get { return Internal_GetBoneWeights(mCachedPtr); }
+            set { Internal_SetBoneWeights(mCachedPtr, value); }
+        }
+
+        public int[] Indices
+        {
+            get { return Internal_GetIndices(mCachedPtr); }
+            set { Internal_SetIndices(mCachedPtr, value); }
+        }
+
+        public int VertexCount
+        {
+            get { return Internal_GetVertexCount(mCachedPtr); }
+        }
+
+        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);
+    }
+
+    // Note: Do not modify, it must match the layout of C++ enum VertexLayout
+    public enum VertexType
+    {
+        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,
+    }
+
+    // Note: Do not modify, it must match the layout of C++ enum ScriptIndexType
+    public enum IndexType
+    {
+        Index16,
+        Index32
+    }
+
+    [StructLayout(LayoutKind.Sequential)]
+    public struct 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;
+    }
+}

+ 104 - 0
MBansheeEngine/Renderable.cs

@@ -0,0 +1,104 @@
+using System;
+
+namespace BansheeEngine
+{
+    public class Renderable : Component
+    {
+        private RenderableHandler handler;
+
+        [SerializeField]
+        private SerializableData serializableData = new SerializableData();
+
+        internal RenderableHandler Handler
+        {
+            get { return handler; }
+        }
+
+        public Mesh Mesh
+        {
+            get { return handler.Mesh; }
+            set 
+            { 
+                handler.Mesh = value; 
+                serializableData.mesh = value;
+
+                Material[] newMaterials = new Material[value.SubMeshCount];
+                int numToCopy = MathEx.Min(newMaterials.Length, serializableData.materials.Length);
+                Array.Copy(serializableData.materials, newMaterials, numToCopy);
+                serializableData.materials = newMaterials;
+            }
+        }
+
+        public Material Material
+        {
+            get { return handler.GetMaterial(0); }
+            set 
+            { handler.SetMaterial(value); serializableData.materials[0] = value; }
+        }
+
+        public Material GetMaterial(int index = 0)
+        {
+            return handler.GetMaterial(index);
+        }
+
+        public void SetMaterial(Material material, int index = 0)
+        {
+            handler.SetMaterial(material, index);
+            serializableData.materials[index] = material;
+        }
+
+        public UInt64 Layers
+        {
+            get { return handler.Layers; }
+            set { handler.Layers = value; serializableData.layers = value; }
+        }
+
+        public Bounds Bounds
+        {
+            get { return handler.GetBounds(sceneObject); }
+        }
+
+        private void OnInitialize()
+        {
+            serializableData.materials = new Material[0];
+            serializableData.layers = 0xFFFFFFFFFFFFFFFF;
+        }
+
+        private void OnReset()
+        {
+            if (handler != null)
+                handler.OnDestroy();
+
+            handler = new RenderableHandler(sceneObject);
+
+            // Restore saved values after reset
+            handler.Mesh = serializableData.mesh;
+
+            if (serializableData.materials != null)
+            {
+                for (int i = 0; i < serializableData.materials.Length; i++)
+                    handler.SetMaterial(serializableData.materials[i], i);
+            }
+
+            handler.Layers = serializableData.layers;
+        }
+
+        private void Update()
+        {
+            handler.UpdateTransform(sceneObject);
+        }
+
+        private void OnDestroy()
+        {
+            handler.OnDestroy();
+        }
+
+        [SerializeObject]
+        private struct SerializableData
+        {
+            public Mesh mesh;
+            public Material[] materials;
+            public UInt64 layers;
+        }
+    }
+}

+ 110 - 0
MBansheeEngine/RenderableHandler.cs

@@ -0,0 +1,110 @@
+using System;
+using System.Runtime.CompilerServices;
+
+namespace BansheeEngine
+{
+    internal class RenderableHandler : ScriptObject
+    {
+        internal Mesh Mesh
+        {
+            get
+            {
+                return mesh; 
+            }
+            set
+            {
+                mesh = value;
+
+                Material[] newMaterials = new Material[mesh.SubMeshCount];
+                int numToCopy = MathEx.Min(newMaterials.Length, materials.Length);
+                Array.Copy(materials, newMaterials, numToCopy);
+                materials = newMaterials;
+
+                IntPtr meshPtr = IntPtr.Zero;
+                if (mesh != null)
+                    meshPtr = mesh.GetCachedPtr();
+
+                Internal_SetMesh(mCachedPtr, meshPtr); 
+                
+            }
+        }
+
+        internal Bounds GetBounds(SceneObject parent)
+        {
+            AABox box;
+            Sphere sphere;
+
+            Internal_GetBounds(mCachedPtr, parent.mCachedPtr, out box, out sphere);
+
+            return new Bounds(box, sphere);
+        }
+
+        internal UInt64 Layers
+        {
+            get { return Internal_GetLayers(mCachedPtr); }
+            set { Internal_SetLayers(mCachedPtr, value); }
+        }
+
+        private Material[] materials = new Material[0];
+        private Mesh mesh;
+        
+        public RenderableHandler(SceneObject sceneObject)
+        {
+            IntPtr sceneObjPtr = IntPtr.Zero;
+            if (sceneObject != null)
+                sceneObjPtr = sceneObject.GetCachedPtr();
+
+            Internal_Create(this, sceneObjPtr);
+        }
+
+        internal Material GetMaterial(int index = 0)
+        {
+            return materials[index];
+        }
+
+        internal void SetMaterial(Material material, int index = 0)
+        {
+            materials[index] = material;
+
+            IntPtr materialPtr = IntPtr.Zero;
+            if (material != null)
+                materialPtr = material.GetCachedPtr();
+
+            Internal_SetMaterial(mCachedPtr, materialPtr, index);
+        }
+
+        internal void UpdateTransform(SceneObject sceneObject)
+        {
+            Internal_UpdateTransform(mCachedPtr, sceneObject.mCachedPtr);
+        }
+        
+        internal void OnDestroy()
+        {
+            Internal_OnDestroy(mCachedPtr);
+        }
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_Create(RenderableHandler instance, IntPtr parentSO);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_UpdateTransform(IntPtr thisPtr, IntPtr parentSO);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMesh(IntPtr thisPtr, IntPtr mesh);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_GetBounds(IntPtr thisPtr, IntPtr parentSO, out AABox box, out Sphere sphere);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern UInt64 Internal_GetLayers(IntPtr thisPtr);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetLayers(IntPtr thisPtr, UInt64 layers);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_SetMaterial(IntPtr thisPtr, IntPtr material, int index);
+
+        [MethodImpl(MethodImplOptions.InternalCall)]
+        private static extern void Internal_OnDestroy(IntPtr thisPtr);
+    }
+}

+ 29 - 0
MBansheeEngine/Sphere.cs

@@ -0,0 +1,29 @@
+using System.Runtime.InteropServices;
+
+namespace BansheeEngine
+{
+    [StructLayout(LayoutKind.Sequential), SerializeObject]
+    public struct Sphere
+    {
+        private float _radius;
+        private Vector3 _center;
+        
+        public Vector3 Center
+        {
+            get { return _center; }
+            set { _center = value; }
+        }
+
+        public float Radius
+        {
+            get { return _radius; }
+            set { _radius = value; }
+        }
+
+        public Sphere(Vector3 center, float radius)
+        {
+            _center = center;
+            _radius = radius;
+        }
+    };
+}

+ 9 - 0
SBansheeEditor/Source/BsGUIResourceField.cpp

@@ -301,6 +301,15 @@ namespace BansheeEngine
 				}
 			}
 				break;
+			case TID_Mesh:
+			{
+				if (ScriptAssemblyManager::instance().getMeshClass()->isSubClassOf(acceptedClass))
+				{
+					setUUID(uuid);
+					found = true;
+				}
+			}
+				break;
 			case TID_ManagedResource:
 			{
 				ManagedResourceMetaDataPtr managedResMetaData = std::static_pointer_cast<ManagedResourceMetaData>(meta->getResourceMetaData());

+ 1 - 0
SBansheeEngine/Include/BsManagedSerializableObjectInfo.h

@@ -30,6 +30,7 @@ namespace BansheeEngine
 		ScriptCodeRef,
 		ShaderRef,
 		MaterialRef,
+		MeshRef,
 		SceneObjectRef,
 		ComponentRef
 	};

+ 2 - 0
SBansheeEngine/Include/BsScriptAssemblyManager.h

@@ -33,6 +33,7 @@ namespace BansheeEngine
 		MonoClass* getSpriteTextureClass() const { return mSpriteTextureClass; }
 		MonoClass* getShaderClass() const { return mShaderClass; }
 		MonoClass* getMaterialClass() const { return mMaterialClass; }
+		MonoClass* getMeshClass() const { return mMeshClass; }
 		MonoClass* getFontClass() const { return mFontClass; }
 		MonoClass* getPlainTextClass() const { return mPlainTextClass; }
 		MonoClass* getScriptCodeClass() const { return mScriptCodeClass; }
@@ -56,6 +57,7 @@ namespace BansheeEngine
 		MonoClass* mSpriteTextureClass;
 		MonoClass* mShaderClass;
 		MonoClass* mMaterialClass;
+		MonoClass* mMeshClass;
 		MonoClass* mManagedResourceClass;
 		MonoClass* mFontClass;
 		MonoClass* mPlainTextClass;

+ 20 - 0
SBansheeEngine/Include/BsScriptBoneWeight.h

@@ -0,0 +1,20 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptObject.h"
+#include "BsMeshData.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptBoneWeight : public ScriptObject <ScriptBoneWeight>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "BoneWeight")
+
+		static BoneWeight unbox(MonoObject* obj);
+		static MonoObject* box(const BoneWeight& value);
+
+	private:
+		ScriptBoneWeight(MonoObject* instance);
+	};
+}

+ 2 - 0
SBansheeEngine/Include/BsScriptEnginePrerequisites.h

@@ -32,6 +32,7 @@ namespace BansheeEngine
 	class ScriptScriptCode;
 	class ScriptShader;
 	class ScriptMaterial;
+	class ScriptMesh;
 	class ScriptGUIElementStyle;
 	class ScriptGUIElementStateStyle;
 	class ScriptGUILayout;
@@ -43,6 +44,7 @@ namespace BansheeEngine
 	class ScriptRenderTarget;
 	class ScriptRenderTexture2D;
 	class ScriptCameraHandler;
+	class ScriptMeshData;
 	class ManagedComponent;
 	class ManagedSerializableFieldData;
 	class ManagedSerializableFieldKey;

+ 71 - 0
SBansheeEngine/Include/BsScriptMesh.h

@@ -0,0 +1,71 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptResource.h"
+#include "BsScriptMeshData.h"
+#include "BsMesh.h"
+
+namespace BansheeEngine
+{
+	enum class MeshTopology
+	{
+		PointList = 1,
+		LineList = 2,
+		LineStrip = 3,
+		TriangleList = 4,
+		TriangleStrip = 5,
+		TriangleFan = 6
+	};
+
+	struct BS_SCR_BE_EXPORT SubMeshData
+	{
+		UINT32 indexOffset;
+		UINT32 indexCount;
+		MeshTopology topology;
+	};
+
+	class BS_SCR_BE_EXPORT ScriptSubMesh : public ScriptObject < ScriptSubMesh >
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "SubMesh")
+
+		static SubMeshData unbox(MonoObject* obj);
+		static MonoObject* box(const SubMeshData& value);
+
+	private:
+		ScriptSubMesh(MonoObject* instance);
+	};
+
+	class BS_SCR_BE_EXPORT ScriptMesh : public ScriptObject <ScriptMesh, ScriptResourceBase>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "Mesh")
+
+		HResource getNativeHandle() const { return mMesh; }
+		void setNativeHandle(const HResource& resource);
+
+		HMesh getMeshHandle() const { return mMesh; }
+	private:
+		friend class ScriptResourceManager;
+
+		ScriptMesh(MonoObject* instance, const HMesh& mesh);
+
+		static void internal_CreateInstance(MonoObject* instance, int numVertices,
+			int numIndices, MonoArray* subMeshes, MeshUsage usage, VertexLayout vertex, ScriptIndexType index);
+		static void internal_CreateInstanceMeshData(MonoObject* instance, ScriptMeshData* data, MonoArray* subMeshes,
+			MeshUsage usage);
+		static MonoArray* internal_GetSubMeshes(ScriptMesh* thisPtr);
+		static UINT32 internal_GetSubMeshCount(ScriptMesh* thisPtr);
+		static void internal_GetBounds(ScriptMesh* thisPtr, AABox* box, Sphere* sphere);
+		static MonoObject* internal_GetMeshData(ScriptMesh* thisPtr);
+		static void internal_SetMeshData(ScriptMesh* thisPtr, ScriptMeshData* value);
+
+		static DrawOperationType meshTopologyToDrawOp(MeshTopology topology);
+		static MeshTopology drawOpToMeshTopology(DrawOperationType drawOp);
+		static Vector<SubMesh> monoToNativeSubMeshes(MonoArray* subMeshes);
+
+		void _onManagedInstanceDeleted();
+
+		HMesh mMesh;
+	};
+}

+ 56 - 0
SBansheeEngine/Include/BsScriptMeshData.h

@@ -0,0 +1,56 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptObject.h"
+#include "BsDefaultMeshData.h"
+
+namespace BansheeEngine
+{
+	// Note: Do not modify, it must match the layout of C# enum IndexType
+	enum class ScriptIndexType
+	{
+		Index16,
+		Index32
+	};
+
+	class BS_SCR_BE_EXPORT ScriptMeshData : public ScriptObject <ScriptMeshData>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "MeshData")
+
+		DefaultMeshDataPtr getInternalValue() const { return mMeshData; }
+
+		static MonoObject* create(const DefaultMeshDataPtr& meshData);
+		static MonoObject* create(const MeshDataPtr& meshData);
+	private:
+		ScriptMeshData(MonoObject* managedInstance);
+		~ScriptMeshData();
+
+		void initialize(const DefaultMeshDataPtr& meshData);
+
+		static void internal_CreateInstance(MonoObject* instance, int numVertices,
+			int numIndices, VertexLayout vertex, ScriptIndexType index);
+		static MonoArray* internal_GetPositions(ScriptMeshData* thisPtr);
+		static void internal_SetPositions(ScriptMeshData* thisPtr, MonoArray* value);
+		static MonoArray* internal_GetNormals(ScriptMeshData* thisPtr);
+		static void internal_SetNormals(ScriptMeshData* thisPtr, MonoArray* value);
+		static MonoArray* internal_GetTangents(ScriptMeshData* thisPtr);
+		static void internal_SetTangents(ScriptMeshData* thisPtr, MonoArray* value);
+		static MonoArray* internal_GetColors(ScriptMeshData* thisPtr);
+		static void internal_SetColors(ScriptMeshData* thisPtr, MonoArray* value);
+		static MonoArray* internal_GetUV0(ScriptMeshData* thisPtr);
+		static void internal_SetUV0(ScriptMeshData* thisPtr, MonoArray* value);
+		static MonoArray* internal_GetUV1(ScriptMeshData* thisPtr);
+		static void internal_SetUV1(ScriptMeshData* thisPtr, MonoArray* value);
+		static MonoArray* internal_GetBoneWeights(ScriptMeshData* thisPtr);
+		static void internal_SetBoneWeights(ScriptMeshData* thisPtr, MonoArray* value);
+		static MonoArray* internal_GetIndices(ScriptMeshData* thisPtr);
+		static void internal_SetIndices(ScriptMeshData* thisPtr, MonoArray* value);
+		static int internal_GetVertexCount(ScriptMeshData* thisPtr);
+		static int internal_GetIndexCount(ScriptMeshData* thisPtr);
+
+		static bool checkIsLocked(ScriptMeshData* thisPtr);
+		
+		DefaultMeshDataPtr mMeshData;
+	};
+}

+ 33 - 0
SBansheeEngine/Include/BsScriptRenderableHandler.h

@@ -0,0 +1,33 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptObject.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptRenderableHandler : public ScriptObject < ScriptRenderableHandler >
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "RenderableHandler")
+
+		SPtr<RenderableHandler> getInternal() const { return mRenderableHandler; }
+
+	private:
+		ScriptRenderableHandler(MonoObject* managedInstance, const HSceneObject& parentSO);
+		~ScriptRenderableHandler();
+
+		void updateTransform(const HSceneObject& parent);
+
+		static void internal_Create(MonoObject* instance, ScriptSceneObject* parentSO);
+		static void internal_UpdateTransform(ScriptRenderableHandler* thisPtr, ScriptSceneObject* parentSO);
+		static void internal_SetMesh(ScriptRenderableHandler* thisPtr, ScriptMesh* mesh);
+		static void internal_GetBounds(ScriptRenderableHandler* thisPtr, ScriptSceneObject* parentSO, AABox* box, Sphere* sphere);
+		static UINT64 internal_GetLayers(ScriptRenderableHandler* thisPtr);
+		static void internal_SetLayers(ScriptRenderableHandler* thisPtr, UINT64 layers);
+		static void internal_SetMaterial(ScriptRenderableHandler* thisPtr, ScriptMaterial* material, int index);
+		static void internal_OnDestroy(ScriptRenderableHandler* thisPtr);
+
+		SPtr<RenderableHandler> mRenderableHandler;
+		UINT32 mLastUpdateHash;
+	};
+}

+ 17 - 0
SBansheeEngine/Include/BsScriptResourceManager.h

@@ -71,6 +71,18 @@ namespace BansheeEngine
 		 */
 		ScriptMaterial* createScriptMaterial(MonoObject* existingInstance, const HMaterial& resourceHandle);
 
+		/**
+		 * @note Throws an exception if resource for the handle already exists.
+		 * 		 Initializes the ScriptResource with an existing managed instance.
+		 */
+		ScriptMesh* createScriptMesh(const HMesh& resourceHandle);
+
+		/**
+		 * @note Throws an exception if resource for the handle already exists.
+		 * 		 Initializes the ScriptResource with an existing managed instance.
+		 */
+		ScriptMesh* createScriptMesh(MonoObject* existingInstance, const HMesh& resourceHandle);
+
 		/**
 		 * @note Throws an exception if resource for the handle already exists.
 		 * 		 Initializes the ScriptResource with an existing managed instance.
@@ -150,6 +162,11 @@ namespace BansheeEngine
 		 */
 		ScriptMaterial* getScriptMaterial(const HMaterial& resourceHandle);
 
+		/**
+		 * @note Returns nullptr if script resource doesn't exist.
+		 */
+		ScriptMesh* getScriptMesh(const HMesh& resourceHandle);
+
 		/**
 		 * @note Returns nullptr if script resource doesn't exist.
 		 */

+ 46 - 0
SBansheeEngine/Include/BsScriptVector.h

@@ -0,0 +1,46 @@
+#pragma once
+
+#include "BsScriptEnginePrerequisites.h"
+#include "BsScriptObject.h"
+#include "BsVector2.h"
+#include "BsVector3.h"
+#include "BsVector4.h"
+
+namespace BansheeEngine
+{
+	class BS_SCR_BE_EXPORT ScriptVector2 : public ScriptObject <ScriptVector2>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "Vector2")
+
+		static Vector2 unbox(MonoObject* obj);
+		static MonoObject* box(const Vector2& value);
+
+	private:
+		ScriptVector2(MonoObject* instance);
+	};
+
+	class BS_SCR_BE_EXPORT ScriptVector3 : public ScriptObject <ScriptVector3>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "Vector3")
+
+		static Vector3 unbox(MonoObject* obj);
+		static MonoObject* box(const Vector3& value);
+
+	private:
+		ScriptVector3(MonoObject* instance);
+	};
+
+	class BS_SCR_BE_EXPORT ScriptVector4 : public ScriptObject <ScriptVector4>
+	{
+	public:
+		SCRIPT_OBJ(ENGINE_ASSEMBLY, "BansheeEngine", "Vector4")
+
+		static Vector4 unbox(MonoObject* obj);
+		static MonoObject* box(const Vector4& value);
+
+	private:
+		ScriptVector4(MonoObject* instance);
+	};
+}

+ 10 - 0
SBansheeEngine/SBansheeEngine.vcxproj

@@ -252,6 +252,7 @@
     <ClInclude Include="Include\BsManagedSerializableObjectDataRTTI.h" />
     <ClInclude Include="Include\BsScriptAssemblyManager.h" />
     <ClInclude Include="Include\BsScriptAsyncOp.h" />
+    <ClInclude Include="Include\BsScriptBoneWeight.h" />
     <ClInclude Include="Include\BsScriptBuiltin.h" />
     <ClInclude Include="Include\BsScriptCameraHandler.h" />
     <ClInclude Include="Include\BsScriptColor.h" />
@@ -286,12 +287,15 @@
     <ClInclude Include="Include\BsScriptMacros.h" />
     <ClInclude Include="Include\BsScriptManagedResource.h" />
     <ClInclude Include="Include\BsScriptMaterial.h" />
+    <ClInclude Include="Include\BsScriptMesh.h" />
+    <ClInclude Include="Include\BsScriptMeshData.h" />
     <ClInclude Include="Include\BsScriptObject.h" />
     <ClInclude Include="Include\BsScriptObjectImpl.h" />
     <ClInclude Include="Include\BsScriptObjectManager.h" />
     <ClInclude Include="Include\BsScriptPixelData.h" />
     <ClInclude Include="Include\BsScriptPixelUtility.h" />
     <ClInclude Include="Include\BsScriptPlainText.h" />
+    <ClInclude Include="Include\BsScriptRenderableHandler.h" />
     <ClInclude Include="Include\BsScriptRenderTarget.h" />
     <ClInclude Include="Include\BsScriptRenderTexture.h" />
     <ClInclude Include="Include\BsScriptRenderTexture2D.h" />
@@ -317,6 +321,7 @@
     <ClInclude Include="Include\BsScriptTexture3D.h" />
     <ClInclude Include="Include\BsScriptTextureCube.h" />
     <ClInclude Include="Include\BsScriptTime.h" />
+    <ClInclude Include="Include\BsScriptVector.h" />
     <ClInclude Include="Include\BsScriptVector2I.h" />
     <ClInclude Include="Include\BsScriptVirtualButton.h" />
     <ClInclude Include="Include\BsScriptVirtualInput.h" />
@@ -329,6 +334,7 @@
     <ClCompile Include="Source\BsManagedSerializableObjectData.cpp" />
     <ClCompile Include="Source\BsScriptAssemblyManager.cpp" />
     <ClCompile Include="Source\BsScriptAsyncOp.cpp" />
+    <ClCompile Include="Source\BsScriptBoneWeight.cpp" />
     <ClCompile Include="Source\BsScriptBuiltin.cpp" />
     <ClCompile Include="Source\BsScriptCameraHandler.cpp" />
     <ClCompile Include="Source\BsScriptColor.cpp" />
@@ -362,12 +368,15 @@
     <ClCompile Include="Source\BsScriptInputConfiguration.cpp" />
     <ClCompile Include="Source\BsScriptManagedResource.cpp" />
     <ClCompile Include="Source\BsScriptMaterial.cpp" />
+    <ClCompile Include="Source\BsScriptMesh.cpp" />
+    <ClCompile Include="Source\BsScriptMeshData.cpp" />
     <ClCompile Include="Source\BsScriptObject.cpp" />
     <ClCompile Include="Source\BsScriptObjectImpl.cpp" />
     <ClCompile Include="Source\BsScriptObjectManager.cpp" />
     <ClCompile Include="Source\BsScriptPixelData.cpp" />
     <ClCompile Include="Source\BsScriptPixelUtility.cpp" />
     <ClCompile Include="Source\BsScriptPlainText.cpp" />
+    <ClCompile Include="Source\BsScriptRenderableHandler.cpp" />
     <ClCompile Include="Source\BsScriptRenderTarget.cpp" />
     <ClCompile Include="Source\BsScriptRenderTexture.cpp" />
     <ClCompile Include="Source\BsScriptRenderTexture2D.cpp" />
@@ -396,6 +405,7 @@
     <ClCompile Include="Source\BsScriptTexture3D.cpp" />
     <ClCompile Include="Source\BsScriptTextureCube.cpp" />
     <ClCompile Include="Source\BsScriptTime.cpp" />
+    <ClCompile Include="Source\BsScriptVector.cpp" />
     <ClCompile Include="Source\BsScriptVector2I.cpp" />
     <ClCompile Include="Source\BsScriptVirtualInput.cpp" />
     <ClCompile Include="Source\BsScriptVirtualButton.cpp" />

+ 30 - 0
SBansheeEngine/SBansheeEngine.vcxproj.filters

@@ -297,6 +297,21 @@
     <ClInclude Include="Include\BsScriptMaterial.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsScriptMesh.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptMeshData.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptVector.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptBoneWeight.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsScriptRenderableHandler.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsScriptTexture2D.cpp">
@@ -530,5 +545,20 @@
     <ClCompile Include="Source\BsScriptMaterial.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsScriptMesh.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsScriptMeshData.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsScriptVector.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsScriptBoneWeight.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsScriptRenderableHandler.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 28 - 0
SBansheeEngine/Source/BsManagedSerializableField.cpp

@@ -14,6 +14,7 @@
 #include "BsScriptScriptCode.h"
 #include "BsScriptShader.h"
 #include "BsScriptMaterial.h"
+#include "BsScriptMesh.h"
 #include "BsScriptSceneObject.h"
 #include "BsScriptComponent.h"
 #include "BsManagedSerializableObject.h"
@@ -214,6 +215,18 @@ namespace BansheeEngine
 
 				return fieldData;
 			}
+			case ScriptPrimitiveType::MeshRef:
+			{
+				auto fieldData = bs_shared_ptr<ManagedSerializableFieldDataResourceRef>();
+
+				if (value != nullptr)
+				{
+					ScriptMesh* scriptMesh = ScriptMesh::toNative(value);
+					fieldData->value = static_resource_cast<ScriptMesh>(scriptMesh->getNativeHandle());
+				}
+
+				return fieldData;
+			}
 			case ScriptPrimitiveType::ManagedResourceRef:
 				{
 					auto fieldData = bs_shared_ptr<ManagedSerializableFieldDataResourceRef>();
@@ -571,6 +584,21 @@ namespace BansheeEngine
 				else
 					return nullptr;
 			}
+			else if (primitiveTypeInfo->mType == ScriptPrimitiveType::MeshRef)
+			{
+				if (value)
+				{
+					HMesh mesh = static_resource_cast<Mesh>(value);
+					ScriptMesh* scriptResource = ScriptResourceManager::instance().getScriptMesh(mesh);
+					if (scriptResource == nullptr)
+						scriptResource = ScriptResourceManager::instance().createScriptMesh(mesh);
+
+					if (scriptResource != nullptr)
+						return scriptResource->getManagedInstance();
+				}
+				else
+					return nullptr;
+			}
 			else if (primitiveTypeInfo->mType == ScriptPrimitiveType::PlainTextRef)
 			{
 				if (value)

+ 2 - 0
SBansheeEngine/Source/BsManagedSerializableObjectInfo.cpp

@@ -141,6 +141,8 @@ namespace BansheeEngine
 			return ScriptAssemblyManager::instance().getShaderClass()->_getInternalClass();
 		case ScriptPrimitiveType::MaterialRef:
 			return ScriptAssemblyManager::instance().getMaterialClass()->_getInternalClass();
+		case ScriptPrimitiveType::MeshRef:
+			return ScriptAssemblyManager::instance().getMeshClass()->_getInternalClass();
 		case ScriptPrimitiveType::ManagedResourceRef:
 			return ScriptAssemblyManager::instance().getManagedResourceClass()->_getInternalClass();
 		case ScriptPrimitiveType::PlainTextRef:

+ 12 - 1
SBansheeEngine/Source/BsScriptAssemblyManager.cpp

@@ -19,7 +19,7 @@ namespace BansheeEngine
 		mSerializeFieldAttribute(nullptr), mHideInInspectorAttribute(nullptr), mSystemArrayClass(nullptr), mSystemGenericListClass(nullptr),
 		mSystemGenericDictionaryClass(nullptr), mManagedResourceClass(nullptr), mFontClass(nullptr), mMissingComponentClass(nullptr),
 		mPlainTextClass(nullptr), mScriptCodeClass(nullptr), mShaderClass(nullptr), mMaterialClass(nullptr), mTexture3DClass(nullptr),
-		mTextureCubeClass(nullptr)
+		mTextureCubeClass(nullptr), mMeshClass(nullptr)
 	{
 
 	}
@@ -308,6 +308,12 @@ namespace BansheeEngine
 				typeInfo->mType = ScriptPrimitiveType::MaterialRef;
 				return typeInfo;
 			}
+			else if (monoClass->isSubClassOf(mMeshClass))
+			{
+				std::shared_ptr<ManagedSerializableTypeInfoPrimitive> typeInfo = bs_shared_ptr<ManagedSerializableTypeInfoPrimitive>();
+				typeInfo->mType = ScriptPrimitiveType::MeshRef;
+				return typeInfo;
+			}
 			else if (monoClass->isSubClassOf(mPlainTextClass))
 			{
 				std::shared_ptr<ManagedSerializableTypeInfoPrimitive> typeInfo = bs_shared_ptr<ManagedSerializableTypeInfoPrimitive>();
@@ -429,6 +435,7 @@ namespace BansheeEngine
 		mSpriteTextureClass = nullptr;
 		mShaderClass = nullptr;
 		mMaterialClass = nullptr;
+		mMeshClass = nullptr;
 		mFontClass = nullptr;
 		mPlainTextClass = nullptr;
 		mScriptCodeClass = nullptr;
@@ -508,6 +515,10 @@ namespace BansheeEngine
 		if (mMaterialClass == nullptr)
 			BS_EXCEPT(InvalidStateException, "Cannot find Material managed class.");
 
+		mMeshClass = bansheeEngineAssembly->getClass("BansheeEngine", "Mesh");
+		if (mMeshClass == nullptr)
+			BS_EXCEPT(InvalidStateException, "Cannot find Mesh managed class.");
+
 		mFontClass = bansheeEngineAssembly->getClass("BansheeEngine", "Font");
 		if (mFontClass == nullptr)
 			BS_EXCEPT(InvalidStateException, "Cannot find Font managed class.");

+ 26 - 0
SBansheeEngine/Source/BsScriptBoneWeight.cpp

@@ -0,0 +1,26 @@
+#include "BsScriptBoneWeight.h"
+#include "BsMonoManager.h"
+#include "BsMonoClass.h"
+#include "BsMonoUtil.h"
+
+namespace BansheeEngine
+{
+	ScriptBoneWeight::ScriptBoneWeight(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptBoneWeight::initRuntimeData()
+	{ }
+
+	MonoObject* ScriptBoneWeight::box(const BoneWeight& value)
+	{
+		// We're casting away const but it's fine since structs are passed by value anyway
+		return mono_value_box(MonoManager::instance().getDomain(),
+			metaData.scriptClass->_getInternalClass(), (void*)&value);
+	}
+
+	BoneWeight ScriptBoneWeight::unbox(MonoObject* obj)
+	{
+		return *(BoneWeight*)mono_object_unbox(obj);
+	}
+}

+ 213 - 0
SBansheeEngine/Source/BsScriptMesh.cpp

@@ -0,0 +1,213 @@
+#include "BsScriptMesh.h"
+#include "BsScriptResourceManager.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoArray.h"
+#include "BsMonoManager.h"
+#include "BsCoreThread.h"
+
+namespace BansheeEngine
+{
+	ScriptSubMesh::ScriptSubMesh(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptSubMesh::initRuntimeData()
+	{ }
+
+	MonoObject* ScriptSubMesh::box(const SubMeshData& value)
+	{
+		// We're casting away const but it's fine since structs are passed by value anyway
+		return mono_value_box(MonoManager::instance().getDomain(),
+			metaData.scriptClass->_getInternalClass(), (void*)&value);
+	}
+
+	SubMeshData ScriptSubMesh::unbox(MonoObject* obj)
+	{
+		return *(SubMeshData*)mono_object_unbox(obj);
+	}
+
+	ScriptMesh::ScriptMesh(MonoObject* instance, const HMesh& mesh)
+		:ScriptObject(instance), mMesh(mesh)
+	{
+
+	}
+
+	void ScriptMesh::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_CreateInstance", &ScriptMesh::internal_CreateInstance);
+		metaData.scriptClass->addInternalCall("Internal_CreateInstanceMeshData", &ScriptMesh::internal_CreateInstanceMeshData);
+		metaData.scriptClass->addInternalCall("Internal_GetSubMeshes", &ScriptMesh::internal_GetSubMeshes);
+		metaData.scriptClass->addInternalCall("Internal_GetSubMeshCount", &ScriptMesh::internal_GetSubMeshCount);
+		metaData.scriptClass->addInternalCall("Internal_GetBounds", &ScriptMesh::internal_GetBounds);
+		metaData.scriptClass->addInternalCall("Internal_GetMeshData", &ScriptMesh::internal_GetMeshData);
+		metaData.scriptClass->addInternalCall("Internal_SetMeshData", &ScriptMesh::internal_SetMeshData);
+	}
+
+	void ScriptMesh::internal_CreateInstance(MonoObject* instance, int numVertices, int numIndices, 
+		MonoArray* subMeshes, MeshUsage usage, VertexLayout vertex, ScriptIndexType index)
+	{
+		VertexDataDescPtr vertexDesc = DefaultMeshData::vertexLayoutVertexDesc(vertex);
+
+		IndexType indexType = IT_16BIT;
+		if (index == ScriptIndexType::Index32)
+			indexType = IT_32BIT;
+
+		Vector<SubMesh> nativeSubMeshes = monoToNativeSubMeshes(subMeshes);
+		HMesh mesh = Mesh::create(numVertices, numIndices, vertexDesc, nativeSubMeshes, usage, indexType);
+
+		ScriptResourceManager::instance().createScriptMesh(instance, mesh);
+	}
+
+	void ScriptMesh::internal_CreateInstanceMeshData(MonoObject* instance, ScriptMeshData* data, MonoArray* subMeshes,
+		MeshUsage usage)
+	{
+		MeshDataPtr meshData;
+		if (data != nullptr)
+			meshData = data->getInternalValue()->getData();
+
+		Vector<SubMesh> nativeSubMeshes = monoToNativeSubMeshes(subMeshes);
+		HMesh mesh = Mesh::create(meshData, nativeSubMeshes, usage);
+
+		ScriptResourceManager::instance().createScriptMesh(instance, mesh);
+	}
+
+	MonoArray* ScriptMesh::internal_GetSubMeshes(ScriptMesh* thisPtr)
+	{
+		HMesh mesh = thisPtr->getMeshHandle();
+
+		UINT32 numSubMeshes = mesh->getProperties().getNumSubMeshes();
+		ScriptArray subMeshArray = ScriptArray::create<ScriptSubMesh>(numSubMeshes);
+
+		for (UINT32 i = 0; i < numSubMeshes; i++)
+		{
+			SubMesh curSubMesh = mesh->getProperties().getSubMesh(i);
+
+			SubMeshData data;
+			data.indexOffset = curSubMesh.indexOffset;
+			data.indexCount = curSubMesh.indexCount;
+			data.topology = drawOpToMeshTopology(curSubMesh.drawOp);
+
+			subMeshArray.set(i, data);
+		}
+
+		return subMeshArray.getInternal();
+	}
+
+	UINT32 ScriptMesh::internal_GetSubMeshCount(ScriptMesh* thisPtr)
+	{
+		HMesh mesh = thisPtr->getMeshHandle();
+
+		return mesh->getProperties().getNumSubMeshes();
+	}
+
+	void ScriptMesh::internal_GetBounds(ScriptMesh* thisPtr, AABox* box, Sphere* sphere)
+	{
+		HMesh mesh = thisPtr->getMeshHandle();
+
+		Bounds bounds = mesh->getProperties().getBounds();
+		*box = bounds.getBox();
+		*sphere = bounds.getSphere();
+	}
+
+	MonoObject* ScriptMesh::internal_GetMeshData(ScriptMesh* thisPtr)
+	{
+		HMesh mesh = thisPtr->getMeshHandle();
+
+		MeshDataPtr meshData = mesh->allocateSubresourceBuffer(0);
+		mesh->readData(*meshData);
+
+		return ScriptMeshData::create(meshData);
+	}
+
+	void ScriptMesh::internal_SetMeshData(ScriptMesh* thisPtr, ScriptMeshData* value)
+	{
+		HMesh mesh = thisPtr->getMeshHandle();
+		if (value != nullptr)
+		{
+			MeshDataPtr meshData = value->getInternalValue()->getData();
+			mesh->writeSubresource(gCoreAccessor(), 0, meshData, true);
+		}
+	}
+
+	DrawOperationType ScriptMesh::meshTopologyToDrawOp(MeshTopology topology)
+	{
+		switch (topology)
+		{
+		case MeshTopology::PointList:
+			return DOT_POINT_LIST;
+		case MeshTopology::LineList:
+			return DOT_LINE_LIST;
+		case MeshTopology::LineStrip:
+			return DOT_LINE_STRIP;
+		case MeshTopology::TriangleList:
+			return DOT_TRIANGLE_LIST;
+		case MeshTopology::TriangleStrip:
+			return DOT_TRIANGLE_STRIP;
+		case MeshTopology::TriangleFan:
+			return DOT_TRIANGLE_FAN;
+		}
+
+		return DOT_TRIANGLE_LIST;
+	}
+
+	MeshTopology ScriptMesh::drawOpToMeshTopology(DrawOperationType drawOp)
+	{
+		switch (drawOp)
+		{
+		case DOT_POINT_LIST:
+			return MeshTopology::PointList;
+		case DOT_LINE_LIST:
+			return MeshTopology::TriangleList;
+		case DOT_LINE_STRIP:
+			return MeshTopology::TriangleStrip;
+		case DOT_TRIANGLE_LIST:
+			return MeshTopology::TriangleList;
+		case DOT_TRIANGLE_STRIP:
+			return MeshTopology::TriangleStrip;
+		case DOT_TRIANGLE_FAN:
+			return MeshTopology::TriangleFan;
+		}
+
+		return MeshTopology::TriangleList;
+	}
+
+	Vector<SubMesh> ScriptMesh::monoToNativeSubMeshes(MonoArray* subMeshes)
+	{
+		Vector<SubMesh> nativeSubMeshes;
+
+		if (subMeshes != nullptr)
+		{
+			ScriptArray subMeshArray(subMeshes);
+
+			UINT32 numSubMeshes = subMeshArray.size();
+			for (UINT32 i = 0; i < numSubMeshes; i++)
+			{
+				SubMeshData curData = subMeshArray.get<SubMeshData>(i);
+
+				SubMesh subMesh;
+				subMesh.indexOffset = curData.indexOffset;
+				subMesh.indexCount = curData.indexCount;
+				subMesh.drawOp = meshTopologyToDrawOp(curData.topology);
+
+				nativeSubMeshes.push_back(subMesh);
+			}
+		}
+
+		return nativeSubMeshes;
+	}
+
+	void ScriptMesh::_onManagedInstanceDeleted()
+	{
+		mManagedInstance = nullptr;
+
+		if (!mRefreshInProgress)
+			ScriptResourceManager::instance().destroyScriptResource(this);
+	}
+
+	void ScriptMesh::setNativeHandle(const HResource& resource)
+	{
+		mMesh = static_resource_cast<Mesh>(resource);
+	}
+}

+ 307 - 0
SBansheeEngine/Source/BsScriptMeshData.cpp

@@ -0,0 +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 DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size) { }
+		static void set(const DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size) { }
+	};
+
+	template<>
+	struct TVertexDataAccessor < (int)VertexLayout::Position >
+	{
+		static void get(const DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->getPositions((Vector3*)buffer, size); }
+
+		static void set(const DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->setPositions((Vector3*)buffer, size); }
+	};
+
+	template<>
+	struct TVertexDataAccessor < (int)VertexLayout::Normal >
+	{
+		static void get(const DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->getNormals((Vector3*)buffer, size); }
+
+		static void set(const DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->setNormals((Vector3*)buffer, size); }
+	};
+
+	template<>
+	struct TVertexDataAccessor < (int)VertexLayout::Tangent >
+	{
+		static void get(const DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->getTangents((Vector4*)buffer, size); }
+
+		static void set(const DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->setTangents((Vector4*)buffer, size); }
+	};
+
+	template<>
+	struct TVertexDataAccessor < (int)VertexLayout::Color >
+	{
+		static void get(const DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->getColors((Color*)buffer, size); }
+
+		static void set(const DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->setColors((Color*)buffer, size); }
+	};
+
+	template<>
+	struct TVertexDataAccessor < (int)VertexLayout::UV0 >
+	{
+		static void get(const DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->getUV0((Vector2*)buffer, size); }
+
+		static void set(const DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->setUV0((Vector2*)buffer, size); }
+	};
+
+	template<>
+	struct TVertexDataAccessor < (int)VertexLayout::UV1 >
+	{
+		static void get(const DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->getUV1((Vector2*)buffer, size); }
+
+		static void set(const DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->setUV1((Vector2*)buffer, size); }
+	};
+
+	template<>
+	struct TVertexDataAccessor < (int)VertexLayout::BoneWeights >
+	{
+		static void get(const DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->getBoneWeights((BoneWeight*)buffer, size); }
+
+		static void set(const DefaultMeshDataPtr& meshData, UINT8* buffer, UINT32 size)
+		{ meshData->setBoneWeights((BoneWeight*)buffer, size); }
+	};
+
+	template<int Semantic, class TNative, class TScript>
+	MonoArray* getVertexDataArray(ScriptMeshData* scriptMeshData)
+	{
+		DefaultMeshDataPtr 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;
+
+		DefaultMeshDataPtr 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 DefaultMeshDataPtr& meshData)
+	{
+		mMeshData = meshData;
+	}
+
+	MonoObject* ScriptMeshData::create(const DefaultMeshDataPtr& 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();
+
+		DefaultMeshDataPtr defaultMeshData = DefaultMeshData::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;
+
+		DefaultMeshDataPtr meshData = DefaultMeshData::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)
+	{
+		DefaultMeshDataPtr 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;
+
+		DefaultMeshDataPtr 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)
+	{
+		DefaultMeshDataPtr meshData = thisPtr->getInternalValue();
+
+		return (int)meshData->getData()->getNumVertices();
+	}
+
+	int ScriptMeshData::internal_GetIndexCount(ScriptMeshData* thisPtr)
+	{
+		DefaultMeshDataPtr 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;
+	}
+}

+ 116 - 0
SBansheeEngine/Source/BsScriptRenderableHandler.cpp

@@ -0,0 +1,116 @@
+#include "BsScriptRenderableHandler.h"
+#include "BsScriptMeta.h"
+#include "BsMonoField.h"
+#include "BsMonoClass.h"
+#include "BsMonoManager.h"
+#include "BsMonoUtil.h"
+#include "BsApplication.h"
+#include "BsRenderableHandler.h"
+#include "BsScriptSceneObject.h"
+#include "BsSceneObject.h"
+#include "BsSceneManager.h"
+#include "BsScriptMesh.h"
+#include "BsScriptMaterial.h"
+
+namespace BansheeEngine
+{
+	ScriptRenderableHandler::ScriptRenderableHandler(MonoObject* managedInstance, const HSceneObject& parentSO)
+		:ScriptObject(managedInstance), mRenderableHandler(nullptr), mLastUpdateHash(0)
+	{
+		mRenderableHandler = RenderableHandler::create();
+		gSceneManager()._registerRenderable(mRenderableHandler, parentSO);
+	}
+
+	ScriptRenderableHandler::~ScriptRenderableHandler()
+	{
+
+	}
+
+	void ScriptRenderableHandler::initRuntimeData()
+	{
+		metaData.scriptClass->addInternalCall("Internal_Create", &ScriptRenderableHandler::internal_Create);
+		metaData.scriptClass->addInternalCall("Internal_UpdateTransform", &ScriptRenderableHandler::internal_UpdateTransform);
+		metaData.scriptClass->addInternalCall("Internal_SetMesh", &ScriptRenderableHandler::internal_SetMesh);
+		metaData.scriptClass->addInternalCall("Internal_GetBounds", &ScriptRenderableHandler::internal_GetBounds);
+		metaData.scriptClass->addInternalCall("Internal_GetLayers", &ScriptRenderableHandler::internal_GetLayers);
+		metaData.scriptClass->addInternalCall("Internal_SetLayers", &ScriptRenderableHandler::internal_SetLayers);
+		metaData.scriptClass->addInternalCall("Internal_SetMaterial", &ScriptRenderableHandler::internal_SetMaterial);
+		metaData.scriptClass->addInternalCall("Internal_OnDestroy", &ScriptRenderableHandler::internal_OnDestroy);
+	}
+
+	void ScriptRenderableHandler::updateTransform(const HSceneObject& parent)
+	{
+		UINT32 curHash = parent->getTransformHash();
+		if (curHash != mLastUpdateHash)
+		{
+			mRenderableHandler->setTransform(parent->getWorldTfrm());
+
+			mLastUpdateHash = curHash;
+		}
+
+		if (parent->getActive() != mRenderableHandler->getIsActive())
+		{
+			mRenderableHandler->setIsActive(parent->getActive());
+		}
+	}
+
+	void ScriptRenderableHandler::internal_Create(MonoObject* instance, ScriptSceneObject* parentSO)
+	{
+		HSceneObject so;
+		if (parentSO != nullptr)
+			so = parentSO->getNativeHandle();
+
+		ScriptRenderableHandler* nativeInstance = new (bs_alloc<ScriptRenderableHandler>()) ScriptRenderableHandler(instance, so);
+	}
+
+	void ScriptRenderableHandler::internal_UpdateTransform(ScriptRenderableHandler* thisPtr, ScriptSceneObject* parent)
+	{
+		HSceneObject parentSO = parent->getNativeSceneObject();
+
+		thisPtr->updateTransform(parentSO);
+	}
+
+	void ScriptRenderableHandler::internal_SetMesh(ScriptRenderableHandler* thisPtr, ScriptMesh* mesh)
+	{
+		HMesh nativeMesh;
+		if (mesh != nullptr)
+			nativeMesh = mesh->getMeshHandle();
+
+		thisPtr->getInternal()->setMesh(nativeMesh);
+	}
+
+	void ScriptRenderableHandler::internal_GetBounds(ScriptRenderableHandler* thisPtr, ScriptSceneObject* parent, AABox* box, Sphere* sphere)
+	{
+		HSceneObject parentSO = parent->getNativeSceneObject();
+		thisPtr->updateTransform(parentSO);
+
+		Bounds bounds = thisPtr->getInternal()->getBounds();
+
+		*box = bounds.getBox();
+		*sphere = bounds.getSphere();
+	}
+
+	UINT64 ScriptRenderableHandler::internal_GetLayers(ScriptRenderableHandler* thisPtr)
+	{
+		return thisPtr->getInternal()->getLayer();
+	}
+
+	void ScriptRenderableHandler::internal_SetLayers(ScriptRenderableHandler* thisPtr, UINT64 layers)
+	{
+		thisPtr->getInternal()->setLayer(layers);
+	}
+
+	void ScriptRenderableHandler::internal_SetMaterial(ScriptRenderableHandler* thisPtr, ScriptMaterial* material, int index)
+	{
+		HMaterial nativeMaterial;
+		if (material != nullptr)
+			nativeMaterial = material->getMaterialHandle();
+
+		thisPtr->getInternal()->setMaterial(index, nativeMaterial);
+	}
+
+	void ScriptRenderableHandler::internal_OnDestroy(ScriptRenderableHandler* thisPtr)
+	{
+		gSceneManager()._unregisterRenderable(thisPtr->getInternal());
+	}
+}

+ 29 - 0
SBansheeEngine/Source/BsScriptResourceManager.cpp

@@ -10,6 +10,7 @@
 #include "BsScriptScriptCode.h"
 #include "BsScriptShader.h"
 #include "BsScriptMaterial.h"
+#include "BsScriptMesh.h"
 #include "BsScriptFont.h"
 #include "BsScriptManagedResource.h"
 #include "BsScriptAssemblyManager.h"
@@ -125,6 +126,27 @@ namespace BansheeEngine
 		return scriptResource;
 	}
 
+	ScriptMesh* ScriptResourceManager::createScriptMesh(const HMesh& resourceHandle)
+	{
+		MonoClass* meshClass = ScriptAssemblyManager::instance().getMeshClass();
+		MonoObject* monoInstance = meshClass->createInstance();
+
+		return createScriptMesh(monoInstance, resourceHandle);
+	}
+
+	ScriptMesh* ScriptResourceManager::createScriptMesh(MonoObject* instance, const HMesh& resourceHandle)
+	{
+		const String& uuid = resourceHandle.getUUID();
+#if BS_DEBUG_MODE
+		throwExceptionIfInvalidOrDuplicate(uuid);
+#endif
+
+		ScriptMesh* scriptResource = new (bs_alloc<ScriptMesh>()) ScriptMesh(instance, resourceHandle);
+		mScriptResources[uuid] = scriptResource;
+
+		return scriptResource;
+	}
+
 	ScriptPlainText* ScriptResourceManager::createScriptPlainText(const HPlainText& resourceHandle)
 	{
 		MonoClass* plainTextClass = ScriptAssemblyManager::instance().getPlainTextClass();
@@ -250,6 +272,11 @@ namespace BansheeEngine
 		return static_cast<ScriptMaterial*>(getScriptResource(resourceHandle.getUUID()));
 	}
 
+	ScriptMesh* ScriptResourceManager::getScriptMesh(const HMesh& resourceHandle)
+	{
+		return static_cast<ScriptMesh*>(getScriptResource(resourceHandle.getUUID()));
+	}
+
 	ScriptPlainText* ScriptResourceManager::getScriptPlainText(const HPlainText& resourceHandle)
 	{
 		return static_cast<ScriptPlainText*>(getScriptResource(resourceHandle.getUUID()));
@@ -311,6 +338,8 @@ namespace BansheeEngine
 			return createScriptShader(static_resource_cast<Shader>(resource));
 		case TID_Material:
 			return createScriptMaterial(static_resource_cast<Material>(resource));
+		case TID_Mesh:
+			return createScriptMesh(static_resource_cast<Mesh>(resource));
 		case TID_ManagedResource:
 			BS_EXCEPT(InternalErrorException, "Managed resources must have a managed instance by default, this call is invalid.")
 				break;

+ 64 - 0
SBansheeEngine/Source/BsScriptVector.cpp

@@ -0,0 +1,64 @@
+#include "BsScriptVector.h"
+#include "BsMonoManager.h"
+#include "BsMonoClass.h"
+#include "BsMonoUtil.h"
+
+namespace BansheeEngine
+{
+	ScriptVector2::ScriptVector2(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptVector2::initRuntimeData()
+	{ }
+
+	MonoObject* ScriptVector2::box(const Vector2& value)
+	{
+		// We're casting away const but it's fine since structs are passed by value anyway
+		return mono_value_box(MonoManager::instance().getDomain(),
+			metaData.scriptClass->_getInternalClass(), (void*)&value);
+	}
+
+	Vector2 ScriptVector2::unbox(MonoObject* obj)
+	{
+		return *(Vector2*)mono_object_unbox(obj);
+	}
+
+	ScriptVector3::ScriptVector3(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptVector3::initRuntimeData()
+	{ }
+
+	MonoObject* ScriptVector3::box(const Vector3& value)
+	{
+		// We're casting away const but it's fine since structs are passed by value anyway
+		return mono_value_box(MonoManager::instance().getDomain(),
+			metaData.scriptClass->_getInternalClass(), (void*)&value);
+	}
+
+	Vector3 ScriptVector3::unbox(MonoObject* obj)
+	{
+		return *(Vector3*)mono_object_unbox(obj);
+	}
+
+	ScriptVector4::ScriptVector4(MonoObject* instance)
+		:ScriptObject(instance)
+	{ }
+
+	void ScriptVector4::initRuntimeData()
+	{ }
+
+	MonoObject* ScriptVector4::box(const Vector4& value)
+	{
+		// We're casting away const but it's fine since structs are passed by value anyway
+		return mono_value_box(MonoManager::instance().getDomain(),
+			metaData.scriptClass->_getInternalClass(), (void*)&value);
+	}
+
+	Vector4 ScriptVector4::unbox(MonoObject* obj)
+	{
+		return *(Vector4*)mono_object_unbox(obj);
+	}
+}

+ 6 - 13
TODO.txt

@@ -22,22 +22,17 @@ TODO - Setting Material array parameters isn't possible from C#
 
 GUIResourceField doesn't distinguish between tex2d, tex3d and texcube.
 
-Add C# Renderable
- - Mesh
- - Material (primary)
- - SetMaterial(i, Material)
- - GetMaterial
- - Bounds Bounds
-
 ----------------------------------------------------------------------
 Project window
 
-Positions in color picker are screwed up
-Depth in COlorPicker is fucked up
-Test dock manager and sliders (right now it doesn't seem to work at all)
+FBXImporter:
+ - It should use DefaultMeshData
+ - It should use and apply MeshImportOptions
+
+TODO:
+ - Implement C# and Script mesh
 
 Simple tasks:
- - Add C# Renderable interface
  - Add C# context menu support for GUI elements
  - Hook up windows drag and drop support
  - Hook up drag and drop internal to project window
@@ -85,13 +80,11 @@ Other simple stuff:
  - C# wrapper for GUISkin (and a way to assign the current skin to a window)
  - Move all the code files into subfolders so their hierarchy is similar to VS filters
  - Font doesn't have a C# interface
- - Material/Shader/Technique/Pass don't have a C# interface
  - Get rid of PoolAlloc and other unused allocators (plus fix bs_new and others which have weird overloads)
  - Call stack from C# to use in Debug.Log calls
  - Get rid of event callback from HString and figure out a better way
  - GUI TextureField similar to ResourceField but it displays the texture it has assigned
  - Better handle and gizmo shaders
- - Fix FBX indexes and while at it also find out how to extract animation data, bone weights and tangent frames
 
 ----------------------------------------------------------------------
 Handles