瀏覽代碼

Moved sprite offset/clip rect to fillBuffer

Marko Pintera 12 年之前
父節點
當前提交
9bd30df1a8

+ 2 - 0
BansheeEngine/Include/BsGUIButton.h

@@ -57,5 +57,7 @@ namespace BansheeEngine
 		GUIButton(GUIWidget& parent, const GUIElementStyle* style, const CM::WString& text, const GUILayoutOptions& layoutOptions);
 		GUIButton(GUIWidget& parent, const GUIElementStyle* style, const CM::WString& text, const GUILayoutOptions& layoutOptions);
 
 
 		virtual bool mouseEvent(const GUIMouseEvent& ev);
 		virtual bool mouseEvent(const GUIMouseEvent& ev);
+		CM::Rect getTextBounds() const;
+		CM::Rect getTextClipRect() const;
 	};
 	};
 }
 }

+ 7 - 0
BansheeEngine/Include/BsGUIInputBox.h

@@ -80,6 +80,8 @@ namespace BansheeEngine
 		virtual bool commandEvent(const GUICommandEvent& ev);
 		virtual bool commandEvent(const GUICommandEvent& ev);
 
 
 		Sprite* renderElemToSprite(CM::UINT32 renderElemIdx, CM::UINT32& localRenderElemIdx) const;
 		Sprite* renderElemToSprite(CM::UINT32 renderElemIdx, CM::UINT32& localRenderElemIdx) const;
+		CM::Int2 renderElemToOffset(CM::UINT32 renderElemIdx) const;
+		CM::Rect renderElemToClipRect(CM::UINT32 renderElemIdx) const;
 
 
 		void showCaret();
 		void showCaret();
 		void hideCaret();
 		void hideCaret();
@@ -107,6 +109,11 @@ namespace BansheeEngine
 		bool isNewlineChar(CM::UINT32 charIdx) const;
 		bool isNewlineChar(CM::UINT32 charIdx) const;
 		CM::Vector<CM::Rect>::type getSelectionRects() const;
 		CM::Vector<CM::Rect>::type getSelectionRects() const;
 
 
+		CM::Int2 getSelectionSpriteOffset(CM::UINT32 spriteIdx) const;
+		CM::Rect getSelectionSpriteClipRect(CM::UINT32 spriteIdx) const;
+
+		CM::Int2 getTextOffset() const;
+		CM::Rect getTextClipRect() const;
 		CM::Rect getTextBounds() const;
 		CM::Rect getTextBounds() const;
 		TEXT_SPRITE_DESC getTextDesc() const;
 		TEXT_SPRITE_DESC getTextDesc() const;
 	};
 	};

+ 7 - 2
BansheeEngine/Include/BsGUIInputCaret.h

@@ -14,11 +14,14 @@ namespace BansheeEngine
 	class BS_EXPORT GUIInputCaret
 	class BS_EXPORT GUIInputCaret
 	{
 	{
 	public:
 	public:
-		GUIInputCaret(const TEXT_SPRITE_DESC& textDesc);
+		GUIInputCaret(const TEXT_SPRITE_DESC& textDesc, const CM::Int2& offset, const CM::Int2 clipOffset);
 		~GUIInputCaret();
 		~GUIInputCaret();
 
 
 		ImageSprite* getSprite() const { return mCaretSprite; }
 		ImageSprite* getSprite() const { return mCaretSprite; }
-		void updateText(const TEXT_SPRITE_DESC& textDesc);
+		CM::Int2 getSpriteOffset() const;
+		CM::Rect getSpriteClipRect() const;
+
+		void updateText(const TEXT_SPRITE_DESC& textDesc, const CM::Int2& offset, const CM::Int2 clipOffset);
 		void updateSprite(const CM::Int2& offset);
 		void updateSprite(const CM::Int2& offset);
 
 
 		void moveCaretToStart();
 		void moveCaretToStart();
@@ -44,5 +47,7 @@ namespace BansheeEngine
 		ImageSprite* mCaretSprite;
 		ImageSprite* mCaretSprite;
 
 
 		TEXT_SPRITE_DESC mTextDesc;
 		TEXT_SPRITE_DESC mTextDesc;
+		CM::Int2 mTextOffset;
+		CM::Int2 mClipOffset;
 	};
 	};
 }
 }

+ 2 - 0
BansheeEngine/Include/BsGUIToggle.h

@@ -58,5 +58,7 @@ namespace BansheeEngine
 		GUIToggle(GUIWidget& parent, const GUIElementStyle* style, const CM::WString& text, const GUILayoutOptions& layoutOptions);
 		GUIToggle(GUIWidget& parent, const GUIElementStyle* style, const CM::WString& text, const GUILayoutOptions& layoutOptions);
 
 
 		virtual bool mouseEvent(const GUIMouseEvent& ev);
 		virtual bool mouseEvent(const GUIMouseEvent& ev);
+		CM::Rect getTextBounds() const;
+		CM::Rect getTextClipRect() const;
 	};
 	};
 }
 }

+ 0 - 2
BansheeEngine/Include/BsImageSprite.h

@@ -13,10 +13,8 @@ namespace BansheeEngine
 			borderTop(0), borderBottom(0), uvScale(1.0f, 1.0f), uvOffset(0.0f, 0.0f)
 			borderTop(0), borderBottom(0), uvScale(1.0f, 1.0f), uvOffset(0.0f, 0.0f)
 		{ }
 		{ }
 
 
-		CM::Int2 offset;
 		CM::UINT32 width;
 		CM::UINT32 width;
 		CM::UINT32 height;
 		CM::UINT32 height;
-		CM::Rect clipRect;
 		SpriteAnchor anchor;
 		SpriteAnchor anchor;
 		CM::Vector2 uvScale;
 		CM::Vector2 uvScale;
 		CM::Vector2 uvOffset;
 		CM::Vector2 uvOffset;

+ 2 - 2
BansheeEngine/Include/BsSprite.h

@@ -38,7 +38,7 @@ namespace BansheeEngine
 		Sprite();
 		Sprite();
 		virtual ~Sprite();
 		virtual ~Sprite();
 
 
-		const CM::Rect& getBounds() const { return mBounds; }
+		CM::Rect getBounds(const CM::Int2& offset, const CM::Rect& clipRect) const;
 
 
 		/**
 		/**
 		 * @brief	Returns the number of separate render elements in the sprite. Normally this is one, but some sprites
 		 * @brief	Returns the number of separate render elements in the sprite. Normally this is one, but some sprites
@@ -89,7 +89,7 @@ namespace BansheeEngine
 		 * @param	renderElementIdx	Zero-based index of the render element.
 		 * @param	renderElementIdx	Zero-based index of the render element.
 		 */
 		 */
 		CM::UINT32 fillBuffer(CM::UINT8* vertices, CM::UINT8* uv, CM::UINT32* indices, CM::UINT32 startingQuad, CM::UINT32 maxNumQuads, 
 		CM::UINT32 fillBuffer(CM::UINT8* vertices, CM::UINT8* uv, CM::UINT32* indices, CM::UINT32 startingQuad, CM::UINT32 maxNumQuads, 
-			CM::UINT32 vertexStride, CM::UINT32 indexStride, CM::UINT32 renderElementIdx) const;
+			CM::UINT32 vertexStride, CM::UINT32 indexStride, CM::UINT32 renderElementIdx, const CM::Int2& offset, const CM::Rect& clipRect) const;
 
 
 		static void clipToRect(CM::Vector2* vertices, CM::Vector2* uv, CM::UINT32 numQuads, const CM::Rect& clipRect);
 		static void clipToRect(CM::Vector2* vertices, CM::Vector2* uv, CM::UINT32 numQuads, const CM::Rect& clipRect);
 		static CM::Int2 getAnchorOffset(SpriteAnchor anchor, CM::UINT32 width, CM::UINT32 height);
 		static CM::Int2 getAnchorOffset(SpriteAnchor anchor, CM::UINT32 width, CM::UINT32 height);

