Selaa lähdekoodia

More work on GUI

Marko Pintera 12 vuotta sitten
vanhempi
sitoutus
9476a511d7

+ 3 - 2
CamelotCore/CamelotCore.vcxproj

@@ -212,11 +212,12 @@
     <ClInclude Include="Include\CmGpuProgramManager.h" />
     <ClInclude Include="Include\CmGpuProgramManager.h" />
     <ClInclude Include="Include\CmGpuProgramParams.h" />
     <ClInclude Include="Include\CmGpuProgramParams.h" />
     <ClInclude Include="Include\CmGpuProgramRTTI.h" />
     <ClInclude Include="Include\CmGpuProgramRTTI.h" />
-    <ClInclude Include="Include\CmGUI.h" />
     <ClInclude Include="Include\CmGUIElement.h" />
     <ClInclude Include="Include\CmGUIElement.h" />
+    <ClInclude Include="Include\CmGUIElementStyle.h" />
     <ClInclude Include="Include\CmGUILabel.h" />
     <ClInclude Include="Include\CmGUILabel.h" />
     <ClInclude Include="Include\CmGUIManager.h" />
     <ClInclude Include="Include\CmGUIManager.h" />
     <ClInclude Include="Include\CmGUIMaterialManager.h" />
     <ClInclude Include="Include\CmGUIMaterialManager.h" />
+    <ClInclude Include="Include\CmGUISkin.h" />
     <ClInclude Include="Include\CmGUIWidget.h" />
     <ClInclude Include="Include\CmGUIWidget.h" />
     <ClInclude Include="Include\CmHardwareBuffer.h" />
     <ClInclude Include="Include\CmHardwareBuffer.h" />
     <ClInclude Include="Include\CmHardwareBufferManager.h" />
     <ClInclude Include="Include\CmHardwareBufferManager.h" />
@@ -323,11 +324,11 @@
     <ClCompile Include="Source\CmGpuProgramImportOptions.cpp" />
     <ClCompile Include="Source\CmGpuProgramImportOptions.cpp" />
     <ClCompile Include="Source\CmGpuProgramManager.cpp" />
     <ClCompile Include="Source\CmGpuProgramManager.cpp" />
     <ClCompile Include="Source\CmGpuProgramParams.cpp" />
     <ClCompile Include="Source\CmGpuProgramParams.cpp" />
-    <ClCompile Include="Source\CmGUI.cpp" />
     <ClCompile Include="Source\CmGUIElement.cpp" />
     <ClCompile Include="Source\CmGUIElement.cpp" />
     <ClCompile Include="Source\CmGUILabel.cpp" />
     <ClCompile Include="Source\CmGUILabel.cpp" />
     <ClCompile Include="Source\CmGUIManager.cpp" />
     <ClCompile Include="Source\CmGUIManager.cpp" />
     <ClCompile Include="Source\CmGUIMaterialManager.cpp" />
     <ClCompile Include="Source\CmGUIMaterialManager.cpp" />
+    <ClCompile Include="Source\CmGUISkin.cpp" />
     <ClCompile Include="Source\CmGUIWidget.cpp" />
     <ClCompile Include="Source\CmGUIWidget.cpp" />
     <ClCompile Include="Source\CmHardwareBufferManager.cpp" />
     <ClCompile Include="Source\CmHardwareBufferManager.cpp" />
     <ClCompile Include="Source\CmImportOptions.cpp" />
     <ClCompile Include="Source\CmImportOptions.cpp" />

+ 9 - 6
CamelotCore/CamelotCore.vcxproj.filters

@@ -438,9 +438,6 @@
     <ClInclude Include="Include\CmImageSprite.h">
     <ClInclude Include="Include\CmImageSprite.h">
       <Filter>Header Files\2D</Filter>
       <Filter>Header Files\2D</Filter>
     </ClInclude>
     </ClInclude>
-    <ClInclude Include="Include\CmGUI.h">
-      <Filter>Header Files\GUI</Filter>
-    </ClInclude>
     <ClInclude Include="Include\CmGUIWidget.h">
     <ClInclude Include="Include\CmGUIWidget.h">
       <Filter>Header Files\GUI</Filter>
       <Filter>Header Files\GUI</Filter>
     </ClInclude>
     </ClInclude>
