Text is an important part of almost all games. From informing the player of the awesome combo that they just got, to menu titles, button captions and epic storylines. In this tutorial, we will take a look at SDL_ttf, an addon library for SDL that uses the FreeType library to load fonts and render text. SDL_ttf adheres to the C-style syntax of SDL, so if you are familiar with SDL (which you hopefully are) it won't be too hard to get used to SDL_ttf's calling conventions. You can get the newest version as of this writing (2.0.10-1 to be exact) here.

Let's start by defining some font terms which we will use throughout this tutorial:

Font face: A style of a font. For example bold or italic. Font files can contain more than one font face.
Point size: The font measure originally used in typography. Some but not all digital fonts use point sizes and one of these is roughly 1/72 of an inch (~2.54cm), but this is by no means a guarantee.
Glyph: A single character of a font, like 'a'.

Initialization, shutdown and library versions

Loading and unloading SDL_ttf is very similar to that of SDL. All SDL_ttf functions are prefixed with 'TTF_'. Before we can use any of these functions, however, we need to initialize the library:
if (TTF_Init() < 0) {
    // Handle error...
}
TTF_Init() returns -1 if an error occurred and zero if the initialization was successful. Similar to SDL_WasInit(...), you can check if SDL_ttf was successfully initialized like this:
int was_init = TTF_WasInit();

if (was_init == 1)
    // SDL_ttf was already initialized
else if (was_init == 0)
    // SDL_ttf was not already initialized
When you are done with your sweet text-rendering business, SDL_ttf is shut down like this:
void TTF_Quit();
Alternatively, you can use the atexit(...) function to ensure it is automatically called when the program terminates:
#include <cstdlib> // The function is defined in this header

// ...

atexit(TTF_Quit); // Ensure TTF_Quit() is called when we exit
You can also check the version of the linked SDL_ttf library you are using at runtime. Unlike the other functions provided by SDL_ttf, these two do not need any prior initialization to be used:
const SDL_version *TTF_Linked_Version();
void SDL_TTF_VERSION(SDL_version *compile_version);
Here's an example:
#include <iostream>

const SDL_version *linked_version = TTF_Linked_Version();
SDL_version compiled_version;
SDL_TTF_VERSION(&compiled_version);

std::cout << "Linked version:\n"
        << linked_version->major << "." << linked_version->minor << "." << linked_version->patch;

std::cout << "Compiled version:\n"
        << compiled_verison.major << "." << compiled_version.minor << "." << compiled_version.patch << std::endl << std::endl;
Note: I am using the standard I/O (input/output) library to print text to the console window. This gives the same result as using the C function printf(...)

Opening and closing fonts

SDL_ttf uses a single struct to represent its fonts: TTF_Font. The documentation warns not to directly access its contents as they may change in future releases and deprecate projects using older versions. Use the available functions instead. SDL_ttf supports loading of TrueType fonts (with the '.ttf' extension) and opening a font is quite simple. There are four ways of doing it and this is the first one:
TTF_Font* TTF_OpenFont(const char* file, int ptsize);
The first function takes a TrueType font file and a point size and returns the loaded TTF_Font pointer or NULL if loading failed. The point size is a somewhat vague term as mentioned earlier on. It used to be a measure of the height of the metal frame of characters used in typography in olden times, but in digital fonts it is a bit more complicated. I suggest that you experiment with the size until you get the one you want instead of worrying about point sizes because you seldom know what size you want beforehand anyways. If you still want to know about point sizes, take a look in the suggested reading section at the bottom of this tutorial.

The second function looks like this:
TTF_Font* TTF_OpenFontIndex(const char* file, int ptsize, long index);
It is identical to the previous function apart from the last argument. This function loads a specific font face from the file, and is useful if your font file contains several font faces. A font index of 0 is always the first font in the file.

The third function is:
TTF_Font* TTF_OpenFontRW(SDL_RWops *src, int freesrc, int ptsize);
You may or may not have seen the SDL_RWops struct before. It is an undocumented feature of SDL and so is rarely seen (I personally have never seen nor used it). It is capable of taking a pointer to memory where some data is stored, but files are supported too. Since this tutorial is about SDL_ttf and not SDL_RWops, I've added a suggested reading entry at the bottom if you want to know more. If you pass a non-zero value as the second argument the memory used by the SDL_RWops struct is automatically freed before the function returns. The third and last argument is the point size.

