浏览代码

Reorganized how renderer works (using RenderOperations)
First step towards render sorting

Marko Pintera 12 年之前
父节点
当前提交
1265f65506
共有 54 个文件被更改,包括 853 次插入1065 次删除
  1. 3 0
      BansheeEngine.sln
  2. 4 0
      BansheeEngine/BansheeEngine.vcxproj
  3. 12 0
      BansheeEngine/BansheeEngine.vcxproj.filters
  4. 8 4
      BansheeEngine/Include/BsCamera.h
  5. 1 1
      BansheeEngine/Include/BsDebugDraw.h
  6. 13 0
      BansheeEngine/Include/BsDefaultRendererSort.h
  7. 11 0
      BansheeEngine/Include/BsPrerequisites.h
  8. 18 0
      BansheeEngine/Include/BsRenderOperation.h
  9. 18 4
      BansheeEngine/Include/BsRenderable.h
  10. 29 0
      BansheeEngine/Include/BsRendererSort.h
  11. 2 0
      BansheeEngine/Include/BsSceneManager.h
  12. 5 10
      BansheeEngine/Source/BsCamera.cpp
  13. 2 2
      BansheeEngine/Source/BsDebugDraw.cpp
  14. 30 0
      BansheeEngine/Source/BsDefaultRendererSort.cpp
  15. 1 1
      BansheeEngine/Source/BsGUIManager.cpp
  16. 91 2
      BansheeEngine/Source/BsRenderable.cpp
  17. 3 0
      BansheeForwardRenderer/Include/BsForwardRenderer.h
  18. 35 28
      BansheeForwardRenderer/Source/BsForwardRenderer.cpp
  19. 3 0
      BansheeOctreeSM/Include/BsOctreeSceneManager.h
  20. 26 1
      BansheeOctreeSM/Source/BsOctreeSceneManager.cpp
  21. 1 1
      CamelotClient/CamelotClient.cpp
  22. 1 1
      CamelotCore/CamelotCore.vcxproj
  23. 3 3
      CamelotCore/CamelotCore.vcxproj.filters
  24. 1 1
      CamelotCore/Include/CmCoreThreadAccessor.h
  25. 1 1
      CamelotCore/Include/CmGpuProgram.h
  26. 1 1
      CamelotCore/Include/CmGpuProgramParams.h
  27. 3 0
      CamelotCore/Include/CmMaterial.h
  28. 6 2
      CamelotCore/Include/CmMesh.h
  29. 1 1
      CamelotCore/Include/CmPrerequisites.h
  30. 32 0
      CamelotCore/Include/CmRenderOpMesh.h
  31. 0 85
      CamelotCore/Include/CmRenderOperation.h
  32. 2 2
      CamelotCore/Include/CmRenderSystem.h
  33. 0 6
      CamelotCore/Include/CmRenderer.h
  34. 1 1
      CamelotCore/Source/CmIndexData.cpp
  35. 1 1
      CamelotCore/Source/CmMaterial.cpp
  36. 16 2
      CamelotCore/Source/CmMesh.cpp
  37. 1 1
      CamelotCore/Source/CmRenderSystem.cpp
  38. 1 1
      CamelotD3D11RenderSystem/Include/CmD3D11Mappings.h
  39. 2 2
      CamelotUtility/CamelotUtility.vcxproj
  40. 6 6
      CamelotUtility/CamelotUtility.vcxproj.filters
  41. 266 0
      CamelotUtility/Include/CmAABox.cpp
  42. 86 0
      CamelotUtility/Include/CmAABox.h
  43. 0 35
      CamelotUtility/Include/CmAxisAlignedBox.cpp
  44. 0 813
      CamelotUtility/Include/CmAxisAlignedBox.h
  45. 1 1
      CamelotUtility/Include/CmFwdDeclUtil.h
  46. 5 5
      CamelotUtility/Include/CmMath.h
  47. 1 1
      CamelotUtility/Include/CmPlane.h
  48. 1 1
      CamelotUtility/Include/CmRay.h
  49. 1 1
      CamelotUtility/Include/CmSphere.h
  50. 14 30
      CamelotUtility/Source/CmMath.cpp
  51. 2 7
      CamelotUtility/Source/CmPlane.cpp
  52. 21 0
      DrawHelper.txt
  53. 23 0
      PlatformPorting.txt
  54. 37 0
      RenderOperation.txt

+ 3 - 0
BansheeEngine.sln

@@ -40,8 +40,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
 	ProjectSection(SolutionItems) = preProject
 		CSharpWrap.txt = CSharpWrap.txt
 		Dependencies.txt = Dependencies.txt
+		DrawHelper.txt = DrawHelper.txt
 		EditorWindowDock.txt = EditorWindowDock.txt
 		Notes.txt = Notes.txt
+		PlatformPorting.txt = PlatformPorting.txt
+		RenderOperation.txt = RenderOperation.txt
 		TODO.txt = TODO.txt
 		TODO_2D_GUI.txt = TODO_2D_GUI.txt
 		TODODoc.txt = TODODoc.txt

+ 4 - 0
BansheeEngine/BansheeEngine.vcxproj

@@ -228,6 +228,7 @@
   <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" />
@@ -264,6 +265,8 @@
     <ClInclude Include="Include\BsGUISkin.h" />
     <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" />
@@ -313,6 +316,7 @@
     <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" />

+ 12 - 0
BansheeEngine/BansheeEngine.vcxproj.filters

@@ -198,6 +198,15 @@
     <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">
@@ -341,5 +350,8 @@
     <ClCompile Include="Source\BsGUIViewport.cpp">
       <Filter>Source Files\GUI</Filter>
     </ClCompile>
+    <ClCompile Include="Source\BsDefaultRendererSort.cpp">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 8 - 4
BansheeEngine/Include/BsCamera.h

@@ -37,7 +37,7 @@ THE SOFTWARE.
 #include "CmMatrix4.h"
 #include "CmVector3.h"
 #include "CmVector2.h"
-#include "CmAxisAlignedBox.h"
+#include "CmAABox.h"
 #include "CmVertexData.h"
 #include "CmIndexData.h"
 #include "CmPlane.h"
@@ -342,7 +342,7 @@ namespace BansheeEngine {
             @par
                 Otherwise, false is returned.
         */
-        virtual bool isVisible(const CM::AxisAlignedBox& bound, FrustumPlane* culledBy = 0) const;
+        virtual bool isVisible(const CM::AABox& bound, FrustumPlane* culledBy = 0) const;
 
         /** Tests whether the given container is visible in the Frustum.
             @param
@@ -371,7 +371,7 @@ namespace BansheeEngine {
         virtual bool isVisible(const CM::Vector3& vert, FrustumPlane* culledBy = 0) const;
 
         /** Overridden from MovableObject */
-        const CM::AxisAlignedBox& getBoundingBox(void) const;
+        const CM::AABox& getBoundingBox(void) const;
 
         /** Overridden from MovableObject */
 		float getBoundingRadius(void) const;
@@ -424,10 +424,14 @@ namespace BansheeEngine {
 		CM::INT32 getPriority() const { return mPriority; }
 		void setPriority(CM::INT32 priority) { mPriority = priority; }
 
+		CM::UINT64 getLayers() const { return mLayers; }
+		void setLayers(CM::UINT64 layers) { mLayers = layers; }
+
         /// Small constant used to reduce far plane projection to avoid inaccuracies
         static const float INFINITE_FAR_PLANE_ADJUST;
     protected:
 		CM::ViewportPtr mViewport;
+		CM::UINT64 mLayers;
 
 		/// Orthographic or perspective?
 		ProjectionType mProjType;
@@ -498,7 +502,7 @@ namespace BansheeEngine {
 		/// Signal to update frustum information.
 		virtual void invalidateFrustum(void) const;
 
-		mutable CM::AxisAlignedBox mBoundingBox;
+		mutable CM::AABox mBoundingBox;
 
 		mutable CM::Vector3 mWorldSpaceCorners[8];
 

+ 1 - 1
BansheeEngine/Include/BsDebugDraw.h

@@ -3,7 +3,7 @@
 #include "BsPrerequisites.h"
 #include "CmModule.h"
 #include "CmColor.h"
-#include "CmAxisAlignedBox.h"
+#include "CmAABox.h"
 
 namespace BansheeEngine
 {

+ 13 - 0
BansheeEngine/Include/BsDefaultRendererSort.h

@@ -0,0 +1,13 @@
+#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);
+	};
+}

+ 11 - 0
BansheeEngine/Include/BsPrerequisites.h

@@ -68,6 +68,9 @@ 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;
@@ -83,6 +86,14 @@ namespace BansheeEngine
 		TID_Camera = 30000,
 		TID_Renderable = 30001
 	};
+
+	enum class RenderQueue
+	{
+		Skybox = 10000,
+		Opaque = 11000,
+		Transparent = 12000,
+		Overlay = 13000
+	};
 }
 
 namespace BS = BansheeEngine;

+ 18 - 0
BansheeEngine/Include/BsRenderOperation.h

@@ -0,0 +1,18 @@
+#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;
+	};
+}

+ 18 - 4
BansheeEngine/Include/BsRenderable.h

@@ -1,7 +1,9 @@
 #pragma once
 
 #include "BsPrerequisites.h"
+#include "BsRenderOperation.h"
 #include "CmComponent.h"
+#include "CmAABox.h"
 
 namespace BansheeEngine
 {
@@ -9,13 +11,25 @@ namespace BansheeEngine
 	{
 	public:
 		void setMesh(CM::HMesh mesh) { mMesh = mesh; }
-		void setMaterial(CM::HMaterial material) { mMaterial = material; }
+		void setNumMaterials(CM::UINT32 numMaterials);
+		void setMaterial(CM::UINT32 idx, CM::HMaterial material);
+		void setLayer(CM::UINT64 layer);
 
-		CM::HMesh getMesh() const { return mMesh; }
-		CM::HMaterial getMaterial() const { return mMaterial; }
+		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; }
+
+		void updateWorldBounds();
 	private:
 		CM::HMesh mMesh;
-		CM::HMaterial mMaterial;
+		CM::Vector<CM::HMaterial>::type mMaterials;
+		CM::UINT64 mLayer;
+		CM::Vector<CM::AABox>::type mWorldBounds;
 
 		/************************************************************************/
 		/* 							COMPONENT OVERRIDES                    		*/

+ 29 - 0
BansheeEngine/Include/BsRendererSort.h

@@ -0,0 +1,29 @@
+#pragma once
+
+#include "BsPrerequisites.h"
+
+namespace BansheeEngine 
+{
+	enum class DepthSortOrder
+	{
+		FrontToBack,
+		BackToFront,
+		NoDepthSort
+	};
+
+	struct BS_EXPORT SortedRenderOp
+	{
+		SortedRenderOp(const RenderOperation& op)
+			:baseOperation(op), passIdx(0)
+		{ }
+
+		const RenderOperation& baseOperation;
+		CM::UINT32 passIdx;
+	};
+
+	class BS_EXPORT RendererSort
+	{
+	public:
+		virtual CM::Vector<SortedRenderOp>::type sort(const HCamera& camera, const CM::Vector<RenderOperation>::type& renderOperations, DepthSortOrder sortOrder, bool allowSortByPass) = 0;
+	};
+}

+ 2 - 0
BansheeEngine/Include/BsSceneManager.h

@@ -20,6 +20,8 @@ namespace BansheeEngine
 		 * @brief	Returns all renderables visible to the specified camera.
 		 */
 		virtual CM::Vector<HRenderable>::type getVisibleRenderables(const HCamera& camera) const = 0;
+
+		virtual void updateRenderableBounds() = 0;
 	};
 
 	BS_EXPORT SceneManager& gSceneManager();

