2
0
Эх сурвалжийг харах

Massive refactor due to work on Renderer

Marko Pintera 11 жил өмнө
parent
commit
4101088f37
97 өөрчлөгдсөн 1751 нэмэгдсэн , 835 устгасан
  1. 9 2
      BansheeCore/BansheeCore.vcxproj
  2. 27 6
      BansheeCore/BansheeCore.vcxproj.filters
  3. 20 0
      BansheeCore/Include/BsCameraProxy.h
  4. 22 0
      BansheeCore/Include/BsCommonTypes.h
  5. 9 0
      BansheeCore/Include/BsCorePrerequisites.h
  6. 1 0
      BansheeCore/Include/BsCoreSceneManager.h
  7. 2 7
      BansheeCore/Include/BsCoreThreadAccessor.h
  8. 29 0
      BansheeCore/Include/BsDrawList.h
  9. 1 1
      BansheeCore/Include/BsIndexBuffer.h
  10. 0 22
      BansheeCore/Include/BsIndexData.h
  11. 4 0
      BansheeCore/Include/BsMaterial.h
  12. 38 0
      BansheeCore/Include/BsMaterialProxy.h
  13. 68 49
      BansheeCore/Include/BsMesh.h
  14. 38 28
      BansheeCore/Include/BsMeshBase.h
  15. 0 5
      BansheeCore/Include/BsMeshBaseRTTI.h
  16. 1 32
      BansheeCore/Include/BsMeshData.h
  17. 11 10
      BansheeCore/Include/BsMeshHeap.h
  18. 12 34
      BansheeCore/Include/BsMeshManager.h
  19. 42 0
      BansheeCore/Include/BsMeshProxy.h
  20. 3 3
      BansheeCore/Include/BsRenderOperation.h
  21. 2 10
      BansheeCore/Include/BsRenderQueue.h
  22. 1 1
      BansheeCore/Include/BsRenderSystem.h
  23. 38 0
      BansheeCore/Include/BsRenderableProxy.h
  24. 2 2
      BansheeCore/Include/BsRenderer.h
  25. 20 0
      BansheeCore/Include/BsSceneObject.h
  26. 20 1
      BansheeCore/Include/BsTransientMesh.h
  27. 4 3
      BansheeCore/Include/BsViewport.h
  28. 1 0
      BansheeCore/Source/BsCameraProxy.cpp
  29. 1 77
      BansheeCore/Source/BsCoreThreadAccessor.cpp
  30. 1 1
      BansheeCore/Source/BsDefaultRenderQueue.cpp
  31. 26 0
      BansheeCore/Source/BsDrawList.cpp
  32. 0 1
      BansheeCore/Source/BsHardwareBufferManager.cpp
  33. 0 18
      BansheeCore/Source/BsIndexData.cpp
  34. 61 0
      BansheeCore/Source/BsMaterial.cpp
  35. 121 82
      BansheeCore/Source/BsMesh.cpp
  36. 9 62
      BansheeCore/Source/BsMeshBase.cpp
  37. 5 6
      BansheeCore/Source/BsMeshData.cpp
  38. 29 19
      BansheeCore/Source/BsMeshHeap.cpp
  39. 12 3
      BansheeCore/Source/BsMeshManager.cpp
  40. 42 0
      BansheeCore/Source/BsMeshProxy.cpp
  41. 1 2
      BansheeCore/Source/BsRenderQueue.cpp
  42. 3 3
      BansheeCore/Source/BsRenderSystem.cpp
  43. 20 0
      BansheeCore/Source/BsRenderableProxy.cpp
  44. 1 1
      BansheeCore/Source/BsRenderer.cpp
  45. 11 1
      BansheeCore/Source/BsSceneObject.cpp
  46. 9 4
      BansheeCore/Source/BsTransientMesh.cpp
  47. 0 1
      BansheeCore/Source/BsVertexData.cpp
  48. 6 12
      BansheeCore/Source/BsViewport.cpp
  49. 0 1
      BansheeD3D11RenderSystem/Include/BsD3D11Mappings.h
  50. 1 1
      BansheeD3D11RenderSystem/Include/BsD3D11RenderSystem.h
  51. 9 12
      BansheeD3D11RenderSystem/Source/BsD3D11RenderSystem.cpp
  52. 1 1
      BansheeD3D9RenderSystem/Include/BsD3D9RenderSystem.h
  53. 11 13
      BansheeD3D9RenderSystem/Source/BsD3D9RenderSystem.cpp
  54. 1 1
      BansheeEditor/Include/BsDockManager.h
  55. 3 3
      BansheeEditor/Source/BsDockManager.cpp
  56. 1 1
      BansheeEditor/Source/BsEditorWindowBase.cpp
  57. 4 2
      BansheeEngine.sln
  58. 3 1
      BansheeEngine/Include/BsBuiltinMaterialManager.h
  59. 3 1
      BansheeEngine/Include/BsCamera.h
  60. 3 0
      BansheeEngine/Include/BsD3D11BuiltinMaterialFactory.h
  61. 3 0
      BansheeEngine/Include/BsD3D9BuiltinMaterialFactory.h
  62. 1 1
      BansheeEngine/Include/BsDrawHelperTemplate.h
  63. 3 0
      BansheeEngine/Include/BsGLBuiltinMaterialFactory.h
  64. 1 1
      BansheeEngine/Include/BsGUIManager.h
  65. 1 1
      BansheeEngine/Include/BsOverlay.h
  66. 1 1
      BansheeEngine/Include/BsOverlayManager.h
  67. 35 8
      BansheeEngine/Include/BsRenderable.h
  68. 4 4
      BansheeEngine/Include/BsRenderableRTTI.h
  69. 11 3
      BansheeEngine/Include/BsSceneManager.h
  70. 7 0
      BansheeEngine/Source/BsBuiltinMaterialManager.cpp
  71. 13 0
      BansheeEngine/Source/BsCamera.cpp
  72. 39 0
      BansheeEngine/Source/BsD3D11BuiltinMaterialFactory.cpp
  73. 39 0
      BansheeEngine/Source/BsD3D9BuiltinMaterialFactory.cpp
  74. 5 5
      BansheeEngine/Source/BsDrawHelperTemplate.cpp
  75. 45 0
      BansheeEngine/Source/BsGLBuiltinMaterialFactory.cpp
  76. 3 3
      BansheeEngine/Source/BsGUIManager.cpp
  77. 1 1
      BansheeEngine/Source/BsGUIWidget.cpp
  78. 2 2
      BansheeEngine/Source/BsOverlayManager.cpp
  79. 3 2
      BansheeEngine/Source/BsProfilerOverlay.cpp
  80. 75 66
      BansheeEngine/Source/BsRenderable.cpp
  81. 7 3
      BansheeFBXImporter/Source/BsFBXImporter.cpp
  82. 1 1
      BansheeGLRenderSystem/Include/BsGLRenderSystem.h
  83. 6 8
      BansheeGLRenderSystem/Source/BsGLRenderSystem.cpp
  84. 40 4
      BansheeRenderer/Include/BsBansheeRenderer.h
  85. 277 101
      BansheeRenderer/Source/BsBansheeRenderer.cpp
  86. 6 7
      BansheeSceneManager/Include/BsBansheeSceneManager.h
  87. 9 29
      BansheeSceneManager/Source/BsBansheeSceneManager.cpp
  88. 2 0
      BansheeUtility/BansheeUtility.vcxproj
  89. 6 0
      BansheeUtility/BansheeUtility.vcxproj.filters
  90. 71 0
      BansheeUtility/Include/BsBounds.h
  91. 17 0
      BansheeUtility/Include/BsSphere.h
  92. 1 1
      BansheeUtility/Include/BsTime.h
  93. 2 0
      BansheeUtility/Include/Win32/BsTimerImp.h
  94. 45 0
      BansheeUtility/Source/BsBounds.cpp
  95. 31 0
      BansheeUtility/Source/BsSphere.cpp
  96. 0 37
      RenderOperation.txt
  97. 115 0
      Renderer.txt

+ 9 - 2
BansheeCore/BansheeCore.vcxproj

@@ -272,6 +272,11 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClInclude Include="Include\BsCameraProxy.h" />
+    <ClInclude Include="Include\BsDrawList.h" />
+    <ClInclude Include="Include\BsMaterialProxy.h" />
+    <ClInclude Include="Include\BsMeshProxy.h" />
+    <ClInclude Include="Include\BsRenderableProxy.h" />
     <ClInclude Include="Include\BsRenderStats.h" />
     <ClInclude Include="Include\BsBindableGpuParamBlock.h" />
     <ClInclude Include="Include\BsBindableGpuParams.h" />
@@ -395,7 +400,6 @@
     <ClInclude Include="Include\BsTextureManager.h" />
     <ClInclude Include="Include\BsTextureRTTI.h" />
     <ClInclude Include="Include\BsSamplerState.h" />
-    <ClInclude Include="Include\BsIndexData.h" />
     <ClInclude Include="Include\BsVertexDataDesc.h" />
     <ClInclude Include="Include\BsVertexDataDescRTTI.h" />
     <ClInclude Include="Include\BsVertexDeclaration.h" />
@@ -419,7 +423,10 @@
   <ItemGroup>
     <ClCompile Include="Source\BsBindableGpuParamBlock.cpp" />
     <ClCompile Include="Source\BsBindableGpuParams.cpp" />
+    <ClCompile Include="Source\BsCameraProxy.cpp" />
     <ClCompile Include="Source\BsCoreThread.cpp" />
+    <ClCompile Include="Source\BsDrawList.cpp" />
+    <ClCompile Include="Source\BsMeshProxy.cpp" />
     <ClCompile Include="Source\BsProfilerCPU.cpp" />
     <ClCompile Include="Source\BsDefaultRenderQueue.cpp" />
     <ClCompile Include="Source\BsDeferredCallManager.cpp" />
@@ -454,7 +461,6 @@
     <ClCompile Include="Source\BsGpuParam.cpp" />
     <ClCompile Include="Source\BsImportOptions.cpp" />
     <ClCompile Include="Source\BsIndexBuffer.cpp" />
-    <ClCompile Include="Source\BsIndexData.cpp" />
     <ClCompile Include="Source\BsMaterialManager.cpp" />
     <ClCompile Include="Source\BsMeshBase.cpp" />
     <ClCompile Include="Source\BsMeshHeap.cpp" />
@@ -469,6 +475,7 @@
     <ClCompile Include="Source\BsPlatform.cpp" />
     <ClCompile Include="Source\BsProfilingManager.cpp" />
     <ClCompile Include="Source\BsQueryManager.cpp" />
+    <ClCompile Include="Source\BsRenderableProxy.cpp" />
     <ClCompile Include="Source\BsRenderer.cpp" />
     <ClCompile Include="Source\BsRenderQueue.cpp" />
     <ClCompile Include="Source\BsResourceManifest.cpp" />

+ 27 - 6
BansheeCore/BansheeCore.vcxproj.filters

@@ -357,9 +357,6 @@
     <ClInclude Include="Include\BsMeshManager.h">
       <Filter>Header Files\RenderSystem</Filter>
     </ClInclude>
-    <ClInclude Include="Include\BsIndexData.h">
-      <Filter>Header Files\RenderSystem</Filter>
-    </ClInclude>
     <ClInclude Include="Include\BsIndexBuffer.h">
       <Filter>Header Files\RenderSystem</Filter>
     </ClInclude>
@@ -519,6 +516,21 @@
     <ClInclude Include="Include\BsProfilingManager.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsRenderableProxy.h">
+      <Filter>Header Files\Renderer</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsCameraProxy.h">
+      <Filter>Header Files\Renderer</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsMaterialProxy.h">
+      <Filter>Header Files\Renderer</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsDrawList.h">
+      <Filter>Header Files\Renderer</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\BsMeshProxy.h">
+      <Filter>Header Files\Renderer</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsCoreApplication.cpp">
@@ -674,9 +686,6 @@
     <ClCompile Include="Source\BsIndexBuffer.cpp">
       <Filter>Source Files\RenderSystem</Filter>
     </ClCompile>
-    <ClCompile Include="Source\BsIndexData.cpp">
-      <Filter>Source Files\RenderSystem</Filter>
-    </ClCompile>
     <ClCompile Include="Source\BsMeshManager.cpp">
       <Filter>Source Files\RenderSystem</Filter>
     </ClCompile>
@@ -821,5 +830,17 @@
     <ClCompile Include="Source\BsProfilingManager.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsRenderableProxy.cpp">
+      <Filter>Source Files\Renderer</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsDrawList.cpp">
+      <Filter>Source Files\Renderer</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsMeshProxy.cpp">
+      <Filter>Source Files\Renderer</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\BsCameraProxy.cpp">
+      <Filter>Source Files\Renderer</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 20 - 0
BansheeCore/Include/BsCameraProxy.h

@@ -0,0 +1,20 @@
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsViewport.h"
+#include "BsMatrix4.h"
+
+namespace BansheeEngine
+{
+	// TODO UNDOCUMENTED
+	class BS_CORE_EXPORT CameraProxy
+	{
+	public:
+		Viewport viewport;
+		Matrix4 viewMatrix;
+		Matrix4 projMatrix;
+		INT32 priority;
+		UINT64 layer;
+		bool ignoreSceneRenderables;
+	};
+}

+ 22 - 0
BansheeCore/Include/BsCommonTypes.h

@@ -297,6 +297,28 @@ namespace BansheeEngine
 		NoOverwrite
 	};
 
+	/**
+	 * @brief	Suggested queue priority numbers used for sorting objects in
+	 *			the render queue. Objects with higher priority will be renderer sooner.
+	 */
+	enum class QueuePriority
+	{
+		Opaque = 100000,
+		Transparent = 90000,
+		Skybox = 80000,
+		Overlay = 70000
+	};
+
+	/**
+	 * @brief	Type of sorting to perform on an object when added to a render queue.
+	 */
+	enum class QueueSortType
+	{
+		FrontToBack, /**< All objects with the same priority will be rendered front to back based on their center. */
+		BackToFront, /**< All objects with the same priority will be rendered back to front based on their center. */
+		None /**< Objects will not be sorted and will be processed in the order they were added to the queue. */
+	};
+
 	/**
 	 * @brief	Texture addressing mode, per component.
 	 */

+ 9 - 0
BansheeCore/Include/BsCorePrerequisites.h

@@ -130,6 +130,12 @@ namespace BansheeEngine
 	class VideoMode;
 	class VideoOutputInfo;
 	class VideoModeInfo;
+	class RenderableProxy;
+	class RenderableSubProxy;
+	class MeshProxy;
+	class CameraProxy;
+	class MaterialProxy;
+	class DrawList;
 	// Asset import
 	class SpecificImporter;
 	class Importer;
@@ -189,6 +195,7 @@ namespace BansheeEngine
 	typedef std::shared_ptr<Pass> PassPtr;
 	typedef std::shared_ptr<Shader> ShaderPtr;
 	typedef std::shared_ptr<Material> MaterialPtr;
+	typedef std::shared_ptr<BindableGpuParams> BindableGpuParamsPtr;
 	typedef std::shared_ptr<Renderer> RendererPtr;
 	typedef std::shared_ptr<RendererFactory> RendererFactoryPtr;
 	typedef std::shared_ptr<PassParameters> PassParametersPtr;
@@ -222,6 +229,8 @@ namespace BansheeEngine
 	typedef std::shared_ptr<OcclusionQuery> OcclusionQueryPtr;
 	typedef std::shared_ptr<ResourceManifest> ResourceManifestPtr;
 	typedef std::shared_ptr<VideoModeInfo> VideoModeInfoPtr;
+	typedef std::shared_ptr<DrawList> DrawListPtr;
+	typedef std::shared_ptr<RenderQueue> RenderQueuePtr;
 }
 
 /************************************************************************/

+ 1 - 0
BansheeCore/Include/BsCoreSceneManager.h

@@ -29,6 +29,7 @@ namespace BansheeEngine
 		 * @note	Internal method.
 		 */
 		virtual void _update();
+
 	protected:
 		friend class SceneObject;
 

+ 2 - 7
BansheeCore/Include/BsCoreThreadAccessor.h

@@ -4,6 +4,7 @@
 #include "BsRenderSystem.h"
 #include "BsCommandQueue.h"
 #include "BsAsyncOp.h"
+#include "BsViewport.h"
 #include "BsColor.h"
 
 namespace BansheeEngine
@@ -38,7 +39,7 @@ namespace BansheeEngine
 		void setDepthStencilState(const DepthStencilStatePtr& depthStencilState, UINT32 stencilRefValue);
 
 		/** @copydoc RenderSystem::setViewport() */
-		void setViewport(const ViewportPtr& vp);
+		void setViewport(Viewport vp);
 
 		/** @copydoc RenderSystem::setDrawOperation() */
 		void setDrawOperation(DrawOperationType op);
@@ -91,12 +92,6 @@ namespace BansheeEngine
 		/** @copydoc RenderSystem::drawIndexed() */
 		void drawIndexed(UINT32 startIndex, UINT32 indexCount, UINT32 vertexOffset, UINT32 vertexCount);
 
-		/**
-		 * @brief	Binds the specified parameters to the pass GPU programs and activates the pass and its
-		 * 			states for any further rendering.
-		 */
-		void setPass(const PassPtr& pass, const PassParametersPtr& params);
-
 		/**
 		 * @copydoc RenderSystem::writeSubresource()
 		 *

+ 29 - 0
BansheeCore/Include/BsDrawList.h

@@ -0,0 +1,29 @@
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsVector3.h"
+
+namespace BansheeEngine
+{
+	// TODO UNDOCUMENTED
+	struct BS_CORE_EXPORT DrawOperation
+	{
+		MaterialPtr material;
+		MeshBasePtr mesh;
+		UINT32 submeshIdx;
+		Vector3 worldPosition;
+	};
+
+	// TODO UNDOCUMENTED
+	class BS_CORE_EXPORT DrawList
+	{
+	public:
+		void add(const MaterialPtr& material, const MeshBasePtr& mesh, UINT32 submeshIdx, const Vector3& worldPosForSort);
+		void clear();
+
+		const Vector<DrawOperation>& getDrawOperations() const;
+
+	protected:
+		Vector<DrawOperation> mDrawOperations;
+	};
+}

+ 1 - 1
BansheeCore/Include/BsIndexBuffer.h

@@ -31,7 +31,7 @@ namespace BansheeEngine
 		/**
 		 * @brief	Returns the number of indices this buffer can hold.
 		 */
-		UINT32 getNumIndexes() const { return mNumIndexes; }
+		UINT32 getNumIndices() const { return mNumIndexes; }
 
 		/**
 		 * @brief	Returns the size of a single index in bytes.

+ 0 - 22
BansheeCore/Include/BsIndexData.h

@@ -1,22 +0,0 @@
-#pragma once
-
-#include "BsCorePrerequisites.h"
-#include "BsIndexBuffer.h"
-
-namespace BansheeEngine 
-{
-	/**
-	 * @brief	Container that holds data about indices in a subset of an index buffer.
-	 */
-	class BS_CORE_EXPORT IndexData
-	{
-    public:
-        IndexData();
-        ~IndexData();
-
-		IndexBufferPtr indexBuffer; /**< Reference to an index buffer to fetch the indices from. */
-
-		UINT32 indexStart; /**< Starting index of the subset. */
-		UINT32 indexCount; /**< Number of indices in the subset. */
-	};
-}

+ 4 - 0
BansheeCore/Include/BsMaterial.h

@@ -2,6 +2,7 @@
 
 #include "BsCorePrerequisites.h"
 #include "BsResource.h"
+#include "BsMaterialProxy.h"
 #include "BsGpuParam.h"
 #include "BsVector2.h"
 #include "BsVector3.h"
@@ -378,6 +379,9 @@ namespace BansheeEngine
 		 */
 		PassParametersPtr getPassParameters(UINT32 passIdx) const;
 
+		// TODO UNDOCUMENTED
+		MaterialProxy _createProxy(FrameAlloc* allocator);
+
 		/**
 		 * @brief	Creates a new empty material.
 		 * 			

+ 38 - 0
BansheeCore/Include/BsMaterialProxy.h

@@ -0,0 +1,38 @@
+#pragma once
+
+#include "BsCorePrerequisites.h"
+
+namespace BansheeEngine
+{
+	// TODO UNDOCUMENTED
+	class BS_CORE_EXPORT MaterialProxy
+	{
+	public:
+		struct PassData
+		{
+			HGpuProgram vertexProg;
+			HGpuProgram fragmentProg;
+			HGpuProgram geometryProg;
+			HGpuProgram hullProg;
+			HGpuProgram domainProg;
+			HGpuProgram computeProg;
+
+			BindableGpuParamsPtr vertexProgParams;
+			BindableGpuParamsPtr fragmentProgParams;
+			BindableGpuParamsPtr geometryProgParams;
+			BindableGpuParamsPtr hullProgParams;
+			BindableGpuParamsPtr domainProgParams;
+			BindableGpuParamsPtr computeProgParams;
+
+			HBlendState blendState;
+			HRasterizerState rasterizerState;
+			HDepthStencilState depthStencilState;
+			UINT32 stencilRefValue;
+		};
+
+		Vector<PassData> passes;
+		bool separablePasses;
+		UINT32 queuePriority;
+		QueueSortType queueSortType;
+	};
+}

+ 68 - 49
BansheeCore/Include/BsMesh.h

@@ -2,11 +2,12 @@
 
 #include "BsCorePrerequisites.h"
 #include "BsMeshBase.h"
+#include "BsMeshProxy.h"
 #include "BsMeshData.h"
 #include "BsVertexData.h"
-#include "BsIndexData.h"
 #include "BsDrawOps.h"
 #include "BsSubMesh.h"
+#include "BsBounds.h"
 
 namespace BansheeEngine
 {
@@ -34,31 +35,16 @@ namespace BansheeEngine
 		 * @brief	Allocates a buffer you may use for storage when reading a subresource. You
 		 * 			need to allocate such a buffer if you are calling "readSubresource".
 		 * 			
+		 * @param	subresourceIdx	Only 0 is supported. You can only update entire mesh at once.
+		 *
 		 * @note	This method is thread safe.
 		 */
 		MeshDataPtr allocateSubresourceBuffer(UINT32 subresourceIdx) const;
 
 		/**
-		 * @brief	TODO - Currently does nothing. But normally it should provide a way to map subresource index to
-		 * 			a specific submesh or buffer stream. Right now you can only work with entire mesh at once, not its subsets.
-		 */
-		void mapFromSubresourceIdx(UINT32 subresourceIdx) const {}
-
-		/**
-		 * @brief	TODO - Currently does nothing. But normally it should provide a way to map submesh or stream index to
-		 * 			a specific subresource index. Right now you can only work with entire mesh at once, not its subsets.
-		 */
-		UINT32 mapToSubresourceIdx() const { return 0; }
-
-		/**
-		 * @brief	Returns an axis aligned bounding box of the geometry contained in the vertex buffers for all submeshes.
-		 */
-		const AABox& getBounds() const;
-
-		/**
-		 * @brief	Returns an axis aligned bounding box of the geometry contained in the specific sub-mesh.
+		 * @brief	Returns bounds of the geometry contained in the vertex buffers for all sub-meshes.
 		 */
-		const AABox& getBounds(UINT32 submeshIdx) const;
+		const Bounds& getBounds() const { return mBounds; }
 
 		/**
 		 * @copydoc MeshBase::getVertexData
@@ -68,7 +54,12 @@ namespace BansheeEngine
 		/**
 		 * @copydoc MeshBase::getIndexData
 		 */
