Marko Pintera 12 лет назад
Родитель
Сommit
c9b3b5c492

+ 2 - 0
BansheeEngine/Include/BsGUIInputBox.h

@@ -55,6 +55,7 @@ namespace BansheeEngine
 		CM::UINT32 mNumImageRenderElements;
 		bool mInputCursorSet;
 		bool mDragInProgress;
+		bool mIsMultiline;
 
 		CM::UINT32 mSelectionStart;
 		CM::UINT32 mSelectionEnd;
@@ -83,5 +84,6 @@ namespace BansheeEngine
 		CM::Vector<CM::Rect>::type getSelectionRects() const;
 
 		CM::UINT32 getCharAtPosition(const CM::Int2& pos) const;
+		CM::Rect getTextBounds() const;
 	};
 }

+ 6 - 0
BansheeEngine/Include/BsGUIManager.h

@@ -40,7 +40,9 @@ namespace BansheeEngine
 		void render(CM::ViewportPtr& target, CM::CoreAccessor& coreAccessor);
 
 		void setCaretColor(const CM::Color& color) { mCaretColor = color; updateCaretTexture(); }
+		void setTextSelectionColor(const CM::Color& color) { mTextSelectionColor = color; updateTextSelectionTexture(); }
 		const SpriteTexturePtr& getCaretTexture() const { return mCaretTexture; }
+		const SpriteTexturePtr& getTextSelectionTexture() const { return mTextSelectionTexture; }
 		bool getCaretBlinkState() const { return mIsCaretOn; }
 
 	private:
@@ -73,6 +75,9 @@ namespace BansheeEngine
 		float mCaretLastBlinkTime;
 		bool mIsCaretOn;
 
+		SpriteTexturePtr mTextSelectionTexture;
+		CM::Color mTextSelectionColor;
+
 		boost::signals::connection mOnButtonDownConn;
 		boost::signals::connection mOnButtonUpConn;
 		boost::signals::connection mOnMouseMovedConn;
@@ -86,6 +91,7 @@ namespace BansheeEngine
 
 		void updateMeshes();
 		void updateCaretTexture();
+		void updateTextSelectionTexture();
 
 		void onButtonDown(const CM::ButtonEvent& event);
 		void onButtonUp(const CM::ButtonEvent& event);

+ 2 - 2
BansheeEngine/Include/BsSprite.h

@@ -98,7 +98,7 @@ namespace BansheeEngine
 		void updateBounds() const;
 		void clearMesh() const;
 
-		void clipToRect(CM::Vector2* vertices, CM::Vector2* uv, CM::UINT32 numQuads, const CM::Rect& clipRect) const;
-		CM::Int2 getAnchorOffset(SpriteAnchor anchor, CM::UINT32 width, CM::UINT32 height) const;
+		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);
 	};
 }

+ 2 - 0
BansheeEngine/Include/BsTextSprite.h

@@ -42,5 +42,7 @@ namespace BansheeEngine
 		TextSprite();
 
 		void update(const TEXT_SPRITE_DESC& desc);
+
+		static void getTextVertices(const TEXT_SPRITE_DESC& desc, CM::Vector2* vertices, CM::Vector2* uv = nullptr);
 	};
 }

+ 69 - 14
BansheeEngine/Source/BsGUIInputBox.cpp

@@ -9,6 +9,7 @@
 #include "BsGUIButtonEvent.h"
 #include "BsGUIMouseEvent.h"
 #include "BsGUICommandEvent.h"
+#include "CmTextUtility.h"
 #include "CmTexture.h"
 #include "CmCursor.h"
 
@@ -24,7 +25,8 @@ namespace BansheeEngine
 
 	GUIInputBox::GUIInputBox(GUIWidget& parent, const GUIElementStyle* style, const GUILayoutOptions& layoutOptions)
 		:GUIElement(parent, style, layoutOptions), mNumImageRenderElements(0), mInputCursorSet(false), mDragInProgress(false),
