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; }
 		void setDirty() { mIsDirty = true; }
 		Point getAnchorOffset() const;
 		Point getAnchorOffset() const;
+		bool isClipRectangleValid() const;
 
 
 		virtual void updateMesh() const = 0;
 		virtual void updateMesh() const = 0;
 		void clearMesh() const;
 		void clearMesh() const;

+ 2 - 0
CamelotCore/Include/CmTextSprite.h

@@ -45,5 +45,7 @@ namespace CamelotEngine
 		virtual void updateMesh() const;
 		virtual void updateMesh() const;
 
 
 		const FontData* getFontData() 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();
 		return Point();
 	}
 	}
 
 
+	bool Sprite::isClipRectangleValid() const
+	{
+		return mClipRect.width > 0 && mClipRect.height > 0;
+	}
+
 	void Sprite::clearMesh() const
 	void Sprite::clearMesh() const
 	{
 	{
 		for(auto& renderElem : mCachedRenderElements)
 		for(auto& renderElem : mCachedRenderElements)

+ 70 - 3
CamelotCore/Source/CmTextSprite.cpp

@@ -3,6 +3,7 @@
 #include "CmFontDesc.h"
 #include "CmFontDesc.h"
 #include "CmFont.h"
 #include "CmFont.h"
 #include "CmVector2.h"
 #include "CmVector2.h"
+#include "CmMath.h"
 #include "CmGUIMaterialManager.h"
 #include "CmGUIMaterialManager.h"
 
 
 namespace CamelotEngine
 namespace CamelotEngine
@@ -386,9 +387,13 @@ namespace CamelotEngine
 		for(size_t i = 0; i < textLines.size(); i++)
 		for(size_t i = 0; i < textLines.size(); i++)
 			delete textLines[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
 	const FontData* TextSprite::getFontData() const
@@ -400,4 +405,66 @@ namespace CamelotEngine
 
 
 		return mFont->getFontDataForSize(nearestSize);
 		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
 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:
 Immediate TODO:
-Add clone() method to Materials
 Implement image shader for D3D11BuiltinMaterialManager
 Implement image shader for D3D11BuiltinMaterialManager
 Improve text shader so it doesn't have resolution values hardcoded in
 Improve text shader so it doesn't have resolution values hardcoded in
-Start-up D3D11BuiltinMaterialManager
 Implement D3D9 and GL BuiltInMaterialManager
 Implement D3D9 and GL BuiltInMaterialManager
-Start-up GUIManager
 
 
 
 
 Test:
 Test: