Browse Source

Tested and fixed normalized and pixel coordinates

Marko Pintera 12 years ago
parent
commit
c8d859fa7b

+ 32 - 23
BansheeEngine/Include/BsDrawHelper.h

@@ -9,8 +9,8 @@ namespace BansheeEngine
 {
 	enum class CoordType
 	{
-		ScreenSpace,
-		ClipSpace
+		Pixel,
+		Normalized
 	};
 
 	class BS_EXPORT DrawHelper : public CM::Module<DrawHelper>
@@ -35,53 +35,60 @@ namespace BansheeEngine
 		DrawHelper();
 
 		/**
-		 * @brief	TODO
+		 * @brief	Fills the mesh data with vertices representing a quad (2 triangles).
 		 *
-		 * @param	pos				TODO
-		 * @param	size			TODO
-		 * @param	meshData		Mesh data that will be populated by this method.
-		 * @param	vertexOffset	Number of vertices from buffer start to start writing at.
-		 * @param	indexOffset 	Number of indices from buffer start to start writing at.
+		 * @param	area			Area in which to draw the quad.
+		 * @param	meshData		Mesh data that will be populated.
+		 * @param	vertexOffset	Offset in number of vertices from the start of the buffer to start writing at.
+		 * @param	indexOffset 	Offset in number of indices from the start of the buffer to start writing at.
 		 * 							
 		 * @note	Provided MeshData must have some specific elements at least:
 		 * 			  Vector2 VES_POSITION
 		 * 			  32bit index buffer
+		 * 			  Enough space for 4 vertices and 6 indices
 		 */
-		void quad2D(const CM::Vector2& pos, const CM::Vector2& size, const CM::MeshDataPtr& meshData, CM::UINT32 vertexOffset, CM::UINT32 indexOffset);
+		void quad2D(const CM::FRect& area, const CM::MeshDataPtr& meshData, CM::UINT32 vertexOffset, CM::UINT32 indexOffset);
 
 		/**
-		 * @brief	TODO
+		 * @brief	Fills the mesh data with vertices representing a per-pixel line.
 		 *
-		 * @param	pos				TODO
-		 * @param	size			TODO
-		 * @param	meshData		Mesh data that will be populated by this method.
-		 * @param	vertexOffset	Number of vertices from buffer start to start writing at.
-		 * @param	indexOffset 	Number of indices from buffer start to start writing at.
+		 * @param	a				Start point of the line.
+		 * @param	b				End point of the line.
+		 * @param	color			Color of the line.
+		 * @param	meshData		Mesh data that will be populated.
+		 * @param	vertexOffset	Offset in number of vertices from the start of the buffer to start writing at.
+		 * @param	indexOffset 	Offset in number of indices from the start of the buffer to start writing at.
 		 * 							
 		 * @note	Provided MeshData must have some specific elements at least:
 		 * 			  Vector2 VES_POSITION
 		 * 			  UINT32  VES_COLOR
 		 * 			  32bit index buffer
+		 * 			  Enough space for 2 vertices and 2 indices
 		 */
 		void line2D_Pixel(const CM::Vector2& a, const CM::Vector2& b, const CM::Color& color, const CM::MeshDataPtr& meshData, CM::UINT32 vertexOffset, CM::UINT32 indexOffset);
 
 		/**
-		 * @brief	TODO
+		 * @brief	Fills the mesh data with vertices representing an anti-aliased line of specific width. Antialiasing is done using alpha blending.
 		 *
-		 * @param	pos				TODO
-		 * @param	size			TODO
+		 * @param	a				Start point of the line.
+		 * @param	b				End point of the line.
+		 * @param	width			Width of the line.
+		 * @param	color			Color of the line.
 		 * @param	meshData		Mesh data that will be populated by this method.
-		 * @param	vertexOffset	Number of vertices from buffer start to start writing at.
-		 * @param	indexOffset 	Number of indices from buffer start to start writing at.
+		 * @param	vertexOffset	Offset in number of vertices from the start of the buffer to start writing at.
+		 * @param	indexOffset 	Offset in number of indices from the start of the buffer to start writing at.
 		 * 							
 		 * @note	Provided MeshData must have some specific elements at least:
 		 * 			  Vector2 VES_POSITION
 		 * 			  UINT32  VES_COLOR
 		 * 			  32bit index buffer
+		 *			  Enough space for 8 vertices and 30 indices
 		 */
 		void line2D_AA(const CM::Vector2& a, const CM::Vector2& b, float width, const CM::Color& color, const CM::MeshDataPtr& meshData, CM::UINT32 vertexOffset, CM::UINT32 indexOffset);
 
-		void drawQuad2D(const HCamera& camera, const CM::Vector2& pos, const CM::Vector2& size, const CM::Color& color = CM::Color::White, CoordType coordType = CoordType::ScreenSpace, float timeout = 0.0f);
+		void drawQuad2D(const HCamera& camera, const CM::FRect& area, const CM::Color& color = CM::Color::White, CoordType coordType = CoordType::Pixel, float timeout = 0.0f);
+		void drawLine2D_Pixel(const HCamera& camera, const CM::Vector2& a, const CM::Vector2& b, const CM::Color& color = CM::Color::White, CoordType coordType = CoordType::Pixel, float timeout = 0.0f);
+		void drawLine2D_AA(const HCamera& camera, const CM::Vector2& a, const CM::Vector2& b, float width, const CM::Color& color = CM::Color::White, CoordType coordType = CoordType::Pixel, float timeout = 0.0f);
 
 		void render(const HCamera& camera, CM::RenderQueue& renderQueue);
 
@@ -90,8 +97,7 @@ namespace BansheeEngine
 
 		CM::UnorderedMap<const CM::Viewport*, CM::Vector<DebugDrawCommand>::type>::type mCommandsPerViewport;
 
-		// TODO - Add a version that accepts 4 points
-		void quad2D(const CM::Vector2& pos, const CM::Vector2& size, CM::UINT8* outVertices, CM::UINT32 vertexOffset, 
+		void quad2D(const CM::FRect& area, CM::UINT8* outVertices, CM::UINT32 vertexOffset, 
 			CM::UINT32 vertexStride, CM::UINT32* outIndices, CM::UINT32 indexOffset);
 
 		void line2D_Pixel(const CM::Vector2& a, const CM::Vector2& b, const CM::Color& color, CM::UINT8* outVertices, CM::UINT8* outColors, 
@@ -102,5 +108,8 @@ namespace BansheeEngine
 
 		void polygon2D_AA(const CM::Vector<CM::Vector2>::type& points, float width, const CM::Color& color, CM::UINT8* outVertices, CM::UINT8* outColors, 
 			CM::UINT32 vertexOffset, CM::UINT32 vertexStride, CM::UINT32* outIndices, CM::UINT32 indexOffset);
+
+		CM::FRect normalizedCoordToClipSpace(const CM::FRect& area) const;
+		CM::Vector2 normalizedCoordToClipSpace(const CM::Vector2& pos) const;
 	};
 }

+ 3 - 0
BansheeEngine/Source/BsD3D11BuiltinMaterialFactory.cpp

@@ -297,6 +297,9 @@ namespace BansheeEngine
 
 		mDebugDraw2DScreenSpaceShader = Shader::create("DebugDraw2DScreenSpaceShader");
 
+		mDebugDraw2DScreenSpaceShader->addParameter("invViewportWidth", "invViewportWidth", GPDT_FLOAT1);
+		mDebugDraw2DScreenSpaceShader->addParameter("invViewportHeight", "invViewportHeight", GPDT_FLOAT1);
+
 		TechniquePtr newTechnique = mDebugDraw2DScreenSpaceShader->addTechnique("D3D11RenderSystem", RendererManager::getCoreRendererName()); 
 		PassPtr newPass = newTechnique->addPass();
 		newPass->setVertexProgram(vsProgram);

+ 3 - 0
BansheeEngine/Source/BsD3D9BuiltinMaterialFactory.cpp

@@ -295,6 +295,9 @@ namespace BansheeEngine
 
 		mDebugDraw2DScreenSpaceShader = Shader::create("DebugDraw2DScreenSpaceShader");
 
+		mDebugDraw2DScreenSpaceShader->addParameter("invViewportWidth", "invViewportWidth", GPDT_FLOAT1);
+		mDebugDraw2DScreenSpaceShader->addParameter("invViewportHeight", "invViewportHeight", GPDT_FLOAT1);
+
 		TechniquePtr newTechnique = mDebugDraw2DScreenSpaceShader->addTechnique("D3D9RenderSystem", RendererManager::getCoreRendererName()); 
 		PassPtr newPass = newTechnique->addPass();
 		newPass->setVertexProgram(vsProgram);

+ 132 - 28
BansheeEngine/Source/BsDrawHelper.cpp

@@ -1,4 +1,5 @@
 #include "BsDrawHelper.h"
+#include "CmFRect.h"
 #include "CmMesh.h"
 #include "CmTime.h"
 #include "CmVector2.h"
@@ -18,41 +19,41 @@ namespace BansheeEngine
 		mMaterial2DClipSpace = BuiltinMaterialManager::instance().createDebugDraw2DClipSpaceMaterial();
 	}
 
