Browse Source

Fixed DX9 and GL rendering which was broken due to new way forward renderer clears targets and renders objects
Made GUI materials use point filtering
Fixed incorrect 1 pixel offset in DX9 GUI materials

Marko Pintera 12 years ago
parent
commit
0581e2fea5

+ 2 - 0
BansheeEngine/Include/BsD3D11BuiltinMaterialFactory.h

@@ -24,6 +24,8 @@ namespace BansheeEngine
 		CM::ShaderPtr mSpriteImageShader;
 		CM::ShaderPtr mSpriteImageShader;
 		CM::ShaderPtr mDebugDrawShader;
 		CM::ShaderPtr mDebugDrawShader;
 
 
+		CM::HSamplerState mGUISamplerState;
+
 		void initSpriteTextShader();
 		void initSpriteTextShader();
 		void initSpriteImageShader();
 		void initSpriteImageShader();
 		void initDebugDrawShader();
 		void initDebugDrawShader();

+ 2 - 0
BansheeEngine/Include/BsD3D9BuiltinMaterialFactory.h

@@ -24,6 +24,8 @@ namespace BansheeEngine
 		CM::ShaderPtr mSpriteImageShader;
 		CM::ShaderPtr mSpriteImageShader;
 		CM::ShaderPtr mDebugDrawShader;
 		CM::ShaderPtr mDebugDrawShader;
 
 
+		CM::HSamplerState mGUISamplerState;
+
 		void initSpriteTextShader();
 		void initSpriteTextShader();
 		void initSpriteImageShader();
 		void initSpriteImageShader();
 		void initDebugDrawShader();
 		void initDebugDrawShader();

+ 2 - 0
BansheeEngine/Include/BsGLBuiltinMaterialFactory.h

@@ -24,6 +24,8 @@ namespace BansheeEngine
 		CM::ShaderPtr mSpriteImageShader;
 		CM::ShaderPtr mSpriteImageShader;
 		CM::ShaderPtr mDebugDrawShader;
 		CM::ShaderPtr mDebugDrawShader;
 
 
+		CM::HSamplerState mGUISamplerState;
+
 		void initSpriteTextShader();
 		void initSpriteTextShader();
 		void initSpriteImageShader();
 		void initSpriteImageShader();
 		void initDebugDrawShader();
 		void initDebugDrawShader();

+ 15 - 2
BansheeEngine/Source/BsD3D11BuiltinMaterialFactory.cpp

@@ -16,6 +16,13 @@ namespace BansheeEngine
 		initSpriteTextShader();
 		initSpriteTextShader();
 		initSpriteImageShader();
 		initSpriteImageShader();
 		initDebugDrawShader();
 		initDebugDrawShader();
+
+		SAMPLER_STATE_DESC ssDesc;
+		ssDesc.magFilter = FO_POINT;
+		ssDesc.minFilter = FO_POINT;
+		ssDesc.mipFilter = FO_POINT;
+
+		mGUISamplerState = SamplerState::create(ssDesc);
 	}
 	}
 
 
 	void D3D11BuiltinMaterialFactory::shutDown()
 	void D3D11BuiltinMaterialFactory::shutDown()
@@ -33,12 +40,18 @@ namespace BansheeEngine
 
 
 	HMaterial D3D11BuiltinMaterialFactory::createSpriteTextMaterial() const
 	HMaterial D3D11BuiltinMaterialFactory::createSpriteTextMaterial() const
 	{
 	{
-		return Material::create(mSpriteTextShader);
+		HMaterial newMaterial = Material::create(mSpriteTextShader);
+		newMaterial->setSamplerState("mainTexSamp", mGUISamplerState);
+
+		return newMaterial;
 	}
 	}
 
 
 	HMaterial D3D11BuiltinMaterialFactory::createSpriteImageMaterial() const
 	HMaterial D3D11BuiltinMaterialFactory::createSpriteImageMaterial() const
 	{
 	{
-		return Material::create(mSpriteImageShader);
+		HMaterial newMaterial = Material::create(mSpriteImageShader);
+		newMaterial->setSamplerState("mainTexSamp", mGUISamplerState);
+
+		return newMaterial;
 	}
 	}
 
 
 	HMaterial D3D11BuiltinMaterialFactory::createDebugDrawMaterial() const
 	HMaterial D3D11BuiltinMaterialFactory::createDebugDrawMaterial() const

