Marko Pintera 12 лет назад
Родитель
Сommit
1f8f83eb1b
2 измененных файлов с 38 добавлено и 3 удалено
  1. 35 3
      BansheeEngine/Source/BsGUILayoutX.cpp
  2. 3 0
      TODO.txt

+ 35 - 3
BansheeEngine/Source/BsGUILayoutX.cpp

@@ -13,6 +13,7 @@ namespace BansheeEngine
 		UINT32 totalOptimalSize = 0;
 		UINT32 totalOptimalSize = 0;
 		UINT32 numNonClampedElements = 0;
 		UINT32 numNonClampedElements = 0;
 		UINT32 numFlexibleSpaces = 0;
 		UINT32 numFlexibleSpaces = 0;
+		UINT32 numLayouts = 0;
 
 
 		bool* processedElements = CM_NEW_ARRAY(bool, (UINT32)mChildren.size(), ScratchAlloc);
 		bool* processedElements = CM_NEW_ARRAY(bool, (UINT32)mChildren.size(), ScratchAlloc);
 		memset(processedElements, 0, mChildren.size() * sizeof(bool));
 		memset(processedElements, 0, mChildren.size() * sizeof(bool));
@@ -20,6 +21,9 @@ namespace BansheeEngine
 		UINT32* elementSizes = CM_NEW_ARRAY(UINT32, (UINT32)mChildren.size(), ScratchAlloc);
 		UINT32* elementSizes = CM_NEW_ARRAY(UINT32, (UINT32)mChildren.size(), ScratchAlloc);
 		memset(elementSizes, 0, mChildren.size() * sizeof(UINT32));
 		memset(elementSizes, 0, mChildren.size() * sizeof(UINT32));
 
 
+		float* elementScaleWeights = CM_NEW_ARRAY(float, (UINT32)mChildren.size(), ScratchAlloc);
+		memset(elementScaleWeights, 0, mChildren.size() * sizeof(float));
+
 		// Set fixed-size elements and determine optimal size
 		// Set fixed-size elements and determine optimal size
 		UINT32 childIdx = 0;
 		UINT32 childIdx = 0;
 		for(auto& child : mChildren)
 		for(auto& child : mChildren)
@@ -57,7 +61,7 @@ namespace BansheeEngine
 			}
 			}
 			else if(child.isLayout())
 			else if(child.isLayout())
 			{
 			{
-				// Layout use any size that's available (quite possibly none), but it might be better to give them a certain minimum size.
+				numLayouts++;
 				numNonClampedElements++;
 				numNonClampedElements++;
 			}
 			}
 			else if(child.isFlexibleSpace())
 			else if(child.isFlexibleSpace())
@@ -69,6 +73,30 @@ namespace BansheeEngine
 			childIdx++;
 			childIdx++;
 		}
 		}
 
 
+		// Determine layout size. We could just calculate optimal size of all elements in the layout
+		// but I feel that's an overkill. Instead I just use the average size.
+		childIdx = 0;
+		UINT32 layoutSize = (UINT32)Math::CeilToInt(totalOptimalSize / (float)numLayouts);
+		for(auto& child : mChildren)
+		{
+			if(child.isLayout())
+			{
+				elementSizes[childIdx] += layoutSize;
+				totalOptimalSize += layoutSize;
+			}
+			childIdx++;
+		}
+
+		// Determine weight scale for every element
+		childIdx = 0;
+		float invOptimalSize = 1.0f / totalOptimalSize;
+		for(auto& child : mChildren)
+		{
+			elementScaleWeights[childIdx] = invOptimalSize * elementSizes[childIdx];
+
+			childIdx++;
+		}
+
 		// Our optimal size is larger than maximum allowed, so we need to reduce size of some elements
 		// Our optimal size is larger than maximum allowed, so we need to reduce size of some elements
 		if(totalOptimalSize > width)
 		if(totalOptimalSize > width)
 		{
 		{
@@ -79,7 +107,7 @@ namespace BansheeEngine
 			// equal average sizes 
 			// equal average sizes 
 			while(remainingSize > 0 && numNonClampedElements > 0)
 			while(remainingSize > 0 && numNonClampedElements > 0)
 			{
 			{
-				float avgSize = remainingSize / (float)numNonClampedElements;
+				UINT32 totalRemainingSize = remainingSize;
 
 
 				childIdx = 0;
 				childIdx = 0;
 				for(auto& child : mChildren)
 				for(auto& child : mChildren)
@@ -87,6 +115,8 @@ namespace BansheeEngine
 					if(processedElements[childIdx])
 					if(processedElements[childIdx])
 						continue;
 						continue;
 
 
+					float avgSize = totalRemainingSize * elementScaleWeights[childIdx];
+					
 					UINT32 extraWidth = std::min((UINT32)Math::CeilToInt(avgSize), remainingSize);
 					UINT32 extraWidth = std::min((UINT32)Math::CeilToInt(avgSize), remainingSize);
 					UINT32 elementWidth = (UINT32)std::max(0, (INT32)elementSizes[childIdx] - (INT32)extraWidth);
 					UINT32 elementWidth = (UINT32)std::max(0, (INT32)elementSizes[childIdx] - (INT32)extraWidth);
 
 
@@ -172,7 +202,7 @@ namespace BansheeEngine
 				// equal average sizes 
 				// equal average sizes 
 				while(remainingSize > 0 && numNonClampedElements > 0)
 				while(remainingSize > 0 && numNonClampedElements > 0)
 				{
 				{
-					float avgSize = remainingSize / (float)numNonClampedElements;
+					UINT32 totalRemainingSize = remainingSize;
 
 
 					childIdx = 0;
 					childIdx = 0;
 					for(auto& child : mChildren)
 					for(auto& child : mChildren)
@@ -180,6 +210,7 @@ namespace BansheeEngine
 						if(processedElements[childIdx])
 						if(processedElements[childIdx])
 							continue;
 							continue;
 
 
+						float avgSize = totalRemainingSize * elementScaleWeights[childIdx];
 						UINT32 extraWidth = std::min((UINT32)Math::CeilToInt(avgSize), remainingSize);
 						UINT32 extraWidth = std::min((UINT32)Math::CeilToInt(avgSize), remainingSize);
 						UINT32 elementWidth = elementSizes[childIdx] + extraWidth;
 						UINT32 elementWidth = elementSizes[childIdx] + extraWidth;
 
 
@@ -267,6 +298,7 @@ namespace BansheeEngine
 
 
 		CM_DELETE_ARRAY(processedElements, bool, (UINT32)mChildren.size(), ScratchAlloc);
 		CM_DELETE_ARRAY(processedElements, bool, (UINT32)mChildren.size(), ScratchAlloc);
 		CM_DELETE_ARRAY(elementSizes, UINT32, (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
 		//// Calculate flexible space sizes
 		//std::vector<UINT32> flexibleSpaceSizes;
 		//std::vector<UINT32> flexibleSpaceSizes;

+ 3 - 0
TODO.txt

@@ -23,6 +23,9 @@ GUIWidget::updateMeshes leaks. If I leave the game running I can see memory cont
 
 
 IMMEDIATE:
 IMMEDIATE:
  - Implement GUILayoutY
  - 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 nested elements
 Test with flexible space, left center and right
 Test with flexible space, left center and right