-	void DrawHelper::quad2D(const Vector2& pos, const Vector2& size, UINT8* outVertices, 
+	void DrawHelper::quad2D(const CM::FRect& area, UINT8* outVertices, 
 		UINT32 vertexOffset, UINT32 vertexStride, UINT32* outIndices, UINT32 indexOffset)
 	{
 		outVertices += (vertexOffset * vertexStride);
 
 		Vector2* vertices = (Vector2*)outVertices;
-		(*vertices) = Vector2(pos.x, pos.y);
+		(*vertices) = Vector2(area.x, area.y);
 
 		vertices = (Vector2*)(outVertices + vertexStride);
-		(*vertices) = Vector2(pos.x + size.x, pos.y);
+		(*vertices) = Vector2(area.x + area.width, area.y);
 
 		vertices = (Vector2*)(outVertices + vertexStride * 2);
-		(*vertices) = Vector2(pos.x, pos.y + size.y);
+		(*vertices) = Vector2(area.x, area.y + area.height);
 
 		vertices = (Vector2*)(outVertices + vertexStride * 3);
-		(*vertices) = Vector2(pos.x + size.x, pos.y + size.y);
+		(*vertices) = Vector2(area.x + area.width, area.y + area.height);
 
 		outIndices += indexOffset;
 		outIndices[0] = vertexOffset + 0;
-		outIndices[1] = vertexOffset + 2;
-		outIndices[2] = vertexOffset + 1;
+		outIndices[1] = vertexOffset + 1;
+		outIndices[2] = vertexOffset + 2;
 		outIndices[3] = vertexOffset + 1;
-		outIndices[4] = vertexOffset + 2;
-		outIndices[5] = vertexOffset + 3;
+		outIndices[4] = vertexOffset + 3;
+		outIndices[5] = vertexOffset + 2;
 	}
 
-	void DrawHelper::quad2D(const CM::Vector2& pos, const CM::Vector2& size, const MeshDataPtr& meshData, CM::UINT32 vertexOffset, CM::UINT32 indexOffset)
+	void DrawHelper::quad2D(const CM::FRect& area, const MeshDataPtr& meshData, CM::UINT32 vertexOffset, CM::UINT32 indexOffset)
 	{
 		UINT32* indexData = meshData->getIndices32();
 		UINT8* positionData = meshData->getElementData(VES_POSITION);
 
-		assert((vertexOffset + 4) < meshData->getNumVertices());
-		assert((indexOffset + 6) < meshData->getNumIndices());
+		assert((vertexOffset + 4) <= meshData->getNumVertices());
+		assert((indexOffset + 6) <= meshData->getNumIndices());
 
-		quad2D(pos, size, positionData, vertexOffset, meshData->getVertexStride(), indexData, indexOffset);
+		quad2D(area, positionData, vertexOffset, meshData->getVertexStride(), indexData, indexOffset);
 	}
 
 	void DrawHelper::line2D_Pixel(const CM::Vector2& a, const CM::Vector2& b, const CM::Color& color, CM::UINT8* outVertices, CM::UINT8* outColors, 
@@ -84,8 +85,8 @@ namespace BansheeEngine
 		UINT8* positionData = meshData->getElementData(VES_POSITION);
 		UINT8* colorData = meshData->getElementData(VES_COLOR);
 
-		assert((vertexOffset + 2) < meshData->getNumVertices());
-		assert((indexOffset + 2) < meshData->getNumIndices());
+		assert((vertexOffset + 2) <= meshData->getNumVertices());
+		assert((indexOffset + 2) <= meshData->getNumIndices());
 
 		line2D_Pixel(a, b, color, positionData, colorData, vertexOffset, meshData->getVertexStride(), indexData, indexOffset);
 	}
@@ -127,8 +128,8 @@ namespace BansheeEngine
 		UINT8* positionData = meshData->getElementData(VES_POSITION);
 		UINT8* colorData = meshData->getElementData(VES_COLOR);
 
-		assert((vertexOffset + 2) < meshData->getNumVertices());
-		assert((indexOffset + 2) < meshData->getNumIndices());
+		assert((vertexOffset + 8) <= meshData->getNumVertices());
+		assert((indexOffset + 30) <= meshData->getNumIndices());
 
 		line2D_AA(a, b, width, color, positionData, colorData, vertexOffset, meshData->getVertexStride(), indexData, indexOffset);
 	}