-		mSelectionStart(0), mSelectionEnd(0), mCaretSprite(nullptr), mCaretShown(false), mSelectionShown(false), mCaretPos(0)
+		mSelectionStart(0), mSelectionEnd(0), mCaretSprite(nullptr), mCaretShown(false), mSelectionShown(false), mCaretPos(0),
+		mIsMultiline(false)
 	{
 		mImageSprite = cm_new<ImageSprite, PoolAlloc>();
 		mCaretSprite = cm_new<ImageSprite, PoolAlloc>();
@@ -49,6 +51,9 @@ namespace BansheeEngine
 		cm_delete<PoolAlloc>(mTextSprite);
 		cm_delete<PoolAlloc>(mCaretSprite);
 		cm_delete<PoolAlloc>(mImageSprite);
+
+		for(auto& sprite : mSelectionSprites)
+			cm_delete(sprite);
 	}
 
 	GUIInputBox* GUIInputBox::create(GUIWidget& parent, const GUIElementStyle* style)
@@ -124,18 +129,10 @@ namespace BansheeEngine
 		textDesc.font = mStyle->font;
 		textDesc.fontSize = mStyle->fontSize;
 
-		Rect contentBounds = mBounds;
-
-		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;
+		Rect textBounds = getTextBounds();
+		textDesc.offset = Int2(textBounds.x, textBounds.y);
+		textDesc.width = textBounds.width;
+		textDesc.height = textBounds.height;
 		textDesc.clipRect = Rect(0, 0, textDesc.width, textDesc.height);
 		textDesc.horzAlign = mStyle->textHorzAlign;
 		textDesc.vertAlign = mStyle->textVertAlign;
@@ -157,7 +154,38 @@ namespace BansheeEngine
 		if(mSelectionShown)
 		{
 			Vector<Rect>::type selectionRects = getSelectionRects();
-			// TODO - Update sprites
+
+			INT32 diff = (INT32)(mSelectionSprites.size() - selectionRects.size());
+
+			if(diff > 0)
+			{
+				for(INT32 i = 0; i < diff; i++)
+					cm_delete(mSelectionSprites[i]);
+
+				mSelectionSprites.erase(mSelectionSprites.begin() + selectionRects.size(), mSelectionSprites.end());
+			}
+			else if(diff < 0)
+			{
+				for(INT32 i = diff; i < 0; i++)
+				{
+					ImageSprite* newSprite = cm_new<ImageSprite>();
+					mSelectionSprites.push_back(newSprite);
+				}
+			}
+
+			UINT32 idx = 0;
+			for(auto& sprite : mSelectionSprites)
+			{
+				IMAGE_SPRITE_DESC desc;
+				desc.offset = Int2(selectionRects[idx].x, selectionRects[idx].y);
+				desc.width = selectionRects[idx].width;
+				desc.height = selectionRects[idx].height;
+				desc.clipRect = Rect(0, 0, textDesc.width, textDesc.height);
+				desc.texture = GUIManager::instance().getTextSelectionTexture();
+
+				sprite->update(desc);
+				idx++;
+			}
 		}
 	}
 
@@ -423,6 +451,10 @@ namespace BansheeEngine
 
 	void GUIInputBox::clearSelection()
 	{
+		for(auto& sprite : mSelectionSprites)
+			cm_delete(sprite);
+		
+		mSelectionSprites.clear();
 		mSelectionShown = false;
 		markAsDirty();
 	}
@@ -435,10 +467,33 @@ namespace BansheeEngine
 
 	UINT32 GUIInputBox::getCharAtPosition(const Int2& pos) const
 	{
+		Rect textBounds = getTextBounds();
+
+		//std::shared_ptr<TextUtility::TextData> textData = 
+		//	TextUtility::getTextData(mText, mStyle->font, mStyle->fontSize, 
+		//	textBounds.width, textBounds.height, mIsMultiline);
+
+		//textData->getLines()
+
 		// TODO
 		return 0;
 	}
 