+ 5 - 10
BansheeEngine/Source/BsCamera.cpp

@@ -31,7 +31,7 @@ THE SOFTWARE.
 #include "CmMath.h"
 #include "CmMatrix3.h"
 #include "CmVector2.h"
-#include "CmAxisAlignedBox.h"
+#include "CmAABox.h"
 #include "CmSphere.h"
 #include "CmHardwareBufferManager.h"
 #include "CmVertexBuffer.h"
@@ -67,7 +67,8 @@ namespace BansheeEngine
 		mCustomProjMatrix(false),
 		mFrustumExtentsManuallySet(false),
 		mIgnoreSceneRenderables(false),
-		mPriority(0)
+		mPriority(0),
+		mLayers(0xFFFFFFFFFFFFFFFF)
     {
 		updateView();
 		updateFrustum();
@@ -223,14 +224,8 @@ namespace BansheeEngine
 	}
 
 	//-----------------------------------------------------------------------
-	bool Camera::isVisible(const AxisAlignedBox& bound, FrustumPlane* culledBy) const
+	bool Camera::isVisible(const AABox& bound, FrustumPlane* culledBy) const
 	{
-		// Null boxes always invisible
-		if (bound.isNull()) return false;
-
-		// Infinite boxes always visible
-		if (bound.isInfinite()) return true;
-
 		// Make any pending updates to the calculated frustum planes
 		updateFrustumPlanes();
 
@@ -676,7 +671,7 @@ namespace BansheeEngine
 		invalidateFrustum();
 	}
 	//-----------------------------------------------------------------------
-	const AxisAlignedBox& Camera::getBoundingBox(void) const
+	const AABox& Camera::getBoundingBox(void) const
 	{
 		return mBoundingBox;
 	}

+ 2 - 2
BansheeEngine/Source/BsDebugDraw.cpp

@@ -175,7 +175,7 @@ namespace BansheeEngine
 			PassParametersPtr paramsPtr = mLineMaterial->getPassParameters(i);
 			pass->bindParameters(coreAccessor, paramsPtr);
 
-			coreAccessor.render(mLineMesh->getRenderOperation());
+			coreAccessor.render(mLineMesh->getSubMeshData());
 		}
 
 		for(UINT32 i = 0; i < mTriangleMaterial->getNumPasses(); i++)
@@ -186,7 +186,7 @@ namespace BansheeEngine
 			PassParametersPtr paramsPtr = mTriangleMaterial->getPassParameters(i);
 			pass->bindParameters(coreAccessor, paramsPtr);
 
-			coreAccessor.render(mTriangleMesh->getRenderOperation());
+			coreAccessor.render(mTriangleMesh->getSubMeshData());
 		}
 	}
 

+ 30 - 0
BansheeEngine/Source/BsDefaultRendererSort.cpp

@@ -0,0 +1,30 @@
+#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;
+	}
+}

+ 1 - 1
BansheeEngine/Source/BsGUIManager.cpp

@@ -243,7 +243,7 @@ namespace BansheeEngine
 			PassParametersPtr paramsPtr = material->getPassParameters(i);
 			pass->bindParameters(coreAccessor, paramsPtr);
 
-			coreAccessor.render(mesh->getRenderOperation());
+			coreAccessor.render(mesh->getSubMeshData());
 		}
 	}
 

+ 91 - 2
BansheeEngine/Source/BsRenderable.cpp

@@ -1,13 +1,102 @@
 #include "BsRenderable.h"
 #include "BsRenderableRTTI.h"
+#include "CmSceneObject.h"
+#include "CmMesh.h"
 
 using namespace CamelotFramework;
 
 namespace BansheeEngine
 {
 	Renderable::Renderable(const HSceneObject& parent)
-		:Component(parent)
-	{ }
+		:Component(parent), mLayer(1)
+	{
+		mMaterials.resize(1);
+	}
+
+	void Renderable::setNumMaterials(CM::UINT32 numMaterials)
+	{
+		mMaterials.resize(numMaterials);
+	}
+
+	void Renderable::setMaterial(CM::UINT32 idx, CM::HMaterial material)
+	{
+		mMaterials[idx] = material;
+	}
+
+	UINT32 Renderable::getNumRenderOperations() const
+	{
+		if(mMesh == nullptr || !mMesh.isLoaded())
+			return 0;
+
+		bool hasAtLeastOneMaterial = false;
+		for(auto& material : mMaterials)
+		{
+			if(material != nullptr)
+			{
+				hasAtLeastOneMaterial = true;
+
+				if(!material.isLoaded()) // We wait until all materials are loaded
+					return 0;
+			}
+		}
+
+		if(hasAtLeastOneMaterial)
+			return mMesh->getNumSubMeshes();
+		else
+			return 0;
+	}
+
+	void Renderable::updateWorldBounds()
+	{
+		if(mMesh == nullptr || !mMesh.isLoaded())
+			return;
+
+		// 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++)
+		{
+			mWorldBounds[i] = mMesh->getBounds(i);
+			mWorldBounds[i].transformAffine(SO()->getWorldTfrm());
+		}
+	}
+
+	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);
+
+		if(!isPow2)
+			CM_EXCEPT(InvalidParametersException, "Invalid layer provided. Only one layer bit may be set.");
+
+		mLayer = layer;
+	}
 
 	RTTITypeBase* Renderable::getRTTIStatic()
 	{

+ 3 - 0
BansheeForwardRenderer/Include/BsForwardRenderer.h

@@ -15,5 +15,8 @@ namespace BansheeEngine
 
 		virtual void renderAll();
 		virtual void render(const HCamera& camera);
+
+	private:
+		RendererSort* mRenderOpSorter;
 	};
 }

+ 35 - 28
BansheeForwardRenderer/Source/BsForwardRenderer.cpp

@@ -13,6 +13,7 @@
 #include "CmRenderTarget.h"
 #include "BsOverlayManager.h"
 #include "BsGUIManager.h"
+#include "BsDefaultRendererSort.h"
 
 using namespace CamelotFramework;
 
@@ -20,10 +21,13 @@ namespace BansheeEngine
 {
 	ForwardRenderer::ForwardRenderer()
 	{
+		mRenderOpSorter = cm_new<DefaultRendererSort>();
 	}
 
 	ForwardRenderer::~ForwardRenderer()
-	{ }
+	{
+		cm_delete(mRenderOpSorter);
+	}
 
 	const String& ForwardRenderer::getName() const
 	{
@@ -33,6 +37,8 @@ namespace BansheeEngine
 
 	void ForwardRenderer::renderAll() 
 	{
+		gSceneManager().updateRenderableBounds();
+
 		CoreAccessor& coreAccessor = gMainCA();
 		const Vector<HCamera>::type& allCameras = gSceneManager().getAllCameras();
 
@@ -97,14 +103,7 @@ namespace BansheeEngine
 				if(clearBuffers != 0)
 					coreAccessor.clearViewport(clearBuffers, viewport->getClearColor(), viewport->getClearDepthValue(), viewport->getClearStencilValue());
 
-				// Render scene
 				render(camera);
-
-				// Render overlays
-				OverlayManager::instance().render(camera->getViewport(), coreAccessor);
-
-				// Render GUI elements
-				GUIManager::instance().render(camera->getViewport(), coreAccessor);
 			}
 
 			coreAccessor.endFrame();
@@ -127,37 +126,45 @@ namespace BansheeEngine
 
 		Matrix4 viewProjMatrix = projMatrixCstm * viewMatrixCstm;
 
-		// TODO - sort renderables by material/pass/parameters to minimize state changes
+		Vector<RenderOperation>::type renderOperations;
 		for(auto iter = allRenderables.begin(); iter != allRenderables.end(); ++iter)
 		{
-			HMaterial material = (*iter)->getMaterial();
-
-			if(material == nullptr || !material.isLoaded())
-				continue;
+			UINT32 numOps = (*iter)->getNumRenderOperations();
 
-			HMesh mesh = (*iter)->getMesh();
-
-			if(mesh == nullptr || !mesh.isLoaded())
-				continue;
+			for(UINT32 i = 0; i < numOps; i++)
+				renderOperations.push_back((*iter)->getRenderOperation(i));
+		}
 
+		// 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?)
-			material->setMat4("matViewProjection", viewProjMatrix);
+			renderOp.material->setMat4("matViewProjection", viewProjMatrix);
+		}
 
-			for(UINT32 i = 0; i < material->getNumPasses(); i++)
-			{
-				PassPtr pass = material->getPass(i);
-				pass->activate(coreAccessor);
+		// TODO - Material queue is completely ignored
+		Vector<SortedRenderOp>::type sortedROps =  mRenderOpSorter->sort(camera, renderOperations, DepthSortOrder::FrontToBack, true);
+
+		for(auto iter = sortedROps.begin(); iter != sortedROps.end(); ++iter)
+		{
+			const RenderOperation& renderOp = iter->baseOperation;
+			HMaterial material = renderOp.material;
 
-				PassParametersPtr paramsPtr = material->getPassParameters(i);
-				pass->bindParameters(coreAccessor, paramsPtr);
+			PassPtr pass = material->getPass(iter->passIdx);
+			pass->activate(coreAccessor);
 
-				coreAccessor.render(mesh->getRenderOperation());
-			}
+			PassParametersPtr paramsPtr = material->getPassParameters(iter->passIdx);
+			pass->bindParameters(coreAccessor, paramsPtr);
+
+			coreAccessor.render(renderOp.meshData);
 		}
 
-		// TODO - Sort renderables
-		// Render them
+		// Render overlays
+		OverlayManager::instance().render(camera->getViewport(), coreAccessor);
+
+		// Render GUI elements
+		GUIManager::instance().render(camera->getViewport(), coreAccessor);
 	}
 }

+ 3 - 0
BansheeOctreeSM/Include/BsOctreeSceneManager.h

@@ -14,10 +14,13 @@ namespace BansheeEngine
 		const CM::Vector<HCamera>::type& getAllCameras() const { return mCachedCameras; }
 
 		CM::Vector<HRenderable>::type getVisibleRenderables(const HCamera& camera) const;
+
+		void updateRenderableBounds();
 	private:
 		void notifyComponentAdded(const CM::HComponent& component);
 		void notifyComponentRemoved(const CM::HComponent& component);
 
 		CM::Vector<HCamera>::type mCachedCameras;
+		CM::Vector<HRenderable>::type mRenderables;
 	};
 }

+ 26 - 1
BansheeOctreeSM/Source/BsOctreeSceneManager.cpp

@@ -25,7 +25,10 @@ namespace BansheeEngine
 
 			HRenderable curRenderable = currentGO->getComponent<Renderable>();
 			if(curRenderable != nullptr)
-				renderables.push_back(curRenderable);
+			{
+				if((curRenderable->getLayer() & camera->getLayers()) != 0)
+					renderables.push_back(curRenderable);
+			}
 
 			for(UINT32 i = 0; i < currentGO->getNumChildren(); i++)
 				todo.push(currentGO->getChild(i));
@@ -34,6 +37,14 @@ namespace BansheeEngine
 		return renderables;
 	}
 
+	void OctreeSceneManager::updateRenderableBounds()
+	{
+		for(auto& iter : mRenderables)
+		{
+			iter->updateWorldBounds();
+		}
+	}
+
 	void OctreeSceneManager::notifyComponentAdded(const HComponent& component)
 	{
 		if(component->getTypeId() == TID_Camera)
@@ -48,6 +59,11 @@ namespace BansheeEngine
 
 			mCachedCameras.push_back(camera);
 		}
+		else if(component->getTypeId() == TID_Renderable)
+		{
+			HRenderable renderable = static_object_cast<Renderable>(component);
+			mRenderables.push_back(renderable);
+		}
 	}
 
 	void OctreeSceneManager::notifyComponentRemoved(const HComponent& component)
@@ -64,5 +80,14 @@ namespace BansheeEngine
 
 			mCachedCameras.erase(findIter);
 		}
+		else if(component->getTypeId() == TID_Renderable)
+		{
+			HRenderable renderable = static_object_cast<Renderable>(component);
+
+			// TODO - I should probably use some for of a hash set because searching through possibly thousands of renderables will be slow
+			auto findIter = std::find(mRenderables.begin(), mRenderables.end(), renderable);
+			if(findIter != mRenderables.end())
+				mRenderables.erase(findIter);
+		}
 	}
 }

+ 1 - 1
CamelotClient/CamelotClient.cpp

