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

RenderQueue and improved RenderOperation design and handling

Marko Pintera 12 лет назад
Родитель
Сommit
8ae8dc6752

+ 0 - 3
BansheeEngine/BansheeEngine.vcxproj

@@ -228,7 +228,6 @@
   <ItemGroup>
     <ClInclude Include="Include\BsApplication.h" />
     <ClInclude Include="Include\BsDebugDraw.h" />
-    <ClInclude Include="Include\BsDefaultRendererSort.h" />
     <ClInclude Include="Include\BsDragAndDropManager.h" />
     <ClInclude Include="Include\BsEngineGUI.h" />
     <ClInclude Include="Include\BsGUIArea.h" />
@@ -266,7 +265,6 @@
     <ClInclude Include="Include\BsGUIWidget.h" />
     <ClInclude Include="Include\BsImageSprite.h" />
     <ClInclude Include="Include\BsRendererSort.h" />
-    <ClInclude Include="Include\BsRenderOperation.h" />
     <ClInclude Include="Include\BsSceneManager.h" />
     <ClInclude Include="Include\BsGUIScrollArea.h" />
     <ClInclude Include="Include\BsSprite.h" />
@@ -316,7 +314,6 @@
     <ClCompile Include="Source\BsGUIWindowFrame.cpp" />
     <ClCompile Include="Source\BsGUIWindowMover.cpp" />
     <ClCompile Include="Source\BsImageSprite.cpp" />
-    <ClCompile Include="Source\BsDefaultRendererSort.cpp" />
     <ClCompile Include="Source\BsSceneManager.cpp" />
     <ClCompile Include="Source\BsGUIScrollArea.cpp" />
     <ClCompile Include="Source\BsSprite.cpp" />

+ 0 - 9
BansheeEngine/BansheeEngine.vcxproj.filters

@@ -198,15 +198,9 @@
     <ClInclude Include="Include\BsGUIViewport.h">
       <Filter>Header Files\GUI</Filter>
     </ClInclude>
-    <ClInclude Include="Include\BsRenderOperation.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
     <ClInclude Include="Include\BsRendererSort.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="Include\BsDefaultRendererSort.h">
-      <Filter>Header Files</Filter>
-    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\BsGUIElement.cpp">
@@ -350,8 +344,5 @@
     <ClCompile Include="Source\BsGUIViewport.cpp">
       <Filter>Source Files\GUI</Filter>
     </ClCompile>
-    <ClCompile Include="Source\BsDefaultRendererSort.cpp">
-      <Filter>Source Files</Filter>
-    </ClCompile>
   </ItemGroup>
 </Project>

+ 0 - 13
BansheeEngine/Include/BsDefaultRendererSort.h

@@ -1,13 +0,0 @@
-#pragma once
-
-#include "BsPrerequisites.h"
-#include "BsRendererSort.h"
-
-namespace BansheeEngine 
-{
-	class BS_EXPORT DefaultRendererSort : public RendererSort
-	{
-	public:
-		CM::Vector<SortedRenderOp>::type sort(const HCamera& camera, const CM::Vector<RenderOperation>::type& renderOperations, DepthSortOrder sortOrder, bool allowSortByPass);
-	};
-}

+ 1 - 3
BansheeEngine/Include/BsGUIManager.h

@@ -48,7 +48,7 @@ namespace BansheeEngine
 		void unregisterWidget(GUIWidget* widget);
 
 		void update();
-		void render(CM::ViewportPtr& target, CM::CoreAccessor& coreAccessor);
+		void render(CM::ViewportPtr& target, CM::RenderQueue& renderQueue) const;
 
 		void setCaretColor(const CM::Color& color) { mCaretColor = color; updateCaretTexture(); }
 		void setTextSelectionColor(const CM::Color& color) { mTextSelectionColor = color; updateTextSelectionTexture(); }
@@ -104,8 +104,6 @@ namespace BansheeEngine
 		boost::signals::connection mWindowLostFocusConn;
 		boost::signals::connection mWindowMovedOrResizedConn;
 
-		void renderMesh(const CM::HMesh& mesh, const CM::HMaterial& material, const CM::Matrix4& tfrm, CM::ViewportPtr& target, CM::CoreAccessor& coreAccessor);
-
 		void updateMeshes();
 		void updateCaretTexture();
 		void updateTextSelectionTexture();

+ 1 - 1
BansheeEngine/Include/BsOverlay.h