@@ -222,7 +223,7 @@ namespace BansheeEngine
 		}
 	}
 
-	void DrawHelper::drawQuad2D(const HCamera& camera, const Vector2& pos, const Vector2& size, const Color& color, CoordType coordType, float timeout)
+	void DrawHelper::drawQuad2D(const HCamera& camera, const CM::FRect& area, const Color& color, CoordType coordType, float timeout)
 	{
 		const Viewport* viewport = camera->getViewport().get();
 
@@ -230,7 +231,6 @@ namespace BansheeEngine
 
 		commands.push_back(DebugDrawCommand());
 		DebugDrawCommand& dbgCmd = commands.back();
-		dbgCmd.type = DebugDrawType::ScreenSpace;
 		dbgCmd.endTime = gTime().getTime() + timeout;
 
 		MeshDataPtr meshData = cm_shared_ptr<MeshData, ScratchAlloc>(4);
@@ -238,19 +238,21 @@ namespace BansheeEngine
 		meshData->beginDesc();
 
 		meshData->addSubMesh(6);
-		meshData->addVertElem(VET_FLOAT3, VES_POSITION);
+		meshData->addVertElem(VET_FLOAT2, VES_POSITION);
 		meshData->addVertElem(VET_COLOR, VES_COLOR);
 
 		meshData->endDesc();
 
-		UINT32* indexData = meshData->getIndices32();
-		UINT8* positionData = meshData->getElementData(VES_POSITION);
-		UINT8* colorData = meshData->getElementData(VES_COLOR);
+		FRect actualArea = area;
+		if(coordType == CoordType::Normalized)
+			actualArea = normalizedCoordToClipSpace(area);
 
-		quad2D(pos, size, positionData, 0, meshData->getVertexStride(), indexData, 0);
+		quad2D(actualArea, meshData, 0, 0);
 
 		UINT32 vertexStride = meshData->getVertexStride();
-		UINT32* colors = (UINT32*)meshData->getElementData(VES_COLOR);
+		UINT8* colorData = meshData->getElementData(VES_COLOR);
+
+		UINT32* colors = (UINT32*)colorData;
 		(*colors) = color.getAsRGBA();
 
 		colors = (UINT32*)(colorData + vertexStride);
@@ -269,12 +271,98 @@ namespace BansheeEngine
 		dbgCmd.mesh = mesh;
 		dbgCmd.worldCenter = Vector3::ZERO;
 
-		if(coordType == CoordType::ClipSpace)
+		if(coordType == CoordType::Normalized)
 		{
+			dbgCmd.type = DebugDrawType::ClipSpace;
 			dbgCmd.material = mMaterial2DClipSpace;
 		}
 		else
 		{
+			dbgCmd.type = DebugDrawType::ScreenSpace;
+			dbgCmd.material = BuiltinMaterialManager::instance().createDebugDraw2DScreenSpaceMaterial();
+		}
+	}
+
+	void DrawHelper::drawLine2D_Pixel(const HCamera& camera, const Vector2& a, const Vector2& b, const Color& color, CoordType coordType, float timeout)
+	{
+		const Viewport* viewport = camera->getViewport().get();
+
+		Vector<DebugDrawCommand>::type& commands = mCommandsPerViewport[viewport];
+
+		commands.push_back(DebugDrawCommand());
+		DebugDrawCommand& dbgCmd = commands.back();
+		dbgCmd.endTime = gTime().getTime() + timeout;
+
+		MeshDataPtr meshData = cm_shared_ptr<MeshData, ScratchAlloc>(2);
+
+		meshData->beginDesc();
+
+		meshData->addSubMesh(2, 0, DOT_LINE_LIST);
+		meshData->addVertElem(VET_FLOAT2, VES_POSITION);
+		meshData->addVertElem(VET_COLOR, VES_COLOR);
+
+		meshData->endDesc();
+
+		line2D_Pixel(a, b, color, meshData, 0, 0);
+
+		HMesh mesh = Mesh::create();
+
+		gMainSyncedCA().writeSubresource(mesh.getInternalPtr(), 0, *meshData);
+		gMainSyncedCA().submitToCoreThread(true);
+
+		dbgCmd.mesh = mesh;
+		dbgCmd.worldCenter = Vector3::ZERO;
+
+		if(coordType == CoordType::Normalized)
+		{
+			dbgCmd.type = DebugDrawType::ClipSpace;
+			dbgCmd.material = mMaterial2DClipSpace;
+		}
+		else
+		{
+			dbgCmd.type = DebugDrawType::ScreenSpace;
+			dbgCmd.material = BuiltinMaterialManager::instance().createDebugDraw2DScreenSpaceMaterial();
+		}
+	}
+
+	void DrawHelper::drawLine2D_AA(const HCamera& camera, const Vector2& a, const Vector2& b, float width, const Color& color, CoordType coordType, float timeout)
+	{
+		const Viewport* viewport = camera->getViewport().get();
+
+		Vector<DebugDrawCommand>::type& commands = mCommandsPerViewport[viewport];
+
+		commands.push_back(DebugDrawCommand());
+		DebugDrawCommand& dbgCmd = commands.back();
+		dbgCmd.endTime = gTime().getTime() + timeout;
+
+		MeshDataPtr meshData = cm_shared_ptr<MeshData, ScratchAlloc>(8);
+
+		meshData->beginDesc();
+
+		meshData->addSubMesh(30, 0, DOT_TRIANGLE_LIST);
+		meshData->addVertElem(VET_FLOAT2, VES_POSITION);
+		meshData->addVertElem(VET_COLOR, VES_COLOR);
+
+		meshData->endDesc();
+
+		line2D_AA(a, b, width, color, meshData, 0, 0);
+
+		HMesh mesh = Mesh::create();
+
+		gMainSyncedCA().writeSubresource(mesh.getInternalPtr(), 0, *meshData);
+		gMainSyncedCA().submitToCoreThread(true);
+
+		dbgCmd.mesh = mesh;
+		dbgCmd.worldCenter = Vector3::ZERO;
+
+		if(coordType == CoordType::Normalized)
+		{
+			dbgCmd.type = DebugDrawType::ClipSpace;
+			dbgCmd.material = mMaterial2DClipSpace;
+		}
+		else
+		{
+			dbgCmd.type = DebugDrawType::ScreenSpace;
 			dbgCmd.material = BuiltinMaterialManager::instance().createDebugDraw2DScreenSpaceMaterial();
 		}
 	}