-		virtual std::shared_ptr<IndexData> _getIndexData() const;
+		virtual IndexBufferPtr _getIndexBuffer() const;
+
+		/**
+		 * @copydoc	MeshBase::_getMeshProxy
+		 */
+		MeshProxy& _getMeshProxy(UINT32 subMeshIdx) { return mMeshProxies[subMeshIdx]; }
 
 		/**
 		 * @brief	Returns a dummy mesh, containing just one triangle. Don't modify the returned mesh.
@@ -78,19 +69,24 @@ namespace BansheeEngine
 	protected:
 		friend class MeshManager;
 
-		Mesh(UINT32 numVertices, UINT32 numIndices, 
-			const VertexDataDescPtr& vertexDesc, MeshBufferType bufferType = MeshBufferType::Static, 
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
+		Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
+			MeshBufferType bufferType = MeshBufferType::Static, DrawOperationType drawOp = DOT_TRIANGLE_LIST,
+			IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 
-		Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, const MeshDataPtr& initialMeshData, 
-			MeshBufferType bufferType = MeshBufferType::Static, DrawOperationType drawOp = DOT_TRIANGLE_LIST, 
+		Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc,
+			const Vector<SubMesh>& subMeshes, MeshBufferType bufferType = MeshBufferType::Static,
 			IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 
-		Mesh(const MeshDataPtr& initialMeshData, 
-			MeshBufferType bufferType = MeshBufferType::Static, DrawOperationType drawOp = DOT_TRIANGLE_LIST);
+		Mesh(const MeshDataPtr& initialMeshData, MeshBufferType bufferType = MeshBufferType::Static, 
+			DrawOperationType drawOp = DOT_TRIANGLE_LIST);
+
+		Mesh(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes, MeshBufferType bufferType = MeshBufferType::Static);
 
 		std::shared_ptr<VertexData> mVertexData; // Core thread
-		std::shared_ptr<IndexData> mIndexData; // Core thread
+		IndexBufferPtr mIndexBuffer; // Core thread
+
+		Bounds mBounds; // Core thread
+		Vector<MeshProxy> mMeshProxies; // Core thread
 
 		VertexDataDescPtr mVertexDesc; // Immutable
 		MeshBufferType mBufferType; // Immutable
@@ -108,6 +104,15 @@ namespace BansheeEngine
 		 */
 		virtual void destroy_internal();
 
+		/**
+		 * @brief	Calculates bounds surrounding the vertices in the provided buffer.
+		 *
+		 * @param	verticesPtr	Pointer to the buffer containing the positions of vertices to calculate bounds for.
+		 * @param	numVertices	Number of vertices in the provided buffer.
+		 * @param	stride		How many bytes are needed to advance from one vertex to another.
+		 */
+		Bounds calculateBounds(UINT8* verticesPtr, UINT32 numVertices, UINT32 stride) const;
+
 		/************************************************************************/
 		/* 								SERIALIZATION                      		*/
 		/************************************************************************/
@@ -125,7 +130,7 @@ namespace BansheeEngine
 		
 	public:
 		/**
-		 * @brief	Creates a new empty mesh.
+		 * @brief	Creates a new empty mesh. Created mesh will have no sub-meshes.
 		 *
 		 * @param	numVertices		Number of vertices in the mesh.
 		 * @param	numIndices		Number of indices in the mesh. 
@@ -139,36 +144,30 @@ namespace BansheeEngine
 		 * @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, MeshBufferType bufferType = MeshBufferType::Static,
 			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 
 		/**
-		 * @brief	Creates a new mesh and immediately writes some data to the mesh. This is faster than writing
-		 *			the data in a separate step after creation.
+		 * @brief	Creates a new empty mesh. Created mesh will have specified sub-meshes you may render independently.
 		 *
 		 * @param	numVertices		Number of vertices in the mesh.
 		 * @param	numIndices		Number of indices in the mesh. 
 		 * @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	initialMeshData	Vertex and index data used for initializing the mesh. Caller must ensure the data vertex and index buffers
-		 *							match the ones in the mesh, however the data might only write to a certain subset of the mesh, it does not
-		 *							have to write to all of it.
+		 * @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	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, const MeshDataPtr& initialMeshData, 
-			MeshBufferType bufferType = MeshBufferType::Static, DrawOperationType drawOp = DOT_TRIANGLE_LIST, 
-			IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
+		static HMesh create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, const Vector<SubMesh>& subMeshes,
+			MeshBufferType bufferType = MeshBufferType::Static, IndexBuffer::IndexType indexType = IndexBuffer::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.
+		 *			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
@@ -179,30 +178,50 @@ namespace BansheeEngine
 		static HMesh create(const MeshDataPtr& initialMeshData, MeshBufferType bufferType = MeshBufferType::Static, 
 			DrawOperationType drawOp = DOT_TRIANGLE_LIST);
 
+		/**
+		 * @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 specified sub-meshes you may render independently.
+		 *
+		 * @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.
+		 */
+		static HMesh create(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes, MeshBufferType bufferType = MeshBufferType::Static);
+
 		/**
 		 * @copydoc	create(UINT32, UINT32, const VertexDataDescPtr&, MeshBufferType, DrawOperationType, IndexBuffer::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, MeshBufferType bufferType = MeshBufferType::Static,
 			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 
 		/**
-		 * @copydoc	create(UINT32, UINT32, const VertexDataDescPtr&, const MeshDataPtr&, MeshBufferType, DrawOperationType, IndexBuffer::IndexType)
+		 * @copydoc	create(UINT32, UINT32, const VertexDataDescPtr&, const Vector<SubMesh>&, MeshBufferType, IndexBuffer::IndexType)
 		 *
 		 * @note	Internal method. Use "create" for normal use.
 		 */
-		static MeshPtr _createPtr(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, const MeshDataPtr& initialMeshData, 
-			MeshBufferType bufferType = MeshBufferType::Static, DrawOperationType drawOp = DOT_TRIANGLE_LIST, 
-			IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
+		static MeshPtr _createPtr(UINT32 numVertices, UINT32 numIndices, 
+			const VertexDataDescPtr& vertexDesc, const Vector<SubMesh>& subMeshes,
+			MeshBufferType bufferType = MeshBufferType::Static, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 
 		/**
 		 * @copydoc	create(const MeshDataPtr&, MeshBufferType, 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, MeshBufferType bufferType = MeshBufferType::Static,
 			DrawOperationType drawOp = DOT_TRIANGLE_LIST);
+
+		/**
+		 * @copydoc	create(const MeshDataPtr&, const Vector<SubMesh>&, MeshBufferType)
+		 *
+		 * @note	Internal method. Use "create" for normal use.
+		 */
+		static MeshPtr _createPtr(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes,
+			MeshBufferType bufferType = MeshBufferType::Static);
 	};
 }

+ 38 - 28
BansheeCore/Include/BsMeshBase.h

@@ -22,60 +22,62 @@ namespace BansheeEngine
 	 * @brief	Base class all mesh implementations derive from. Meshes hold geometry information,
 	 *			normally in the form of one or serveral index or vertex buffers. Different mesh implementations
 	 *			might choose to manage those buffers differently.
+	 *
+	 * @note	Core thread only unless noted otherwise.
 	 */
 	class BS_CORE_EXPORT MeshBase : public GpuResource
 	{
 	public:
 		/**
-		 * @brief	Constructs a new instance.
+		 * @brief	Constructs a new mesh with no sub-meshes.
+		 *
 		 * @param	numVertices		Number of vertices in the mesh.
 		 * @param	numIndices		Number of indices in 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.
 		 */
 		MeshBase(UINT32 numVertices, UINT32 numIndices, DrawOperationType drawOp = DOT_TRIANGLE_LIST);
-		virtual ~MeshBase();
-
-		/**
-		 * @brief	Removes all sub-meshes in the mesh. All indices in the mesh will be assumed to
-		 *			belong to a single mesh.
-		 *
-		 * @note	Sim thread only.
-		 */
-		void clearSubMeshes();
 
 		/**
-		 * @brief	Allows you to mark a part of the mesh as a sub-mesh so you may draw that part separately.
+		 * @brief	Constructs a new mesh with one or multiple sub-meshes. (When using just one sub-mesh it is equivalent
+		 *			to using the other overload).
 		 *
-		 * @note	Sim thread only.
+		 * @param	numVertices		Number of vertices in the mesh.
+		 * @param	numIndices		Number of indices in the mesh.
+		 * @param	subMeshes		Defines how are indices separated into sub-meshes, and how are those sub-meshes rendered.
 		 */
-		void addSubMesh(UINT32 indexOffset, UINT32 indexCount, DrawOperationType drawOp = DOT_TRIANGLE_LIST);
+		MeshBase(UINT32 numVertices, UINT32 numIndices, const Vector<SubMesh>& subMeshes);
 
-		/**
-		 * @brief	Sets a set of sub-meshes containing data used for rendering a 
-		 * 			certain portion of this mesh. Overwrites any previous sub-meshes.
-		 * 			
-		 * @note	Sim thread only.
-		 */
-		void setSubMeshes(const Vector<SubMesh>& subMeshes);
+		virtual ~MeshBase();
 
 		/**
 		 * @brief	Retrieves a sub-mesh containing data used for rendering a
 		 * 			certain portion of this mesh. If no sub-meshes are specified manually
 		 *			a special sub-mesh containing all indices is returned.
-		 * 			
-		 * @note	Sim thread only.
+		 *
+		 * @note	Thread safe.
 		 */
 		const SubMesh& getSubMesh(UINT32 subMeshIdx = 0) const;
 
 		/**
 		 * @brief	Retrieves a total number of sub-meshes in this mesh.
-		 * 			
-		 * @note	Sim thread only.
+		 *
+		 * @note	Thread safe.
 		 */
 		UINT32 getNumSubMeshes() const;
 
+		/**
+		 * @brief	Returns maximum number of vertices the mesh may store.
+		 *
+		 * @note	Thread safe.
+		 */
 		UINT32 getNumVertices() const { return mNumVertices; }
+
+		/**
+		 * @brief	Returns maximum number of indices the mesh may store.
+		 *
+		 * @note	Thread safe.
+		 */
 		UINT32 getNumIndices() const { return mNumIndices; }
 
 		/**
@@ -90,7 +92,7 @@ namespace BansheeEngine
 		 *  
 		 * @note	Core thread only. Internal method.
 		 */
-		virtual std::shared_ptr<IndexData> _getIndexData() const = 0;
+		virtual IndexBufferPtr _getIndexBuffer() const = 0;
 
 		/**
 		 * @brief	Returns an offset into the vertex buffers that is returned
@@ -124,10 +126,18 @@ namespace BansheeEngine
 		 */
 		virtual void _notifyUsedOnGPU() { }
 
-	protected:
-		Vector<SubMesh> mSubMeshes; // Sim thread
-		SubMesh mDefaultSubMesh; // Immutable
+		/************************************************************************/
+		/* 								PROXIES		                     		*/
+		/************************************************************************/
 
+		/**
+		 * @brief	Gets mesh proxy object unique to this mesh. Each Mesh
+		 *			has one proxy. Mesh will update the proxy as changes to Mesh occur.
+		 */
+		virtual MeshProxy& _getMeshProxy(UINT32 subMeshIdx) = 0;
+
+	protected:
+		Vector<SubMesh> mSubMeshes; // Immutable
 		UINT32 mNumVertices; // Immutable
 		UINT32 mNumIndices; // Immutable
 

+ 0 - 5
BansheeCore/Include/BsMeshBaseRTTI.h

@@ -17,9 +17,6 @@ namespace BansheeEngine
 		UINT32 getNumSubmeshes(MeshBase* obj) { return (UINT32)obj->mSubMeshes.size(); }
 		void setNumSubmeshes(MeshBase* obj, UINT32 numElements) { obj->mSubMeshes.resize(numElements); }
 
-		SubMesh& getDefaultSubMesh(MeshBase* obj) { return obj->mDefaultSubMesh; }
-		void setDefaultSubMesh(MeshBase* obj, SubMesh& value) { obj->mDefaultSubMesh = value; }
-
 		UINT32& getNumVertices(MeshBase* obj) { return obj->mNumVertices; }
 		void setNumVertices(MeshBase* obj, UINT32& value) { obj->mNumVertices = value; }
 
@@ -34,8 +31,6 @@ namespace BansheeEngine
 
 			addPlainArrayField("mSubMeshes", 2, &MeshBaseRTTI::getSubMesh, 
 				&MeshBaseRTTI::getNumSubmeshes, &MeshBaseRTTI::setSubMesh, &MeshBaseRTTI::setNumSubmeshes);
-
-			addPlainField("mDefaultSubMesh", 3, &MeshBaseRTTI::getDefaultSubMesh, &MeshBaseRTTI::setDefaultSubMesh);
 		}
 
 		virtual std::shared_ptr<IReflectable> newRTTIObject() 

+ 1 - 32
BansheeCore/Include/BsMeshData.h

@@ -7,6 +7,7 @@
 #include "BsVertexDeclaration.h"
 #include "BsDrawOps.h"
 #include "BsSubMesh.h"
+#include "BsBounds.h"
 
 namespace BansheeEngine
 {
@@ -99,35 +100,6 @@ namespace BansheeEngine
 		MeshData(UINT32 numVertices, UINT32 numIndexes, const VertexDataDescPtr& vertexData, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 		~MeshData();
 
-		/**
-		 * @brief	Determines at which position in the mesh will the vertex data be written into or read from.
-		 *
-		 * @param	bytes	Offset in number of vertices.
-		 */
-		void setResourceVertexOffset(UINT32 vertices) { mResourceVertexOffset = vertices; }
-
-		/**
-		 * @brief	Determines at which position in the mesh will the index data be written into or read from.
-		 *
-		 * @param	bytes	Offset in number of indices.
-		 */
-		void setResourceIndexOffset(UINT32 indices) { mResourceIndexOffset = indices; }
-
-		/**
-		 * @brief	Determines at which position in the mesh will the vertex data be written into or read
-		 * 			from.
-		 *
-		 * @return	Offset in number of vertices.
-		 */
-		UINT32 getResourceVertexOffset() const { return mResourceVertexOffset; }
-
-		/**
-		 * @brief	Determines at which position in the mesh will the index data be written into or read from.
-		 *
-		 * @return	Offset in number of indices.
-		 */
-		UINT32 getResourceIndexOffset() const { return mResourceIndexOffset; }
-
 		/**
 		 * @brief	Copies data from "data" parameter into the internal buffer for the specified semantic.
 		 *
@@ -307,9 +279,6 @@ namespace BansheeEngine
 
 		UINT8* mData;
 
-		UINT32 mResourceVertexOffset;
-		UINT32 mResourceIndexOffset;
-
 		UINT32 mNumVertices;
 		UINT32 mNumIndices;
 		IndexBuffer::IndexType mIndexType;

+ 11 - 10
BansheeCore/Include/BsMeshHeap.h

@@ -2,8 +2,8 @@
 
 #include "BsCorePrerequisites.h"
 #include "BsCoreObject.h"
-#include "BsIndexData.h"
 #include "BsDrawOps.h"
+#include "BsIndexBuffer.h"
 
 namespace BansheeEngine
 {
@@ -54,6 +54,7 @@ namespace BansheeEngine
 
 			UseFlags useFlags;
 			UINT32 eventQueryIdx;
+			TransientMeshPtr mesh;
 		};
 
 		/**
@@ -104,32 +105,32 @@ namespace BansheeEngine
 			const VertexDataDescPtr& vertexDesc, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 
 		/**
-		 * @copydoc Resource::initialize_internal()
+		 * @copydoc CoreObject::initialize_internal()
 		 */
 		virtual void initialize_internal();
 
 		/**
-		 * @copydoc Resource::destroy_internal()
+		 * @copydoc CoreObject::destroy_internal()
 		 */
 		virtual void destroy_internal();
 
 		/**
 		 * @brief	Allocates a new mesh in the heap, expanding the heap if needed. 
 		 *
-		 * @param	meshId		Unique mesh ID.
+		 * @param	meshId		Mesh for which we are allocating the data.
 		 * @param	meshData	Data to initialize the new mesh with.
 		 *
 		 * @note	Core thread.
 		 */
-		void allocInternal(UINT32 meshId, const MeshDataPtr& meshData);
+		void allocInternal(TransientMeshPtr mesh, const MeshDataPtr& meshData);
 
 		/**
-		 * @brief	Deallocates the mesh with the provided ID. Freed memory
+		 * @brief	Deallocates the provided mesh Freed memory
 		 *			will be re-used as soon as the GPU is done with the mesh
 		 *
 		 * @note	Core thread.
 		 */
-		void deallocInternal(UINT32 meshId);
+		void deallocInternal(TransientMeshPtr mesh);
 
 		/**
 		 * @brief	Resizes the vertex buffers so they max contain the provided
@@ -166,12 +167,12 @@ namespace BansheeEngine
 		/**
 		 * @brief	Gets internal vertex data for all the meshes.
 		 */
-		std::shared_ptr<VertexData> getVertexData() const;
+		std::shared_ptr<VertexData> _getVertexData() const;
 
 		/**
 		 * @brief	Gets internal index data for all the meshes.
 		 */
-		std::shared_ptr<IndexData> getIndexData() const;
+		IndexBufferPtr _getIndexBuffer() const;
 
 		/**
 		 * @brief	Returns the offset in vertices from the start of the buffer
@@ -210,7 +211,7 @@ namespace BansheeEngine
 		UINT32 mNumIndices; // Core thread
 
 		std::shared_ptr<VertexData> mVertexData; // Core thread
-		std::shared_ptr<IndexData> mIndexData; // Core thread
+		IndexBufferPtr mIndexBuffer; // Core thread
 
 		Vector<UINT8*> mCPUVertexData; // Core thread
 		UINT8* mCPUIndexData; // Core thread

+ 12 - 34
BansheeCore/Include/BsMeshManager.h

@@ -16,48 +16,26 @@ namespace BansheeEngine
 		~MeshManager();
 
 		/**
-		 * @brief	Creates an empty mesh with enough space to store vertex and index data described by the parameters.
-		 *
-		 * @param	numVertices	Number of vertices in the mesh.
-		 * @param	numIndices	Number of indices in the mesh.
-		 * @param	vertexDesc	Vertex description that describes how are vertices organized within the vertex buffer(s).
-		 * @param	bufferType	Type of buffers to use to store mesh vertex and index data. Specify dynamic if you plan on
-		 *						updating the mesh often, or static otherwise.
-		 * @param	drawOp		Informs the render system on how to draw the mesh. Determines how are indices and vertices interpreted.
-		 * @param	indexType	Type of indexes in the index buffer. Determines size of an index.
+		 * @copydoc	Mesh::create(UINT32, UINT32, const VertexDataDescPtr&, MeshBufferType, DrawOperationType, IndexBuffer::IndexType)
 		 */
 		MeshPtr create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, MeshBufferType bufferType = MeshBufferType::Static, 
-			 DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
+			DrawOperationType drawOp = DOT_TRIANGLE_LIST, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 
 		/**
-		 * @brief	Creates an mesh with enough space to store vertex and index data described by the parameters, and initializes
-		 *			a portion (or entire) mesh with some data.
-		 *
-		 * @param	numVertices	Number of vertices in the mesh.
-		 * @param	numIndices	Number of indices in the mesh.
-		 * @param	vertexDesc	Vertex description that describes how are vertices organized within the vertex buffer(s).
-		 * @param	initialData	Initial data to initialize the mesh with. Internal offsets in this object will be used to
-		 *						determine where to write the data in the Mesh buffers.
-		 * @param	bufferType	Type of buffers to use to store mesh vertex and index data. Specify dynamic if you plan on
-		 *						updating the mesh often, or static otherwise.
-		 * @param	drawOp		Informs the render system on how to draw the mesh. Determines how are indices and vertices interpreted.
-		 * @param	indexType	Type of indexes in the index buffer. Determines size of an index.
+		 * @copydoc	Mesh::create(UINT32, UINT32, const VertexDataDescPtr&, const Vector<SubMesh>&, MeshBufferType, IndexBuffer::IndexType)
 		 */
-		MeshPtr create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, const MeshDataPtr& initialData, 
-			MeshBufferType bufferType = MeshBufferType::Static, DrawOperationType drawOp = DOT_TRIANGLE_LIST, 
-			IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
+		MeshPtr create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, const Vector<SubMesh>& subMeshes, 
+			MeshBufferType bufferType = MeshBufferType::Static, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
 
 		/**
-		 * @brief	Creates a mesh and initializes it with the provided data. Mesh will be of exact size needed to hold the data.
-		 *
-		 * @param	initialData	Initial data to initialize the mesh with. Size of the buffers and vertex declaration will be taken
-		 *						from this object.
-		 * @param	bufferType	Type of buffers to use to store mesh vertex and index data. Specify dynamic if you plan on
-		 *						updating the mesh often, or static otherwise.
-		 * @param	drawOp		Informs the render system on how to draw the mesh. Determines how are indices and vertices interpreted.
+		 * @copyodc	Mesh::create(const MeshDataPtr&, MeshBufferType, DrawOperationType)
 		 */
-		MeshPtr create(const MeshDataPtr& initialData, MeshBufferType bufferType = MeshBufferType::Static,
-			DrawOperationType drawOp = DOT_TRIANGLE_LIST);
+		MeshPtr create(const MeshDataPtr& initialData, MeshBufferType bufferType = MeshBufferType::Static, DrawOperationType drawOp = DOT_TRIANGLE_LIST);
+
+		/**
+		 * @copyodc	Mesh::create(const MeshDataPtr&, const Vector<SubMesh>&, MeshBufferType)
+		 */
+		MeshPtr create(const MeshDataPtr& initialData, const Vector<SubMesh>& subMeshes, MeshBufferType bufferType = MeshBufferType::Static);
 
 		/**
 		 * @brief	Creates a new empty and uninitialized mesh. You will need to manually initialize the mesh before using it.

+ 42 - 0
BansheeCore/Include/BsMeshProxy.h

@@ -0,0 +1,42 @@
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsBounds.h"
+#include "BsSubMesh.h"
+
+namespace BansheeEngine
+{
+	/**
+	* Mesh proxy keeps a copy of Mesh data that is used by the Renderer. It
+	* also contains some Renderer specific data. Essentially it is a class that
+	* links Mesh and Renderer.
+	*/
+	// TODO UNDOCUMENTED
+	class BS_CORE_EXPORT MeshProxy
+	{
+	public:
+		MeshProxy() {}
+		MeshProxy(const std::shared_ptr<VertexData>& vertexData, const IndexBufferPtr& indexBuffer,
+			const SubMesh& subMesh);
+
+		void addRenderableProxy(RenderableSubProxy* proxy);
+		void removeRenderableProxy(RenderableSubProxy* proxy);
+
+		void updateBounds(const Bounds& bounds);
+		Bounds getBounds() const { return mBounds; }
+
+		void updateData(const std::shared_ptr<VertexData>& vertexData, const IndexBufferPtr& indexBuffer, const SubMesh& subMesh);
+
+		std::shared_ptr<VertexData> getVertexData() const { return mVertexData; }
+		IndexBufferPtr getIndexBuffer() const { return mIndexBuffer; }
+		SubMesh getSubMesh() const { return mSubMesh; }
+
+	private:
+		std::shared_ptr<VertexData> mVertexData;
+		IndexBufferPtr mIndexBuffer;
+		SubMesh mSubMesh;
+
+		Vector<RenderableSubProxy*> mRenderableProxies;
+		Bounds mBounds;
+	};
+}

+ 3 - 3
BansheeCore/Include/BsRenderOperation.h

@@ -1,6 +1,7 @@
 #pragma once
 
 #include "BsCorePrerequisites.h"
+#include "BsMaterialProxy.h"
 #include "BsDrawOps.h"
 #include "BsVector3.h"
 
@@ -15,9 +16,8 @@ namespace BansheeEngine
 		RenderOperation()
 		{ }
 
-		MaterialPtr material;
-		MeshBasePtr mesh;
-		UINT32 submeshIdx;
+		MaterialProxy material;
+		MeshProxy* mesh;
 		Vector3 worldPosition;
 	};
 }

+ 2 - 10
BansheeCore/Include/BsRenderQueue.h

@@ -26,21 +26,13 @@ namespace BansheeEngine
 	 *			You need to provide your own implementation of the render queue sorting method. Likely the sorting method
 	 *			will need to be closely tied to the renderer used.
 	 */
