// @param It must be a valid initialized text iterator
// @param Font 0 is silently ignored
FVector2D ComputeTextSize(FTextIterator It, class UFont* Font,
	float XScale, float YScale, float HorizSpacingAdjust)
{
	FVector2D Ret(0, 0);

	if(!Font)
	{
		return Ret;
	}

	const float CharIncrement = ( (float)Font->Kerning + HorizSpacingAdjust ) * XScale;

	float LineX = 0;

	const int32 PageIndex = 0;

	int32 Ch;
	while (It.NextCharacterInLine(Ch))
	{
		Ch = (int32)Font->RemapChar(Ch);

		if(!Font->Characters.IsValidIndex(Ch + PageIndex))
		{
			continue;
		}

		FFontCharacter& Char = Font->Characters[Ch + PageIndex];

		if(!Font->Textures.IsValidIndex(Char.TextureIndex))
		{
			continue;
		}

		UTexture2D* Tex = Font->Textures[Char.TextureIndex];

		if(Tex)
		{
			FIntPoint ImportedTextureSize = Tex->GetImportedSize();
			FVector2D InvTextureSize(1.0f / (float)ImportedTextureSize.X, 1.0f / (float)ImportedTextureSize.Y);

			const float X		= LineX;
			const float Y		= Char.VerticalOffset * YScale;
			float SizeX			= Char.USize * XScale;
			const float SizeY	= Char.VSize * YScale;
			const float U		= Char.StartU * InvTextureSize.X;
			const float V		= Char.StartV * InvTextureSize.Y;
			const float SizeU	= Char.USize * InvTextureSize.X;
			const float SizeV	= Char.VSize * InvTextureSize.Y;

			float Right = X + SizeX;
			float Bottom = Y + SizeY;

			Ret.X = FMath::Max(Ret.X, Right);
			Ret.Y = FMath::Max(Ret.Y, Bottom);

			// if we have another non-whitespace character to render, add the font's kerning.
			int32 NextCh;
			if( It.Peek(NextCh) && !FChar::IsWhitespace(NextCh) )
			{
				SizeX += CharIncrement;
			}

			LineX += SizeX;
		}
	}

	return Ret;
}
/**
* For the given text, constructs a mesh to be used by the vertex factory for rendering.
*/
bool  FTextRenderSceneProxy::BuildStringMesh( TArray<FDynamicMeshVertex>& OutVertices, TArray<uint16>& OutIndices )
{
	if(!Font || Text.IsEmpty())
	{
		return false;
	}

	float FirstLineHeight = -1; // Only kept around for legacy positioning support
	float StartY = 0;

	const float CharIncrement = ( (float)Font->Kerning + HorizSpacingAdjust ) * XScale;

	float LineX = 0;

	const int32 PageIndex = 0;

	FTextIterator It(*Text.ToString());
	while (It.NextLine())
	{
		FVector2D LineSize = ComputeTextSize(It, Font, XScale, YScale, HorizSpacingAdjust);
		float StartX = ComputeHorizontalAlignmentOffset(LineSize, HorizontalAlignment);

		if (FirstLineHeight < 0)
		{
			FirstLineHeight = LineSize.Y;
		}

		LineX = 0;
		int32 Ch;

		while (It.NextCharacterInLine(Ch))
		{
			Ch = (int32)Font->RemapChar(Ch);

			if(!Font->Characters.IsValidIndex(Ch + PageIndex))
			{
				continue;
			}

			FFontCharacter& Char = Font->Characters[Ch + PageIndex];

			if(!Font->Textures.IsValidIndex(Char.TextureIndex))
			{
				continue;
			}

			UTexture2D* Tex = Font->Textures[Char.TextureIndex];

			if(Tex)
			{
				FIntPoint ImportedTextureSize = Tex->GetImportedSize();
				FVector2D InvTextureSize(1.0f / (float)ImportedTextureSize.X, 1.0f / (float)ImportedTextureSize.Y);

				const float X      = LineX + StartX;
				const float Y      = StartY + Char.VerticalOffset * YScale;
				float SizeX = Char.USize * XScale;
				const float SizeY = Char.VSize * YScale;
				const float U		= Char.StartU * InvTextureSize.X;
				const float V		= Char.StartV * InvTextureSize.Y;
				const float SizeU	= Char.USize * InvTextureSize.X;
				const float SizeV	= Char.VSize * InvTextureSize.Y;			

				float Left = X;
				float Top = Y;
				float Right = X + SizeX;
				float Bottom = Y + SizeY;

				// axis choice and sign to get good alignment when placed on surface
				FVector4 V0 = FVector4(0, -Left, -Top, 0);
				FVector4 V1 = FVector4(0, -Right, -Top, 0);
				FVector4 V2 = FVector4(0, -Left, -Bottom, 0);
				FVector4 V3 = FVector4(0, -Right, -Bottom, 0);

				FVector TangentX(0, -1, 0);
				FVector TangentY(0, 0, -1);
				FVector TangentZ(1, 0, 0);

				int32 V00 = OutVertices.Add(FDynamicMeshVertex(V0, TangentX, TangentZ, FVector2D(U, V), TextRenderColor));
				int32 V10 = OutVertices.Add(FDynamicMeshVertex(V1, TangentX, TangentZ, FVector2D(U + SizeU, V), TextRenderColor));
				int32 V01 = OutVertices.Add(FDynamicMeshVertex(V2, TangentX, TangentZ, FVector2D(U, V + SizeV), TextRenderColor));
				int32 V11 = OutVertices.Add(FDynamicMeshVertex(V3, TangentX, TangentZ, FVector2D(U + SizeU, V + SizeV), TextRenderColor));

				check(V00 < 65536);
				check(V10 < 65536);
				check(V01 < 65536);
				check(V11 < 65536);

				OutIndices.Add(V00);
				OutIndices.Add(V11);
				OutIndices.Add(V10);

				OutIndices.Add(V00);
				OutIndices.Add(V01);
				OutIndices.Add(V11);

				// if we have another non-whitespace character to render, add the font's kerning.
				int32 NextChar;
				if( It.Peek(NextChar) && !FChar::IsWhitespace(NextChar) )
				{
					SizeX += CharIncrement;
				}

				LineX += SizeX;
			}
		}

		// Move Y position down to next line. If the current line is empty, move by max char height in font
		StartY += LineSize.Y > 0 ? LineSize.Y : Font->GetMaxCharHeight();
	}

	// Avoid initializing RHI resources when no vertices are generated.
	return (OutVertices.Num() > 0);
}
Ejemplo n.º 3
0
void FCanvasTextItem::DrawStringInternal( class FCanvas* InCanvas, const FVector2D& DrawPos, const FLinearColor& InColour )
{		
	DrawnSize.X = 0.0f;
	FHitProxyId HitProxyId = InCanvas->GetHitProxyId();
	FTexture* LastTexture = NULL;
	UTexture2D* Tex = NULL;
	FVector2D InvTextureSize(1.0f,1.0f);
	const TArray< TCHAR >& Chars = Text.ToString().GetCharArray();
	// Draw all characters in string.
	for( int32 i=0; i < TextLen; i++ )
	{
		int32 Ch = (int32)Font->RemapChar(Chars[i]);

		// Process character if it's valid.
		if( Font->Characters.IsValidIndex(Ch) )
		{
			FFontCharacter& Char = Font->Characters[Ch];
			if( Font->Textures.IsValidIndex(Char.TextureIndex) && 
				(Tex=Font->Textures[Char.TextureIndex])!=NULL && 
				Tex->Resource != NULL )
			{
				if( LastTexture != Tex->Resource || BatchedElements == NULL )
				{
					FBatchedElementParameters* BatchedElementParameters = NULL;
					BatchedElements = InCanvas->GetBatchedElements(FCanvas::ET_Triangle, BatchedElementParameters, Tex->Resource, BlendMode, FontRenderInfo.GlowInfo);
					check(BatchedElements != NULL);
					// trade-off between memory and performance by pre-allocating more reserved space 
					// for the triangles/vertices of the batched elements used to render the text tiles
					//BatchedElements->AddReserveTriangles(TextLen*2,Tex->Resource,BlendMode);
					//BatchedElements->AddReserveVertices(TextLen*4);

					FIntPoint ImportedTextureSize = Tex->GetImportedSize();
					InvTextureSize.X = 1.0f / (float)ImportedTextureSize.X;
					InvTextureSize.Y = 1.0f / (float)ImportedTextureSize.Y;
				}
				LastTexture = Tex->Resource;

				const float X		= DrawnSize.X + DrawPos.X;
				const float Y		= DrawPos.Y + + Char.VerticalOffset * YScale;
				float SizeX			= Char.USize * XScale;
				const float SizeY	= Char.VSize * YScale;
				const float U		= Char.StartU * InvTextureSize.X;
				const float V		= Char.StartV * InvTextureSize.Y;
				const float SizeU	= Char.USize * InvTextureSize.X;
				const float SizeV	= Char.VSize * InvTextureSize.Y;				

				float Left, Top, Right, Bottom;
				Left = X * Depth;
				Top = Y * Depth;
				Right = (X + SizeX) * Depth;
				Bottom = (Y + SizeY) * Depth;

				int32 V00 = BatchedElements->AddVertex(
					FVector4( Left, Top, 0.f, Depth ),
					FVector2D( U, V ),
					InColour,
					HitProxyId );
				int32 V10 = BatchedElements->AddVertex(
					FVector4( Right, Top, 0.0f, Depth ),
					FVector2D( U + SizeU, V ),			
					InColour,
					HitProxyId );
				int32 V01 = BatchedElements->AddVertex(
					FVector4( Left, Bottom, 0.0f, Depth ),
					FVector2D( U, V + SizeV ),	
					InColour,
					HitProxyId);
				int32 V11 = BatchedElements->AddVertex(
					FVector4( Right, Bottom, 0.0f, Depth ),
					FVector2D( U + SizeU, V + SizeV ),
					InColour,
					HitProxyId);

				BatchedElements->AddTriangle(V00, V10, V11, Tex->Resource, BlendMode, FontRenderInfo.GlowInfo);
				BatchedElements->AddTriangle(V00, V11, V01, Tex->Resource, BlendMode, FontRenderInfo.GlowInfo);

				// if we have another non-whitespace character to render, add the font's kerning.
				if ( Chars[i+1] && !FChar::IsWhitespace(Chars[i+1]) )
				{
					SizeX += CharIncrement;
				}

				// Update the current rendering position
				DrawnSize.X += SizeX;
			}
		}
	}
}