Bladeren bron

Fixing various GUI issues to get it back to working state after the recent refactors

Marko Pintera 10 jaren geleden
bovenliggende
commit
baf74e865e

+ 2 - 2
BansheeEditor/Source/BsGUIColor.cpp

@@ -134,7 +134,7 @@ namespace BansheeEngine
 		if(renderElementIdx < alphaSpriteIdx)
 		{
 			mColorSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, 
-				vertexStride, indexStride, renderElementIdx, offset, mLayoutData.clipRect);
+				vertexStride, indexStride, renderElementIdx, offset, mLayoutData.getLocalClipRect());
 
 			return;
 		}
@@ -144,7 +144,7 @@ namespace BansheeEngine
 			UINT32 xOffset = (UINT32)(mLayoutData.area.width * ALPHA_SPLIT_POSITION);
 			alphaOffset.x += xOffset;
 
-			Rect2I alphaClipRect = mLayoutData.clipRect;
+			Rect2I alphaClipRect = mLayoutData.getLocalClipRect();
 			alphaClipRect.x -= xOffset;
 
 			mAlphaSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, 

+ 1 - 0
BansheeEngine.sln

@@ -6,6 +6,7 @@ MinimumVisualStudioVersion = 10.0.40219.1
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "_Notes", "_Notes", "{1D081E5A-615A-4C06-B2DF-0D8D9390DE02}"
 	ProjectSection(SolutionItems) = preProject
 		TODO.txt = TODO.txt
+		TODOExperimentation.txt = TODOExperimentation.txt
 	EndProjectSection
 EndProject
 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BansheeEngine", "BansheeEngine\BansheeEngine.vcxproj", "{07B0C186-5173-46F2-BE26-7E4148BD0CCA}"

+ 8 - 0
BansheeEngine/Include/BsGUIElement.h

@@ -186,6 +186,14 @@ namespace BansheeEngine
 		 */
 		void _setElementDepth(UINT8 depth);
 
+		/**
+		 * @brief	Retrieve element part of element depth. Less significant than both
+		 *			widget and area depth.
+		 *
+		 * @note	Internal method.
+		 */
+		UINT8 _getElementDepth() const;
+
 		/**
 		 * @copydoc	GUIElementBase::_setLayoutData
 		 */

+ 9 - 2
BansheeEngine/Include/BsGUIElementBase.h

@@ -81,7 +81,7 @@ namespace BansheeEngine
 		void disableRecursively();
 
 		/**
-		 * @brief	Returns non-clipped bounds of the GUI element. Relative to the parent GUI panel.
+		 * @brief	Returns non-clipped bounds of the GUI element. Relative to a parent GUI panel.
 		 *
 		 * @param	relativeTo	Parent panel of the provided element relative to which to return the
 		 *						bounds. If null the bounds relative to the first parent panel are returned.
@@ -91,6 +91,13 @@ namespace BansheeEngine
 		 */
 		Rect2I getBounds(GUIPanel* relativeTo = nullptr);
 
+		/**
+		 * @brief	Returns non-clipped bounds of the GUI element. Relative to a parent GUI widget.
+		 *
+		 * @note	This call can be potentially expensive if the GUI state is dirty.
+		 */
+		Rect2I getGlobalBounds();
+
 		/**
 		 * @brief	Returns non-clipped visible bounds of the GUI element (bounds exclude the margins). Relative to the parent GUI panel.
 		 *
@@ -336,8 +343,8 @@ namespace BansheeEngine
 		GUIWidget* mParentWidget;
 		GUIPanel* mAnchorParent;
 		GUIElementBase* mUpdateParent;
-
 		GUIElementBase* mParentElement;
+
 		Vector<GUIElementBase*> mChildren;	
 		bool mIsDisabled;
 		bool mIsDirty;

+ 4 - 5
BansheeEngine/Include/BsGUILayoutData.h

@@ -21,9 +21,9 @@ namespace BansheeEngine
 		/**
 		 * @brief	Set widget part of element depth. (Most significant part)
 		 */
-		void setWidgetDepth(UINT8 depth)
+		void setWidgetDepth(UINT8 widgetDepth)
 		{
-			UINT32 shiftedDepth = depth << 24;
+			UINT32 shiftedDepth = widgetDepth << 24;
 
 			depth = shiftedDepth | (depth & 0x00FFFFFF);
 		}
@@ -32,14 +32,13 @@ namespace BansheeEngine
 		 * @brief	Set panel part of element depth. Less significant than widget
 		 *			depth but more than custom element depth.
 		 */
-		void setPanelDepth(INT16 depth)
+		void setPanelDepth(INT16 panelDepth)
 		{
-			UINT32 signedDepth = ((INT32)depth + 32768) << 8;
+			UINT32 signedDepth = ((INT32)panelDepth + 32768) << 8;
 
 			depth = signedDepth | (depth & 0xFF0000FF);;
 		}
 
-
 		/**
 		 * @brief	Retrieve widget part of element depth. (Most significant part)
 		 */

+ 10 - 0
BansheeEngine/Source/BsGUIElement.cpp

@@ -61,9 +61,19 @@ namespace BansheeEngine
 		_markMeshAsDirty();
 	}
 
+	UINT8 GUIElement::_getElementDepth() const
+	{
+		return mLayoutData.depth & 0xFF;
+	}
+
 	void GUIElement::_setLayoutData(const GUILayoutData& data)
 	{
+		// Preserve element depth as that is not controlled by layout but is stored
+		// there only for convenience
+		UINT8 elemDepth = _getElementDepth();
 		GUIElementBase::_setLayoutData(data);
+		_setElementDepth(elemDepth);
+
 		updateClippedBounds();
 	}
 

+ 24 - 18
BansheeEngine/Source/BsGUIElementBase.cpp

@@ -153,25 +153,10 @@ namespace BansheeEngine
 
 		Rect2I anchorBounds;
 		if (relativeTo != nullptr)
-			anchorBounds = relativeTo->getBounds();
+			anchorBounds = relativeTo->getGlobalBounds();
 
-		if (mUpdateParent != nullptr)
-		{
-			if (mUpdateParent->_isDirty() && mParentWidget != nullptr)
-			{
-				GUIElementBase* updateParent = mUpdateParent;
-				if (updateParent->_getType() == GUIElementBase::Type::Panel)
-				{
-					GUIElementBase* optimizedUpdateParent = this;
-					while (optimizedUpdateParent->_getParent() != updateParent)
-						optimizedUpdateParent = optimizedUpdateParent->_getParent();
-
-					updateParent = optimizedUpdateParent;
-				}
-
-				mParentWidget->_updateLayout(updateParent);
-			}
-		}
+		if (mUpdateParent != nullptr && mUpdateParent->_isDirty() && mParentWidget != nullptr)
+			mParentWidget->_updateLayout(mUpdateParent);
 
 		Rect2I bounds = mLayoutData.area;
 		bounds.x -= anchorBounds.x;
@@ -180,6 +165,14 @@ namespace BansheeEngine
 		return bounds;
 	}
 
+	Rect2I GUIElementBase::getGlobalBounds()
+	{
+		if (mUpdateParent != nullptr && mUpdateParent->_isDirty() && mParentWidget != nullptr)
+			mParentWidget->_updateLayout(mUpdateParent);
+
+		return mLayoutData.area;
+	}
+
 	Rect2I GUIElementBase::getVisibleBounds()
 	{
 		return getBounds();
@@ -382,7 +375,20 @@ namespace BansheeEngine
 			bool boundsDependOnChildren = !parentDimensions.fixedHeight() || !parentDimensions.fixedWidth();
 
 			if (!boundsDependOnChildren)
+			{
+				// If parent is a panel then we can do an optimization and only update
+				// one child instead of all of them, so change parent to that child.
+				if (currentElement->_getType() == GUIElementBase::Type::Panel)
+				{
+					GUIElementBase* optimizedUpdateParent = this;
+					while (optimizedUpdateParent != currentElement)
+						optimizedUpdateParent = optimizedUpdateParent->_getParent();
+
+					currentElement = optimizedUpdateParent;
+				}
+
 				return currentElement;
+			}
 
 			currentElement = currentElement->mParentElement;
 		}

+ 1 - 1
BansheeEngine/Source/BsGUILabel.cpp

@@ -72,7 +72,7 @@ namespace BansheeEngine
 		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
 
 		mTextSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, 
-			indexStride, renderElementIdx, offset, mLayoutData.clipRect);
+			indexStride, renderElementIdx, offset, mLayoutData.getLocalClipRect());
 	}
 
 	void GUILabel::setContent(const GUIContent& content)