+ 17 - 4
BansheeEngine/Source/BsD3D9BuiltinMaterialFactory.cpp

@@ -16,6 +16,13 @@ namespace BansheeEngine
 		initSpriteTextShader();
 		initSpriteTextShader();
 		initSpriteImageShader();
 		initSpriteImageShader();
 		initDebugDrawShader();
 		initDebugDrawShader();
+
+		SAMPLER_STATE_DESC ssDesc;
+		ssDesc.magFilter = FO_POINT;
+		ssDesc.minFilter = FO_POINT;
+		ssDesc.mipFilter = FO_POINT;
+
+		mGUISamplerState = SamplerState::create(ssDesc);
 	}
 	}
 
 
 	void D3D9BuiltinMaterialFactory::shutDown()
 	void D3D9BuiltinMaterialFactory::shutDown()
@@ -33,12 +40,18 @@ namespace BansheeEngine
 
 
 	HMaterial D3D9BuiltinMaterialFactory::createSpriteTextMaterial() const
 	HMaterial D3D9BuiltinMaterialFactory::createSpriteTextMaterial() const
 	{
 	{
-		return Material::create(mSpriteTextShader);
+		HMaterial newMaterial = Material::create(mSpriteTextShader);
+		newMaterial->setSamplerState("mainTexSamp", mGUISamplerState);
+
+		return newMaterial;
 	}
 	}
 
 
 	HMaterial D3D9BuiltinMaterialFactory::createSpriteImageMaterial() const
 	HMaterial D3D9BuiltinMaterialFactory::createSpriteImageMaterial() const
 	{
 	{
-		return Material::create(mSpriteImageShader);
+		HMaterial newMaterial = Material::create(mSpriteImageShader);
+		newMaterial->setSamplerState("mainTexSamp", mGUISamplerState);
+
+		return newMaterial;
 	}
 	}
 
 
 	HMaterial D3D9BuiltinMaterialFactory::createDebugDrawMaterial() const
 	HMaterial D3D9BuiltinMaterialFactory::createDebugDrawMaterial() const
@@ -62,7 +75,7 @@ namespace BansheeEngine
 				float4 tfrmdPos = mul(worldTransform, float4(inPos.xy, 0, 1));	\
 				float4 tfrmdPos = mul(worldTransform, float4(inPos.xy, 0, 1));	\
 																\
 																\
 				float tfrmdX = -1.0f + ((tfrmdPos.x - 0.5f) * invViewportWidth);			\
 				float tfrmdX = -1.0f + ((tfrmdPos.x - 0.5f) * invViewportWidth);			\
-				float tfrmdY = 1.0f - ((tfrmdPos.y + 0.5f) * invViewportHeight);			\
+				float tfrmdY = 1.0f - ((tfrmdPos.y - 0.5f) * invViewportHeight);			\
 																\
 																\
 				oPosition = float4(tfrmdX, tfrmdY, 0, 1);		\
 				oPosition = float4(tfrmdX, tfrmdY, 0, 1);		\
 				oUv = uv;										\
 				oUv = uv;										\
@@ -123,7 +136,7 @@ namespace BansheeEngine
 						float4 tfrmdPos = mul(worldTransform, float4(inPos.xy, 0, 1));	\
 						float4 tfrmdPos = mul(worldTransform, float4(inPos.xy, 0, 1));	\
 						\
 						\
 						float tfrmdX = -1.0f + ((tfrmdPos.x - 0.5f) * invViewportWidth);			\
 						float tfrmdX = -1.0f + ((tfrmdPos.x - 0.5f) * invViewportWidth);			\
-						float tfrmdY = 1.0f - ((tfrmdPos.y + 0.5f) * invViewportHeight);			\
+						float tfrmdY = 1.0f - ((tfrmdPos.y - 0.5f) * invViewportHeight);			\
 						\
 						\
 						oPosition = float4(tfrmdX, tfrmdY, 0, 1);		\
 						oPosition = float4(tfrmdX, tfrmdY, 0, 1);		\
 						oUv = uv;										\
 						oUv = uv;										\

+ 5 - 1
BansheeEngine/Source/BsEngineGUI.cpp

@@ -17,7 +17,7 @@ namespace BansheeEngine
 	const String EngineGUI::DefaultFontPath = "C:\\arial.ttf";
 	const String EngineGUI::DefaultFontPath = "C:\\arial.ttf";
 	const UINT32 EngineGUI::DefaultFontSize = 12;
 	const UINT32 EngineGUI::DefaultFontSize = 12;
 
 