@@ -462,6 +459,12 @@
     <ClInclude Include="Include\CmBuiltinMaterialManager.h">
     <ClInclude Include="Include\CmBuiltinMaterialManager.h">
       <Filter>Source Files\Material</Filter>
       <Filter>Source Files\Material</Filter>
     </ClInclude>
     </ClInclude>
+    <ClInclude Include="Include\CmGUIElementStyle.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
+    <ClInclude Include="Include\CmGUISkin.h">
+      <Filter>Header Files\GUI</Filter>
+    </ClInclude>
   </ItemGroup>
   </ItemGroup>
   <ItemGroup>
   <ItemGroup>
     <ClCompile Include="Source\CamelotRenderer.cpp">
     <ClCompile Include="Source\CamelotRenderer.cpp">
@@ -698,9 +701,6 @@
     <ClCompile Include="Source\CmGUIWidget.cpp">
     <ClCompile Include="Source\CmGUIWidget.cpp">
       <Filter>Source Files\GUI</Filter>
       <Filter>Source Files\GUI</Filter>
     </ClCompile>
     </ClCompile>
-    <ClCompile Include="Source\CmGUI.cpp">
-      <Filter>Source Files\GUI</Filter>
-    </ClCompile>
     <ClCompile Include="Source\CmGUILabel.cpp">
     <ClCompile Include="Source\CmGUILabel.cpp">
       <Filter>Source Files\GUI</Filter>
       <Filter>Source Files\GUI</Filter>
     </ClCompile>
     </ClCompile>
@@ -713,5 +713,8 @@
     <ClCompile Include="Source\CmGUIMaterialManager.cpp">
     <ClCompile Include="Source\CmGUIMaterialManager.cpp">
       <Filter>Source Files\GUI</Filter>
       <Filter>Source Files\GUI</Filter>
     </ClCompile>
     </ClCompile>
+    <ClCompile Include="Source\CmGUISkin.cpp">
+      <Filter>Source Files\GUI</Filter>
+    </ClCompile>
   </ItemGroup>
   </ItemGroup>
 </Project>
 </Project>

+ 0 - 11
CamelotCore/Include/CmGUI.h

@@ -1,11 +0,0 @@
-#pragma once
-
-#include "CmPrerequisites.h"
-
-namespace CamelotEngine
-{
-	class CM_EXPORT GUI
-	{
-
-	};
-}

+ 12 - 7
CamelotCore/Include/CmGUIElement.h

@@ -8,15 +8,9 @@ namespace CamelotEngine
 	class CM_EXPORT GUIElement
 	class CM_EXPORT GUIElement
 	{
 	{
 	public:
 	public:
-		GUIElement();
+		GUIElement(GUIWidget* parent, const GUISkin* skin);
 		~GUIElement();
 		~GUIElement();
 
 
-		//  onMouseMove
-		//	onMousePress
-		//	onMouseReleased
-		//	onKeyPressed
-		//	onKeyReleased
-	protected:
 		/**
 		/**
 		 * @brief	Returns the number of separate render elements in the GUI element.
 		 * @brief	Returns the number of separate render elements in the GUI element.
 		 * 			
 		 * 			
@@ -65,5 +59,16 @@ namespace CamelotEngine
 		 * @param	renderElementIdx	Zero-based index of the render element.
 		 * @param	renderElementIdx	Zero-based index of the render element.
 		 */
 		 */
 		virtual void fillBuffer(Vector2* vertices, Vector2* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 renderElementIdx) const = 0;
 		virtual void fillBuffer(Vector2* vertices, Vector2* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 renderElementIdx) const = 0;
+
+		//  onMouseMove
+		//	onMousePress
+		//	onMouseReleased
+		//	onKeyPressed
+		//	onKeyReleased
+	protected:
+		GUIWidget* mParent;
+		const GUIElementStyle* mStyle;
+
+		virtual const String& getGUITypeName() = 0;
 	};
 	};
 }
 }

+ 18 - 0
CamelotCore/Include/CmGUIElementStyle.h

@@ -0,0 +1,18 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+
+namespace CamelotEngine
+{
+	struct CM_EXPORT GUIElementStyle
+	{
+		GUIElementStyle()
+			:fontSize(8)
+		{
+
+		}
+
+		FontPtr font;
+		UINT32 fontSize;
+	};
+}

+ 5 - 4
CamelotCore/Include/CmGUILabel.h