+ 1 - 2
BansheeEngine/Source/BsGUILayoutX.cpp

@@ -383,11 +383,10 @@ namespace BansheeEngine
 		for(auto& child : mChildren)
 		{
 			childData.area = elementAreas[childIdx];
-			child->_setLayoutData(childData);
-
 			childData.clipRect = childData.area;
 			childData.clipRect.clip(data.clipRect);
 
+			child->_setLayoutData(childData);
 			child->_updateLayoutInternal(childData);
 
 			childIdx++;

+ 1 - 2
BansheeEngine/Source/BsGUILayoutY.cpp

@@ -381,11 +381,10 @@ namespace BansheeEngine
 		for(auto& child : mChildren)
 		{
 			childData.area = elementAreas[childIdx];
-			child->_setLayoutData(childData);
-
 			childData.clipRect = childData.area;
 			childData.clipRect.clip(data.clipRect);
 
+			child->_setLayoutData(childData);
 			child->_updateLayoutInternal(childData);
 
 			childIdx++;

+ 1 - 1
BansheeEngine/Source/BsGUIPanel.cpp

@@ -223,11 +223,11 @@ namespace BansheeEngine
 	void GUIPanel::_updateChildLayout(GUIElementBase* element, const GUILayoutData& data)
 	{
 		GUILayoutData childData = data;
-		element->_setLayoutData(childData);
 
 		childData.clipRect = data.area;
 		childData.clipRect.clip(data.clipRect);
 
+		element->_setLayoutData(childData);
 		element->_updateLayoutInternal(childData);
 	}
 

+ 1 - 1
BansheeEngine/Source/BsGUISliderHandle.cpp

@@ -139,7 +139,7 @@ namespace BansheeEngine
 		else
 			offset.y += getHandlePosPx();
 
-		Rect2I clipRect = mLayoutData.clipRect;
+		Rect2I clipRect = mLayoutData.getLocalClipRect();
 		if(mHorizontal)
 			clipRect.x -= getHandlePosPx();
 		else

+ 2 - 2
BansheeEngine/Source/BsGUITexture.cpp

@@ -206,8 +206,8 @@ namespace BansheeEngine
 
 	void GUITexture::updateClippedBounds()
 	{
-		Vector2I offset(mLayoutData.area.x, mLayoutData.area.y);
-		mClippedBounds = mImageSprite->getBounds(offset, mLayoutData.getLocalClipRect());
+		mClippedBounds = mLayoutData.area;
+		mClippedBounds.clip(mLayoutData.clipRect);
 	}
 
 	void GUITexture::styleUpdated()

+ 7 - 50
BansheeEngine/Source/BsGUIWidget.cpp

@@ -102,8 +102,6 @@ namespace BansheeEngine
 
 	void GUIWidget::_updateLayout()
 	{
-		UnorderedMap<GUIElementBase*, bool> elementsToUpdate;
-
 		// Determine dirty contents and layouts
 		Stack<GUIElementBase*> todo;
 		todo.push(mPanel);
@@ -119,58 +117,16 @@ namespace BansheeEngine
 				assert(updateParent != nullptr || currentElem == mPanel);
 
 				if (updateParent != nullptr)
-				{
-					if (updateParent->_getType() == GUIElementBase::Type::Panel)
-					{
-						GUIElementBase* optimizedUpdateParent = currentElem;
-						while (optimizedUpdateParent->_getParent() != updateParent)
-							optimizedUpdateParent = optimizedUpdateParent->_getParent();
-
-						elementsToUpdate.insert(std::make_pair(optimizedUpdateParent, true));
-					}
-					else
-						elementsToUpdate.insert(std::make_pair(updateParent, false));
-				}
+					_updateLayout(updateParent);
 				else // Must be root panel
-				{
-					elementsToUpdate.insert(std::make_pair(mPanel, false));
-				}
+					_updateLayout(mPanel);
 			}
-
-			UINT32 numChildren = currentElem->_getNumChildren();
-			for (UINT32 i = 0; i < numChildren; i++)
-				todo.push(currentElem->_getChild(i));
-		}
-
-		// Determine top-level layouts and update them
-		for (auto& elemData : elementsToUpdate)
-		{
-			GUIElementBase* updateParent = nullptr;
-
-			bool isPanelOptimized = elemData.second;
-			if (isPanelOptimized)
-				updateParent = elemData.first->_getParent();
 			else
-				updateParent = elemData.first;
-
-			// Skip update if a parent element is also queued for update
-			bool isTopLevel = true;
-			GUIElementBase* curUpdateParent = elemData.first->_getParent();
-			while (curUpdateParent != nullptr)
 			{
-				if (elementsToUpdate.find(curUpdateParent) != elementsToUpdate.end())
-				{
-					isTopLevel = false;
-					break;
-				}
-
-				curUpdateParent = curUpdateParent->_getParent();
+				UINT32 numChildren = currentElem->_getNumChildren();
+				for (UINT32 i = 0; i < numChildren; i++)
+					todo.push(currentElem->_getChild(i));
 			}
-
-			if (!isTopLevel)
-				continue;
-
-			_updateLayout(elemData.first);
 		}
 	}
 