-	const CM::String EngineGUI::WindowFramePrimaryTexture = "C:\\WindowFrameTest.bmp";
+	const CM::String EngineGUI::WindowFramePrimaryTexture = "C:\\WindowFrame.psd";
 
 
 	EngineGUI::EngineGUI()
 	EngineGUI::EngineGUI()
 	{
 	{
@@ -53,6 +53,10 @@ namespace BansheeEngine
 
 
 		GUIElementStyle windowFrameStyle;
 		GUIElementStyle windowFrameStyle;
 		windowFrameStyle.normal.texture = SpriteTexturePtr(CM_NEW(SpriteTexture, PoolAlloc) SpriteTexture(windowFrameTex), &MemAllocDeleter<SpriteTexture, PoolAlloc>::deleter);
 		windowFrameStyle.normal.texture = SpriteTexturePtr(CM_NEW(SpriteTexture, PoolAlloc) SpriteTexture(windowFrameTex), &MemAllocDeleter<SpriteTexture, PoolAlloc>::deleter);
+		windowFrameStyle.border.left = 1;
+		windowFrameStyle.border.right = 1;
+		windowFrameStyle.border.top = 1;
+		windowFrameStyle.border.bottom = 1;
 
 
 		mSkin.setStyle(GUIWindowFrame::getGUITypeName(), windowFrameStyle);
 		mSkin.setStyle(GUIWindowFrame::getGUITypeName(), windowFrameStyle);
 	}
 	}

+ 15 - 2
BansheeEngine/Source/BsGLBuiltinMaterialFactory.cpp

@@ -16,6 +16,13 @@ namespace BansheeEngine
 		initSpriteTextShader();
 		initSpriteTextShader();
 		initSpriteImageShader();
 		initSpriteImageShader();
 		initDebugDrawShader();
 		initDebugDrawShader();
+
+		SAMPLER_STATE_DESC ssDesc;
+		ssDesc.magFilter = FO_POINT;
+		ssDesc.minFilter = FO_POINT;
+		ssDesc.mipFilter = FO_POINT;
+
+		mGUISamplerState = SamplerState::create(ssDesc);
 	}
 	}
 
 
 	void GLBuiltinMaterialFactory::shutDown()
 	void GLBuiltinMaterialFactory::shutDown()
@@ -33,12 +40,18 @@ namespace BansheeEngine
 
 
 	HMaterial GLBuiltinMaterialFactory::createSpriteTextMaterial() const
 	HMaterial GLBuiltinMaterialFactory::createSpriteTextMaterial() const
 	{
 	{
-		return Material::create(mSpriteTextShader);
+		HMaterial newMaterial = Material::create(mSpriteTextShader);
+		newMaterial->setSamplerState("mainTexSamp", mGUISamplerState);
+
+		return newMaterial;
 	}
 	}
 
 
 	HMaterial GLBuiltinMaterialFactory::createSpriteImageMaterial() const
 	HMaterial GLBuiltinMaterialFactory::createSpriteImageMaterial() const
 	{
 	{
-		return Material::create(mSpriteImageShader);
+		HMaterial newMaterial = Material::create(mSpriteImageShader);
+		newMaterial->setSamplerState("mainTexSamp", mGUISamplerState);
+
+		return newMaterial;
 	}
 	}
 
 
 	HMaterial GLBuiltinMaterialFactory::createDebugDrawMaterial() const
 	HMaterial GLBuiltinMaterialFactory::createDebugDrawMaterial() const

+ 2 - 0
BansheeEngine/Source/BsGUIWindowFrame.cpp

@@ -36,6 +36,8 @@ namespace BansheeEngine
 		desc.borderRight = mStyle->border.right;
 		desc.borderRight = mStyle->border.right;
 		desc.borderTop = mStyle->border.top;
 		desc.borderTop = mStyle->border.top;
 		desc.borderBottom = mStyle->border.bottom;
 		desc.borderBottom = mStyle->border.bottom;
+		desc.width = 200;
+		desc.height = 200;
 
 
 		mImageSprite->update(desc);
 		mImageSprite->update(desc);
 
 

+ 4 - 2
BansheeEngine/Source/BsImageSprite.cpp

