Text styles using SDL2_ttf

In the last post we looked at how to render text. Now let’s take this a step further and change the appearance of the font. There are two ways you can change how the font looks. Font style and font outline.

Fon styles

SDL TTF allows you to set the style of the font. It supports the following font styles

• bold
• italic
• underlined
• strikthrough

You can combine these in any way you like. We’ll start off with just setting a single font style at a time, and then move on to see how we can apply several of them at once.

Font styles

Settnig font styles in TTF is easy, it just requires a single function. The function let us you set one or more font styles. Let’s start off by looking at how to set just one font style

Setting the font style

We can set the font style using the following function

Arguments :

•  TTF_Font *font – the font to set the style on
• int style       – the style to set on the font

As you can see, the style parameter is an int and not an enum. I’ll get back to why that is later, but for now let’s look at the possible values for style, these are all self-explanatory so I won’t be adding a description.

• TTF_STYLE_NORMAL
• TTF_STYLE_BOLD
• TTF_STYLE_ITALIC
• TTF_STYLE_UNDERLINE
• TTF_STYLE_STRIKETRHOUGH

Any text you render after setting this font style will have the new effect, but it won’t change any text you have written with a different style. So when you set the style to TTF_STYLE_BOLD, all text you render from that point and until you set a different style will be bold. And as long as you pass any of the above values to the function, the font will only have the one last style you set.

Let’s do a simple example

Any text rendered at this point will be normal with no font styles

Any text rendered at this point will be bold

Any text rendered at this point will be in italics, but not bold

Any text rendered at this point will be normal with no font styles

Any text rendered at this point will be underlined

As you can see, this is pretty straight forwards. So let’s make things a little bit trickier by setting multiple font styles at once. To do this, we must first look a bit at the binary number system

Binary numbers

In order to learn about how to combine these flags, we need to look at binary numbers first of all. If you don’t already know about binary numbers, you should take a look at the above link. It’s not crucial, but it is highly recommended to know a little about them. I might create a blog post about them at some point. For now, I’ll just talk a tiny bit about the binary number system. But as I said, I highly recommend understanding it fully to the point where you can convert back and forth between binary and decimal numbers

The binary number system

On a daily basis, we use the decimal number system. The binary numbers system is just a different way of representing numbers. Any numbers can be converted from any other number system. So you can convert binary numbers to decimal numbers ( and the other way around ).

A computer stores numbers as individual bits ( 0‘s and 1‘s ). They correspond to on / off or true / false.

Let’s take a look at an 8 bit binary number ( 1 byte )

1010 0101

As you can see, it has 8 digits. So that’s eight different flags. Each of these flags have two different possible values : 0 / 1 or false / true. So that’s 8 bools for the price of a single byte!

Bitwise operations

So how do we use these 8 booleans? As you know, we have the following boolean operations in C++:

• and ( && )
• or ( ||

These work on an entire variable. An int, for instance will be false if its value is 0, otherwise its true.

But there are similar operations that does this on all bits of a variable. These are called bitwise operations, simply because they operate on a simple byte. To do a bitwise operation, we need two variables of equal size ( same number of digits ), for instance two bytes. The result of a bitwise operation is a third variable of the same size. So if we do a bitwise operation between two bytes, we get a third byte back as a result.

Let’s create two bytes, we’ll use these for a few examples

Byte 1 : 0101 0011 ( 64 + 16 + 2 + 1 = 85 )
Byte 2 : 0110 0010 ( 32 + 64 + 2 = 98 )

We’ll be referring to each digit as a position. So the digits in the first position is 0 in both or bytes. In the second position it’s 1 in both bytes and in the third it’s 0 in the first byte and 1 in the second byte.

Bitwise OR

A bitwise OR operation means we look at all positions as check if either of them is 1 if so, we set the digit in that position to 0. If no digit in that position is 1, we set it to 0

The operator for bitwise OR in C++ is | ( just one |, not two )

Here is a simple example of bitwise OR between two bytes

0101 0011 OR 0110 0010 = 0111 0011

Bitwise AND

In a bitwise AND operation, we look at each position and see if both of them are 1. If so, we set the digit in that position to 1, otherwise we set it to 0. So in OR we set it to 1 if any of the two is 1, here we only set it to 1 if both are 1.

The operator for bitwise AND in C++ is & ( just one &, not two )

Here’s the a simple example :

0101 0011 AND 0110 0010 = 0100 0010 

Bitwise XOR

XOR or exclusive OR is slightly less known than OR and AND. In an XOR operation, we check if the two values are different. So this is equivalent to != in C++.

• ( true  != false ) = true
• ( true  != true  ) = false
• ( false != true  ) = true
• ( false != false ) = false

Simply put, an XOR operation is true if the two parts are different. So in a bitwise XOR operation, we look at each position and see if the two digits are different. If so we set the digit at that position to 1, otherwise we set it to 0.

The operator for bitwise XOR in C++ is !=

Here is an example :

0101 0011 XOR 0110 0010 = 0011 0001 

Bitwise NOT

We also have the a bitwise version of the NOT opeartion this is done by using the ~ operator in C++. If we used ! we would get the result of NOT on the entire variable, not the individual bits which is what we want. This operation only takes a single element and flips all bits ( turns 1‘s into 0‘s and 0‘s into 1‘s. ). Let’s test it on our two bytes

The operator for bitwise NOT in C++ is !

Byte 1 :

NOT 0101 0011 =   1010 1100

Byte 2 :

NOT 0110 0010 =   1001 1101

Setting and checking individual bits

So now that we know how to do bitwise operations, we need a way of checking and setting the individual bits. This is done simply by using OR, AND and XOR. Before we take a look at how to do this, let’s define a few values to check.

Remember that the different font styles are ints? This is because they are used to perform bitwise operations to set and unset different bits. Here they are again, this time with their values. For simplicity, I’ll only list the last four bits ( the others are always 0 ). The values are in decimal with the binary representation in parenthesis

• TTF_STYLE_NORMAL = 0 ( 0000 )
• TTF_STYLE_BOLD = 1 ( 0001 )
• TTF_STYLE_ITALIC = 2 ( 0010 )
• TTF_STYLE_UNDERLINE = 4 ( 0100 )
• TTF_STYLE_STRIKETRHOUGH = 8 ( 1000 )

As you can see, they all have only one ( or zero ) bit set. This means we can use AND, OR or XOR on just one bit.

Setting a bit

To set a bit ( without affect any other bit ) we use the ORoperation. So say that we have four bits set to 0, 0000 and we want to set the bit for bold on it ( 0001 ). In other words, we want the result 0001. What we do is : that we take our original 4 bits ( 0001 ) and set it to the original 4 bits ( 0001 ) OR‘ed with the bitmask for bold ( 0001 ) :

0000 OR 0001 ( value of TTF_STYLE_BOLD )
=
0001

Simple as that! This woks for any of the other flags in the same way. They all will end up setting one bit.

Note that this will not change any other bits. If we try set the italics font style on the above variable we get :

0001 OR 0010 ( value of TTF_STYLE_ITALIC )
=
0011 ( TTF_STYLE_BOLD and TTF_STYLE_ITALIC set )

Let’s make a simple function that adds a style to a mask.

Unsetting a bit

Sometimes we want to unset a bit. Say for instance we want to remove the italics from the font above. How do we do that without affection the other values? This is a bit more complex, because it requires two operations. What we are trying to do is the following :

Say we have a bitmask ( 0000 1011 ) and we want to unset the bit for bold text, but leave the rest unchanged. So we need to be able to go :

From 1011 to 1010

To do this, we need to use an AND operation. This is because we can’t turn of a bit using OR, and XOR would only flip it back and forth between 0 and 1

But we can’t use AND with the flag we want to unset alone, because that would keep the flag at 1 and change every other to 0!

0000 0101 AND 0000 0001 = 0000 0001

This is the opposite of what we want! Wait? Opposite you say? Well how about we use the NOT operator here to get the opposite result? This works perfectly, because NOT 0000 0001 is 1111 1110. And, as we saw earlier, doing AND 1 won’t change the element we’re AND‘ing with. So we get :

0000 0101 AND 1111 1110 = 0000 0100

Success! Only the bit we were trying to unset has changed. So let’s make a function that does this for us :

Checking a bit

To check a bit, we also need to use the bitwise AND operation. And since we are only checking and not setting, we don’t have to store the value anywhere which means we don’t have to worry about changing anything.

To check a bitmask, simply do an AND operation with the value you want to check for ( in this case, any of the TTF_STYLE_.... values ). So, to check if a text is bold, we do an AND between our mask and TTF_STYLE_BOLD :

0011 ( our bit mask, TTF_STYLE_BOLD and TTF_STYLE_ITALIC set )
AND 0001 = 0001

As you can see, we only check the bit that’s set in our variable ( TTF_STYLE_ITALIC set ) the others will be 0 no matter what our mask is. The value 0001 is not 0, and thus this evaluates to true and we now know that the font is bold.

If our mask didn’t have the bold bit set ( only the italic one ), our mask would be 0010. An AND between 0010 AND 0001 is false ( they have no bit set to 1 in common ) and the result is 0 aka false.

So let’s create a function for that too!

Conclusion

With a little knowledge about binary numbers and bitwise operations, we can easily set, add, remove and check various font styles in SDL_TTF.

Since it does involve a little low level code, I made a simple class that does the apparitions for us in a more intuitive way. I strongly suggest using this opposed to “raw” TTF_Fount*

Feel free to comment if you have anything to say or ask questions if anything is unclear. I always appreciate getting comments.

You can also email me : olevegard@headerphile.com

Rendering text

In the previous parts, we’ve look at how to render rectangles and images, both with and without transparency. Now it’s time to look at how we can render text.

Rendering text is tricky. You’ll want to be able to render any font, in any size and preferably every possible character. Luckily, with the SDL_ttf library, this is easy.

SDL2_ttf

SDL2_ttf, just like SDL2_image, is an additional library for SDL2. It can use just about every font, and you can set the size and text styling too!

What’s TTF?

TTF, or TrueType Fonts is a type of fonts developed by Apple and Microsoft in the late 90’s. True Type Fonts offers a high degree of control on how the font looks. The internals of TTF fonts and how they work isn’t important here. The important part is that they’re easy to use, will look really nice ( even scaled up. ) And they’re also widely used, so finding fonts shouldn’t be a problem.

SDL2 TTF?

As with SDL2_image, SDL2_ttf is an additional library for SDL2 that deals with rendering text and makes it very easy. It is based on libfreetype, a library for writing text using TTF fonts. However, it’s not very practical to use. SDL2_TTF makes using it a lot easier. But if you do want to use it yourself, you can take a look at their tutorial.

Setting up SDL2_TTF

Setting up SDL2 requires a tiny bit more work than SDL2_image, but don’t be scared, it’s still very easy. First we need to install the ttf library.

Installation

Installing SDL2_ttf is done exactly like SDL2_image. Just replace SDL2_image with SDL2_ttf

Here’s the short version :

Linux

For Linux you can use need to install -lSDL2_ttf or -libSDL2_ttf or -SDL2_ttf ( the actual name might be different in different distributions. )

The linker flag is -lSDL2_ttf

The process is more or less identical to that of setting up SDL2_image.

If you can’t find SDL2_ttf in any repositories and it’s not installed by default, you might have to compile it yourself. For more information, see my blog post about setting up SDL2.

Windows

Similar to setting up SDL2 base.

The difference is that you have to download the development files for SDL2_ttf

And similarly add SDL2_ttf.lib to library includes and add SDL2_ttf.lib to the library flags ( where you previously added SDL2_image.lib )

And with that, it should work.

Mac

See the first part of my tutorial. Just install SDL2_ttf instead of SDL2

Initialization

Unlike SDL2_image does need to be initialized. Why? Because libfreetype, the library that SDL2_ttf builds upon needs to be initialized, so naturally SDL_ttf needs to be initialized too.

Initializing SDL2_ttf requires a single function, TTF_Init() :

Just like SDL_Init(Uint32 flags) this function returns -1 on error, but unlike SDL_Init(Uint32 flags), this method does not have any flags.

Sine this function can fail and return -1, we should print an error if this happens. This means our routine for initializing SDL2_ttf will be the similar to SDL2, just with the two functions above :

TTF_Font

The basic object for SDL_TTF is TTF_Font. A TTF_Font basically holds information about a font like the font itself and data about styling and size. The exact internals of TTF_Fonts is only known to the library using it so I won’t go into depths about it.

The only thing you need to remember about TTF_Fonts is that they hold all information about the font that SDL_TTF needs to render it, and that they need to be loaded and unloaded ( we’ll look at this later. )

This is the central structure of SDL2_ttf. It holds the font itself, the size and some other style information ( I’ll go into this in the next part ). So, in order for us to use an TTF_Font we need to load it. This is done using a load function :

Arguments :

• const char *file – a pointer to the .ttf file
• int ptsize – the size of the font

Return value :

A pointer to the created TTF_Font<

The function returns a NULL pointer of it can’t find the file, or there is another error ( like SDL2_ttf isn’t initialized. So this too should be handled by priting the error using SDL_GetError(), just like when initializing ttf

Cleaning up fonts

Just like we with SDL_Texture*  and SDL_Surface*, we need to clean our fonts when done. This is just as easy for TTF_Fonts as with SDL_Texture*  and SDL_Surface*. We simply call a function that does it for us :

Rendering text

There are three functions you can use to render text, depending on what you want. Let’s start with the first one :

TTF_RenderText_Solid

This function is used for quick and simple rendering of a text, using a specific font and a font color. The background of this is transparent. Here’s the signature:

Arguments :

•  TTF_Font *font – the font to use
• const char *text – the text to render
• SDL_Color fg –  the color to use for the text

Return value :

A SDL_Surface with the rendered text

The function returns a NULL pointer of it can’t find the file, or there is another error ( like SDL2_ttf isn’t initialized. So this too should be handled by priting the error using SDL_GetError(), just like when initializing ttf

The result will look something like this :

TTF_RenderText_Blended

The next function is very similar to the previous one

Arguments :

•  TTF_Font *font – the font to use
• const char *text – the text to render
• SDL_Color fg –  the color to use for the text
• SDL_Color fg –  the color to use for the text

Return value :

A SDL_Surface with the rendered text

The function returns a NULL pointer of it can’t find the file, or there is another error ( like SDL2_ttf isn’t initialized. So this too should be handled by priting the error using SDL_GetError(), just like when initializing ttf

As you can see, both the arguments and return value is the same for TTF_RenderText_Solid and TTF_RenderText_Blended. So what’s the difference between TTF_RenderText_Solid and TTF_RenderText_Blended? The difference is that TTF_RenderText_Solid is very quick, but TTF_RenderText_Blended produces a better result. In our game, we won’t be updating our text surfaces all that often, and there’s not a lot of them either, so TTF_RenderText_Blended is a good choice.

Here’s what TTF_RenderText_Blended looks like :

And here’s a comparison between TTF_RenderText_Solid and TTF_RenderText_Blended :

The difference is not huge, but in the actual game it will be more clear. And the difference might also vary from font to font.

This function is a bit different from the two other ones. It will render the texture with a specified background color.

Arguments :

•  TTF_Font *font – the font to use
• const char *text – the text to render
• SDL_Color fg –  the color to use for the text
• SDL_Color bg –  the color to use for the background

Return value :

A SDL_Surface with the rendered text

The function returns a NULL pointer of it can’t find the file, or there is another error ( like SDL2_ttf isn’t initialized. So this too should be handled by priting the error using SDL_GetError(), just like when initializing ttf

So it’s almost the same as the other two, just with a fourth argument for the background color. The return value is also the same as the other two. The difference in the resulting function is that you will get a texture with a background color. The background color ( bg ) will fill the entire rect around the text. The text will be rendered on top of it with the specified foreground color ( fg ).

The result will look something like this :

An example

Below is a simple example that should run and compile out of the box. For compilation details, look below.

Compilation notes

Running it is just as simple as with SDL2_image. So that means compilation on Windows is already set up when you installed TTF

Linux / Mac

If you are compiling using the compiler, you have to add -lSDL2_ttf to the compile string like so :

clang++ main.cpp -std=c++11 -o Game -lSDL2 -lSDL2_image -lSDL2_ttf

If you want to run it, you simply do

./Game

Updated game code

I have done a bit of cleaning up in the game code. I’ve added a new Texture class for text, cleaned up include, removed ( and added ) comments, improve delta calculation++ Everything should be explained in comments, but, of course, if you have any questions of any kinds, just comment or contact me, I’ll be happy to help.

You can find the code here.

Conclusion

Text rendering can be hard, but SDL2 makes it quite easy. Just load your TTF_Fonts and you can easily get them as a SDL_Surface.

Feel free to comment if you have anything to say or ask questions if anything is unclear. I always appreciate getting comments.

You can also email me : olevegard@headerphile.com