Browse Source

Added text sprite clipping

Marko Pintera 12 years ago
parent
commit
af247e8381

+ 1 - 0
CamelotCore/Include/CmSprite.h

@@ -106,6 +106,7 @@ namespace CamelotEngine
 
 		void setDirty() { mIsDirty = true; }
 		Point getAnchorOffset() const;
+		bool isClipRectangleValid() const;
 
 		virtual void updateMesh() const = 0;
 		void clearMesh() const;

+ 2 - 0
CamelotCore/Include/CmTextSprite.h

@@ -45,5 +45,7 @@ namespace CamelotEngine
 		virtual void updateMesh() const;
 
 		const FontData* getFontData() const;
+
+		void clipToRect(Vector2* vertices, Vector2* uv, UINT32 numQuads, Rect clipRect) const;
 	};
 }

+ 5 - 0
CamelotCore/Source/CmSprite.cpp

@@ -98,6 +98,11 @@ namespace CamelotEngine
 		return Point();
 	}
 
+	bool Sprite::isClipRectangleValid() const
+	{
+		return mClipRect.width > 0 && mClipRect.height > 0;
+	}
+
 	void Sprite::clearMesh() const
 	{
 		for(auto& renderElem : mCachedRenderElements)

+ 70 - 3
CamelotCore/Source/CmTextSprite.cpp

@@ -3,6 +3,7 @@
 #include "CmFontDesc.h"
 #include "CmFont.h"
 #include "CmVector2.h"
+#include "CmMath.h"
 #include "CmGUIMaterialManager.h"
 
 namespace CamelotEngine
@@ -386,9 +387,13 @@ namespace CamelotEngine
 		for(size_t i = 0; i < textLines.size(); i++)
 			delete textLines[i];
 
-		// TODO - Clip the mesh based on mWidth/mHeight
-		
-		// TODO - How do I implement a scrollable text area without a clip rect?
+		if(isClipRectangleValid())
+		{
+			for(auto& renderElem : mCachedRenderElements)
+			{
+				clipToRect(renderElem.vertices, renderElem.uvs, renderElem.numQuads, mClipRect);
+			}
+		}
 	}
 
 	const FontData* TextSprite::getFontData() const
@@ -400,4 +405,66 @@ namespace CamelotEngine
 
 		return mFont->getFontDataForSize(nearestSize);
 	}
+
+	// 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 TextSprite::clipToRect(Vector2* vertices, Vector2* uv, UINT32 numQuads, Rect clipRect) const
+	{
+		float left = (float)clipRect.x;
+		float right = (float)clipRect.x + clipRect.width;
+		float top = (float)clipRect.y;
+		float bottom = (float)clipRect.y - clipRect.height;
+
+		for(UINT32 i = 0; i < numQuads; i++)
+		{
+			UINT32 vertIdx = i * 4;
+
+			// Attempt to skip those that are definitely not clipped
+			if(vertices[vertIdx + 0].x >= left && vertices[vertIdx + 1].x <= right &&
+				vertices[vertIdx + 0].y <= top && vertices[vertIdx + 2].y >= bottom)
+			{
+				continue;
+			}
+
+			float du = (uv[vertIdx + 1].x - uv[vertIdx + 0].x) / (vertices[vertIdx + 1].x - vertices[vertIdx + 0].x);
+			float dv = (uv[vertIdx + 0].y - uv[vertIdx + 2].y) / (vertices[vertIdx + 0].y - vertices[vertIdx + 2].y);
+
+			// Clip left
+			float newLeft = Math::Clamp(vertices[vertIdx + 0].x, left, right);
+			float uvLeftOffset = (newLeft - vertices[vertIdx + 0].x) * du;
+
+			vertices[vertIdx + 0].x = newLeft;
+			vertices[vertIdx + 2].x = newLeft;
+			uv[vertIdx + 0].x += uvLeftOffset;
+			uv[vertIdx + 2].x += uvLeftOffset;
+
+			// Clip right
+			float newRight = Math::Clamp(vertices[vertIdx + 1].x, left, right);
+			float uvRightOffset = (vertices[vertIdx + 1].x - newRight) * du;
+
+			vertices[vertIdx + 1].x = newRight;
+			vertices[vertIdx + 3].x = newRight;
+			uv[vertIdx + 1].x -= uvRightOffset;
+			uv[vertIdx + 3].x -= uvRightOffset;
+
+			// Clip top
+			float newTop = Math::Clamp(vertices[vertIdx + 0].y, bottom, top);
+			float uvTopOffset = (vertices[vertIdx + 0].y - newTop) * dv;
+
+			vertices[vertIdx + 0].y = newTop;
+			vertices[vertIdx + 1].y = newTop;
+			uv[vertIdx + 0].y -= uvTopOffset;
+			uv[vertIdx + 1].y -= uvTopOffset;
+
+			// Clip bottom
+			float newBottom = Math::Clamp(vertices[vertIdx + 2].y, bottom, top);
+			float uvBottomOffset = (newBottom - vertices[vertIdx + 2].y) * dv;
+
+			vertices[vertIdx + 2].y = newBottom;
+			vertices[vertIdx + 3].y = newBottom;
+			uv[vertIdx + 2].y += uvBottomOffset;
+			uv[vertIdx + 3].y += uvBottomOffset;
+		}
+	}
 }

+ 4 - 3
TODO.txt

@@ -21,13 +21,14 @@ Figure out how to store texture references in a font?
 
 Move Debug to CamelotCore and add SetFillMode
 
+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
+
 Immediate TODO:
-Add clone() method to Materials
 Implement image shader for D3D11BuiltinMaterialManager
 Improve text shader so it doesn't have resolution values hardcoded in
-Start-up D3D11BuiltinMaterialManager
 Implement D3D9 and GL BuiltInMaterialManager
-Start-up GUIManager
 
 
 Test: