Browse Source

Added GUI bounds and gui widget transform

Marko Pintera 12 years ago
parent
commit
4f6bbe7067

+ 3 - 0
CamelotCore/Include/CmGUIElement.h

@@ -60,6 +60,8 @@ namespace CamelotEngine
 		 */
 		 */
 		virtual void fillBuffer(Vector2* vertices, Vector2* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 renderElementIdx) const = 0;
 		virtual void fillBuffer(Vector2* vertices, Vector2* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 renderElementIdx) const = 0;
 
 
+		const Rect& getBounds() const { return mBounds; }
+
 		//  onMouseMove
 		//  onMouseMove
 		//	onMousePress
 		//	onMousePress
 		//	onMouseReleased
 		//	onMouseReleased
@@ -67,6 +69,7 @@ namespace CamelotEngine
 		//	onKeyReleased
 		//	onKeyReleased
 	protected:
 	protected:
 		GUIWidget* mParent;
 		GUIWidget* mParent;
+		Rect mBounds;
 		const GUIElementStyle* mStyle;
 		const GUIElementStyle* mStyle;
 	};
 	};
 }
 }

+ 3 - 0
CamelotCore/Include/CmSprite.h

@@ -48,6 +48,7 @@ namespace CamelotEngine
 		UINT32 getHeight() const { return mHeight; }
 		UINT32 getHeight() const { return mHeight; }
 		Rect getClipRect() const { return mClipRect; }
 		Rect getClipRect() const { return mClipRect; }
 		SpriteAnchor getAnchor() const { return mAnchor; }
 		SpriteAnchor getAnchor() const { return mAnchor; }