@@ -28,11 +28,12 @@ namespace CamelotEngine
 		 */
 		 */
 		virtual void fillBuffer(Vector2* vertices, Vector2* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 renderElementIdx) const;
 		virtual void fillBuffer(Vector2* vertices, Vector2* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 renderElementIdx) const;
 	private:
 	private:
-		friend class GUI;
-
-		GUILabel(const String& text, const FontPtr& font, UINT32 fontSize);
-
 		TextSprite* mTextSprite;
 		TextSprite* mTextSprite;
 		String mText;
 		String mText;
+
+		friend class GUIWidget;
+		GUILabel(GUIWidget* parent, const String& text, const GUISkin* skin);
+
+		virtual const String& getGUITypeName();
 	};
 	};
 }
 }

+ 6 - 1
CamelotCore/Include/CmGUIManager.h

@@ -2,6 +2,7 @@
 
 
 #include "CmPrerequisites.h"
 #include "CmPrerequisites.h"
 #include "CmModule.h"
 #include "CmModule.h"
+#include "CmRenderOperation.h"
 
 
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
@@ -14,9 +15,13 @@ namespace CamelotEngine
 		void registerWidget(GUIWidget* widget);
 		void registerWidget(GUIWidget* widget);
 		void unregisterWidget(GUIWidget* widget);
 		void unregisterWidget(GUIWidget* widget);
 
 
-		void renderGUI();
+		vector<RenderObject>::type getRenderObjects();
 
 
 	private:
 	private:
+		vector<GUIWidget*>::type mWidgets;
+		vector<MeshHandle>::type mMeshes;
+		vector<MaterialHandle>::type mMaterials;
+
 		void updateDirtyMeshes();
 		void updateDirtyMeshes();
 	};
 	};
 }
 }

+ 19 - 0
CamelotCore/Include/CmGUISkin.h

@@ -0,0 +1,19 @@
+#pragma once
+
+#include "CmPrerequisites.h"
+#include "CmGUIElementStyle.h"
+
+namespace CamelotEngine
+{
+	class CM_EXPORT GUISkin
+	{
+	public:
+		const GUIElementStyle* getStyle(const String& guiElemType) const;
+		void setStyle(const String& guiElemType, const GUIElementStyle& style);
+
+	private:
+		static GUIElementStyle DefaultStyle;
+
+		unordered_map<std::string, GUIElementStyle>::type mStyles;
+	};
+}

+ 17 - 2
CamelotCore/Include/CmGUIWidget.h

@@ -12,11 +12,26 @@ namespace CamelotEngine
 
 
 		virtual void update();
 		virtual void update();
 
 
+	protected:
+		GUILabel* addLabel(const String& text);
+
+		const GUISkin* getGUISkin() const;
+
 	private:
 	private:
 		friend class GameObject;
 		friend class GameObject;
-
-		GUI* mGUI;
+		friend class GUIManager;
 
 
 		GUIWidget(GameObjectPtr parent);
 		GUIWidget(GameObjectPtr parent);
+
+		vector<GUIElement*>::type mElements;
+		/**
+		 * @brief	GUIWidgets sharing the same mesh group ID will attempted to be merged into
+		 * 			a single render mesh (as much as materials allow).
+		 * 			
+		 * @note	ID of -1 means that the widget mesh should never be grouped.
+		 */
+		INT32 mMeshGroupID;
+		const GUISkin* mSkin;
+		static GUISkin DefaultSkin;
 	};
 	};
 }
 }

+ 2 - 1
CamelotCore/Include/CmPrerequisites.h

@@ -167,7 +167,8 @@ namespace CamelotEngine {
 	class GUIWidget;
 	class GUIWidget;
 	class GUIElement;
 	class GUIElement;
 	class GUILabel;
 	class GUILabel;
-	class GUI;
+	struct GUIElementStyle;
+	class GUISkin;
 	// RTTI
 	// RTTI
 	class MeshRTTI;
 	class MeshRTTI;
 	// Desc structs
 	// Desc structs

+ 6 - 0
CamelotCore/Include/CmRenderOperation.h

@@ -82,4 +82,10 @@ namespace CamelotEngine
 	};
 	};
 	/** @} */
 	/** @} */
 	/** @} */
 	/** @} */
+
+	struct RenderObject
+	{
+		RenderOperation op;
+		MaterialHandle mat;
+	};
 }
 }

+ 0 - 6
CamelotCore/Source/CmGUI.cpp

@@ -1,6 +0,0 @@
-#include "CmGUI.h"
-
-namespace CamelotEngine
-{
-
-}