The final function does the same thing as the previous one, but loads a specific font face from the SDL_RWops struct.
TTF_Font* TTF_OpenFontIndexRW(SDL_RWops *src, int freesrc, int ptsize, long index);
Just like SDL_Surfaces, there is a single function to free a TTF_Font:
void TTF_CloseFont(TTF_Font *font);
When a function fails to load, you may use TTF_SetError and TTF_GetError just as you use the equivalent functions of SDL:
void TTF_SetError(const char *fmt, ...)
char *TTF_GetError()
These functions are actually defined macros to SDL_SetError(...) and SDL_GetError() and so work just like them:
if (/* loading failed */) {
    TTF_SetError("Loading failed :( (code: %d)", 142);
    std::cout << "Error: " << TTF_GetError() << std::endl;
}

Rendering fonts

Let's get to the rendering part and get some cool fonts onto the screen. There are twelve functions int total available for rendering which I have chosen to split into three categories: Solid-, shaded- and blended rendering. Here are the first four for solid rendering:
SDL_Surface *TTF_RenderGlyph_Solid(TTF_Font* font, Uint16 ch, SDL_Color fg);
SDL_Surface *TTF_RenderText_Solid(TTF_Font *font, const char *text, SDL_Color fg);
SDL_Surface *TTF_RenderUTF8_Solid(TTF_Font *font, const char *text, SDL_Color fg);
SDL_Surface *TTF_RenderUNICODE_Solid(TTF_Font *font, const Uint16 *text, SDL_Color fg);
Solid rendering is the fastest type of text rendering but gives you the lowest quality. It is best used for text that is expected to change frequently. The first function renders a single glyph while the others render full text strings. However, the last two functions render with text encoding. If you are unfamiliar with the UNICODE standard or UTF-8, I've added entries in the suggested reading section, but I'll give a short introduction to both of them. UNICODE is a standard for text encoding. It defines a set of rules for characters. UNICODE text encoding can be used with different character encodings, one of the most popularly being UTF-8. UTF stands for Unicode transformation format, and the number denotes the bit-size used for the encoding. For example, the character 'T' encodes as U+0054. This is properly a bit confusing, so I advise you to go read the suggested reading entries for a more thorough explanation.

Next up is shaded rendering:
SDL_Surface *TTF_RenderGlyph_Shaded(TTF_Font* font, Uint16 ch, SDL_Color fg, SDL_Color bg);
SDL_Surface *TTF_RenderText_Shaded(TTF_Font *font, const char *text, SDL_Color fg, SDL_Color bg);
SDL_Surface *TTF_RenderUTF8_Shaded(TTF_Font *font, const char *text, SDL_Color fg, SDL_Color bg);
SDL_Surface *TTF_RenderUNICODE_Shaded(TTF_Font *font, const Uint16 *text, SDL_Color fg, SDL_Color bg);
Shaded rendering gives a nicer anti-aliased result, but is slower. Additionally, the text will have a box around it. The color of this box is the bg (background) color you pass to the function. If you're unsure what anti-aliased means, it's when an image (like text) is surrounded at its edges by pixels shaded roughly the same color as that part of the image. This results in a more smooth and nicer-looking image. Here's an example to explain what I mean:

Text with and without anti-aliasing

The last four functions are:
SDL_Surface *TTF_RenderGlyph_Blended(TTF_Font *font, Uint16 ch, SDL_Color fg);
SDL_Surface *TTF_RenderText_Blended(TTF_Font *font, const char *text, SDL_Color fg);
SDL_Surface *TTF_RenderUTF8_Blended(TTF_Font *font, const char *text, SDL_Color fg);
SDL_Surface *TTF_RenderUNICODE_Blended(TTF_Font *font, const Uint16 *text, SDL_Color fg);
Blended rendering yields the best results and as you might suspect it is the slowest of all the rendering functions though not really that much slower relative to shaded rendering. The returned SDL_Surface is a 32-bit ARGB surface with alpha transparency and anti-aliasing. Because this surface will blit slower than either solid or shaded rendered surfaces, you should use it for text that isn't expected to change a lot.

Here's an image of three types of rendering so you can see the differences:

Solid, shaded and blended rendering

Font properties

Fonts have properties and attributes that you can both set and retrieve. One is the font style. Bold, italic and underline are examples of a font style. Additionally, the newest version of SDL_ttf provides the strikethrough style as well, which puts a line right through the middle of the text. To set a font's style you use the following function:
void TTF_SetFontStyle(TTF_Font *font, int style);
The first argument is a pointer to the font for which you wish to change the style. The second is an integer that denotes which style you want to change to. This argument can be any of the below:
TTF_STYLE_BOLD
TTF_STYLE_ITALIC
TTF_STYLE_UNDERLINE
TTF_STYLE_STRIKETHROUGH
TTF_STYLE_NORMAL
These are all bitmasks and so can be combined just like the entity flags used in the SDL Collision tutorial:
TTF_SetFontStyle(myFont, TTF_STYLE_BOLD | TTF_STYLE_UNDERLINE);
Use TTF_STYLE_NORMAL to reset all styles applied to a font. As you may expect, there's an accompaniying get function for getting the styles applied to a font:
int TTF_GetFontStyle(TTF_Font *font);
This returns the bitmask flags set for the font you pass to the function. It returns TTF_STYLE_NORMAL if no style applies. If you don't know how to use bitmasks, fear not! This is how:
int myFontStyles = TTF_GetFontStyle(myFont);