+ 0 - 2
BansheeEngine/Include/BsTextSprite.h

@@ -23,10 +23,8 @@ namespace BansheeEngine
 			horzAlign(THA_Left), vertAlign(TVA_Top), wordWrap(false)
 			horzAlign(THA_Left), vertAlign(TVA_Top), wordWrap(false)
 		{ }
 		{ }
 
 
-		CM::Int2 offset;
 		CM::UINT32 width;
 		CM::UINT32 width;
 		CM::UINT32 height;
 		CM::UINT32 height;
-		CM::Rect clipRect;
 		SpriteAnchor anchor;
 		SpriteAnchor anchor;
 
 
 		CM::WString text;
 		CM::WString text;

+ 37 - 17
BansheeEngine/Source/BsGUIButton.cpp

@@ -95,13 +95,11 @@ namespace BansheeEngine
 
 
 	void GUIButton::updateRenderElementsInternal()
 	void GUIButton::updateRenderElementsInternal()
 	{		
 	{		
-		mImageDesc.offset = mOffset;
 		mImageDesc.width = mWidth;
 		mImageDesc.width = mWidth;
 		mImageDesc.height = mHeight;
 		mImageDesc.height = mHeight;
-		mImageDesc.clipRect = mClipRect;
 
 
 		mImageSprite->update(mImageDesc);
 		mImageSprite->update(mImageDesc);
-		mBounds = mImageSprite->getBounds();
+		mBounds = mImageSprite->getBounds(mOffset, mClipRect);
 		mNumImageRenderElements = mImageSprite->getNumRenderElements();
 		mNumImageRenderElements = mImageSprite->getNumRenderElements();
 
 
 		TEXT_SPRITE_DESC textDesc;
 		TEXT_SPRITE_DESC textDesc;
@@ -109,19 +107,10 @@ namespace BansheeEngine
 		textDesc.font = mStyle->font;
 		textDesc.font = mStyle->font;
 		textDesc.fontSize = mStyle->fontSize;
 		textDesc.fontSize = mStyle->fontSize;
 
 
-		Rect contentBounds = mBounds;
+		Rect textBounds = getTextBounds();
 
 
-		contentBounds.x += mStyle->margins.left + mStyle->contentOffset.left;
-		contentBounds.y += mStyle->margins.top + mStyle->contentOffset.top;
-		contentBounds.width = (UINT32)std::max(0, (INT32)contentBounds.width - 
-			(INT32)(mStyle->margins.left + mStyle->margins.right + mStyle->contentOffset.left + mStyle->contentOffset.right));
-		contentBounds.height = (UINT32)std::max(0, (INT32)contentBounds.height - 
-			(INT32)(mStyle->margins.top + mStyle->margins.bottom + mStyle->contentOffset.top + mStyle->contentOffset.bottom));
-
-		textDesc.offset = Int2(contentBounds.x, contentBounds.y);
-		textDesc.width = contentBounds.width;
-		textDesc.height = contentBounds.height;
-		textDesc.clipRect = Rect(0, 0, textDesc.width, textDesc.height);
+		textDesc.width = textBounds.width;
+		textDesc.height = textBounds.height;
 		textDesc.horzAlign = mStyle->textHorzAlign;
 		textDesc.horzAlign = mStyle->textHorzAlign;
 		textDesc.vertAlign = mStyle->textVertAlign;
 		textDesc.vertAlign = mStyle->textVertAlign;
 
 
@@ -160,9 +149,19 @@ namespace BansheeEngine
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 	{
 	{
 		if(renderElementIdx >= mNumImageRenderElements)
 		if(renderElementIdx >= mNumImageRenderElements)
-			mTextSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, mNumImageRenderElements - renderElementIdx);
+		{
+			Rect textBounds = getTextBounds();
+			Int2 offset(textBounds.x, textBounds.y);
+			Rect textClipRect = getTextClipRect();
+
+			mTextSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, 
+			vertexStride, indexStride, mNumImageRenderElements - renderElementIdx, offset, textClipRect);
+		}
 		else
 		else
-			mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx);
+		{
+			mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, 
+			vertexStride, indexStride, renderElementIdx, mOffset, mClipRect);
+		}
 	}
 	}
 
 
 	bool GUIButton::mouseEvent(const GUIMouseEvent& ev)
 	bool GUIButton::mouseEvent(const GUIMouseEvent& ev)
@@ -198,4 +197,25 @@ namespace BansheeEngine
 		
 		
 		return false;
 		return false;
 	}
 	}
+
+	Rect GUIButton::getTextBounds() const
+	{
+		Rect textBounds = mBounds;
+
+		textBounds.x += mStyle->margins.left + mStyle->contentOffset.left;
+		textBounds.y += mStyle->margins.top + mStyle->contentOffset.top;
+		textBounds.width = (UINT32)std::max(0, (INT32)textBounds.width - 
+			(INT32)(mStyle->margins.left + mStyle->margins.right + mStyle->contentOffset.left + mStyle->contentOffset.right));
+		textBounds.height = (UINT32)std::max(0, (INT32)textBounds.height - 
+			(INT32)(mStyle->margins.top + mStyle->margins.bottom + mStyle->contentOffset.top + mStyle->contentOffset.bottom));
+
+		return textBounds;
+	}
+
+	Rect GUIButton::getTextClipRect() const
+	{
+		Rect textBounds = getTextBounds();
+
+		return Rect(0, 0, textBounds.width, textBounds.height);
+	}
 }
 }

+ 127 - 79
BansheeEngine/Source/BsGUIInputBox.cpp