@@ -24,7 +24,7 @@ namespace BansheeEngine
 		 */
 		void initialize(CM::Viewport* target);
 
-		virtual void render(CM::CoreAccessor& coreAccessor) const = 0;
+		virtual void render(CM::RenderQueue& renderQueue) const = 0;
 		virtual void update() {}
 
 		CM::Viewport* getTarget() const { return mRenderTarget; }

+ 1 - 1
BansheeEngine/Include/BsOverlayManager.h

@@ -22,7 +22,7 @@ namespace BansheeEngine
 		};
 
 	public:
-		void render(CM::ViewportPtr& target, CM::CoreAccessor& coreAccessor) const;
+		void render(CM::ViewportPtr& target, CM::RenderQueue& renderQueue) const;
 
 	private:
 		friend class Overlay;

+ 0 - 11
BansheeEngine/Include/BsPrerequisites.h

@@ -68,9 +68,6 @@ namespace BansheeEngine
 	class Renderable;
 	class Camera;
 
-	struct RenderOperation;
-	class RendererSort;
-
 	typedef std::shared_ptr<TextSprite> TextSpritePtr;
 	typedef std::shared_ptr<SpriteTexture> SpriteTexturePtr;
 	typedef std::shared_ptr<Overlay> OverlayPtr;
@@ -86,14 +83,6 @@ namespace BansheeEngine
 		TID_Camera = 30000,
 		TID_Renderable = 30001
 	};
-
-	enum class RenderQueue
-	{
-		Skybox = 10000,
-		Opaque = 11000,
-		Transparent = 12000,
-		Overlay = 13000
-	};
 }
 
 namespace BS = BansheeEngine;

+ 0 - 18
BansheeEngine/Include/BsRenderOperation.h

@@ -1,18 +0,0 @@
-#pragma once
-
-#include "BsPrerequisites.h"
-#include "CmRenderOpMesh.h"
-#include "CmVector3.h"
-
-namespace BansheeEngine 
-{
-	struct BS_EXPORT RenderOperation
-	{
-		RenderOperation()
-		{ }
-
-		CM::HMaterial material;
-		CM::RenderOpMesh meshData;
-		CM::Vector3 worldPosition;
-	};
-}

+ 3 - 8
BansheeEngine/Include/BsRenderable.h

@@ -1,7 +1,6 @@
 #pragma once
 
 #include "BsPrerequisites.h"
-#include "BsRenderOperation.h"
 #include "CmComponent.h"
 #include "CmAABox.h"
 
@@ -15,15 +14,11 @@ namespace BansheeEngine
 		void setMaterial(CM::UINT32 idx, CM::HMaterial material);
 		void setLayer(CM::UINT64 layer);
 
-		CM::UINT32 getNumRenderOperations() const;
-
-		/**
-		* @note  This method relies on getNumRenderOperations() being called and ensuring that idx doesn't exceed
-		* the number returned by that method
-		*/
-		RenderOperation getRenderOperation(CM::UINT32 idx) const;
 		CM::UINT64 getLayer() const { return mLayer; }
+		CM::UINT32 getNumMaterials() const { return (CM::UINT32)mMaterials.size(); }
+		CM::HMaterial& getMaterial(CM::UINT32 idx) { return mMaterials[idx]; }
 
+		void render(CM::RenderQueue& renderQueue);
 		void updateWorldBounds();
 	private:
 		CM::HMesh mMesh;

+ 0 - 30
BansheeEngine/Source/BsDefaultRendererSort.cpp

@@ -1,30 +0,0 @@
-#include "BsDefaultRendererSort.h"
-#include "BsRenderOperation.h"
-#include "CmMaterial.h"
-
-using namespace CamelotFramework;
-
-namespace BansheeEngine
-{
-	Vector<SortedRenderOp>::type DefaultRendererSort::sort(const HCamera& camera, const Vector<RenderOperation>::type& renderOperations, DepthSortOrder sortOrder, bool allowSortByPass)
-	{
-		Vector<SortedRenderOp>::type sortedOps;
-
-		// Just pass-through for now
-		for(auto& renderOp : renderOperations)
-		{
-			UINT32 numPasses = renderOp.material->getNumPasses();
-			for(UINT32 i = 0; i < numPasses; i++)
-			{
-				sortedOps.push_back(SortedRenderOp(renderOp));
-
-				SortedRenderOp& sortedOp = sortedOps.back();
-				sortedOp.passIdx = i;
-			}
-		}
-
-		// TODO - Actually do some sorting
-
-		return sortedOps;
-	}
-}

+ 19 - 34
BansheeEngine/Source/BsGUIManager.cpp

@@ -17,6 +17,7 @@
 #include "CmInput.h"
 #include "CmPass.h"
 #include "CmDebug.h"
+#include "CmRenderQueue.h"
 #include "BsGUIInputCaret.h"
 #include "BsGUIInputSelection.h"
 #include "BsDragAndDropManager.h"
@@ -182,27 +183,40 @@ namespace BansheeEngine
 		updateMeshes();
 	}
 
-	void GUIManager::render(ViewportPtr& target, CoreAccessor& coreAccessor)
+	void GUIManager::render(ViewportPtr& target, CM::RenderQueue& renderQueue) const
 	{
 		auto findIter = mCachedGUIData.find(target.get());
 
 		if(findIter == mCachedGUIData.end())
 			return;
 
-		coreAccessor.setViewport(target);
-
-		GUIRenderData& renderData = findIter->second;
+		const GUIRenderData& renderData = findIter->second;
 
 		// Render the meshes
 		if(mSeparateMeshesByWidget)
 		{
+			// TODO - Possible optimization. I currently divide by width/height inside the shader, while it
+			// might be more optimal to just scale the mesh as the resolution changes?
+			float invViewportWidth = 1.0f / (target->getWidth() * 0.5f);
+			float invViewportHeight = 1.0f / (target->getHeight() * 0.5f);
+
 			UINT32 meshIdx = 0;
 			for(auto& mesh : renderData.cachedMeshes)
 			{
 				HMaterial material = renderData.cachedMaterials[meshIdx];
 				GUIWidget* widget = renderData.cachedWidgetsPerMesh[meshIdx];
 
-				renderMesh(mesh, material, widget->SO()->getWorldTfrm(), target, coreAccessor);
+				if(material == nullptr || !material.isLoaded())
+					continue;
+
+				if(mesh == nullptr || !mesh.isLoaded())
+					continue;
+
+				material->setFloat("invViewportWidth", invViewportWidth);
+				material->setFloat("invViewportHeight", invViewportHeight);
+				material->setMat4("worldTransform", widget->SO()->getWorldTfrm());
+
+				renderQueue.add(material, mesh->getSubMeshData(), Vector3::ZERO);
 
 				meshIdx++;
 			}
@@ -218,35 +232,6 @@ namespace BansheeEngine
 		}
 	}
 
-	void GUIManager::renderMesh(const CM::HMesh& mesh, const CM::HMaterial& material, const CM::Matrix4& tfrm, CM::ViewportPtr& target, CM::CoreAccessor& coreAccessor)
-	{
-		// TODO - Possible optimization. I currently divide by width/height inside the shader, while it
-		// might be more optimal to just scale the mesh as the resolution changes?
-		float invViewportWidth = 1.0f / (target->getWidth() * 0.5f);
-		float invViewportHeight = 1.0f / (target->getHeight() * 0.5f);
-
-		material->setFloat("invViewportWidth", invViewportWidth);
-		material->setFloat("invViewportHeight", invViewportHeight);
-		material->setMat4("worldTransform", tfrm);
-
-		if(material == nullptr || !material.isLoaded())
-			return;
-
-		if(mesh == nullptr || !mesh.isLoaded())
-			return;
-
-		for(UINT32 i = 0; i < material->getNumPasses(); i++)
-		{
-			PassPtr pass = material->getPass(i);
-			pass->activate(coreAccessor);
-
-			PassParametersPtr paramsPtr = material->getPassParameters(i);
-			pass->bindParameters(coreAccessor, paramsPtr);
-
-			coreAccessor.render(mesh->getSubMeshData());
-		}
-	}
-
 	void GUIManager::updateMeshes()
 	{
 		for(auto& cachedMeshData : mCachedGUIData)

+ 2 - 4
BansheeEngine/Source/BsOverlayManager.cpp

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

+ 29 - 32
BansheeEngine/Source/BsRenderable.cpp

@@ -2,6 +2,7 @@
 #include "BsRenderableRTTI.h"
 #include "CmSceneObject.h"
 #include "CmMesh.h"
+#include "CmRenderQueue.h"
 
 using namespace CamelotFramework;
 
@@ -23,10 +24,10 @@ namespace BansheeEngine
 		mMaterials[idx] = material;
 	}
 