+	// TODO UNDOCUMENTED
 	class BS_CORE_EXPORT RenderQueue
 	{
 	public:
 		RenderQueue();
 
-		/**
-		 * @brief	Adds a new render operation to the rendering queue. These operations will be sorted
-		 * 			and rendered by the Renderer in sorted order.
-		 *
-		 * @param	material	   	The material to use for rendering the object.
-		 * @param	mesh		   	The mesh to render.
-		 * @param	submeshIdx	   	Sub-mesh index in "mesh" to render.
-		 * @param	worldPosForSort	The world position used for sorting.
-		 */
-		void add(const MaterialPtr& material, const MeshBasePtr& mesh, UINT32 submeshIdx, const Vector3& worldPosForSort);
+		void add(const MaterialProxy& material, MeshProxy* mesh, const Vector3& worldPosForSort);
 
 		/**
 		 * @brief	Clears all render operations from the queue.

+ 1 - 1
BansheeCore/Include/BsRenderSystem.h

@@ -105,7 +105,7 @@ namespace BansheeEngine
 		 * @brief	Sets the active viewport that will be used for all render operations.
 		 *			Viewport will change active render target if needed.
 		 */
-		virtual void setViewport(const ViewportPtr& vp) = 0;
+		virtual void setViewport(Viewport vp) = 0;
 
 		/**
 		 * @brief	Sets the provided vertex buffers starting at the specified source index.

+ 38 - 0
BansheeCore/Include/BsRenderableProxy.h

@@ -0,0 +1,38 @@
+#pragma once
+
+#include "BsCorePrerequisites.h"
+#include "BsMaterialProxy.h"
+#include "BsBounds.h"
+#include "BsMatrix4.h"
+
+namespace BansheeEngine
+{
+	// TODO UNDOCUMENTED
+	class BS_CORE_EXPORT RenderableSubProxy
+	{
+	public:
+		RenderableSubProxy();
+
+		void markBoundsDirty() { mBoundsDirty = true; }
+		void markBoundsClean() { mBoundsDirty = false; }
+		bool getBoundsDirty() const { return mBoundsDirty; }
+		Bounds calculateWorldBounds();
+
+		UINT32 id;
+		Matrix4 worldTransform;
+
+		MeshProxy* mesh;
+		MaterialProxy material;
+
+		UINT64 layer;
+
+	private:
+		bool mBoundsDirty;
+	};
+
+	class BS_CORE_EXPORT RenderableProxy
+	{
+	public:
+		Vector<RenderableSubProxy*> subProxies;
+	};
+}

+ 2 - 2
BansheeCore/Include/BsRenderer.h

@@ -32,9 +32,9 @@ namespace BansheeEngine
 		 * 			will be called before rendering and you will be able to populate the
 		 * 			render queue with render commands that will be executed when rendering.
 		 */
-		void addRenderCallback(const Viewport* viewport, std::function<void(const Viewport*, RenderQueue&)> callback);
+		void addRenderCallback(const Viewport* viewport, std::function<void(const Viewport*, DrawList&)> callback);
 
 	protected:
-		UnorderedMap<const Viewport*, Vector<std::function<void(const Viewport*, RenderQueue&)>>> mRenderCallbacks;
+		UnorderedMap<const Viewport*, Vector<std::function<void(const Viewport*, DrawList&)>>> mRenderCallbacks;
 	};
 }

+ 20 - 0
BansheeCore/Include/BsSceneObject.h

@@ -187,6 +187,24 @@ namespace BansheeEngine
 		 */
 		void pitch(const Radian& angle);
 
+		/**
+		 * @brief	Forces any dirty transform matrices on this object to be updated.
+		 *
+		 * @note	Normally this is done internally when retrieving a transform, but sometimes
+		 *			it is useful to update transforms manually.
+		 */
+		void updateTransformsIfDirty();
+
+		/**
+		 * @brief	Called by the renderer to check if the transform changed in any way.
+		 */
+		bool _isRenderDataUpToDate() const { return mIsRenderDataUpToDate; }
+
+		/**
+		 * @brief	Called by the renderer to notify the scene object that render data has been updated.
+		 */
+		void _markRenderDataUpToDate() { mIsRenderDataUpToDate = true; }
+
 	private:
 		Vector3 mPosition;
 		Quaternion mRotation;
@@ -202,6 +220,8 @@ namespace BansheeEngine
 		mutable Matrix4 mCachedWorldTfrm;
 		mutable bool mIsCachedWorldTfrmUpToDate;
 
+		mutable bool mIsRenderDataUpToDate;
+
 		/**
 		 * @brief	Marks the transform as dirty so that we know to update
 		 *			it when the transform is requested.

+ 20 - 1
BansheeCore/Include/BsTransientMesh.h

@@ -2,6 +2,7 @@
 
 #include "BsCorePrerequisites.h"
 #include "BsMeshBase.h"
+#include "BsMeshProxy.h"
 
 namespace BansheeEngine
 {
@@ -38,7 +39,17 @@ namespace BansheeEngine
 		 /**
 		 * @copydoc MeshBase::getIndexData
 		 */
-		std::shared_ptr<IndexData> _getIndexData() const;
+		IndexBufferPtr _getIndexBuffer() const;
+
+		/**
+		 * @copydoc	MeshBase::_getMeshProxy
+		 */
+		MeshProxy& _getMeshProxy(UINT32 subMeshIdx) { return mMeshProxy; }
+
+		/**
+		 * @brief	Returns the ID that uniquely identifies this mesh in the parent heap.
+		 */
+		UINT32 getMeshHeapId() const { return mId; }
 
 		/**
 		 * @copydoc MeshBase::getVertexOffset
@@ -55,6 +66,12 @@ namespace BansheeEngine
 		 */
 		virtual void _notifyUsedOnGPU();
 
+		/**
+		 * @brief	Called by parent MeshHeap when notable changes that invalidate
+		 *			the mesh proxy happen.
+		 */
+		void _updateProxy();
+
 	protected:
 		friend class MeshHeap;
 
@@ -75,5 +92,7 @@ namespace BansheeEngine
 		bool mIsDestroyed;
 		MeshHeapPtr mParentHeap;
 		UINT32 mId;
+
+		MeshProxy mMeshProxy;
 	};
 }

+ 4 - 3
BansheeCore/Include/BsViewport.h

@@ -101,7 +101,10 @@ namespace BansheeEngine
 		bool getRequiresStencilClear() const { return mRequiresStencilClear; }
 		void setRequiresStencilClear(bool requiresClear) { mRequiresStencilClear = requiresClear; }
 
-		Event<void()> onResized;
+		/**
+		 * @brief	Makes an exact copy of this viewport.
+		 */
+		Viewport clone();
     protected:
         RenderTargetPtr mTarget;
 
@@ -116,8 +119,6 @@ namespace BansheeEngine
 		float mDepthClearValue;
 		UINT16 mStencilClearValue;
 
-		HEvent mTargetResizedConn;
-
 		static const Color DEFAULT_CLEAR_COLOR;
 
         void updateArea();

+ 1 - 0
BansheeCore/Source/BsCameraProxy.cpp

@@ -0,0 +1 @@
+#include "BsCameraProxy.h"

+ 1 - 77
BansheeCore/Source/BsCoreThreadAccessor.cpp

@@ -54,7 +54,7 @@ namespace BansheeEngine
 		mCommandQueue->queue(std::bind(&RenderSystem::setDepthStencilState, RenderSystem::instancePtr(), depthStencilState, stencilRefValue));
 	}
 
-	void CoreThreadAccessorBase::setViewport(const ViewportPtr& vp)
+	void CoreThreadAccessorBase::setViewport(Viewport vp)
 	{
 		mCommandQueue->queue(std::bind(&RenderSystem::setViewport, RenderSystem::instancePtr(), vp));
 	}
@@ -144,82 +144,6 @@ namespace BansheeEngine
 		mCommandQueue->queue(std::bind(&RenderSystem::drawIndexed, RenderSystem::instancePtr(), startIndex, indexCount, vertexOffset, vertexCount));
 	}
 
-	void CoreThreadAccessorBase::setPass(const PassPtr& pass, const PassParametersPtr& params)
-	{
-		HGpuProgram vertProgram = pass->getVertexProgram();
-		if(vertProgram)
-			bindGpuProgram(vertProgram);
-		else
-			unbindGpuProgram(GPT_VERTEX_PROGRAM);
-
-		HGpuProgram fragProgram = pass->getFragmentProgram();
-		if(fragProgram)
-			bindGpuProgram(fragProgram);
-		else
-			unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
-
-		HGpuProgram geomProgram = pass->getGeometryProgram();
-		if(geomProgram)
-			bindGpuProgram(geomProgram);
-		else
-			unbindGpuProgram(GPT_GEOMETRY_PROGRAM);
-
-		HGpuProgram hullProgram = pass->getHullProgram();
-		if(hullProgram)
-			bindGpuProgram(hullProgram);
-		else
-			unbindGpuProgram(GPT_HULL_PROGRAM);
-
-		HGpuProgram domainProgram = pass->getDomainProgram();
-		if(domainProgram)
-			bindGpuProgram(domainProgram);
-		else
-			unbindGpuProgram(GPT_DOMAIN_PROGRAM);
-
-		// TODO - Try to limit amount of state changes, if previous state is already the same (especially with textures)
-
-		// TODO: Disable remaining texture units
-		//renderSystem->_disableTextureUnitsFrom(pass->getNumTextures());
-
-		// Set up non-texture related pass settings
-		HBlendState blendState = pass->getBlendState();
-		if(blendState != nullptr)
-			setBlendState(blendState.getInternalPtr());
-		else
-			setBlendState(BlendState::getDefault());
-
-		HDepthStencilState depthStancilState = pass->getDepthStencilState();
-		if(depthStancilState != nullptr)
-			setDepthStencilState(depthStancilState.getInternalPtr(), pass->getStencilRefValue());
-		else
-			setDepthStencilState(DepthStencilState::getDefault(), pass->getStencilRefValue());
-
-		HRasterizerState rasterizerState = pass->getRasterizerState();
-		if(rasterizerState != nullptr)
-			setRasterizerState(rasterizerState.getInternalPtr());
-		else
-			setRasterizerState(RasterizerState::getDefault());
-
-		if(vertProgram)
-			bindGpuParams(GPT_VERTEX_PROGRAM, params->mVertParams);
-
-		if(fragProgram)
-			bindGpuParams(GPT_FRAGMENT_PROGRAM, params->mFragParams);
-
-		if(geomProgram)
-			bindGpuParams(GPT_GEOMETRY_PROGRAM, params->mGeomParams);
-
-		if(hullProgram)
-			bindGpuParams(GPT_HULL_PROGRAM, params->mHullParams);
-
-		if(domainProgram)
-			bindGpuParams(GPT_DOMAIN_PROGRAM, params->mDomainParams);
-
-		HGpuProgram computeProgram = pass->getComputeProgram();
-		if(computeProgram)
-			bindGpuParams(GPT_COMPUTE_PROGRAM, params->mComputeParams);
-	}
-
 	AsyncOp CoreThreadAccessorBase::writeSubresource(GpuResourcePtr resource, UINT32 subresourceIdx, const GpuResourceDataPtr& data, bool discardEntireBuffer)
 	{
 		data->_lock();

+ 1 - 1
BansheeCore/Source/BsDefaultRenderQueue.cpp

@@ -9,7 +9,7 @@ namespace BansheeEngine
 		// Just pass-through for now
 		for(auto& renderOp : mRenderOperations)
 		{
-			UINT32 numPasses = renderOp.material->getNumPasses();
+			UINT32 numPasses = (UINT32)renderOp.material.passes.size();
 			for(UINT32 i = 0; i < numPasses; i++)
 			{
 				mSortedRenderOps.push_back(SortedRenderOp());

+ 26 - 0
BansheeCore/Source/BsDrawList.cpp

@@ -0,0 +1,26 @@
+#include "BsDrawList.h"
+
+namespace BansheeEngine
+{
+	void DrawList::clear()
+	{
+		mDrawOperations.clear();
+	}
+
+	void DrawList::add(const MaterialPtr& material, const MeshBasePtr& mesh, UINT32 submeshIdx, const Vector3& worldPosForSort)
+	{
+		// TODO - Make sure RenderOperations are cached so we dont allocate memory for them every frame
+		mDrawOperations.push_back(DrawOperation());
+
+		DrawOperation& renderOp = mDrawOperations.back();
+		renderOp.material = material;
+		renderOp.mesh = mesh;
+		renderOp.worldPosition = worldPosForSort;
+		renderOp.submeshIdx = submeshIdx;
+	}
+
+	const Vector<DrawOperation>& DrawList::getDrawOperations() const
+	{
+		return mDrawOperations;
+	}
+}

+ 0 - 1
BansheeCore/Source/BsHardwareBufferManager.cpp

@@ -1,6 +1,5 @@
 #include "BsHardwareBufferManager.h"
 #include "BsVertexData.h"
-#include "BsIndexData.h"
 #include "BsGpuBuffer.h"
 #include "BsVertexDeclaration.h"
 #include "BsGpuParamBlockBuffer.h"

+ 0 - 18
BansheeCore/Source/BsIndexData.cpp

@@ -1,18 +0,0 @@
-#include "BsIndexData.h"
-#include "BsHardwareBufferManager.h"
-#include "BsVertexBuffer.h"
-#include "BsIndexBuffer.h"
-#include "BsVector3.h"
-#include "BsAABox.h"
-#include "BsException.h"
-#include "BsRenderSystem.h"
-
-namespace BansheeEngine 
-{
-	IndexData::IndexData()
-		:indexCount(0), indexStart(0)
-	{ }
-
-	IndexData::~IndexData()
-	{ }
-}

+ 61 - 0
BansheeCore/Source/BsMaterial.cpp

@@ -10,6 +10,7 @@
 #include "BsGpuParamDesc.h"
 #include "BsMaterialRTTI.h"
 #include "BsMaterialManager.h"
+#include "BsBindableGpuParams.h"
 #include "BsDebug.h"
 #include "BsResources.h"
 
@@ -697,6 +698,66 @@ namespace BansheeEngine
 		BS_EXCEPT(InternalErrorException, "Shader has no parameter with the name: " + name);
 	}
 
+	MaterialProxy Material::_createProxy(FrameAlloc* allocator)
+	{
+		throwIfNotInitialized();
+
+		MaterialProxy proxy;
+
+		UINT32 numPasses = mShader->getBestTechnique()->getNumPasses();
+		for (UINT32 i = 0; i < numPasses; i++)
+		{
+			PassParametersPtr params = mParametersPerPass[i];
+			PassPtr pass = mShader->getBestTechnique()->getPass(i);
+
+			proxy.passes.push_back(MaterialProxy::PassData());
+			MaterialProxy::PassData& passData = proxy.passes.back();
+
+			if (pass->hasVertexProgram())
+			{
+				passData.vertexProg = pass->getVertexProgram();
+				passData.vertexProgParams = bs_shared_ptr<BindableGpuParams>(params->mVertParams, allocator);
+			}
+
+			if (pass->hasFragmentProgram())
+			{
+				passData.fragmentProg = pass->getFragmentProgram();
+				passData.fragmentProgParams = bs_shared_ptr<BindableGpuParams>(params->mFragParams, allocator);
+			}
+
+			if (pass->hasGeometryProgram())
+			{
+				passData.geometryProg = pass->getGeometryProgram();
+				passData.geometryProgParams = bs_shared_ptr<BindableGpuParams>(params->mGeomParams, allocator);
+			}
+
+			if (pass->hasHullProgram())
+			{
+				passData.hullProg = pass->getHullProgram();
+				passData.hullProgParams = bs_shared_ptr<BindableGpuParams>(params->mHullParams, allocator);
+			}
+
+			if (pass->hasDomainProgram())
+			{
+				passData.domainProg = pass->getDomainProgram();
+				passData.domainProgParams = bs_shared_ptr<BindableGpuParams>(params->mDomainParams, allocator);
+			}
+
+			if (pass->hasComputeProgram())
+			{
+				passData.computeProg = pass->getComputeProgram();
+				passData.computeProgParams = bs_shared_ptr<BindableGpuParams>(params->mComputeParams, allocator);
+			}
+
+			passData.blendState = pass->getBlendState();
+			passData.rasterizerState = pass->getRasterizerState();
+			passData.depthStencilState = pass->getDepthStencilState();
+			passData.stencilRefValue = pass->getStencilRefValue();
+		}
+
+		return proxy;
+	}
+
 	void Material::destroy_internal()
 	{
 		freeParamBuffers();

+ 121 - 82
BansheeCore/Source/BsMesh.cpp

@@ -16,31 +16,38 @@ namespace BansheeEngine
 {
 	Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
 		MeshBufferType bufferType, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
-		:MeshBase(numVertices, numIndices, drawOp), mVertexData(nullptr), mIndexData(nullptr),
+		:MeshBase(numVertices, numIndices, drawOp), mVertexData(nullptr), mIndexBuffer(nullptr),
 		mVertexDesc(vertexDesc), mBufferType(bufferType), mIndexType(indexType)
 	{
 
 	}
 
-	Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
-		const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
-		:MeshBase(numVertices, numIndices, drawOp), mVertexData(nullptr), mIndexData(nullptr),
-		mVertexDesc(vertexDesc), mBufferType(bufferType), mIndexType(indexType), 
-		mTempInitialMeshData(initialMeshData)
+	Mesh::Mesh(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc,
+		const Vector<SubMesh>& subMeshes, MeshBufferType bufferType, IndexBuffer::IndexType indexType)
+		:MeshBase(numVertices, numIndices, subMeshes), mVertexData(nullptr), mIndexBuffer(nullptr),
+		mVertexDesc(vertexDesc), mBufferType(bufferType), mIndexType(indexType)
 	{
 
 	}
 
 	Mesh::Mesh(const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp)
 		:MeshBase(initialMeshData->getNumVertices(), initialMeshData->getNumIndices(), drawOp), 
-		mVertexData(nullptr), mIndexData(nullptr), mIndexType(initialMeshData->getIndexType()),
+		mVertexData(nullptr), mIndexBuffer(nullptr), mIndexType(initialMeshData->getIndexType()),
+		mVertexDesc(initialMeshData->getVertexDesc()), mTempInitialMeshData(initialMeshData)
+	{
+
+	}
+
+	Mesh::Mesh(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes, MeshBufferType bufferType)
+		:MeshBase(initialMeshData->getNumVertices(), initialMeshData->getNumIndices(), subMeshes),
+		mVertexData(nullptr), mIndexBuffer(nullptr), mIndexType(initialMeshData->getIndexType()),
 		mVertexDesc(initialMeshData->getVertexDesc()), mTempInitialMeshData(initialMeshData)
 	{
 
 	}
 
 	Mesh::Mesh()
-		:MeshBase(0, 0, DOT_TRIANGLE_LIST), mVertexData(nullptr), mIndexData(nullptr), 
+		:MeshBase(0, 0, DOT_TRIANGLE_LIST), mVertexData(nullptr), mIndexBuffer(nullptr), 
 		mBufferType(MeshBufferType::Static), mIndexType(IndexBuffer::IT_32BIT)
 	{
 
@@ -48,6 +55,7 @@ namespace BansheeEngine
 
 	Mesh::~Mesh()
 	{
+
 	}
 
 	void Mesh::writeSubresource(UINT32 subresourceIdx, const GpuResourceData& data, bool discardEntireBuffer)
@@ -57,9 +65,11 @@ namespace BansheeEngine
 		if(data.getTypeId() != TID_MeshData)
 			BS_EXCEPT(InvalidParametersException, "Invalid GpuResourceData type. Only MeshData is supported.");
 
-		if(discardEntireBuffer)
+		const MeshData& meshData = static_cast<const MeshData&>(data);
+
+		if (discardEntireBuffer)
 		{
-			if(mBufferType == MeshBufferType::Static)
+			if (mBufferType == MeshBufferType::Static)
 			{
 				LOGWRN("Buffer discard is enabled but buffer was not created as dynamic. Disabling discard.");
 				discardEntireBuffer = false;
@@ -67,71 +77,67 @@ namespace BansheeEngine
 		}
 		else
 		{
-			if(mBufferType == MeshBufferType::Dynamic)
+			if (mBufferType == MeshBufferType::Dynamic)
 			{
 				LOGWRN("Buffer discard is not enabled but buffer was created as dynamic. Enabling discard.");
 				discardEntireBuffer = true;
 			}
 		}
 
-		const MeshData& meshData = static_cast<const MeshData&>(data);
-
 		// Indices
-		UINT32 indexOffset = meshData.getResourceIndexOffset() * meshData.getIndexElementSize();
 		UINT32 indicesSize = meshData.getIndexBufferSize();
-		UINT8* srcIdxData = meshData.getIndexData(); 
+		UINT8* srcIdxData = meshData.getIndexData();
 
-		if(meshData.getIndexElementSize() != mIndexData->indexBuffer->getIndexSize())
+		if (meshData.getIndexElementSize() != mIndexBuffer->getIndexSize())
 		{
-			BS_EXCEPT(InvalidParametersException, "Provided index size doesn't match meshes index size. Needed: " + 
-				toString(mIndexData->indexBuffer->getIndexSize()) + ". Got: " + toString(meshData.getIndexElementSize()));
+			BS_EXCEPT(InvalidParametersException, "Provided index size doesn't match meshes index size. Needed: " +
+				toString(mIndexBuffer->getIndexSize()) + ". Got: " + toString(meshData.getIndexElementSize()));
 		}
 
-		if((indexOffset + indicesSize) > mIndexData->indexBuffer->getSizeInBytes())
+		if (indicesSize > mIndexBuffer->getSizeInBytes())
 			BS_EXCEPT(InvalidParametersException, "Index buffer values are being written out of valid range.");
 
-		mIndexData->indexBuffer->writeData(indexOffset, indicesSize, srcIdxData, discardEntireBuffer ? BufferWriteType::Discard : BufferWriteType::Normal);
+		mIndexBuffer->writeData(0, indicesSize, srcIdxData, discardEntireBuffer ? BufferWriteType::Discard : BufferWriteType::Normal);
 
 		// Vertices
-		for(UINT32 i = 0; i <= mVertexDesc->getMaxStreamIdx(); i++)
+		for (UINT32 i = 0; i <= mVertexDesc->getMaxStreamIdx(); i++)
 		{
-			if(!mVertexDesc->hasStream(i))
+			if (!mVertexDesc->hasStream(i))
 				continue;
 
-			if(!meshData.getVertexDesc()->hasStream(i))
+			if (!meshData.getVertexDesc()->hasStream(i))
 				continue;
 
 			// Ensure both have the same sized vertices
 			UINT32 myVertSize = mVertexDesc->getVertexStride(i);
 			UINT32 otherVertSize = meshData.getVertexDesc()->getVertexStride(i);
-			if(myVertSize != otherVertSize)
+			if (myVertSize != otherVertSize)
 			{
-				BS_EXCEPT(InvalidParametersException, "Provided vertex size for stream " + toString(i) + " doesn't match meshes vertex size. Needed: " + 
+				BS_EXCEPT(InvalidParametersException, "Provided vertex size for stream " + toString(i) + " doesn't match meshes vertex size. Needed: " +
 					toString(myVertSize) + ". Got: " + toString(otherVertSize));
 			}
 
 			VertexBufferPtr vertexBuffer = mVertexData->getBuffer(i);
 
-			UINT32 bufferOffset = meshData.getResourceVertexOffset() * meshData.getVertexDesc()->getVertexStride(i);
 			UINT32 bufferSize = meshData.getStreamSize(i);
 			UINT8* srcVertBufferData = meshData.getStreamData(i);
 
-			if((bufferOffset + bufferSize) > vertexBuffer->getSizeInBytes())
+			if (bufferSize > vertexBuffer->getSizeInBytes())
 				BS_EXCEPT(InvalidParametersException, "Vertex buffer values for stream \"" + toString(i) + "\" are being written out of valid range.");
 
-			if(vertexBuffer->vertexColorReqRGBFlip())
+			if (vertexBuffer->vertexColorReqRGBFlip())
 			{
 				UINT8* bufferCopy = (UINT8*)bs_alloc(bufferSize);
 				memcpy(bufferCopy, srcVertBufferData, bufferSize); // TODO Low priority - Attempt to avoid this copy
 
 				UINT32 vertexStride = meshData.getVertexDesc()->getVertexStride(i);
-				for(INT32 semanticIdx = 0; semanticIdx < VertexBuffer::MAX_SEMANTIC_IDX; semanticIdx++)
+				for (INT32 semanticIdx = 0; semanticIdx < VertexBuffer::MAX_SEMANTIC_IDX; semanticIdx++)
 				{
-					if(!meshData.getVertexDesc()->hasElement(VES_COLOR, semanticIdx, i))
+					if (!meshData.getVertexDesc()->hasElement(VES_COLOR, semanticIdx, i))
 						continue;
 
 					UINT8* colorData = bufferCopy + mVertexDesc->getElementOffsetFromStream(VES_COLOR, semanticIdx, i);
-					for(UINT32 j = 0; j < mVertexData->vertexCount; j++)
+					for (UINT32 j = 0; j < mVertexData->vertexCount; j++)
 					{
 						UINT32* curColor = (UINT32*)colorData;
 
@@ -141,15 +147,35 @@ namespace BansheeEngine
 					}
 				}
 
-				vertexBuffer->writeData(bufferOffset, bufferSize, bufferCopy, discardEntireBuffer ? BufferWriteType::Discard : BufferWriteType::Normal);
+				vertexBuffer->writeData(0, bufferSize, bufferCopy, discardEntireBuffer ? BufferWriteType::Discard : BufferWriteType::Normal);
 
 				bs_free(bufferCopy);
 			}
 			else
 			{
-				vertexBuffer->writeData(bufferOffset, bufferSize, srcVertBufferData, discardEntireBuffer ? BufferWriteType::Discard : BufferWriteType::Normal);
+				vertexBuffer->writeData(0, bufferSize, srcVertBufferData, discardEntireBuffer ? BufferWriteType::Discard : BufferWriteType::Normal);
 			}
 		}
+
+		// Update bounds
+		VertexDataDescPtr vertexDesc = meshData.getVertexDesc();
+		for (UINT32 i = 0; i < vertexDesc->getNumElements(); i++)
+		{
+			const VertexElement& curElement = vertexDesc->getElement(i);
+
+			if (curElement.getSemantic() != VES_POSITION || (curElement.getType() != VET_FLOAT3 && curElement.getType() != VET_FLOAT4))
+				continue;
+
+			UINT8* data = meshData.getElementData(curElement.getSemantic(), curElement.getSemanticIdx(), curElement.getStreamIdx());
+			UINT32 stride = vertexDesc->getVertexStride(curElement.getStreamIdx());
+
+			mBounds = calculateBounds((UINT8*)data, mTempInitialMeshData->getNumVertices(), stride);
+
+			for (auto& proxy : mMeshProxies)
+				proxy.updateBounds(mBounds);
+
+			break;
+		}
 	}
 
 	void Mesh::readSubresource(UINT32 subresourceIdx, GpuResourceData& data)
@@ -160,22 +186,21 @@ namespace BansheeEngine
 			BS_EXCEPT(InvalidParametersException, "Invalid GpuResourceData type. Only MeshData is supported.");
 
 		IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT;
-		if(mIndexData)
-			indexType = mIndexData->indexBuffer->getType();
+		if(mIndexBuffer)
+			indexType = mIndexBuffer->getType();
 
 		MeshData& meshData = static_cast<MeshData&>(data);
 
-		if(mIndexData)
+		if(mIndexBuffer)
 		{
-			if(meshData.getIndexElementSize() != mIndexData->indexBuffer->getIndexSize())
+			if(meshData.getIndexElementSize() != mIndexBuffer->getIndexSize())
 			{
 				BS_EXCEPT(InvalidParametersException, "Provided index size doesn't match meshes index size. Needed: " + 
-					toString(mIndexData->indexBuffer->getIndexSize()) + ". Got: " + toString(meshData.getIndexElementSize()));
+					toString(mIndexBuffer->getIndexSize()) + ". Got: " + toString(meshData.getIndexElementSize()));
 			}
 
-			UINT8* idxData = static_cast<UINT8*>(mIndexData->indexBuffer->lock(GBL_READ_ONLY));
-			UINT32 idxElemSize = mIndexData->indexBuffer->getIndexSize();
-			UINT32 indexResourceOffset = meshData.getResourceIndexOffset();
+			UINT8* idxData = static_cast<UINT8*>(mIndexBuffer->lock(GBL_READ_ONLY));
+			UINT32 idxElemSize = mIndexBuffer->getIndexSize();
 
 			UINT8* indices = nullptr;
 
@@ -184,17 +209,15 @@ namespace BansheeEngine
 			else
 				indices = (UINT8*)meshData.getIndices32();
 
-			UINT32 remainingNumIndices = (UINT32)std::max(0, (INT32)(mNumIndices - indexResourceOffset));
-			UINT32 numIndicesToCopy = std::min(remainingNumIndices, meshData.getNumIndices());
+			UINT32 numIndicesToCopy = std::min(mNumIndices, meshData.getNumIndices());
 
 			UINT32 indicesSize = numIndicesToCopy * idxElemSize;
 			if(indicesSize > meshData.getIndexBufferSize())
 				BS_EXCEPT(InvalidParametersException, "Provided buffer doesn't have enough space to store mesh indices.");
 
-			idxData += indexResourceOffset * idxElemSize;
 			memcpy(indices, idxData, numIndicesToCopy * idxElemSize);
 
-			mIndexData->indexBuffer->unlock();
+			mIndexBuffer->unlock();
 		}
 
 		if(mVertexData)
@@ -216,18 +239,15 @@ namespace BansheeEngine
 						toString(myVertSize) + ". Got: " + toString(otherVertSize));
 				}
 
-				UINT32 vertexResourceOffset = meshData.getResourceVertexOffset();
-				UINT32 bufferOffset = vertexResourceOffset * meshData.getVertexDesc()->getVertexStride(streamIdx);
-
 				UINT32 numVerticesToCopy = meshData.getNumVertices();
 
 				VertexBufferPtr vertexBuffer = iter->second;
 				UINT32 bufferSize = vertexBuffer->getVertexSize() * numVerticesToCopy;
 				
-				if((bufferOffset + bufferSize) > vertexBuffer->getSizeInBytes())
+				if(bufferSize > vertexBuffer->getSizeInBytes())
 					BS_EXCEPT(InvalidParametersException, "Vertex buffer values for stream \"" + toString(streamIdx) + "\" are being read out of valid range.");
 
-				UINT8* vertDataPtr = static_cast<UINT8*>(vertexBuffer->lock(GBL_READ_ONLY)) + vertexResourceOffset * meshData.getVertexDesc()->getVertexStride(streamIdx);
+				UINT8* vertDataPtr = static_cast<UINT8*>(vertexBuffer->lock(GBL_READ_ONLY));
 
 				UINT8* dest = meshData.getStreamData(streamIdx);
 				memcpy(dest, vertDataPtr, bufferSize);
@@ -242,26 +262,14 @@ namespace BansheeEngine
 	MeshDataPtr Mesh::allocateSubresourceBuffer(UINT32 subresourceIdx) const
 	{
 		IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT;
-		if(mIndexData)
-			indexType = mIndexData->indexBuffer->getType();
+		if(mIndexBuffer)
+			indexType = mIndexBuffer->getType();
 
 		MeshDataPtr meshData = bs_shared_ptr<MeshData>(mVertexData->vertexCount, mNumIndices, mVertexDesc, indexType);
 
 		return meshData;
 	}
 
-	const AABox& Mesh::getBounds() const
-	{
-		// TODO - Retrieve bounds for entire mesh (need to calculate them during creation)
-		return AABox::BOX_EMPTY;
-	}
-
-	const AABox& Mesh::getBounds(UINT32 submeshIdx) const
-	{
-		// TODO - Retrieve bounds a specific sub-mesh (need to calculate them during creation)
-		return AABox::BOX_EMPTY;
-	}
-
 	std::shared_ptr<VertexData> Mesh::_getVertexData() const
 	{
 		THROW_IF_NOT_CORE_THREAD;
@@ -269,24 +277,19 @@ namespace BansheeEngine
 		return mVertexData;
 	}
 
-	std::shared_ptr<IndexData> Mesh::_getIndexData() const
+	IndexBufferPtr Mesh::_getIndexBuffer() const
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
-		return mIndexData;
+		return mIndexBuffer;
 	}
 
 	void Mesh::initialize_internal()
 	{
 		THROW_IF_NOT_CORE_THREAD;
 		
-		mIndexData = std::shared_ptr<IndexData>(bs_new<IndexData, PoolAlloc>());
-
-		mIndexData->indexCount = mNumIndices;
-		mIndexData->indexBuffer = HardwareBufferManager::instance().createIndexBuffer(
-			mIndexType,
-			mIndexData->indexCount, 
-			mBufferType == MeshBufferType::Dynamic ? GBU_DYNAMIC : GBU_STATIC);
+		mIndexBuffer = HardwareBufferManager::instance().createIndexBuffer(mIndexType,
+			mNumIndices, mBufferType == MeshBufferType::Dynamic ? GBU_DYNAMIC : GBU_STATIC);
 
 		mVertexData = std::shared_ptr<VertexData>(bs_new<VertexData, PoolAlloc>());
 
@@ -311,10 +314,15 @@ namespace BansheeEngine
 		if(mTempInitialMeshData != nullptr)
 		{
 			writeSubresource(0, *mTempInitialMeshData, mBufferType == MeshBufferType::Dynamic);
-
 			mTempInitialMeshData = nullptr;
 		}
 
+		for (auto& subMesh : mSubMeshes)
+		{
+			mMeshProxies.push_back(MeshProxy(mVertexData, mIndexBuffer, subMesh));
+
+		}
+
 		Resource::initialize_internal();
 	}
 
@@ -325,6 +333,27 @@ namespace BansheeEngine
 		Resource::destroy_internal();
 	}
 
+	Bounds Mesh::calculateBounds(UINT8* verticesPtr, UINT32 numVertices, UINT32 stride) const
+	{
+		Bounds bounds;
+
+		if (mNumVertices > 0)
+		{
+			Vector3 curPosition = *(Vector3*)verticesPtr;
+			Sphere initialSphere(curPosition, 0.0f);
+			AABox initialBox(curPosition, curPosition);
+
+			bounds.setBounds(initialBox, initialSphere);
+			for (UINT32 i = 1; i < mNumVertices; i++)
+			{
+				Vector3 curPosition = *(Vector3*)(verticesPtr + stride * i);
+				bounds.merge(curPosition);
+			}
+		}
+
+		return bounds;
+	}
+
 	HMesh Mesh::dummy()
 	{
 		return MeshManager::instance().getDummyMesh();
@@ -356,11 +385,10 @@ namespace BansheeEngine
 		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
 	}
 
-	HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
-		const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
+	HMesh Mesh::create(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc,
+		const Vector<SubMesh>& subMeshes, MeshBufferType bufferType, IndexBuffer::IndexType indexType)
 	{
-		MeshPtr meshPtr = _createPtr(numVertices, numIndices, vertexDesc, 
-			initialMeshData, bufferType, drawOp, indexType);
+		MeshPtr meshPtr = _createPtr(numVertices, numIndices, vertexDesc, subMeshes, bufferType, indexType);
 
 		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
 	}
@@ -372,21 +400,32 @@ namespace BansheeEngine
 		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
 	}
 