@@ -1,6 +1,8 @@
 #include "BsImageSprite.h"
 #include "BsImageSprite.h"
 #include "BsSpriteTexture.h"
 #include "BsSpriteTexture.h"
 #include "BsGUIMaterialManager.h"
 #include "BsGUIMaterialManager.h"
+#include "BsSpriteTexture.h"
+#include "CmTexture.h"
 
 
 using namespace CamelotFramework;
 using namespace CamelotFramework;
 
 
@@ -143,8 +145,8 @@ namespace BansheeEngine
 			renderElem.vertices[34] = Vector2(topRightStart, bottomStart + bottomBorder);
 			renderElem.vertices[34] = Vector2(topRightStart, bottomStart + bottomBorder);
 			renderElem.vertices[35] = Vector2(topRightStart + rightBorder, bottomStart + bottomBorder);
 			renderElem.vertices[35] = Vector2(topRightStart + rightBorder, bottomStart + bottomBorder);
 
 
-			float invWidth = 1.0f / (float)desc.width;
-			float invHeight = 1.0f / (float)desc.height;
+			float invWidth = 1.0f / (float)desc.texture->getTexture()->getWidth();
+			float invHeight = 1.0f / (float)desc.texture->getTexture()->getHeight();
 
 
 			float uvLeftBorder = desc.borderLeft * invWidth;
 			float uvLeftBorder = desc.borderLeft * invWidth;
 			float uvRightBorder = desc.borderRight * invWidth;
 			float uvRightBorder = desc.borderRight * invWidth;

+ 2 - 2
CamelotClient/CamelotClient.cpp

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

+ 2 - 0
CamelotClient/CmEditorWindow.cpp

@@ -6,6 +6,7 @@
 #include "BsGUIManager.h"
 #include "BsGUIManager.h"
 #include "BsGUIWidget.h"
 #include "BsGUIWidget.h"
 #include "BsGUILabel.h"
 #include "BsGUILabel.h"
+#include "BsGUIWindowFrame.h"
 #include "BsGUISkin.h"
 #include "BsGUISkin.h"
 #include "BsOverlayManager.h"
 #include "BsOverlayManager.h"
 #include "BsCamera.h"
 #include "BsCamera.h"
@@ -46,6 +47,7 @@ namespace BansheeEditor
 		//// DEBUG
 		//// DEBUG
 		mGUI->setSkin(&EngineGUI::instance().getSkin());
 		mGUI->setSkin(&EngineGUI::instance().getSkin());
 		mDbgLabel = GUILabel::create(mGUI.get(), "Testing test", renderWindowDesc.width);
 		mDbgLabel = GUILabel::create(mGUI.get(), "Testing test", renderWindowDesc.width);
+		GUIWindowFrame::create(mGUI.get());
 	}
 	}
 
 
 	EditorWindow::~EditorWindow()
 	EditorWindow::~EditorWindow()

+ 1 - 1
CamelotCore/Include/CmGpuParams.h

@@ -48,7 +48,7 @@ namespace CamelotFramework
 		void setTexture(const String& name, const HTexture& val);
 		void setTexture(const String& name, const HTexture& val);
 		HTexture getTexture(UINT32 slot);
 		HTexture getTexture(UINT32 slot);
 
 
-		void setSamplerState(const String& name, HSamplerState& val);
+		void setSamplerState(const String& name, const HSamplerState& val);
 		HSamplerState getSamplerState(UINT32 slot);
 		HSamplerState getSamplerState(UINT32 slot);
 
 
 		void setTransposeMatrices(bool transpose) { mTransposeMatrices = transpose; }
 		void setTransposeMatrices(bool transpose) { mTransposeMatrices = transpose; }

+ 1 - 1
CamelotCore/Include/CmMaterial.h

@@ -68,7 +68,7 @@ namespace CamelotFramework
 		ShaderPtr getShader() const { return mShader; }
 		ShaderPtr getShader() const { return mShader; }
 
 
 		void setTexture(const String& name, const HTexture& value);
 		void setTexture(const String& name, const HTexture& value);