-	UINT32 Renderable::getNumRenderOperations() const
+	void Renderable::render(CM::RenderQueue& renderQueue)
 	{
 		if(mMesh == nullptr || !mMesh.isLoaded())
-			return 0;
+			return;
 
 		bool hasAtLeastOneMaterial = false;
 		for(auto& material : mMaterials)
@@ -36,14 +37,37 @@ namespace BansheeEngine
 				hasAtLeastOneMaterial = true;
 
 				if(!material.isLoaded()) // We wait until all materials are loaded
-					return 0;
+					return;
 			}
 		}
 
 		if(hasAtLeastOneMaterial)
-			return mMesh->getNumSubMeshes();
+		{
+			for(UINT32 i = 0; i < mMesh->getNumSubMeshes(); i++)
+			{
+				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, mMesh->getSubMeshData(i), mWorldBounds[i].getCenter());
+			}
+
+		}
 		else
-			return 0;
+			return;
 	}
 
 	void Renderable::updateWorldBounds()
@@ -61,33 +85,6 @@ namespace BansheeEngine
 		}
 	}
 
-	RenderOperation Renderable::getRenderOperation(CM::UINT32 idx) const
-	{
-		// TODO - Creating a RenderOperation each call might be excessive considering this will be called a few thousand times a frame
-		RenderOperation ro;
-		
-		if(idx < mMaterials.size() && mMaterials[idx] != nullptr)
-		{
-			ro.material = mMaterials[idx];
-		}
-		else
-		{
-			for(auto& iter = mMaterials.rbegin(); iter != mMaterials.rend(); ++iter)
-			{
-				if((*iter) != nullptr)
-				{
-					ro.material = *iter;
-					break;
-				}
-			}
-		}
-
-		ro.meshData = mMesh->getSubMeshData(idx);
-		ro.worldPosition = mWorldBounds[idx].getCenter();
-
-		return ro;
-	}
-
 	void Renderable::setLayer(UINT64 layer)
 	{
 		bool isPow2 = layer && !( (layer-1) & layer);

+ 1 - 1
BansheeForwardRenderer/Include/BsForwardRenderer.h

@@ -17,6 +17,6 @@ namespace BansheeEngine
 		virtual void render(const HCamera& camera);
 
 	private:
-		RendererSort* mRenderOpSorter;
+		CM::RenderQueue* mRenderQueue; // TODO - Move this to base class
 	};
 }

+ 28 - 23
BansheeForwardRenderer/Source/BsForwardRenderer.cpp

@@ -11,9 +11,10 @@
 #include "CmApplication.h"
 #include "CmViewport.h"
 #include "CmRenderTarget.h"
+#include "CmRenderOperation.h"
+#include "CmDefaultRenderQueue.h"
 #include "BsOverlayManager.h"
 #include "BsGUIManager.h"
-#include "BsDefaultRendererSort.h"
 
 using namespace CamelotFramework;
 
@@ -21,12 +22,12 @@ namespace BansheeEngine
 {
 	ForwardRenderer::ForwardRenderer()
 	{
-		mRenderOpSorter = cm_new<DefaultRendererSort>();
+		mRenderQueue = cm_new<DefaultRenderQueue>();
 	}
 
 	ForwardRenderer::~ForwardRenderer()
 	{
-		cm_delete(mRenderOpSorter);
+		cm_delete(mRenderQueue);
 	}
 
 	const String& ForwardRenderer::getName() const
@@ -126,30 +127,40 @@ namespace BansheeEngine
 
 		Matrix4 viewProjMatrix = projMatrixCstm * viewMatrixCstm;
 
-		Vector<RenderOperation>::type renderOperations;
+		mRenderQueue->clear();
+
+		// Get scene render operations
 		for(auto iter = allRenderables.begin(); iter != allRenderables.end(); ++iter)
 		{
-			UINT32 numOps = (*iter)->getNumRenderOperations();
+			UINT32 numMaterials = (*iter)->getNumMaterials();
 
-			for(UINT32 i = 0; i < numOps; i++)
-				renderOperations.push_back((*iter)->getRenderOperation(i));
-		}
+			for(UINT32 i = 0; i < numMaterials; i++)
+			{
+				// TODO - Do different things depending on material and renderable settings
+				
+				// 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?)
+				HMaterial& material = (*iter)->getMaterial(i);
+				material->setMat4("matViewProjection", viewProjMatrix);
+			}
 
-		// TODO - Do different things depending on render op settings
-		for(auto& renderOp : renderOperations)
-		{
-			// 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?)
-			renderOp.material->setMat4("matViewProjection", viewProjMatrix);
+			(*iter)->render(*mRenderQueue);
 		}
 
+		// Get GUI render operations
+		GUIManager::instance().render(camera->getViewport(), *mRenderQueue);
+
+		// Get overlay render operations
+		OverlayManager::instance().render(camera->getViewport(), *mRenderQueue);
+
 		// TODO - Material queue is completely ignored
-		Vector<SortedRenderOp>::type sortedROps =  mRenderOpSorter->sort(camera, renderOperations, DepthSortOrder::FrontToBack, true);
+		mRenderQueue->sort();
+		const Vector<SortedRenderOp>::type& sortedROps =  mRenderQueue->getSortedRenderOps();
 
 		for(auto iter = sortedROps.begin(); iter != sortedROps.end(); ++iter)
 		{
-			const RenderOperation& renderOp = iter->baseOperation;
+			const RenderOperation& renderOp = *iter->baseOperation;
 			HMaterial material = renderOp.material;
 
 			PassPtr pass = material->getPass(iter->passIdx);
@@ -160,11 +171,5 @@ namespace BansheeEngine
 
 			coreAccessor.render(renderOp.meshData);
 		}
-
-		// Render overlays
-		OverlayManager::instance().render(camera->getViewport(), coreAccessor);
-
-		// Render GUI elements
-		GUIManager::instance().render(camera->getViewport(), coreAccessor);
 	}
 }

+ 5 - 0
CamelotCore/CamelotCore.vcxproj

@@ -273,6 +273,7 @@
   </ItemDefinitionGroup>
   <ItemGroup>
     <ClInclude Include="Include\CmCoreThread.h" />
+    <ClInclude Include="Include\CmDefaultRenderQueue.h" />
     <ClInclude Include="Include\CmDeferredCallManager.h" />
     <ClInclude Include="Include\CmGameObjectHandle.h" />
     <ClInclude Include="Include\CmGameObject.h" />
@@ -287,6 +288,8 @@
     <ClInclude Include="Include\CmPixelData.h" />
     <ClInclude Include="Include\CmPixelDataRTTI.h" />
     <ClInclude Include="Include\CmPixelUtil.h" />
+    <ClInclude Include="Include\CmRenderOperation.h" />
+    <ClInclude Include="Include\CmRenderQueue.h" />
     <ClInclude Include="Include\CmSceneObjectRTTI.h" />
     <ClInclude Include="Include\CmMemAllocCategories.h" />
     <ClInclude Include="Include\CmApplication.h" />
@@ -398,6 +401,7 @@
   <ItemGroup>
     <ClCompile Include="Include\CmMaterialManager.cpp" />
     <ClCompile Include="Source\CmCoreThread.cpp" />
+    <ClCompile Include="Source\CmDefaultRenderQueue.cpp" />
     <ClCompile Include="Source\CmDeferredCallManager.cpp" />
     <ClCompile Include="Source\CmGameObjectHandle.cpp" />
     <ClCompile Include="Source\CmGameObject.cpp" />
@@ -437,6 +441,7 @@
     <ClCompile Include="Source\CmGpuProgIncludeImporter.cpp" />
     <ClCompile Include="Source\CmPixelData.cpp" />
     <ClCompile Include="Source\CmPixelUtil.cpp" />
+    <ClCompile Include="Source\CmRenderQueue.cpp" />
     <ClCompile Include="Source\CmTextureView.cpp" />
     <ClCompile Include="Source\CmTextUtility.cpp" />
     <ClCompile Include="Source\CmVertexBuffer.cpp" />

+ 15 - 0
CamelotCore/CamelotCore.vcxproj.filters

@@ -459,6 +459,15 @@
     <ClInclude Include="Include\CmRenderOpMesh.h">
       <Filter>Header Files\RenderSystem</Filter>
     </ClInclude>
+    <ClInclude Include="Include\CmDefaultRenderQueue.h">
+      <Filter>Header Files\Renderer</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmRenderOperation.h">
+      <Filter>Header Files\Renderer</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmRenderQueue.h">
+      <Filter>Header Files\Renderer</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CmApplication.cpp">
@@ -707,5 +716,11 @@
     <ClCompile Include="Source\CmDeferredCallManager.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Source\CmDefaultRenderQueue.cpp">
