Sign in to follow this  

Game Font

This topic is 4714 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hey, I sort of learned a new trick. I actually done something like this before but I’m much happier with my results I have now. Okay, how many of you see cool font being used on games? By cool font I mean multi-colored, gradients and shadows. I’ve see many developers build their font they use in their games as bitmap images. They print text using that image as tiles, or at least that’s what I’m doing. So I parse through a string and calculate the tile(letter) to be drawn. Here is how I did it:
HRESULT __stdcall DDTextOut( int nX, int nY, LPDIRECTDRAWSURFACE7 lpDDSFont, LPCSTR lpszText, ... )
{
	va_list					 Ap;
	CHAR					 szBuffer[ MAX_PATH ];
	int						 nTrail = nX,
							 nFrame = 0;

	// Convert variable argument list
	//
	va_start( Ap, lpszText );

	vsprintf( szBuffer, lpszText, Ap );

	va_end( Ap );

	// Parse the string
	//
	for ( int I = 0; I < ( int )strlen( szBuffer ); I++ )
	{
		if ( szBuffer[ I ] == '.' )
		{
			nFrame = 62;
		}
		else if ( isalpha( szBuffer[ I ] ) )
		{
			if ( isupper( szBuffer[ I ] ) )
			{
				nFrame = ( szBuffer[ I ] - 'A' );
			}
			else
			{
				nFrame = ( szBuffer[ I ] - 'a' ) + 26;
			}
		}
		else if ( isdigit( szBuffer[ I ] ) )
		{
			nFrame = ( szBuffer[ I ] - '0' ) + 52;
		}
		else if ( isspace( szBuffer[ I ] ) )
		{
			nTrail += 16;

			continue;
		}
		else
		{
			nFrame = 63;
		}

		DDBlit( nTrail, nY, nFrame, lpDDSFont );

		nTrail += 22;
	}

	return ( S_OK );
}

The image I use for the font is a 256x256 image that has 64 tiles filled with my custom font I made in Photoshop. I calculate the tile coordinates in the source image by using a special formula. Here is the DDBlit( ) function:
HRESULT __stdcall DDBlit( int nX, int nY, int nFrame, LPDIRECTDRAWSURFACE7 lpDDSSource )
{
	RECT					 rcDst, rcSrc;

	// Calculate destination & source blitting rects
	//
	rcDst.left				 = nX;
	rcDst.top				 = nY;
	rcDst.right				 = nX + 32;
	rcDst.bottom			 = nY + 32;

	rcSrc.left				 = ( nFrame % 8 ) * 32;
	rcSrc.top				 = ( nFrame / 8 ) * 32;
	rcSrc.right				 = rcSrc.left + 32;
	rcSrc.bottom			 = rcSrc.top  + 32;

	g_lpDDSBack->Blt( &rcDst, lpDDSSource, &rcSrc, DDBLT_KEYSRC | DDBLT_WAIT, NULL );

	return ( S_OK );
}

Notice that I use constant values for calculating the source rectangle. I do this because I KNOW that the image is 256x256 and that each of the font tiles are 32x32. This could easily be made into something more flexible but for it will do for testing purposes. Here is the font that I’m using: Font So what do you guys think, cool huh?!

Share this post


Link to post
Share on other sites
Yes, it's rather nice, but that huge if/else system in your printing function could be replaced with a simple (and fast!) table lookup. That is, use an array where you store the coordinates of each character glyph at the index corresponding to the value of that character. Here is something like I have usually done:


// assumes that the glyphs are stored on one row in the image,
// but should be easy to adapt to your system
int offsets[128] = { 0 };
char chars[] = "abcdefghijklmn..." // the characters in the order they are in your image

void init() // constructor if C++
{
char *c = chars; int offset = 0;
for(; *c; ++c)
{
offsets[*c] = offset;
offset += 16; // assume that characters are 16 pixels wide - of course this should not be hardcoded like this
}
}

void draw(const char *str)
{
...
for(; *str; ++str)
{
int offset = offsets[*str];
// now just calculate the source rect using the offset and blit away!
}
}



With some modifications this can be adapted to variable-width fonts too, you just have to also store the glyph's width in the offsets array, and do some additional calculations in the init phase.

Share this post


Link to post
Share on other sites
Hmmm, I though about using something similar to that actually. Like I said, that code could be optimized but its good enough for testing purposes.

When I was working on this last night I came up with some alternatives. One, is to use 16x16 tiles for font. I could fir 128 16x16 tiles on a 256x256 bitmap. That’s perfect amount of tiles because ASCII characters 0-127 are what’s mostly used. I could just use the ASCII decimal value for an offset. Keep in mind though, I would have to add in blank spaces for all those characters that I didn’t use like smiley faces and other weird symbols.

I was also thinking about using a text buffer. The reason for this is because I wanted to use special effects with the test. By special effects I mean blink, scrolling and other thing similar to those. Or I could device a type of markup / scripting language similar to HTML that would make use of special tags that enable text effects. It’s a little complex for something so simple but I would be fun to implement and play around with.

Any ways, I was having lots of fun with this last night so I decided to share it with all of you. Thanks for your comment; I’ll consider them.

Share this post


Link to post
Share on other sites
You might be able to speed up creating your fonts if you use Bitmap Font Builder to create the original black and white version of a font and then use photoshop to add fill, color, gradient, shadow etc. For effects you might consider using an escape sequence (much like using a markup language but simpler) like ^B for bold or ^U for underline etc. Since you already render each character individually I don't see this being a big problem (although I imagine blinking text can cause some trouble) because you just check for an escape sequence whenever you hit the escape character ^, change the way you render the rest of the chars until you hit the end escape sequence or the end of a line. It is up to you really but I have had some small success with this while writing color code for text based games.

Share this post


Link to post
Share on other sites
Not to hijack a thread, but is this the "professional" way of making a font engine? The idea I was mulling about was like the OPs and I didn't think that was the way they actually did it.

Share this post


Link to post
Share on other sites
I'm still curious as to why anyone would use this sort of thing over D3DXFont... [other than the fact that reasonable speed D3DXFont is new]

Especially for us developers with poor artistic skill, D3DXFont is grand, as it allows the use of any common windows font at really any size or language set [no, ASCII chars are *not* the most common...] in very few lines of code.

Share this post


Link to post
Share on other sites
Quote:
Original post by Telastyn
I'm still curious as to why anyone would use this sort of thing over D3DXFont... [other than the fact that reasonable speed D3DXFont is new].


Well, maybe someone who's not using Direc3D? It's Windows-only you know, and even in Windows domain there is an alternative.

Share this post


Link to post
Share on other sites

This topic is 4714 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this