Browse Source

Some fixes to GUILayout

Marko Pintera 12 years ago
parent
commit
5ceaf3f0a2

+ 6 - 6
BansheeEngine/Include/BsGUIElement.h

@@ -83,11 +83,11 @@ namespace BansheeEngine
 		GUILayout* _getParentLayout() const { return mParentLayout; }
 		void _setParentLayout(GUILayout* layout) { mParentLayout = layout; }
 
-		void _setDepth(INT32 depth) { mDepth = depth; }
-		void _setOffset(const CM::Int2& offset) { mOffset = offset; }
-		void _setWidth(UINT32 width) { mWidth = width; }
-		void _setHeight(UINT32 height) { mHeight = height; }
-		void _setClipRect(const CM::Rect& clipRect) { mClipRect = clipRect; }
+		void _setDepth(INT32 depth);
+		void _setOffset(const CM::Int2& offset);
+		void _setWidth(UINT32 width);
+		void _setHeight(UINT32 height);
+		void _setClipRect(const CM::Rect& clipRect);
 
 		UINT32 _getWidth() const { return mWidth; }
 		UINT32 _getHeight() const { return mHeight; }
@@ -116,7 +116,7 @@ namespace BansheeEngine
 		void setLayoutOptions(const GUI_LAYOUT_OPTIONS& layoutOptions);
 		
 		void markAsClean() { mIsDirty = false; }
-		void markAsDirty() { mIsDirty = true; }
+		void markAsDirty();
 
 		GUIWidget& mParent;
 		GUILayout* mParentLayout;

+ 1 - 0
BansheeEngine/Include/BsGUILayout.h

@@ -88,6 +88,7 @@ namespace BansheeEngine
 		 */
 		void _update(UINT32 x, UINT32 y, UINT32 width, UINT32 height, UINT32 depth);
 
+		void _markAsDirty() { mIsDirty = true; }
 		bool _isDirty();
 
 	protected:

+ 2 - 0
BansheeEngine/Include/BsGUIWidget.h

@@ -40,6 +40,8 @@ namespace BansheeEngine
 		const CM::RenderWindow* getOwnerWindow() const { return mOwnerWindow; }
 		CM::Viewport* getTarget() const { return mTarget; }
 		const std::vector<GUIElement*>& getElements() const { return mElements; }
+
+		void _updateLayout();
 	protected:
 		friend class CM::SceneObject;
 		friend class GUIElement;

+ 12 - 2
BansheeEngine/Source/BsGUIArea.cpp

@@ -1,6 +1,7 @@
 #include "BsGUIArea.h"
 #include "BsGUIWidget.h"
 #include "BsGUILayoutX.h"
+#include "CmViewport.h"
 
 using namespace CamelotFramework;
 
@@ -11,8 +12,17 @@ namespace BansheeEngine
 	{
 		mLayout = CM_NEW(GUILayoutX, PoolAlloc) GUILayoutX();
 
-		mResizeWidthWithWindow = width == 0;
-		mResizeHeightWithWindow = height == 0;
+		if(width <= 0)
+		{
+			mWidth = mWidget.getTarget()->getWidth();
+			mResizeWidthWithWindow = true;
+		}
+
+		if(height <= 0)
+		{
+			mHeight = mWidget.getTarget()->getHeight();
+			mResizeHeightWithWindow = true;
+		}
 
 		mWidget.registerArea(this);
 	}

+ 41 - 0
BansheeEngine/Source/BsGUIElement.cpp

@@ -49,6 +49,47 @@ namespace BansheeEngine
 		return false;
 	}
 