@@ -293,10 +381,10 @@ namespace BansheeEngine
 
 		for(auto& cmd : commands)
 		{
-			if(cmd.mesh == nullptr || !cmd.mesh.isLoaded())
+			if(cmd.mesh == nullptr || !cmd.mesh.isLoaded() || !cmd.mesh->isInitialized())
 				continue;
 
-			if(cmd.material == nullptr || !cmd.material.isLoaded())
+			if(cmd.material == nullptr || !cmd.material.isLoaded() || !cmd.material->isInitialized())
 				continue;
 
 			if(cmd.type == DebugDrawType::ClipSpace)
@@ -328,4 +416,20 @@ namespace BansheeEngine
 
 		commands.swap(newCommands);
 	}
+
+	FRect DrawHelper::normalizedCoordToClipSpace(const FRect& area) const
+	{
+		FRect clipSpaceRect;
+		clipSpaceRect.x = area.x * 2.0f - 1.0f;
+		clipSpaceRect.width = area.width * 2.0f;
+		clipSpaceRect.y = -area.y * 2.0f + 1.0f;
+		clipSpaceRect.height = area.height * -2.0f;
+
+		return clipSpaceRect;
+	}
+
+	Vector2 DrawHelper::normalizedCoordToClipSpace(const Vector2& pos) const
+	{
+		return Vector2(pos.x * 2.0f - 1.0f, -pos.y * 2.0f + 1.0f);
+	}
 }

