OpenGL:Tutorials:Font System

This page documents a rather simple font system for OpenGL (using C++). It consists of two parts - a command-line tool to generate font files from true type fonts, and a component you add to a program to actually load and draw the font. Blob Shepherd uses this font system.

While there are certain advantages to using the technique described below, some may wish to support loading of TrueType fonts within their OpenGL programs. James Turk has has put together a class (based on this page) that does just that in GLFT_Font.

Note that the texture has only one channel, the intensity of the character at that point. This means it has to be loaded into OpenGL as an alpha texture (GL_ALPHA). When drawing you blend the glyphs onto the screen.

Using fonts in OpenGL

The system to load and display the fonts needs to do a few things:

Load the font texture

Know where each character/glyph is located in the texture

Know the size of glyphs

Draw text to the screen

In C++ this can be conveniently done with a Font class. Objects of this class load in a font when they are created, and release the texture and memory they use when destroyed. It's declaration might look like this:

class Font
{
public:
Font(constchar* file);
~Font();// The line height is constantsize_t Line_Height()const;// Knowing the width of a character or a string can be useful if you// want your UI to look good at all.size_t Char_Width(unsignedchar c)const;size_t String_Width(const std::string& str)const;// Draw a string at a given position.void Draw_String(const std::string& str,float x,float y);
private:// Information about a glyph. Tex_y2 can be calculated from tex_y1// and _tex_line_height (see below). Advance is the width of the// glyph in screen space.struct Glyph
{float tex_x1, tex_y1, tex_x2;size_t advance;};// An array to store the glyphs.
Glyph* _glyphs;// A table to quickly get the glyph belonging to a character.
Glyph* _table[256];// The line height, in screen space and in texture space, and the// OpenGL id of the font texture.size_t _line_height, _texture;float _tex_line_height;};

The constructor of this class does the most work, it has to load the font file and interpret it's contents. Here is a possible way to do this:

This only leaves Draw_String. This function just goes over every character in a string and draws them next to each other. It is left up to the caller to set the projection matrix to orthogonal with 1 unit = 1 pixel, and to enable texturing and blending. The text is drawn using OpenGL's current color.

Possible improvements

This system works, and is quite easy to use. The reason the tool to create font files is a separate program is that this way you won't have to link FreeType with your main program, and loading a font is very fast. If you want your program to be able to load and use arbitrary true type fonts you will have to integrate the functionality of fonttool into your main program.

The file size for fonts is not a real problem at the moment (unless the characters are very big), but it can easily be made smaller by compression. If you use zlib, compressing files is very easy.

Something that always comes up when drawing fonts is line breaking. If you want to show a piece of text on more than one line you'll have to break it up into separate lines. To have things look professional you'll want the line breaks to happen at spaces in the text, not in the middle of words. It would be possible to write a line breaking system that works with this font system to support for example a Broken_String object that contains a string broken up in lines of a specific width and has functions to make drawing the string easy.