@@ -31,7 +31,7 @@ namespace BansheeEngine
 	{
 	{
 		mImageSprite = cm_new<ImageSprite, PoolAlloc>();
 		mImageSprite = cm_new<ImageSprite, PoolAlloc>();
 		mTextSprite = cm_new<TextSprite, PoolAlloc>();
 		mTextSprite = cm_new<TextSprite, PoolAlloc>();
-		mInputCaret = cm_new<GUIInputCaret, PoolAlloc>(getTextDesc());
+		mInputCaret = cm_new<GUIInputCaret, PoolAlloc>(getTextDesc(), getTextOffset(), mTextOffset);
 
 
 		mImageDesc.texture = mStyle->normal.texture;
 		mImageDesc.texture = mStyle->normal.texture;
 
 
@@ -117,20 +117,18 @@ namespace BansheeEngine
 
 
 	void GUIInputBox::updateRenderElementsInternal()
 	void GUIInputBox::updateRenderElementsInternal()
 	{		
 	{		
-		mImageDesc.offset = mOffset;
 		mImageDesc.width = mWidth;
 		mImageDesc.width = mWidth;
 		mImageDesc.height = mHeight;
 		mImageDesc.height = mHeight;
-		mImageDesc.clipRect = mClipRect;
 
 
 		mImageSprite->update(mImageDesc);
 		mImageSprite->update(mImageDesc);
-		mBounds = mImageSprite->getBounds();
+		mBounds = mImageSprite->getBounds(mOffset, mClipRect);
 
 
 		TEXT_SPRITE_DESC textDesc = getTextDesc();
 		TEXT_SPRITE_DESC textDesc = getTextDesc();
 		mTextSprite->update(textDesc);
 		mTextSprite->update(textDesc);
 
 
 		if(mCaretShown && GUIManager::instance().getCaretBlinkState())
 		if(mCaretShown && GUIManager::instance().getCaretBlinkState())
 		{
 		{
-			mInputCaret->updateText(textDesc);
+			mInputCaret->updateText(textDesc, getTextOffset(), mTextOffset);
 			mInputCaret->updateSprite(mTextOffset);
 			mInputCaret->updateSprite(mTextOffset);
 		}
 		}
 
 
@@ -160,11 +158,8 @@ namespace BansheeEngine
 			for(auto& sprite : mSelectionSprites)
 			for(auto& sprite : mSelectionSprites)
 			{
 			{
 				IMAGE_SPRITE_DESC desc;
 				IMAGE_SPRITE_DESC desc;
-				desc.offset = Int2(selectionRects[idx].x, selectionRects[idx].y);
 				desc.width = selectionRects[idx].width;
 				desc.width = selectionRects[idx].width;
 				desc.height = selectionRects[idx].height;
 				desc.height = selectionRects[idx].height;
-				desc.clipRect = Rect(getTextBounds().x - selectionRects[idx].x, 
-					getTextBounds().y - selectionRects[idx].y, textDesc.width, textDesc.height);
 				desc.texture = GUIManager::instance().getTextSelectionTexture();
 				desc.texture = GUIManager::instance().getTextSelectionTexture();
 
 
 				sprite->update(desc);
 				sprite->update(desc);
@@ -223,6 +218,86 @@ namespace BansheeEngine
 		return nullptr;
 		return nullptr;
 	}
 	}
 
 
+	Int2 GUIInputBox::renderElemToOffset(UINT32 renderElemIdx) const
+	{
+		UINT32 oldNumElements = 0;
+		UINT32 newNumElements = oldNumElements + mTextSprite->getNumRenderElements();
+		if(renderElemIdx < newNumElements)
+			return getTextOffset();
+
+		oldNumElements = newNumElements;
+		newNumElements += mImageSprite->getNumRenderElements();
+
+		if(renderElemIdx < newNumElements)
+			return mOffset;
+
+		if(mCaretShown && GUIManager::instance().getCaretBlinkState())
+		{
+			oldNumElements = newNumElements;
+			newNumElements += mInputCaret->getSprite()->getNumRenderElements();
+
+			if(renderElemIdx < newNumElements)
+				return mInputCaret->getSpriteOffset();
+		}
+
+		if(mSelectionShown)
+		{
+			UINT32 spriteIdx = 0;
+			for(auto& selectionSprite : mSelectionSprites)
+			{
+				oldNumElements = newNumElements;
+				newNumElements += selectionSprite->getNumRenderElements();
+
+				if(renderElemIdx < newNumElements)
+					return getSelectionSpriteOffset(spriteIdx);
+
+				spriteIdx++;
+			}
+		}
+
+		return Int2();
+	}
+
+	Rect GUIInputBox::renderElemToClipRect(UINT32 renderElemIdx) const
+	{
+		UINT32 oldNumElements = 0;
+		UINT32 newNumElements = oldNumElements + mTextSprite->getNumRenderElements();
+		if(renderElemIdx < newNumElements)
+			return getTextClipRect();
+
+		oldNumElements = newNumElements;
+		newNumElements += mImageSprite->getNumRenderElements();
+
+		if(renderElemIdx < newNumElements)
+			return mClipRect;
+
+		if(mCaretShown && GUIManager::instance().getCaretBlinkState())
+		{
+			oldNumElements = newNumElements;
+			newNumElements += mInputCaret->getSprite()->getNumRenderElements();
+
+			if(renderElemIdx < newNumElements)
+				return mInputCaret->getSpriteClipRect();
+		}
+
+		if(mSelectionShown)
+		{
+			UINT32 spriteIdx = 0;
+			for(auto& selectionSprite : mSelectionSprites)
+			{
+				oldNumElements = newNumElements;
+				newNumElements += selectionSprite->getNumRenderElements();
+
+				if(renderElemIdx < newNumElements)
+					return getSelectionSpriteClipRect(spriteIdx);
+
+				spriteIdx++;
+			}
+		}
+
+		return Rect();
+	}
+
 	UINT32 GUIInputBox::_getOptimalWidth() const
 	UINT32 GUIInputBox::_getOptimalWidth() const
 	{
 	{
 		if(mImageDesc.texture != nullptr)
 		if(mImageDesc.texture != nullptr)
@@ -263,8 +338,10 @@ namespace BansheeEngine
 	{
 	{
 		UINT32 localRenderElementIdx;
 		UINT32 localRenderElementIdx;
 		Sprite* sprite = renderElemToSprite(renderElementIdx, localRenderElementIdx);
 		Sprite* sprite = renderElemToSprite(renderElementIdx, localRenderElementIdx);
+		Int2 offset = renderElemToOffset(renderElementIdx);
+		Rect clipRect = renderElemToClipRect(renderElementIdx);
 
 
-		sprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, localRenderElementIdx);
+		sprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, localRenderElementIdx, offset, clipRect);
 	}
 	}
 
 
 	bool GUIInputBox::mouseEvent(const GUIMouseEvent& ev)
 	bool GUIInputBox::mouseEvent(const GUIMouseEvent& ev)
@@ -374,7 +451,7 @@ namespace BansheeEngine
 					{
 					{
 						UINT32 selStart = getSelectionStart();
 						UINT32 selStart = getSelectionStart();
 						mText.erase(mText.begin() + selStart, mText.begin() + getSelectionEnd());
 						mText.erase(mText.begin() + selStart, mText.begin() + getSelectionEnd());
-						mInputCaret->updateText(getTextDesc());
+						mInputCaret->updateText(getTextDesc(), getTextOffset(), mTextOffset);
 
 
 						if(selStart > 0)
 						if(selStart > 0)
 						{
 						{
@@ -396,7 +473,7 @@ namespace BansheeEngine
 						if(charIdx < (UINT32)mText.size())
 						if(charIdx < (UINT32)mText.size())
 						{
 						{
 							mText.erase(charIdx, 1);
 							mText.erase(charIdx, 1);
-							mInputCaret->updateText(getTextDesc());
+							mInputCaret->updateText(getTextDesc(), getTextOffset(), mTextOffset);
 
 
 							if(charIdx > 0)
 							if(charIdx > 0)
 								charIdx--;
 								charIdx--;
@@ -421,7 +498,7 @@ namespace BansheeEngine
 					{
 					{
 						UINT32 selStart = getSelectionStart();
 						UINT32 selStart = getSelectionStart();
 						mText.erase(mText.begin() + selStart, mText.begin() + getSelectionEnd());
 						mText.erase(mText.begin() + selStart, mText.begin() + getSelectionEnd());
-						mInputCaret->updateText(getTextDesc());
+						mInputCaret->updateText(getTextDesc(), getTextOffset(), mTextOffset);
 
 
 						if(selStart > 0)
 						if(selStart > 0)
 						{
 						{
@@ -442,7 +519,7 @@ namespace BansheeEngine
 						if(charIdx < (UINT32)mText.size())
 						if(charIdx < (UINT32)mText.size())
 						{
 						{
 							mText.erase(charIdx, 1);
 							mText.erase(charIdx, 1);
-							mInputCaret->updateText(getTextDesc());
+							mInputCaret->updateText(getTextDesc(), getTextOffset(), mTextOffset);
 
 
 							if(charIdx > 0)
 							if(charIdx > 0)
 								charIdx--;
 								charIdx--;
@@ -554,34 +631,6 @@ namespace BansheeEngine
 
 
 				markAsDirty();
 				markAsDirty();
 				return true;
 				return true;
-
-				//if(ev.isShiftDown())
-				//{
-				//	if(!mSelectionShown)
-				//	{
-				//		if(isNewlineChar(caretPosToSelectionChar(mInputCaret->getCaretPos(), SelectionDir::Right)))
-				//		{
-				//			mInputCaret->moveCaretLeft();
-				//		}
-
-				//		showSelection(mInputCaret->getCaretPos(), SelectionDir::Left);
-				//	}
-
-				//	moveSelectionUp();
-				//	scrollTextToCaret();
-
-				//	markAsDirty();
-				//	return true;
-				//}
-				//else
-				//{
-				//	clearSelection();
-				//	mInputCaret->moveCaretUp();
-				//	scrollTextToCaret();
-
-				//	markAsDirty();
-				//	return true;
-				//}
 			}
 			}
 
 
 			if(ev.getKey() == BC_DOWN)
 			if(ev.getKey() == BC_DOWN)
@@ -613,34 +662,6 @@ namespace BansheeEngine
 
 
 				markAsDirty();
 				markAsDirty();
 				return true;
 				return true;
-
-				//if(ev.isShiftDown())
-				//{
-				//	if(!mSelectionShown)
-				//	{
-				//		if(isNewlineChar(caretPosToSelectionChar(mInputCaret->getCaretPos(), SelectionDir::Left)))
-				//		{
-				//			mInputCaret->moveCaretRight();
-				//		}
-
-				//		showSelection(mInputCaret->getCaretPos(), SelectionDir::Left);
-				//	}
-
-				//	moveSelectionDown();
-				//	scrollTextToCaret();
-
-				//	markAsDirty();
-				//	return true;
-				//}
-				//else
-				//{
-				//	clearSelection();
-				//	mInputCaret->moveCaretDown();
-				//	scrollTextToCaret();
-
-				//	markAsDirty();
-				//	return true;
-				//}
 			}
 			}
 
 
 			if(ev.getKey() == BC_RETURN)
 			if(ev.getKey() == BC_RETURN)
@@ -651,7 +672,7 @@ namespace BansheeEngine
 					{
 					{
 						UINT32 selStart = getSelectionStart();
 						UINT32 selStart = getSelectionStart();
 						mText.erase(mText.begin() + selStart, mText.begin() + getSelectionEnd());
 						mText.erase(mText.begin() + selStart, mText.begin() + getSelectionEnd());
-						mInputCaret->updateText(getTextDesc());
+						mInputCaret->updateText(getTextDesc(), getTextOffset(), mTextOffset);
 
 
 						mInputCaret->moveCaretToChar(selStart, CARET_BEFORE);
 						mInputCaret->moveCaretToChar(selStart, CARET_BEFORE);
 						scrollTextToCaret();
 						scrollTextToCaret();
@@ -659,7 +680,7 @@ namespace BansheeEngine
 					}
 					}
 
 
 					mText.insert(mText.begin() + mInputCaret->getCharIdxAtCaretPos(), '\n');
 					mText.insert(mText.begin() + mInputCaret->getCharIdxAtCaretPos(), '\n');
-					mInputCaret->updateText(getTextDesc());
+					mInputCaret->updateText(getTextDesc(), getTextOffset(), mTextOffset);
 
 
 					mInputCaret->moveCaretRight();
 					mInputCaret->moveCaretRight();
 					scrollTextToCaret();
 					scrollTextToCaret();
@@ -685,7 +706,7 @@ namespace BansheeEngine
 			{
 			{
 				UINT32 selStart = getSelectionStart();
 				UINT32 selStart = getSelectionStart();
 				mText.erase(mText.begin() + selStart, mText.begin() + getSelectionEnd());
 				mText.erase(mText.begin() + selStart, mText.begin() + getSelectionEnd());
-				mInputCaret->updateText(getTextDesc());
+				mInputCaret->updateText(getTextDesc(), getTextOffset(), mTextOffset);
 
 
 				mInputCaret->moveCaretToChar(selStart, CARET_BEFORE);
 				mInputCaret->moveCaretToChar(selStart, CARET_BEFORE);
 				clearSelection();
 				clearSelection();
@@ -693,7 +714,7 @@ namespace BansheeEngine
 
 
 			UINT32 charIdx = mInputCaret->getCharIdxAtCaretPos();
 			UINT32 charIdx = mInputCaret->getCharIdxAtCaretPos();
 			mText.insert(mText.begin() + charIdx, ev.getInputChar());
 			mText.insert(mText.begin() + charIdx, ev.getInputChar());
-			mInputCaret->updateText(getTextDesc());
+			mInputCaret->updateText(getTextDesc(), getTextOffset(), mTextOffset);
 
 
 			mInputCaret->moveCaretToChar(charIdx, CARET_AFTER);
 			mInputCaret->moveCaretToChar(charIdx, CARET_AFTER);
 
 
@@ -734,17 +755,18 @@ namespace BansheeEngine
 	{
 	{
 		TEXT_SPRITE_DESC textDesc = getTextDesc();
 		TEXT_SPRITE_DESC textDesc = getTextDesc();
 
 
-		Int2 caretPos = mInputCaret->getCaretPosition(textDesc.offset);
+		Int2 textOffset = getTextOffset();
+		Int2 caretPos = mInputCaret->getCaretPosition(textOffset);
 		UINT32 caretHeight = mInputCaret->getCaretHeight();
 		UINT32 caretHeight = mInputCaret->getCaretHeight();
 		UINT32 caretWidth = 1;
 		UINT32 caretWidth = 1;
 		INT32 caretRight = caretPos.x + (INT32)caretWidth;
 		INT32 caretRight = caretPos.x + (INT32)caretWidth;
 		INT32 caretBottom = caretPos.y + (INT32)caretHeight;
 		INT32 caretBottom = caretPos.y + (INT32)caretHeight;
 
 
-		INT32 left = textDesc.offset.x - mTextOffset.x;
+		INT32 left = textOffset.x - mTextOffset.x;
 		// Include caret width here because we don't want to scroll if just the caret is outside the bounds
 		// Include caret width here because we don't want to scroll if just the caret is outside the bounds
 		// (Possible if the text width is exactly the maximum width)
 		// (Possible if the text width is exactly the maximum width)
 		INT32 right = left + (INT32)textDesc.width + caretWidth; 
 		INT32 right = left + (INT32)textDesc.width + caretWidth; 
-		INT32 top = textDesc.offset.y - mTextOffset.y;
+		INT32 top = textOffset.y - mTextOffset.y;
 		INT32 bottom = top + (INT32)textDesc.height;
 		INT32 bottom = top + (INT32)textDesc.height;
 
 
 		Int2 offset;
 		Int2 offset;
@@ -767,7 +789,7 @@ namespace BansheeEngine
 		}
 		}
 
 
 		mTextOffset += offset;
 		mTextOffset += offset;
-		mInputCaret->updateText(getTextDesc());
+		mInputCaret->updateText(getTextDesc(), getTextOffset(), mTextOffset);
 
 
 		markAsDirty();
 		markAsDirty();
 	}
 	}
@@ -1132,6 +1154,34 @@ namespace BansheeEngine
 		return selectionRects;
 		return selectionRects;
 	}
 	}
 
 
+	Int2 GUIInputBox::getSelectionSpriteOffset(UINT32 spriteIdx) const
+	{
+		Vector<Rect>::type selectionRects = getSelectionRects(); // TODO - Cache these?
+
+		return Int2(selectionRects[spriteIdx].x, selectionRects[spriteIdx].y);
+	}
+
+	Rect GUIInputBox::getSelectionSpriteClipRect(UINT32 spriteIdx) const
+	{
+		Vector<Rect>::type selectionRects = getSelectionRects(); // TODO - Cache these?
+
+		return Rect(getTextBounds().x - selectionRects[spriteIdx].x, 
+			getTextBounds().y - selectionRects[spriteIdx].y, 
+			selectionRects[spriteIdx].width, selectionRects[spriteIdx].height);
+	}
+
+	CM::Int2 GUIInputBox::getTextOffset() const
+	{
+		Rect textBounds = getTextBounds();
+		return Int2(textBounds.x, textBounds.y) + mTextOffset;
+	}
+
+	CM::Rect GUIInputBox::getTextClipRect() const
+	{
+		Rect textBounds = getTextBounds();
+		return Rect(-mTextOffset.x, -mTextOffset.y, textBounds.width, textBounds.height);
+	}
+
 	CM::Rect GUIInputBox::getTextBounds() const
 	CM::Rect GUIInputBox::getTextBounds() const
 	{
 	{
 		Rect textBounds = mBounds;
 		Rect textBounds = mBounds;
@@ -1154,10 +1204,8 @@ namespace BansheeEngine
 		textDesc.fontSize = mStyle->fontSize;
 		textDesc.fontSize = mStyle->fontSize;
 
 
 		Rect textBounds = getTextBounds();
 		Rect textBounds = getTextBounds();
-		textDesc.offset = Int2(textBounds.x, textBounds.y) + mTextOffset;
 		textDesc.width = textBounds.width;
 		textDesc.width = textBounds.width;
 		textDesc.height = textBounds.height;
 		textDesc.height = textBounds.height;
-		textDesc.clipRect = Rect(-mTextOffset.x, -mTextOffset.y, textDesc.width, textDesc.height);
 		textDesc.horzAlign = mStyle->textHorzAlign;
 		textDesc.horzAlign = mStyle->textHorzAlign;
 		textDesc.vertAlign = mStyle->textVertAlign;
 		textDesc.vertAlign = mStyle->textVertAlign;
 		textDesc.wordWrap = mIsMultiline;
 		textDesc.wordWrap = mIsMultiline;

+ 20 - 10
BansheeEngine/Source/BsGUIInputCaret.cpp

@@ -7,8 +7,8 @@ using namespace CamelotFramework;
 
 
 namespace BansheeEngine
 namespace BansheeEngine
 {
 {
-	GUIInputCaret::GUIInputCaret(const TEXT_SPRITE_DESC& textDesc)
-		:mCaretPos(0), mTextDesc(textDesc)
+	GUIInputCaret::GUIInputCaret(const TEXT_SPRITE_DESC& textDesc, const Int2& offset, const Int2 clipOffset)
+		:mCaretPos(0), mTextDesc(textDesc), mTextOffset(offset), mClipOffset(clipOffset)
 	{
 	{
 		mCaretSprite = cm_new<ImageSprite, PoolAlloc>();
 		mCaretSprite = cm_new<ImageSprite, PoolAlloc>();
 		mTextSprite = cm_new<TextSprite, PoolAlloc>();
 		mTextSprite = cm_new<TextSprite, PoolAlloc>();
@@ -22,23 +22,33 @@ namespace BansheeEngine
 		cm_delete<PoolAlloc>(mTextSprite);
 		cm_delete<PoolAlloc>(mTextSprite);
 	}
 	}
 
 
-	void GUIInputCaret::updateText(const TEXT_SPRITE_DESC& textDesc)
+	void GUIInputCaret::updateText(const TEXT_SPRITE_DESC& textDesc, const Int2& offset, const Int2 clipOffset)
 	{
 	{
 		mTextDesc = textDesc;
 		mTextDesc = textDesc;
-		mTextDesc.clipRect = Rect(0, 0, 0, 0); // No clipping otherwise we don't know position of chars
-		// outside of the element, which is something we need when moving the cursor
+		mTextOffset = offset;
+		mClipOffset = clipOffset;
 
 
 		mTextSprite->update(mTextDesc);
 		mTextSprite->update(mTextDesc);
 	}
 	}
 
 
+	Int2 GUIInputCaret::getSpriteOffset() const
+	{
+		return getCaretPosition(mTextOffset);
+	}
+
+	Rect GUIInputCaret::getSpriteClipRect() const
+	{
+		Int2 offset = getSpriteOffset();
+
+		return Rect(-offset.x + mTextOffset.x - mClipOffset.x, -offset.y + mTextOffset.y - mClipOffset.y, 
+			mTextDesc.width + 1, mTextDesc.height); // Increase clip size by 1, so we can fit the caret in case it is fully at the end of the text
+	}
+
 	void GUIInputCaret::updateSprite(const CM::Int2& offset)
 	void GUIInputCaret::updateSprite(const CM::Int2& offset)
 	{
 	{
 		IMAGE_SPRITE_DESC mCaretDesc;
 		IMAGE_SPRITE_DESC mCaretDesc;
-		mCaretDesc.offset = getCaretPosition(mTextDesc.offset);
 		mCaretDesc.width = 1;
 		mCaretDesc.width = 1;
 		mCaretDesc.height = getCaretHeight();
 		mCaretDesc.height = getCaretHeight();
-		mCaretDesc.clipRect = Rect(-mCaretDesc.offset.x + mTextDesc.offset.x - offset.x, -mCaretDesc.offset.y + mTextDesc.offset.y - offset.y, 
-			mTextDesc.width + 1, mTextDesc.height); // Increase clip size by 1, so we can fit the caret in case it is fully at the end of the text
 		mCaretDesc.texture = GUIManager::instance().getCaretTexture();
 		mCaretDesc.texture = GUIManager::instance().getCaretTexture();
 
 
 		mCaretSprite->update(mCaretDesc);
 		mCaretSprite->update(mCaretDesc);
@@ -85,7 +95,7 @@ namespace BansheeEngine
 			return;
 			return;
 		}
 		}
 
 
-		Int2 caretCoords = getCaretPosition(mTextDesc.offset);
+		Int2 caretCoords = getCaretPosition(mTextOffset);
 		caretCoords.y -= getCaretHeight();
 		caretCoords.y -= getCaretHeight();
 
 
 		moveCaretToPos(caretCoords);
 		moveCaretToPos(caretCoords);
@@ -110,7 +120,7 @@ namespace BansheeEngine
 			return;
 			return;
 		}
 		}
 
 
-		Int2 caretCoords = getCaretPosition(mTextDesc.offset);
+		Int2 caretCoords = getCaretPosition(mTextOffset);
 		caretCoords.y += getCaretHeight();
 		caretCoords.y += getCaretHeight();
 
 
 		moveCaretToPos(caretCoords);
 		moveCaretToPos(caretCoords);

+ 0 - 5
BansheeEngine/Source/BsGUIInputSelection.cpp

@@ -26,8 +26,6 @@ namespace BansheeEngine
 	void GUIInputSelection::updateText(const TEXT_SPRITE_DESC& textDesc)
 	void GUIInputSelection::updateText(const TEXT_SPRITE_DESC& textDesc)
 	{
 	{
 		mTextDesc = textDesc;
 		mTextDesc = textDesc;
-		mTextDesc.clipRect = Rect(0, 0, 0, 0); // No clipping otherwise we don't know position of chars
-		// outside of the element, which is something we need when moving the cursor
 
 
 		mTextSprite->update(mTextDesc);
 		mTextSprite->update(mTextDesc);
 	}
 	}
@@ -58,11 +56,8 @@ namespace BansheeEngine
 		for(auto& sprite : mSprites)
 		for(auto& sprite : mSprites)
 		{
 		{
 			IMAGE_SPRITE_DESC desc;
 			IMAGE_SPRITE_DESC desc;
-			desc.offset = Int2(selectionRects[idx].x, selectionRects[idx].y);
 			desc.width = selectionRects[idx].width;
 			desc.width = selectionRects[idx].width;
 			desc.height = selectionRects[idx].height;
 			desc.height = selectionRects[idx].height;
-			desc.clipRect = Rect(mTextDesc.offset.x - selectionRects[idx].x, 
-				mTextDesc.offset.y - selectionRects[idx].y, mTextDesc.width, mTextDesc.height);
 			desc.texture = GUIManager::instance().getTextSelectionTexture();
 			desc.texture = GUIManager::instance().getTextSelectionTexture();
 
 
 			sprite->update(desc);
 			sprite->update(desc);

+ 2 - 4
BansheeEngine/Source/BsGUILabel.cpp

@@ -45,13 +45,11 @@ namespace BansheeEngine
 
 
 	void GUILabel::updateRenderElementsInternal()
 	void GUILabel::updateRenderElementsInternal()
 	{		
 	{		
-		mDesc.offset = mOffset;
 		mDesc.width = mWidth;
 		mDesc.width = mWidth;
 		mDesc.height = mHeight;
 		mDesc.height = mHeight;
-		mDesc.clipRect = mClipRect;
 
 
 		mTextSprite->update(mDesc);
 		mTextSprite->update(mDesc);
-		mBounds = mTextSprite->getBounds();
+		mBounds = mTextSprite->getBounds(mOffset, mClipRect);
 	}
 	}
 
 
 	UINT32 GUILabel::_getOptimalWidth() const
 	UINT32 GUILabel::_getOptimalWidth() const
@@ -95,7 +93,7 @@ namespace BansheeEngine
 	void GUILabel::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
 	void GUILabel::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 	{
 	{
-		mTextSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx);
+		mTextSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx, mOffset, mClipRect);
 	}
 	}
 
 
 	void GUILabel::setText(const CM::WString& text)
 	void GUILabel::setText(const CM::WString& text)

+ 2 - 4
BansheeEngine/Source/BsGUITexture.cpp

@@ -101,10 +101,8 @@ namespace BansheeEngine
 
 
 	void GUITexture::updateRenderElementsInternal()
 	void GUITexture::updateRenderElementsInternal()
 	{		
 	{		
-		mDesc.offset = mOffset;
 		mDesc.width = mWidth;
 		mDesc.width = mWidth;
 		mDesc.height = mHeight;
 		mDesc.height = mHeight;
-		mDesc.clipRect = mClipRect;
 
 
 		float optimalWidth = 0.0f;
 		float optimalWidth = 0.0f;
 		float optimalHeight = 0.0f;
 		float optimalHeight = 0.0f;
@@ -160,7 +158,7 @@ namespace BansheeEngine
 		}
 		}
 
 
 		mImageSprite->update(mDesc);
 		mImageSprite->update(mDesc);
-		mBounds = mImageSprite->getBounds();
+		mBounds = mImageSprite->getBounds(mOffset, mClipRect);
 	}
 	}
 
 
 	UINT32 GUITexture::_getOptimalWidth() const
 	UINT32 GUITexture::_getOptimalWidth() const
@@ -186,6 +184,6 @@ namespace BansheeEngine
 	void GUITexture::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
 	void GUITexture::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 	{
 	{
-		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx);
+		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx, mOffset, mClipRect);
 	}
 	}
 }
 }

+ 37 - 17
BansheeEngine/Source/BsGUIToggle.cpp

@@ -95,13 +95,11 @@ namespace BansheeEngine
 
 
 	void GUIToggle::updateRenderElementsInternal()
 	void GUIToggle::updateRenderElementsInternal()
 	{		
 	{		
-		mImageDesc.offset = mOffset;
 		mImageDesc.width = mWidth;
 		mImageDesc.width = mWidth;
 		mImageDesc.height = mHeight;
 		mImageDesc.height = mHeight;
-		mImageDesc.clipRect = mClipRect;
 
 
 		mImageSprite->update(mImageDesc);
 		mImageSprite->update(mImageDesc);
-		mBounds = mImageSprite->getBounds();
+		mBounds = mImageSprite->getBounds(mOffset, mClipRect);
 		mNumImageRenderElements = mImageSprite->getNumRenderElements();
 		mNumImageRenderElements = mImageSprite->getNumRenderElements();
 
 
 		TEXT_SPRITE_DESC textDesc;
 		TEXT_SPRITE_DESC textDesc;
@@ -109,19 +107,10 @@ namespace BansheeEngine
 		textDesc.font = mStyle->font;
 		textDesc.font = mStyle->font;
 		textDesc.fontSize = mStyle->fontSize;
 		textDesc.fontSize = mStyle->fontSize;
 
 
-		Rect contentBounds = mBounds;
+		Rect textBounds = getTextBounds();
 
 
-		contentBounds.x += mStyle->margins.left + mStyle->contentOffset.left;
-		contentBounds.y += mStyle->margins.top + mStyle->contentOffset.top;
-		contentBounds.width = (UINT32)std::max(0, (INT32)contentBounds.width - 
-			(INT32)(mStyle->margins.left + mStyle->margins.right + mStyle->contentOffset.left + mStyle->contentOffset.right));
-		contentBounds.height = (UINT32)std::max(0, (INT32)contentBounds.height - 
-			(INT32)(mStyle->margins.top + mStyle->margins.bottom + mStyle->contentOffset.top + mStyle->contentOffset.bottom));
-
-		textDesc.offset = Int2(contentBounds.x, contentBounds.y);
-		textDesc.width = contentBounds.width;
-		textDesc.height = contentBounds.height;
-		textDesc.clipRect = Rect(0, 0, textDesc.width, textDesc.height);
+		textDesc.width = textBounds.width;
+		textDesc.height = textBounds.height;
 		textDesc.horzAlign = mStyle->textHorzAlign;
 		textDesc.horzAlign = mStyle->textHorzAlign;
 		textDesc.vertAlign = mStyle->textVertAlign;
 		textDesc.vertAlign = mStyle->textVertAlign;
 
 
@@ -160,9 +149,19 @@ namespace BansheeEngine
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 	{
 	{
 		if(renderElementIdx >= mNumImageRenderElements)
 		if(renderElementIdx >= mNumImageRenderElements)
-			mTextSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, mNumImageRenderElements - renderElementIdx);
+		{
+			Rect textBounds = getTextBounds();
+			Int2 offset(textBounds.x, textBounds.y);
+			Rect textClipRect = getTextClipRect();
+
+			mTextSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, 
+				vertexStride, indexStride, mNumImageRenderElements - renderElementIdx, offset, textClipRect);
+		}
 		else
 		else
-			mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx);
+		{
+			mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, 
+				vertexStride, indexStride, renderElementIdx, mOffset, mClipRect);
+		}
 	}
 	}
 
 
 	bool GUIToggle::mouseEvent(const GUIMouseEvent& ev)
 	bool GUIToggle::mouseEvent(const GUIMouseEvent& ev)
@@ -212,4 +211,25 @@ namespace BansheeEngine
 
 
 		return false;
 		return false;
 	}
 	}
+
+	CM::Rect GUIToggle::getTextBounds() const
+	{
+		Rect textBounds = mBounds;
+
+		textBounds.x += mStyle->margins.left + mStyle->contentOffset.left;
+		textBounds.y += mStyle->margins.top + mStyle->contentOffset.top;
+		textBounds.width = (UINT32)std::max(0, (INT32)textBounds.width - 
+			(INT32)(mStyle->margins.left + mStyle->margins.right + mStyle->contentOffset.left + mStyle->contentOffset.right));
+		textBounds.height = (UINT32)std::max(0, (INT32)textBounds.height - 
+			(INT32)(mStyle->margins.top + mStyle->margins.bottom + mStyle->contentOffset.top + mStyle->contentOffset.bottom));
+
+		return textBounds;
+	}
+
+	CM::Rect GUIToggle::getTextClipRect() const
+	{
+		Rect textBounds = getTextBounds();
+
+		return Rect(0, 0, textBounds.width, textBounds.height);
+	}
 }
 }