+      <Filter>Source Files\Renderer</Filter>
+    </ClCompile>
+    <ClCompile Include="Source\CmRenderQueue.cpp">
+      <Filter>Source Files\Renderer</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 13 - 0
CamelotCore/Include/CmDefaultRenderQueue.h

@@ -0,0 +1,13 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+#include "CmRenderQueue.h"
+
+namespace CamelotFramework 
+{
+	class CM_EXPORT DefaultRenderQueue : public RenderQueue
+	{
+	public:
+		void sort();
+	};
+}

+ 2 - 0
CamelotCore/Include/CmPrerequisites.h

@@ -155,6 +155,8 @@ namespace CamelotFramework {
 	class GpuResource;
 	class GpuResourceData;
 	class BindableGpuParams;
+	struct RenderOperation;
+	class RenderQueue;
 	// Asset import
 	class SpecificImporter;
 	class Importer;

+ 18 - 0
CamelotCore/Include/CmRenderOperation.h

@@ -0,0 +1,18 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+#include "CmRenderOpMesh.h"
+#include "CmVector3.h"
+
+namespace CamelotFramework 
+{
+	struct CM_EXPORT RenderOperation
+	{
+		RenderOperation()
+		{ }
+
+		HMaterial material;
+		RenderOpMesh meshData;
+		Vector3 worldPosition;
+	};
+}

+ 32 - 0
CamelotCore/Include/CmRenderQueue.h

@@ -0,0 +1,32 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+
+namespace CamelotFramework 
+{
+	struct CM_EXPORT SortedRenderOp
+	{
+		SortedRenderOp()
+			:baseOperation(nullptr), passIdx(0)
+		{ }
+
+		const RenderOperation* baseOperation;
+		UINT32 passIdx;
+	};
+
+	class CM_EXPORT RenderQueue
+	{
+	public:
+		RenderQueue();
+
+		void add(const HMaterial& material, const RenderOpMesh& mesh, const Vector3& worldPosForSort);
+		void clear();
+		
+		virtual void sort() = 0;
+		const Vector<SortedRenderOp>::type& getSortedRenderOps() const;
+
+	protected:
+		Vector<RenderOperation>::type mRenderOperations;
+		Vector<SortedRenderOp>::type mSortedRenderOps;
+	};
+}

+ 26 - 0
CamelotCore/Source/CmDefaultRenderQueue.cpp

@@ -0,0 +1,26 @@
+#include "CmDefaultRenderQueue.h"
+#include "CmRenderOperation.h"
+#include "CmMaterial.h"
+
+namespace CamelotFramework
+{
+	void DefaultRenderQueue::sort()
+	{
+		// Just pass-through for now
+		for(auto& renderOp : mRenderOperations)
+		{
+			UINT32 numPasses = renderOp.material->getNumPasses();
+			for(UINT32 i = 0; i < numPasses; i++)
+			{
+				mSortedRenderOps.push_back(SortedRenderOp());
+
+				SortedRenderOp& sortedOp = mSortedRenderOps.back();
+				sortedOp.baseOperation = &renderOp;
+				sortedOp.passIdx = i;
+			}
+		}
+
+		// TODO - Actually do some sorting
+		// Note: When sorting make sure not to change order of unsorted elements. Some outside managers (like overlay and GUI) will provide render ops which are already sorted
+	}
+}

+ 32 - 0
CamelotCore/Source/CmRenderQueue.cpp

@@ -0,0 +1,32 @@
+#include "CmRenderQueue.h"
+#include "CmRenderOperation.h"
+
+namespace CamelotFramework
+{
+	RenderQueue::RenderQueue()
+	{
+
+	}
+
+	void RenderQueue::clear()
+	{
+		mRenderOperations.clear();
+		mSortedRenderOps.clear();
+	}
+
+	void RenderQueue::add(const HMaterial& material, const RenderOpMesh& mesh, const Vector3& worldPosForSort)
+	{
+		// TODO - Make sure RenderOperations are cached so we dont allocate memory for them every frame
+		mRenderOperations.push_back(RenderOperation());
+
+		RenderOperation& renderOp = mRenderOperations.back();
+		renderOp.material = material;
+		renderOp.meshData = mesh;
+		renderOp.worldPosition = worldPosForSort;
+	}
+
+	const Vector<SortedRenderOp>::type& RenderQueue::getSortedRenderOps() const
+	{
+		return mSortedRenderOps;
+	}
+}