Text Rendering Part 1: Font Rendering Basics
- November 25th, 2011
- By Rok Breulj
- Write comment
To an unknowledgeable individual, rendering text proposes itself to be quite simple. Take a texture for each character (glyph) and render it where the previous character ended. Throw all the glyphs into one texture and you have how most games render fonts – bitmap font rendering. But is that really all there is to it? No. People want pretty, scalable fonts where the characters align perfectly with each other, and in that process they created vector (or outline) fonts and a bunch of metrics you are expected to care about.
Fixed Distance Bitmap Font Rendering
In Conquest, we had actually used the simple, optimistic approach. Most fonts in use today are stored in an OpenType or TrueType format with the .ttf extension. Glyphs in these formats are stored in vector form, so we had extracted all glyphs from a .ttf font file into a bitmap image in which each glyph had been placed in a 16×16 pixel space so we could fill a 256×256 texture with the 256 ASCII characters.
We had also extracted each glyph’s width for the given size and pulled some offsets out of our posteriors to give some blank space between the letters.
[Font] GlyphOffsetX = 1 GlyphOffsetY = 3 GlyphWidthModifier = 1 Size = 16 Texture = ZeroThrees [GlyphWidths] 0 = 6 1 = 6 2 = 6 3 = 6 ...
After a solid amount of preprocessing work on the texture, I think it actually looks pretty great. At least for this particular font. A fat and heavy look.
Certainly not very space friendly though. For text which is rendered over non-black background we had created another texture with a black glow around each glyph.
It’s not perfect, there is too much blank space in front of each “y” letter for example, but it’s minimal. Even in games such as Starcraft 2 you can find such occurrences, even though their method is more sophisticated and tries to get rid of such imperfections.
The issue lies in the fact that there just aren’t enough pixels available to render the vector glyph accurately on small sizes, especially after it is anti-aliased to appear smoother and hinted to fit the pixel grid better and appear more legible. Font designers can manually input additional parameters, hinting and kerning for each size, to remedy this, but only commercial fonts of the highest quality have that kind of effort put into them.
Distances the Right Way
Most AAA games, every web browser and word processing application don’t just leave one pixel blank between characters. They use metrics embedded in font files. I’ve seen Microsoft define them with the extremely verbose “a”, “b” and “c” values, but we don’t like that so we’ll use the definitions from FreeType’s glyph conventions.

Horizontal glyph metrics.
The most important one is the advance. It says how much we move to the right after rendering a specific glyph.

Horizontal advances.
For vertical layouts (drawing text from top to bottom), it’s similar, just that we move downwards and the glyphs are centered around the baseline instead of above it.
Fairly simple so far, but there’s another bane waiting for us. This bane is called kerning and it specifies a distance adjustment between two corresponding glyphs. For example, when the letter “A” is followed by “V” we can pull the “V” closer to the “A” so it appears more natural.
Bravo unkerned.
Bravo kerned.
The same distance adjustment could not be said to be desirable if “A” was followed by “B”. It is also not necessarily true that the kerning is the same if you swap the positions of the two characters, i.e. the pair (A, V) and (V, A).
If we were to render a vertical layout there would be another whole set of different kerning information for vertical distance adjustment.
What takes this from being a bane to a pain in the bottom is that .ttf fonts may store kerning information in different structures. There’s the simple “kern” table which defines distance adjustments for each pair, and a more complex GPOS table which adds support for a whole other slew of position adjustments, like how to position accents over characters and context based positioning. This allows font designers to combine accents and other marks with virtually any other base glyph, and adds proper support for non-Latin scripts.
Support for non-Latin writing systems doesn’t stop there though. There’s also glyph substitution via the GSUB table and probably more. Sadly though designers of Latin fonts often fill the GPOS table and leave the “kern” table empty, so we can’t get all the kerning information we’d like just by using the de-facto portable font rendering library: FreeType 2.
In the next part I’ll disregard non-Latin scripts and talk about styled rich text rendering with FreeType 2. I’ll also briefly touch on higher level alternatives and text layouting.


No comments yet.