@@ -255,7 +255,7 @@ int CALLBACK WinMain(
 	//_ASSERT(_CrtCheckMemory());
 
 	testRenderable->setMesh(dbgMeshRef);
-	testRenderable->setMaterial(testMaterial);
+	testRenderable->setMaterial(0, testMaterial);
 
 	//// Set the new state for the flag
 	//_CrtSetDbgFlag( tmpFlag );

+ 1 - 1
CamelotCore/CamelotCore.vcxproj

@@ -354,7 +354,7 @@
     <ClInclude Include="Include\CmRenderer.h" />
     <ClInclude Include="Include\CmRendererFactory.h" />
     <ClInclude Include="Include\CmRendererManager.h" />
-    <ClInclude Include="Include\CmRenderOperation.h" />
+    <ClInclude Include="Include\CmRenderOpMesh.h" />
     <ClInclude Include="Include\CmRenderStateManager.h" />
     <ClInclude Include="Include\CmRenderSystem.h" />
     <ClInclude Include="Include\CmRenderSystemCapabilities.h" />

+ 3 - 3
CamelotCore/CamelotCore.vcxproj.filters

@@ -255,9 +255,6 @@
     <ClInclude Include="Include\CmSamplerState.h">
       <Filter>Header Files\RenderSystem</Filter>
     </ClInclude>
-    <ClInclude Include="Include\CmRenderOperation.h">
-      <Filter>Header Files\RenderSystem</Filter>
-    </ClInclude>
     <ClInclude Include="Include\CmResourceHandle.h">
       <Filter>Header Files\Resources</Filter>
     </ClInclude>
@@ -459,6 +456,9 @@
     <ClInclude Include="Include\CmDeferredCallManager.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\CmRenderOpMesh.h">
+      <Filter>Header Files\RenderSystem</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CmApplication.cpp">

+ 1 - 1
CamelotCore/Include/CmCoreThreadAccessor.h

@@ -197,7 +197,7 @@ namespace CamelotFramework
 
 
 		/** @copydoc RenderSystem::render() */
-		void render(const RenderOperation& op)
+		void render(const RenderOpMesh& op)
 		{
 			mCommandQueue->queue(boost::bind(&RenderSystem::render, RenderSystem::instancePtr(), op));
 		}

+ 1 - 1
CamelotCore/Include/CmGpuProgram.h

@@ -30,7 +30,7 @@ THE SOFTWARE.
 
 // Precompiler options
 #include "CmPrerequisites.h"
-#include "CmRenderOperation.h"
+#include "CmRenderOpMesh.h"
 #include "CmGpuProgramParams.h"
 #include "CmResource.h"
 #include "CmGpuParamDesc.h"

+ 1 - 1
CamelotCore/Include/CmGpuProgramParams.h

@@ -30,7 +30,7 @@ THE SOFTWARE.
 
 // Precompiler options
 #include "CmPrerequisites.h"
-#include "CmRenderOperation.h"
+#include "CmRenderOpMesh.h"
 #include "CmSamplerState.h"
 
 namespace CamelotFramework {

+ 3 - 0
CamelotCore/Include/CmMaterial.h

@@ -77,6 +77,7 @@ namespace CamelotFramework
 		void setMat3(const String& name, const Matrix3& value, UINT32 arrayIdx = 0);
 		void setMat4(const String& name, const Matrix4& value, UINT32 arrayIdx = 0);
 		void setStructData(const String& name, void* value, UINT32 size, UINT32 arrayIdx = 0);
+		void setRenderQueue(INT16 renderQueue) { mRenderQueue = renderQueue; }
 
 		//void setParamBlock(const String& name, GpuParamBlockPtr paramBlock);
 
@@ -89,6 +90,7 @@ namespace CamelotFramework
 		Matrix3 getMat3(const String& name, UINT32 arrayIdx = 0) const;
 		Matrix4 getMat4(const String& name, UINT32 arrayIdx = 0) const;
 		const StructData& getStructData(const String& name, UINT32 arrayIdx = 0) const;
+		INT16 getRenderQueue() const { return mRenderQueue; }
 
 		UINT32 getNumPasses() const;
 
@@ -106,6 +108,7 @@ namespace CamelotFramework
 
 		ShaderPtr mShader;
 		TechniquePtr mBestTechnique;
+		INT16 mRenderQueue;
 
 		Set<String>::type mValidShareableParamBlocks;
 		Map<String, String>::type mValidParams; // Also maps Shader param name -> gpu variable name

+ 6 - 2
CamelotCore/Include/CmMesh.h

@@ -5,7 +5,7 @@
 #include "CmMeshData.h"
 #include "CmVertexData.h"
 #include "CmIndexData.h"
-#include "CmRenderOperation.h"
+#include "CmRenderOpMesh.h"
 
 namespace CamelotFramework
 {
@@ -58,7 +58,11 @@ namespace CamelotFramework
 		 */
 		UINT32 mapToSubresourceIdx() const { return 0; }
 
-		RenderOperation getRenderOperation(UINT32 subMeshIdx = 0) const;
+		RenderOpMesh getSubMeshData(UINT32 subMeshIdx = 0) const;
+		UINT32 getNumSubMeshes() const { return (UINT32)mSubMeshes.size(); }
+
+		const AABox& getBounds() const;
+		const AABox& getBounds(UINT32 submeshIdx) const;
 
 		/**
 		 * @brief	Returns a dummy mesh, containing just one triangle. Don't modify the returned mesh.

+ 1 - 1
CamelotCore/Include/CmPrerequisites.h

@@ -119,7 +119,7 @@ namespace CamelotFramework {
     class RenderTexture;
 	class MultiRenderTexture;
     class RenderWindow;
-    class RenderOperation;
+    struct RenderOpMesh;
     class StringInterface;
     class SamplerState;
     class TextureManager;

+ 32 - 0
CamelotCore/Include/CmRenderOpMesh.h

@@ -0,0 +1,32 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+#include "CmVertexDeclaration.h"
+#include "CmVertexData.h"
+#include "CmIndexData.h"
+
+namespace CamelotFramework 
+{
+	enum DrawOperationType {
+		DOT_POINT_LIST = 1,
+		DOT_LINE_LIST = 2,
+		DOT_LINE_STRIP = 3,
+		DOT_TRIANGLE_LIST = 4,
+		DOT_TRIANGLE_STRIP = 5,
+		DOT_TRIANGLE_FAN = 6
+	};
+
+	struct RenderOpMesh
+	{
+		RenderOpMesh() 
+			:vertexData(nullptr), operationType(DOT_TRIANGLE_LIST), useIndexes(true),
+			indexData(nullptr) 
+		{ }
+
+		VertexData *vertexData;
+		IndexData *indexData;
+
+		DrawOperationType operationType;
+		bool useIndexes;
+	};
+}

+ 0 - 85
CamelotCore/Include/CmRenderOperation.h

@@ -1,85 +0,0 @@
-/*
------------------------------------------------------------------------------
-This source file is part of OGRE
-    (Object-oriented Graphics Rendering Engine)
-For the latest info, see http://www.ogre3d.org/
-
-Copyright (c) 2000-2011 Torus Knot Software Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
------------------------------------------------------------------------------
-*/
-#pragma once
-
-#include "CmPrerequisites.h"
-#include "CmVertexDeclaration.h"
-#include "CmVertexData.h"
-#include "CmIndexData.h"
-
-namespace CamelotFramework 
-{
-	/// The rendering operation type to perform
-	enum DrawOperationType {
-		/// A list of points, 1 vertex per point
-		DOT_POINT_LIST = 1,
-		/// A list of lines, 2 vertices per line
-		DOT_LINE_LIST = 2,
-		/// A strip of connected lines, 1 vertex per line plus 1 start vertex
-		DOT_LINE_STRIP = 3,
-		/// A list of triangles, 3 vertices per triangle
-		DOT_TRIANGLE_LIST = 4,
-		/// A strip of triangles, 3 vertices for the first triangle, and 1 per triangle after that 
-		DOT_TRIANGLE_STRIP = 5,
-		/// A fan of triangles, 3 vertices for the first triangle, and 1 per triangle after that
-		DOT_TRIANGLE_FAN = 6
-	};
-
-	/** \addtogroup Core
-	*  @{
-	*/
-	/** \addtogroup RenderSystem
-	*  @{
-	*/
-	/** Rendering command that is used for rendering of a single object
-	 using a single pass */
-	class RenderOperation
-	{
-	public:
-		/// Vertex source data
-		VertexData *vertexData;
-
-		/// The type of operation to perform
-		DrawOperationType operationType;
-
-		/** Specifies whether to use indexes to determine the vertices to use as input. If false, the vertices are
-		 simply read in sequence to define the primitives. If true, indexes are used instead to identify vertices
-		 anywhere in the buffer, and allowing vertices to be used more than once.
-	   	 If true, then the indexBuffer, indexStart and numIndexes properties must be valid. */
-		bool useIndexes;
-
-		/// Index data - only valid if useIndexes is true
-		IndexData *indexData;
-
-        RenderOperation() :
-            vertexData(0), operationType(DOT_TRIANGLE_LIST), useIndexes(true),
-                indexData(0) {}
-	};
-	/** @} */
-	/** @} */
-}

+ 2 - 2
CamelotCore/Include/CmRenderSystem.h

@@ -39,7 +39,7 @@ THE SOFTWARE.
 #include "CmCommonEnums.h"
 
 #include "CmCommandQueue.h"
-#include "CmRenderOperation.h"
+#include "CmRenderOpMesh.h"
 #include "CmRenderSystemCapabilities.h"
 #include "CmRenderTarget.h"
 #include "CmRenderTexture.h"
@@ -184,7 +184,7 @@ namespace CamelotFramework
 		 * 			It will automatically set up vertex declaration, draw operation, 
 		 * 			vertex and index buffers and draw them.
 		 */
-		virtual void render(const RenderOperation& op);
+		virtual void render(const RenderOpMesh& op);
 
 		/**
 		 * @brief	Draw an object based on currently set

+ 0 - 6
CamelotCore/Include/CmRenderer.h

@@ -14,11 +14,5 @@ namespace CamelotFramework
 		 * @brief	Renders all cameras.
 		 */
 		virtual void renderAll() = 0;
-
-		/**
-		 * @brief	 Renders the scene from the perspective of a single camera
-		 * 			 // TODO - Temporarily disabled since I moved Camera out of Camelot
-		 */
-		//virtual void render(const HCamera& camera) = 0;
 	};
 }

+ 1 - 1
CamelotCore/Source/CmIndexData.cpp

@@ -3,7 +3,7 @@
 #include "CmVertexBuffer.h"
 #include "CmIndexBuffer.h"
 #include "CmVector3.h"
-#include "CmAxisAlignedBox.h"
+#include "CmAABox.h"
 #include "CmException.h"
 #include "CmRenderSystem.h"
 

+ 1 - 1
CamelotCore/Source/CmMaterial.cpp

@@ -16,7 +16,7 @@
 namespace CamelotFramework
 {
 	Material::Material()
-		:Resource(false)
+		:Resource(false), mRenderQueue(0)
 	{
 
 	}

+ 16 - 2
CamelotCore/Source/CmMesh.cpp

@@ -8,6 +8,7 @@
 #include "CmMeshManager.h"
 #include "CmCoreThread.h"
 #include "CmAsyncOp.h"
+#include "CmAABox.h"
 
 namespace CamelotFramework
 {
@@ -199,7 +200,7 @@ namespace CamelotFramework
 		return meshData;
 	}
 
-	RenderOperation Mesh::getRenderOperation(UINT32 subMeshIdx) const
+	RenderOpMesh Mesh::getSubMeshData(UINT32 subMeshIdx) const
 	{
 		if(subMeshIdx < 0 || subMeshIdx >= mSubMeshes.size())
 		{
@@ -208,7 +209,8 @@ namespace CamelotFramework
 		}
 
 		// TODO - BIG TODO - Completely ignores subMeshIdx and always renders the entire thing
-		RenderOperation ro;
+		// TODO - Creating a RenderOpMesh each call might be excessive considering this will be called a few thousand times a frame
+		RenderOpMesh ro;
 		ro.indexData = mIndexData;
 		ro.vertexData = mVertexData;
 		ro.useIndexes = true;
@@ -217,6 +219,18 @@ namespace CamelotFramework
 		return ro;
 	}
 
+	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;
+	}
+
 	void Mesh::initialize_internal()
 	{
 		THROW_IF_NOT_CORE_THREAD;

+ 1 - 1
CamelotCore/Source/CmRenderSystem.cpp

@@ -210,7 +210,7 @@ namespace CamelotFramework {
         return false;
 	}
 
-	void RenderSystem::render(const RenderOperation& op)
+	void RenderSystem::render(const RenderOpMesh& op)
 	{
 		THROW_IF_NOT_CORE_THREAD;
 

+ 1 - 1
CamelotD3D11RenderSystem/Include/CmD3D11Mappings.h

@@ -8,7 +8,7 @@
 #include "CmVertexData.h"
 #include "CmIndexData.h"
 #include "CmSamplerState.h"
-#include "CmRenderOperation.h"
+#include "CmRenderOpMesh.h"
 
 namespace CamelotFramework
 {

+ 2 - 2
CamelotUtility/CamelotUtility.vcxproj

@@ -292,7 +292,7 @@
     <ClInclude Include="Include\CmTimer.h" />
     <ClInclude Include="Include\CmTypes.h" />
     <ClInclude Include="Include\CmFwdDeclUtil.h" />
-    <ClInclude Include="Include\CmAxisAlignedBox.h" />
+    <ClInclude Include="Include\CmAABox.h" />
     <ClInclude Include="Include\CmMath.h" />
     <ClInclude Include="Include\CmMatrix3.h" />
     <ClInclude Include="Include\CmMatrix4.h" />
@@ -320,7 +320,7 @@
     <ClInclude Include="Include\CmTexAtlasGenerator.h" />
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="Include\CmAxisAlignedBox.cpp" />
+    <ClCompile Include="Include\CmAABox.cpp" />
     <ClCompile Include="Source\CmColor.cpp" />
     <ClCompile Include="Source\CmDebug.cpp" />
     <ClCompile Include="Source\CmDynLibManager.cpp" />

+ 6 - 6
CamelotUtility/CamelotUtility.vcxproj.filters

@@ -69,9 +69,6 @@
     <ClInclude Include="Include\CmMathAsm.h">
       <Filter>Header Files\Math</Filter>
     </ClInclude>
-    <ClInclude Include="Include\CmAxisAlignedBox.h">
-      <Filter>Header Files\Math</Filter>
-    </ClInclude>
     <ClInclude Include="Include\CmMath.h">
       <Filter>Header Files\Math</Filter>
     </ClInclude>
@@ -219,11 +216,11 @@
     <ClInclude Include="Include\CmMemStack.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="Include\CmAABox.h">
+      <Filter>Header Files\Math</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
-    <ClCompile Include="Include\CmAxisAlignedBox.cpp">
-      <Filter>Source Files\Math</Filter>
-    </ClCompile>
     <ClCompile Include="Source\CmMath.cpp">
       <Filter>Source Files\Math</Filter>
     </ClCompile>
@@ -329,5 +326,8 @@
     <ClCompile Include="Source\CmMemStack.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="Include\CmAABox.cpp">
+      <Filter>Source Files\Math</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 266 - 0
CamelotUtility/Include/CmAABox.cpp

@@ -0,0 +1,266 @@
+#include "CmAABox.h"
+
+namespace CamelotFramework
+{
+	const AABox AABox::BOX_EMPTY;
+
+	AABox::AABox() 
+		:mMinimum(Vector3::ZERO), mMaximum(Vector3::UNIT_SCALE)
+	{
+		// Default to a null box 
+		setMin(Vector3(-0.5f, -0.5f, -0.5f));
+		setMax(Vector3(0.5f, 0.5f, 0.5f));
+	}
+
+	AABox::AABox(const AABox & rkBox)
+		:mMinimum(Vector3::ZERO), mMaximum(Vector3::UNIT_SCALE)
+	{
+		setExtents( rkBox.mMinimum, rkBox.mMaximum );
+	}
+
+	AABox::AABox(const Vector3& min, const Vector3& max)
+		:mMinimum(Vector3::ZERO), mMaximum(Vector3::UNIT_SCALE)
+	{
+		setExtents( min, max );
+	}
+
+	AABox& AABox::operator=(const AABox& rhs)
+	{
+		setExtents(rhs.mMinimum, rhs.mMaximum);
+
+		return *this;
+	}
+
+	void AABox::setExtents( const Vector3& min, const Vector3& max )
+	{
+        assert( (min.x <= max.x && min.y <= max.y && min.z <= max.z) &&
+            "The minimum corner of the box must be less than or equal to maximum corner" );
+
+		mMinimum = min;
+		mMaximum = max;
+	}
+
+	Vector3 AABox::getCorner(CornerEnum cornerToGet) const
+	{
+		switch(cornerToGet)
+		{
+		case FAR_LEFT_BOTTOM:
+			return mMinimum;
+		case FAR_LEFT_TOP:
+			return Vector3(mMinimum.x, mMaximum.y, mMinimum.z);
+		case FAR_RIGHT_TOP:
+			return Vector3(mMaximum.x, mMaximum.y, mMinimum.z);
+		case FAR_RIGHT_BOTTOM:
+			return Vector3(mMaximum.x, mMinimum.y, mMinimum.z);
+		case NEAR_RIGHT_BOTTOM:
+			return Vector3(mMaximum.x, mMinimum.y, mMaximum.z);
+		case NEAR_LEFT_BOTTOM:
+			return Vector3(mMinimum.x, mMinimum.y, mMaximum.z);
+		case NEAR_LEFT_TOP:
+			return Vector3(mMinimum.x, mMaximum.y, mMaximum.z);
+		case NEAR_RIGHT_TOP:
+			return mMaximum;
+		default:
+			return Vector3();
+		}
+	}
+
+	void AABox::merge( const AABox& rhs )
+	{
+		Vector3 min = mMinimum;
+		Vector3 max = mMaximum;
+		max.makeCeil(rhs.mMaximum);
+		min.makeFloor(rhs.mMinimum);
+
+		setExtents(min, max);
+	}
+
+	void AABox::merge( const Vector3& point )
+	{
+		mMaximum.makeCeil(point);
+		mMinimum.makeFloor(point);
+	}
+
+	void AABox::transform( const Matrix4& matrix )
+	{
+		Vector3 oldMin, oldMax, currentCorner;
+
+		// Getting the old values so that we can use the existing merge method.
+		oldMin = mMinimum;
+		oldMax = mMaximum;
+
+		// We sequentially compute the corners in the following order :
+		// 0, 6, 5, 1, 2, 4 ,7 , 3
+		// This sequence allows us to only change one member at a time to get at all corners.
+
+		// For each one, we transform it using the matrix
+		// Which gives the resulting point and merge the resulting point.
+
+		// First corner 
+		// min min min
+		currentCorner = oldMin;
+		merge( matrix * currentCorner );
+
+		// min,min,max
+		currentCorner.z = oldMax.z;
+		merge( matrix * currentCorner );
+
+		// min max max
+		currentCorner.y = oldMax.y;
+		merge( matrix * currentCorner );
+
+		// min max min
+		currentCorner.z = oldMin.z;
+		merge( matrix * currentCorner );
+
+		// max max min
+		currentCorner.x = oldMax.x;
+		merge( matrix * currentCorner );
+
+		// max max max
+		currentCorner.z = oldMax.z;
+		merge( matrix * currentCorner );
+
+		// max min max
+		currentCorner.y = oldMin.y;
+		merge( matrix * currentCorner );
+
+		// max min min
+		currentCorner.z = oldMin.z;
+		merge( matrix * currentCorner ); 
+	}
+
+	void AABox::transformAffine(const Matrix4& m)
+	{
+		assert(m.isAffine());
+
+		Vector3 centre = getCenter();
+		Vector3 halfSize = getHalfSize();
+
+		Vector3 newCentre = m.transformAffine(centre);
+		Vector3 newHalfSize(
+			Math::Abs(m[0][0]) * halfSize.x + Math::Abs(m[0][1]) * halfSize.y + Math::Abs(m[0][2]) * halfSize.z, 
+			Math::Abs(m[1][0]) * halfSize.x + Math::Abs(m[1][1]) * halfSize.y + Math::Abs(m[1][2]) * halfSize.z,
+			Math::Abs(m[2][0]) * halfSize.x + Math::Abs(m[2][1]) * halfSize.y + Math::Abs(m[2][2]) * halfSize.z);
+
+		setExtents(newCentre - newHalfSize, newCentre + newHalfSize);
+	}
+
+	bool AABox::intersects(const AABox& b2) const
+	{
+		// Use up to 6 separating planes
+		if (mMaximum.x < b2.mMinimum.x)
+			return false;
+		if (mMaximum.y < b2.mMinimum.y)
+			return false;
+		if (mMaximum.z < b2.mMinimum.z)
+			return false;
+
+		if (mMinimum.x > b2.mMaximum.x)
+			return false;
+		if (mMinimum.y > b2.mMaximum.y)
+			return false;
+		if (mMinimum.z > b2.mMaximum.z)
+			return false;
+
+		// otherwise, must be intersecting
+		return true;
+	}
+
+	AABox AABox::intersection(const AABox& b2) const
+	{
+		Vector3 intMin = mMinimum;
+        Vector3 intMax = mMaximum;
+
+        intMin.makeCeil(b2.getMin());
+        intMax.makeFloor(b2.getMax());
+
+        // Check intersection isn't null
+        if (intMin.x < intMax.x &&
+            intMin.y < intMax.y &&
+            intMin.z < intMax.z)
+        {
+            return AABox(intMin, intMax);
+        }
+
+        return AABox();
+	}
+
+	float AABox::volume(void) const
+	{
+		Vector3 diff = mMaximum - mMinimum;
+		return diff.x * diff.y * diff.z;
+	}
+
+	void AABox::scale(const Vector3& s)
+	{
+		// NB assumes centered on origin
+		Vector3 min = mMinimum * s;
+		Vector3 max = mMaximum * s;
+		setExtents(min, max);
+	}
+
+	bool AABox::intersects(const Sphere& s) const
+	{
+		return Math::intersects(s, *this); 
+	}
+
+	bool AABox::intersects(const Plane& p) const
+	{
+		return Math::intersects(p, *this);
+	}
+
+	bool AABox::intersects(const Vector3& v) const
+	{
+		return(v.x >= mMinimum.x  &&  v.x <= mMaximum.x  && 
+			v.y >= mMinimum.y  &&  v.y <= mMaximum.y  && 
+			v.z >= mMinimum.z  &&  v.z <= mMaximum.z);
+	}
+
+	Vector3 AABox::getCenter(void) const
+	{
+		return Vector3(
+			(mMaximum.x + mMinimum.x) * 0.5f,
+			(mMaximum.y + mMinimum.y) * 0.5f,
+			(mMaximum.z + mMinimum.z) * 0.5f);
+	}
+
+	Vector3 AABox::getSize(void) const
+	{
+		return mMaximum - mMinimum;
+	}
+
+	Vector3 AABox::getHalfSize(void) const
+	{
+		return (mMaximum - mMinimum) * 0.5;
+	}
+
+    bool AABox::contains(const Vector3& v) const
+    {
+        return mMinimum.x <= v.x && v.x <= mMaximum.x &&
+                mMinimum.y <= v.y && v.y <= mMaximum.y &&
+                mMinimum.z <= v.z && v.z <= mMaximum.z;
+    }
+
+    bool AABox::contains(const AABox& other) const
+    {
+        return this->mMinimum.x <= other.mMinimum.x &&
+                this->mMinimum.y <= other.mMinimum.y &&
+                this->mMinimum.z <= other.mMinimum.z &&
+                other.mMaximum.x <= this->mMaximum.x &&
+                other.mMaximum.y <= this->mMaximum.y &&
+                other.mMaximum.z <= this->mMaximum.z;
+    }
+
+    bool AABox::operator== (const AABox& rhs) const
+    {
+        return this->mMinimum == rhs.mMinimum &&
+                this->mMaximum == rhs.mMaximum;
+    }
+
+    bool AABox::operator!= (const AABox& rhs) const
+    {
+        return !(*this == rhs);
+    }
+}
+

+ 86 - 0
CamelotUtility/Include/CmAABox.h

@@ -0,0 +1,86 @@
+#pragma once
+
+#include "CmPrerequisitesUtil.h"
+
+#include "CmVector3.h"
+#include "CmMatrix4.h"
+
+namespace CamelotFramework 
+{
+	class CM_UTILITY_EXPORT AABox
+	{
+	public:
+		/*
+		   1-----2
+		  /|    /|
+		 / |   / |
+		5-----4  |
+		|  0--|--3
+		| /   | /
+		|/    |/
+		6-----7
+		*/
+		typedef enum CornerEnum {
+			FAR_LEFT_BOTTOM = 0,
+			FAR_LEFT_TOP = 1,
+			FAR_RIGHT_TOP = 2,
+			FAR_RIGHT_BOTTOM = 3,
+			NEAR_RIGHT_BOTTOM = 7,
+			NEAR_LEFT_BOTTOM = 6,
+			NEAR_LEFT_TOP = 5,
+			NEAR_RIGHT_TOP = 4
+		};
+
+		AABox();
+		AABox(const AABox & rkBox);
+		AABox(const Vector3& min, const Vector3& max);
+
+		AABox& operator=(const AABox& rhs);
+
+		~AABox() { }
+
+		const Vector3& getMin(void) const { return mMinimum; }
+		const Vector3& getMax(void) const { return mMaximum; }
+
+		void setMin(const Vector3& vec) { mMinimum = vec; }
+		void setMax(const Vector3& vec) { mMaximum = vec; }
+
+		void setExtents(const Vector3& min, const Vector3& max);
+
+		Vector3 getCorner(CornerEnum cornerToGet) const;
+
+		void merge(const AABox& rhs);
+		void merge(const Vector3& point);
+
+		void transform(const Matrix4& matrix);
+		void transformAffine(const Matrix4& matrix);
+
+		bool intersects(const AABox& b2) const;
+
+		AABox intersection(const AABox& b2) const;
+
+		float volume() const;
+
+		inline void scale(const Vector3& s);
+
+		bool intersects(const Sphere& s) const;
+		bool intersects(const Plane& p) const;
+		bool intersects(const Vector3& v) const;
+
+		Vector3 getCenter() const;
+		Vector3 getSize() const;
+		Vector3 getHalfSize() const;
+
+        bool contains(const Vector3& v) const;
+        bool contains(const AABox& other) const;
+
+        bool operator== (const AABox& rhs) const;
+        bool operator!= (const AABox& rhs) const;
+
+		static const AABox BOX_EMPTY;
+
+	protected:
+		Vector3 mMinimum;
+		Vector3 mMaximum;
+	};
+}

+ 0 - 35
CamelotUtility/Include/CmAxisAlignedBox.cpp

@@ -1,35 +0,0 @@
-/*
------------------------------------------------------------------------------
-This source file is part of OGRE
-(Object-oriented Graphics Rendering Engine)
-For the latest info, see http://www.ogre3d.org/
-
-Copyright (c) 2000-2011 Torus Knot Software Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
------------------------------------------------------------------------------
-*/
-#include "CmAxisAlignedBox.h"
-
-namespace CamelotFramework
-{
-	const AxisAlignedBox AxisAlignedBox::BOX_NULL;
-	const AxisAlignedBox AxisAlignedBox::BOX_INFINITE(AxisAlignedBox::EXTENT_INFINITE);
-}
-

+ 0 - 813
CamelotUtility/Include/CmAxisAlignedBox.h

@@ -1,813 +0,0 @@
-/*
------------------------------------------------------------------------------
-This source file is part of OGRE
-(Object-oriented Graphics Rendering Engine)
-For the latest info, see http://www.ogre3d.org/
-
-Copyright (c) 2000-2011 Torus Knot Software Ltd
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
------------------------------------------------------------------------------
-*/
-#ifndef __AxisAlignedBox_H_
-#define __AxisAlignedBox_H_
-
-// Precompiler options
-#include "CmPrerequisitesUtil.h"
-
-#include "CmVector3.h"
-#include "CmMatrix4.h"
-
-namespace CamelotFramework {
-	/** \addtogroup Core
-	*  @{
-	*/
-	/** \addtogroup Math
-	*  @{
-	*/
-
-	/** A 3D box aligned with the x/y/z axes.
-	@remarks
-	This class represents a simple box which is aligned with the
-	axes. Internally it only stores 2 points as the extremeties of
-	the box, one which is the minima of all 3 axes, and the other
-	which is the maxima of all 3 axes. This class is typically used
-	for an axis-aligned bounding box (AABB) for collision and
-	visibility determination.
-	*/
-	class CM_UTILITY_EXPORT AxisAlignedBox
-	{
-	public:
-		enum Extent
-		{
-			EXTENT_NULL,
-			EXTENT_FINITE,
-			EXTENT_INFINITE
-		};
-	protected:
-
-		Vector3 mMinimum;
-		Vector3 mMaximum;
-		Extent mExtent;
-		mutable Vector3* mpCorners;
-
-	public:
-		/*
-		   1-----2
-		  /|    /|
-		 / |   / |
-		5-----4  |
-		|  0--|--3
-		| /   | /
-		|/    |/
-		6-----7
-		*/
-		typedef enum {
-			FAR_LEFT_BOTTOM = 0,
-			FAR_LEFT_TOP = 1,
-			FAR_RIGHT_TOP = 2,
-			FAR_RIGHT_BOTTOM = 3,
-			NEAR_RIGHT_BOTTOM = 7,
-			NEAR_LEFT_BOTTOM = 6,
-			NEAR_LEFT_TOP = 5,
-			NEAR_RIGHT_TOP = 4
-		} CornerEnum;
-		inline AxisAlignedBox() : mMinimum(Vector3::ZERO), mMaximum(Vector3::UNIT_SCALE), mpCorners(0)
-		{
-			// Default to a null box 
-			setMinimum( -0.5, -0.5, -0.5 );
-			setMaximum( 0.5, 0.5, 0.5 );
-			mExtent = EXTENT_NULL;
-		}
-		inline AxisAlignedBox(Extent e) : mMinimum(Vector3::ZERO), mMaximum(Vector3::UNIT_SCALE), mpCorners(0)
-		{
-			setMinimum( -0.5, -0.5, -0.5 );
-			setMaximum( 0.5, 0.5, 0.5 );
-			mExtent = e;
-		}
-
-		inline AxisAlignedBox(const AxisAlignedBox & rkBox) : mMinimum(Vector3::ZERO), mMaximum(Vector3::UNIT_SCALE), mpCorners(0)
-
-		{
-			if (rkBox.isNull())
-				setNull();
-			else if (rkBox.isInfinite())
-				setInfinite();
-			else
-				setExtents( rkBox.mMinimum, rkBox.mMaximum );
-		}
-
-		inline AxisAlignedBox( const Vector3& min, const Vector3& max ) : mMinimum(Vector3::ZERO), mMaximum(Vector3::UNIT_SCALE), mpCorners(0)
-		{
-			setExtents( min, max );
-		}
-
-		inline AxisAlignedBox(
-			float mx, float my, float mz,
-			float Mx, float My, float Mz ) : mMinimum(Vector3::ZERO), mMaximum(Vector3::UNIT_SCALE), mpCorners(0)
-		{
-			setExtents( mx, my, mz, Mx, My, Mz );
-		}
-
-		AxisAlignedBox& operator=(const AxisAlignedBox& rhs)
-		{
-			// Specifically override to avoid copying mpCorners
-			if (rhs.isNull())
-				setNull();
-			else if (rhs.isInfinite())
-				setInfinite();
-			else
-				setExtents(rhs.mMinimum, rhs.mMaximum);
-
-			return *this;
-		}
-
-		~AxisAlignedBox()
-		{
-			if (mpCorners)
-				free(mpCorners);
-		}
-
-
-		/** Gets the minimum corner of the box.
-		*/
-		inline const Vector3& getMinimum(void) const
-		{ 
-			return mMinimum; 
-		}
-
-		/** Gets a modifiable version of the minimum
-		corner of the box.
-		*/
-		inline Vector3& getMinimum(void)
-		{ 
-			return mMinimum; 
-		}
-
-		/** Gets the maximum corner of the box.
-		*/
-		inline const Vector3& getMaximum(void) const
-		{ 
-			return mMaximum;
-		}
-
-		/** Gets a modifiable version of the maximum
-		corner of the box.
-		*/
-		inline Vector3& getMaximum(void)
-		{ 
-			return mMaximum;
-		}
-
-
-		/** Sets the minimum corner of the box.
-		*/
-		inline void setMinimum( const Vector3& vec )
-		{
-			mExtent = EXTENT_FINITE;
-			mMinimum = vec;
-		}
-
-		inline void setMinimum( float x, float y, float z )
-		{
-			mExtent = EXTENT_FINITE;
-			mMinimum.x = x;
-			mMinimum.y = y;
-			mMinimum.z = z;
-		}
-
-		/** Changes one of the components of the minimum corner of the box
-		used to resize only one dimension of the box
-		*/
-		inline void setMinimumX(float x)
-		{
-			mMinimum.x = x;
-		}
-
-		inline void setMinimumY(float y)
-		{
-			mMinimum.y = y;
-		}
-
-		inline void setMinimumZ(float z)
-		{
-			mMinimum.z = z;
-		}
-
-		/** Sets the maximum corner of the box.
-		*/
-		inline void setMaximum( const Vector3& vec )
-		{
-			mExtent = EXTENT_FINITE;
-			mMaximum = vec;
-		}
-
-		inline void setMaximum( float x, float y, float z )
-		{
-			mExtent = EXTENT_FINITE;
-			mMaximum.x = x;
-			mMaximum.y = y;
-			mMaximum.z = z;
-		}
-
-		/** Changes one of the components of the maximum corner of the box
-		used to resize only one dimension of the box
-		*/
-		inline void setMaximumX( float x )
-		{
-			mMaximum.x = x;
-		}
-
-		inline void setMaximumY( float y )
-		{
-			mMaximum.y = y;
-		}
-
-		inline void setMaximumZ( float z )
-		{
-			mMaximum.z = z;
-		}
-
-		/** Sets both minimum and maximum extents at once.
-		*/
-		inline void setExtents( const Vector3& min, const Vector3& max )
-		{
-            assert( (min.x <= max.x && min.y <= max.y && min.z <= max.z) &&
-                "The minimum corner of the box must be less than or equal to maximum corner" );
-
-			mExtent = EXTENT_FINITE;
-			mMinimum = min;
-			mMaximum = max;
-		}
-
-		inline void setExtents(
-			float mx, float my, float mz,
-			float Mx, float My, float Mz )
-		{
-            assert( (mx <= Mx && my <= My && mz <= Mz) &&
-                "The minimum corner of the box must be less than or equal to maximum corner" );
-
-			mExtent = EXTENT_FINITE;
-
-			mMinimum.x = mx;
-			mMinimum.y = my;
-			mMinimum.z = mz;
-
-			mMaximum.x = Mx;
-			mMaximum.y = My;
-			mMaximum.z = Mz;
-
-		}
-
-		/** Returns a pointer to an array of 8 corner points, useful for
-		collision vs. non-aligned objects.
-		@remarks
-		If the order of these corners is important, they are as
-		follows: The 4 points of the minimum Z face (note that
-		because Engine uses right-handed coordinates, the minimum Z is
-		at the 'back' of the box) starting with the minimum point of
-		all, then anticlockwise around this face (if you are looking
-		onto the face from outside the box). Then the 4 points of the
-		maximum Z face, starting with maximum point of all, then
-		anticlockwise around this face (looking onto the face from
-		outside the box). Like this:
-		<pre>
-		1-----2
-		/|    /|
-		/ |   / |
-		5-----4  |
-		|  0--|--3
-		| /   | /
-		|/    |/
-		6-----7
-		</pre>
-		@remarks as this implementation uses a static member, make sure to use your own copy !
-		*/
-		inline const Vector3* getAllCorners(void) const
-		{
-			assert( (mExtent == EXTENT_FINITE) && "Can't get corners of a null or infinite AAB" );
-
-			// The order of these items is, using right-handed co-ordinates:
-			// Minimum Z face, starting with Min(all), then anticlockwise
-			//   around face (looking onto the face)
-			// Maximum Z face, starting with Max(all), then anticlockwise
-			//   around face (looking onto the face)
-			// Only for optimization/compatibility.
-			if (!mpCorners)
-				mpCorners = (Vector3*)malloc(sizeof(Vector3) * 8);
-
-			mpCorners[0] = mMinimum;
-			mpCorners[1].x = mMinimum.x; mpCorners[1].y = mMaximum.y; mpCorners[1].z = mMinimum.z;
-			mpCorners[2].x = mMaximum.x; mpCorners[2].y = mMaximum.y; mpCorners[2].z = mMinimum.z;
-			mpCorners[3].x = mMaximum.x; mpCorners[3].y = mMinimum.y; mpCorners[3].z = mMinimum.z;            
-
-			mpCorners[4] = mMaximum;
-			mpCorners[5].x = mMinimum.x; mpCorners[5].y = mMaximum.y; mpCorners[5].z = mMaximum.z;
-			mpCorners[6].x = mMinimum.x; mpCorners[6].y = mMinimum.y; mpCorners[6].z = mMaximum.z;
-			mpCorners[7].x = mMaximum.x; mpCorners[7].y = mMinimum.y; mpCorners[7].z = mMaximum.z;
-
-			return mpCorners;
-		}
-
-		/** gets the position of one of the corners
-		*/
-		Vector3 getCorner(CornerEnum cornerToGet) const
-		{
-			switch(cornerToGet)
-			{
-			case FAR_LEFT_BOTTOM:
-				return mMinimum;
-			case FAR_LEFT_TOP:
-				return Vector3(mMinimum.x, mMaximum.y, mMinimum.z);
-			case FAR_RIGHT_TOP:
-				return Vector3(mMaximum.x, mMaximum.y, mMinimum.z);
-			case FAR_RIGHT_BOTTOM:
-				return Vector3(mMaximum.x, mMinimum.y, mMinimum.z);
-			case NEAR_RIGHT_BOTTOM:
-				return Vector3(mMaximum.x, mMinimum.y, mMaximum.z);
-			case NEAR_LEFT_BOTTOM:
-				return Vector3(mMinimum.x, mMinimum.y, mMaximum.z);
-			case NEAR_LEFT_TOP:
-				return Vector3(mMinimum.x, mMaximum.y, mMaximum.z);
-			case NEAR_RIGHT_TOP:
-				return mMaximum;
-			default:
-				return Vector3();
-			}
-		}
-
-		CM_UTILITY_EXPORT friend std::ostream& operator<<( std::ostream& o, const AxisAlignedBox aab )
-		{
-			switch (aab.mExtent)
-			{
-			case EXTENT_NULL:
-				o << "AxisAlignedBox(null)";
-				return o;
-
-			case EXTENT_FINITE:
-				o << "AxisAlignedBox(min=" << aab.mMinimum << ", max=" << aab.mMaximum << ")";
-				return o;
-
-			case EXTENT_INFINITE:
-				o << "AxisAlignedBox(infinite)";
-				return o;
-
-			default: // shut up compiler
-				assert( false && "Never reached" );
-				return o;
-			}
-		}
-
-		/** Merges the passed in box into the current box. The result is the
-		box which encompasses both.
-		*/
-		void merge( const AxisAlignedBox& rhs )
-		{
-			// Do nothing if rhs null, or this is infinite
-			if ((rhs.mExtent == EXTENT_NULL) || (mExtent == EXTENT_INFINITE))
-			{
-				return;
-			}
-			// Otherwise if rhs is infinite, make this infinite, too
-			else if (rhs.mExtent == EXTENT_INFINITE)
-			{
-				mExtent = EXTENT_INFINITE;
-			}
-			// Otherwise if current null, just take rhs
-			else if (mExtent == EXTENT_NULL)
-			{
-				setExtents(rhs.mMinimum, rhs.mMaximum);
-			}
-			// Otherwise merge
-			else
-			{
-				Vector3 min = mMinimum;
-				Vector3 max = mMaximum;
-				max.makeCeil(rhs.mMaximum);
-				min.makeFloor(rhs.mMinimum);
-
-				setExtents(min, max);
-			}
-
-		}
-
-		/** Extends the box to encompass the specified point (if needed).
-		*/
-		inline void merge( const Vector3& point )
-		{
-			switch (mExtent)
-			{
-			case EXTENT_NULL: // if null, use this point
-				setExtents(point, point);
-				return;
-
-			case EXTENT_FINITE:
-				mMaximum.makeCeil(point);
-				mMinimum.makeFloor(point);
-				return;
-
-			case EXTENT_INFINITE: // if infinite, makes no difference
-				return;
-			}
-
-			assert( false && "Never reached" );
-		}
-
-		/** Transforms the box according to the matrix supplied.
-		@remarks
-		By calling this method you get the axis-aligned box which
-		surrounds the transformed version of this box. Therefore each
-		corner of the box is transformed by the matrix, then the
-		extents are mapped back onto the axes to produce another
-		AABB. Useful when you have a local AABB for an object which
-		is then transformed.
-		*/
-		inline void transform( const Matrix4& matrix )
-		{
-			// Do nothing if current null or infinite
-			if( mExtent != EXTENT_FINITE )
-				return;
-
-			Vector3 oldMin, oldMax, currentCorner;
-
-			// Getting the old values so that we can use the existing merge method.
-			oldMin = mMinimum;
-			oldMax = mMaximum;
-
-			// reset
-			setNull();
-
-			// We sequentially compute the corners in the following order :
-			// 0, 6, 5, 1, 2, 4 ,7 , 3
-			// This sequence allows us to only change one member at a time to get at all corners.
-
-			// For each one, we transform it using the matrix
-			// Which gives the resulting point and merge the resulting point.
-
-			// First corner 
-			// min min min
-			currentCorner = oldMin;
-			merge( matrix * currentCorner );
-
-			// min,min,max
-			currentCorner.z = oldMax.z;
-			merge( matrix * currentCorner );
-
-			// min max max
-			currentCorner.y = oldMax.y;
-			merge( matrix * currentCorner );
-
-			// min max min
-			currentCorner.z = oldMin.z;
-			merge( matrix * currentCorner );
-
-			// max max min
-			currentCorner.x = oldMax.x;
-			merge( matrix * currentCorner );
-
-			// max max max
-			currentCorner.z = oldMax.z;
-			merge( matrix * currentCorner );
-
-			// max min max
-			currentCorner.y = oldMin.y;
-			merge( matrix * currentCorner );
-
-			// max min min
-			currentCorner.z = oldMin.z;
-			merge( matrix * currentCorner ); 
-		}
-
-		/** Transforms the box according to the affine matrix supplied.
-		@remarks
-		By calling this method you get the axis-aligned box which
-		surrounds the transformed version of this box. Therefore each
-		corner of the box is transformed by the matrix, then the
-		extents are mapped back onto the axes to produce another
-		AABB. Useful when you have a local AABB for an object which
-		is then transformed.
-		@note
-		The matrix must be an affine matrix. @see Matrix4::isAffine.
-		*/
-		void transformAffine(const Matrix4& m)
-		{
-			assert(m.isAffine());
-
-			// Do nothing if current null or infinite
-			if ( mExtent != EXTENT_FINITE )
-				return;
-
-			Vector3 centre = getCenter();
-			Vector3 halfSize = getHalfSize();
-
-			Vector3 newCentre = m.transformAffine(centre);
-			Vector3 newHalfSize(
-				Math::Abs(m[0][0]) * halfSize.x + Math::Abs(m[0][1]) * halfSize.y + Math::Abs(m[0][2]) * halfSize.z, 
-				Math::Abs(m[1][0]) * halfSize.x + Math::Abs(m[1][1]) * halfSize.y + Math::Abs(m[1][2]) * halfSize.z,
-				Math::Abs(m[2][0]) * halfSize.x + Math::Abs(m[2][1]) * halfSize.y + Math::Abs(m[2][2]) * halfSize.z);
-
-			setExtents(newCentre - newHalfSize, newCentre + newHalfSize);
-		}
-
-		/** Sets the box to a 'null' value i.e. not a box.
-		*/
-		inline void setNull()
-		{
-			mExtent = EXTENT_NULL;
-		}
-
-		/** Returns true if the box is null i.e. empty.
-		*/
-		inline bool isNull(void) const
-		{
-			return (mExtent == EXTENT_NULL);
-		}
-
-		/** Returns true if the box is finite.
-		*/
-		bool isFinite(void) const
-		{
-			return (mExtent == EXTENT_FINITE);
-		}
-
-		/** Sets the box to 'infinite'
-		*/
-		inline void setInfinite()
-		{
-			mExtent = EXTENT_INFINITE;
-		}
-
-		/** Returns true if the box is infinite.
-		*/
-		bool isInfinite(void) const
-		{
-			return (mExtent == EXTENT_INFINITE);
-		}
-
-		/** Returns whether or not this box intersects another. */
-		inline bool intersects(const AxisAlignedBox& b2) const
-		{
-			// Early-fail for nulls
-			if (this->isNull() || b2.isNull())
-				return false;
-
-			// Early-success for infinites
-			if (this->isInfinite() || b2.isInfinite())
-				return true;
-
-			// Use up to 6 separating planes
-			if (mMaximum.x < b2.mMinimum.x)
-				return false;
-			if (mMaximum.y < b2.mMinimum.y)
-				return false;
-			if (mMaximum.z < b2.mMinimum.z)
-				return false;
-
-			if (mMinimum.x > b2.mMaximum.x)
-				return false;
-			if (mMinimum.y > b2.mMaximum.y)
-				return false;
-			if (mMinimum.z > b2.mMaximum.z)
-				return false;
-
-			// otherwise, must be intersecting
-			return true;
-
-		}
-
-		/// Calculate the area of intersection of this box and another
-		inline AxisAlignedBox intersection(const AxisAlignedBox& b2) const
-		{
-            if (this->isNull() || b2.isNull())
-			{
-				return AxisAlignedBox();
-			}
-			else if (this->isInfinite())
-			{
-				return b2;
-			}
-			else if (b2.isInfinite())
-			{
-				return *this;
-			}
-
-			Vector3 intMin = mMinimum;
-            Vector3 intMax = mMaximum;
-
-            intMin.makeCeil(b2.getMinimum());
-            intMax.makeFloor(b2.getMaximum());
-
-            // Check intersection isn't null
-            if (intMin.x < intMax.x &&
-                intMin.y < intMax.y &&
-                intMin.z < intMax.z)
-            {
-                return AxisAlignedBox(intMin, intMax);
-            }
-
-            return AxisAlignedBox();
-		}
-
-		/// Calculate the volume of this box
-		float volume(void) const
-		{
-			switch (mExtent)
-			{
-			case EXTENT_NULL:
-				return 0.0f;
-
-			case EXTENT_FINITE:
-				{
-					Vector3 diff = mMaximum - mMinimum;
-					return diff.x * diff.y * diff.z;
-				}
-
-			case EXTENT_INFINITE:
-				return Math::POS_INFINITY;
-
-			default: // shut up compiler
-				assert( false && "Never reached" );
-				return 0.0f;
-			}
-		}
-
-		/** Scales the AABB by the vector given. */
-		inline void scale(const Vector3& s)
-		{
-			// Do nothing if current null or infinite
-			if (mExtent != EXTENT_FINITE)
-				return;
-
-			// NB assumes centered on origin
-			Vector3 min = mMinimum * s;
-			Vector3 max = mMaximum * s;
-			setExtents(min, max);
-		}
-
-		/** Tests whether this box intersects a sphere. */
-		bool intersects(const Sphere& s) const
-		{
-			return Math::intersects(s, *this); 
-		}
-		/** Tests whether this box intersects a plane. */
-		bool intersects(const Plane& p) const
-		{
-			return Math::intersects(p, *this);
-		}
-		/** Tests whether the vector point is within this box. */
-		bool intersects(const Vector3& v) const
-		{
-			switch (mExtent)
-			{
-			case EXTENT_NULL:
-				return false;
-
-			case EXTENT_FINITE:
-				return(v.x >= mMinimum.x  &&  v.x <= mMaximum.x  && 
-					v.y >= mMinimum.y  &&  v.y <= mMaximum.y  && 
-					v.z >= mMinimum.z  &&  v.z <= mMaximum.z);
-
-			case EXTENT_INFINITE:
-				return true;
-
-			default: // shut up compiler
-				assert( false && "Never reached" );
-				return false;
-			}
-		}
-		/// Gets the centre of the box
-		Vector3 getCenter(void) const
-		{
-			assert( (mExtent == EXTENT_FINITE) && "Can't get center of a null or infinite AAB" );
-
-			return Vector3(
-				(mMaximum.x + mMinimum.x) * 0.5f,
-				(mMaximum.y + mMinimum.y) * 0.5f,
-				(mMaximum.z + mMinimum.z) * 0.5f);
-		}
-		/// Gets the size of the box
-		Vector3 getSize(void) const
-		{
-			switch (mExtent)
-			{
-			case EXTENT_NULL:
-				return Vector3::ZERO;
-
-			case EXTENT_FINITE:
-				return mMaximum - mMinimum;
-
-			case EXTENT_INFINITE:
-				return Vector3(
-					Math::POS_INFINITY,
-					Math::POS_INFINITY,
-					Math::POS_INFINITY);
-
-			default: // shut up compiler
-				assert( false && "Never reached" );
-				return Vector3::ZERO;
-			}
-		}
-		/// Gets the half-size of the box
-		Vector3 getHalfSize(void) const
-		{
-			switch (mExtent)
-			{
-			case EXTENT_NULL:
-				return Vector3::ZERO;
-
-			case EXTENT_FINITE:
-				return (mMaximum - mMinimum) * 0.5;
-
-			case EXTENT_INFINITE:
-				return Vector3(
-					Math::POS_INFINITY,
-					Math::POS_INFINITY,
-					Math::POS_INFINITY);
-
-			default: // shut up compiler
-				assert( false && "Never reached" );
-				return Vector3::ZERO;
-			}
-		}
-
-        /** Tests whether the given point contained by this box.
-        */
-        bool contains(const Vector3& v) const
-        {
-            if (isNull())
-                return false;
-            if (isInfinite())
-                return true;
-
-            return mMinimum.x <= v.x && v.x <= mMaximum.x &&
-                   mMinimum.y <= v.y && v.y <= mMaximum.y &&
-                   mMinimum.z <= v.z && v.z <= mMaximum.z;
-        }
-
-        /** Tests whether another box contained by this box.
-        */
-        bool contains(const AxisAlignedBox& other) const
-        {
-            if (other.isNull() || this->isInfinite())
-                return true;
-
-            if (this->isNull() || other.isInfinite())
-                return false;
-
-            return this->mMinimum.x <= other.mMinimum.x &&
-                   this->mMinimum.y <= other.mMinimum.y &&
-                   this->mMinimum.z <= other.mMinimum.z &&
-                   other.mMaximum.x <= this->mMaximum.x &&
-                   other.mMaximum.y <= this->mMaximum.y &&
-                   other.mMaximum.z <= this->mMaximum.z;
-        }
-
-        /** Tests 2 boxes for equality.
-        */
-        bool operator== (const AxisAlignedBox& rhs) const
-        {
-            if (this->mExtent != rhs.mExtent)
-                return false;
-
-            if (!this->isFinite())
-                return true;
-
-            return this->mMinimum == rhs.mMinimum &&
-                   this->mMaximum == rhs.mMaximum;
-        }
-
-        /** Tests 2 boxes for inequality.
-        */
-        bool operator!= (const AxisAlignedBox& rhs) const
-        {
-            return !(*this == rhs);
-        }
-
-		// special values
-		static const AxisAlignedBox BOX_NULL;
-		static const AxisAlignedBox BOX_INFINITE;
-
-
-	};
-
-	/** @} */
-	/** @} */
-} // namespace CamelotFramework
-
-#endif

+ 1 - 1
CamelotUtility/Include/CmFwdDeclUtil.h

@@ -5,7 +5,7 @@ namespace CamelotFramework {
 	// Allows use of pointers in header files without including individual .h
 	// so decreases dependencies between files
 	class Angle;
-	class AxisAlignedBox;
+	class AABox;
 	class Degree;
 	class Math;
 	class Matrix3;

+ 5 - 5
CamelotUtility/Include/CmMath.h

@@ -438,7 +438,7 @@ namespace CamelotFramework
             bool discardInside = true);
         
         /** Ray / box intersection, returns boolean result and distance. */
-        static std::pair<bool, float> intersects(const Ray& ray, const AxisAlignedBox& box);
+        static std::pair<bool, float> intersects(const Ray& ray, const AABox& box);
 
         /** Ray / box intersection, returns boolean result and two intersection distance.
         @param
@@ -462,7 +462,7 @@ namespace CamelotFramework
             If the ray isn't intersects the box, <b>false</b> is returned, and
             <i>d1</i> and <i>d2</i> is unmodified.
         */
-        static bool intersects(const Ray& ray, const AxisAlignedBox& box,
+        static bool intersects(const Ray& ray, const AABox& box,
             float* d1, float* d2);
 
         /** Ray / triangle intersection, returns boolean result and distance.
@@ -518,10 +518,10 @@ namespace CamelotFramework
             bool positiveSide = true, bool negativeSide = true);
 
         /** Sphere / box intersection test. */
-        static bool intersects(const Sphere& sphere, const AxisAlignedBox& box);
+        static bool intersects(const Sphere& sphere, const AABox& box);
 
         /** Plane / box intersection test. */
-        static bool intersects(const Plane& plane, const AxisAlignedBox& box);
+        static bool intersects(const Plane& plane, const AABox& box);
 
         /** Ray / convex plane list intersection test. 
         @param ray The ray to test with
@@ -590,7 +590,7 @@ namespace CamelotFramework
 			const Matrix4* reflectMatrix = 0);
 
 		/** Get a bounding radius value from a bounding box. */
-		static float boundingRadiusFromAABB(const AxisAlignedBox& aabb);
+		static float boundingRadiusFromAABB(const AABox& aabb);
 
 
 

+ 1 - 1
CamelotUtility/Include/CmPlane.h

@@ -91,7 +91,7 @@ namespace CamelotFramework {
         Returns the side where the alignedBox is. The flag BOTH_SIDE indicates an intersecting box.
         One corner ON the plane is sufficient to consider the box and the plane intersecting.
         */
-        Side getSide (const AxisAlignedBox& rkBox) const;
+        Side getSide (const AABox& rkBox) const;
 
         /** Returns which side of the plane that the given box lies on.
             The box is defined as centre/half-size pairs for effectively.

+ 1 - 1
CamelotUtility/Include/CmRay.h

@@ -98,7 +98,7 @@ namespace CamelotFramework {
 			indicate the distance along the ray at which it intersects. 
 			This can be converted to a point in space by calling getPoint().
 		*/
-		std::pair<bool, float> intersects(const AxisAlignedBox& box) const
+		std::pair<bool, float> intersects(const AABox& box) const
 		{
 			return Math::intersects(*this, box);
 		}

+ 1 - 1
CamelotUtility/Include/CmSphere.h

@@ -82,7 +82,7 @@ namespace CamelotFramework {
                 Math::Sqr(s.mRadius + mRadius);
 		}
 		/** Returns whether or not this sphere intersects a box. */
-		bool intersects(const AxisAlignedBox& box) const
+		bool intersects(const AABox& box) const
 		{
 			return Math::intersects(*this, box);
 		}

+ 14 - 30
CamelotUtility/Source/CmMath.cpp

@@ -32,7 +32,7 @@ THE SOFTWARE.
 #include "CmVector4.h"
 #include "CmRay.h"
 #include "CmSphere.h"
-#include "CmAxisAlignedBox.h"
+#include "CmAABox.h"
 #include "CmPlane.h"
 
 
@@ -484,17 +484,14 @@ namespace CamelotFramework
 
     }
     //-----------------------------------------------------------------------
-	std::pair<bool, float> Math::intersects(const Ray& ray, const AxisAlignedBox& box)
+	std::pair<bool, float> Math::intersects(const Ray& ray, const AABox& box)
 	{
-		if (box.isNull()) return std::pair<bool, float>(false, 0.0f);
-		if (box.isInfinite()) return std::pair<bool, float>(true, 0.0f);
-
 		float lowt = 0.0f;
 		float t;
 		bool hit = false;
 		Vector3 hitpoint;
-		const Vector3& min = box.getMinimum();
-		const Vector3& max = box.getMaximum();
+		const Vector3& min = box.getMin();
+		const Vector3& max = box.getMax();
 		const Vector3& rayorig = ray.getOrigin();
 		const Vector3& raydir = ray.getDirection();
 
@@ -612,21 +609,11 @@ namespace CamelotFramework
 
 	} 
     //-----------------------------------------------------------------------
-    bool Math::intersects(const Ray& ray, const AxisAlignedBox& box,
+    bool Math::intersects(const Ray& ray, const AABox& box,
         float* d1, float* d2)
     {
-        if (box.isNull())
-            return false;
-
-        if (box.isInfinite())
-        {
-            if (d1) *d1 = 0;
-            if (d2) *d2 = Math::POS_INFINITY;
-            return true;
-        }
-
-        const Vector3& min = box.getMinimum();
-        const Vector3& max = box.getMaximum();
+        const Vector3& min = box.getMin();
+        const Vector3& max = box.getMax();
         const Vector3& rayorig = ray.getOrigin();
         const Vector3& raydir = ray.getDirection();
 
@@ -801,16 +788,13 @@ namespace CamelotFramework
         return intersects(ray, a, b, c, normal, positiveSide, negativeSide);
     }
     //-----------------------------------------------------------------------
-    bool Math::intersects(const Sphere& sphere, const AxisAlignedBox& box)
+    bool Math::intersects(const Sphere& sphere, const AABox& box)
     {
-        if (box.isNull()) return false;
-        if (box.isInfinite()) return true;
-
         // Use splitting planes
         const Vector3& center = sphere.getCenter();
         float radius = sphere.getRadius();
-        const Vector3& min = box.getMinimum();
-        const Vector3& max = box.getMaximum();
+        const Vector3& min = box.getMin();
+        const Vector3& max = box.getMax();
 
 		// Arvo's algorithm
 		float s, d = 0;
@@ -831,7 +815,7 @@ namespace CamelotFramework
 
     }
     //-----------------------------------------------------------------------
-    bool Math::intersects(const Plane& plane, const AxisAlignedBox& box)
+    bool Math::intersects(const Plane& plane, const AABox& box)
     {
         return (plane.getSide(box) == Plane::BOTH_SIDE);
     }
@@ -966,10 +950,10 @@ namespace CamelotFramework
 
 	}
 	//---------------------------------------------------------------------
-	float Math::boundingRadiusFromAABB(const AxisAlignedBox& aabb)
+	float Math::boundingRadiusFromAABB(const AABox& aabb)
 	{
-		Vector3 max = aabb.getMaximum();
-		Vector3 min = aabb.getMinimum();
+		Vector3 max = aabb.getMax();
+		Vector3 min = aabb.getMin();
 
 		Vector3 magnitude = max;
 		magnitude.makeCeil(-max);

+ 2 - 7
CamelotUtility/Source/CmPlane.cpp

@@ -28,7 +28,7 @@ THE SOFTWARE.
 
 #include "CmPlane.h"
 #include "CmMatrix3.h"
-#include "CmAxisAlignedBox.h" 
+#include "CmAABox.h" 
 
 namespace CamelotFramework {
 	//-----------------------------------------------------------------------
@@ -86,13 +86,8 @@ namespace CamelotFramework {
 
 
 	//-----------------------------------------------------------------------
-	Plane::Side Plane::getSide (const AxisAlignedBox& box) const
+	Plane::Side Plane::getSide (const AABox& box) const
 	{
-		if (box.isNull()) 
-			return NO_SIDE;
-		if (box.isInfinite())
-			return BOTH_SIDE;
-
         return getSide(box.getCenter(), box.getHalfSize());
 	}
     //-----------------------------------------------------------------------

+ 21 - 0
DrawHelper.txt

@@ -0,0 +1,21 @@
+Add class DrawHelper:
+ - Line2D_AA - Creates an emulated AA line using triangles. See Recast/imguiRenderGL::drawPolygon for implementation. Line vertices and colors
+      are appended in the specified buffer. No actual drawing is done.
+ - Line2D_Pixel - Creates a simple line using LINE primitive topology. Line vertices and colors are appended in the specified buffer.
+ - Quad2D
+ - QuadBorder2D_AA
+ - QuadBorder2D_Pixel
+ - Polygon2D
+ - PolygonBorder2D_AA
+ - PolygonBorder2D_Pixel
+ - LineList2D_AA
+ - LineList2D_Pixel
+ - RoundedRect2D - Also copy from Recast/imguiRenderGL::drawRoundedRect
+ - Also 3D equivalents
+  - Line, Quad, QuadBorder, Box, BoxBorder
+
+ - Then I also need draw* equivalents of those methods. draw equivalents will also create the buffer and submit the draw call.
+   - draw equivalents accept a time for how long to display the element, if 0 it will only be displayed for one frame
+   - all elements should be grouped into a common vertex/index buffer (as much as possible)
+   - draw methods should combine methods above to make drawing easier. e.g. a transparent box with AA line borders should be easily drawable
+

+ 23 - 0
PlatformPorting.txt

@@ -0,0 +1,23 @@
+Make porting to other platforms easier. Move platform specific files into their own /Platform subfolder.
+Reduce use of CM_PLATFORM where possible
+Split class into different files per-platform where possible
+
+GLRenderer
+ - Win32Window
+ - Win32Prerequisites
+ - Win32Context
+ - Win32GLSupport
+ - GLPRerequisities - different includes are added depending on platform 
+
+Utility
+ - Timer
+ - DynLibManager (currently has everything in one file, need to split it up)
+ - FileSystem - has some OS specific functionality
+
+Core
+ - Cursor - Also move to Utility?
+ - WindowEventUtilities - Rename the class, also split it into separate files per platform
+ - Application::loadPlugin - uses different extensions based on platform. Move platform specific functionality outside?
+
+Search for all occurencess of CM_PLATFORM
+ - Although in all other cases use of CM_PLATFORM can be removed, or is justified

+ 37 - 0
RenderOperation.txt

@@ -0,0 +1,37 @@
+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