@@ -212,7 +168,7 @@ namespace BansheeEngine
 
 		// Mark dirty contents
 		Stack<GUIElementBase*> todo;
-		todo.push(updateParent);
+		todo.push(elem);
 
 		while (!todo.empty())
 		{
@@ -357,6 +313,7 @@ namespace BansheeEngine
 		layoutData.area.width = width;
 		layoutData.area.height = height;
 		layoutData.clipRect = Rect2I(0, 0, width, height);
+		layoutData.setWidgetDepth(mDepth);
 
 		mPanel->setWidth(width);
 		mPanel->setHeight(height);

+ 4 - 4
TODO.txt

@@ -32,10 +32,6 @@ Add C# Renderable
 ----------------------------------------------------------------------
 Project window
 
-Potential issue: isPanelOptimize is now determined on the fly in _updateLayout but it can trigger
- on elements that were originally imaged to be panel optimized (but the end result /should/ be the same)
-
-Root panel isn't being updated properly
 Positions in color picker are screwed up
 Depth in COlorPicker is fucked up
 Test dock manager and sliders (right now it doesn't seem to work at all)
@@ -135,6 +131,10 @@ Need a way to drag and drop items from Scene tree view to Scene view
 ----------------------------------------------------------------------
 Other
 
+There is a memory corruption happening. Haven't determined where exactly but it's possible it has something
+to do with the opening of ColorPicker window. One time I got a heap read after delete error caused by GUIManager
+attempting to allocate a new transient mesh, and another time I got a hang when inserting a script object into a std::set.
+
 Got a crash on shutdown that was caused by locking a mutex in an Event destructor. Event was Platform::onMouseCaptureChanged. 
 Issue happened when I closed the app via the X button (if that's relevant). It doesn't seem to happen always.
  - This is likely due to some other error. When VS finds an exception it triggers a dialog box which triggers the msg loop in-engine and causes another exception.

+ 27 - 0
TODOExperimentation.txt

@@ -0,0 +1,27 @@
+-------------------------
+FBX
+ - Unity stores mesh attributes per-index and then performs splitting as needed. See code in ImportMeshUtility
+  - This means I probably want to delay creating MeshData - which is also okay since I determine bone weights at a later stage anyway
+ - Transform tangent/bitangent and encode them into a 4-vector value
+ - Transform between FBX trans/rot/scale and engine trans/rot/scale
+ - Neater mesh parsing
+ - Calculate normals from smoothing groups
+  - Control this via an import option? Since in same cases normals are provided.
+ - Import skeleton
+  - Unity just maps nodes referenced by FbxSkin clusters to bones, it do no separate parsing
+ - Import keyframes
+  - ?? TODO
+ - Import blend weights
+  - FbxSkin
+    -> FbxCluster - One cluster per bone, contains weights for each influenced control point in destination geometry
+	  - Its transform is also the bind pose transfrom for the bone
+ - Import blend shapes
+  - FbxBlendShape
+    -> FbxBlendShapeChannel - One channel per blend "animation". One animation can have multiple 
+	   target shapes. e.g. shape 0 is used for 0-40% of the animation, and shape 1 for 40-100%.
+      -> FbxShape -> Contains a set of geometry used for the shape. This should be a set of vertices, 
+	     but I need normals/tangents too. Not sure if FBX stores those as Unity seems to assume it doesn't and calculates them manually.
+
+Create a set of output data that is retrieved from the FBX. Then convert that data to Banshee mesh/animation/etc.
+For now I would only use the mesh part but later I can just take the rest of the data as needed without messing with the
+FBX importer.