+ 2 - 4
BansheeEngine/Source/BsGUIWindowFrame.cpp

@@ -160,13 +160,11 @@ namespace BansheeEngine
 
 
 	void GUIWindowFrame::updateRenderElementsInternal()
 	void GUIWindowFrame::updateRenderElementsInternal()
 	{		
 	{		
-		mDesc.offset = mOffset;
 		mDesc.width = mWidth;
 		mDesc.width = mWidth;
 		mDesc.height = mHeight;
 		mDesc.height = mHeight;
-		mDesc.clipRect = mClipRect;
 
 
 		mImageSprite->update(mDesc);
 		mImageSprite->update(mDesc);
-		mBounds = mImageSprite->getBounds();
+		mBounds = mImageSprite->getBounds(mOffset, mClipRect);
 	}
 	}
 
 
 	UINT32 GUIWindowFrame::_getOptimalWidth() const
 	UINT32 GUIWindowFrame::_getOptimalWidth() const
@@ -206,7 +204,7 @@ namespace BansheeEngine
 	void GUIWindowFrame::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
 	void GUIWindowFrame::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 	{
 	{
-		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx);
+		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx, mOffset, mClipRect);
 	}
 	}
 
 
 	void GUIWindowFrame::setFocused(bool focused)
 	void GUIWindowFrame::setFocused(bool focused)