+ 3 - 0
BansheeEngine/Source/BsGLBuiltinMaterialFactory.cpp

@@ -309,6 +309,9 @@ namespace BansheeEngine
 
 		mDebugDraw2DScreenSpaceShader = Shader::create("DebugDraw2DScreenSpaceShader");
 
+		mDebugDraw2DScreenSpaceShader->addParameter("invViewportWidth", "invViewportWidth", GPDT_FLOAT1);
+		mDebugDraw2DScreenSpaceShader->addParameter("invViewportHeight", "invViewportHeight", GPDT_FLOAT1);
+
 		TechniquePtr newTechnique = mDebugDraw2DScreenSpaceShader->addTechnique("GLRenderSystem", RendererManager::getCoreRendererName()); 
 		PassPtr newPass = newTechnique->addPass();
 		newPass->setVertexProgram(vsProgram);

+ 2 - 2
CamelotClient/CamelotClient.cpp

@@ -36,9 +36,9 @@
 #include "CmRTTIType.h"
 #include "CmCursor.h"
 
-//#define DX11
+#define DX11
 //#define DX9
-#define GL
+//#define GL
 
 using namespace CamelotFramework;
 using namespace BansheeEditor;

+ 3 - 1
CamelotClient/Source/BsMainEditorWindow.cpp

@@ -8,6 +8,7 @@
 #include "CmTestTextSprite.h"
 #include "CmDebugCamera.h"
 #include "BsDrawHelper.h"
+#include "CmFRect.h"
 
 using namespace CamelotFramework;
 using namespace BansheeEngine;
@@ -38,7 +39,8 @@ namespace BansheeEditor
 
 		textSprite->init(sceneCamera, "Testing in a new row, does this work?", nullptr);
 
-		DrawHelper::instance().drawQuad2D(sceneCamera, Vector2(-1.0f, 0.0f), Vector2(100, 50), Color::White, CoordType::ClipSpace, 50.0f);
+		DrawHelper::instance().drawQuad2D(sceneCamera, FRect(0.0f, 0.2f, 0.75f, 0.5f), Color::White, CoordType::Normalized, 50.0f);
+		DrawHelper::instance().drawQuad2D(sceneCamera, FRect(50.0f, 50.0f, 100.0f, 50.0f), Color::Blue, CoordType::Pixel, 50.0f);
 	}
 
 	MainEditorWindow::~MainEditorWindow()

+ 4 - 3
CamelotCore/Include/CmMesh.h

@@ -12,15 +12,16 @@ namespace CamelotFramework
 	struct CM_EXPORT SubMesh
 	{
 		SubMesh():
-			indexOffset(0), indexCount(0)
+			indexOffset(0), indexCount(0), drawOp(DOT_TRIANGLE_LIST)
 		{ }
 
-		SubMesh(UINT32 indexOffset, UINT32 indexCount):
-			indexOffset(indexOffset), indexCount(indexCount)
+		SubMesh(UINT32 indexOffset, UINT32 indexCount, DrawOperationType drawOp):
+			indexOffset(indexOffset), indexCount(indexCount), drawOp(drawOp)
 		{ }
 
 		UINT32 indexOffset;
 		UINT32 indexCount;
+		DrawOperationType drawOp;
 	};
 
 	class CM_EXPORT Mesh : public GpuResource

+ 11 - 6
CamelotCore/Include/CmMeshData.h

@@ -5,6 +5,7 @@
 #include "CmVertexBuffer.h"
 #include "CmIndexBuffer.h"
 #include "CmVertexDeclaration.h"
