changeset 26:3a63df04f3c0

Several Gui enhancements; Drag and drop should work; Added resource caching
author koryspansel
date Fri, 16 Sep 2011 15:28:15 -0700
parents eae13b04b06f
children 5656c8e382fc
files LightClone/LightClone.vcproj LightClone/Source/FixedString.h LightClone/Source/GuiButton.cpp LightClone/Source/GuiButton.h LightClone/Source/GuiElement.cpp LightClone/Source/GuiElement.h LightClone/Source/GuiEvent.h LightClone/Source/GuiEventMap.h LightClone/Source/GuiImage.cpp LightClone/Source/GuiInterface.cpp LightClone/Source/GuiInterface.h LightClone/Source/GuiLabel.cpp LightClone/Source/GuiLabel.h LightClone/Source/HashMap.h LightClone/Source/HashMapIterator.h LightClone/Source/InputManager.cpp LightClone/Source/InputManager.h LightClone/Source/ResourceManager.cpp LightClone/Source/ResourceManager.h LightClone/Source/World.cpp LightClone/ToDo.txt
diffstat 21 files changed, 731 insertions(+), 257 deletions(-) [+]
line wrap: on
line diff
--- a/LightClone/LightClone.vcproj	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/LightClone.vcproj	Fri Sep 16 15:28:15 2011 -0700
@@ -241,38 +241,6 @@
 				>
 			</File>
 			<File
-				RelativePath=".\Source\GuiButton.cpp"
-				>
-			</File>
-			<File
-				RelativePath=".\Source\GuiCursor.cpp"
-				>
-			</File>
-			<File
-				RelativePath=".\Source\GuiElement.cpp"
-				>
-			</File>
-			<File
-				RelativePath=".\Source\GuiEvent.cpp"
-				>
-			</File>
-			<File
-				RelativePath=".\Source\GuiEventMap.cpp"
-				>
-			</File>
-			<File
-				RelativePath=".\Source\GuiImage.cpp"
-				>
-			</File>
-			<File
-				RelativePath=".\Source\GuiInterface.cpp"
-				>
-			</File>
-			<File
-				RelativePath=".\Source\GuiLabel.cpp"
-				>
-			</File>
-			<File
 				RelativePath=".\Source\InputManager.cpp"
 				>
 			</File>
@@ -320,6 +288,42 @@
 				RelativePath=".\Source\World.cpp"
 				>
 			</File>
+			<Filter
+				Name="Gui"
+				>
+				<File
+					RelativePath=".\Source\GuiButton.cpp"
+					>
+				</File>
+				<File
+					RelativePath=".\Source\GuiCursor.cpp"
+					>
+				</File>
+				<File
+					RelativePath=".\Source\GuiElement.cpp"
+					>
+				</File>
+				<File
+					RelativePath=".\Source\GuiEvent.cpp"
+					>
+				</File>
+				<File
+					RelativePath=".\Source\GuiEventMap.cpp"
+					>
+				</File>
+				<File
+					RelativePath=".\Source\GuiImage.cpp"
+					>
+				</File>
+				<File
+					RelativePath=".\Source\GuiInterface.cpp"
+					>
+				</File>
+				<File
+					RelativePath=".\Source\GuiLabel.cpp"
+					>
+				</File>
+			</Filter>
 		</Filter>
 		<Filter
 			Name="Header Files"
@@ -399,43 +403,11 @@
 				>
 			</File>
 			<File
-				RelativePath=".\Source\GuiButton.h"
-				>
-			</File>
-			<File
-				RelativePath=".\Source\GuiCursor.h"
-				>
-			</File>
-			<File
-				RelativePath=".\Source\GuiElement.h"
-				>
-			</File>
-			<File
-				RelativePath=".\Source\GuiEvent.h"
+				RelativePath=".\Source\HashMap.h"
 				>
 			</File>
 			<File
-				RelativePath=".\Source\GuiEventMap.h"
-				>
-			</File>
-			<File
-				RelativePath=".\Source\GuiFunctor.h"
-				>
-			</File>
-			<File
-				RelativePath=".\Source\GuiImage.h"
-				>
-			</File>
-			<File
-				RelativePath=".\Source\GuiInterface.h"
-				>
-			</File>
-			<File
-				RelativePath=".\Source\GuiLabel.h"
-				>
-			</File>
-			<File
-				RelativePath=".\Source\HashMap.h"
+				RelativePath=".\Source\HashMapIterator.h"
 				>
 			</File>
 			<File
@@ -486,6 +458,46 @@
 				RelativePath=".\Source\World.h"
 				>
 			</File>
+			<Filter
+				Name="Gui"
+				>
+				<File
+					RelativePath=".\Source\GuiButton.h"
+					>
+				</File>
+				<File
+					RelativePath=".\Source\GuiCursor.h"
+					>
+				</File>
+				<File
+					RelativePath=".\Source\GuiElement.h"
+					>
+				</File>
+				<File
+					RelativePath=".\Source\GuiEvent.h"
+					>
+				</File>
+				<File
+					RelativePath=".\Source\GuiEventMap.h"
+					>
+				</File>
+				<File
+					RelativePath=".\Source\GuiFunctor.h"
+					>
+				</File>
+				<File
+					RelativePath=".\Source\GuiImage.h"
+					>
+				</File>
+				<File
+					RelativePath=".\Source\GuiInterface.h"
+					>
+				</File>
+				<File
+					RelativePath=".\Source\GuiLabel.h"
+					>
+				</File>
+			</Filter>
 		</Filter>
 		<Filter
 			Name="Resource Files"
--- a/LightClone/Source/FixedString.h	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/FixedString.h	Fri Sep 16 15:28:15 2011 -0700
@@ -21,6 +21,28 @@
 	 */
 	static const uint32 MaximumLength = Size;
 
