浏览代码

Fixed issue with text rendering where spaces were being rendered as invalid glyphs

Marko Pintera 12 年之前
父节点
当前提交
97589a7a46
共有 4 个文件被更改,包括 68 次插入38 次删除
  1. 3 3
      CamelotClient/CamelotClient.cpp
  2. 18 0
      CamelotCore/Include/CmSceneObject.h
  3. 47 21
      CamelotCore/Source/CmTextSprite.cpp
  4. 0 14
      TODO.txt

+ 3 - 3
CamelotClient/CamelotClient.cpp

@@ -66,8 +66,8 @@ int CALLBACK WinMain(
 	HSceneObject testModelGO = SceneObject::create("TestMesh");
 	HRenderable testRenderable = testModelGO->addComponent<Renderable>();
 
-	//HSceneObject testTextGO = SceneObject::create("TestText");
-	//GameObjectHandle<TestTextSprite> textSprite = testTextGO->addComponent<TestTextSprite>();
+	HSceneObject testTextGO = SceneObject::create("TestText");
+	GameObjectHandle<TestTextSprite> textSprite = testTextGO->addComponent<TestTextSprite>();
 
 	HFont font;
 	
@@ -85,7 +85,7 @@ int CALLBACK WinMain(
 		font = Importer::instance().import("C:\\arial.ttf", fontImportOptions);
 	}
 
-	//textSprite->setText(camera, "TESTfAV", font, 12);
+	textSprite->setText(camera, "Testing in a new row, does this work?", font, 12);
 
 #if defined DX9
 	///////////////// HLSL 9 SHADERS //////////////////////////

+ 18 - 0
CamelotCore/Include/CmSceneObject.h

@@ -245,6 +245,24 @@ namespace CamelotEngine
 			return static_object_cast<T>(getComponent(T::getRTTIStatic()->getRTTIId()));
 		}
 
+		/**
+		 * @brief	Checks if the current object contains the specified component
+		 * 			 			
+		 * @note	Don't call this too often as it is relatively slow. 
+		 *
+		 * @tparam	typename T	Type of the component.
+		 *
+		 * @return	True if component exists on the object.
+		 */
+		template <typename T>
+		bool hasComponent()
+		{
+			BOOST_STATIC_ASSERT_MSG((boost::is_base_of<CamelotEngine::Component, T>::value), 
+				"Specified type is not a valid Component.");
+
+			return hasComponent(T::getRTTIStatic()->getRTTIId());
+		}
+
 		/**
 		 * @brief	Searches for a component with the specified type id and returns the first one it
 		 * 			finds.

+ 47 - 21
CamelotCore/Source/CmTextSprite.cpp

@@ -14,7 +14,7 @@ namespace CamelotEngine
 	{
 	public:
 		TextWord(bool spacer)
-			:mWidth(0), mSpacer(spacer)
+			:mWidth(0), mSpacer(spacer), mSpaceWidth(0)
 		{ }
 
 		void addChar(const CHAR_DESC& desc)
@@ -24,6 +24,11 @@ namespace CamelotEngine
 			calculateWidth();
 		}
 
+		void addSpace(UINT32 spaceWidth)
+		{
+			mSpaceWidth += spaceWidth;
+		}
+
 		void removeLastChar()
 		{
 			if(mChars.size() > 0)
@@ -42,9 +47,16 @@ namespace CamelotEngine
 		vector<CHAR_DESC>::type mChars;
 		UINT32 mWidth;
 		bool mSpacer;
+		UINT32 mSpaceWidth;
 
 		void calculateWidth()
 		{
+			if(isSpacer())
+			{
+				mWidth = mSpaceWidth;
+				return;
+			}
+
 			if(mChars.size() == 0)
 			{
 				mWidth = 0;
@@ -91,7 +103,7 @@ namespace CamelotEngine
 		{
 			if(mLastWord == nullptr)
 			{
-				TextWord* newWord = CM_NEW(TextWord, ScratchAlloc) TextWord(charDesc.charId == SPACE_CHAR);
+				TextWord* newWord = CM_NEW(TextWord, ScratchAlloc) TextWord(false);
 				mLastWord = newWord;
 
 				mWords.push_back(mLastWord);
@@ -100,27 +112,39 @@ namespace CamelotEngine
 			}
 			else
 			{
-				if(charDesc.charId != SPACE_CHAR)
-				{
-					if(mLastWord->isSpacer())
-					{
-						TextWord* newWord = CM_NEW(TextWord, ScratchAlloc) TextWord(false);
-						mLastWord = newWord;
-
-						mWords.push_back(mLastWord);
-					}
-
-					mLastWord->addChar(charDesc);
-				}
-				else
+				if(mLastWord->isSpacer())
 				{
-					TextWord* newWord = CM_NEW(TextWord, ScratchAlloc) TextWord(true); // Each space is counted as its own word, to make certain operations easier
+					TextWord* newWord = CM_NEW(TextWord, ScratchAlloc) TextWord(false);
 					mLastWord = newWord;
 
 					mWords.push_back(mLastWord);
-
-					mLastWord->addChar(charDesc);
 				}
+
+				mLastWord->addChar(charDesc);
+			}
+
+			calculateBounds();
+		}
+
+		void addSpace(UINT32 spaceWidth)
+		{
+			if(mLastWord == nullptr)
+			{
+				TextWord* newWord = CM_NEW(TextWord, ScratchAlloc) TextWord(true);
+				mLastWord = newWord;
+
+				mWords.push_back(mLastWord);
+
+				mLastWord->addSpace(spaceWidth);
+			}
+			else
+			{
+				TextWord* newWord = CM_NEW(TextWord, ScratchAlloc) TextWord(true); // Each space is counted as its own word, to make certain operations easier
+				mLastWord = newWord;
+
+				mWords.push_back(mLastWord);
+
+				mLastWord->addSpace(spaceWidth);
 			}
 
 			calculateBounds();
@@ -292,15 +316,17 @@ namespace CamelotEngine
 			UINT32 charId = mText[charIdx];
 			const CHAR_DESC& charDesc = fontData->getCharDesc(charId);
 
-			curLine->add(charDesc);
-
-			if(charDesc.charId != SPACE_CHAR)
+			if(charId != SPACE_CHAR)
 			{
+				curLine->add(charDesc);
+
 				if(charDesc.page >= (UINT32)newRenderElemSizes.size())
 					newRenderElemSizes.resize(charDesc.page + 1);
 
 				newRenderElemSizes[charDesc.page]++;
 			}
+			else
+				curLine->addSpace(fontData->fontDesc.spaceWidth);
 
 			if(widthIsLimited && curLine->getWidth() > mWidth)
 			{

+ 0 - 14
TODO.txt

@@ -21,20 +21,6 @@ Figure out how to store texture references in a font?
 
 Move Debug to CamelotCore and add SetFillMode
 
-GameObjectHandle has  SceneObject friend which doesn't make sense
-
-GameObject destructor should be private and only callable by GameObjectHandle
- - This was I can ensure object is only destroyed when calling destroy(), and I can replace internal shared_ptr
-
-Make GameObjectHandle hold a normal pointer instead of a shared one
- - By its definition its guaranteed to have only one reference so there's no need for shared ptr
-
-getVisibleRederables iterates over all gameobjects and calls getType, which will return empty handle if none is found, which is expensive
-
-
-
-
-
 Add TextUtil class
  - Ability to calculate a size of a line (will need this if I want to add "..." to text that doesn't fit)
  - Maybe even move line and word classes to it