if (myFontStyles & TTF_STYLE_BOLD) {
    // Font is bold
}
If you want your font to have an outline, that's possible too. An outline is an additional border around the font. Here's an example:

Example of an outlined font

Just as with most of these functions, there is a set/get function pair available for font outlines as well:
void TTF_SetFontOutline(TTF_Font *font, int outline);
int TTF_GetFontOutline(TTF_Font *font);
The second parameter to TTF_SetFontOutline is the outline width in pixels. Passing zero turns outlines off. The second function simply returns the current outline width.

SDL_ttf also allows you to turn kerning on and off. What is kerning you ask? Let's look at a string like "AV". Here's what it will look like with and without kerning:

Text with and without kerning

See the difference? In the first image, the 'V' is rendered besides the 'A' such that you could draw a line between the letters that will just touch the edge of each letter. In the second, the letters have been moved closer together. This essentially "compresses" the string because it uses the "free space" that is not available without kerning. Note that this is not always possible everytime. For example, in the string "AA" you can't move either 'A' further towards each other.

The SDL_ttf set/get function pair is:
void TTF_SetFontKerning(TTF_Font *font, int allowed);
int TTF_GetFontKerning(TTF_Font *font);
Passing zero to the second parameter of TTF_SetFontKerning disables kerning. A non-zero integer value turns kerning on. The second function returns zero if kerning is disabled and a non-zero value if kerning is on.

Note: For newly loaded fonts, the default kerning is 1, i.e. on.

Now we take a look at some functions that deal more with the actual physical size of the text:
int TTF_FontHeight(const TTF_Font *font);
int TTF_FontAscent(const TTF_Font *font);
int TTF_FontDescent(const TTF_Font *font);
int TTF_FontLineSkip(const TTF_Font *font);
int TTF_SizeText(TTF_Font *font, const char *text, int *w, int *h);
int TTF_SizeUTF8(TTF_Font *font, const char *text, int *w, int *h);
int TTF_SizeUNICODE(TTF_Font *font, const Uint16 *text, int *w, int *h);
Refer to this picture for glyph metric conventions:

Glyph metric convention

Let's work our way through all these functions from top to bottom. The first function returns the maximum pixel height of the glyphs loaded for the particular font. That is, the pixel height of the tallest glyph contained within the font.

The second returns the maximum pixel ascent of the font. The ascent is the distance from the top of the glyph to its baseline.

The third function returns the maxmum pixel descent of the font. This is the distance from the baseline to the bottom of the font.

Although you can use TTF_FontHeight to space multi-line text, it is better to provide some space between each line. This space is what the fourth function TTF_FontLineSkip returns.

Note: TTF_FontLineSkip returns only a suggested value for the size of the line gap. Not necessarily the "correct" one.

The final three functions return information about the size of a text string if it was rendered. TTF_SizeText fills the w and h variables with the correct values. The function returns zero if the third and fourth parameters were successfully filled, -1 otherwise. The other two functions with similar names do the same but for UTF8- and UNICODE-encoded strings.

Here's an example for the first function:
#include <iostream>

int w = 0;
int h = 0;