+#include "CmRenderOpMesh.h"
 
 namespace CamelotFramework
 {
@@ -67,12 +68,13 @@ namespace CamelotFramework
 		struct IndexElementData
 		{
 			IndexElementData()
-				:numIndices(0), subMesh(0), elementSize(0)
+				:numIndices(0), subMesh(0), elementSize(0), drawOp(DOT_TRIANGLE_LIST)
 			{ }
 
 			UINT32 numIndices;
 			UINT32 elementSize;
 			UINT32 subMesh;
+			DrawOperationType drawOp;
 		};
 
 		MeshData(UINT32 numVertices, IndexBuffer::IndexType indexType = IndexBuffer::IT_32BIT);
@@ -103,13 +105,15 @@ namespace CamelotFramework
 		void addVertElem(VertexElementType type, VertexElementSemantic semantic, UINT32 semanticIdx = 0, UINT32 streamIdx = 0);
 
 		/**
-		* @brief	Informs the internal buffer that it needs to make room for an index buffer of the specified size. If specified submesh
-		* 			already exists it will just be updated. This must be called between beginDesc and endDesc.
+		 * @brief	Informs the internal buffer that it needs to make room for an index buffer of the
+		 * 			specified size. If specified submesh already exists it will just be updated. This
+		 * 			must be called between beginDesc and endDesc.
 		 *
-		 * @param	numIndices	   	Number of indices.
-		 * @param	subMesh		   	(optional) the sub mesh.
+		 * @param	numIndices	Number of indices.
+		 * @param	subMesh   	(optional) Index of the sub-mesh to add/update.
+		 * @param	drawOp	  	(optional) Specifies the primitive type contained by the mesh.
 		 */
-		void addSubMesh(UINT32 numIndices, UINT32 subMesh = 0);
+		void addSubMesh(UINT32 numIndices, UINT32 subMesh = 0, DrawOperationType drawOp = DOT_TRIANGLE_LIST);
 
 		/**
 		 * @brief	Query if we have vertex data for the specified semantic.
@@ -176,6 +180,7 @@ namespace CamelotFramework
 		UINT32 getNumVertices() const { return mNumVertices; }
 		UINT32 getNumIndices(UINT32 subMesh) const;
 		UINT32 getNumIndices() const;
+		DrawOperationType getDrawOp(UINT32 subMesh) const;
 
 		UINT16* getIndices16(UINT32 subMesh = 0) const;
 		UINT32* getIndices32(UINT32 subMesh = 0) const;

+ 2 - 2
CamelotCore/Source/CmMesh.cpp

@@ -40,7 +40,7 @@ namespace CamelotFramework
 
 			if(numIndices > 0)
 			{
-				mSubMeshes.push_back(SubMesh(meshData.getIndexBufferOffset(i), numIndices));
+				mSubMeshes.push_back(SubMesh(meshData.getIndexBufferOffset(i), numIndices, meshData.getDrawOp(i)));
 			}
 		}
 
@@ -208,7 +208,7 @@ namespace CamelotFramework
 		ro.indexData = mIndexData;
 		ro.vertexData = mVertexData;
 		ro.useIndexes = true;
-		ro.operationType = DOT_TRIANGLE_LIST;
+		ro.operationType = mSubMeshes[subMeshIdx].drawOp;
 
 		return ro;
 	}

+ 7 - 1
CamelotCore/Source/CmMeshData.cpp

@@ -66,7 +66,7 @@ namespace CamelotFramework
 		mVertexElements.insert(mVertexElements.begin() + insertToIndex, newElement);
 	}
 
-	void MeshData::addSubMesh(UINT32 numIndices, UINT32 subMesh)
+	void MeshData::addSubMesh(UINT32 numIndices, UINT32 subMesh, DrawOperationType drawOp)
 	{
 		if(!mDescBuilding)
 			CM_EXCEPT(InternalErrorException, "Cannot add indices when not building description. Call beginDesc() first.");
@@ -79,6 +79,7 @@ namespace CamelotFramework
 		indexData.numIndices = numIndices;
 		indexData.elementSize = getIndexElementSize();
 		indexData.subMesh = subMesh;
+		indexData.drawOp = drawOp;
 
 		mSubMeshes[subMesh] = indexData;
 	}
@@ -111,6 +112,11 @@ namespace CamelotFramework
 		return mSubMeshes.at(subMesh).numIndices;
 	}
 
+	DrawOperationType MeshData::getDrawOp(UINT32 subMesh) const
+	{
+		return mSubMeshes.at(subMesh).drawOp;
+	}
+
 	UINT32 MeshData::getNumIndices() const
 	{
 		UINT32 count = 0;

+ 2 - 2
CamelotUtility/CamelotUtility.vcxproj

@@ -247,10 +247,10 @@
     <ClCompile Include="Source\CmAsyncOp.cpp" />
     <ClCompile Include="Source\CmBitmapWriter.cpp" />
     <ClCompile Include="Source\CmBox.cpp" />
+    <ClCompile Include="Source\CmFRect.cpp" />
     <ClCompile Include="Source\CmInt2.cpp" />
     <ClCompile Include="Source\CmManagedDataBlock.cpp" />
     <ClCompile Include="Source\CmMemStack.cpp" />
-    <ClCompile Include="Source\CmORect.cpp" />
     <ClCompile Include="Source\CmRect.cpp" />
     <ClCompile Include="Source\CmTexAtlasGenerator.cpp" />
     <ClCompile Include="Source\CmUUID.cpp" />
@@ -267,6 +267,7 @@
     <ClInclude Include="Include\CmException.h" />
     <ClInclude Include="Include\CmFileSerializer.h" />
     <ClInclude Include="Include\CmFileSystem.h" />
+    <ClInclude Include="Include\CmFRect.h" />
     <ClInclude Include="Include\CmInt2.h" />
     <ClInclude Include="Include\CmIReflectable.h" />
     <ClInclude Include="Include\CmKeyValuePair.h" />
@@ -275,7 +276,6 @@
     <ClInclude Include="Include\CmMathAsm.h" />
     <ClInclude Include="Include\CmMemoryAllocator.h" />
     <ClInclude Include="Include\CmModule.h" />
-    <ClInclude Include="Include\CmORect.h" />
     <ClInclude Include="Include\CmPath.h" />
     <ClInclude Include="Include\CmRect.h" />
     <ClInclude Include="Include\CmRTTIField.h" />

+ 6 - 6
CamelotUtility/CamelotUtility.vcxproj.filters

@@ -210,15 +210,15 @@
     <ClInclude Include="Include\CmMemoryAllocator.h">
       <Filter>Header Files</Filter>
     </ClInclude>
-    <ClInclude Include="Include\CmORect.h">
-      <Filter>Header Files\Math</Filter>
-    </ClInclude>
     <ClInclude Include="Include\CmMemStack.h">
       <Filter>Header Files</Filter>
     </ClInclude>
     <ClInclude Include="Include\CmAABox.h">
       <Filter>Header Files\Math</Filter>
     </ClInclude>
+    <ClInclude Include="Include\CmFRect.h">
+      <Filter>Header Files\Math</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CmMath.cpp">
@@ -311,9 +311,6 @@
     <ClCompile Include="Source\CmTexAtlasGenerator.cpp">
       <Filter>Source Files</Filter>
     </ClCompile>
-    <ClCompile Include="Source\CmORect.cpp">
-      <Filter>Source Files\Math</Filter>
-    </ClCompile>
     <ClCompile Include="Source\CmBox.cpp">
       <Filter>Source Files\Math</Filter>
     </ClCompile>
@@ -329,5 +326,8 @@
     <ClCompile Include="Include\CmAABox.cpp">
       <Filter>Source Files\Math</Filter>
     </ClCompile>
+    <ClCompile Include="Source\CmFRect.cpp">
+      <Filter>Source Files\Math</Filter>
+    </ClCompile>
   </ItemGroup>
 </Project>

+ 41 - 0
CamelotUtility/Include/CmFRect.h

@@ -0,0 +1,41 @@
+#pragma once
+
+#include "CmPrerequisitesUtil.h"
+
+namespace CamelotFramework
+{
+	class CM_UTILITY_EXPORT FRect
+	{
+	public:
+		FRect();
+		FRect(float _x, float _y, float _width, float _height);
+
+		float x, y, width, height;
+
+		bool contains(const Vector2& point) const;
+		bool overlaps(const FRect& other) const;
+		void encapsulate(const FRect& other);
+		void clip(const FRect& clipRect);
+
+		/**
+		 * @brief	Transforms the bounds by the given matrix.
+		 * 			Resulting value is an axis aligned rectangle encompassing the transformed points.
+		 * 			
+		 * @note	Since the resulting value is an AA rectangle of the original transformed rectangle, the bounds
+		 * 			will be larger than needed. Oriented rectangle would provide a much tighter fit.
+		 */
+		void transform(const Matrix4& matrix);
+
+		inline bool operator== (const FRect& rhs) const
+		{
+			return x == rhs.x && y == rhs.y && width == rhs.width && height == rhs.height;
+		}
+
+		inline bool operator!= (const FRect& rhs) const
+		{
+			return !(*this == rhs);
+		}
+
+		static const FRect EMPTY;
+	};
+}

