Texture Fonts

Home --> Programming Projects --> FPS Game Code --> Texture Fonts

Simple Solution

Suppose we want to render text in a computer game with doing as little work as possible. A nice solution is to have a texture that contains all the ascii characters from 32 to 126 inclusive, and to draw quads with appropriately selected texture coordinates for verticies. For example, we could use the following texture:
Well, we don't actually want to use that picture because it is a .jpg, so we should use the .tga version instead. Notice that this .tga file has an alpha component.

In order to render a string of text, we should first call this command to get OpenGL ready for rendering flat stuff:
void PrepForFlatDrawing() {
    glDisable(GL_CULL_FACE);
    glMatrixMode( GL_PROJECTION );
    glLoadIdentity();
    glOrtho(0, 1, 0, 1, -1, 1);
    glMatrixMode( GL_MODELVIEW );
    glLoadIdentity();
}
Next, we should call the following function:
void DrawScreenText(
    float x, float y,
    float w, float h,
    const string & text)
{
    if( text.size() > 0 ) {
        glBegin(GL_QUADS);
    }

    for (int i = 0; i < (int)text.length(); ++i) {
        unsigned char c = text[i];
        if ( c == 32 )
            c = 128;
		if (c < 33 || c > 128 )
            c = 127;

        float s = (1+32*((int)((c-33)%16))) / 512.0f;
        float t = (1+47*((int)((c-33)/16))) / 512.0f;

        glTexCoord2f(s, t+0.091f);
        glVertex3f(x, y, 0);

        glTexCoord2f(s, t);
        glVertex3f(x, y+h, 0);
        
        glTexCoord2f(s+0.0625f, t);
        glVertex3f(x+w, y+h, 0);

        glTexCoord2f(s+0.0625f, t+0.091f);
        glVertex3f(x+w, y, 0);        
        
        x += w;
    }
    
    if( text.size() > 0 ) {
        glEnd();
    }
}
The texture and the DrawScreenText function are both due to Zach Barth, originally intended for Infinifrag 2.

More General Solution

The texture in the above section was created using photoshop. Suppose we want to modify this texture. We would have to make sure that all the important characters are in the same location, otherwise the function DrawScreenText will not work correctly. Hence, we would have to be very careful.

There are programs that can generate these "font textures". I personally like Bitmap Font Builder, however I am told that the program Bitmap Font Generator is excellent (it outputs Kerning Pairs). When using such a program, the output texture will not necessarily have characters in the same positions as the above texture. For example, this font texture which is used in version 1.0 of Block Arena. What we need is a more general function than DrawScreenText that can use texture coordinates specified by a file.

We can specify the appropriate texture coordinates in a text file with the following format: each line is of the form "ascii_char min_u min_v max_u max_v" The convention is that u = 0 is the left side of the texture, and v = 0 is the bottom of the texture. Here is an example such file to be used with this texture:
32 0.012 0.812 0.050 0.875
33 0.075 0.812 0.113 0.875
34 0.137 0.812 0.175 0.875
35 0.200 0.812 0.238 0.875
36 0.262 0.812 0.300 0.875
37 0.325 0.812 0.363 0.875
38 0.387 0.812 0.425 0.875
39 0.450 0.812 0.488 0.875
40 0.512 0.812 0.550 0.875
41 0.575 0.812 0.613 0.875
42 0.637 0.812 0.675 0.875
43 0.700 0.812 0.738 0.875
44 0.762 0.812 0.800 0.875
45 0.825 0.812 0.863 0.875
46 0.887 0.812 0.925 0.875
47 0.950 0.812 0.988 0.875
48 0.012 0.750 0.050 0.812
49 0.075 0.750 0.113 0.812
50 0.137 0.750 0.175 0.812
51 0.200 0.750 0.238 0.812
52 0.262 0.750 0.300 0.812
53 0.325 0.750 0.363 0.812
54 0.387 0.750 0.425 0.812
55 0.450 0.750 0.488 0.812
56 0.512 0.750 0.550 0.812
57 0.575 0.750 0.613 0.812
58 0.637 0.750 0.675 0.812
59 0.700 0.750 0.738 0.812
60 0.762 0.750 0.800 0.812
61 0.825 0.750 0.863 0.812
62 0.887 0.750 0.925 0.812
63 0.950 0.750 0.988 0.812
64 0.012 0.688 0.050 0.750
65 0.075 0.688 0.113 0.750
66 0.137 0.688 0.175 0.750
67 0.200 0.688 0.238 0.750
68 0.262 0.688 0.300 0.750
69 0.325 0.688 0.363 0.750
70 0.387 0.688 0.425 0.750
71 0.450 0.688 0.488 0.750
72 0.512 0.688 0.550 0.750
73 0.575 0.688 0.613 0.750
74 0.637 0.688 0.675 0.750
75 0.700 0.688 0.738 0.750
76 0.762 0.688 0.800 0.750
77 0.825 0.688 0.863 0.750
78 0.887 0.688 0.925 0.750
79 0.950 0.688 0.988 0.750
80 0.012 0.625 0.050 0.688
81 0.075 0.625 0.113 0.688
82 0.137 0.625 0.175 0.688
83 0.200 0.625 0.238 0.688
84 0.262 0.625 0.300 0.688
85 0.325 0.625 0.363 0.688
86 0.387 0.625 0.425 0.688
87 0.450 0.625 0.488 0.688
88 0.512 0.625 0.550 0.688
89 0.575 0.625 0.613 0.688
90 0.637 0.625 0.675 0.688
91 0.700 0.625 0.738 0.688
92 0.762 0.625 0.800 0.688
93 0.825 0.625 0.863 0.688
94 0.887 0.625 0.925 0.688
95 0.950 0.625 0.988 0.688
96 0.012 0.562 0.050 0.625
97 0.075 0.562 0.113 0.625
98 0.137 0.562 0.175 0.625
99 0.200 0.562 0.238 0.625
100 0.262 0.562 0.300 0.625
101 0.325 0.562 0.363 0.625
102 0.387 0.562 0.425 0.625
103 0.450 0.562 0.488 0.625
104 0.512 0.562 0.550 0.625
105 0.575 0.562 0.613 0.625
106 0.637 0.562 0.675 0.625
107 0.700 0.562 0.738 0.625
108 0.762 0.562 0.800 0.625
109 0.825 0.562 0.863 0.625
110 0.887 0.562 0.925 0.625
111 0.950 0.562 0.988 0.625
112 0.012 0.500 0.050 0.562
113 0.075 0.500 0.113 0.562
114 0.137 0.500 0.175 0.562
115 0.200 0.500 0.238 0.562
116 0.262 0.500 0.300 0.562
117 0.325 0.500 0.363 0.562
118 0.387 0.500 0.425 0.562
119 0.450 0.500 0.488 0.562
120 0.512 0.500 0.550 0.562
121 0.575 0.500 0.613 0.562
122 0.637 0.500 0.675 0.562
123 0.700 0.500 0.738 0.562
124 0.762 0.500 0.800 0.562
125 0.825 0.500 0.863 0.562
126 0.887 0.500 0.925 0.562
The above file was generated by this python script.

It is easy to write a class that reads in the above file on construction and uses this information for drawing text. Here is the header file and here is the source file to accomplish this.

A nice advantage of this more general solution is it allows the end user to completely customize the texture font that is being used (without recompiling)!