-		void setSamplerState(const String& name, HSamplerState& samplerState);
+		void setSamplerState(const String& name, const HSamplerState& samplerState);
 		void setFloat(const String& name, float value, UINT32 arrayIdx = 0);
 		void setFloat(const String& name, float value, UINT32 arrayIdx = 0);
 		void setColor(const String& name, const Color& value, UINT32 arrayIdx = 0);
 		void setColor(const String& name, const Color& value, UINT32 arrayIdx = 0);
 		void setVec2(const String& name, const Vector2& value, UINT32 arrayIdx = 0);
 		void setVec2(const String& name, const Vector2& value, UINT32 arrayIdx = 0);

+ 1 - 1
CamelotCore/Source/CmGpuParams.cpp

@@ -270,7 +270,7 @@ namespace CamelotFramework
 		return mTextures[slot];
 		return mTextures[slot];
 	}
 	}
 
 
-	void GpuParams::setSamplerState(const String& name, HSamplerState& val)
+	void GpuParams::setSamplerState(const String& name, const HSamplerState& val)
 	{
 	{
 		auto paramIter = mParamDesc.samplers.find(name);
 		auto paramIter = mParamDesc.samplers.find(name);
 		if(paramIter == mParamDesc.samplers.end())
 		if(paramIter == mParamDesc.samplers.end())

+ 1 - 1
CamelotCore/Source/CmMaterial.cpp

@@ -547,7 +547,7 @@ namespace CamelotFramework
 		mTextureValues[name] = value;
 		mTextureValues[name] = value;
 	}
 	}
 
 
-	void Material::setSamplerState(const String& name, HSamplerState& samplerState)
+	void Material::setSamplerState(const String& name, const HSamplerState& samplerState)
 	{
 	{
 		throwIfNotInitialized();
 		throwIfNotInitialized();
 
 

+ 1 - 1
CamelotD3D9Renderer/Source/CmD3D9RenderSystem.cpp

@@ -1412,7 +1412,7 @@ namespace CamelotFramework
 			CM_EXCEPT(RenderingAPIException, "Error clearing frame buffer : " + msg);
 			CM_EXCEPT(RenderingAPIException, "Error clearing frame buffer : " + msg);
 		}
 		}
 
 
-		if(target != previousRenderTarget)
+		if(previousRenderTarget != nullptr && target != previousRenderTarget)
 		{
 		{
 			setRenderTarget(previousRenderTarget);
 			setRenderTarget(previousRenderTarget);
 		}
 		}

+ 1 - 11
CamelotGLRenderer/Source/CmGLRenderSystem.cpp

@@ -806,22 +806,12 @@ namespace CamelotFramework
 			glStencilMask(mStencilWriteMask);
 			glStencilMask(mStencilWriteMask);
 		}
 		}
 
 
-		if(target != previousRenderTarget)
+		if(previousRenderTarget != nullptr && target != previousRenderTarget)
 		{
 		{
 			setRenderTarget(previousRenderTarget);
 			setRenderTarget(previousRenderTarget);
 		}
 		}
 	}
 	}
 
 
-
-
-
-
-
-
-
-
-
-
 	/************************************************************************/
 	/************************************************************************/
 	/* 								PRIVATE		                     		*/
 	/* 								PRIVATE		                     		*/
 	/************************************************************************/
 	/************************************************************************/

+ 25 - 0
Notes.txt

@@ -32,6 +32,31 @@ Potential optimizations:
 ----------------------------------------------------------------------------------------------
 ----------------------------------------------------------------------------------------------
 More detailed thought out system descriptions:
 More detailed thought out system descriptions:
 
 
