I finally decided to tackle the rendering of TrueType fonts in my engine. It proved to be a much bigger challenge than I had originally anticipated; I perused over dozens of outdated guides, tutorials, code snippets, and documentation files to finally achieve something legible on screen. I decided to provide a complete guide to this process so that if anyone should decide to follow in my footsteps, they will know where to go.
FreeType 2 InstallationOpenGL works with pixels, and TrueType fonts are not stored like image files, so we need the FreeType 2 library to create font bitmaps. If you are well-versed in 3rd party API installation, feel free to skip this section. I have only performed the compilation using Visual Studio 2010 and 2012.
- Download the latest headers for FreeType 2 from SourceForge. As of this write-up, the latest version is 2.4.11.
- Unzip the archive and go to the builds folder to locate your platform. I will be demonstrating this with the win32/vc2010 build.
- Open freetype.sln in Visual Studio. If you are running VS2012, you will need to update the solution to use the latest compiler and libraries.
- Select the Release candidate and go to Build->Build Solution.
- The compiled .lib file will be located in objs/win32/vc2010/freetype[version].lib, where [version] is "2411" as of this writing.
- Copy this file to somewhere in your current project directory's library path.
- Copy the contents of the include/ folder to somewhere in your current project directory's include path.
We are going to define some structures in order to make handling the fonts a bit easier. We need a rectangle to keep track of dimensions, a color for the text color, an a 2D vector to track position. Also, I'm going to include my vertex structure, representing a vertex to send to the VBO for rendering. This is pretty standard and I assume if you've made it this far in OpenGL, you have one of your own.
The comments should explain everything else in a pretty detailed fashion. Now on to the implementation.
This a detailed explanation of the implementation of the CFont class.
Here the TrueType library is initialized. This can be called explicitly via CFont::Initialize(), but it will also be called by default when a CFont instance is created.
CFont()This is the class constructor. Here, we will load the shader and verify that the TrueType library is initialized.
Now we must load the font. Filename is a path to a TrueType font (.ttf) and size is the size of the font, in pixels.
RenderText()text is, obviously, the text we want to render. Currently, this only supports one line at a time, so characters like '\n' will not render properly. Actually they likely won't render at all and will cause a crash. You should add bounds checking to ensure that the provided char is within the range of render-able bitmaps. Pos is the position where to start rendering. It is not the top-left corner of the text, but rather is on the line to be written on. Imagine a piece of paper: Pos is the line which you're writing on.
FontRender.fsThere is some shader magic necessary in order to properly render the text. Since TrueType gives us a monochrome bitmap, we need to specify that we want to use the r value (specified when we said GL_R8 and GL_RED in the glTexImage2D call in CFont::LoadFromFile() in the incoming texture fragment for all four components for the output fragment.
There you have it! The rest of the methods in CFont should be fairly easy to implement. I mean, I'm sure it's fairly self-explanatory that CFont::SetColor() just modifies CFont::m_Color to reflect the new RGB values, and that Resize() just calls CFont::LoadFromFile() again with the new size specified.
You can see the raw class files directly from my IronClad rendering engine in their entirety on my Github here (header) and here (implementation). Hopefully I will be modifying this system soon to use a texture atlas to contain all of the glyph bitmaps in a single texture and load a VBO with custom texture coordinates on-demand. Feel free to add any comments, questions, or suggestions below!