+	CM::Rect GUIInputBox::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;
+	}
+
 	void GUIInputBox::_setFocus(bool focus)
 	{
 		if(focus)

+ 22 - 2
BansheeEngine/Source/BsGUIManager.cpp

@@ -46,7 +46,8 @@ namespace BansheeEngine
 	GUIManager::GUIManager()
 		:mMouseOverElement(nullptr), mMouseOverWidget(nullptr), mSeparateMeshesByWidget(true), mActiveElement(nullptr), 
 		mActiveWidget(nullptr), mActiveMouseButton(GUIMouseButton::Left), mKeyboardFocusElement(nullptr), mKeyboardFocusWidget(nullptr),
-		mCaretTexture(nullptr), mCaretBlinkInterval(0.5f), mCaretLastBlinkTime(0.0f), mCaretColor(Color::Black), mIsCaretOn(false)
+		mCaretTexture(nullptr), mCaretBlinkInterval(0.5f), mCaretLastBlinkTime(0.0f), mCaretColor(Color::Black), mIsCaretOn(false),
+		mTextSelectionColor(1.0f, 0.6588f, 0.0f)
 	{
 		mOnButtonDownConn = gInput().onButtonDown.connect(boost::bind(&GUIManager::onButtonDown, this, _1));
 		mOnButtonUpConn = gInput().onButtonUp.connect(boost::bind(&GUIManager::onButtonUp, this, _1));
@@ -59,6 +60,7 @@ namespace BansheeEngine
 
 		// Need to defer this call because I want to make sure all managers are initialized first
 		deferredCall(std::bind(&GUIManager::updateCaretTexture, this));
+		deferredCall(std::bind(&GUIManager::updateTextSelectionTexture, this));
 	}
 
 	GUIManager::~GUIManager()
@@ -456,7 +458,25 @@ namespace BansheeEngine
 		UINT32 subresourceIdx = tex->mapToSubresourceIdx(0, 0);
 		PixelDataPtr data = tex->allocateSubresourceBuffer(subresourceIdx);
 
-		data->setColorAt(Color::Red, 0, 0);
+		data->setColorAt(mCaretColor, 0, 0);
+
+		gMainSyncedCA().writeSubresource(tex.getInternalPtr(), tex->mapToSubresourceIdx(0, 0), *data);
+		gMainSyncedCA().submitToCoreThread(true); // TODO - Remove this once I make writeSubresource accept a shared_ptr for MeshData
+	}
+
+	void GUIManager::updateTextSelectionTexture()
+	{
+		if(mTextSelectionTexture == nullptr)
+		{
+			HTexture newTex = Texture::create(TEX_TYPE_2D, 1, 1, 0, PF_R8G8B8A8);
+			mTextSelectionTexture = cm_shared_ptr<SpriteTexture>(newTex);
+		}
+
+		const HTexture& tex = mTextSelectionTexture->getTexture();
+		UINT32 subresourceIdx = tex->mapToSubresourceIdx(0, 0);
+		PixelDataPtr data = tex->allocateSubresourceBuffer(subresourceIdx);
+
+		data->setColorAt(mTextSelectionColor, 0, 0);
 
 		gMainSyncedCA().writeSubresource(tex.getInternalPtr(), tex->mapToSubresourceIdx(0, 0), *data);
 		gMainSyncedCA().submitToCoreThread(true); // TODO - Remove this once I make writeSubresource accept a shared_ptr for MeshData

+ 2 - 2
BansheeEngine/Source/BsSprite.cpp

@@ -63,7 +63,7 @@ namespace BansheeEngine
 		return renderElem.numQuads;
 	}
 
