Things i've made

Looking for more? See a list of everything i've made.

Monday, July 30, 2012

OpenGL and Freetype

As part of a project I have been working on, I have been upgrading a font system in an OpenGL application. I decided that the old glx/wgl based system could be moved to use freetype and at the same time improve the visual appearance. You see, glx/wgl allow you to use fonts but they are very strict about their use and only give you 1-bit images - sad. Using freetype allows you to have smooth font edges and a lot more flexibility with newer OpenGL pipelines.

To begin with, there are a lot of tutorials out there on how to use freetype with OpenGL so I won't be covering what they already have, instead I'll review what they did and provide some insight on an improved implementation:
(Details are for OpenGL < 3.0, determine for yourself what it correct for your target version)

 

Texture Format

The first common shortcoming of OpenGL font code is to use a texture format that requires excessive processing. Some implementations/tutorials will say to use GL_RGBA as the internal format and GL_INTENSITY_ALPHA for the data format which requires some shuffling of data from freetype to OpenGL. The correct type to use is GL_ALPHA* for internal and GL_ALPHA for the data format.

Using GL_INTENSITY or GL_LUMINANCE will appear to work correctly for black/white text and backgrounds but when you have colored text you will notice that the edges of each glyph are a little dark. This is because the color value for each pixel in the font texture should be (1.0, 1.0, 1.0) and instead you have color = alpha. When you alpha blend, color = alpha will darken the color as the alpha goes toward zero - not what you were after.

Advance

When determining how many pixels are between the start of each character you should include x-advance, glyph bitmap left positioning, and kerning. Many implementations only use one of these factors and end up with text with spacing that just doesn't seem right.

 

Unicode

Freetype supports unicode glyphs well. Rendering these glyphs to a texture for later use that isn't big enough to hold unicode glyphs will limit you use of text. Adding even simple unicode support is a great way to increase the global appeal of your application.

 

Sub-optimal Rendering

To get good performance when rendering, I like to do a sort of batch processing for my fonts and store the quads for each font I use for a single frame in an array until I am done with all font rendering and then call glDrawArrays over the buffer. Using multiple glTranslate, glBegin, etc calls is terrible for performance. Even though font rendering may only account for a small percentage of your screen rendering time, it should be negligible if you are aiming for a high frame rate.