Sfoglia il codice sorgente

Make sure the widget updates if its transform changes

Marko Pintera 12 anni fa
parent
commit
f7869ea14f

+ 7 - 1
BansheeEngine/Include/BsGUIWidget.h

@@ -3,6 +3,8 @@
 #include "BsPrerequisites.h"
 #include "CmComponent.h"
 #include "CmRect.h"
+#include "CmVector3.h"
+#include "CmQuaternion.h"
 
 namespace BansheeEngine
 {
@@ -59,7 +61,7 @@ namespace BansheeEngine
 
 		void ownerWindowResized(CM::RenderWindow* window);
 
-		virtual void update() {}
+		virtual void update();
 
 		const CM::RenderWindow* mOwnerWindow;
 		CM::Viewport* mTarget;
@@ -67,6 +69,10 @@ namespace BansheeEngine
 		std::vector<GUIArea*> mAreas;
 		UINT16 mDepth;
 
+		CM::Vector3 mLastFramePosition;
+		CM::Quaternion mLastFrameRotation;
+		CM::Vector3 mLastFrameScale;
+
 		mutable bool mWidgetIsDirty;
 		mutable CM::Rect mBounds;
 		mutable std::vector<CM::HMesh> mCachedMeshes;

+ 0 - 216
BansheeEngine/Source/BsGUILayoutX.cpp

@@ -299,221 +299,5 @@ namespace BansheeEngine
 		CM_DELETE_ARRAY(processedElements, bool, (UINT32)mChildren.size(), ScratchAlloc);
 		CM_DELETE_ARRAY(elementSizes, UINT32, (UINT32)mChildren.size(), ScratchAlloc);
 		CM_DELETE_ARRAY(elementScaleWeights, float, (UINT32)mChildren.size(), ScratchAlloc);
-
-		//// Calculate flexible space sizes
-		//std::vector<UINT32> flexibleSpaceSizes;
-		//UINT32 minimalTotalSize = 0;
-		//for(auto& child : mChildren)
-		//{
-		//	if(child.isFlexibleSpace())
-		//	{
-		//		flexibleSpaceSizes.push_back(0);
-		//	}
-		//	else if(child.isFixedSpace())
-		//	{
-		//		minimalTotalSize += child.space->getSize();
-		//	}
-		//	else if(child.isElement())
-		//	{
-		//		const GUILayoutOptions& layoutOptions = child.element->_getLayoutOptions();
-
-		//		if(layoutOptions.fixedWidth)
-		//			minimalTotalSize += layoutOptions.width;
-		//		else
-		//		{
-		//			UINT32 optimalWidth = child.element->_getOptimalWidth();
-
-		//			if(layoutOptions.minHeight > 0)
-		//				optimalWidth = std::max(layoutOptions.minWidth, optimalWidth);
-
-		//			if(layoutOptions.maxHeight > 0)
-		//				optimalWidth = std::min(layoutOptions.maxWidth, optimalWidth);
-
-		//			minimalTotalSize += optimalWidth;
-		//		}
-		//	}
-		//}
-
-		//UINT32 remainingFlexSpaceSize = (UINT32)std::max(0, (INT32)width - (INT32)minimalTotalSize);
-		//float avgFlexibleSpaceSize = remainingFlexSpaceSize / (float)flexibleSpaceSizes.size();
-		//
-		//for(size_t i = 0; i < flexibleSpaceSizes.size(); i++)
-		//{
-		//	UINT32 spaceSize = (UINT32)Math::CeilToInt(avgFlexibleSpaceSize);
-		//	spaceSize = std::min(remainingFlexSpaceSize, spaceSize);
-
-		//	remainingFlexSpaceSize -= spaceSize;
-		//	flexibleSpaceSizes[i] = spaceSize;
-		//}
-
-		//// Get a basic estimate of the average width
-		//UINT32 totalWidth = 0;
-		//UINT32 numFreeElems = 0;
-		//float avgWidth = 0.0f;
-		//UINT32 flexibleSpaceIdx = 0;
-		//for(auto& child : mChildren)
-		//{
-		//	if(child.isElement())
-		//	{
-		//		const GUILayoutOptions& layoutOptions = child.element->_getLayoutOptions();
-
-		//		if(layoutOptions.fixedWidth)
-		//		{
-		//			totalWidth += layoutOptions.width;
-		//		}
-		//		else
-		//		{
-		//			numFreeElems++;
-		//		}
-		//	}
-		//	else if(child.isFixedSpace())
-		//	{
-		//		totalWidth += child.space->getSize();
-		//	}
-		//	else if(child.isFlexibleSpace())
-		//	{
-		//		totalWidth += flexibleSpaceSizes[flexibleSpaceIdx];
-		//		flexibleSpaceIdx++;
-		//	}
-		//	else
-		//	{
-		//		numFreeElems++;
-		//	}
-		//}
-
-		//UINT32 leftoverWidth = (UINT32)std::max(0, (INT32)width - (INT32)totalWidth);
-		//float averageWidth = leftoverWidth / (float) numFreeElems;
-
-		//// Only assign elements with fixed, or clamped width
-		//bool* processedElements = CM_NEW_ARRAY(bool, (UINT32)mChildren.size(), ScratchAlloc);
-		//memset(processedElements, 0, mChildren.size() * sizeof(bool));
-
-		//UINT32 childIdx = 0;
-		//for(auto& child : mChildren)
-		//{
-		//	if(child.isElement())
-		//	{
-		//		const GUILayoutOptions& layoutOptions = child.element->_getLayoutOptions();
-
-		//		UINT32 elementWidth = 0;
-
-		//		if(layoutOptions.fixedWidth)
-		//		{
-		//			elementWidth = layoutOptions.width;
-		//			processedElements[childIdx] = true;
-		//		}
-		//		else
-		//		{
-		//			UINT32 availableWidth = std::min((UINT32)Math::CeilToInt(averageWidth), leftoverWidth);
-
-		//			// Clamp average to min max
-		//			if(layoutOptions.minWidth > 0 && availableWidth < layoutOptions.minWidth)
-		//			{
-		//				elementWidth = layoutOptions.minWidth;
-		//				leftoverWidth = (UINT32)std::max(0, (INT32)leftoverWidth - (INT32)elementWidth);
-		//				
-		//				processedElements[childIdx] = true;
-		//				numFreeElems--;
-		//			}
-		//			else if(layoutOptions.maxWidth > 0 && availableWidth > layoutOptions.maxWidth)
-		//			{
-		//				elementWidth = layoutOptions.maxWidth;
-		//				leftoverWidth = (UINT32)std::max(0, (INT32)leftoverWidth - (INT32)elementWidth);
-		//				
-		//				processedElements[childIdx] = true;
-		//				numFreeElems--;
-		//			}
-		//		}
-
-		//		child.element->_setWidth(elementWidth);
-		//	}
-
-		//	childIdx++;
-		//}
-
-		//averageWidth = leftoverWidth / (float) numFreeElems;
-
-		//// Assign free scaling elements now that we have a good estimate on average width
-		//// Note: Our average value is JUST an estimate. It's hard to predict the actual value because
-		//// of min/max constraints and would probably require a few iterations to get a somewhat accurate value,
-		//// but I don't think that is worth the trouble. For that reason min/max clamping that might happen in 
-		//// the next block might cause elements to either be a bit too small or too large for the layout.
-		//// It is the assumption that such clamping won't happen often.
-		//// 
-		//// Also calculate offset and element height.
-		//UINT32 xOffset = 0;
-		//flexibleSpaceIdx = 0;
-		//childIdx = 0;
-		//for(auto& child : mChildren)
-		//{
-		//	if(child.isElement())
-		//	{
-		//		const GUILayoutOptions& layoutOptions = child.element->_getLayoutOptions();
-
-		//		if(!processedElements[childIdx])
-		//		{
-		//			UINT32 elementWidth = std::min((UINT32)Math::CeilToInt(averageWidth), leftoverWidth);
-
-		//			if(layoutOptions.minWidth > 0 && elementWidth < layoutOptions.minWidth)
-		//				elementWidth = layoutOptions.minWidth;
-		//			else if(layoutOptions.maxWidth > 0 && elementWidth > layoutOptions.maxWidth)
-		//				elementWidth = layoutOptions.maxWidth;
-
-		//			leftoverWidth = (UINT32)std::max(0, (INT32)leftoverWidth - (INT32)elementWidth);
-
-		//			child.element->_setWidth(elementWidth);
-		//		}
-
-		//		if(layoutOptions.fixedHeight)
-		//			child.element->_setHeight(layoutOptions.height);
-		//		else
-		//		{
-		//			UINT32 optimalHeight = child.element->_getOptimalHeight();
-
-		//			if(layoutOptions.minHeight > 0)
-		//				optimalHeight = std::max(layoutOptions.minHeight, optimalHeight);
-
-		//			if(layoutOptions.maxHeight > 0)
-		//				optimalHeight = std::min(layoutOptions.maxHeight, optimalHeight);
-
-		//			child.element->_setHeight(optimalHeight);
-		//		}
-
-		//		UINT32 yOffset = (UINT32)Math::CeilToInt((height - child.element->_getHeight()) * 0.5f);
-
-		//		Int2 offset(x + xOffset, y + yOffset);
-		//		child.element->_setOffset(offset);
-		//		child.element->_setDepth(depth);
-
-		//		UINT32 clippedWidth = (UINT32)std::min((INT32)child.element->_getWidth(), (INT32)width - offset.x);
-		//		UINT32 clippedHeight = (UINT32)std::min((INT32)child.element->_getHeight(), (INT32)height - offset.y);
-
-		//		child.element->_setClipRect(Rect(0, 0, clippedWidth, clippedHeight));
-
-		//		xOffset += child.element->_getWidth();
-		//	}
-		//	else if(child.isLayout())
-		//	{
-		//		UINT32 elementWidth = std::min((UINT32)Math::CeilToInt(averageWidth), leftoverWidth);
-		//		leftoverWidth = (UINT32)std::max(0, (INT32)leftoverWidth - (INT32)elementWidth);
-
-		//		child.layout->_update(x + xOffset, y, elementWidth, height, depth);
-
-		//		xOffset += elementWidth;
-		//	}
-		//	else if(child.isFixedSpace())
-		//	{
-		//		xOffset += child.space->getSize();
-		//	}
-		//	else if(child.isFlexibleSpace())
-		//	{
-		//		xOffset += flexibleSpaceSizes[flexibleSpaceIdx];
-		//		flexibleSpaceIdx++;
-		//	}
-
-		//	childIdx++;
-		//}
-
-		//CM_DELETE_ARRAY(processedElements, bool, (UINT32)mChildren.size(), ScratchAlloc);
 	}
 }