+ 2 - 4
BansheeEngine/Source/BsGUIWindowMover.cpp

@@ -80,13 +80,11 @@ namespace BansheeEngine
 
 
 	void GUIWindowMover::updateRenderElementsInternal()
 	void GUIWindowMover::updateRenderElementsInternal()
 	{		
 	{		
-		mDesc.offset = mOffset;
 		mDesc.width = mWidth;
 		mDesc.width = mWidth;
 		mDesc.height = mHeight;
 		mDesc.height = mHeight;
-		mDesc.clipRect = mClipRect;
 
 
 		mImageSprite->update(mDesc);
 		mImageSprite->update(mDesc);
-		mBounds = mImageSprite->getBounds();
+		mBounds = mImageSprite->getBounds(mOffset, mClipRect);
 	}
 	}
 
 
 	UINT32 GUIWindowMover::_getOptimalWidth() const
 	UINT32 GUIWindowMover::_getOptimalWidth() const
@@ -112,7 +110,7 @@ namespace BansheeEngine
 	void GUIWindowMover::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
 	void GUIWindowMover::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
 	{
 	{
-		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx);
+		mImageSprite->fillBuffer(vertices, uv, indices, startingQuad, maxNumQuads, vertexStride, indexStride, renderElementIdx, mOffset, mClipRect);
 	}
 	}
 
 
 	void GUIWindowMover::setFocused(bool focused)
 	void GUIWindowMover::setFocused(bool focused)

+ 0 - 13
BansheeEngine/Source/BsImageSprite.cpp

@@ -229,19 +229,6 @@ namespace BansheeEngine
 			renderElem.uvs[3] = desc.texture->transformUV(Vector2(uvOffset.x + uvScale.x, uvOffset.y + uvScale.y));
 			renderElem.uvs[3] = desc.texture->transformUV(Vector2(uvOffset.x + uvScale.x, uvOffset.y + uvScale.y));
 		}
 		}
 
 
-		if(desc.clipRect.width > 0 && desc.clipRect.height > 0)
-		{
-			clipToRect(renderElem.vertices, renderElem.uvs, renderElem.numQuads, desc.clipRect);
-		}
-
-		// Apply offset
-		UINT32 numVertices = renderElem.numQuads * 4;
-		for(size_t i = 0; i < numVertices; i++)
-		{
-			renderElem.vertices[i].x += (float)desc.offset.x;
-			renderElem.vertices[i].y += (float)desc.offset.y;
-		}
-
 		updateBounds();
 		updateBounds();
 	}
 	}
 }
 }

+ 121 - 20
BansheeEngine/Source/BsSprite.cpp

@@ -16,6 +16,19 @@ namespace BansheeEngine
 		clearMesh();
 		clearMesh();
 	}
 	}
 
 
+	CM::Rect Sprite::getBounds(const Int2& offset, const Rect& clipRect) const 
+	{
+		Rect bounds = mBounds;
+
+		if(clipRect.width > 0 && clipRect.height > 0)
+			bounds.clip(clipRect);
+
+		bounds.x += offset.x;
+		bounds.y += offset.y;
+
+		return bounds; 
+	}
+
 	UINT32 Sprite::getNumRenderElements() const
 	UINT32 Sprite::getNumRenderElements() const
 	{
 	{
 		return (UINT32)mCachedRenderElements.size();
 		return (UINT32)mCachedRenderElements.size();
@@ -31,7 +44,8 @@ namespace BansheeEngine
 		return mCachedRenderElements.at(renderElementIdx).numQuads;
 		return mCachedRenderElements.at(renderElementIdx).numQuads;
 	}
 	}
 
 
-	UINT32 Sprite::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx) const
+	UINT32 Sprite::fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 startingQuad, UINT32 maxNumQuads, 
+		UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx, const Int2& offset, const Rect& clipRect) const
 	{
 	{
 		auto renderElem = mCachedRenderElements.at(renderElementIdx);
 		auto renderElem = mCachedRenderElements.at(renderElementIdx);
 
 
@@ -48,18 +62,108 @@ namespace BansheeEngine
 		assert((startIndex + mNumIndices) <= maxIndexIdx);
 		assert((startIndex + mNumIndices) <= maxIndexIdx);
 
 
 		UINT8* vertDst = vertices + startVert * vertexStride;
 		UINT8* vertDst = vertices + startVert * vertexStride;
-		for(UINT32 i = 0; i < mNumVertices; i++)
+		UINT8* uvDst = uv + startVert * vertexStride;
+
+		// TODO - I'm sure this can be done in a more cache friendly way. Profile it later.
+		Vector2 vecOffset((float)offset.x, (float)offset.y);
+		if(clipRect.width > 0 && clipRect.height > 0)
 		{
 		{
-			memcpy(vertDst, &renderElem.vertices[i], sizeof(Vector2));
-			vertDst += vertexStride;
-		}
+			for(UINT32 i = 0; i < renderElem.numQuads; i++)
+			{
+				UINT8* vecStart = vertDst;
+				Vector2* uvStart = (Vector2*)uvDst;
+				UINT32 vertIdx = i * 4;
+
+				Vector2 vecPlusOffset = renderElem.vertices[vertIdx + 0] + vecOffset;
+
+				memcpy(vertDst, &renderElem.vertices[vertIdx + 0], sizeof(Vector2));
+				memcpy(uvDst, &renderElem.uvs[vertIdx + 0], sizeof(Vector2));
+
+				vertDst += vertexStride;
+				uvDst += vertexStride;
+
+				memcpy(vertDst, &renderElem.vertices[vertIdx + 1], sizeof(Vector2));
+				memcpy(uvDst, &renderElem.uvs[vertIdx + 1], sizeof(Vector2));
+
+				vertDst += vertexStride;
+				uvDst += vertexStride;
+
+				memcpy(vertDst, &renderElem.vertices[vertIdx + 2], sizeof(Vector2));
+				memcpy(uvDst, &renderElem.uvs[vertIdx + 2], sizeof(Vector2));
+
+				vertDst += vertexStride;
+				uvDst += vertexStride;
+
+				memcpy(vertDst, &renderElem.vertices[vertIdx + 3], sizeof(Vector2));
+				memcpy(uvDst, &renderElem.uvs[vertIdx + 3], sizeof(Vector2));
+
+				clipToRect((Vector2*)vecStart, uvStart, 1, clipRect);
+
+				vertDst = vecStart;
+				Vector2* curVec = (Vector2*)vertDst;
+				*curVec += vecOffset;
+
+				vertDst += vertexStride;
+				curVec = (Vector2*)vertDst;
+				*curVec += vecOffset;
 
 
-		if(uv != nullptr)
+				vertDst += vertexStride;
+				curVec = (Vector2*)vertDst;
+				*curVec += vecOffset;
+
+				vertDst += vertexStride;
+				curVec = (Vector2*)vertDst;
+				*curVec += vecOffset;
+
+				vertDst += vertexStride;
+				uvDst += vertexStride;
+			}
+		}
+		else
 		{
 		{
-			UINT8* uvDst = uv + startVert * vertexStride;
-			for(UINT32 i = 0; i < mNumVertices; i++)
+			for(UINT32 i = 0; i < renderElem.numQuads; i++)
 			{
 			{
-				memcpy(uvDst, &renderElem.uvs[i], sizeof(Vector2));
+				UINT8* vecStart = vertDst;
+				UINT32 vertIdx = i * 4;
+
+				memcpy(vertDst, &renderElem.vertices[vertIdx + 0], sizeof(Vector2));
+				memcpy(uvDst, &renderElem.uvs[vertIdx + 0], sizeof(Vector2));
+
+				vertDst += vertexStride;
+				uvDst += vertexStride;
+
+				memcpy(vertDst, &renderElem.vertices[vertIdx + 1], sizeof(Vector2));
+				memcpy(uvDst, &renderElem.uvs[vertIdx + 1], sizeof(Vector2));
+
+				vertDst += vertexStride;
+				uvDst += vertexStride;
+
+				memcpy(vertDst, &renderElem.vertices[vertIdx + 2], sizeof(Vector2));
+				memcpy(uvDst, &renderElem.uvs[vertIdx + 2], sizeof(Vector2));
+
+				vertDst += vertexStride;
+				uvDst += vertexStride;
+
+				memcpy(vertDst, &renderElem.vertices[vertIdx + 3], sizeof(Vector2));
+				memcpy(uvDst, &renderElem.uvs[vertIdx + 3], sizeof(Vector2));
+
+				vertDst = vecStart;
+				Vector2* curVec = (Vector2*)vertDst;
+				*curVec += vecOffset;
+
+				vertDst += vertexStride;
+				curVec = (Vector2*)vertDst;
+				*curVec += vecOffset;
+
+				vertDst += vertexStride;
+				curVec = (Vector2*)vertDst;
+				*curVec += vecOffset;
+
+				vertDst += vertexStride;
+				curVec = (Vector2*)vertDst;
+				*curVec += vecOffset;
+
+				vertDst += vertexStride;
 				uvDst += vertexStride;
 				uvDst += vertexStride;
 			}
 			}
 		}
 		}
@@ -208,17 +312,14 @@ namespace BansheeEngine
 			vertices[vertIdx + 2].y = newBottom;
 			vertices[vertIdx + 2].y = newBottom;
 			vertices[vertIdx + 3].y = newBottom;
 			vertices[vertIdx + 3].y = newBottom;
 			
 			
-			if(uv != nullptr)
-			{
-				uv[vertIdx + 0].x += uvLeftOffset;
-				uv[vertIdx + 2].x += uvLeftOffset;
-				uv[vertIdx + 1].x -= uvRightOffset;
-				uv[vertIdx + 3].x -= uvRightOffset;
-				uv[vertIdx + 0].y += uvTopOffset;
-				uv[vertIdx + 1].y += uvTopOffset;
-				uv[vertIdx + 2].y -= uvBottomOffset;
-				uv[vertIdx + 3].y -= uvBottomOffset;
-			}
+			uv[vertIdx + 0].x += uvLeftOffset;
+			uv[vertIdx + 2].x += uvLeftOffset;
+			uv[vertIdx + 1].x -= uvRightOffset;
+			uv[vertIdx + 3].x -= uvRightOffset;
+			uv[vertIdx + 0].y += uvTopOffset;
+			uv[vertIdx + 1].y += uvTopOffset;
+			uv[vertIdx + 2].y -= uvBottomOffset;
+			uv[vertIdx + 3].y -= uvBottomOffset;
 		}
 		}
 	}
 	}
 }
 }

+ 1 - 18
BansheeEngine/Source/BsTextSprite.cpp

@@ -95,23 +95,6 @@ namespace BansheeEngine
 				renderElem.vertices, renderElem.uvs, renderElem.indexes, renderElem.numQuads);
 				renderElem.vertices, renderElem.uvs, renderElem.indexes, renderElem.numQuads);
 		}
 		}
 
 
-		if(desc.clipRect.width > 0 && desc.clipRect.height > 0)
-		{
-			for(auto& renderElem : mCachedRenderElements)
-				clipToRect(renderElem.vertices, renderElem.uvs, renderElem.numQuads, desc.clipRect);
-		}
-
-		// Apply offset
-		for(auto& renderElem : mCachedRenderElements)
-		{
-			UINT32 numVertices = renderElem.numQuads * 4;
-			for(size_t i = 0; i < numVertices; i++)
-			{
-				renderElem.vertices[i].x += (float)desc.offset.x;
-				renderElem.vertices[i].y += (float)desc.offset.y;
-			}
-		}
-
 		// Store cached line data
 		// Store cached line data
 		UINT32 curCharIdx = 0;
 		UINT32 curCharIdx = 0;
 		UINT32 cachedLineY = 0;
 		UINT32 cachedLineY = 0;
@@ -125,7 +108,7 @@ namespace BansheeEngine
 			UINT32 startChar = curCharIdx;
 			UINT32 startChar = curCharIdx;
 			UINT32 endChar = curCharIdx + line.getNumChars() + (hasNewline ? 1 : 0);
 			UINT32 endChar = curCharIdx + line.getNumChars() + (hasNewline ? 1 : 0);
 			UINT32 lineHeight = line.getYOffset();
 			UINT32 lineHeight = line.getYOffset();
-			INT32 lineYStart = alignmentOffsets[curLineIdx].y + desc.offset.y;
+			INT32 lineYStart = alignmentOffsets[curLineIdx].y + 0; // TODO - Ignoring offset
 
 
 			SpriteLineDesc lineDesc(startChar, endChar, lineHeight, lineYStart, hasNewline);
 			SpriteLineDesc lineDesc(startChar, endChar, lineHeight, lineYStart, hasNewline);
 			mLineDescs.push_back(lineDesc);
 			mLineDescs.push_back(lineDesc);

+ 1 - 0
CamelotUtility/Include/CmRect.h

@@ -13,6 +13,7 @@ namespace CamelotFramework
 		bool contains(const Int2& point) const;
 		bool contains(const Int2& point) const;
 		bool overlaps(const Rect& other) const;
 		bool overlaps(const Rect& other) const;
 		void encapsulate(const Rect& other);
 		void encapsulate(const Rect& other);
+		void clip(const Rect& clipRect);
 
 
 		/**
 		/**
 		 * @brief	Transforms the bounds by the given matrix.
 		 * @brief	Transforms the bounds by the given matrix.

+ 14 - 0
CamelotUtility/Source/CmRect.cpp

@@ -63,6 +63,20 @@ namespace CamelotFramework
 			height = myBottom - y;
 			height = myBottom - y;
 	}
 	}
 
 
+	void Rect::clip(const Rect& clipRect)
+	{
+		int newLeft = std::max(x, clipRect.x);
+		int newTop = std::max(y, clipRect.y);
+
+		int newRight = std::min(x + width, clipRect.x + clipRect.width);
+		int newBottom = std::min(y + height, clipRect.x + clipRect.height);
+
+		x = newLeft;
+		y = newTop;
+		width = newRight - newLeft;
+		height = newBottom - newTop;
+	}
+
 	void Rect::transform(const Matrix4& matrix)
 	void Rect::transform(const Matrix4& matrix)
 	{
 	{
 		Vector4 verts[4];
 		Vector4 verts[4];

+ 6 - 0
TODO.txt

@@ -31,6 +31,12 @@ TextBox needed elements:
   - Make them use their own text rendering methods instead of relying on TextSprite.
   - Make them use their own text rendering methods instead of relying on TextSprite.
   - Make them a singleton so that any input element can use them, and not every element needs to have its own copy.
   - Make them a singleton so that any input element can use them, and not every element needs to have its own copy.
   - Since caret and selection are so connected make sure their classes share a common base class.
   - Since caret and selection are so connected make sure their classes share a common base class.
+ - All classes dealing with text (Button, Toggle, Label, InputBox) determine text field size based on mBounds which is calculated from 
+    clipped mImageSprite coordinates. Which is wrong because text word wrap will change depending how clipped the sprite is.
+ - Add GUIInputTextBase which is a parent to both caret and selection
+ - Don't forget to make the classes input/selection singletons
+ - Elements need TWO different dirty flags. Right now setting dirty causes both content update and fillBuffer update.
+   - But I'd like only fillBuffer update when element is moved, or clipped as content update may be expensive
 
 
 TextData::getVertexData(vertex, uv, bool splitByPages)
 TextData::getVertexData(vertex, uv, bool splitByPages)
  - Called by both TextSprite, InputCaret and InputSelection
  - Called by both TextSprite, InputCaret and InputSelection