+		const Rect& getBounds() const;
 
 
 		/**
 		/**
 		 * @brief	Returns the number of separate render elements in the sprite. Normally this is one, but some sprites
 		 * @brief	Returns the number of separate render elements in the sprite. Normally this is one, but some sprites
@@ -101,6 +102,7 @@ namespace CamelotEngine
 		Rect mClipRect;
 		Rect mClipRect;
 		SpriteAnchor mAnchor;
 		SpriteAnchor mAnchor;
 
 
+		mutable Rect mBounds;
 		mutable bool mIsDirty;
 		mutable bool mIsDirty;
 		mutable vector<SpriteRenderElement>::type mCachedRenderElements;
 		mutable vector<SpriteRenderElement>::type mCachedRenderElements;
 
 
@@ -109,6 +111,7 @@ namespace CamelotEngine
 		bool isClipRectangleValid() const;
 		bool isClipRectangleValid() const;
 
 
 		virtual void updateMesh() const = 0;
 		virtual void updateMesh() const = 0;
+		void updateBounds() const;
 		void clearMesh() const;
 		void clearMesh() const;
 	};
 	};
 }
 }

+ 2 - 0
CamelotCore/Source/CmGUILabel.cpp

@@ -18,6 +18,8 @@ namespace CamelotEngine
 		mTextSprite->setWordWrap(wordWrap);
 		mTextSprite->setWordWrap(wordWrap);
 		mTextSprite->setClipRect(Rect(0, 0, fixedWidth, fixedHeight));
 		mTextSprite->setClipRect(Rect(0, 0, fixedWidth, fixedHeight));
 		mTextSprite->setAlignment(horzAlign, vertAlign);
 		mTextSprite->setAlignment(horzAlign, vertAlign);
+
+		mBounds = mTextSprite->getBounds();
 	}
 	}
 
 
 	GUILabel::~GUILabel()
 	GUILabel::~GUILabel()

+ 4 - 1
CamelotCore/Source/CmGUIWidget.cpp

@@ -8,6 +8,7 @@
 #include "CmMesh.h"
 #include "CmMesh.h"
 #include "CmCamera.h"
 #include "CmCamera.h"
 #include "CmViewport.h"
 #include "CmViewport.h"
+#include "CmSceneObject.h"
 
 
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
@@ -159,6 +160,8 @@ namespace CamelotEngine
 
 
 	void GUIWidget::render(const Camera* camera, DeferredRenderContextPtr& renderContext) const
 	void GUIWidget::render(const Camera* camera, DeferredRenderContextPtr& renderContext) const
 	{
 	{
+		SO()->setPosition(Vector3(200, 100, 0));
+
 		// Mesh is re-created every frame. There might be a better approach that only recreates it upon change,
 		// Mesh is re-created every frame. There might be a better approach that only recreates it upon change,
 		// but for now it seems like too much hassle for something like GUI that is pretty dynamic anyway.
 		// but for now it seems like too much hassle for something like GUI that is pretty dynamic anyway.
 		updateMeshes();
 		updateMeshes();
@@ -173,6 +176,7 @@ namespace CamelotEngine
 			// might be more optimal to just scale the mesh as the resolution changes?
 			// might be more optimal to just scale the mesh as the resolution changes?
 			material->setFloat("halfViewportWidth", camera->getViewport()->getWidth() * 0.5f);
 			material->setFloat("halfViewportWidth", camera->getViewport()->getWidth() * 0.5f);
 			material->setFloat("halfViewportHeight", camera->getViewport()->getHeight() * 0.5f);
 			material->setFloat("halfViewportHeight", camera->getViewport()->getHeight() * 0.5f);
+			material->setMat4("worldTransform", SO()->getWorldTfrm());
 
 
 			if(material == nullptr || !material.isLoaded())
 			if(material == nullptr || !material.isLoaded())
 				continue;
 				continue;
@@ -180,7 +184,6 @@ namespace CamelotEngine
 			if(mesh == nullptr || !mesh.isLoaded())
 			if(mesh == nullptr || !mesh.isLoaded())
 				continue;
 				continue;
 
 
-			// TODO - Set current viewport resolution so that GUI can be rendered properly
 			for(UINT32 i = 0; i < material->getNumPasses(); i++)
 			for(UINT32 i = 0; i < material->getNumPasses(); i++)
 			{
 			{
 				PassPtr pass = material->getPass(i);
 				PassPtr pass = material->getPass(i);

+ 46 - 0
CamelotCore/Source/CmSprite.cpp

@@ -103,6 +103,51 @@ namespace CamelotEngine
 		return mClipRect.width > 0 && mClipRect.height > 0;
 		return mClipRect.width > 0 && mClipRect.height > 0;
 	}
 	}
 
 
+	const Rect& Sprite::getBounds() const
+	{
+		if(mIsDirty)
+		{
+			updateMesh();
+			mIsDirty = false;
+		}
+
+		return mBounds;
+	}
+
+	void Sprite::updateBounds() const
+	{
+		Vector2 min;
+		Vector2 max;
+
+		// Find starting point
+		for(auto& renderElem : mCachedRenderElements)
+		{
+			if(renderElem.vertices != nullptr && renderElem.numQuads > 0)
+			{
+				min = renderElem.vertices[0];
+				max = renderElem.vertices[0];
+				break;
+			}
+		}
+
+		// Calculate bounds
+		for(auto& renderElem : mCachedRenderElements)
+		{
+			if(renderElem.vertices != nullptr && renderElem.numQuads > 0)
+			{
+				UINT32 vertexCount = renderElem.numQuads * 4;
+
+				for(UINT32 i = 0; i < vertexCount; i++)
+				{
+					min = Vector2::min(min, renderElem.vertices[i]);
+					max = Vector2::max(max, renderElem.vertices[i]);
+				}
+			}
+		}
+
+		mBounds = Rect((int)min.x, (int)min.y, (int)(max.x - min.x), (int)(max.y - min.y));
+	}
+
 	void Sprite::clearMesh() const
 	void Sprite::clearMesh() const
 	{
 	{
 		for(auto& renderElem : mCachedRenderElements)
 		for(auto& renderElem : mCachedRenderElements)
@@ -126,5 +171,6 @@ namespace CamelotEngine
 		}
 		}
 
 
 		mCachedRenderElements.clear();
 		mCachedRenderElements.clear();
+		updateBounds();
 	}
 	}
 }
 }

+ 2 - 0
CamelotCore/Source/CmTextSprite.cpp

@@ -445,6 +445,8 @@ namespace CamelotEngine
 				clipToRect(renderElem.vertices, renderElem.uvs, renderElem.numQuads, mClipRect);
 				clipToRect(renderElem.vertices, renderElem.uvs, renderElem.numQuads, mClipRect);
 			}
 			}
 		}
 		}
+
+		updateBounds();
 	}
 	}
 
 
 	const FontData* TextSprite::getFontData() const
 	const FontData* TextSprite::getFontData() const

+ 6 - 2
CamelotD3D11RenderSystem/Source/CmD3D11BuiltinMaterialManager.cpp

@@ -30,6 +30,7 @@ namespace CamelotEngine
 		String vsCode = "										\
 		String vsCode = "										\
 			float halfViewportWidth;							\
 			float halfViewportWidth;							\
 			float halfViewportHeight;							\
 			float halfViewportHeight;							\
+			float4x4 worldTransform;							\
 																\
 																\
 			void vs_main(										\
 			void vs_main(										\
 			in float3 inPos : POSITION,							\
 			in float3 inPos : POSITION,							\
@@ -37,8 +38,10 @@ namespace CamelotEngine
 			out float4 oPosition : SV_Position,					\
 			out float4 oPosition : SV_Position,					\
 			out float2 oUv : TEXCOORD0)							\
 			out float2 oUv : TEXCOORD0)							\
 			{													\
 			{													\
-				float tfrmdX = (inPos.x / halfViewportWidth) - 1.0f;			\
-				float tfrmdY = (inPos.y / halfViewportHeight) + 1.0f;			\
+				float4 tfrmdPos = mul(worldTransform, float4(inPos.xy, 0, 1));	\
+																\
+				float tfrmdX = (tfrmdPos.x / halfViewportWidth) - 1.0f;			\
+				float tfrmdY = (tfrmdPos.y / halfViewportHeight) + 1.0f;		\
 																\
 																\
 				oPosition = float4(tfrmdX, tfrmdY, 0, 1);		\
 				oPosition = float4(tfrmdX, tfrmdY, 0, 1);		\
 				oUv = uv;										\
 				oUv = uv;										\
@@ -63,6 +66,7 @@ namespace CamelotEngine
 
 
 		mSpriteTextShader = Shader::create("TextShader");
 		mSpriteTextShader = Shader::create("TextShader");
 
 
+		mSpriteTextShader->addParameter("worldTransform", "worldTransform", GPDT_MATRIX_4X4);
 		mSpriteTextShader->addParameter("halfViewportWidth", "halfViewportWidth", GPDT_FLOAT1);
 		mSpriteTextShader->addParameter("halfViewportWidth", "halfViewportWidth", GPDT_FLOAT1);
 		mSpriteTextShader->addParameter("halfViewportHeight", "halfViewportHeight", GPDT_FLOAT1);
 		mSpriteTextShader->addParameter("halfViewportHeight", "halfViewportHeight", GPDT_FLOAT1);
 		mSpriteTextShader->addParameter("mainTexSamp", "mainTexSamp", GPOT_SAMPLER2D);
 		mSpriteTextShader->addParameter("mainTexSamp", "mainTexSamp", GPOT_SAMPLER2D);

+ 10 - 0
CamelotUtility/Include/CmVector2.h

@@ -547,6 +547,16 @@ namespace CamelotEngine
 			return Math::isNaN(x) || Math::isNaN(y);
 			return Math::isNaN(x) || Math::isNaN(y);
 		}
 		}
 
 
+		static Vector2 min(const Vector2& a, const Vector2& b)
+		{
+			return Vector2(std::min(a.x, b.x), std::min(a.y, b.y));
+		}
+
+		static Vector2 max(const Vector2& a, const Vector2& b)
+		{
+			return Vector2(std::max(a.x, b.x), std::max(a.y, b.y));
+		}
+
         // special points
         // special points
         static const Vector2 ZERO;
         static const Vector2 ZERO;
         static const Vector2 UNIT_X;
         static const Vector2 UNIT_X;

+ 10 - 0
CamelotUtility/Include/CmVector3.h

@@ -769,6 +769,16 @@ namespace CamelotEngine
 			return Math::isNaN(x) || Math::isNaN(y) || Math::isNaN(z);
 			return Math::isNaN(x) || Math::isNaN(y) || Math::isNaN(z);
 		}
 		}
 
 
+		static Vector3 min(const Vector3& a, const Vector3& b)
+		{
+			return Vector3(std::min(a.x, b.x), std::min(a.y, b.y), std::min(a.z, b.z));
+		}
+
+		static Vector3 max(const Vector3& a, const Vector3& b)
+		{
+			return Vector3(std::max(a.x, b.x), std::max(a.y, b.y), std::max(a.z, b.z));
+		}
+
 		// special points
 		// special points
         static const Vector3 ZERO;
         static const Vector3 ZERO;
         static const Vector3 UNIT_X;
         static const Vector3 UNIT_X;

+ 25 - 0
TODO.txt

@@ -33,6 +33,31 @@ Immediate sprite related stuff:
  - 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)
  - Transformable GUI elements and their bounds
  - Transformable GUI elements and their bounds
 
 
+ GUIWidget::update
+ - Gets bounds from all elements and transforms them by its own transform matrix
+  - Stores them in a map so I can easily scan through them later and find referenced element
+  - Keeps a total bound of all elements so I can easily reject elements that not even under the cursor
+ - Has mouseEvent, keyboardEvent handlers that it propagates to its children
+   - (possibly not keyboardEvent, see below why)
+   - mouse events only if cursor is over the element
+   - events originate from GUIManager
+ - When bounds are transformed it also transforms elements center
+   - Elements are sorted based on that center so when rendering we can render them back to front
+     - (back to front because they can be transparent)
+
+GUIElement
+ - Extend it with "hasFocus" flag
+  - flag gets set whenever user clicks on the element
+   - but how do I unset the flag? register element in focus with GUIManager?
+ - Only elements in focus receive keyboard events
+
+GUI windows!? - Figure out how to handle GUI window creation easily
+
+
+There is an issue that custom-UIs won't have their mesh shared. For example most game UIs will be advanced and will 
+likely use on GUIWidget per element. However currently I only perform batching within a single widget which 
+doesn't help in the mentioned case.
+
 -----------------------IMMEDIATE TODO---------------------------------------------------------------
 -----------------------IMMEDIATE TODO---------------------------------------------------------------
 
 
  Assets manifest
  Assets manifest