+ 46 - 1
BansheeEngine/Source/BsGUIWidget.cpp

@@ -24,7 +24,11 @@ namespace BansheeEngine
 
 	GUIWidget::GUIWidget(const HSceneObject& parent)
 		:Component(parent), mSkin(nullptr), mOwnerWindow(nullptr), mWidgetIsDirty(false), mTarget(nullptr), mDepth(0)
-	{	}
+	{
+		mLastFramePosition = SO()->getWorldPosition();
+		mLastFrameRotation = SO()->getWorldRotation();
+		mLastFrameScale = SO()->getWorldScale();
+	}
 
 	GUIWidget::~GUIWidget()
 	{
@@ -60,6 +64,47 @@ namespace BansheeEngine
 		mOwnerWindow->onWindowMovedOrResized.connect(boost::bind(&GUIWidget::ownerWindowResized, this, _1));
 	}
 
+	void GUIWidget::update()
+	{
+		// If the widgets parent scene object moved, we need to mark it as dirty
+		// as the GUIManager batching relies on object positions, so it needs to be updated.
+		const float diffEpsilon = 0.0001f;
+
+		Vector3 position = SO()->getWorldPosition();
+		Quaternion rotation = SO()->getWorldRotation();
+		Vector3 scale = SO()->getWorldScale();
+
+		if(!mWidgetIsDirty)
+		{
+			Vector3 posDiff = mLastFramePosition - position;
+			if(Math::Abs(posDiff.x) > diffEpsilon || Math::Abs(posDiff.y) > diffEpsilon || Math::Abs(posDiff.z) > diffEpsilon)
+			{
+				mWidgetIsDirty = true;
+			}
+			else
+			{
+				Quaternion rotDiff = mLastFrameRotation - rotation;
+				if(Math::Abs(rotDiff.x) > diffEpsilon || Math::Abs(rotDiff.y) > diffEpsilon || 
+					Math::Abs(rotDiff.z) > diffEpsilon || Math::Abs(rotDiff.w) > diffEpsilon)
+				{
+					mWidgetIsDirty = true;
+				}
+				else
+				{
+					Vector3 scaleDiff = mLastFrameScale - scale;
+					if(Math::Abs(scaleDiff.x) > diffEpsilon || Math::Abs(scaleDiff.y) > diffEpsilon || Math::Abs(scaleDiff.z) > diffEpsilon)
+					{
+						mWidgetIsDirty = true;
+					}
+				}
+			}
+		}
+
+		mLastFramePosition = position;
+		mLastFrameRotation = rotation;
+		mLastFrameScale = scale;
+	}
+
 	void GUIWidget::_updateLayout()
 	{
 		for(auto& area : mAreas)

+ 3 - 2
CamelotClient/CmEditorWindow.cpp

@@ -58,11 +58,12 @@ namespace BansheeEditor
 		GUIArea* mainArea = GUIArea::create(*mGUI, 0, 0, 0, 0, 1);
 		GUILayout& otherLayout = mainArea->getLayout();
 
+		GUIFlexibleSpace& space4 = otherLayout.addFlexibleSpace();
 		otherLayout.addElement(mDbgLabel);
 
 		//GUIFixedSpace& space = otherLayout.addSpace(10); // Due to bug in MSVC compiler I need to store return value
-		//GUIFlexibleSpace& space3 = otherLayout.addFlexibleSpace();
-		otherLayout.addElement(GUIWindowFrame::create(*mGUI, GUILayoutOptions::expandableX(20, 100)));
+		GUIFlexibleSpace& space3 = otherLayout.addFlexibleSpace();
+		otherLayout.addElement(GUIWindowFrame::create(*mGUI, GUILayoutOptions::expandableX(20, 20)));
 		//GUIFixedSpace& space2 = otherLayout.addSpace(10);
 		otherLayout.addElement(GUIWindowFrame::create(*mGUI));
 	}

+ 0 - 3
TODO.txt

@@ -23,9 +23,6 @@ GUIWidget::updateMeshes leaks. If I leave the game running I can see memory cont
 
 IMMEDIATE:
  - Implement GUILayoutY
- - Layout algorithm currently reduces/expands elements based on avg size. However it would be better if each element was resized based on a weighted
-   value which is determined by its optimal size compared to the size of all elements combined. Otherwise very small elements get reduced to 0 size while larger
-   ones still take up plenty of screen.
 
 Test nested elements
 Test with flexible space, left center and right