+<<<<Reducing render state changes>>>>
+ - Transparent objects get sorted back to front, always
+ - Opaque objects I can choose between front to back, no sort or back to front
+ - Then sort based on material-pass combo, rendering all passes of the same material at once, then moving to next pass, then to next material, etc.
+   - For transucent objects I need to render entire material at once, and not group by pass
+   - Ignore individual state and textures changes, just sort based on material
+ - Use key-based approach as described here: http://realtimecollisiondetection.net/blog/?p=86
+
+Questions/Notes:
+ 1. Could I make use of multiple texture slots so I don't have to re-assign textures for every material when rendering translucent objects pass by pass?
+   - When sorting back to front (or front to back) it's highly unlikely that there will be many objects sharing the same material next to the same depth level anyway. 
+     So probably ignore this problem for now, and just change the states.
+
+ 2. Should sorting be done on main or render thread?
+   - Main thread. It's highly unlikely main thread will be using as much CPU as render thread will, so free up render thread as much as possible.
+
+ 3. Should oct-tree queries be done on main or render thread?
+   - Main thread as I would need to save and copy the state of the entire scene, in order to pass it to the render thread. Otherwise we risk race conditions.
+
+ 4. Since render state and shader changes are much more expensive than shader constant/buffer/mesh (and even texture) changes, it might be a good idea to sort based on these,
+    instead of exact material? A lot of materials might share shaders and render states but not textures.
+
+ 5. This guy: http://home.comcast.net/~tom_forsyth/blog.wiki.html#%5B%5BRenderstate%20change%20costs%5D%5D (who's a driver programmer) sorts all opaque objects based on shader/state
+    into buckets, and then orders elements in these bucks in front to back order. This gives him best of two worlds, early z rejection and low state changes.
+
 <<<<DirectDraw>>>>
 <<<<DirectDraw>>>>
  - Used for quickly drawing something, usually for debug and editor purposes.
  - Used for quickly drawing something, usually for debug and editor purposes.
  - It consists of methods like: DrawLine, DrawPolygon, DrawCube, DrawSphere, etc.
  - It consists of methods like: DrawLine, DrawPolygon, DrawCube, DrawSphere, etc.

+ 9 - 9
TODO.txt

@@ -14,9 +14,8 @@ DebugDraw
  - DebugDraw support for AA lines
  - DebugDraw support for AA lines
  - Add DX9 and GL debug draw shaders
  - Add DX9 and GL debug draw shaders
 
 
-Avoid updating GUI every frame. Instead remember processed events and only update then.
 I still re-create GUIWidget mesh every frame instead of just updating it.
 I still re-create GUIWidget mesh every frame instead of just updating it.
-Make it so that widgets can be batched together. Probably means GUIWidget::updateMesh methods needs to move up to GUIManager or similar.
+
 MAJOR ISSUE: writeSubresource/readSubresoure doesn't require a shared ptr to GpuResourceData which means it could get destroyed while still in command queue. Right now it only works because I block right after I call those methods, which ensures nothing is destroyed.
 MAJOR ISSUE: writeSubresource/readSubresoure doesn't require a shared ptr to GpuResourceData which means it could get destroyed while still in command queue. Right now it only works because I block right after I call those methods, which ensures nothing is destroyed.
 GUIWidget::updateMeshes leaks. If I leave the game running I can see memory continously going up
 GUIWidget::updateMeshes leaks. If I leave the game running I can see memory continously going up
 
 
@@ -24,14 +23,15 @@ GUIWidget::updateMeshes leaks. If I leave the game running I can see memory cont
   - Although more than likely I am loading the model incorrectly since it works in Unity?
   - Although more than likely I am loading the model incorrectly since it works in Unity?
   - I probably want to determine front faces based on normals
   - I probably want to determine front faces based on normals
 
 
- GUIManager
-  - It starts before RenderWindowManager, which means I can't register the callbacks.
-    - If I start it after I miss main window creation, and also get an assert (not sure why the assert though - didn't explore)
-  - Keep track of window in focus
-
 Immediate TODO:
 Immediate TODO:
- - Allow only one widget per window (remove direct calls to attach/detach widget, and require parent window to be provided when initializing widget)
- - And make sure I clip widget to that window when updating bounds
+ - A way to handle onMouseOver, onMouseOut, onMouseDown, onMouseUp events
+ - Viewports have a Z order as well. I should use that instead of GUIWidget depth
+ - Make it so that widgets can be batched together. Probably means GUIWidget::updateMesh methods needs to move up to GUIManager or similar.
+   - However having widget transform update in shader means I have no way of merging multiple small GUIWidget elements into larger one (useful for batching when game UIs start using animation and stuff)
+     - However this might work with DX11 and newer OpenGL where we can fit in multiple transforms per pass.
+     - So refactor GUIWidget so it is capable of populating a vertex/index buffer, and then have 
+	   GUIManager be in charge of creating a mesh. And if possible we create as little meshes as possible, otherwise we just render them as we do now.
+     - Make sure to only batch widgets belonging to the same viewport
  - (optional) Implement DirectDraw for drawing the bounds so I know they're correct
  - (optional) Implement DirectDraw for drawing the bounds so I know they're correct
  - A way to update mesh buffers without recreating vertex/index buffers (Setting data currently does exactly that)
  - A way to update mesh buffers without recreating vertex/index buffers (Setting data currently does exactly that)