+	/*
+	 * Hash
+	 */
+	struct Hash
+	{
+		/*
+		 * operator()
+		 */
+		uint32 operator()(const FixedString& kString)
+		{
+			uint32 nHash = 5381;
+
+			const char* pString = (const char*)kString;
+			while(*pString)
+			{
+				nHash = ((nHash << 5) + nHash) + *pString++;
+			}
+
+			return nHash;
+		}
+	};
+
 private:
 
 	/*
@@ -112,28 +134,6 @@
 };
 
 /*
- * FixedStringHash
- */
-struct FixedStringHash
-{
-	/*
-	 * operator()
-	 */
-	uint32 operator()(const FixedString<>& kString)
-	{
-		uint32 nHash = 5381;
-
-		const char* pString = (const char*)kString;
-		while(*pString)
-		{
-			nHash = ((nHash << 5) + nHash) + *pString++;
-		}
-
-		return nHash;
-	}
-};
-
-/*
  * operator ==
  */
 template<uint32 Size>
--- a/LightClone/Source/GuiButton.cpp	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/GuiButton.cpp	Fri Sep 16 15:28:15 2011 -0700
@@ -3,6 +3,7 @@
  */
 
 #include "GuiButton.h"
+#include "GuiInterface.h"
 #include "VertexTypes.h"
 
 /*
@@ -85,7 +86,7 @@
  */
 void GuiButton::Render(RenderContext& kContext, Camera& kCamera)
 {
-	if(bVisible)
+	if(nFlags & GuiElementFlag_Visible)
 	{
 		if(pTexture[nState])
 		{
@@ -200,15 +201,25 @@
 }
 
 /*
+ * OnMouseEnter
+ */
+void GuiButton::OnMouseEnter()
+{
+}
+
+/*
+ * OnMouseLeave
+ */
+void GuiButton::OnMouseLeave()
+{
+}
+
+/*
  * OnMouseDown
  */
 void GuiButton::OnMouseDown(uint32 nButton, float fX, float fY)
 {
-	//TODO: Proper states and click handling
-	GuiEventArguments kArguments;
-	kArguments.pSource = this;
-
-	Fire(EventClick, kArguments);
+	pInterface->AcquireCursor(this);
 }
 
 /*
@@ -216,6 +227,46 @@
  */
 void GuiButton::OnMouseUp(uint32 nButton, float fX, float fY)
 {
+	if(pInterface->IsCursorAcquiredBy(this))
+	{
+		pInterface->ReleaseCursor();
+
+		if(Contains(fX, fY))
+		{
+			nState = GuiButtonState_Hover;
+
+			GuiEventArguments kArguments(this);
+			Fire(EventClick, kArguments);
+		}
+		else
+		{
+			nState = GuiButtonState_Normal;
+		}
+	}
+}
+
+/*
+ * OnMouseMove
+ */
+void GuiButton::OnMouseMove(float fX, float fY)
+{
+	if(pInterface->IsCursorAcquiredBy(this))
+	{
+		if(Contains(fX, fY))
+		{
+			nState = GuiButtonState_Down;
+		}
+		else
+		{
+			nState = GuiButtonState_Hover;
+		}
+	}
+	else
+	{
+		//NOTE: If we're not capturing the mouse we only get mouse
+		//		move events when the cursor is inside the button bounds
+		nState = GuiButtonState_Hover;
+	}
 }
 
 /*
--- a/LightClone/Source/GuiButton.h	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/GuiButton.h	Fri Sep 16 15:28:15 2011 -0700
@@ -112,6 +112,16 @@
 	void SetText(const char* pText);
 
 	/*
+	 * OnMouseEnter
+	 */
+	virtual void OnMouseEnter();
+
+	/*
+	 * OnMouseLeave
+	 */
+	virtual void OnMouseLeave();
+
+	/*
 	 * OnMouseDown
 	 */
 	virtual void OnMouseDown(uint32 nButton, float fX, float fY);
@@ -121,6 +131,11 @@
 	 */
 	virtual void OnMouseUp(uint32 nButton, float fX, float fY);
 
+	/*
+	 * OnMouseMove
+	 */
+	virtual void OnMouseMove(float fX, float fY);
+
 private:
 
 	/*
--- a/LightClone/Source/GuiElement.cpp	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/GuiElement.cpp	Fri Sep 16 15:28:15 2011 -0700
@@ -7,7 +7,7 @@
 /*
  * GuiElement
  */
-GuiElement::GuiElement() : pContainer(NULL), kPosition(0.0f, 0.0f), kDimensions(0.0f, 0.0f), kColor(0xFFFFFFFF), bVisible(true)
+GuiElement::GuiElement() : pContainer(NULL), kPosition(0.0f, 0.0f), kDimensions(0.0f, 0.0f), kColor(0xFFFFFFFF), nFlags(GuiElementFlag_Visible)
 {
 }
 
@@ -49,7 +49,7 @@
  */
 void GuiElement::Render(RenderContext& kContext, Camera& kCamera)
 {
-	if(bVisible)
+	if(nFlags & GuiElementFlag_Visible)
 	{
 		for(uint32 i = 0; i < kChildren.Size(); ++i)
 		{
@@ -157,11 +157,27 @@
 }
 
 /*
- * SetVisible
+ * SetFlag
+ */
+void GuiElement::SetFlag(uint32 nValue)
+{
+	nFlags |= nValue;
+}
+
+/*
+ * ClearFlag
  */
-void GuiElement::SetVisible(bool bValue)
+void GuiElement::ClearFlag(uint32 nValue)
 {
-	bVisible = bValue;
+	nFlags &= ~nValue;
+}
+
+/*
+ * HasFlag
+ */
+bool GuiElement::HasFlag(uint32 nValue) const
+{
+	return (nFlags & nValue) == nValue;
 }
 
 /*
@@ -169,7 +185,7 @@
  */
 bool GuiElement::IsVisible() const
 {
-	return bVisible;
+	return (nFlags & GuiElementFlag_Visible) != 0;
 }
 
 /*
@@ -181,12 +197,9 @@
 
 	for(int32 i = (int32)kChildren.Size() - 1; i >= 0 && !pElement; --i)
 	{
-		if(kChildren[i]->bVisible)
+		if(kChildren[i]->HasFlag(GuiElementFlag_Visible | GuiElementFlag_Pickable))
 		{
-			const D3DXVECTOR2& kLocation	= kChildren[i]->GetPosition();
-			const D3DXVECTOR2& kSize		= kChildren[i]->GetDimensions();
-
-			if(Rectangle2(kLocation.x, kLocation.y, kSize.x, kSize.y).Contains(fX, fY))
+			if(kChildren[i]->Contains(fX, fY))
 			{
 				pElement = kChildren[i]->Pick(fX, fY);
 			}
@@ -195,12 +208,9 @@
 
 	if(!pElement)
 	{
-		if(bVisible)
+		if(HasFlag(GuiElementFlag_Visible | GuiElementFlag_Pickable))
 		{
-			const D3DXVECTOR2& kLocation	= GetPosition();
-			const D3DXVECTOR2& kSize		= GetDimensions();
-
-			if(Rectangle2(kLocation.x, kLocation.y, kSize.x, kSize.y).Contains(fX, fY))
+			if(Contains(fX, fY))
 			{
 				pElement = this;
 			}
@@ -250,6 +260,33 @@
 }
 
 /*
+ * Contains
+ */
+bool GuiElement::Contains(float fX, float fY)
+{
+	const D3DXVECTOR2& kLocation = GetPosition();
+
+	const float fDeltaX	= fX - kLocation.x;
+	const float fDeltaY = fY - kLocation.y;
+
+	return (0.0f <= fDeltaX && fDeltaX < kDimensions.x) && (0.0f <= fDeltaY && fDeltaY < kDimensions.y);
+}
+
+/*
+ * OnMouseEnter
+ */
+void GuiElement::OnMouseEnter()
+{
+}
+
+/*
+ * OnMouseLeave
+ */
+void GuiElement::OnMouseLeave()
+{
+}
+
+/*
  * OnMouseDown
  */
 void GuiElement::OnMouseDown(uint32 nButton, float fX, float fY)
--- a/LightClone/Source/GuiElement.h	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/GuiElement.h	Fri Sep 16 15:28:15 2011 -0700
@@ -13,15 +13,24 @@
 #include "GuiEventMap.h"
 
 /*
- * GuiInterface
+ * GuiElementFlag
  */
-class GuiInterface;
+enum
+{
+	GuiElementFlag_Visible	= 1 << 0,
+	GuiElementFlag_Pickable	= 1 << 1,
+};
 
 /*
  * GuiElement
  */
 class GuiElement : private GuiEventMap
 {
+	/*
+	 * GuiInterface
+	 */
+	friend class GuiInterface;
+
 public:
 
 	/*
@@ -57,9 +66,9 @@
 	D3DCOLOR kColor;
 
 	/*
-	 * bVisible
+	 * nFlags
 	 */
-	bool bVisible;
+	uint32 nFlags;
 
 	/*
 	 * kChildren
@@ -159,9 +168,19 @@
 	float GetHeight() const;
 
 	/*
-	 * SetVisible
+	 * SetFlag
+	 */
+	void SetFlag(uint32 nValue);
+
+	/*
+	 * ClearFlag
 	 */
-	void SetVisible(bool bValue);
+	void ClearFlag(uint32 nValue);
+
+	/*
+	 * HasFlag
+	 */
+	bool HasFlag(uint32 nValue) const;
 
 	/*
 	 * IsVisible
@@ -184,6 +203,33 @@
 	ErrorCode Remove(GuiElement* pElement);
 
 	/*
+	 * Contains
+	 */
+	bool Contains(float fX, float fY);
+
+	/*
+	 * Subscribe
+	 */
+	using GuiEventMap::Subscribe;
+
+	/*
+	 * Fire
+	 */
+	using GuiEventMap::Fire;
+
+protected:
+
+	/*
+	 * OnMouseEnter
+	 */
+	virtual void OnMouseEnter();
+
+	/*
+	 * OnMouseLeave
+	 */
+	virtual void OnMouseLeave();
+
+	/*
 	 * OnMouseDown
 	 */
 	virtual void OnMouseDown(uint32 nButton, float fX, float fY);
@@ -202,16 +248,6 @@
 	 * OnDrop
 	 */
 	virtual void OnDrop(GuiElement* pSource, float fX, float fY);
-
-	/*
-	 * Subscribe
-	 */
-	using GuiEventMap::Subscribe;
-
-	/*
-	 * Fire
-	 */
-	using GuiEventMap::Fire;
 };
 
 #endif //__GUIELEMENT_H__
--- a/LightClone/Source/GuiEvent.h	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/GuiEvent.h	Fri Sep 16 15:28:15 2011 -0700
@@ -23,6 +23,13 @@
 	 * pSource
 	 */
 	GuiElement* pSource;
+
+	/*
+	 * GuiEventArguments
+	 */
+	GuiEventArguments(GuiElement* pInstance) : pSource(pInstance)
+	{
+	}
 };
 
 /*
--- a/LightClone/Source/GuiEventMap.h	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/GuiEventMap.h	Fri Sep 16 15:28:15 2011 -0700
@@ -17,7 +17,7 @@
 	/*
 	 * kMap
 	 */
-	HashMap<FixedString<>, GuiEvent*, FixedStringHash> kMap;
+	HashMap<FixedString<>, GuiEvent*, FixedString<>::Hash> kMap;
 
 public:
 
--- a/LightClone/Source/GuiImage.cpp	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/GuiImage.cpp	Fri Sep 16 15:28:15 2011 -0700
@@ -68,7 +68,7 @@
  */
 void GuiImage::Render(RenderContext& kContext, Camera& kCamera)
 {
-	if(bVisible)
+	if(nFlags & GuiElementFlag_Visible)
 	{
 		if(pTexture)
 		{
--- a/LightClone/Source/GuiInterface.cpp	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/GuiInterface.cpp	Fri Sep 16 15:28:15 2011 -0700
@@ -71,66 +71,94 @@
 		pCursor->Update(fElapsed);
 	}
 
-	GuiElement* pElement = Pick(fMouseX, fMouseY);
-
-	if(fMouseDeltaX != 0.0f || fMouseDeltaY != 0.0f)
+	if(pDragElement)
 	{
-		//Mouse moved
-		if(pCaptureElement)
+		if(pInputManager->IsButtonReleased(nDragButton))
+		{
+			EndDrag(Pick(fMouseX, fMouseY), fMouseX, fMouseY);
+		}
+		else
 		{
-
+			for(uint32 nButton = MouseButton_Left; nButton < MouseButton_Count; ++nButton)
+			{
+				if(pInputManager->IsButtonPressed(nButton) || pInputManager->IsButtonReleased(nButton))
+				{
+					EndDrag(NULL, fMouseX, fMouseY);
+				}
+			}
 		}
 	}
-
-	for(uint32 nButton = MouseButton_Left; nButton < MouseButton_Count; ++nButton)
+	else
 	{
-		// button down
-		if(pInputManager->IsButtonDown(nButton) && !pInputManager->WasButtonDown(nButton))
+		GuiElement* pElement = Pick(fMouseX, fMouseY);
+
+		if(pFocusElement != pElement)
 		{
-			if(pCaptureElement)
+			if(!pCaptureElement)
 			{
-				//TODO: Does capture make sense for mouse down events?
-				pElement->OnMouseDown(nButton, fMouseX, fMouseY);
+				if(pFocusElement)
+				{
+					pFocusElement->OnMouseLeave();
+				}
+
+				if(pElement)
+				{
+					pElement->OnMouseEnter();
+				}
 			}
-			else
+
+			pFocusElement = pElement;
+		}
+
+		for(uint32 nButton = MouseButton_Left; nButton < MouseButton_Count; ++nButton)
+		{
+			// button down
+			if(pInputManager->IsButtonPressed(nButton))
 			{
+				if(pCaptureElement)
+				{
+					pElement->OnMouseDown(nButton, fMouseX, fMouseY);
+				}
+				else
+
 				if(pElement)
 				{
 					pElement->OnMouseDown(nButton, fMouseX, fMouseY);
 				}
 			}
-		}
-		else
+			else
 
-		// button up
-		if(!pInputManager->IsButtonDown(nButton) && pInputManager->WasButtonDown(nButton))
-		{
-			if(pDragElement)
-			{
-				GuiElement* pElement = Pick(fMouseX, fMouseY);
-				if(pElement)
-				{
-					pElement->OnDrop(pDragElement, fMouseX, fMouseY);
-				}
-
-				pDragElement = NULL;
-			}
-			else
+			// button up
+			if(pInputManager->IsButtonReleased(nButton))
 			{
 				if(pCaptureElement)
 				{
 					pCaptureElement->OnMouseUp(nButton, fMouseX, fMouseY);
 				}
 				else
+
+				if(pElement)
 				{
-					GuiElement* pElement = Pick(fMouseX, fMouseY);
-					if(pElement)
-					{
-						pElement->OnMouseUp(nButton, fMouseX, fMouseY);
-					}
+					pElement->OnMouseUp(nButton, fMouseX, fMouseY);
 				}
 			}
 		}
+
+		// mouse moved
+		if(fDeltaX != 0.0f || fDeltaY != 0.0f)
+		//if(pInputManager->MouseMoved())
+		{
+			if(pCaptureElement)
+			{
+				pCaptureElement->OnMouseMove(fMouseX, fMouseY);
+			}
+			else
+
+			if(pElement)
+			{
+				pElement->OnMouseMove(fMouseX, fMouseY);
+			}
+		}
 	}
 }
 
@@ -142,7 +170,7 @@
 	//TODO: Begin batch
 	//kContext.BeginBatch();
 
-	if(bVisible)
+	if(nFlags & GuiElementFlag_Visible)
 	{
 		//TODO: Inside Render functions call kContext.AddToBatch(pTexture, kPosition, kDimensions, kColor)
 		GuiElement::Render(kContext, kCamera);
@@ -185,15 +213,33 @@
 }
 
 /*
+ * IsCursorAcquiredBy
+ */
+bool GuiInterface::IsCursorAcquiredBy(GuiElement* pElement) const
+{
+	return pDragElement == pElement;
+}
+
+/*
  * BeginDrag
  */
-void GuiInterface::BeginDrag(GuiElement* pSource)
+void GuiInterface::BeginDrag(GuiElement* pSource, uint32 nButton)
 {
+	//ASSERT(pDragElement == NULL);
+
+	pDragElement	= pSource;
+	nDragButton		= nButton;
 }
 
 /*
  * EndDrag
  */
-void GuiInterface::EndDrag()
+void GuiInterface::EndDrag(GuiElement* pTarget, float fX, float fY)
 {
+	if(pTarget)
+	{
+		pTarget->OnDrop(pDragElement, fX, fY);
+	}
+
+	pDragElement = NULL;
 }
--- a/LightClone/Source/GuiInterface.h	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/GuiInterface.h	Fri Sep 16 15:28:15 2011 -0700
@@ -31,6 +31,11 @@
 	GuiElement* pDragElement;
 
 	/*
+	 * nDragButton
+	 */
+	uint32 nDragButton;
+
+	/*
 	 * pCaptureElement
 	 */
 	GuiElement* pCaptureElement;
@@ -78,14 +83,19 @@
 	void ReleaseCursor();
 
 	/*
+	 * IsCursorAcquiredBy
+	 */
+	bool IsCursorAcquiredBy(GuiElement* pElement) const;
+
+	/*
 	 * BeginDrag
 	 */
-	void BeginDrag(GuiElement* pSource);
+	void BeginDrag(GuiElement* pSource, uint32 nButton);
 
 	/*
 	 * EndDrag
 	 */
-	void EndDrag();
+	void EndDrag(GuiElement* pTarget, float fX, float fY);
 
 private:
 
--- a/LightClone/Source/GuiLabel.cpp	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/GuiLabel.cpp	Fri Sep 16 15:28:15 2011 -0700
@@ -7,9 +7,8 @@
 /*
  * GuiLabel
  */
-GuiLabel::GuiLabel() : pResourceManager(NULL), pFont(NULL), nFlags(0), kColor(0xFFFFFFFF)
+GuiLabel::GuiLabel() : pResourceManager(NULL), pFont(NULL), nLabelFlags(0)
 {
-	memset(kLabel, 0, sizeof(kLabel));
 }
 
 /*
@@ -44,7 +43,7 @@
  */
 void GuiLabel::Render(RenderContext& kContext, Camera& kCamera)
 {
-	if(bVisible)
+	if(nFlags & GuiElementFlag_Visible)
 	{
 		if(pFont)
 		{
@@ -56,21 +55,20 @@
 			kRectangle.right	= (int32)kLocation.x;
 			kRectangle.bottom	= (int32)kLocation.y;
 
-			uint32 nLength = strlen(kLabel);
 			uint32 nFormat = 0;
 
-			if(nFlags & GuiLabelFlag_CenterX)
+			if(nLabelFlags & GuiLabelFlag_CenterX)
 			{
 				nFormat |= DT_CENTER;
 			}
 
-			if(nFlags & GuiLabelFlag_CenterY)
+			if(nLabelFlags & GuiLabelFlag_CenterY)
 			{
 				nFormat |= DT_VCENTER;
 			}
 
-			pFont->DrawTextA(NULL, kLabel, nLength, &kRectangle, nFormat | DT_CALCRECT, kColor);
-			pFont->DrawTextA(NULL, kLabel, nLength, &kRectangle, nFormat, kColor);
+			pFont->DrawTextA(NULL, kLabel, kLabel.Length(), &kRectangle, nFormat | DT_CALCRECT, kColor);
+			pFont->DrawTextA(NULL, kLabel, kLabel.Length(), &kRectangle, nFormat, kColor);
 		}
 
 		GuiElement::Render(kContext, kCamera);
@@ -96,30 +94,21 @@
  */
 ErrorCode GuiLabel::SetText(const char* pText)
 {
-	ErrorCode eCode = Error_Fail;
-
-	uint32 nLength = strlen(pText);
-	if(nLength < MaximumLabelLength)
-	{
-		strncpy_s(kLabel, pText, nLength);
-		eCode = Error_Success;
-	}
-
-	return eCode;
+	return kLabel = pText, Error_Success;
 }
 
 /*
- * SetFlags
+ * SetLabelFlag
  */
-ErrorCode GuiLabel::SetFlags(uint32 nValue)
+ErrorCode GuiLabel::SetLabelFlag(uint32 nValue)
 {
-	return nFlags |= nValue, Error_Success;
+	return nLabelFlags |= nValue, Error_Success;
 }
 
 /*
- * ClearFlags
+ * ClearLabelFlag
  */
-ErrorCode GuiLabel::ClearFlags(uint32 nValue)
+ErrorCode GuiLabel::ClearLabelFlag(uint32 nValue)
 {
-	return nFlags &= ~nValue, Error_Success;
+	return nLabelFlags &= ~nValue, Error_Success;
 }
\ No newline at end of file
--- a/LightClone/Source/GuiLabel.h	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/GuiLabel.h	Fri Sep 16 15:28:15 2011 -0700
@@ -7,6 +7,7 @@
 
 #include "Core.h"
 #include "GuiElement.h"
+#include "FixedString.h"
 
 /*
  * GuiLabelFlag
@@ -23,11 +24,6 @@
 class GuiLabel : public GuiElement
 {
 	/*
-	 * MaximumLabelLength
-	 */
-	static const uint32 MaximumLabelLength = 32;
-
-	/*
 	 * pResourceManager
 	 */
 	ResourceManager* pResourceManager;
@@ -40,17 +36,12 @@
 	/*
 	 * kLabel
 	 */
-	char kLabel[MaximumLabelLength];
+	FixedString<> kLabel;
 
 	/*
-	 * nFlags
+	 * nLabelFlags
 	 */
-	uint32 nFlags;
-
-	/*
-	 * kColor
-	 */
-	D3DCOLOR kColor;
+	uint32 nLabelFlags;
 
 public:
 
@@ -90,14 +81,14 @@
 	ErrorCode SetText(const char* pText);
 
 	/*
-	 * SetFlags
+	 * SetLabelFlag
 	 */
-	ErrorCode SetFlags(uint32 nFlags);
+	ErrorCode SetLabelFlag(uint32 nFlag);
 
 	/*
-	 * ClearFlags
+	 * ClearLabelFlag
 	 */
-	ErrorCode ClearFlags(uint32 nFlags);
+	ErrorCode ClearLabelFlag(uint32 nFlag);
 };
 
 #endif //__GUILABEL_H__
--- a/LightClone/Source/HashMap.h	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/HashMap.h	Fri Sep 16 15:28:15 2011 -0700
@@ -6,6 +6,7 @@
 #define __HASHMAP_H__
 
 #include "Types.h"
+#include "HashMapIterator.h"
 
 /*
  * DefaultHash
@@ -56,6 +57,25 @@
 		}
 	};
 
+public:
+
+	/*
+	 * KeyType
+	 */
+	typedef Key KeyType;
+
+	/*
+	 * ValueType
+	 */
+	typedef Value ValueType;
+
+	/*
+	 * Iterator
+	 */
+	typedef HashMapIterator<HashMap<Key, Value, HashFunction, Size>, Value> Iterator;
+
+private:
+
 	/*
 	 * pTable
 	 */
@@ -71,7 +91,7 @@
 	/*
 	 * HashMap
 	 */
-	HashMap() //: kHash()
+	HashMap()
 	{
 		for(uint32 i = 0; i < Size; ++i)
 		{
@@ -121,6 +141,16 @@
 		return NULL;
 	}
 
+	/*
+	 * Begin
+	 */
+	Iterator Begin();
+
+	/*
+	 * End
+	 */
+	Iterator End();
+
 private:
 
 	/*
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LightClone/Source/HashMapIterator.h	Fri Sep 16 15:28:15 2011 -0700
@@ -0,0 +1,94 @@
+/*
+ * HashMapIterator
+ */
+
+#ifndef __HASHMAPITERATOR_H__
+#define __HASHMAPITERATOR_H__
+
+#include "Types.h"
+
+/*
+ * HashMapIterator
+ */
+template<typename Map, typename Value>
+class HashMapIterator
+{
+	/*
+	 * pMap
+	 */
+	Map* pMap;
+
+	/*
+	 * nSize
+	 */
+	uint32 nSize;
+
+	/*
+	 * pNode
+	 */
+	typename Map::Node* pNode;
+
+	/*
+	 * nSlot
+	 */
+	uint32 nSlot;
+
+public:
+
+	/*
+	 * HashMapIterator
+	 */
+	HashMapIterator(Map* pInstance, uint32 nInstanceSize) : pMap(pInstance), nSize(nInstanceSize), pNode(NULL), nSlot(0)
+	{
+	}
+
+	/*
+	 * HashMapIterator
+	 */
+	HashMapIterator(Map* pInstance, uint32 nInstanceSize, uint32 nStart) : pMap(pInstance), nSize(nInstanceSize), pNode(NULL), nSlot(nStart)
+	{
+		//pNode = pInstance->pTable[nSlot];
+	}
+
+	/*
+	 * operator ++
+	 */
+	HashMapIterator& operator ++()
+	{
+		return *this;
+	}
+
+	/*
+	 * operator ++
+	 */
+	HashMapIterator& operator ++(int)
+	{
+		return *this;
+	}
+
+	/*
+	 * operator *
+	 */
+	Value operator *()
+	{
+		return pNode ? pNode->kValue : Value();
+	}
+
+	/*
+	 * operator ==
+	 */
+	bool operator ==(HashMapIterator& kOther)
+	{
+		return nSlot == kOther.nSlot && pNode == kOther.pNode;
+	}
+
+	/*
+	 * operator !=
+	 */
+	bool operator !=(HashMapIterator& kOther)
+	{
+		return nSlot != kOther.nSlot || pNode != kOther.pNode;
+	}
+};
+
+#endif //__HASHMAPITERATOR_H__
--- a/LightClone/Source/InputManager.cpp	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/InputManager.cpp	Fri Sep 16 15:28:15 2011 -0700
@@ -270,6 +270,22 @@
 }
 
 /*
+ * IsButtonPressed
+ */
+bool InputManager::IsButtonPressed(uint32 nButton) const
+{
+	return ((kCurrentMouseState.rgbButtons[nButton] & 0x80) != 0) && ((kPreviousMouseState.rgbButtons[nButton] & 0x80) == 0);
+}
+
+/*
+ * IsButtonReleased
+ */
+bool InputManager::IsButtonReleased(uint32 nButton) const
+{
+	return ((kCurrentMouseState.rgbButtons[nButton] & 0x80) == 0) && ((kPreviousMouseState.rgbButtons[nButton] & 0x80) == 0);
+}
+
+/*
  * GetMouseX
  */
 float InputManager::GetMouseX() const
@@ -283,4 +299,20 @@
 float InputManager::GetMouseY() const
 {
 	return fMouseY;
+}
+
+/*
+ * GetMouseDeltaX
+ */
+float InputManager::GetMouseDeltaX() const
+{
+	return (float)kCurrentMouseState.lX;
+}
+
+/*
+ * GetMouseDeltaY
+ */
+float InputManager::GetMouseDeltaY() const
+{
+	return (float)kCurrentMouseState.lY;
 }
\ No newline at end of file
--- a/LightClone/Source/InputManager.h	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/InputManager.h	Fri Sep 16 15:28:15 2011 -0700
@@ -35,6 +35,7 @@
 	MouseButton_Left,
 	MouseButton_Right,
 	MouseButton_Middle,
+	MouseButton_Count,
 };
 
 /*
@@ -193,6 +194,16 @@
 	bool WasButtonDown(uint32 nButton) const;
 
 	/*
+	 * IsButtonPressed
+	 */
+	bool IsButtonPressed(uint32 nButton) const;
+
+	/*
+	 * IsButtonReleased
+	 */
+	bool IsButtonReleased(uint32 nButton) const;
+
+	/*
 	 * GetMouseX
 	 */
 	float GetMouseX() const;
@@ -201,6 +212,16 @@
 	 * GetMouseY
 	 */
 	float GetMouseY() const;
+
+	/*
+	 * GetMouseDeltaX
+	 */
+	float GetMouseDeltaX() const;
+
+	/*
+	 * GetMouseDeltaY
+	 */
+	float GetMouseDeltaY() const;
 };
 
 #endif //__INPUTMANAGER_H__
--- a/LightClone/Source/ResourceManager.cpp	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/ResourceManager.cpp	Fri Sep 16 15:28:15 2011 -0700
@@ -5,6 +5,41 @@
 #include "ResourceManager.h"
 
 /*
+ * CreateTextureHelper
+ */
+ErrorCode CreateTextureHelper(GraphicsDevice* pDevice, const char* pName, IDirect3DTexture9** pTexture)
+{
+	const uint32 nSizeX		= D3DX_DEFAULT_NONPOW2;
+	const uint32 nSizeY		= D3DX_DEFAULT_NONPOW2;
+	const uint32 nFilter	= D3DX_DEFAULT;
+	const uint32 nFilterMip	= D3DX_DEFAULT;
+
+	return SUCCEEDED(D3DXCreateTextureFromFileExA(*pDevice, pName, nSizeX, nSizeY, 0, 0, D3DFMT_FROM_FILE, D3DPOOL_MANAGED, nFilter, nFilterMip, 0, NULL, NULL, pTexture)) ? Error_Success : Error_Fail;
+}
+
+/*
+ * CreateEffectHelper
+ */
+ErrorCode CreateEffectHelper(GraphicsDevice* pDevice, const char* pName, ID3DXEffect** pEffect)
+{
+	ID3DXBuffer* pBuffer = NULL;
+	return SUCCEEDED(D3DXCreateEffectFromFileA(*pDevice, pName, NULL, NULL, 0, NULL, pEffect, &pBuffer)) ? Error_Success : Error_Fail;
+}
+
+/*
+ * CreateFontHelper
+ */
+ErrorCode CreateFontHelper(GraphicsDevice* pDevice, const char* pName, uint32 nSize, uint32 nWeight, ID3DXFont** pFont)
+{
+	const uint32 nCharset	= DEFAULT_CHARSET;
+	const uint32 nPrecision	= OUT_DEFAULT_PRECIS;
+	const uint32 nQuality	= DEFAULT_QUALITY;
+	const uint32 nPitch		= DEFAULT_PITCH | FF_DONTCARE;
+
+	return SUCCEEDED(D3DXCreateFontA(*pDevice, nSize, 0, nWeight, 1, FALSE, nCharset, nPrecision, nQuality, nPitch, pName, pFont)) ? Error_Success : Error_Fail;
+}
+
+/*
  * ResourceManager
  */
 ResourceManager::ResourceManager()
@@ -24,6 +59,9 @@
  */
 void ResourceManager::Terminate()
 {
+	//TODO: Iterate over each cache and release resources
+
+
 	pGraphicsDevice = NULL;
 }
 
@@ -36,16 +74,25 @@
 
 	if(pGraphicsDevice)
 	{
-		const uint32 nSizeX		= D3DX_DEFAULT_NONPOW2;
-		const uint32 nSizeY		= D3DX_DEFAULT_NONPOW2;
-		const uint32 nFilter	= D3DX_DEFAULT;
-		const uint32 nFilterMip	= D3DX_DEFAULT;
-
-		HRESULT hResult = D3DXCreateTextureFromFileExA(*pGraphicsDevice, pName, nSizeX, nSizeY, 0, 0, D3DFMT_FROM_FILE, D3DPOOL_MANAGED, nFilter, nFilterMip, 0, NULL, NULL, pTexture);
-		if(SUCCEEDED(hResult))
+		IDirect3DTexture9** pInstance = kTextureCache.Find(ResourcePath(pName));
+		if(!pInstance)
+		{
+			pInstance = kTextureCache.Add(ResourcePath(pName));
+			if(pInstance)
+			{
+				eCode = CreateTextureHelper(pGraphicsDevice, pName, pInstance);
+			}
+		}
+		else
 		{
 			eCode = Error_Success;
 		}
+
+		if(eCode == Error_Success)
+		{
+			if(pTexture)
+				*pTexture = *pInstance;
+		}
 	}
 
 	return eCode;
@@ -60,13 +107,58 @@
 
 	if(pGraphicsDevice)
 	{
-		ID3DXBuffer* pBuffer = NULL;
-
-		HRESULT hResult = D3DXCreateEffectFromFileA(*pGraphicsDevice, pName, NULL, NULL, 0, NULL, pEffect, &pBuffer);
-		if(SUCCEEDED(hResult))
+		ID3DXEffect** pInstance = kEffectCache.Find(ResourcePath(pName));
+		if(!pInstance)
+		{
+			pInstance = kEffectCache.Add(ResourcePath(pName));
+			if(pInstance)
+			{
+				eCode = CreateEffectHelper(pGraphicsDevice, pName, pInstance);
+			}
+		}
+		else
 		{
 			eCode = Error_Success;
 		}
+
+		if(eCode == Error_Success)
+		{
+			if(pEffect)
+				*pEffect = *pInstance;
+		}
+	}
+
+	return eCode;
+}
+
+/*
+ * CreateFontFromName
+ */
+ErrorCode ResourceManager::CreateFontFromName(const char* pName, uint32 nSize, uint32 nWeight, ID3DXFont** pFont)
+{
+	ErrorCode eCode = Error_Fail;
+
+	if(pGraphicsDevice)
+	{
+		ID3DXFont** pInstance = kFontCache.Find(ResourcePath(pName));
+		if(!pInstance)
+		{
+			pInstance = kFontCache.Add(ResourcePath(pName));
+			if(pInstance)
+			{
+				eCode = CreateFontHelper(pGraphicsDevice, pName, nSize, nWeight, pInstance);
+			}
+		}
+		else
+		{
+			eCode = Error_Success;
+		}
+
+		if(eCode == Error_Success)
+		{
+			if(pFont)
+				*pFont = *pInstance;
+		}
 	}
 
 	return eCode;
@@ -81,8 +173,7 @@
 
 	if(pGraphicsDevice)
 	{
-		//HRESULT hResult = ((IDirect3DDevice9*)*pGraphicsDevice)->CreateVertexBuffer(nSize, nUsage, 0, (D3DPOOL)nPool, pBuffer, NULL);
-		HRESULT hResult = static_cast<IDirect3DDevice9*>(*pGraphicsDevice)->CreateVertexBuffer(nSize, nUsage, 0, (D3DPOOL)nPool, pBuffer, NULL);
+		HRESULT hResult = ((IDirect3DDevice9*)*pGraphicsDevice)->CreateVertexBuffer(nSize, nUsage, 0, (D3DPOOL)nPool, pBuffer, NULL);
 		if(SUCCEEDED(hResult))
 		{
 			eCode = Error_Success;
@@ -91,22 +182,3 @@
 
 	return eCode;
 }
-
-/*
- * CreateFontFromName
- */
-ErrorCode ResourceManager::CreateFontFromName(const char* pName, uint32 nSize, uint32 nWeight, ID3DXFont** pFont)
-{
-	ErrorCode eCode = Error_Fail;
-
-	if(pGraphicsDevice)
-	{
-		HRESULT hResult = D3DXCreateFontA(*pGraphicsDevice, nSize, 0, nWeight, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, pName, pFont);
-		if(SUCCEEDED(hResult))
-		{
-			eCode = Error_Success;
-		}
-	}
-
-	return eCode;
-}
--- a/LightClone/Source/ResourceManager.h	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/ResourceManager.h	Fri Sep 16 15:28:15 2011 -0700
@@ -7,6 +7,26 @@
 
 #include "Core.h"
 #include "GraphicsDevice.h"
+#include "FixedString.h"
+#include "HashMap.h"
+
+/*
+ * ResourceType
+ */
+enum
+{
+	ResourceType_Texture,
+	ResourceType_Effect,
+	ResourceType_Font,
+	ResourceType_VertexBuffer,
+	ResourceType_IndexBuffer,
+};
+
+/*
+ * ResourcePath
+ *	TODO: Wasting memory
+ */
+typedef FixedString<> ResourcePath;
 
 /*
  * ResourceManager
@@ -18,6 +38,21 @@
 	 */
 	GraphicsDevice* pGraphicsDevice;
 
+	/*
+	 * kTextureCache
+	 */
+	HashMap<ResourcePath, IDirect3DTexture9*, ResourcePath::Hash> kTextureCache;
+
+	/*
+	 * kEffectCache
+	 */
+	HashMap<ResourcePath, ID3DXEffect*, ResourcePath::Hash> kEffectCache;
+
+	/*
+	 * kFontCache
+	 */
+	HashMap<ResourcePath, ID3DXFont*, ResourcePath::Hash> kFontCache;
+
 public:
 
 	/*
@@ -46,14 +81,14 @@
 	ErrorCode CreateEffectFromFile(const char* pName, ID3DXEffect** pEffect);
 
 	/*
+	 * CreateFontFromName
+	 */
+	ErrorCode CreateFontFromName(const char* pName, uint32 nSize, uint32 nWeight, ID3DXFont** pFont);
+
+	/*
 	 * CreateVertexBuffer
 	 */
 	ErrorCode CreateVertexBuffer(uint32 nSize, uint32 nUsage, uint32 nPool, IDirect3DVertexBuffer9** pBuffer);
-
-	/*
-	 * CreateFontFromName
-	 */
-	ErrorCode CreateFontFromName(const char* pName, uint32 nSize, uint32 nWeight, ID3DXFont** pFont);
 };
 
 #endif //__RESOURCEMANAGER_H__
--- a/LightClone/Source/World.cpp	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/Source/World.cpp	Fri Sep 16 15:28:15 2011 -0700
@@ -322,7 +322,7 @@
 
 		pLevelDialog = new GuiImage();
 		pLevelDialog->Initialize(pResourceManager);
-		pLevelDialog->SetVisible(false);
+		pLevelDialog->ClearFlag(GuiElementFlag_Visible);
 		pLevelDialog->SetTexture("Data\\Textures\\Dialog0.tga", true);
 		pLevelDialog->SetPosition(0.5f * (ScreenSizeX - pLevelDialog->GetWidth()), 0.5f * (ScreenSizeY - pLevelDialog->GetHeight()));
 
@@ -350,7 +350,7 @@
 
 		pGameDialog = new GuiImage();
 		pGameDialog->Initialize(pResourceManager);
-		pGameDialog->SetVisible(false);
+		pGameDialog->ClearFlag(GuiElementFlag_Visible);
 		pGameDialog->SetTexture("Data\\Textures\\Dialog0.tga", true);
 		pGameDialog->SetPosition(0.5f * (ScreenSizeX - pGameDialog->GetWidth()), 0.5f * (ScreenSizeY - pGameDialog->GetHeight()));
 		//pGameDialog->Add(pGameDialogOk);
--- a/LightClone/ToDo.txt	Fri Sep 16 13:11:35 2011 -0700
+++ b/LightClone/ToDo.txt	Fri Sep 16 15:28:15 2011 -0700
@@ -5,12 +5,8 @@
 5.	Pause menu
 6.	Robot model & texture
 7.	Implement confirm exit dialog
-8. Help interface
-9. Add button to clear code panes
+8.	Help interface
+9.	Add button to clear code panes
 10. Implement drag and drop
-	a.	Implement mouse capturing
-	b.	Add drag and drop interface to GuiInterface and move handling into subclasses
-11. Add flags to gui elements (picking, visibility)
-12. Implement caching in the resource manager
-13. Implement gui batching
-14.	Add GuiInterface reference to GuiElement
\ No newline at end of file
+	a.	Add drag and drop interface to GuiInterface and move handling into subclasses
+11. Implement gui batching
\ No newline at end of file