+	HMesh Mesh::create(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes, MeshBufferType bufferType)
+	{
+		MeshPtr meshPtr = _createPtr(initialMeshData, subMeshes, bufferType);
+
+		return static_resource_cast<Mesh>(gResources()._createResourceHandle(meshPtr));
+	}
+
 	MeshPtr Mesh::_createPtr(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
 		MeshBufferType bufferType, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
 	{
 		return MeshManager::instance().create(numVertices, numIndices, vertexDesc, bufferType, drawOp, indexType);
 	}
 
-	MeshPtr Mesh::_createPtr(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc, 
-		const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp, IndexBuffer::IndexType indexType)
+	MeshPtr Mesh::_createPtr(UINT32 numVertices, UINT32 numIndices, const VertexDataDescPtr& vertexDesc,
+		const Vector<SubMesh>& subMeshes, MeshBufferType bufferType, IndexBuffer::IndexType indexType)
 	{
-		return MeshManager::instance().create(numVertices, numIndices, vertexDesc, 
-			initialMeshData, bufferType, drawOp, indexType);
+		return MeshManager::instance().create(numVertices, numIndices, vertexDesc, subMeshes, bufferType, indexType);
 	}
 
 	MeshPtr Mesh::_createPtr(const MeshDataPtr& initialMeshData, MeshBufferType bufferType, DrawOperationType drawOp)
 	{
 		return MeshManager::instance().create(initialMeshData, bufferType, drawOp);
 	}
+
+	MeshPtr Mesh::_createPtr(const MeshDataPtr& initialMeshData, const Vector<SubMesh>& subMeshes, MeshBufferType bufferType)
+	{
+		return MeshManager::instance().create(initialMeshData, subMeshes, bufferType);
+	}
 }

+ 9 - 62
BansheeCore/Source/BsMeshBase.cpp

@@ -6,72 +6,29 @@
 namespace BansheeEngine
 {
 	MeshBase::MeshBase(UINT32 numVertices, UINT32 numIndices, DrawOperationType drawOp)
-		:mNumIndices(numIndices), mNumVertices(numVertices), mDefaultSubMesh(0, numIndices, drawOp)
+		:mNumIndices(numIndices), mNumVertices(numVertices)
 	{
-		mSubMeshes.reserve(10);
+		mSubMeshes.push_back(SubMesh(0, numIndices, drawOp));
 	}
 
-	MeshBase::MeshBase()
+	MeshBase::MeshBase(UINT32 numVertices, UINT32 numIndices, const Vector<SubMesh>& subMeshes)
+		: mNumIndices(numIndices), mNumVertices(numVertices)
 	{
-		mSubMeshes.reserve(10);
-	}
-
-	MeshBase::~MeshBase()
-	{
-
-	}
-
-	void MeshBase::clearSubMeshes()
-	{
-		THROW_IF_CORE_THREAD;
-
-		mSubMeshes.clear();
+		mSubMeshes = subMeshes;
 	}
 
-	void MeshBase::addSubMesh(UINT32 indexOffset, UINT32 indexCount, DrawOperationType drawOp)
+	MeshBase::MeshBase()
 	{
-		THROW_IF_CORE_THREAD;
-
-		if((indexOffset + indexCount) > mNumIndices)
-		{
-			LOGWRN("Provided sub-mesh references indexes out of range. Sub-mesh range: " 
-				+ toString(indexOffset) + " .. " + toString(indexOffset + indexCount) + "." \
-				"Valid range is: 0 .. " + toString(mNumIndices) + ". Ignoring command.");
-
-			return;
-		}
-
-		mSubMeshes.push_back(SubMesh(indexOffset, indexCount, drawOp));
+		mSubMeshes.reserve(10);
 	}
 
-	void MeshBase::setSubMeshes(const Vector<SubMesh>& subMeshes)
+	MeshBase::~MeshBase()
 	{
-		THROW_IF_CORE_THREAD;
-
-		for(auto& subMesh : subMeshes)
-		{
-			if((subMesh.indexOffset + subMesh.indexCount) > mNumIndices)
-			{
-				LOGWRN("Provided sub-mesh references indexes out of range. Sub-mesh range: " 
-					+ toString(subMesh.indexOffset) + " .. " + toString(subMesh.indexOffset + subMesh.indexCount) + "." \
-					"Valid range is: 0 .. " + toString(mNumIndices) + ". Ignoring command.");
-
-				return;
-			}
-		}
 
-		mSubMeshes = subMeshes;
 	}
 
 	const SubMesh& MeshBase::getSubMesh(UINT32 subMeshIdx) const
 	{
-		THROW_IF_CORE_THREAD;
-
-		if(mSubMeshes.size() == 0 && subMeshIdx == 0)
-		{
-			return mDefaultSubMesh;
-		}
-
 		if(subMeshIdx < 0 || subMeshIdx >= mSubMeshes.size())
 		{
 			BS_EXCEPT(InvalidParametersException, "Invalid sub-mesh index (" 
@@ -83,17 +40,7 @@ namespace BansheeEngine
 
 	UINT32 MeshBase::getNumSubMeshes() const
 	{
-		THROW_IF_CORE_THREAD;
-
-		if(mSubMeshes.size() > 0)
-			return (UINT32)mSubMeshes.size();
-		else
-		{
-			if(mDefaultSubMesh.indexCount > 0)
-				return 1;
-			else
-				return 0;
-		}
+		return (UINT32)mSubMeshes.size();
 	}
 
 	/************************************************************************/

+ 5 - 6
BansheeCore/Source/BsMeshData.cpp

@@ -1,6 +1,8 @@
 #include "BsMeshData.h"
 #include "BsVector2.h"
 #include "BsVector3.h"
+#include "BsSphere.h"
+#include "BsAABox.h"
 #include "BsHardwareBufferManager.h"
 #include "BsMeshDataRTTI.h"
 #include "BsVertexDeclaration.h"
@@ -10,15 +12,13 @@
 namespace BansheeEngine
 {
 	MeshData::MeshData(UINT32 numVertices, UINT32 numIndexes, const VertexDataDescPtr& vertexData, IndexBuffer::IndexType indexType)
-	   :mNumVertices(numVertices), mNumIndices(numIndexes), mVertexData(vertexData), mIndexType(indexType), mData(nullptr), mResourceIndexOffset(0),
-	   mResourceVertexOffset(0)
+	   :mNumVertices(numVertices), mNumIndices(numIndexes), mVertexData(vertexData), mIndexType(indexType), mData(nullptr)
 	{
 		allocateInternalBuffer();
 	}
 
 	MeshData::MeshData()
-		:mNumVertices(0), mNumIndices(0), mIndexType(IndexBuffer::IT_32BIT), mData(nullptr), 
-		mResourceIndexOffset(0), mResourceVertexOffset(0)
+		:mNumVertices(0), mNumIndices(0), mIndexType(IndexBuffer::IT_32BIT), mData(nullptr)
 	{ }
 
 	MeshData::~MeshData()
@@ -55,7 +55,6 @@ namespace BansheeEngine
 	}
 
 	// TODO - This doesn't handle the case where multiple elements in same slot have different data types
-	//  - actually it will likely corrupt memory in that case
 	MeshDataPtr MeshData::combine(const Vector<MeshDataPtr>& meshes, const Vector<Vector<SubMesh>>& allSubMeshes, 
 		Vector<SubMesh>& subMeshes)
 	{
@@ -86,7 +85,7 @@ namespace BansheeEngine
 					{
 						if(newElement.getType() != existingElement.getType())
 						{
-							BS_EXCEPT(NotImplementedException, "Two elements have same semantics but different types. This is not supported yet.");
+							BS_EXCEPT(NotImplementedException, "Two elements have same semantics but different types. This is not supported.");
 						}
 
 						alreadyExistsIdx = idx;

+ 29 - 19
BansheeCore/Source/BsMeshHeap.cpp

@@ -4,7 +4,6 @@
 #include "BsHardwareBufferManager.h"
 #include "BsVertexDataDesc.h"
 #include "BsVertexData.h"
-#include "BsIndexData.h"
 #include "BsMeshData.h"
 #include "BsMath.h"
 #include "BsEventQuery.h"
@@ -76,7 +75,7 @@ namespace BansheeEngine
 
 		mMeshes[meshIdx] = transientMeshPtr;
 
-		queueGpuCommand(getThisPtr(), std::bind(&MeshHeap::allocInternal, this, meshIdx, meshData));
+		queueGpuCommand(getThisPtr(), std::bind(&MeshHeap::allocInternal, this, transientMeshPtr, meshData));
 
 		return transientMeshPtr;
 	}
@@ -90,15 +89,16 @@ namespace BansheeEngine
 		mesh->markAsDestroyed();
 		mMeshes.erase(iterFind);
 
-		queueGpuCommand(getThisPtr(), std::bind(&MeshHeap::deallocInternal, this, mesh->mId));
+		queueGpuCommand(getThisPtr(), std::bind(&MeshHeap::deallocInternal, this, mesh));
 	}
 
-	void MeshHeap::allocInternal(UINT32 meshId, const MeshDataPtr& meshData)
+	void MeshHeap::allocInternal(TransientMeshPtr mesh, const MeshDataPtr& meshData)
 	{
 		// Find free vertex chunk and grow if needed
 		UINT32 smallestVertFit = 0;
 		UINT32 smallestVertFitIdx = 0;
 
+		bool buffersModified = false;
 		while(smallestVertFit == 0)
 		{
 			UINT32 curIdx = 0;
@@ -125,6 +125,7 @@ namespace BansheeEngine
 			}
 
 			growVertexBuffer(newNumVertices);
+			buffersModified = true;
 		}
 
 		// Find free index chunk and grow if needed
@@ -157,6 +158,16 @@ namespace BansheeEngine
 			}
 
 			growIndexBuffer(newNumIndices);
+			buffersModified = true;
+		}
+
+		if (buffersModified)
+		{
+			for (auto& allocData : mMeshAllocData)
+			{
+				if (allocData.second.useFlags != UseFlags::CPUFree && allocData.second.useFlags != UseFlags::Free)
+					allocData.second.mesh->_updateProxy();
+			}
 		}
 
 		UINT32 freeVertChunkIdx = 0;
@@ -243,8 +254,9 @@ namespace BansheeEngine
 		newAllocData.idxChunkIdx = freeIdxChunkIdx;
 		newAllocData.useFlags = UseFlags::GPUFree;
 		newAllocData.eventQueryIdx = createEventQuery();
+		newAllocData.mesh = mesh;
 
-		mMeshAllocData[meshId] = newAllocData;
+		mMeshAllocData[mesh->getMeshHeapId()] = newAllocData;
 
 		// Actually copy data
 		for(UINT32 i = 0; i <= mVertexDesc->getMaxStreamIdx(); i++)
@@ -292,8 +304,7 @@ namespace BansheeEngine
 			vertexBuffer->writeData(vertChunkStart * vertSize, meshData->getNumVertices() * vertSize, vertDest, BufferWriteType::NoOverwrite);
 		}
 
-		IndexBufferPtr indexBuffer = mIndexData->indexBuffer;
-		UINT32 idxSize = indexBuffer->getIndexSize();
+		UINT32 idxSize = mIndexBuffer->getIndexSize();
 
 		// Ensure index sizes match
 		if(meshData->getIndexElementSize() != idxSize)
@@ -304,12 +315,14 @@ namespace BansheeEngine
 
 		UINT8* idxDest = mCPUIndexData + idxChunkStart * idxSize;
 		memcpy(idxDest, meshData->getIndexData(), meshData->getNumIndices() * idxSize);
-		indexBuffer->writeData(idxChunkStart * idxSize, meshData->getNumIndices() * idxSize, idxDest, BufferWriteType::NoOverwrite);
+		mIndexBuffer->writeData(idxChunkStart * idxSize, meshData->getNumIndices() * idxSize, idxDest, BufferWriteType::NoOverwrite);
+
+		mesh->_updateProxy();
 	}
 
