Much better font system

Published December 09, 2006
Advertisement
Behold my mighty font file generator:



Written with Builder for quickness, you can specify the characters you want to include in the top edit box, then select any font on my PC with the Font button.

Generate then spits out a file in the format discussed below. The file starts with the number of characters included, then the width of a space character to save rendering a blank quad for spaces, then an index of 256 bytes, each of which either contains -1 or the index into the images for the ASCII character's associated image.

The images then follow with each one as a solid white square with the letter shape expressed through alpha values, in the same format as my existing sprite files.

My D3D library has been extended to include a CTextureFont class that can load one of these files and place the images onto a texture passed to it in the load method, so the font can either be placed on the same texture as the sprites to minimise DrawPrimitive calls, or on a seperate texture if it is needed.

CTextureFont then just has a Draw(X,Y,"A string") that adds the letters to the existing CQuadBuffer using the existing library, so the letters can be placed in the quad buffer along with any other sprites and all can be rendered through a single DrawPrimitive.

I need to add TextExtent methods for measuring the text, and I also need to extend the existing D3D library to allow for passing four different diffuse colours to the quad buffer so I can make shaded letters.

Otherwise, it all seems pretty hunky dorey and no longer requires me to mess about with manually clipping letters out of bitmaps.

Scaling the fonts with D3D doesn't seem to work very well so I'm sticking to a single size per font file. I was going to add the capability to have several different sizes in a single file, but then I thought that it would be more flexible to have a file per size since I can then discard sizes when they are not needed and reload them when they are a lot more easily.

So once the above changes have been finished, the font stuff is pretty much done and I've got no excuse not to get on with the game.

[EDIT] All sorted:



Coloured using the diffuse values and centred on the screen based on a TextExtent type method.

Shame I can't use that font, but I'm not sure where it came from.
Previous Entry Font fun continues
Next Entry Refresh rates
0 likes 3 comments

Comments

Mushu
Wow, the gradient you got with the diffuse color looks really nice. What does your API look like to display that kind of text? (like, how do you tell it to render it with those colors?) I remember Programmer16 made some crazy parser or something that would take a formatted input string with all of the color/formatting information in it, then output it all nice and pretty.

In any case, looks pretty :3
December 10, 2006 03:21 AM
Gaiiden
wish my text in TGB looked that nice *sigh*. Something went awry with their t2dTextObject that came with v1.1.3 - the text renders all choppy.

looks good!
December 10, 2006 04:04 AM
Aardvajk
Why, thank you. I thought it looked pur-etty as well [smile].

To answer Mushu's question, my D3D sprite wrapper defines what I have randomly called a D3DCOLORQUAD, which is just a little POD that contains an array of four D3DCOLORs that correspond to each vertex in clockwise fashion, the same as texture co-ordinates.

There are some little helper functions, like:

D3DCOLORQUAD VerticalColorQuad(D3DCOLOR A,D3DCOLOR B);

used for this example. There's nothing as complex as Programmer16's parser. You just pass a D3DCOLORQUAD as an argument to one of the methods of CQuadBuffer that adds a sprite to the buffer:

void CQuadBuffer::Add(int X,int Y,int W,int H,D3DFLOATRECT Src,D3DCOLORQUAD CQ);

Then one of the CTextureFont's overloaded methods looks like:

void CTextureQuad::Draw(int X,int Y,const char *S,D3DCOLORQUAD CQ);

The render function that draws the above looks a bit like this:


CResult CTitleMode::Render(float Delta,CDevice &Dev,CQuadBuffer &Qu,CTexture &Tex,CTextureFont &Font)
{
	D3DCOLORQUAD CQ=VerticalColorQuad(D3DCOLOR_XRGB(255,0,0),D3DCOLOR_XRGB(255,255,0));
	std::string A="THIS IS A TEST LINE OF TEXT";
	std::string B="HERE IS A BIT MORE";
	std::string C="AND FINALLY ANOTHER LINE THAT IS QUITE LONG";

	Dev.ClearTexture();

	Qu.Begin();
	Qu.Add(0,0,800,600,D3DFLOATRECT(),VerticalColorQuad(D3DCOLOR_XRGB(0,0,0),D3DCOLOR_XRGB(0,0,128)));
	Qu.End();
	
	Dev.Draw(Qu);

	Dev.SetTexture(Tex);

	Qu.Begin();
	int W;

	W=Font.Width(A.c_str());
	Font.Draw(Qu,(800-W)/2,100,A.c_str(),CQ);	

	W=Font.Width(B.c_str());
	Font.Draw(Qu,(800-W)/2,200,B.c_str(),CQ);	

	W=Font.Width(C.c_str());
	Font.Draw(Qu,(800-W)/2,200+Font.Height(),C.c_str(),CQ);	

	Qu.End();
	
	Dev.Draw(Qu);

	return rsOk;
}




Obviously you can also specifiy the alpha as part of the color quad, plus there are overloads to pass just a D3DCOLOR that colours each vertex the same, or no color at all, in which case it defaults to white for all four verticies, so the image appears unchanged.

It is quite flexible and not too verbose to code with. I appreciate that my naming conventions will set a lot of people's teeth on edge, but I find they sit quite nicely with the Win32 and D3D APIs. Obviously adding my own D3DWHATEVER structures is a bit cheeky and would require a rethink if I was writing this for anyone else to use.

I know a lot of you think prefixing complex classes with a capital C is the work of the devil as well. I'm starting to come round to this point of view, but it is far too late for this sprite library since I've actually got a game out in public that depends upon it.
December 10, 2006 04:15 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Profile
Author
Advertisement
Advertisement