+ 3 - 2
CamelotCore/Source/CmGUIElement.cpp

@@ -1,10 +1,11 @@
 #include "CmGUIElement.h"
 #include "CmGUIElement.h"
+#include "CmGUISkin.h"
 
 
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
-	GUIElement::GUIElement()
+	GUIElement::GUIElement(GUIWidget* parent, const GUISkin* skin)
+		:mParent(parent)
 	{
 	{
-
 	}
 	}
 
 
 	GUIElement::~GUIElement()
 	GUIElement::~GUIElement()

+ 14 - 3
CamelotCore/Source/CmGUILabel.cpp

@@ -1,12 +1,17 @@
 #include "CmGUILabel.h"
 #include "CmGUILabel.h"
+#include "CmGUIElementStyle.h"
 #include "CmTextSprite.h"
 #include "CmTextSprite.h"
+#include "CmGUISkin.h"
 
 
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
-	GUILabel::GUILabel(const String& text, const FontPtr& font, UINT32 fontSize)
-		:mText(text)
+	GUILabel::GUILabel(GUIWidget* parent, const String& text, const GUISkin* skin)
+		:GUIElement(parent, skin), mText(text)
 	{
 	{
-		mTextSprite = new TextSprite(text, font, fontSize);
+		// This is calling a virtual method but it's okay because we always want the one
+		// existing on this class.
+		mStyle = skin->getStyle(getGUITypeName());
+		mTextSprite = new TextSprite(text, mStyle->font, mStyle->fontSize);
 	}
 	}
 
 
 	UINT32 GUILabel::getNumRenderElements() const
 	UINT32 GUILabel::getNumRenderElements() const
@@ -28,4 +33,10 @@ namespace CamelotEngine
 	{
 	{
 		mTextSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, renderElementIdx);
 		mTextSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, renderElementIdx);
 	}
 	}
+
+	const String& GUILabel::getGUITypeName()
+	{
+		static String typeName = "Label";
+		return typeName;
+	}
 }
 }

+ 180 - 4
CamelotCore/Source/CmGUIManager.cpp

@@ -1,26 +1,202 @@
 #include "CmGUIManager.h"
 #include "CmGUIManager.h"