-	Int2 Sprite::getAnchorOffset(SpriteAnchor anchor, UINT32 width, UINT32 height) const
+	Int2 Sprite::getAnchorOffset(SpriteAnchor anchor, UINT32 width, UINT32 height)
 	{
 		switch(anchor)
 		{
@@ -153,7 +153,7 @@ namespace BansheeEngine
 	// This will only properly clip an array of rectangular quads
 	// Vertices in the quad must be in a specific order: top left, top right, bottom left, bottom right
 	// (0, 0) represents top left of the screen
-	void Sprite::clipToRect(Vector2* vertices, Vector2* uv, UINT32 numQuads, const Rect& clipRect) const
+	void Sprite::clipToRect(Vector2* vertices, Vector2* uv, UINT32 numQuads, const Rect& clipRect)
 	{
 		float left = (float)clipRect.x;
 		float right = (float)clipRect.x + clipRect.width;

+ 112 - 26
BansheeEngine/Source/BsTextSprite.cpp

@@ -23,28 +23,6 @@ namespace BansheeEngine
 		const CM::Vector<TextUtility::TextLine>::type& lines = textData->getLines();
 		const CM::Vector<UINT32>::type& quadsPerPage = textData->getNumQuadsPerPage();
 
-		UINT32 curHeight = 0;
-		for(auto& line : lines)
-		{
-			curHeight += line.getYOffset();
-		}
-
-		// Calc vertical alignment offset
-		UINT32 vertDiff = std::max(0U, desc.height - curHeight);
-		UINT32 vertOffset = 0;
-		switch(desc.vertAlign)
-		{
-		case TVA_Top:
-			vertOffset = 0;
-			break;
-		case TVA_Bottom:
-			vertOffset = std::max(0, (INT32)(desc.height - curHeight));
-			break;
-		case TVA_Center:
-			vertOffset = std::max(0, (INT32)(desc.height - curHeight)) / 2;
-			break;
-		}
-
 		// Resize cached mesh array to needed size
 		if(mCachedRenderElements.size() > quadsPerPage.size())
 		{
@@ -104,6 +82,26 @@ namespace BansheeEngine
 			texPage++;
 		}
 
+		UINT32 curHeight = 0;
+		for(auto& line : lines)
+			curHeight += line.getYOffset();
+
+		// Calc vertical alignment offset
+		UINT32 vertDiff = std::max(0U, desc.height - curHeight);
+		UINT32 vertOffset = 0;
+		switch(desc.vertAlign)
+		{
+		case TVA_Top:
+			vertOffset = 0;
+			break;
+		case TVA_Bottom:
+			vertOffset = std::max(0, (INT32)vertDiff);
+			break;
+		case TVA_Center:
+			vertOffset = std::max(0, (INT32)vertDiff) / 2;
+			break;
+		}
+
 		// Calc horizontal alignment offset and set final line positions
 		Int2 offset = getAnchorOffset(desc.anchor, desc.width, desc.height);
 		UINT32 numPages = (UINT32)quadsPerPage.size();
@@ -138,8 +136,8 @@ namespace BansheeEngine
 				UINT32 numVertices = writtenQuads * 4;
 				for(size_t i = 0; i < numVertices; i++)
 				{
-					renderElem.vertices[offset + i].x += (float)position.x;
-					renderElem.vertices[offset + i].y += (float)position.y;
+					renderElem.vertices[offset * 4 + i].x += (float)position.x;
+					renderElem.vertices[offset * 4 + i].y += (float)position.y;
 				}
 
 				faceOffsets[j] += writtenQuads;
@@ -149,9 +147,7 @@ namespace BansheeEngine
 		if(desc.clipRect.width > 0 && desc.clipRect.height > 0)
 		{
 			for(auto& renderElem : mCachedRenderElements)
-			{
 				clipToRect(renderElem.vertices, renderElem.uvs, renderElem.numQuads, desc.clipRect);
-			}
 		}
 
 		// Apply offset
@@ -167,4 +163,94 @@ namespace BansheeEngine
 
 		updateBounds();
 	}
+
+	void TextSprite::getTextVertices(const TEXT_SPRITE_DESC& desc, CM::Vector2* vertices, CM::Vector2* uvs)
+	{
+		std::shared_ptr<TextUtility::TextData> textData = TextUtility::getTextData(desc.text, desc.font, desc.fontSize, desc.width, desc.height, desc.wordWrap);
+
+		if(textData == nullptr)
+			return;
+
+		const CM::Vector<TextUtility::TextLine>::type& lines = textData->getLines();
+		const CM::Vector<UINT32>::type& quadsPerPage = textData->getNumQuadsPerPage();
+
+		UINT32 numQuads = 0;
+		for(auto& quads : quadsPerPage)
+			numQuads += quads;
+
+		UINT32 curHeight = 0;
+		for(auto& line : lines)
+			curHeight += line.getYOffset();
+
+		// Calc vertical alignment offset
+		UINT32 vertDiff = std::max(0U, desc.height - curHeight);
+		UINT32 vertOffset = 0;
+		switch(desc.vertAlign)
+		{
+		case TVA_Top:
+			vertOffset = 0;
+			break;
+		case TVA_Bottom:
+			vertOffset = std::max(0, (INT32)vertDiff);
+			break;
+		case TVA_Center:
+			vertOffset = std::max(0, (INT32)vertDiff) / 2;
+			break;
+		}
+
+		// Calc horizontal alignment offset and set final line positions
+		Int2 offset = getAnchorOffset(desc.anchor, desc.width, desc.height);
+		UINT32 curY = 0;
+		UINT32 numPages = (UINT32)quadsPerPage.size();
+		UINT32 quadOffset = 0;
+		for(size_t i = 0; i < lines.size(); i++)
+		{
+			UINT32 horzOffset = 0;
+			switch(desc.horzAlign)
+			{
+			case THA_Left:
+				horzOffset = 0;
+				break;
+			case THA_Right:
+				horzOffset = std::max(0, (INT32)(desc.width - lines[i].getWidth()));
+				break;
+			case THA_Center:
+				horzOffset = std::max(0, (INT32)(desc.width - lines[i].getWidth())) / 2;
+				break;
+			}
+
+			Int2 position = offset + Int2(horzOffset, vertOffset + curY);
+			curY += lines[i].getYOffset();
+
+			for(size_t j = 0; j < numPages; j++)
+			{
+				// TODO - fillBuffer won't accept null uv or indexes
+				UINT32 writtenQuads = lines[i].fillBuffer((UINT32)j, vertices, uvs, nullptr, quadOffset, numQuads);
+
+				UINT32 numVertices = writtenQuads * 4;
+				for(size_t i = 0; i < numVertices; i++)
+				{
+					vertices[quadOffset * 4 + i].x += (float)position.x;
+					vertices[quadOffset * 4 + i].y += (float)position.y;
+				}
+
+				quadOffset += writtenQuads;
+			}
+		}
+
+		if(desc.clipRect.width > 0 && desc.clipRect.height > 0)
+		{
+			clipToRect(vertices, uvs, numQuads, desc.clipRect);
+		}
+
+		// Apply offset
+		{
+			UINT32 numVertices = numQuads * 4;
+			for(size_t i = 0; i < numVertices; i++)
+			{
+				vertices[i].x += (float)desc.offset.x;
+				vertices[i].y += (float)desc.offset.y;
+			}
+		}
+	}
 }

+ 17 - 11
CamelotCore/Source/CmTextUtility.cpp

@@ -219,17 +219,23 @@ namespace CamelotFramework
 					vertices[curVert + 2] = Vector2((float)curX, (float)curY + (float)charIter->height);
 					vertices[curVert + 3] = Vector2((float)(curX + charIter->width), (float)curY + (float)charIter->height);
 
-					uvs[curVert + 0] = Vector2(charIter->uvX, charIter->uvY);
-					uvs[curVert + 1] = Vector2(charIter->uvX + charIter->uvWidth, charIter->uvY);
-					uvs[curVert + 2] = Vector2(charIter->uvX, charIter->uvY + charIter->uvHeight);
-					uvs[curVert + 3] = Vector2(charIter->uvX + charIter->uvWidth, charIter->uvY + charIter->uvHeight);
-
-					indexes[curIndex + 0] = curVert + 0;
-					indexes[curIndex + 1] = curVert + 1;
-					indexes[curIndex + 2] = curVert + 2;
-					indexes[curIndex + 3] = curVert + 1;
-					indexes[curIndex + 4] = curVert + 3;
-					indexes[curIndex + 5] = curVert + 2;
+					if(uvs != nullptr)
+					{
+						uvs[curVert + 0] = Vector2(charIter->uvX, charIter->uvY);
+						uvs[curVert + 1] = Vector2(charIter->uvX + charIter->uvWidth, charIter->uvY);
+						uvs[curVert + 2] = Vector2(charIter->uvX, charIter->uvY + charIter->uvHeight);
+						uvs[curVert + 3] = Vector2(charIter->uvX + charIter->uvWidth, charIter->uvY + charIter->uvHeight);
+					}
+
+					if(indexes != nullptr)
+					{
+						indexes[curIndex + 0] = curVert + 0;
+						indexes[curIndex + 1] = curVert + 1;
+						indexes[curIndex + 2] = curVert + 2;
+						indexes[curIndex + 3] = curVert + 1;
+						indexes[curIndex + 4] = curVert + 3;
+						indexes[curIndex + 5] = curVert + 2;
+					}
 
 					offset++;
 					numQuads++;