PHOBOSLAB

Blog Home

Yuckfu Dev Diary #5 – OpenGL, Fonts and You

After my last post I read a bit more about displaying text with OpenGL. One of the more popular solutions is to have a single texture containing all (ASCII) characters of a font. As it turned out, there are several applications to build such a texture for you. Bitmap Font Builder is one of them. It looks a bit clunky, but gets the job done nicely – and it’s free!

Helvetica Font-Map Here’s a quick test I did with the Helvetica typeface. I exported the texture as a transparent PNG file, cropped it and added a simple drop shadow effect in Photoshop. For now, I only used the upper case letters. I’ll probably come back later and export the full set of Latin-1 characters.

Bitmap Font Builder can also export an INI file with the pixel width of each character. I used a simple Regular Expression to convert this into a comma separated list, so I can use it directly in C.

const unsigned char charWidthMap[] = { 
//    ! " # $ %  & ' ( ) * + , - . /
    3,4,6,6,6,10,8,3,4,4,5,8,3,5,3,4,
//  0 1 2 3 4 5 6 7 8 9 : ; < = > ?
    6,6,6,6,6,6,6,6,6,6,3,3,8,8,8,6,
//  @  A B C D E F G H I J K L M  N O
    10,7,7,7,7,6,6,7,7,3,6,7,6,10,7,7,
//  P Q R S T U V W  X Y Z
    7,7,7,7,6,7,7,10,7,7,6 
};

To prepare displaying text on top of my 3D scene, I push the current projection matrix to the stack, load an orthographic (2D) view matrix and disable depth testing and lighting. I can then render my previously computed arrays of vertices and texture coordinates for a particular string in screen space. The vertex coordinates for each character are computed based on the previous characters width.

int offset = 0;
for( int i = 0; text[i] != 0; i++ ) {
    vertices[0].x = offset; // top left
    vertices[0].y = 0;
    …
    vertices[3].x = offset + charSizeInTexture.x; // bottom right
    vertices[3].y = charSizeInTexture.y;

    // Increase the offset for the next character.
    // My charWidthMap starts at ASCII character 32 (space)
    offset += charWidthMap[ text[i] - 32 ];
}

The normalized texture coordinates for each character are computed based on its position in the texture. E.g. for the top left corner:

int x = ((text[i] - 32) % charsPerRow) * charSizeInTexture.x;
int y = ((text[i] - 32) / charsPerRow) * charSizeInTexture.y;
texCoords[0].x = (float)x / textureSize.x;
texCoords[0].y = (float)y / textureSize.y;

OpenGL Text on iPhone As you can see, the result looks pretty good. I’ve got a proportional, anti aliased font with a nice shadow effect that blends in perfectly with the 3D scene. Still, no kerning (look at the spacing between the W and A in “WAR”), but I can live with that – after all, it’s an arcade game not an E-Book reader.

Update: Bitmap Font Builder is only free for non-commercial projects, but there are alternatives. On the other hand, with the current dollar course, I could also spend some 20 bucks.

Update 2: But then again, why pay for something that can be easily implemented with Javascript/HTML?

Saturday, August 16th 2008
— Dominic Szablewski, @phoboslab

3 Comments:

#1 – roli – Tuesday, August 19th 2008, 22:41

heya, what about a rss feed of your blog? :)

#2Dominic – Wednesday, August 20th 2008, 05:39

There is a feed; there always was: www.phoboslab.org/log/feed

Maybe not linking to it and instead relying on the browser to display the feed options isn't such a good idea after all. I'll add a link in the welcome text...

#3 – roli – Thursday, August 21st 2008, 15:25

thanks! my opera probably doesn't show because i disabled the built-in rssreader.

Post a Comment:

Comment: (Required)

(use <code> tags for preformatted text; URLs are recognized automatically)

Name: (Required)

Please type phoboslab into the following input field or enable Javascript. This is an anti-spam measure. Sorry for the inconvenience.