+#include "CmGUIWidget.h"
+#include "CmGUIElement.h"
+#include "CmMaterial.h"
+#include "CmMeshData.h"
+#include "CmMesh.h"
+#include "CmUtil.h"
 
 
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
-	void GUIManager::renderGUI()
+	struct MeshGroupID
+	{
+		class HashFunction
+		{
+		public:
+			inline size_t operator()(const MeshGroupID& v) const
+			{
+				size_t seed = 0;
+				hash_combine(seed, v.materialId);
+				hash_combine(seed, v.meshGroupId);
+				return seed;
+			}
+		};
+
+		class EqualFunction
+		{
+		public:
+			inline bool operator()(const MeshGroupID &a, const MeshGroupID &b) const
+			{
+				return a.materialId == b.materialId && a.meshGroupId == b.meshGroupId;
+			}
+		};
+
+		MeshGroupID(UINT32 _meshGroupId, UINT64 _materialId)
+			:meshGroupId(_meshGroupId), materialId(_materialId)
+		{
+
+		}
+
+		UINT32 meshGroupId;
+		UINT64 materialId;
+		
+	};
+
+	vector<RenderObject>::type GUIManager::getRenderObjects()
 	{
 	{
 		updateDirtyMeshes();
 		updateDirtyMeshes();
 
 
-		// TODO
+		// TODO - It might be better to use standard Component system for rendering meshes
+		// (i.e. make GUIManager a component and have it create "Renderable" components that have
+		// meshes attached to them)
+		UINT32 meshIdx = 0;
+		vector<RenderObject>::type renderObjects;
+		for(auto& mesh : mMeshes)
+		{
+			MaterialHandle material = mMaterials[meshIdx];
+
+			if(material == nullptr || !material.isLoaded())
+				continue;
+
+			MeshHandle mesh = mMeshes[meshIdx];
+
+			if(mesh == nullptr || !mesh.isLoaded())
+				continue;
+
+			// TODO - Set current viewport resolution so that GUI can be rendered properly
+			//  - HOW DO I handle multiple GUIWidgets across different windows?
+
+			RenderObject ro;
+			ro.mat = material;
+			ro.op = mesh->getRenderOperation(0);
+
+			renderObjects.push_back(ro);
+
+			meshIdx++;
+		}
+
+		return renderObjects;
 	}
 	}
 
 
 	void GUIManager::registerWidget(GUIWidget* widget)
 	void GUIManager::registerWidget(GUIWidget* widget)
 	{
 	{
-		// TODO
+		mWidgets.push_back(widget);
 	}
 	}
 
 
 	void GUIManager::unregisterWidget(GUIWidget* widget)
 	void GUIManager::unregisterWidget(GUIWidget* widget)
 	{
 	{
-		// TODO
+		auto findIter = std::find(begin(mWidgets), end(mWidgets), widget);
+
+		if(findIter != end(mWidgets))
+			mWidgets.erase(findIter);
 	}
 	}
 
 
 	void GUIManager::updateDirtyMeshes()
 	void GUIManager::updateDirtyMeshes()
 	{
 	{
+		struct TempMeshData
+		{
+			TempMeshData()
+				:numQuads(0), quadOffset(0), vertices(nullptr),
+				uvs(nullptr), indices(nullptr)
+			{ }
+
+			UINT32 numQuads;
+			UINT32 quadOffset;
+			Vector2* vertices;
+			Vector2* uvs;
+			UINT32* indices;
+			MaterialHandle material;
+		};
+
+		std::unordered_map<MeshGroupID, TempMeshData, MeshGroupID::HashFunction, MeshGroupID::EqualFunction> meshDataPerRenderElement;
+
+		// Group meshes based on widget mesh ID and used materials
+		// Determine mesh sizes per group
+		for(auto& widget : mWidgets)
+		{
+			for(auto& elem : widget->mElements)
+			{
+				UINT32 numRenderElems = elem->getNumRenderElements();
+
+				for(UINT32 i = 0; i < numRenderElems; i++)
+				{
+					const MaterialHandle& mat = elem->getMaterial(i);
+
+					MeshGroupID meshGroup(widget->mMeshGroupID, mat->getInternalID()); // TODO - I group based on material ID. So if two widgets used exact copies of the same material
+																					   // this system won't detect it. Find a better way of determining material similarity?
+																					   
+
+					UINT32 numQuads = elem->getNumQuads(i);
+					meshDataPerRenderElement[meshGroup].numQuads += numQuads;
+					meshDataPerRenderElement[meshGroup].material = mat;
+				}
+			}
+		}
+
+		// Allocate buffers for each group
+		UINT32 numMeshes = 0;
+		for(auto& renderElem : meshDataPerRenderElement)
+		{
+			renderElem.second.vertices = new Vector2[renderElem.second.numQuads * 4];
+			renderElem.second.uvs = new Vector2[renderElem.second.numQuads * 4];
+			renderElem.second.indices = new UINT32[renderElem.second.numQuads * 6];
+			numMeshes++;
+		}
+
+		// Fill buffers for each group
+		for(auto& widget : mWidgets)
+		{
+			for(auto& elem : widget->mElements)
+			{
+				UINT32 numRenderElems = elem->getNumRenderElements();
+
+				for(UINT32 i = 0; i < numRenderElems; i++)
+				{
+					const MaterialHandle& mat = elem->getMaterial(i);
+					MeshGroupID meshGroup(widget->mMeshGroupID, mat->getInternalID()); 
+
+					Vector2* vertices = meshDataPerRenderElement[meshGroup].vertices;
+					Vector2* uvs = meshDataPerRenderElement[meshGroup].uvs;
+					UINT32* indices = meshDataPerRenderElement[meshGroup].indices;
+					UINT32 startingQuad = meshDataPerRenderElement[meshGroup].quadOffset;
+					UINT32 maxNumQuads = meshDataPerRenderElement[meshGroup].numQuads;
+
+					elem->fillBuffer(vertices, uvs, indices, startingQuad, maxNumQuads, i);
+
+					UINT32 numQuads = elem->getNumQuads(i);
+					meshDataPerRenderElement[meshGroup].quadOffset += numQuads;
+				}
+			}
+		}
+
+		// Update meshes
+		for(UINT32 i = (UINT32)mMeshes.size(); i < numMeshes; i++)
+		{
+			MeshHandle newMesh = Mesh::create();
+			mMeshes.push_back(newMesh);
+		}
+
+		while((UINT32)mMeshes.size() > numMeshes && (UINT32)mMeshes.size() > 0)
+		{
+			mMeshes.erase(mMeshes.end() - 1); // TODO: Destroying meshes as soon as they're not used might be a perf. penalty?
+											  //  Maybe instead pool the meshes and only actually remove them when a certain number of unused ones exists.
+		}
+
+		mMaterials.resize(numMeshes);
+
+		UINT32 meshIdx = 0;
+		for(auto& renderElem : meshDataPerRenderElement)
+		{
+			std::shared_ptr<MeshData> meshData(new MeshData());
+
+			meshData->setPositions(renderElem.second.vertices, renderElem.second.numQuads * 4);
+			meshData->setUV0(renderElem.second.uvs, renderElem.second.numQuads * 4);
+			meshData->setIndices(renderElem.second.indices, renderElem.second.numQuads * 6);
+
+			mMeshes[meshIdx]->setMeshData(meshData);
+			mMaterials[meshIdx] = renderElem.second.material;
 
 
+			meshIdx++;
+		}
 	}
 	}
 }
 }