-	void MeshHeap::deallocInternal(UINT32 meshId)
+	void MeshHeap::deallocInternal(TransientMeshPtr mesh)
 	{
-		auto findIter = mMeshAllocData.find(meshId);
+		auto findIter = mMeshAllocData.find(mesh->getMeshHeapId());
 		assert(findIter != mMeshAllocData.end());
 
 		AllocatedData& allocData = findIter->second;
@@ -416,13 +429,10 @@ namespace BansheeEngine
 	{
 		mNumIndices = numIndices;
 
-		mIndexData = std::shared_ptr<IndexData>(bs_new<IndexData, PoolAlloc>());
-		mIndexData->indexCount = mNumIndices;
-		mIndexData->indexBuffer = HardwareBufferManager::instance().createIndexBuffer(
-			mIndexType, mIndexData->indexCount, GBU_DYNAMIC);
+		mIndexBuffer = HardwareBufferManager::instance().createIndexBuffer(mIndexType, mNumIndices, GBU_DYNAMIC);
 
 		// Copy all data to the new buffer
-		UINT32 idxSize = mIndexData->indexBuffer->getIndexSize();
+		UINT32 idxSize = mIndexBuffer->getIndexSize();
 
 		UINT8* oldBuffer = mCPUIndexData;
 		UINT8* buffer = (UINT8*)bs_alloc(idxSize * numIndices);
@@ -444,7 +454,7 @@ namespace BansheeEngine
 		}
 
 		if(destOffset > 0)
-			mIndexData->indexBuffer->writeData(0, destOffset * idxSize, buffer, BufferWriteType::NoOverwrite);
+			mIndexBuffer->writeData(0, destOffset * idxSize, buffer, BufferWriteType::NoOverwrite);
 
 		mCPUIndexData = buffer;
 
@@ -513,14 +523,14 @@ namespace BansheeEngine
 		mFreeEventQueries.push(idx);
 	}
 
-	std::shared_ptr<VertexData> MeshHeap::getVertexData() const
+	std::shared_ptr<VertexData> MeshHeap::_getVertexData() const
 	{
 		return mVertexData;
 	}
 
-	std::shared_ptr<IndexData> MeshHeap::getIndexData() const
+	IndexBufferPtr MeshHeap::_getIndexBuffer() const
 	{
-		return mIndexData;
+		return mIndexBuffer;
 	}
 
 	UINT32 MeshHeap::getVertexOffset(UINT32 meshId) const

+ 12 - 3
BansheeCore/Source/BsMeshManager.cpp

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

+ 42 - 0
BansheeCore/Source/BsMeshProxy.cpp

@@ -0,0 +1,42 @@
+#include "BsMeshProxy.h"
+#include "BsRenderableProxy.h"
+
+namespace BansheeEngine
+{
+	MeshProxy::MeshProxy(const std::shared_ptr<VertexData>& vertexData, 
+		const IndexBufferPtr& indexBuffer, const SubMesh& subMesh)
+		:mVertexData(vertexData), mIndexBuffer(indexBuffer), mSubMesh(subMesh)
+	{
+
+	}
+
+	void MeshProxy::addRenderableProxy(RenderableSubProxy* proxy)
+	{
+		mRenderableProxies.push_back(proxy);
+	}
+
+	void MeshProxy::removeRenderableProxy(RenderableSubProxy* proxy)
+	{
+		auto iterFind = std::find(mRenderableProxies.begin(), mRenderableProxies.end(), proxy);
+
+		if (iterFind != mRenderableProxies.end())
+			mRenderableProxies.erase(iterFind);
+	}
+
+	void MeshProxy::updateBounds(const Bounds& bounds)
+	{
+		mBounds = bounds;
+
+		for (auto& renderableProxy : mRenderableProxies)
+		{
+			renderableProxy->markBoundsDirty();
+		}
+	}
+
+	void MeshProxy::updateData(const std::shared_ptr<VertexData>& vertexData, const IndexBufferPtr& indexBuffer, const SubMesh& subMesh)
+	{
+		mVertexData = vertexData;
+		mIndexBuffer = indexBuffer;
+		mSubMesh = subMesh;
+	}
+}

+ 1 - 2
BansheeCore/Source/BsRenderQueue.cpp

@@ -14,7 +14,7 @@ namespace BansheeEngine
 		mSortedRenderOps.clear();
 	}
 
-	void RenderQueue::add(const MaterialPtr& material, const MeshBasePtr& mesh, UINT32 submeshIdx, const Vector3& worldPosForSort)
+	void RenderQueue::add(const MaterialProxy& material, MeshProxy* mesh, const Vector3& worldPosForSort)
 	{
 		// TODO - Make sure RenderOperations are cached so we dont allocate memory for them every frame
 		mRenderOperations.push_back(RenderOperation());
@@ -23,7 +23,6 @@ namespace BansheeEngine
 		renderOp.material = material;
 		renderOp.mesh = mesh;
 		renderOp.worldPosition = worldPosForSort;
-		renderOp.submeshIdx = submeshIdx;
 	}
 
 	const Vector<SortedRenderOp>& RenderQueue::getSortedRenderOps() const

+ 3 - 3
BansheeCore/Source/BsRenderSystem.cpp

@@ -248,12 +248,12 @@ namespace BansheeEngine {
 
 		if (useIndices)
 		{
-			std::shared_ptr<IndexData> indexData = mesh->_getIndexData();
+			IndexBufferPtr indexBuffer = mesh->_getIndexBuffer();
 
 			if(indexCount == 0)
-				indexCount = indexData->indexCount;
+				indexCount = indexBuffer->getNumIndices();
 
-			setIndexBuffer(indexData->indexBuffer);
+			setIndexBuffer(indexBuffer);
 			drawIndexed(indexOffset + mesh->_getIndexOffset(), indexCount, mesh->_getVertexOffset(), vertexData->vertexCount);
 		}
 		else

+ 20 - 0
BansheeCore/Source/BsRenderableProxy.cpp

@@ -0,0 +1,20 @@
+#include "BsRenderableProxy.h"
+#include "BsMeshProxy.h"
+
+namespace BansheeEngine
+{
+	RenderableSubProxy::RenderableSubProxy()
+		:mBoundsDirty(false), id(0), mesh(nullptr)
+	{ }
+
+	Bounds RenderableSubProxy::calculateWorldBounds()
+	{
+		if (mesh == nullptr)
+			return Bounds();
+
+		Bounds worldBounds = mesh->getBounds();
+		worldBounds.transformAffine(worldTransform);
+
+		return worldBounds;
+	}
+}

+ 1 - 1
BansheeCore/Source/BsRenderer.cpp

@@ -2,7 +2,7 @@
 
 namespace BansheeEngine
 {
-	void Renderer::addRenderCallback(const Viewport* viewport, std::function<void(const Viewport*, RenderQueue&)> callback)
+	void Renderer::addRenderCallback(const Viewport* viewport, std::function<void(const Viewport*, DrawList&)> callback)
 	{
 		mRenderCallbacks[viewport].push_back(callback);
 	}

+ 11 - 1
BansheeCore/Source/BsSceneObject.cpp

@@ -13,7 +13,7 @@ namespace BansheeEngine
 		:GameObject(), mPosition(Vector3::ZERO), mRotation(Quaternion::IDENTITY), mScale(Vector3::ONE),
 		mWorldPosition(Vector3::ZERO), mWorldRotation(Quaternion::IDENTITY), mWorldScale(Vector3::ONE),
 		mCachedLocalTfrm(Matrix4::IDENTITY), mIsCachedLocalTfrmUpToDate(false),
-		mCachedWorldTfrm(Matrix4::IDENTITY), mIsCachedWorldTfrmUpToDate(false)
+		mCachedWorldTfrm(Matrix4::IDENTITY), mIsCachedWorldTfrmUpToDate(false), mIsRenderDataUpToDate(false)
 	{
 		setName(name);
 	}
@@ -229,10 +229,20 @@ namespace BansheeEngine
 		setRotation(targetRotation);
 	}
 
+	void SceneObject::updateTransformsIfDirty()
+	{
+		if (!mIsCachedLocalTfrmUpToDate)
+			updateLocalTfrm();
+
+		if (!mIsCachedWorldTfrmUpToDate)
+			updateWorldTfrm();
+	}
+
 	void SceneObject::markTfrmDirty() const
 	{
 		mIsCachedLocalTfrmUpToDate = false;
 		mIsCachedWorldTfrmUpToDate = false;
+		mIsRenderDataUpToDate = false;
 
 		for(auto iter = mChildren.begin(); iter != mChildren.end(); ++iter)
 		{

+ 9 - 4
BansheeCore/Source/BsTransientMesh.cpp

@@ -1,6 +1,5 @@
 #include "BsTransientMesh.h"
 #include "BsVertexData.h"
-#include "BsIndexData.h"
 #include "BsMeshHeap.h"
 
 namespace BansheeEngine
@@ -32,12 +31,12 @@ namespace BansheeEngine
 
 	std::shared_ptr<VertexData> TransientMesh::_getVertexData() const
 	{
-		return mParentHeap->getVertexData();
+		return mParentHeap->_getVertexData();
 	}
 
-	std::shared_ptr<IndexData> TransientMesh::_getIndexData() const
+	IndexBufferPtr TransientMesh::_getIndexBuffer() const
 	{
-		return mParentHeap->getIndexData();
+		return mParentHeap->_getIndexBuffer();
 	}
 
 	UINT32 TransientMesh::_getVertexOffset() const
@@ -54,4 +53,10 @@ namespace BansheeEngine
 	{
 		mParentHeap->notifyUsedOnGPU(mId);
 	}
+
+	void TransientMesh::_updateProxy()
+	{
+		mMeshProxy.updateData(mParentHeap->_getVertexData(), mParentHeap->_getIndexBuffer(),
+			SubMesh(mParentHeap->getIndexOffset(mId), getNumIndices(), getSubMesh(0).drawOp));
+	}
 }

+ 0 - 1
BansheeCore/Source/BsVertexData.cpp

@@ -1,4 +1,3 @@
-#include "BsIndexData.h"
 #include "BsVertexData.h"
 #include "BsHardwareBufferManager.h"
 #include "BsVertexBuffer.h"

+ 6 - 12
BansheeCore/Source/BsViewport.cpp

@@ -20,26 +20,15 @@ namespace BansheeEngine
          :mTarget(target), mNormArea(x, y, width, height), mClearColor(DEFAULT_CLEAR_COLOR), mRequiresColorClear(true), 
 		 mRequiresDepthClear(true), mRequiresStencilClear(false), mStencilClearValue(0), mDepthClearValue(1.0f)
     {
-		if(target != nullptr)
-		{
-			// Note: RenderTarget resize will only get triggered for RenderWindows, RenderTextures are immutable
-			mTargetResizedConn = target->onResized.connect(std::bind(&Viewport::targetResized, this));
-		}
-
         updateArea();
     }
 
     Viewport::~Viewport()
-    {
-		mTargetResizedConn.disconnect();
-    }
+    { }
 
 	void Viewport::targetResized()
 	{
 		updateArea();
-
-		if(!onResized.empty())
-			onResized();
 	}
 
     void Viewport::updateArea()
@@ -65,4 +54,9 @@ namespace BansheeEngine
 
         updateArea();
     }
+
+	Viewport Viewport::clone()
+	{
+		return *this;
+	}
 }

+ 0 - 1
BansheeD3D11RenderSystem/Include/BsD3D11Mappings.h

@@ -5,7 +5,6 @@
 #include "BsPixelData.h"
 #include "BsIndexBuffer.h"
 #include "BsVertexData.h"
-#include "BsIndexData.h"
 #include "BsSamplerState.h"
 #include "BsDrawOps.h"
 

+ 1 - 1
BansheeD3D11RenderSystem/Include/BsD3D11RenderSystem.h

@@ -43,7 +43,7 @@ namespace BansheeEngine
 		void clearViewport(UINT32 buffers, const Color& color = Color::Black, float depth = 1.0f, UINT16 stencil = 0);
 
 		void setRenderTarget(RenderTargetPtr target);
-		void setViewport(const ViewportPtr& vp);
+		void setViewport(Viewport vp);
 		void setScissorRect(UINT32 left, UINT32 top, UINT32 right, UINT32 bottom);
 
 		void setVertexBuffers(UINT32 index, VertexBufferPtr* buffers, UINT32 numBuffers);

+ 9 - 12
BansheeD3D11RenderSystem/Source/BsD3D11RenderSystem.cpp

@@ -311,29 +311,26 @@ namespace BansheeEngine
 		// Not used
 	}
 
-	void D3D11RenderSystem::setViewport(const ViewportPtr& vp)
+	void D3D11RenderSystem::setViewport(Viewport vp)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
-		assert(vp != nullptr);
-
 		// Set render target
-		RenderTargetPtr target = vp->getTarget();
+		RenderTargetPtr target = vp.getTarget();
 		setRenderTarget(target);
 
-		// set viewport dimensions
-		mViewport.TopLeftX = (FLOAT)vp->getX();
-		mViewport.TopLeftY = (FLOAT)vp->getY();
-		mViewport.Width = (FLOAT)vp->getWidth();
-		mViewport.Height = (FLOAT)vp->getHeight();
+		// Set viewport dimensions
+		mViewport.TopLeftX = (FLOAT)vp.getX();
+		mViewport.TopLeftY = (FLOAT)vp.getY();
+		mViewport.Width = (FLOAT)vp.getWidth();
+		mViewport.Height = (FLOAT)vp.getHeight();
 
-		if (vp->getTarget()->requiresTextureFlipping())
+		if (target->requiresTextureFlipping())
 		{
 			// Convert "top-left" to "bottom-left"
-			mViewport.TopLeftY = vp->getTarget()->getHeight() - mViewport.Height - mViewport.TopLeftY;
+			mViewport.TopLeftY = target->getHeight() - mViewport.Height - mViewport.TopLeftY;
 		}
 
-		// Z-values from 0.0 to 1.0 (TODO: standardise with OpenGL)
 		mViewport.MinDepth = 0.0f;
 		mViewport.MaxDepth = 1.0f;
 

+ 1 - 1
BansheeD3D9RenderSystem/Include/BsD3D9RenderSystem.h

@@ -97,7 +97,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc RenderSystem::setViewport()
 		 */
-		void setViewport(const ViewportPtr& vp);	
+		void setViewport(Viewport vp);
 
 		/**
 		 * @copydoc RenderSystem::beginFrame()

+ 11 - 13
BansheeD3D9RenderSystem/Source/BsD3D9RenderSystem.cpp

@@ -1103,32 +1103,30 @@ namespace BansheeEngine
 		mRenderStats.numRenderTargetChanges++;
 	}
 
-	void D3D9RenderSystem::setViewport(const ViewportPtr& vp)
+	void D3D9RenderSystem::setViewport(Viewport vp)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
-		assert(vp != nullptr);
-
 		// ok, it's different, time to set render target and viewport params
 		D3DVIEWPORT9 d3dvp;
 		HRESULT hr;
 
 		// Set render target
-		RenderTargetPtr target = vp->getTarget();
+		RenderTargetPtr target = vp.getTarget();
 		setRenderTarget(target);
 
 		setCullingMode( mCullingMode );
 
 		// set viewport dimensions
-		mViewportWidth = vp->getWidth();
-		mViewportHeight = vp->getHeight();
-		mViewportLeft = vp->getX();
-		mViewportTop = vp->getY();
-
-		d3dvp.X = vp->getX();
-		d3dvp.Y = vp->getY();
-		d3dvp.Width = vp->getWidth();
-		d3dvp.Height = vp->getHeight();
+		mViewportWidth = vp.getWidth();
+		mViewportHeight = vp.getHeight();
+		mViewportLeft = vp.getX();
+		mViewportTop = vp.getY();
+
+		d3dvp.X = vp.getX();
+		d3dvp.Y = vp.getY();
+		d3dvp.Width = vp.getWidth();
+		d3dvp.Height = vp.getHeight();
 		if (target->requiresTextureFlipping())
 		{
 			// Convert "top-left" to "bottom-left"

+ 1 - 1
BansheeEditor/Include/BsDockManager.h

@@ -81,7 +81,7 @@ namespace BansheeEngine
 		 */
 		void update();
 
-		void render(const Viewport* viewport, RenderQueue& renderQueue);
+		void render(const Viewport* viewport, DrawList& renderQueue);
 		void insert(EditorWidgetContainer* relativeTo, EditorWidgetBase* widgetToInsert, DockLocation location);
 
 		DockManagerLayoutPtr getLayout() const;

+ 3 - 3
BansheeEditor/Source/BsDockManager.cpp

@@ -7,7 +7,7 @@
 #include "BsMesh.h"
 #include "BsMaterial.h"
 #include "BsVector2.h"
-#include "BsRenderQueue.h"
+#include "BsDrawList.h"
 #include "BsCoreApplication.h"
 #include "BsRendererManager.h"
 #include "BsRenderer.h"
@@ -389,7 +389,7 @@ namespace BansheeEngine
 		}
 	}
 
-	void DockManager::render(const Viewport* viewport, RenderQueue& renderQueue)
+	void DockManager::render(const Viewport* viewport, DrawList& drawList)
 	{
 		if(!mShowOverlay)
 			return;
@@ -431,7 +431,7 @@ namespace BansheeEngine
 
 		mDropOverlayMat->setColor("highlightActive", highlightColor);
 
-		renderQueue.add(mDropOverlayMat.getInternalPtr(), mDropOverlayMesh.getInternalPtr(), 0, Vector3::ZERO);
+		drawList.add(mDropOverlayMat.getInternalPtr(), mDropOverlayMesh.getInternalPtr(), 0, Vector3::ZERO);
 	}
 
 	void DockManager::insert(EditorWidgetContainer* relativeTo, EditorWidgetBase* widgetToInsert, DockLocation location)

+ 1 - 1
BansheeEditor/Source/BsEditorWindowBase.cpp

@@ -76,7 +76,7 @@ namespace BansheeEngine
 		mWindowFrame = mSceneObject->addComponent<WindowFrameWidget>(mCamera->getViewport().get(), renderWindow.get(), EditorGUI::instance().getSkin());
 		mWindowFrame->setDepth(129);
 
-		mResizedConn = mCamera->getViewport()->onResized.connect(std::bind(&EditorWindowBase::resized, this));
+		mResizedConn = renderWindow->onResized.connect(std::bind(&EditorWindowBase::resized, this));
 	}
 
 	void EditorWindowBase::setPosition(INT32 x, INT32 y)

+ 4 - 2
BansheeEngine.sln

@@ -1,6 +1,8 @@
 
 Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2012
+# Visual Studio 2013
+VisualStudioVersion = 12.0.21005.1
+MinimumVisualStudioVersion = 10.0.40219.1
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Notes", "_Notes", "{1D081E5A-615A-4C06-B2DF-0D8D9390DE02}"
 	ProjectSection(SolutionItems) = preProject
 		CSharpWrap.txt = CSharpWrap.txt
@@ -15,7 +17,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Notes", "_Notes", "{1D081E
 		Opts.txt = Opts.txt
 		Polish.txt = Polish.txt
 		ProjectLibrary.txt = ProjectLibrary.txt
-		RenderOperation.txt = RenderOperation.txt
+		Renderer.txt = Renderer.txt
 		ResourceBundles.txt = ResourceBundles.txt
 		SpriteTexture.txt = SpriteTexture.txt
 		TODO.txt = TODO.txt

+ 3 - 1
BansheeEngine/Include/BsBuiltinMaterialManager.h

@@ -23,6 +23,7 @@ namespace BansheeEngine
 		virtual HMaterial createDebugDraw2DScreenSpaceMaterial() const = 0;
 		virtual HMaterial createDebugDraw3DMaterial() const = 0;
 		virtual HMaterial createDockDropOverlayMaterial() const = 0;
+		virtual HMaterial createDummyMaterial() const = 0;
 	};
 
 	/**
@@ -41,7 +42,8 @@ namespace BansheeEngine
 		DebugDraw2DClipSpaceMatInfo createDebugDraw2DClipSpaceMaterial() const;
 		DebugDraw2DScreenSpaceMatInfo createDebugDraw2DScreenSpaceMaterial() const;
 		DebugDraw3DMatInfo createDebugDraw3DMaterial() const;
-		HMaterial createDockDropOverlayMaterial() const;
+		HMaterial createDockDropOverlayMaterial() const; // TODO - This belongs in editor
+		HMaterial createDummyMaterial() const;
 
 		void addFactory(BuiltinMaterialFactory* factory);
 		void setActive(const String& renderSystemName);

+ 3 - 1
BansheeEngine/Include/BsCamera.h

@@ -11,11 +11,11 @@
 #include "BsVector2.h"
 #include "BsAABox.h"
 #include "BsVertexData.h"
-#include "BsIndexData.h"
 #include "BsPlane.h"
 #include "BsQuaternion.h"
 #include "BsRay.h"
 #include "BsComponent.h"
+#include "BsCameraProxy.h"
 
 namespace BansheeEngine {
 
@@ -497,6 +497,8 @@ namespace BansheeEngine {
 
 		ViewportPtr getViewport() const { return mViewport; }
 
+		CameraProxy _createProxy() const;
+
 		/************************************************************************/
 		/* 						COMPONENT OVERRIDES                      		*/
 		/************************************************************************/

+ 3 - 0
BansheeEngine/Include/BsD3D11BuiltinMaterialFactory.h

@@ -21,6 +21,7 @@ namespace BansheeEngine
 		HMaterial createDebugDraw2DScreenSpaceMaterial() const;
 		HMaterial createDebugDraw3DMaterial() const;
 		HMaterial createDockDropOverlayMaterial() const;
+		HMaterial createDummyMaterial() const;
 
 	protected:
 		ShaderPtr mSpriteTextShader;
@@ -29,6 +30,7 @@ namespace BansheeEngine
 		ShaderPtr mDebugDraw2DScreenSpaceShader;
 		ShaderPtr mDebugDraw3DShader;
 		ShaderPtr mDockDropOverlayShader;
+		ShaderPtr mDummyShader;
 
 		HSamplerState mGUISamplerState;
 
@@ -38,5 +40,6 @@ namespace BansheeEngine
 		void initDebugDraw2DScreenSpaceShader();
 		void initDebugDraw3DShader();
 		void initDockDropOverlayShader();
+		void initDummyShader();
 	};
 }

+ 3 - 0
BansheeEngine/Include/BsD3D9BuiltinMaterialFactory.h

@@ -21,6 +21,7 @@ namespace BansheeEngine
 		HMaterial createDebugDraw2DScreenSpaceMaterial() const;
 		HMaterial createDebugDraw3DMaterial() const;
 		HMaterial createDockDropOverlayMaterial() const;
+		HMaterial createDummyMaterial() const;
 
 	protected:
 		ShaderPtr mSpriteTextShader;
@@ -29,6 +30,7 @@ namespace BansheeEngine
 		ShaderPtr mDebugDraw2DScreenSpaceShader;
 		ShaderPtr mDebugDraw3DShader;
 		ShaderPtr mDockDropOverlayShader;
+		ShaderPtr mDummyShader;
 
 		HSamplerState mGUISamplerState;
 
@@ -38,5 +40,6 @@ namespace BansheeEngine
 		void initDebugDraw2DScreenSpaceShader();
 		void initDebugDraw3DShader();
 		void initDockDropOverlayShader();
+		void initDummyShader();
 	};
 }

+ 1 - 1
BansheeEngine/Include/BsDrawHelperTemplate.h

@@ -43,7 +43,7 @@ namespace BansheeEngine
 	class BS_EXPORT DrawHelperTemplateBase
 	{
 	public:
-		void render(const HCamera& camera, RenderQueue& renderQueue);
+		void render(const HCamera& camera, DrawList& drawList);
 
 	protected:
 		UnorderedMap<const Viewport*, Vector<DebugDrawCommand>> mCommandsPerViewport;

+ 3 - 0
BansheeEngine/Include/BsGLBuiltinMaterialFactory.h

@@ -21,6 +21,7 @@ namespace BansheeEngine
 		HMaterial createDebugDraw2DScreenSpaceMaterial() const;
 		HMaterial createDebugDraw3DMaterial() const;
 		HMaterial createDockDropOverlayMaterial() const;
+		HMaterial createDummyMaterial() const;
 
 	protected:
 		ShaderPtr mSpriteTextShader;
@@ -29,6 +30,7 @@ namespace BansheeEngine
 		ShaderPtr mDebugDraw2DScreenSpaceShader;
 		ShaderPtr mDebugDraw3DShader;
 		ShaderPtr mDockDropOverlayShader;
+		ShaderPtr mDummyShader;
 
 		HSamplerState mGUISamplerState;
 
@@ -38,5 +40,6 @@ namespace BansheeEngine
 		void initDebugDraw2DScreenSpaceShader();
 		void initDebugDraw3DShader();
 		void initDockDropOverlayShader();
+		void initDummyShader();
 	};
 }

