Loading and using TrueType fonts

TrueType fonts present a higher quality font rendering with the use of font outlines. Each font character is called a glyph. TTF files contain not only outlines but also the glyph's information. Glyph rendering from outlines is much slower than drawing bitmap font characters on screen. This is mainly because these glyphs are being drawn on-the-run and font rendering may be enhanced with antialiasing, which is costly. Because of this, applications using TrueType fonts often cache font glyphs into textures.

The SDL_ttf library manages the loading of the TrueType font files. Everything you need to use these files is included in the LuaSDL library.

This recipe will deal with loading font glyph in surface object, which you can store into the texture or as a smaller part of the bigger texture—texture atlas.

Getting ready

First, you'll need a TTF file with font data. Let's assume that you already have one called font.ttf. The next thing you'll need to know is what font size will be used. This is important because the SDL_ttf library uses this size to set the proper glyph metrics on scalable fonts and to choose the glyph set on nonscalable fonts.

The SDL_ttf library needs initialization before the first use. You can initialize it with the function call:

SDL.TTF_Init()

The same goes for freeing the resources when you're about to quit the application. You should always call SDL.TTF_Quit() at the end.

How to do it…

There are four versions of the function you can use to load the SDL.TTF_OpenFont, SDL.TTF_OpenFontIndex, SDL.TTF_OpenFontRW, and SDL_TTF_OpenFontIndexRW font. The first two use filename to load the font file. The other two use the RWop object. The functions with the index keyword accept one additional parameter with the font face index. Their specifications are as follows:

SDL.TTF_OpenFont(font_filename, font_size)
SDL.TTF_OpenFontIndex(font_filename, font_size, font_face_index)
SDL.TTF_OpenFont(rwop, free_src, font_size)
SDL.TTF_OpenFontIndex(rwop, free_src, font_size, font_face_index)

The free_src parameter set to 1 will free the RWop object after successful load. In this case, the recipe will be using the last version of the function.

First, you need to open the font file:

local rwop = assert(SDL.SDL_RWFromFile("font.ttf","rb"))

Now, you can read the content from the font file:

local font_size = 12
local face_index = 0
local font = assert(SDl.TTF_OpenFontIndexRW(rwop, 1, font_size, face_index))

Now that you have successfully loaded the font file, you can read the font information and glyphs. You'll need the font ascent and descent values to be able to set correct glyph positions.

The next step is to render a glyph. Each glyph contains information about glyph positioning. Without it, the characters wouldn't sit on the baseline because each glyph usually has a different size. To get the glyph positioning information, you need to call SDL.TTF_GlyphMetrics. Each glyph has different metrics, so you need to obtain this information for each glyph. Fortunately, you can store glyph metrics in the Lua table. You can use the method shown in the following sample:

local glyph_metrics = {}
local text = "Hello world ABCDEF"
for i=1,#text do
  local code = string.byte(text, i)
  if not glyph_metrics[code] then
    local _, minx, maxx, miny, maxy, advance = SDL.TTF_GlyphMetrics(font, code)
    glyph_metrics[code] = {
      minx = minx,
      maxx = maxx,
      miny = miny,
      maxy = maxy,
      advance = advance,
    }
  end
end

Glyph metrics are useful if you are rendering texts that change often. If this is not the case, you can safely use the internal SDL_ttf text renderer to produce surface objects that contain whole text with characters at the right places.

The final part of this recipe is text rendering. There are altogether 12 functions that provide text rendering. Their description is shown in the following table:

Function names

Description

SDL.TTF_RenderText_Solid

This renders text in Latin1 encoding in solid mode

SDL.TTF_RenderUTF8_Solid

This renders text in UTF8 encoding in solid mode

SDL.TTF_RenderUNICODE_Solid

This renders text in UNICODE encoding in solid mode

SDL.TTF_RenderGlyph_Solid

This renders a UNICODE glyph in solid mode

SDL.TTF_RenderText_Shaded

This renders text in Latin1 encoding in shaded mode

SDL.TTF_RenderUTF8_Shaded

This renders text in UTF8 encoding in shaded mode

SDL.TTF_RenderUNICODE_Shaded

This renders text in UNICODE encoding in shaded mode

SDL.TTF_RenderGlyph_Shaded

This renders a UNICODE glyph in shaded mode

SDL.TTF_RenderText_Blended

This renders text in Latin1 encoding in blended mode

SDL.TTF_RenderUTF8_Blended

This renders text in UTF8 encoding in blended mode

SDL.TTF_RenderUNICODE_Blended

This renders text in UNICODE encoding in blended mode

SDL.TTF_RenderGlyph_Blended

This renders a UNICODE glyph in blended mode

You must have noticed that there are three rendering modes:

  • Solid: While solid mode is the fastest, it uses an 8-bit surface with palette. Color index 0 is used as a color key—transparent color. Color index 1 is used for text foreground color. The text is not very smooth.
  • Shaded: This mode is slower but nicer. It uses an 8-bit surface. Color index 0 is used as a background. Other colors are used as varying degrees of foreground color. This text is not transparent and it's surrounded with a solid box filled with background color.
  • Blended: This mode is the slowest. It uses a 32-bit surface with the alpha channel. What's more, the text is antialiased.

You should always use the blended mode with OpenGL. Not only does the text look better, but the process of uploading the texture into the graphic card memory is much easier.

You can draw a single character with any of the SDL.TTF_RenderGlyph_xxx functions. The following example will be using the blended mode:

local color = SDL.SDL_Color_local()
color.r,color.g,color.b = 255,255,255
local glyph_surface = assert(SDL.TTF_RenderGlyph_Blended(font, string.byte("A",1), color))

You can blit glyph_surface directly to the screen surface object or transfer it into the OpenGL texture. However, be sure to check the pixel format of the glyph_surface object! The color channel mask can be quite different from what the OpenGL function gl.TexImage expects. The order of the color channels in glyph_surface must match the internal texture format! Otherwise, you can expect incomplete texture, invalid texture colors or even segmentation faults (crashes).

Don't forget to call SDL.TTF_CloseFont to free the font object:

SDL.TTF_CloseFont(font)

How it works…

Font glyph uses metrics information to maintain the correct glyph placement. A summary of these metrics can be found in the following figure:

How it works…

The font ascent and descent values can help you with the vertical positioning of characters. Ascent is the distance from the top of the font to the baseline. Descent is the distance from the baseline to the bottom of the font. You can get these two parameters with the SDL.TTF_FontAscent(font) and SDL.TTF_FontDescent(font) functions.

See also

  • The Displaying the text recipe
  • The Creating texture atlas with the rover design pattern recipe
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.248.162