+ 25 - 0
CamelotCore/Source/CmGUISkin.cpp

@@ -0,0 +1,25 @@
+#include "CmGUISkin.h"
+#include "CmGUIElementStyle.h"
+#include "CmDebug.h"
+
+namespace CamelotEngine
+{
+	GUIElementStyle GUISkin::DefaultStyle;
+
+	const GUIElementStyle* GUISkin::getStyle(const String& guiElemType) const
+	{
+		auto iterFind = mStyles.find(guiElemType);
+
+		if(iterFind != mStyles.end())
+			return &iterFind->second;
+
+		LOGWRN("Cannot find GUI style with name: " + guiElemType + ". Returning default style.");
+
+		return &DefaultStyle;
+	}
+
+	void GUISkin::setStyle(const String& guiElemType, const GUIElementStyle& style)
+	{
+		mStyles[guiElemType] = style;
+	}
+}

+ 27 - 3
CamelotCore/Source/CmGUIWidget.cpp

@@ -1,11 +1,14 @@
 #include "CmGUIWidget.h"
 #include "CmGUIWidget.h"
-#include "CmGUI.h"
 #include "CmGUIManager.h"
 #include "CmGUIManager.h"
+#include "CmGUISkin.h"
+#include "CmGUILabel.h"
 
 
 namespace CamelotEngine
 namespace CamelotEngine
 {
 {
+	GUISkin GUIWidget::DefaultSkin;
+
 	GUIWidget::GUIWidget(GameObjectPtr parent)
 	GUIWidget::GUIWidget(GameObjectPtr parent)
-		:Component(parent), mGUI(new GUI())
+		:Component(parent), mSkin(nullptr), mMeshGroupID(0)
 	{
 	{
 		GUIManager::instance().registerWidget(this);
 		GUIManager::instance().registerWidget(this);
 	}
 	}
@@ -14,7 +17,28 @@ namespace CamelotEngine
 	{
 	{
 		GUIManager::instance().unregisterWidget(this);
 		GUIManager::instance().unregisterWidget(this);
 
 
-		delete mGUI;
+		for(auto& elem : mElements)
+		{
+			delete elem;
+		}
+
+		mElements.clear();
+	}
+
+	GUILabel* GUIWidget::addLabel(const String& text)
+	{
+		GUILabel* label = new GUILabel(this, text, getGUISkin());
+		mElements.push_back(label);
+
+		return label;
+	}
+
+	const GUISkin* GUIWidget::getGUISkin() const
+	{
+		if(mSkin != nullptr)
+			return mSkin;
+		else
+			return &DefaultSkin;
 	}
 	}
 
 
 	void GUIWidget::update()
 	void GUIWidget::update()

+ 2 - 0
TODO.txt

@@ -26,6 +26,8 @@ Add TextUtil class
  - Maybe even move line and word classes to it
  - Maybe even move line and word classes to it
 
 
 Immediate TODO:
 Immediate TODO:
+ IMPORTANT - GUIElement in its constructor calls a virtual method to detect actual type, which won't work
+
 Implement image shader for D3D11BuiltinMaterialManager
 Implement image shader for D3D11BuiltinMaterialManager
 Improve text shader so it doesn't have resolution values hardcoded in
 Improve text shader so it doesn't have resolution values hardcoded in
 Implement D3D9 and GL BuiltInMaterialManager
 Implement D3D9 and GL BuiltInMaterialManager