+ 1 - 0
CamelotUtility/Include/CmFwdDeclUtil.h

@@ -20,6 +20,7 @@ namespace CamelotFramework {
 	class Vector4;
 	struct Int2;
 	class Rect;
+	class FRect;
 	class Color;
 	class DynLib;
 	class DynLibManager;

+ 0 - 32
CamelotUtility/Include/CmORect.h

@@ -1,32 +0,0 @@
-#pragma once
-
-#include "CmPrerequisitesUtil.h"
-#include "CmVector2.h"
-#include "CmRect.h"
-#include "CmMatrix4.h"
-
-namespace CamelotFramework
-{
-	/**
-	 * @brief	Oriented rectangle. Can be rotated/translated/scaled. Skewing and similar transformations
-	 * 			are not supported.
-	 * 			TODO - Can be made faster. Speed wasn't my concern when designing the class.
-	 */
-	class CM_UTILITY_EXPORT ORect
-	{
-	public:
-		ORect();
-		ORect(const Rect& rect);
-		
-		void applyTransform(const Matrix4& tfrm);
-		bool contains(const Vector2& point);
-
-		Vector2 getMin() const;
-		Vector2 getMax() const;
-
-	private:
-		Vector2 mOrigin;
-		Vector2 mSides[2];
-		float mSideLengths[2]; // Redundant but I want my side normals to be normalized
-	};
-}

+ 118 - 0
CamelotUtility/Source/CmFRect.cpp

@@ -0,0 +1,118 @@
+#include "CmFRect.h"
+#include "CmVector2.h"
+#include "CmMatrix4.h"
+#include "CmMath.h"
+
+namespace CamelotFramework
+{
+	const FRect FRect::EMPTY = FRect();
+
+	FRect::FRect()
+		:x(0), y(0), width(0), height(0)
+	{ }
+
+	FRect::FRect(float _x, float _y, float _width, float _height)
+		:x(_x), y(_y), width(_width), height(_height)
+	{ }
+
+	bool FRect::contains(const Vector2& point) const
+	{
+		if(point.x >= x && point.x <= (x + width))
+		{
+			if(point.y >= y && point.y <= (y + height))
+				return true;
+		}
+
+		return false;
+	}
+
+	bool FRect::overlaps(const FRect& other) const
+	{
+		float otherRight = other.x + other.width;
+		float myRight = x + width;
+
+		float otherBottom = other.y + other.height;
+		float myBottom = y + height;
+
+		if(x < otherRight && myRight > other.x &&
+			y < otherBottom && myBottom > other.y)
+			return true;
+
+		return false;
+	}
+
+	void FRect::encapsulate(const FRect& other)
+	{
+		float myRight = x + width;
+		float myBottom = y + height;
+		float otherRight = other.x + other.width;
+		float otherBottom = other.y + other.height;
+
+		if(other.x < x)
+			x = other.x;
+
+		if(other.y < y)
+			y = other.y;
+
+		if(otherRight > myRight)
+			width = otherRight - x;
+		else
+			width = myRight - x;
+
+		if(otherBottom > myBottom)
+			height = otherBottom - y;
+		else
+			height = myBottom - y;
+	}
+
+	void FRect::clip(const FRect& clipRect)
+	{
+		float newLeft = std::max(x, clipRect.x);
+		float newTop = std::max(y, clipRect.y);
+
+		float newRight = std::min(x + width, clipRect.x + clipRect.width);
+		float newBottom = std::min(y + height, clipRect.y + clipRect.height);
+
+		x = newLeft;
+		y = newTop;
+		width = newRight - newLeft;
+		height = newBottom - newTop;
+	}
+
+	void FRect::transform(const Matrix4& matrix)
+	{
+		Vector4 verts[4];
+		verts[0] = Vector4(x, y, 0.0f, 1.0f);
+		verts[1] = Vector4(x + width, y, 0.0f, 1.0f);
+		verts[2] = Vector4(x, y + height, 0.0f, 1.0f);
+		verts[3] = Vector4(x + width, y + height, 0.0f, 1.0f);
+
+		for(UINT32 i = 0; i < 4; i++)
+			verts[i] = matrix * verts[i];
+
+		float minX = std::numeric_limits<float>::max();
+		float maxX = std::numeric_limits<float>::min();
+		float minY = std::numeric_limits<float>::max();
+		float maxY = std::numeric_limits<float>::min();
+
+		for(UINT32 i = 0; i < 4; i++)
+		{
+			if(verts[i].x < minX)
+				minX = verts[i].x;
+
+			if(verts[i].y < minY)
+				minY = verts[i].y;
+
+			if(verts[i].x > maxX)
+				maxX = verts[i].x;
+
+			if(verts[i].y > maxY)
+				maxY = verts[i].y;
+		}
+
+		x = minX;
+		y = minY;
+		width = maxX - x;
+		height = maxY - y;
+	}
+}

+ 0 - 80
CamelotUtility/Source/CmORect.cpp

@@ -1,80 +0,0 @@
-#include "CmORect.h"
-
-namespace CamelotFramework
-{
-	ORect::ORect()
-	{	}
-
-	ORect::ORect(const Rect& rect)
-	{
-		mOrigin = Vector2((float)rect.x, (float)rect.y);
-		mSides[0] = Vector2((float)rect.width, 0.0f);
-		mSides[1] = Vector2(0.0f, (float)rect.height);
-
-		mSideLengths[0] = mSides[0].length();
-		mSideLengths[1] = mSides[1].length();
-
-		mSides[0].normalize();
-		mSides[1].normalize();
-	}
-
-	void ORect::applyTransform(const Matrix4& tfrm)
-	{
-		Vector3 oldOrigin = Vector3(mOrigin.x, mOrigin.y, 0);
-
-		Vector3 oldCornerA = oldOrigin + Vector3(mSides[0].x * mSideLengths[0], mSides[0].y * mSideLengths[0], 0.0f);
-		Vector3 newCornerA = tfrm * oldCornerA;
-
-		Vector3 oldCornerB = oldOrigin + Vector3(mSides[1].x * mSideLengths[1], mSides[1].y * mSideLengths[1], 0.0f);
-		Vector3 newCornerB = tfrm * oldCornerB;
-
-		Vector3 newOrigin = tfrm * oldOrigin;
-		mOrigin.x = newOrigin.x;
-		mOrigin.y = newOrigin.y;
-
-		mSides[0].x = newCornerA.x - newOrigin.x;
-		mSides[0].y = newCornerA.y - newOrigin.y;
-
-		mSides[1].x = newCornerB.x - newOrigin.x;
-		mSides[1].y = newCornerB.y - newOrigin.y;
-
-		mSideLengths[0] = mSides[0].length();
-		mSideLengths[1] = mSides[1].length();
-
-		mSides[0].normalize();
-		mSides[1].normalize();
-	}
-
-	bool ORect::contains(const Vector2& point)
-	{
-		Vector2 localPoint = point - mOrigin;
-
-		float t1 = localPoint.x * mSides[0].x + localPoint.y * mSides[0].y;
-		float t2 = localPoint.x * mSides[1].x + localPoint.y * mSides[1].y;
-
-		if(t1 >= 0.0f && t1 <= mSideLengths[0] && t2 >= 0.0f && t1 <= mSideLengths[1])
-			return true;
-
-		return false;
-	}
-
-	Vector2 ORect::getMin() const
-	{
-		Vector2 result;
-
-		result.x = std::min(std::min(mOrigin.x, mOrigin.x + mSides[0].x), mOrigin.x + mSides[1].x);
-		result.y = std::min(std::min(mOrigin.y, mOrigin.y + mSides[0].y), mOrigin.y + mSides[1].y);
-
-		return result;
-	}
-
-	Vector2 ORect::getMax() const
-	{
-		Vector2 result;
-
-		result.x = std::max(std::max(mOrigin.x, mOrigin.x + mSides[0].x), mOrigin.x + mSides[1].x);
-		result.y = std::max(std::max(mOrigin.y, mOrigin.y + mSides[0].y), mOrigin.y + mSides[1].y);
-
-		return result;
-	}
-}

+ 0 - 4
DrawHelper.txt

@@ -15,8 +15,4 @@ Add class DrawHelper:
 
 --------------------------
 
-Add extra parameter to each of the 2D draw methods: ScreenSpace or ClipSpace
-(They may use 3D versions for world space)
- - I need two separate 2D materials
-
  Only one material per viewport needs to exist, no need for separate material for each element