+ 1 - 1
BansheeEngine/Include/BsGUIManager.h

@@ -81,7 +81,7 @@ namespace BansheeEngine
 		void unregisterWidget(GUIWidget* widget);
 
 		void update();
-		void render(ViewportPtr& target, RenderQueue& renderQueue) const;
+		void render(ViewportPtr& target, DrawList& drawList) const;
 
 		void queueForDestroy(GUIElement* element);
 

+ 1 - 1
BansheeEngine/Include/BsOverlay.h

@@ -17,7 +17,7 @@ namespace BansheeEngine
 	public:
 		virtual ~Overlay();
 
-		virtual void render(RenderQueue& renderQueue) const = 0;
+		virtual void render(DrawList& drawList) const = 0;
 		virtual void update() {}
 
 		Viewport* getTarget() const { return mRenderTarget; }

+ 1 - 1
BansheeEngine/Include/BsOverlayManager.h

@@ -30,7 +30,7 @@ namespace BansheeEngine
 		 * @brief	Schedules any overlays for the specified viewport to be rendered.
 		 *			(adds them to the render queue).
 		 */
-		void render(ViewportPtr& target, RenderQueue& renderQueue) const;
+		void render(ViewportPtr& target, DrawList& drawList) const;
 
 	private:
 		friend class Overlay;

+ 35 - 8
BansheeEngine/Include/BsRenderable.h

@@ -2,6 +2,7 @@
 
 #include "BsPrerequisites.h"
 #include "BsComponent.h"
+#include "BsRenderableProxy.h"
 #include "BsAABox.h"
 #include "BsGpuParam.h"
 
@@ -9,26 +10,52 @@ namespace BansheeEngine
 {
 	class BS_EXPORT Renderable : public Component
 	{
+		struct MeshData
+		{
+			MeshData() {}
+			MeshData(const HMesh& mesh);
+
+			HMesh mesh;
+			mutable bool isLoaded;
+		};
+
+		struct MaterialData
+		{
+			MaterialData() {}
+			MaterialData(const HMaterial& material);
+
+			HMaterial material;
+			mutable bool isLoaded;
+		};
+
 	public:
-		void setMesh(HMesh mesh) { mMesh = mesh; }
+		void setMesh(HMesh mesh);
 		void setNumMaterials(UINT32 numMaterials);
 		void setMaterial(UINT32 idx, HMaterial material);
 		void setMaterial(HMaterial material);
 		void setLayer(UINT64 layer);
 
 		UINT64 getLayer() const { return mLayer; }
-		UINT32 getNumMaterials() const { return (UINT32)mMaterials.size(); }
-		HMaterial& getMaterial(UINT32 idx) { return mMaterials[idx]; }
+		UINT32 getNumMaterials() const { return (UINT32)mMaterialData.size(); }
+		HMaterial& getMaterial(UINT32 idx) { return mMaterialData[idx].material; }
+
+		bool _isRenderDataDirty() const;
+		void _markRenderDataClean() { mIsRenderDataDirty = false; }
+		RenderableProxy* _createProxy(FrameAlloc* allocator) const;
+		RenderableProxy* _getActiveProxy() const { return mActiveProxy; }
+		void _setActiveProxy(RenderableProxy* proxy) { mActiveProxy = proxy; }
+
+	private:
+		void updateResourceLoadStates() const;
 
-		void render(RenderQueue& renderQueue, const Matrix4& viewProjMatrix);
-		void updateWorldBounds();
 	private:
-		HMesh mMesh;
-		Vector<HMaterial> mMaterials;
+		MeshData mMeshData;
+		Vector<MaterialData> mMaterialData;
 		UINT64 mLayer;
 		Vector<AABox> mWorldBounds;
 
-		Vector<GpuParamMat4> mMatViewProjParam;
+		RenderableProxy* mActiveProxy;
+		mutable bool mIsRenderDataDirty;
 
 		/************************************************************************/
 		/* 							COMPONENT OVERRIDES                    		*/

+ 4 - 4
BansheeEngine/Include/BsRenderableRTTI.h

@@ -10,15 +10,15 @@ namespace BansheeEngine
 	class BS_EXPORT RenderableRTTI : public RTTIType<Renderable, Component, RenderableRTTI>
 	{
 	private:
-		HMesh& getMesh(Renderable* obj) { return obj->mMesh; }
-		void setMesh(Renderable* obj, HMesh& val) { obj->mMesh = val; } 
+		HMesh& getMesh(Renderable* obj) { return obj->mMeshData.mesh; }
+		void setMesh(Renderable* obj, HMesh& val) { obj->mMeshData.mesh = val; } 
 
 		UINT64& getLayer(Renderable* obj) { return obj->mLayer; }
 		void setLayer(Renderable* obj, UINT64& val) { obj->mLayer = val; }
 
-		HMaterial& getMaterial(Renderable* obj, UINT32 idx) { return obj->mMaterials[idx]; }
+		HMaterial& getMaterial(Renderable* obj, UINT32 idx) { return obj->mMaterialData[idx].material; }
 		void setMaterial(Renderable* obj, UINT32 idx, HMaterial& val) { obj->setMaterial(idx, val); }
-		UINT32 getNumMaterials(Renderable* obj) { return (UINT32)obj->mMaterials.size(); }
+		UINT32 getNumMaterials(Renderable* obj) { return (UINT32)obj->mMaterialData.size(); }
 		void setNumMaterials(Renderable* obj, UINT32 num) { obj->setNumMaterials(num); }
 
 	public:

+ 11 - 3
BansheeEngine/Include/BsSceneManager.h

@@ -17,11 +17,19 @@ namespace BansheeEngine
 		virtual const Vector<HCamera>& getAllCameras() const = 0;
 
 		/**
-		 * @brief	Returns all renderables visible to the specified camera.
+		 * @brief	Returns all renderables in the scene.
 		 */
-		virtual Vector<HRenderable> getVisibleRenderables(const HCamera& camera) const = 0;
+		virtual const Vector<HRenderable>& getAllRenderables() const = 0;
 
-		virtual void updateRenderableBounds() = 0;
+		/**
+		 * @brief	Updates dirty transforms on any scene objects with a Renderable component.
+		 */
+		virtual void updateRenderableTransforms() = 0;
+
+		/**
+		 * @brief	Triggered whenever a renderable is removed from a SceneObject.
+		 */
+		Event<void(const HRenderable&)> onRenderableRemoved;
 	};
 
 	BS_EXPORT SceneManager& gBsSceneManager();

+ 7 - 0
BansheeEngine/Source/BsBuiltinMaterialManager.cpp

@@ -88,6 +88,13 @@ namespace BansheeEngine
 		return mActiveFactory->createDockDropOverlayMaterial();
 	}
 
+	HMaterial BuiltinMaterialManager::createDummyMaterial() const
+	{
+		assert(mActiveFactory != nullptr);
+
+		return mActiveFactory->createDummyMaterial();
+	}
+
 	void BuiltinMaterialManager::addFactory(BuiltinMaterialFactory* factory)
 	{
 		assert(factory != nullptr);

+ 13 - 0
BansheeEngine/Source/BsCamera.cpp

@@ -751,6 +751,19 @@ namespace BansheeEngine
 
     }
 
+	CameraProxy Camera::_createProxy() const
+	{
+		CameraProxy proxy;
+		proxy.layer = mLayers;
+		proxy.priority = mPriority;
+		proxy.projMatrix = getProjectionMatrixRS();
+		proxy.viewMatrix = getViewMatrix();
+		proxy.viewport = mViewport->clone();
+		proxy.ignoreSceneRenderables = mIgnoreSceneRenderables;
+
+		return proxy;
+	}
+
 	RTTITypeBase* Camera::getRTTIStatic()
 	{
 		return CameraRTTI::instance();

+ 39 - 0
BansheeEngine/Source/BsD3D11BuiltinMaterialFactory.cpp

@@ -18,6 +18,7 @@ namespace BansheeEngine
 		initDebugDraw2DScreenSpaceShader();
 		initDebugDraw3DShader();
 		initDockDropOverlayShader();
+		initDummyShader();
 
 		SAMPLER_STATE_DESC ssDesc;
 		ssDesc.magFilter = FO_POINT;
@@ -35,6 +36,7 @@ namespace BansheeEngine
 		mDebugDraw2DScreenSpaceShader = nullptr;
 		mDebugDraw3DShader = nullptr;
 		mDockDropOverlayShader = nullptr;
+		mDummyShader = nullptr;
 	}
 
 	const String& D3D11BuiltinMaterialFactory::getSupportedRenderSystem() const
@@ -80,6 +82,11 @@ namespace BansheeEngine
 		return Material::create(mDockDropOverlayShader);
 	}
 
+	HMaterial D3D11BuiltinMaterialFactory::createDummyMaterial() const
+	{
+		return Material::create(mDummyShader);
+	}
+
 	void D3D11BuiltinMaterialFactory::initSpriteTextShader()
 	{
 		String vsCode = "										\
@@ -451,4 +458,36 @@ namespace BansheeEngine
 		HDepthStencilState depthState = DepthStencilState::create(depthStateDesc);
 		newPass->setDepthStencilState(depthState);
 	}
+
+	void D3D11BuiltinMaterialFactory::initDummyShader()
+	{
+		String vsCode = "float4x4 matWorldViewProj;				\
+																\
+						 void vs_main(							\
+						 in float3 inPos : POSITION,			\
+						 out float4 oPosition : SV_Position)	\
+						 {										\
+							 oPosition = mul(matWorldViewProj, float4(inPos.xyz, 1)); \
+						 }";
+
+		String psCode = "float4 ps_main() : SV_Target				\
+						 {											\
+							 return float4(0.5f, 0.5f, 0.5f, 0.5f);	\
+						 }";	
+
+		HGpuProgram vsProgram = GpuProgram::create(vsCode, "vs_main", "hlsl", GPT_VERTEX_PROGRAM, GPP_VS_4_0);
+		HGpuProgram psProgram = GpuProgram::create(psCode, "ps_main", "hlsl", GPT_FRAGMENT_PROGRAM, GPP_PS_4_0);
+
+		vsProgram.synchronize();
+		psProgram.synchronize();
+
+		mDummyShader = Shader::create("DummyShader");
+
+		mDummyShader->addParameter("matWorldViewProj", "matWorldViewProj", GPDT_MATRIX_4X4);
+
+		TechniquePtr newTechnique = mDummyShader->addTechnique("D3D11RenderSystem", RendererManager::getCoreRendererName());
+		PassPtr newPass = newTechnique->addPass();
+		newPass->setVertexProgram(vsProgram);
+		newPass->setFragmentProgram(psProgram);
+	}
 }

+ 39 - 0
BansheeEngine/Source/BsD3D9BuiltinMaterialFactory.cpp

@@ -18,6 +18,7 @@ namespace BansheeEngine
 		initDebugDraw2DScreenSpaceShader();
 		initDebugDraw3DShader();
 		initDockDropOverlayShader();
+		initDummyShader();
 
 		SAMPLER_STATE_DESC ssDesc;
 		ssDesc.magFilter = FO_POINT;
@@ -35,6 +36,7 @@ namespace BansheeEngine
 		mDebugDraw2DScreenSpaceShader = nullptr;
 		mDebugDraw3DShader = nullptr;
 		mDockDropOverlayShader = nullptr;
+		mDummyShader = nullptr;
 	}
 
 	const String& D3D9BuiltinMaterialFactory::getSupportedRenderSystem() const
@@ -80,6 +82,11 @@ namespace BansheeEngine
 		return Material::create(mDockDropOverlayShader);
 	}
 
+	HMaterial D3D9BuiltinMaterialFactory::createDummyMaterial() const
+	{
+		return Material::create(mDummyShader);
+	}
+
 	void D3D9BuiltinMaterialFactory::initSpriteTextShader()
 	{
 		String vsCode = "										\
@@ -449,4 +456,36 @@ namespace BansheeEngine
 		HDepthStencilState depthState = DepthStencilState::create(depthStateDesc);
 		newPass->setDepthStencilState(depthState);
 	}
+
+	void D3D9BuiltinMaterialFactory::initDummyShader()
+	{
+		String vsCode = "float4x4 matWorldViewProj;			\
+															\
+						 void vs_main(						\
+						 in float3 inPos : POSITION,		\
+						 out float4 oPosition : POSITION)	\
+						 {									\
+							 oPosition = mul(matWorldViewProj, float4(inPos.xyz, 1));	\
+						 }";
+
+		String psCode = "float4 ps_main() : COLOR0					\
+						 {											\
+						 	return float4(0.5f, 0.5f, 0.5f, 0.5f);	\
+						 }";
+
+		HGpuProgram vsProgram = GpuProgram::create(vsCode, "vs_main", "hlsl", GPT_VERTEX_PROGRAM, GPP_VS_2_0);
+		HGpuProgram psProgram = GpuProgram::create(psCode, "ps_main", "hlsl", GPT_FRAGMENT_PROGRAM, GPP_PS_2_0);
+
+		vsProgram.synchronize();
+		psProgram.synchronize();
+
+		mDummyShader = Shader::create("DummyShader");
+
+		mDummyShader->addParameter("matWorldViewProj", "matWorldViewProj", GPDT_MATRIX_4X4);
+
+		TechniquePtr newTechnique = mDummyShader->addTechnique("D3D9RenderSystem", RendererManager::getCoreRendererName());
+		PassPtr newPass = newTechnique->addPass();
+		newPass->setVertexProgram(vsProgram);
+		newPass->setFragmentProgram(psProgram);
+	}
 }

+ 5 - 5
BansheeEngine/Source/BsDrawHelperTemplate.cpp

@@ -6,13 +6,13 @@
 #include "BsMaterial.h"
 #include "BsPass.h"
 #include "BsCoreApplication.h"
-#include "BsRenderQueue.h"
+#include "BsDrawList.h"
 #include "BsCamera.h"
 #include "BsBuiltinMaterialManager.h"
 
 namespace BansheeEngine
 {
-	void DrawHelperTemplateBase::render(const HCamera& camera, RenderQueue& renderQueue)
+	void DrawHelperTemplateBase::render(const HCamera& camera, DrawList& drawList)
 	{
 		const Viewport* viewport = camera->getViewport().get();
 		Vector<DebugDrawCommand>& commands = mCommandsPerViewport[viewport];
@@ -36,7 +36,7 @@ namespace BansheeEngine
 				if(mat == nullptr || !mat.isLoaded() || !mat->isInitialized())
 					continue;
 
-				renderQueue.add(mat.getInternalPtr(), cmd.mesh.getInternalPtr(), 0, cmd.worldCenter);
+				drawList.add(mat.getInternalPtr(), cmd.mesh.getInternalPtr(), 0, cmd.worldCenter);
 			}
 			else if(cmd.type == DebugDrawType::ScreenSpace)
 			{
@@ -48,7 +48,7 @@ namespace BansheeEngine
 				cmd.matInfo2DScreenSpace.invViewportWidth.set(invViewportWidth);
 				cmd.matInfo2DScreenSpace.invViewportHeight.set(invViewportHeight);
 
-				renderQueue.add(mat.getInternalPtr(), cmd.mesh.getInternalPtr(), 0, cmd.worldCenter);
+				drawList.add(mat.getInternalPtr(), cmd.mesh.getInternalPtr(), 0, cmd.worldCenter);
 			}
 			else if(cmd.type == DebugDrawType::WorldSpace)
 			{
@@ -59,7 +59,7 @@ namespace BansheeEngine
 
 				cmd.matInfo3D.matViewProj.set(viewProjMatrix);
 
-				renderQueue.add(mat.getInternalPtr(), cmd.mesh.getInternalPtr(), 0, cmd.worldCenter);
+				drawList.add(mat.getInternalPtr(), cmd.mesh.getInternalPtr(), 0, cmd.worldCenter);
 			}
 		}
 

+ 45 - 0
BansheeEngine/Source/BsGLBuiltinMaterialFactory.cpp

@@ -18,6 +18,7 @@ namespace BansheeEngine
 		initDebugDraw2DScreenSpaceShader();
 		initDebugDraw3DShader();
 		initDockDropOverlayShader();
+		initDummyShader();
 
 		SAMPLER_STATE_DESC ssDesc;
 		ssDesc.magFilter = FO_POINT;
@@ -35,6 +36,7 @@ namespace BansheeEngine
 		mDebugDraw2DScreenSpaceShader = nullptr;
 		mDebugDraw3DShader = nullptr;
 		mDockDropOverlayShader = nullptr;
+		mDummyShader = nullptr;
 	}
 
 	const String& GLBuiltinMaterialFactory::getSupportedRenderSystem() const
@@ -80,6 +82,11 @@ namespace BansheeEngine
 		return Material::create(mDockDropOverlayShader);
 	}
 
+	HMaterial GLBuiltinMaterialFactory::createDummyMaterial() const
+	{
+		return Material::create(mDummyShader);
+	}
+
 	void GLBuiltinMaterialFactory::initSpriteTextShader()
 	{
 		String vsCode = "#version 400\n							\
@@ -472,4 +479,42 @@ namespace BansheeEngine
 		HDepthStencilState depthState = DepthStencilState::create(depthStateDesc);
 		newPass->setDepthStencilState(depthState);
 	}
+
+void GLBuiltinMaterialFactory::initDummyShader()
+	{
+		String vsCode = "#version 400\n								\
+																	\
+						uniform mat4 matWorldViewProj;				\
+																	\
+						in vec3 bs_position;						\
+																	\
+						void main()									\
+						{											\
+							gl_Position = matWorldViewProj * vec4(bs_position.xyz, 1);		\
+						}";
+
+		String psCode = "#version 400\n						\
+															\
+						out vec4 fragColor;					\
+															\
+						void main()							\
+						{									\
+							fragColor = vec4(0.5f, 0.5f, 0.5f, 0.5f; \
+						}";
+
+		HGpuProgram vsProgram = GpuProgram::create(vsCode, "vs_main", "glsl", GPT_VERTEX_PROGRAM, GPP_VS_4_0);
+		HGpuProgram psProgram = GpuProgram::create(psCode, "ps_main", "glsl", GPT_FRAGMENT_PROGRAM, GPP_PS_4_0);
+
+		vsProgram.synchronize();
+		psProgram.synchronize();
+
+		mDummyShader = Shader::create("DummyShader");
+
+		mDummyShader->addParameter("matWorldViewProj", "matWorldViewProj", GPDT_MATRIX_4X4);
+
+		TechniquePtr newTechnique = mDummyShader->addTechnique("GLRenderSystem", RendererManager::getCoreRendererName());
+		PassPtr newPass = newTechnique->addPass();
+		newPass->setVertexProgram(vsProgram);
+		newPass->setFragmentProgram(psProgram);
+	}
 }

+ 3 - 3
BansheeEngine/Source/BsGUIManager.cpp

@@ -18,7 +18,7 @@
 #include "BsInput.h"
 #include "BsPass.h"
 #include "BsDebug.h"
-#include "BsRenderQueue.h"
+#include "BsDrawList.h"
 #include "BsGUIInputCaret.h"
 #include "BsGUIInputSelection.h"
 #include "BsGUIListBox.h"
@@ -279,7 +279,7 @@ namespace BansheeEngine
 		processDestroyQueue();
 	}
 
-	void GUIManager::render(ViewportPtr& target, RenderQueue& renderQueue) const
+	void GUIManager::render(ViewportPtr& target, DrawList& drawList) const
 	{
 		auto findIter = mCachedGUIData.find(target.get());
 
@@ -318,7 +318,7 @@ namespace BansheeEngine
 				materialInfo.invViewportHeight.set(invViewportHeight);
 				materialInfo.worldTransform.set(widget->SO()->getWorldTfrm());
 
-				renderQueue.add(materialInfo.material.getInternalPtr(), mesh, 0, Vector3::ZERO);
+				drawList.add(materialInfo.material.getInternalPtr(), mesh, 0, Vector3::ZERO);
 
 				meshIdx++;
 			}

+ 1 - 1
BansheeEngine/Source/BsGUIWidget.cpp

@@ -33,7 +33,7 @@ namespace BansheeEngine
 
 		mTarget = target;
 
-		mOwnerTargetResizedConn = mTarget->onResized.connect(std::bind(&GUIWidget::ownerTargetResized, this));
+		mOwnerTargetResizedConn = mTarget->getTarget()->onResized.connect(std::bind(&GUIWidget::ownerTargetResized, this));
 
 		GUIManager::instance().registerWidget(this);
 	}

+ 2 - 2
BansheeEngine/Source/BsOverlayManager.cpp

@@ -9,7 +9,7 @@ namespace BansheeEngine
 		return a->getDepth() > b->getDepth();
 	}
 
-	void OverlayManager::render(ViewportPtr& target, RenderQueue& renderQueue) const
+	void OverlayManager::render(ViewportPtr& target, DrawList& drawList) const
 	{
 		auto overlays = mOverlaysPerTarget.find(target.get());
 
@@ -19,7 +19,7 @@ namespace BansheeEngine
 		// Render all overlays. They should already be sorted by depth, front most rendering last
 		for(auto& overlay : overlays->second)
 		{
-			overlay->render(renderQueue);
+			overlay->render(drawList);
 		}
 	}
 

+ 3 - 2
BansheeEngine/Source/BsProfilerOverlay.cpp

@@ -6,10 +6,11 @@
 #include "BsGUIElement.h"
 #include "BsGUILabel.h"
 #include "BsGUISpace.h"
+#include "BsViewport.h"
 #include "BsTime.h"
 #include "BsBuiltinResources.h"
 #include "BsProfilingManager.h"
