Browse Source

Added the ability to or not to separate GUI elements by widget when rendering

Marko Pintera 12 years ago
parent
commit
9f5f91587c
2 changed files with 63 additions and 24 deletions
  1. 2 0
      BansheeEngine/Include/BsGUIManager.h
  2. 61 24
      BansheeEngine/Source/BsGUIManager.cpp

+ 2 - 0
BansheeEngine/Include/BsGUIManager.h

@@ -20,6 +20,7 @@ namespace BansheeEngine
 
 			std::vector<CM::HMesh> cachedMeshes;
 			std::vector<CM::HMaterial> cachedMaterials;
+			std::vector<GUIWidget*> cachedWidgetsPerMesh;
 			std::vector<GUIWidget*> widgets;
 			bool isDirty;
 		};
@@ -40,6 +41,7 @@ namespace BansheeEngine
 		GUIWidget* mMouseOverWidget;
 		GUIElement* mMouseOverElement;
 
+		bool mSeparateMeshesByWidget;
 		bool mLastFrameButtonState[CM::MB_Count];
 		CM::Int2 mLastCursorPos;
 

+ 61 - 24
BansheeEngine/Source/BsGUIManager.cpp

@@ -42,7 +42,7 @@ namespace BansheeEngine
 	};
 
 	GUIManager::GUIManager()
-		:mMouseOverElement(nullptr), mMouseOverWidget(nullptr)
+		:mMouseOverElement(nullptr), mMouseOverWidget(nullptr), mSeparateMeshesByWidget(true)
 	{
 		for(int i = 0; i < MB_Count; i++)
 			mLastFrameButtonState[i] = false;
@@ -113,39 +113,51 @@ namespace BansheeEngine
 		GUIRenderData& renderData = findIter->second;
 
 		// Render the meshes
-		UINT32 meshIdx = 0;
-		for(auto& mesh : renderData.cachedMeshes)
+		if(mSeparateMeshesByWidget)
 		{
-			HMaterial material = renderData.cachedMaterials[meshIdx];
+			UINT32 meshIdx = 0;
+			for(auto& mesh : renderData.cachedMeshes)
+			{
+				HMaterial material = renderData.cachedMaterials[meshIdx];
+				GUIWidget* widget = renderData.cachedWidgetsPerMesh[meshIdx];
 
-			// TODO - Possible optimization. I currently divide by width/height inside the shader, while it
-			// might be more optimal to just scale the mesh as the resolution changes?
-			float invViewportWidth = 1.0f / (target->getWidth() * 0.5f);
-			float invViewportHeight = 1.0f / (target->getHeight() * 0.5f);
+				// TODO - Possible optimization. I currently divide by width/height inside the shader, while it
+				// might be more optimal to just scale the mesh as the resolution changes?
+				float invViewportWidth = 1.0f / (target->getWidth() * 0.5f);
+				float invViewportHeight = 1.0f / (target->getHeight() * 0.5f);
 
-			material->setFloat("invViewportWidth", invViewportWidth);
-			material->setFloat("invViewportHeight", invViewportHeight);
-			material->setMat4("worldTransform", Matrix4::IDENTITY);
-			//material->setMat4("worldTransform", SO()->getWorldTfrm());
+				material->setFloat("invViewportWidth", invViewportWidth);
+				material->setFloat("invViewportHeight", invViewportHeight);
+				material->setMat4("worldTransform", widget->SO()->getWorldTfrm());
 
-			if(material == nullptr || !material.isLoaded())
-				continue;
+				if(material == nullptr || !material.isLoaded())
+					continue;
 
-			if(mesh == nullptr || !mesh.isLoaded())
-				continue;
+				if(mesh == nullptr || !mesh.isLoaded())
+					continue;
 
-			for(UINT32 i = 0; i < material->getNumPasses(); i++)
-			{
-				PassPtr pass = material->getPass(i);
-				pass->activate(renderContext);
+				for(UINT32 i = 0; i < material->getNumPasses(); i++)
+				{
+					PassPtr pass = material->getPass(i);
+					pass->activate(renderContext);
 
-				PassParametersPtr paramsPtr = material->getPassParameters(i);
-				pass->bindParameters(renderContext, paramsPtr);
+					PassParametersPtr paramsPtr = material->getPassParameters(i);
+					pass->bindParameters(renderContext, paramsPtr);
 
-				renderContext.render(mesh->getRenderOperation());
+					renderContext.render(mesh->getRenderOperation());
+				}
+
+				meshIdx++;
 			}
+		}
+		else
+		{
+			// TODO: I want to avoid separating meshes by widget in the future. On DX11 and GL I can set up a shader
+			// that accepts multiple world transforms (one for each widget). Then I can add some instance information to vertices
+			// and render elements using multiple different transforms with a single call.
+			// Separating meshes can then be used as a compatibility mode for DX9
 
-			meshIdx++;
+			CM_EXCEPT(NotImplementedException, "Not implemented");
 		}
 	}
 
@@ -218,6 +230,17 @@ namespace BansheeEngine
 					GUIMaterialGroup* foundGroup = nullptr;
 					for(auto groupIter = allGroups.rbegin(); groupIter != allGroups.rend(); ++groupIter)
 					{
+						// If we separate meshes by widget, ignore any groups with widget parents other than mine
+						if(mSeparateMeshesByWidget)
+						{
+							if(groupIter->elements.size() > 0)
+							{
+								GUIElement* otherElem = groupIter->elements.begin()->element; // We only need to check the first element
+								if(&otherElem->_getParentWidget() != &elem->_getParentWidget())
+									continue;
+							}
+						}
+
 						GUIMaterialGroup& group = *groupIter;
 
 						if(group.depth == elem->_getDepth() || group.depth == (elem->_getDepth() - 1))
@@ -298,12 +321,26 @@ namespace BansheeEngine
 
 			renderData.cachedMaterials.resize(numMeshes);
 
+			if(mSeparateMeshesByWidget)
+				renderData.cachedWidgetsPerMesh.resize(numMeshes);
+
 			// Fill buffers for each group and update their meshes
 			UINT32 groupIdx = 0;
 			for(auto& group : sortedGroups)
 			{
 				renderData.cachedMaterials[groupIdx] = group->material;
 
+				if(mSeparateMeshesByWidget)
+				{
+					if(group->elements.size() == 0)
+						renderData.cachedWidgetsPerMesh[groupIdx] = nullptr;
+					else
+					{
+						GUIElement* elem = group->elements.begin()->element;
+						renderData.cachedWidgetsPerMesh[groupIdx] = &elem->_getParentWidget();
+					}
+				}
+
 				MeshDataPtr meshData = std::shared_ptr<MeshData>(CM_NEW(MeshData, PoolAlloc) MeshData(group->numQuads * 4),
 					&MemAllocDeleter<MeshData, PoolAlloc>::deleter);