if ((TTF_SizeText(myFont, "SDL_ttf is awesome!", &w, &h) != -1) {
    // Print out the width and height of the string if I render it with myFont
    std::cout << "Width : " << w << "\nHeight: " << h << std::endl;
} else {
    // Error...
}
Next is font hinting. Font hinting "hints" to SDL_ttf how to draw the font using mathematical formulas. The proper details are beyond the scope of this tutorial though.
void TTF_SetFontHinting(TTF_Font *font, int hinting);
int TTF_GetFontHinting(TTF_Font *font);
The second parameter of TTF_SetFontHinting can be either of the following:
TTF_HINTING_NORMAL
TTF_HINTING_LIGHT
TTF_HINTING_MONO
TTF_HINTING_NONE
The documentation advises you to experiment with these settings, as do I. Be careful though! Calling this function flushes the internal cache of pre-rendered glyphs. This is true even if you pass the same hinting parameter already set for the font. Therefore, you should check the font's hinting parameter with TTF_GetFontHinting before you decide to change it.

There are also a couple of functions available if you want to get some information about the font face you are using:
long TTF_FontFaces(const TTF_Font *font);
int TTF_FontFaceIsFixedWidth(const TTF_Font *font);
char * TTF_FontFaceFamilyName(const TTF_Font *font);
char * TTF_FontFaceStyleName(const TTF_Font *font);
The first function returns the number of font faces contained in the given font.
The second function returns zero if the font face is not fixed width and a value above zero if it is. A font with fixed width means that all its characters (glyphs) have the exact same width.
The third gets the family name of a font. These can be names like: Arial or Verdana that you use in a word processor.
The fourth function returns the name of this font's style. Some fonts are all in bold or italic and this is what you'll get from this function. If this function returns NULL, no information could be retrieved.

As for information about glyphs, SDL_ttf provides these two:
int TTF_GlyphIsProvided(const TTF_Font *font, Uint16 ch);
int TTF_GlyphMetrics(TTF_Font *font, Uint16 ch, int *minx, int *maxx, int *miny, int *maxy, int *advance);
The first tells you whether or not the given character is available for the font:
int temp = TTF_GlyphIsProvided(myFont, 'a');

if (temp)
    // glyph is available :D
else
    // glyph is unavailable :(
Note that if the glyph is available the returned integer is actually the glyph index in the font.

The second function fills in minx, maxx, miny, maxy and advance with the proper values if possible. These values correspond those on the image I showed you earlier for glyph metric conventions. Here's an example:
int minx = 0;
int maxx = 0;
int miny = 0;
int maxy = 0;
int advance = 0;

int success = TTF_GlyphMetrics(myFont, 'a', &minx, &maxx, &miny, &maxy, &advance);

if (success == 0) {
    // Yay! No errors
    std::cout << "Min X: " << minx
            << "\nMax X: " << maxx
            << "\nMin Y: " << miny
            << "\nMax Y: " << maxy
            << "\nAdvance: " << advance << std::endl;
} else if (success == -1) {
    // Ohoh...
}
If the function returns -1 for failure, your values get filled with NULL, so watch out!

And so we now take a look at the last function of the SDL_ttf, phew!
void TTF_ByteSwappedUNICODE(int swapped);
This function tells SDL_ttf if UNICODE text is byte swapped or not. What? Well, this has to do with the endianness of your computer. Umm...what? Okok, without going into too much detail, endianness deals with the ordering of bytes in a computer. Hence another word for endianness is "byte order". There's an entry in suggested reading section about endianness.

As a final note, almost all of SDL_ttf's functions that take a pointer to a TTF_Font cause a segfault error if you pass NULL instead, so check the validity of your font pointer before you use it.
if (myFont)
    // Font is OK!
else
    // Font is not OK!

Entering text

Here's a quick example of how to get text entered by the user, that I picked up a while back from the Lazyfoo SDL tutorial site.
std::string text = "";
SDL_EnableUNICODE(SDL_ENABLE);

void OnKeyDown(SDLKey key, SDLMod modifier, Uint16 unicode) {

    if(key == SDLK_BACKSPACE) {
        if(!text.empty())
            text.erase(text.name.length() - 1);
    } else if(key == SDLK_RETURN) {
        if(!text.empty()) {
            // Do stuff with the text
        }
    } else {
        if(text.length() < MAX_NAME_SIZE) {
            if(unicode == ' ' ||
               unicode >= 'a' && unicode <= 'z' ||
               unicode >= 'A' && unicode <= 'Z' ||
               unicode >= '0' && unicode <= '9')
                text.name += (char)unicode;
        }
    }
}

SDL_EnableUNICODE(SDL_DISABLE);

Closing words

And that's all the functions provided by SDL_ttf. Hopefully, you now understand how to use the library or discovered some interesting things you didn't know about it before. I wish you good luck in all your future font-related endeavours :)

As an added bonus, I've included a small sample for you where you can try some the things we've talked in the tutorial for yourself. Enter the directory path of the font you want to load in the "fontname.txt" file and try it out. The sample has only been tested on a Windows computer, but should hopefully work on the other platforms. The controls are:

[s]: Solid rendering
[d]: Shaded rendering
[b]: Blended rendering
[k]: Toggle kerning
[o] + [0-3]: Set outline width
[Esc]: Quit the application

This is my first tutorial ever! So please bear with me if there are some mistakes or pecularities in the text. Hopefully you enjoyed it anyway! I would appreciate any feedback you guys have on how to improve, including any corrections.

Suggested reading

SDL_ttf documentation
UNICODE article entry on Wikipedia
UTF-8 article entry on Wikipedia
SDL_RWops
Endianness

Downloadable fonts (always check how "free" fonts are):
www.1001freefonts.com
www.urbanfonts.com
www.dafont.com