-#include "BsViewport.h"
+#include "BsRenderTarget.h"
 
 namespace BansheeEngine
 {
@@ -306,7 +307,7 @@ namespace BansheeEngine
 
 		mTarget = target;
 
-		mTargetResizedConn = target->onResized.connect(std::bind(&ProfilerOverlay::targetResized, this));
+		mTargetResizedConn = target->getTarget()->onResized.connect(std::bind(&ProfilerOverlay::targetResized, this));
 
 		if(mWidgetSO)
 			mWidgetSO->destroy();

+ 75 - 66
BansheeEngine/Source/BsRenderable.cpp

@@ -1,31 +1,54 @@
 #include "BsRenderable.h"
 #include "BsRenderableRTTI.h"
 #include "BsSceneObject.h"
+#include "BsBuiltinMaterialManager.h"
 #include "BsMesh.h"
 #include "BsMaterial.h"
 #include "BsRenderQueue.h"
 
 namespace BansheeEngine
 {
+	Renderable::MeshData::MeshData(const HMesh& mesh)
+	{
+		this->mesh = mesh;
+		isLoaded = mesh.isLoaded();
+	}
+
+	Renderable::MaterialData::MaterialData(const HMaterial& material)
+	{
+		this->material = material;
+		isLoaded = material.isLoaded();
+	}
+
 	Renderable::Renderable(const HSceneObject& parent)
-		:Component(parent), mLayer(1)
+		:Component(parent), mLayer(1), mIsRenderDataDirty(true), mActiveProxy(nullptr)
 	{
 		setName("Renderable");
 
-		mMaterials.resize(1);
-		mMatViewProjParam.resize(1);
+		mMaterialData.resize(1);
+	}
+
+	void Renderable::setMesh(HMesh mesh)
+	{
+		mMeshData = mesh;
+
+		mIsRenderDataDirty = true;
 	}
 
 	void Renderable::setNumMaterials(UINT32 numMaterials)
 	{
-		mMaterials.resize(numMaterials);
-		mMatViewProjParam.resize(numMaterials);
+		numMaterials = std::max(1U, numMaterials);
+
+		mMaterialData.resize(numMaterials);
+
+		mIsRenderDataDirty = true;
 	}
 
 	void Renderable::setMaterial(UINT32 idx, HMaterial material)
 	{
-		mMaterials[idx] = material;
-		mMatViewProjParam[idx] = material->getParamMat4("matViewProjection");
+		mMaterialData[idx] = material;
+
+		mIsRenderDataDirty = true;
 	}
 
 	void Renderable::setMaterial(HMaterial material)
@@ -33,85 +56,71 @@ namespace BansheeEngine
 		setMaterial(0, material);
 	}
 
-	void Renderable::render(RenderQueue& renderQueue, const Matrix4& viewProjMatrix)
+	void Renderable::setLayer(UINT64 layer)
 	{
-		if(mMesh == nullptr || !mMesh.isLoaded())
-			return;
+		bool isPow2 = layer && !((layer - 1) & layer);
 
-		bool hasAtLeastOneMaterial = false;
-		UINT32 idx = 0;
-		for(auto& material : mMaterials)
-		{
-			if(material != nullptr)
-			{
-				hasAtLeastOneMaterial = true;
+		if (!isPow2)
+			BS_EXCEPT(InvalidParametersException, "Invalid layer provided. Only one layer bit may be set.");
 
-				if(!material.isLoaded()) // We wait until all materials are loaded
-					return;
-			}
+		mLayer = layer;
+		mIsRenderDataDirty = true;
+	}
 
-			// TODO - Do different things depending on material and renderable settings
+	bool Renderable::_isRenderDataDirty() const
+	{ 
+		updateResourceLoadStates();
 
-			// TODO - Renderer should ensure shader is compatible with it, and it contains all the needed parameters
-			// (probably at an earlier stage). e.g. I want the user to be warned if the shader doesn't contain matViewProjection param
-			// (or should we just ignore such missing parameters?)
+		return mIsRenderDataDirty; 
+	}
 
-			mMatViewProjParam[idx].set(viewProjMatrix);
-			idx++;
+	void Renderable::updateResourceLoadStates() const
+	{
+		if (!mMeshData.isLoaded && mMeshData.mesh != nullptr && mMeshData.mesh.isLoaded())
+		{
+			mIsRenderDataDirty = true;
+			mMeshData.isLoaded = true;
 		}
 
-		if(hasAtLeastOneMaterial)
+		for (auto& materialData : mMaterialData)
 		{
-			for(UINT32 i = 0; i < mMesh->getNumSubMeshes(); i++)
+			if (!materialData.isLoaded && materialData.material != nullptr && materialData.material.isLoaded())
 			{
-				HMaterial mat;
-				if(i < mMaterials.size() && mMaterials[i] != nullptr)
-				{
-					mat = mMaterials[i];
-				}
-				else
-				{
-					for(auto& iter = mMaterials.rbegin(); iter != mMaterials.rend(); ++iter)
-					{
-						if((*iter) != nullptr)
-						{
-							mat = *iter;
-							break;
-						}
-					}
-				}
-
-				renderQueue.add(mat.getInternalPtr(), mMesh.getInternalPtr(), i, mWorldBounds[i].getCenter());
+				mIsRenderDataDirty = true;
+				materialData.isLoaded = true;
 			}
-
 		}
-		else
-			return;
 	}
 
-	void Renderable::updateWorldBounds()
+	RenderableProxy* Renderable::_createProxy(FrameAlloc* allocator) const
 	{
-		if(mMesh == nullptr || !mMesh.isLoaded())
-			return;
+		if (mMeshData.mesh == nullptr || !mMeshData.mesh.isLoaded())
+			return nullptr;
 
-		// TODO - This will likely need to be optimized in a more data friendly way
-		// (e.g. store all bounds in a single array, and same with world matrices)
-		mWorldBounds.resize(mMesh->getNumSubMeshes());
-		for(UINT32 i = 0; i < (UINT32)mWorldBounds.size(); i++)
+		RenderableProxy* proxy = bs_new<RenderableProxy>();
+
+		for (UINT32 i = 0; i < mMeshData.mesh->getNumSubMeshes(); i++)
 		{
-			mWorldBounds[i] = mMesh->getBounds(i);
-			mWorldBounds[i].transformAffine(SO()->getWorldTfrm());
-		}
-	}
+			RenderableSubProxy* subProxy = bs_new<RenderableSubProxy>();
+			subProxy->layer = mLayer;
+			subProxy->worldTransform = SO()->getWorldTfrm();
+			subProxy->mesh = &mMeshData.mesh->_getMeshProxy(i);
 
-	void Renderable::setLayer(UINT64 layer)
-	{
-		bool isPow2 = layer && !( (layer-1) & layer);
+			HMaterial material;
+			if (i < mMaterialData.size())
+				material = mMaterialData[i].material;
+			else
+				material = mMaterialData[0].material;
 
-		if(!isPow2)
-			BS_EXCEPT(InvalidParametersException, "Invalid layer provided. Only one layer bit may be set.");
+			if (material == nullptr || !material.isLoaded())
+				material = BuiltinMaterialManager::instance().createDummyMaterial();
 
-		mLayer = layer;
+			subProxy->material = material->_createProxy(allocator);
+
+			proxy->subProxies.push_back(subProxy);
+		}
+
+		return proxy;
 	}
 
 	RTTITypeBase* Renderable::getRTTIStatic()

+ 7 - 3
BansheeFBXImporter/Source/BsFBXImporter.cpp

@@ -50,8 +50,7 @@ namespace BansheeEngine
 
 		shutDownSdk(fbxManager);
 
-		MeshPtr mesh = Mesh::_createPtr(meshData);
-		mesh->setSubMeshes(subMeshes);
+		MeshPtr mesh = Mesh::_createPtr(meshData, subMeshes);
 
 		WString fileName = filePath.getWFilename(false);
 		mesh->setName(toString(fileName));
@@ -176,10 +175,15 @@ namespace BansheeEngine
 		else if(allMeshes.size() == 1)
 		{
 			subMeshes = allSubMeshes[0];
+
 			return allMeshes[0];
 		}
 		else
-			return MeshData::combine(allMeshes, allSubMeshes, subMeshes);
+		{
+			MeshDataPtr combinedMeshData = MeshData::combine(allMeshes, allSubMeshes, subMeshes);
+
+			return combinedMeshData;
+		}
 	}
 
 	MeshDataPtr FBXImporter::parseMesh(FbxMesh* mesh, Vector<SubMesh>& subMeshes, bool createTangentsIfMissing)

+ 1 - 1
BansheeGLRenderSystem/Include/BsGLRenderSystem.h

@@ -85,7 +85,7 @@ namespace BansheeEngine
 		/**
 		 * @copydoc RenderSystem::setViewport()
 		 */
-        void setViewport(const ViewportPtr& vp);
+		void setViewport(Viewport vp);
 
 		/**
 		 * @copydoc RenderSystem::bindGpuProgram()

+ 6 - 8
BansheeGLRenderSystem/Source/BsGLRenderSystem.cpp

@@ -518,21 +518,19 @@ namespace BansheeEngine
 		mRenderStats.numDepthStencilStateChanges++;
 	}
 
-	void GLRenderSystem::setViewport(const ViewportPtr& vp)
+	void GLRenderSystem::setViewport(Viewport vp)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 
-		assert(vp != nullptr);
-
 		RenderTargetPtr target;
-		target = vp->getTarget();
+		target = vp.getTarget();
 		setRenderTarget(target);
 
 		// Calculate the "lower-left" corner of the viewport
-		mViewportWidth = vp->getWidth();
-		mViewportHeight = vp->getHeight();
-		mViewportLeft = vp->getX();
-		mViewportTop = vp->getY();
+		mViewportWidth = vp.getWidth();
+		mViewportHeight = vp.getHeight();
+		mViewportLeft = vp.getX();
+		mViewportTop = vp.getY();
 
 		if (!target->requiresTextureFlipping())
 		{

+ 40 - 4
BansheeRenderer/Include/BsBansheeRenderer.h

@@ -2,6 +2,9 @@
 
 #include "BsBansheeRendererPrerequisites.h"
 #include "BsRenderer.h"
+#include "BsBounds.h"
+#include "BsCameraProxy.h"
+#include "BsMaterialProxy.h"
 
 namespace BansheeEngine
 {
@@ -9,10 +12,27 @@ namespace BansheeEngine
 	 * @brief	Default renderer for Banshee. Performs frustum culling, sorting and renders
 	 *			objects plainly according to their shaders with no fancy effects.
 	 *
-	 * TODO - Update doc when I implement this properly
 	 */
+	// TODO UNDOCUMENTED
 	class BS_BSRND_EXPORT BansheeRenderer : public Renderer
 	{
+		struct CameraData
+		{
+			CameraProxy cameraProxy;
+			RenderQueuePtr renderQueue;
+		};
+
+		struct RenderTargetData
+		{
+			RenderTargetPtr target;
+			Vector<CameraData> cameras;
+		};
+
+		struct FrameData
+		{
+			Vector<RenderTargetData> renderTargets;
+		};
+
 	public:
 		BansheeRenderer();
 		~BansheeRenderer();
@@ -27,12 +47,28 @@ namespace BansheeEngine
 		 */
 		virtual void renderAll();
 
+	private:
+		void addRenderableProxy(RenderableProxy* proxy);
+		void removeRenderableProxy(RenderableProxy* proxy);
+		void updateRenderableProxy(RenderableProxy* proxy, Matrix4 localToWorld);
+
+		void renderAllCore(std::shared_ptr<FrameData> frameData);
+
 		/**
 		 * @brief	Renders all objects visible by the provided camera.
 		 */
-		virtual void render(const HCamera& camera);
+		virtual void render(const CameraProxy& cameraProxy, const RenderQueuePtr& renderQueue);
 
-	private:
-		RenderQueue* mRenderQueue; // TODO - Move this to base class
+		void setPass(const MaterialProxy::PassData& pass);
+
+		void renderableRemoved(const HRenderable& renderable);
+
+		Vector<RenderableProxy*> mDeletedProxies;
+
+		Vector<RenderableSubProxy*> mRenderableProxies;
+		Vector<Matrix4> mWorldTransforms;
+		Vector<Bounds> mWorldBounds;
+
+		HEvent mRenderableRemovedConn;
 	};
 }

+ 277 - 101
BansheeRenderer/Source/BsBansheeRenderer.cpp

@@ -1,5 +1,6 @@
 #include "BsBansheeRenderer.h"
 #include "BsCamera.h"
+#include "BsSceneObject.h"
 #include "BsSceneManager.h"
 #include "BsRenderable.h"
 #include "BsMaterial.h"
@@ -18,19 +19,23 @@
 #include "BsDrawHelper3D.h"
 #include "BsGUIManager.h"
 #include "BsCoreThread.h"
-
 #include "BsProfilerCPU.h"
+#include "BsDrawList.h"
+
+using namespace std::placeholders;
 
 namespace BansheeEngine
 {
 	BansheeRenderer::BansheeRenderer()
 	{
-		mRenderQueue = bs_new<DefaultRenderQueue>();
+		mRenderableRemovedConn = gBsSceneManager().onRenderableRemoved.connect(std::bind(&BansheeRenderer::renderableRemoved, this, _1));
 	}
 
 	BansheeRenderer::~BansheeRenderer()
 	{
-		bs_delete(mRenderQueue);
+		assert(false); // TODO - Delete all renderable proxies
+
+		mRenderableRemovedConn.disconnect();
 	}
 
 	const String& BansheeRenderer::getName() const
@@ -39,168 +44,339 @@ namespace BansheeEngine
 		return name;
 	}
 
+	void BansheeRenderer::addRenderableProxy(RenderableProxy* proxy)
+	{
+		for (auto& subProxy : proxy->subProxies)
+		{
+			mRenderableProxies.push_back(subProxy);
+			mWorldTransforms.push_back(subProxy->worldTransform);
+			mWorldBounds.push_back(subProxy->calculateWorldBounds());
+			subProxy->markBoundsClean();
+
+			subProxy->id = (UINT32)(mRenderableProxies.size() - 1);
+			subProxy->mesh->addRenderableProxy(subProxy);
+		}
+	}
+
+	void BansheeRenderer::removeRenderableProxy(RenderableProxy* proxy)
+	{
+		for (auto& subProxy : proxy->subProxies)
+		{
+			assert(mRenderableProxies.size() > subProxy->id && subProxy->id >= 0);
+
+			if (mRenderableProxies.size() == 0)
+				mRenderableProxies.erase(mRenderableProxies.begin());
+			else
+			{
+				std::swap(mRenderableProxies[subProxy->id], mRenderableProxies.back());
+				mRenderableProxies.erase(mRenderableProxies.end() - 1);
+
+				mRenderableProxies[subProxy->id]->id = subProxy->id;
+			}
+
+			subProxy->mesh->removeRenderableProxy(subProxy);
+			bs_delete(subProxy);
+		}
+
+		bs_delete(proxy);
+	}
+
+	void BansheeRenderer::updateRenderableProxy(RenderableProxy* proxy, Matrix4 localToWorld)
+	{
+		for (auto& subProxy : proxy->subProxies)
+		{
+			subProxy->worldTransform = localToWorld;
+
+			mWorldTransforms[subProxy->id] = localToWorld;
+			mWorldBounds[subProxy->id] = subProxy->calculateWorldBounds();
+			subProxy->markBoundsClean();
+		}
+	}
+
+	void BansheeRenderer::renderableRemoved(const HRenderable& renderable)
+	{
+		if (renderable->_getActiveProxy() != nullptr)
+		{
+			mDeletedProxies.push_back(renderable->_getActiveProxy());
+		}
+	}
+
 	void BansheeRenderer::renderAll() 
 	{
 		gProfilerCPU().beginSample("renderA");
 
-		gBsSceneManager().updateRenderableBounds();
+		gBsSceneManager().updateRenderableTransforms();
 
-		CoreAccessor& coreAccessor = gCoreAccessor();
-		const Vector<HCamera>& allCameras = gBsSceneManager().getAllCameras();
+		// Remove proxies from deleted Renderable
+		for (auto& proxy : mDeletedProxies)
+		{
+			if (proxy != nullptr)
+				gCoreAccessor().queueCommand(std::bind(&BansheeRenderer::removeRenderableProxy, this, proxy));
+		}
 
-		struct RenderTargetRenderInfo
+		// Add or update Renderable proxies
+		const Vector<HRenderable>& allRenderables = gBsSceneManager().getAllRenderables();
+		for (auto& renderable : allRenderables)
 		{
-			RenderTargetPtr target;
-			Vector<HCamera> cameras;
-		};
+			if (!renderable->_isRenderDataDirty())
+			{
+				RenderableProxy* proxy = renderable->_getActiveProxy();
+
+				if (proxy != nullptr)
+					gCoreAccessor().queueCommand(std::bind(&BansheeRenderer::removeRenderableProxy, this, proxy));
+
+				proxy = renderable->_createProxy(gCoreThread().getFrameAlloc());
+				renderable->_setActiveProxy(proxy);
+
+				gCoreAccessor().queueCommand(std::bind(&BansheeRenderer::addRenderableProxy, this, proxy));
 
-		// Find all unique render targets
-		Vector<RenderTargetRenderInfo> camerasPerRenderTarget;
-		for(auto& camera : allCameras)
+				renderable->_markRenderDataClean();
+				renderable->SO()->_markRenderDataUpToDate();
+			}
+			else if (!renderable->SO()->_isRenderDataUpToDate())
+			{
+				RenderableProxy* proxy = renderable->_getActiveProxy();
+				assert(proxy != nullptr);
+
+				gCoreAccessor().queueCommand(std::bind(&BansheeRenderer::updateRenderableProxy, this, proxy, renderable->SO()->getWorldTfrm()));
+
+				renderable->SO()->_markRenderDataUpToDate();
+			}
+		}
+
+		// Create frame data
+		const Vector<HCamera>& allCameras = gBsSceneManager().getAllCameras();
+		Vector<RenderQueuePtr> renderQueues;
+
+		std::shared_ptr<FrameData> frameData = bs_shared_ptr<FrameData>();
+
+		for (auto& camera : allCameras)
 		{
 			RenderTargetPtr target = camera->getViewport()->getTarget();
-			auto findIter = std::find_if(begin(camerasPerRenderTarget), end(camerasPerRenderTarget), [&target] (const RenderTargetRenderInfo& x) { return x.target == target; });
+			auto findIter = std::find_if(begin(frameData->renderTargets), end(frameData->renderTargets), 
+				[&target](const RenderTargetData& x) { return x.target == target; });
 
-			if(findIter == camerasPerRenderTarget.end())
+			if (findIter == frameData->renderTargets.end())
 			{
-				camerasPerRenderTarget.push_back(RenderTargetRenderInfo());
-				camerasPerRenderTarget[camerasPerRenderTarget.size() - 1].target = target;
-				camerasPerRenderTarget[camerasPerRenderTarget.size() - 1].cameras.push_back(camera);
+				frameData->renderTargets.push_back(RenderTargetData());
+				RenderTargetData& renderTargetData = frameData->renderTargets.back();
+
+				renderTargetData.target = target;
+				renderTargetData.cameras.push_back(CameraData());
+
+				CameraData& camData = renderTargetData.cameras.back();
+				camData.cameraProxy = camera->_createProxy();
+				camData.renderQueue = bs_shared_ptr<DefaultRenderQueue>();
+
+				renderQueues.push_back(camData.renderQueue);
 			}
 			else
-				findIter->cameras.push_back(camera);
+			{
+				findIter->cameras.push_back(CameraData());
+
+				CameraData& camData = findIter->cameras.back();
+				camData.cameraProxy = camera->_createProxy();
+				camData.renderQueue = bs_shared_ptr<DefaultRenderQueue>();
+
+				renderQueues.push_back(camData.renderQueue);
+			}
 		}
 
 		// Sort everything based on priority
-		auto cameraComparer = [&] (const HCamera& a, const HCamera& b) { return a->getPriority() > b->getPriority(); };
-		auto renderTargetInfoComparer = [&] (const RenderTargetRenderInfo& a, const RenderTargetRenderInfo& b) { return a.target->getPriority() > b.target->getPriority(); };
-		std::sort(begin(camerasPerRenderTarget), end(camerasPerRenderTarget), renderTargetInfoComparer);
+		auto cameraComparer = [&](const CameraData& a, const CameraData& b) { return a.cameraProxy.priority > b.cameraProxy.priority; };
+		auto renderTargetInfoComparer = [&](const RenderTargetData& a, const RenderTargetData& b) { return a.target->getPriority() > b.target->getPriority(); };
+		std::sort(begin(frameData->renderTargets), end(frameData->renderTargets), renderTargetInfoComparer);
 
-		for(auto& camerasPerTarget : camerasPerRenderTarget)
+		for (auto& camerasPerTarget : frameData->renderTargets)
 		{
-			Vector<HCamera>& cameras = camerasPerTarget.cameras;
+			Vector<CameraData>& cameras = camerasPerTarget.cameras;
 
 			std::sort(begin(cameras), end(cameras), cameraComparer);
 		}
 
-		gProfilerCPU().endSample("renderA");
-		gProfilerCPU().beginSample("renderB");
+		// Populate direct draw lists
+		UINT32 idx = 0;
+		for (auto& camera : allCameras)
+		{
+			DrawList drawList;
+
+			// Get GUI render operations
+			GUIManager::instance().render(camera->getViewport(), drawList);
+
+			// Get overlay render operations
+			OverlayManager::instance().render(camera->getViewport(), drawList);
+
+			// Get debug render operations
+			DrawHelper3D::instance().render(camera, drawList);
+			DrawHelper2D::instance().render(camera, drawList);
+
+			// Get any operations from hooked up callbacks
+			const Viewport* viewportRawPtr = camera->getViewport().get();
+			auto callbacksForViewport = mRenderCallbacks[viewportRawPtr];
+
+			for (auto& callback : callbacksForViewport)
+				callback(viewportRawPtr, drawList);
+
+			RenderQueuePtr renderQueue = renderQueues[idx];
+
+			const Vector<DrawOperation>& drawOps = drawList.getDrawOperations();
+			for (auto& drawOp : drawOps)
+			{
+				// TODO - Will I need to check if materials match renderer?
+
+				renderQueue->add(drawOp.material->_createProxy(gCoreThread().getFrameAlloc()),
+					&drawOp.mesh->_getMeshProxy(drawOp.submeshIdx), drawOp.worldPosition);
+			}
+
+			idx++;
+		}
+
+		gCoreAccessor().queueCommand(std::bind(&BansheeRenderer::renderAllCore, this, frameData));
+	}
 
+	void BansheeRenderer::renderAllCore(std::shared_ptr<FrameData> frameData)
+	{
 		// Render everything, target by target
-		for(auto& camerasPerTarget : camerasPerRenderTarget)
+		for (auto& renderTargetData : frameData->renderTargets)
 		{
-			RenderTargetPtr target = camerasPerTarget.target;
-			const Vector<HCamera>& cameras = camerasPerTarget.cameras;
+			RenderTargetPtr target = renderTargetData.target;
+			Vector<CameraData>& cameraData = renderTargetData.cameras;
 
-			coreAccessor.beginRender();
+			RenderSystem::instance().beginFrame();
 
-			for(auto& camera : cameras)
+			for(auto& data : cameraData)
 			{
-				ViewportPtr viewport = camera->getViewport();
-				coreAccessor.setViewport(viewport);
+				Viewport& viewport = data.cameraProxy.viewport;
+				RenderSystem::instance().setViewport(viewport);
 
 				UINT32 clearBuffers = 0;
-				if(viewport->getRequiresColorClear())
+				if(viewport.getRequiresColorClear())
 					clearBuffers |= FBT_COLOR;
 
-				if(viewport->getRequiresDepthClear())
+				if(viewport.getRequiresDepthClear())
 					clearBuffers |= FBT_DEPTH;
 
-				if(viewport->getRequiresStencilClear())
+				if(viewport.getRequiresStencilClear())
 					clearBuffers |= FBT_STENCIL;
 
 				if(clearBuffers != 0)
-					coreAccessor.clearViewport(clearBuffers, viewport->getClearColor(), viewport->getClearDepthValue(), viewport->getClearStencilValue());
+					RenderSystem::instance().clearViewport(clearBuffers, viewport.getClearColor(), viewport.getClearDepthValue(), viewport.getClearStencilValue());
 
-				render(camera);
+				render(data.cameraProxy, data.renderQueue);
 			}
 
-			coreAccessor.endRender();
-			coreAccessor.swapBuffers(target);
+			RenderSystem::instance().endFrame();
+			RenderSystem::instance().swapBuffers(target);
 		}
-
-		gProfilerCPU().endSample("renderB");
 	}
 