+	void GUIElement::_setDepth(INT32 depth) 
+	{ 
+		mDepth = depth; 
+		markAsDirty();
+	}
+
+	void GUIElement::_setOffset(const CM::Int2& offset) 
+	{ 
+		mOffset = offset; 
+		markAsDirty();
+	}
+
+	void GUIElement::_setWidth(UINT32 width) 
+	{ 
+		mWidth = width; 
+		markAsDirty();
+	}
+
+	void GUIElement::_setHeight(UINT32 height) 
+	{ 
+		mHeight = height; 
+		markAsDirty();
+	}
+
+	void GUIElement::_setClipRect(const CM::Rect& clipRect) 
+	{ 
+		mClipRect = clipRect; 
+		markAsDirty();
+	}
+
+	void GUIElement::markAsDirty() 
+	{ 
+		if(!mIsDirty)
+		{
+			if(mParentLayout != nullptr)
+				mParentLayout->_markAsDirty();
+
+			mIsDirty = true; 
+		}
+	}
+
 	void GUIElement::_destroyInternal(GUIElement* element)
 	{
 		CM_DELETE(element, GUIElement, PoolAlloc);

+ 2 - 2
BansheeEngine/Source/BsGUILayoutX.cpp

@@ -77,13 +77,13 @@ namespace BansheeEngine
 					UINT32 availableWidth = std::min((UINT32)Math::CeilToInt(averageWidth), leftoverWidth);
 
 					// Clamp average to min max
-					if(availableWidth < layoutOptions.minWidth)
+					if(layoutOptions.minWidth > 0 && availableWidth < layoutOptions.minWidth)
 					{
 						elementWidth = layoutOptions.minWidth;
 						leftoverWidth = (UINT32)std::max(0, (INT32)leftoverWidth - (INT32)elementWidth);
 						numFreeElems--;
 					}
-					else if(availableWidth > layoutOptions.maxWidth)
+					else if(layoutOptions.maxWidth > 0 && availableWidth > layoutOptions.maxWidth)
 					{
 						elementWidth = layoutOptions.maxWidth;
 						leftoverWidth = (UINT32)std::max(0, (INT32)leftoverWidth - (INT32)elementWidth);

+ 16 - 1
BansheeEngine/Source/BsGUIManager.cpp

@@ -97,6 +97,12 @@ namespace BansheeEngine
 
 	void GUIManager::update()
 	{
+		// Update layouts
+		for(auto& widget : mWidgets)
+		{
+			widget->_updateLayout();
+		}
+
 		updateMeshes();
 		updateInput();
 	}
@@ -360,7 +366,16 @@ namespace BansheeEngine
 				for(auto& matElement : group->elements)
 				{
 					matElement.element->fillBuffer(vertices, uvs, indices, quadOffset, group->numQuads, vertexStride, indexStride, matElement.renderElement);
-					quadOffset += matElement.element->getNumQuads(matElement.renderElement);
+
+					UINT32 numQuads = matElement.element->getNumQuads(matElement.renderElement);
+					UINT32 indexStart = quadOffset * 6;
+					UINT32 indexEnd = indexStart + numQuads * 6;
+					UINT32 vertOffset = quadOffset * 4;
+
+					for(UINT32 i = indexStart; i < indexEnd; i++)
+						indices[i] += vertOffset;
+
+					quadOffset += numQuads;
 				}
 
 				if(groupIdx >= (UINT32)renderData.cachedMeshes.size())

+ 8 - 0
BansheeEngine/Source/BsGUIWidget.cpp

@@ -60,6 +60,14 @@ namespace BansheeEngine
 		mOwnerWindow->onWindowMovedOrResized.connect(boost::bind(&GUIWidget::ownerWindowResized, this, _1));
 	}
 
+	void GUIWidget::_updateLayout()
+	{
+		for(auto& area : mAreas)
+		{
+			area->_update();
+		}
+	}
+
 	void GUIWidget::registerElement(GUIElement* elem)
 	{
 		assert(elem != nullptr);

+ 2 - 2
BansheeEngine/Source/BsSprite.cpp

@@ -47,8 +47,8 @@ namespace BansheeEngine
 		assert((startVert + mNumVertices) <= maxVertIdx);
 		assert((startIndex + mNumIndices) <= maxIndexIdx);
 
-		UINT8* vertDst = &vertices[startVert];
-		UINT8* uvDst = &uv[startVert];
+		UINT8* vertDst = vertices + startVert * vertexStride;
+		UINT8* uvDst = uv + startVert * vertexStride;
 		for(UINT32 i = 0; i < mNumVertices; i++)
 		{
 			memcpy(vertDst, &renderElem.vertices[i], sizeof(Vector2));

+ 1 - 0
CamelotClient/CmEditorWindow.cpp

@@ -59,6 +59,7 @@ namespace BansheeEditor
 		GUILayout& otherLayout = mainArea->getLayout();
 
 		otherLayout.addElement(GUIWindowFrame::create(*mGUI));
+		otherLayout.addElement(GUIWindowFrame::create(*mGUI));
 	}
 
 	EditorWindow::~EditorWindow()

+ 2 - 0
Notes.txt

@@ -21,6 +21,8 @@ Reminders:
   - Async callbacks. I'd like to be able to assign a callback to an async method, that will execute on the calling thread once the async operation is complete.
      - For example when setting PixelData for a cursor I need to get PixelData from a texture, which is an async operation, in which case I need to block the calling thread
 	   until I get the result. But I'd rather apply the result once render thread is finished.
+  - GUI currently doesn't batch elements belonging to different GUIWidgets because each of them has its own transform. Implement some form of instancing for DX11 and GL
+    so this isn't required. GUIManager already has the ability to properly group meshes, all that is needed is a shader.
 
 Potential optimizations:
  - bulkPixelConversion is EXTREMELY poorly unoptimized. Each pixel it calls a separate method that does redudant operations every pixel.

+ 0 - 2
TODO.txt

@@ -22,8 +22,6 @@ I call waitUntilLoaded too many times. Sometimes 5-6 times in a single function.
 GUIWidget::updateMeshes leaks. If I leave the game running I can see memory continously going up
 
 IMMEDIATE:
- - I'm not setting worldTransform of GUI material in GUIManager::render
-   - I need to separate meshes per-widget and later implement some kind of smart batching using multiple transforms per mesh
  - On content change I need to notify parent layout
  - Add clip rectangles on GUILayoutX
  - Calculate flexible spaces in GUILyoutX