-	void BansheeRenderer::render(const HCamera& camera) 
+	void BansheeRenderer::render(const CameraProxy& cameraProxy, const RenderQueuePtr& renderQueue) 
 	{
-		gProfilerCPU().beginSample("renderC");
+		RenderSystem& rs = RenderSystem::instance();
 
-		Vector<HRenderable> allRenderables;
-		
-		if(!camera->getIgnoreSceneRenderables())
-			allRenderables = gBsSceneManager().getVisibleRenderables(camera);
+		if (!cameraProxy.ignoreSceneRenderables)
+		{
+			// TODO - Do frustum culling
+			for (auto& renderableProxy : mRenderableProxies)
+			{
+				// TODO - Apply world-view-proj matrix
 
-		CoreAccessor& coreAccessor = gCoreAccessor();
-		coreAccessor.setViewport(camera->getViewport());
+				renderQueue->add(renderableProxy->material, renderableProxy->mesh, mWorldBounds[renderableProxy->id].getSphere().getCenter());
+				
+			}
+		}
 
-		Matrix4 projMatrixCstm = camera->getProjectionMatrix();
-		Matrix4 viewMatrixCstm = camera->getViewMatrix();
+		Matrix4 projMatrixCstm = cameraProxy.projMatrix;
+		Matrix4 viewMatrixCstm = cameraProxy.viewMatrix;
 
 		Matrix4 viewProjMatrix = projMatrixCstm * viewMatrixCstm;
 
-		mRenderQueue->clear();
-
-		gProfilerCPU().endSample("renderC");
-		gProfilerCPU().beginSample("renderD");
+		renderQueue->sort();
+		const Vector<SortedRenderOp>& sortedROps = renderQueue->getSortedRenderOps();
 
-		// Get scene render operations
-		for(auto iter = allRenderables.begin(); iter != allRenderables.end(); ++iter)
+		for(auto iter = sortedROps.begin(); iter != sortedROps.end(); ++iter)
 		{
-			(*iter)->render(*mRenderQueue, viewProjMatrix);
-		}
-
-		gProfilerCPU().endSample("renderD");
-		gProfilerCPU().beginSample("renderE");
-
-		// Get GUI render operations
-		GUIManager::instance().render(camera->getViewport(), *mRenderQueue);
-
-		// Get overlay render operations
-		OverlayManager::instance().render(camera->getViewport(), *mRenderQueue);
-
-		// Get debug render operations
-		DrawHelper3D::instance().render(camera, *mRenderQueue);
-		DrawHelper2D::instance().render(camera, *mRenderQueue);
-
-		gProfilerCPU().endSample("renderE");
-		gProfilerCPU().beginSample("renderF");
+			const RenderOperation& renderOp = *iter->baseOperation;
+			const MaterialProxy& materialProxy = renderOp.material;
 
-		// Get any operations from hooked up callbacks
-		const Viewport* viewportRawPtr = camera->getViewport().get();
-		auto callbacksForViewport = mRenderCallbacks[viewportRawPtr];
+			setPass(materialProxy.passes[iter->passIdx]);
 
-		for(auto& callback : callbacksForViewport)
-			callback(viewportRawPtr, *mRenderQueue);
+			// TODO - Call rs.render() - I need to refactor it so it accepts vertex and index data instead of mesh,
+			// but I need to find a way to notify mesh when it is used on GPU. (Notify the proxy?)
 
-		// TODO - Material queue is completely ignored
-		mRenderQueue->sort();
-		const Vector<SortedRenderOp>& sortedROps =  mRenderQueue->getSortedRenderOps();
+			SubMesh subMesh = renderOp.mesh->getSubMesh();
+			//rs.render(renderOp.mesh->getVertexData(), renderOp.mesh->getIndexBuffer(), subMesh.indexOffset, subMesh.indexCount, true, subMesh.drawOp);
+		}
+	}
 
-		gProfilerCPU().endSample("renderF");
+	void BansheeRenderer::setPass(const MaterialProxy::PassData& pass)
+	{
+		RenderSystem& rs = RenderSystem::instance();
 
-		for(auto iter = sortedROps.begin(); iter != sortedROps.end(); ++iter)
+		if (pass.vertexProg)
 		{
-			gProfilerCPU().beginSample("renderG");
-
-			const RenderOperation& renderOp = *iter->baseOperation;
-			MaterialPtr material = renderOp.material;
-
-			gProfilerCPU().endSample("renderG");
-			gProfilerCPU().beginSample("renderH");
+			rs.bindGpuProgram(pass.vertexProg);
+			rs.bindGpuParams(GPT_VERTEX_PROGRAM, *pass.vertexProgParams);
+		}
+		else
+			rs.unbindGpuProgram(GPT_VERTEX_PROGRAM);
 
-			PassPtr pass = material->getPass(iter->passIdx);
-			PassParametersPtr paramsPtr = material->getPassParameters(iter->passIdx);
+		if (pass.fragmentProg)
+		{
+			rs.bindGpuProgram(pass.fragmentProg);
+			rs.bindGpuParams(GPT_FRAGMENT_PROGRAM, *pass.geometryProgParams);
+		}
+		else
+			rs.unbindGpuProgram(GPT_FRAGMENT_PROGRAM);
 
-			coreAccessor.setPass(pass, paramsPtr);
+		if (pass.geometryProg)
+		{
+			rs.bindGpuProgram(pass.geometryProg);
+			rs.bindGpuParams(GPT_GEOMETRY_PROGRAM, *pass.geometryProgParams);
+		}
+		else
+			rs.unbindGpuProgram(GPT_GEOMETRY_PROGRAM);
 
-			gProfilerCPU().endSample("renderH");
-			gProfilerCPU().beginSample("renderI");
+		if (pass.hullProg)
+		{
+			rs.bindGpuProgram(pass.hullProg);
+			rs.bindGpuParams(GPT_HULL_PROGRAM, *pass.hullProgParams);
+		}
+		else
+			rs.unbindGpuProgram(GPT_HULL_PROGRAM);
 
-			const SubMesh& subMesh = renderOp.mesh->getSubMesh(renderOp.submeshIdx);
-			coreAccessor.render(renderOp.mesh, subMesh.indexOffset, subMesh.indexCount, true, subMesh.drawOp);
+		if (pass.domainProg)
+		{
+			rs.bindGpuProgram(pass.domainProg);
+			rs.bindGpuParams(GPT_DOMAIN_PROGRAM, *pass.domainProgParams);
+		}
+		else
+			rs.unbindGpuProgram(GPT_DOMAIN_PROGRAM);
 
-			gProfilerCPU().endSample("renderI");
+		if (pass.computeProg)
+		{
+			rs.bindGpuProgram(pass.computeProg);
+			rs.bindGpuParams(GPT_COMPUTE_PROGRAM, *pass.computeProgParams);
 		}
+		else
+			rs.unbindGpuProgram(GPT_COMPUTE_PROGRAM);
+
+		// TODO - Try to limit amount of state changes, if previous state is already the same
+
+		// Set up non-texture related pass settings
+		if (pass.blendState != nullptr)
+			rs.setBlendState(pass.blendState.getInternalPtr());
+		else
+			rs.setBlendState(BlendState::getDefault());
+
+		if (pass.depthStencilState != nullptr)
+			rs.setDepthStencilState(pass.depthStencilState.getInternalPtr(), pass.stencilRefValue);
+		else
+			rs.setDepthStencilState(DepthStencilState::getDefault(), pass.stencilRefValue);
+
+		if (pass.rasterizerState != nullptr)
+			rs.setRasterizerState(pass.rasterizerState.getInternalPtr());
+		else
+			rs.setRasterizerState(RasterizerState::getDefault());
 	}
 }

+ 6 - 7
BansheeSceneManager/Include/BsBansheeSceneManager.h

@@ -18,21 +18,20 @@ namespace BansheeEngine
 		~BansheeSceneManager() {}
 
 		/**
-		 * @brief	Returns a list of all cameras in the scene.
+		 * @copydoc	SceneManager::getAllCameras
 		 */
 		const Vector<HCamera>& getAllCameras() const { return mCachedCameras; }
 
 		/**
-		 * @brief	Returns a list of all renderables visible by the provided camera.
+		 * @copydoc	SceneManager::getAllRenderables
 		 */
-		Vector<HRenderable> getVisibleRenderables(const HCamera& camera) const;
+		const Vector<HRenderable>& getAllRenderables() const { return mRenderables; }
 
 		/**
-		 * @brief	Update world bounds of all renderables. This should be called
-		 *			at the end or beginning of every frame to ensure bounds are kept
-		 *			up to date.
+		 * @copydoc	SceneManager
 		 */
-		void updateRenderableBounds();
+		void updateRenderableTransforms();
+
 	private:
 		/**
 		 * @brief	Called by scene objects whenever a new component is added to the scene.

+ 9 - 29
BansheeSceneManager/Source/BsBansheeSceneManager.cpp

@@ -7,39 +7,17 @@
 
 namespace BansheeEngine
 {
-	Vector<HRenderable> BansheeSceneManager::getVisibleRenderables(const HCamera& camera) const
+	void BansheeSceneManager::updateRenderableTransforms()
 	{
-		// TODO - Cull invisible objects
+		// TODO - Consider a way to make the update faster. Either do it concurrently or
+		// consider organizing renderable matrices in an array for quicker updates
+		//   - I could keep everything in a sequential array but deal with dynamic elements
+		//     but putting them in a slow, normal array. Once the number of dynamic elements
+		//	   goes over some number the hierarchy is re-optimized.
 
-		Vector<HRenderable> renderables;
-
-		Stack<HSceneObject> todo;
-		todo.push(mRootNode);
-
-		while(!todo.empty())
-		{
-			HSceneObject currentGO = todo.top();
-			todo.pop();
-
-			HRenderable curRenderable = currentGO->getComponent<Renderable>();
-			if(curRenderable != nullptr)
-			{
-				if((curRenderable->getLayer() & camera->getLayers()) != 0)
-					renderables.push_back(curRenderable);
-			}
-
-			for(UINT32 i = 0; i < currentGO->getNumChildren(); i++)
-				todo.push(currentGO->getChild(i));
-		}
-
-		return renderables;
-	}
-
-	void BansheeSceneManager::updateRenderableBounds()
-	{
 		for(auto& iter : mRenderables)
 		{
-			iter->updateWorldBounds();
+			iter->SO()->updateTransformsIfDirty();
 		}
 	}
 
@@ -86,6 +64,8 @@ namespace BansheeEngine
 			auto findIter = std::find(mRenderables.begin(), mRenderables.end(), renderable);
 			if(findIter != mRenderables.end())
 				mRenderables.erase(findIter);
+
+			onRenderableRemoved(renderable);
 		}
 	}
 }

+ 2 - 0
BansheeUtility/BansheeUtility.vcxproj

@@ -245,6 +245,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="Source\BsBounds.cpp" />
     <ClCompile Include="Source\BsTaskScheduler.cpp" />
     <ClCompile Include="Source\BsThreadPool.cpp" />
     <ClCompile Include="Source\BsAABox.cpp" />
@@ -268,6 +269,7 @@
     <ClCompile Include="Source\Win32\BsFileSystem.cpp" />
     <ClCompile Include="Source\Win32\BsTimer.cpp" />
     <ClInclude Include="Include\BsAny.h" />
+    <ClInclude Include="Include\BsBounds.h" />
     <ClInclude Include="Include\BsEvent.h" />
     <ClInclude Include="Include\BsSpinLock.h" />
     <ClInclude Include="Include\BsTaskScheduler.h" />

+ 6 - 0
BansheeUtility/BansheeUtility.vcxproj.filters

@@ -240,6 +240,9 @@
     <ClInclude Include="Include\BsBitmapWriter.h">
       <Filter>Header Files\Debug</Filter>
     </ClInclude>
+    <ClInclude Include="Include\BsBounds.h">
+      <Filter>Header Files\Math</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsThreadPool.cpp">
@@ -377,5 +380,8 @@
     <ClCompile Include="Source\BsBitmapWriter.cpp">
       <Filter>Source Files\Debug</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsBounds.cpp">
+      <Filter>Source Files\Math</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 71 - 0
BansheeUtility/Include/BsBounds.h

@@ -0,0 +1,71 @@
+#pragma once
+
+#include "BsPrerequisitesUtil.h"
+#include "BsVector3.h"
+#include "BsAABox.h"
+#include "BsSphere.h"
+#include "BsMatrix4.h"
+
+namespace BansheeEngine
+{
+	/**
+	 * @brief	Bounds represented by an axis aligned box and a sphere.
+	 */
+	class BS_UTILITY_EXPORT Bounds
+	{
+	public:
+		Bounds();
+		Bounds(const AABox& box, const Sphere& sphere);
+		~Bounds() { }
+
+		/**
+		 * @brief	Returns the axis aligned box representing the bounds.
+		 */
+		const AABox& getBox() const { return mBox; }
+
+		/**
+		 * @brief	Returns the sphere representing the bounds.
+		 */
+		const Sphere& getSphere() const { return mSphere; }
+
+		/**
+		 * @brief	Updates the bounds by setting the new bounding box and sphere.
+		 */
+		void setBounds(const AABox& box, const Sphere& sphere);
+
+		/**
+		 * @brief	Merges the two bounds, creating a new bounds that encapsulates 
+		 *			them both.
+		 */
+		void merge(const Bounds& rhs);
+
+		/**
+		* @brief	Expands the bounds so it includes the provided point.
+		*/
+		void merge(const Vector3& point);
+
+		/**
+		 * @brief	Transforms the bounds by the given matrix.
+		 *
+		 * @note	As the resulting box will no longer be axis aligned, an axis align box
+		 * 			is instead created by encompassing the transformed oriented bounding box.
+		 * 			Retrieving the value as an actual OBB would provide a tighter fit.
+		 */
+		void transform(const Matrix4& matrix);
+
+		/**
+		 * @brief	Transforms the bounds by the given matrix.
+		 *
+		 * @note	As the resulting box will no longer be axis aligned, an axis align box
+		 * 			is instead created by encompassing the transformed oriented bounding box.
+		 * 			Retrieving the value as an actual OBB would provide a tighter fit.
+		 *
+		 *			Provided matrix must be affine.
+		 */
+		void transformAffine(const Matrix4& matrix);
+
+	protected:
+		AABox mBox;
+		Sphere mSphere;
+	};
+}

+ 17 - 0
BansheeUtility/Include/BsSphere.h

@@ -41,6 +41,23 @@ namespace BansheeEngine
          */
         void setCenter(const Vector3& center) { mCenter = center; }
 
+		/**
+		 * @brief	Merges the two spheres, creating a new
+		 * 			sphere that encapsulates them both.
+		 */
+		void merge(const Sphere& rhs);
+
+		/**
+		 * @brief	Expands the sphere so it includes
+		 * 			the provided point.
+		 */
+		void merge(const Vector3& point);
+
+		/**
+		 * @brief	Transforms the sphere by the given matrix.
+		 */
+		void transform(const Matrix4& matrix);
+
 		/**
 		 * @brief	Returns whether or not this sphere contains the provided point.
 		 */

+ 1 - 1
BansheeUtility/Include/BsTime.h

@@ -8,7 +8,7 @@ namespace BansheeEngine
 	/**
 	 * @brief	Manages all time related functionality.
 	 * 			
-	 * @note	Not thread safe.
+	 * @note	Sim thread only 
 	 */
 	class BS_UTILITY_EXPORT Time : public Module<Time>
 	{

+ 2 - 0
BansheeUtility/Include/Win32/BsTimerImp.h

@@ -14,6 +14,8 @@ namespace BansheeEngine
 {
 	/**
 	 * @brief	Timer class used for querying high precision timers.
+	 *
+	 * @note	Not thread safe.
 	 */
 	class BS_UTILITY_EXPORT Timer
     {

+ 45 - 0
BansheeUtility/Source/BsBounds.cpp

@@ -0,0 +1,45 @@
+#include "BsBounds.h"
+#include "BsRay.h"
+#include "BsPlane.h"
+#include "BsSphere.h"
+
+namespace BansheeEngine
+{
+	Bounds::Bounds()
+	{ }
+
+	Bounds::Bounds(const AABox& box, const Sphere& sphere)
+		:mBox(box), mSphere(sphere)
+	{ }
+
+	void Bounds::setBounds(const AABox& box, const Sphere& sphere)
+	{
+		mBox = box;
+		mSphere = sphere;
+	}
+
+	void Bounds::merge(const Bounds& rhs)
+	{
+		mBox.merge(rhs.mBox);
+		mSphere.merge(rhs.mSphere);
+	}
+
+	void Bounds::merge(const Vector3& point)
+	{
+		mBox.merge(point);
+		mSphere.merge(point);
+	}
+
+	void Bounds::transform(const Matrix4& matrix)
+	{
+		mBox.transform(matrix);
+		mSphere.transform(matrix);
+	}
+
+	void Bounds::transformAffine(const Matrix4& matrix)
+	{
+		mBox.transformAffine(matrix);
+		mSphere.transform(matrix);
+	}
+}
+

+ 31 - 0
BansheeUtility/Source/BsSphere.cpp

@@ -5,6 +5,37 @@
 
 namespace BansheeEngine
 {
+	void Sphere::merge(const Sphere& rhs)
+	{
+		Vector3 newCenter = (mCenter + rhs.mCenter) * 0.5f;
+
+		float newRadiusA = newCenter.distance(mCenter) + getRadius();
+		float newRadiusB = newCenter.distance(rhs.mCenter) + rhs.getRadius();
+		
+		mCenter = newCenter;
+		mRadius = std::max(newRadiusA, newRadiusB);
+	}
+
+	void Sphere::merge(const Vector3& point)
+	{
+		Vector3 newCenter = (mCenter + point) * 0.5f;
+
+		float newRadiusA = newCenter.distance(mCenter) + getRadius();
+		float newRadiusB = newCenter.distance(point);
+
+		mCenter = newCenter;
+		mRadius = std::max(newRadiusA, newRadiusB);
+	}
+
+	void Sphere::transform(const Matrix4& matrix)
+	{
+		Vector3 edge = mCenter + Vector3::UNIT_X * mRadius;
+		mCenter = matrix.multiply3x4(mCenter);
+		edge = matrix.multiply3x4(edge);
+
+		mRadius = mCenter.distance(edge);
+	}
+
 	std::pair<bool, float> Sphere::intersects(const Ray& ray, bool discardInside) const
 	{
 		const Vector3& raydir = ray.getDirection();

+ 0 - 37
RenderOperation.txt

@@ -1,37 +0,0 @@
-Since DrawHelper needs to queue render commands together with scene objects (in order for transparency to work okay), I will need to implement the RenderOperation approach I thought about earlier.
- Rename current RenderOperation to SubMeshData
- Real render operations contains SubMeshData + layer (can be filtered per-camera) + queue (each mesh has a queue and another queue by camera) + Pass
- (Remove Camera->rendersSceneObjects and replace it with layer)
- (Make sure to set up preset queues, like opaque, transparent, etc)
-
- Then I can hook up GUIManager, OverlayManager and DrawHelper with a callback that is used by Renderer to retrieve their operations
- Attempt to move all sorting (including by render target) out of forward renderer and into an overridable sorter class
-  - Create a hash list with key(containing type, queue, layer, etc.) used for sorting
-
-  Add "materialGroup" to material. It can be used for sorting similar materials together, instead of using some automatic way of determining it.
-
-  Issues with my render operation system:
- Sorting by depth is impossible because I don't provide any position info with my RenderOperation
-
- For each frame I will need to calculate world bounds and world position. I cannot do it each time I retrieve a RenderOperation so it should be cached somewhere and reused throughout the frame.
- - Unity keeps it with Renderable
-   - What happens when the Mesh resource is updated?
- - How do I do it for non-renerables though?
-
- ---------------------
-
- RenderOpSorter:
- - (Before we send RenderOps to the sorter we first filter them by camera)
- - Accepts parameters whether to sort back-to-front, front-to-back or ignore depth (depth ignored with skybox and overlay)
- - Another parameter is whether to sort by pass (transparent ops can't be sorted by pass)
- - Then we sort:
-  - If back to front
-    - We sort by depth and that's it. We could also sort by material by that only makes sense if two elements have exact same depth which will almost never happen
-  - If front to back
-    - Sort by material first. We call materialSimilarity() method which returns lesser value depending how similar two materials are. We do a pass over all unsorted materials and if similarity is below some threshold we add it to the current bucket. If there are no more similar materials we create a new bucket.
-    - Within bucket we sort by similarity as well (as the elements are added)
-    - Then finally we sort the buckets by depth front to back
-  - No depth
-   - Same as front to back, without the depth sort
-
- - Sorter should operate directly on provided render op array

+ 115 - 0
Renderer.txt

@@ -0,0 +1,115 @@
+To get it to compile:
+ - Add dummy material that will be used when material is not loaded
+ - Actually implement core render methods in Renderer
+ - Go through all changes on commit and see if anything else needs doing
+
+Next stage:
+ - Track material changes
+   - Figure out how to update material data buffers only when material actually changes (shader or parameters)
+   - Should each object have their own set of buffers instead of just updating material ones per frame? Probably.
+     - Although I should still have an option to use a shared block that isn't per object.
+ - Add sort type, priority and separable pass options to Shader (and its RTTI)
+ - Implement RenderQueue sorting with support for sort type, priority and separable pass
+ - Document elements marked with TODO UNDOCUMENTED
+ - Add Renderer <-> Material interface matching
+   - Allow parameter blocks to be specified as one-time, per-frame, per-object, etc.
+ - Actually add frustum culling
+
+Finally
+ - Refactor/rename everything so it makes more sense. Possibly lay out a design diagram.
+ - Get rid of Camera::getIgnoreSceneRenderables it can be doing using layers
+ - Delete RenderOperation as I don't think I use it anymore
+
+
+-----------------------------------------
+
+While I am  on this also consider working on how will parameter matching between Renderer and Material work (e.g. when rendering with 
+shadows or lighting the renderer will expect materials to have certain parameters used for those effects)
+ - Make it a separate GPU param buffer? RendererOneTime, RendererPerFrame, RendererPerObject
+
+
+Each renderer can specify which Renderable types it supports.
+ - Renderable can have various options like shadow, no shadow, animation, etc.
+ - Together those options result in an Enum describing the type of Renderable
+
+Each renderer can specify a set of parameters it needs from a material, per Renderable type
+ - e.g. "Matrix4 viewProjTfrm" for BasicRenderable type
+
+When a Material is hooked up to a Renderable is will check if the Material has the required parameters.
+ - If not that object will be drawn using a dummy (most basic) shader.
+ - Optionally the parameters are grouped into parameter blocks e.g. RendererOneTime, RendererPerFrame, RendererPerObject.
+ - If a parameter block is detected by the renderer it will only update those parameters once when they are needed, and reuse
+   them in all materials. If no parameter block is detected the parameters will be updated on all objects whenever it is changed.
+ - I will potentially need to add parameter block semantic to Shader in order to make the user able to specify which blocks
+   are for the renderer. (And so that Material knows not to create those buffers manually)
+
+
+   ---------------------------
+
+Just notes for later potentially:
+ - I can only update entire Mesh at once. 
+ - I keep bounds for the entire mesh and not per-submesh
+ - I don't serialize bounds and they are recalculated whenever a mesh is loaded
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+OLD:
+
+
+
+Since DrawHelper needs to queue render commands together with scene objects (in order for transparency to work okay), I will need to implement the RenderOperation approach I thought about earlier.
+ Rename current RenderOperation to SubMeshData
+ Real render operations contains SubMeshData + layer (can be filtered per-camera) + queue (each mesh has a queue and another queue by camera) + Pass
+ (Remove Camera->rendersSceneObjects and replace it with layer)
+ (Make sure to set up preset queues, like opaque, transparent, etc)
+
+ Then I can hook up GUIManager, OverlayManager and DrawHelper with a callback that is used by Renderer to retrieve their operations
+ Attempt to move all sorting (including by render target) out of forward renderer and into an overridable sorter class
+  - Create a hash list with key(containing type, queue, layer, etc.) used for sorting
+
+  Add "materialGroup" to material. It can be used for sorting similar materials together, instead of using some automatic way of determining it.
+
+  Issues with my render operation system:
+ Sorting by depth is impossible because I don't provide any position info with my RenderOperation
+
+ For each frame I will need to calculate world bounds and world position. I cannot do it each time I retrieve a RenderOperation so it should be cached somewhere and reused throughout the frame.
+ - Unity keeps it with Renderable
+   - What happens when the Mesh resource is updated?
+ - How do I do it for non-renerables though?
+
+ ---------------------
+
+ RenderOpSorter:
+ - (Before we send RenderOps to the sorter we first filter them by camera)
+ - Accepts parameters whether to sort back-to-front, front-to-back or ignore depth (depth ignored with skybox and overlay)
+ - Another parameter is whether to sort by pass (transparent ops can't be sorted by pass)
+ - Then we sort:
+  - If back to front
+    - We sort by depth and that's it. We could also sort by material by that only makes sense if two elements have exact same depth which will almost never happen
+  - If front to back
+    - Sort by material first. We call materialSimilarity() method which returns lesser value depending how similar two materials are. We do a pass over all unsorted materials and if similarity is below some threshold we add it to the current bucket. If there are no more similar materials we create a new bucket.
+    - Within bucket we sort by similarity as well (as the elements are added)
+    - Then finally we sort the buckets by depth front to back
+  - No depth
+   - Same as front to back, without the depth sort
+
+ - Sorter should operate directly on provided render op array