[SDL2] Handle TrueType and Bitmap Fonts

Hi, I migrated my SDL-wrapper from v1.2 to v2. Now I plan to improve my text rendering api. Currently, I am caching TTF_Fonts and create surface (and then the texture) each time I change a text.

My new approach might be pre-rendering all needed characters once, creating the surface (and then texture), so I can render the parts of the texture depending on the string I am rendering.

Here is some simplified pseudocode for the actual rendering

Code:
function renderString(texture t, string s, position xy):
for each character c in s:
calculate offset for c within t
render(t, offset, xy)
x += width of c (might be equidistant)

Is this approach useful? I’m not sure whether this iteration-through-the-string-on-each-render is fast enough. By the way: I am working on a netbook - so speed is quite relevant (not in critical way, but relevant^^). In my opinion this approach (using equidistant character width) might be useful for bitmap-based fonts as well.

I hope I described enough in detail :slight_smile: Anyway, thanks in advance! :slight_smile:

Kind regards
Glocke

Iterating through strings is pretty fast. Don’t worry too much about it.

Try to imagine a computer going through an array of bytes (a string) versus
copying a bitmap and uploading the whole thing (likely 4 bytes per pixel)
to the graphics card. Checking a few bytes is nothing compared to copying
a few thousand bytes twice.

You should focus on getting something working that feels good to you, then
you can profile it to see where performance bottlenecks are.

Jonny DOn Mon, Feb 10, 2014 at 11:23 AM, Glocke wrote:

Hi, I migrated my SDL-wrapper from v1.2 to v2. Now I plan to improve my
text rendering api. Currently, I am caching TTF_Fonts and create surface
(and then the texture) each time I change a text.

My new approach might be pre-rendering all needed characters once,
creating the surface (and then texture), so I can render the parts of the
texture depending on the string I am rendering.

Here is some simplified pseudocode for the actual rendering

Code:

function renderString(texture t, string s, position xy):
for each character c in s:
calculate offset for c within t
render(t, offset, xy)
x += width of c (might be equidistant)

Is this approach useful? I’m not sure whether this
iteration-through-the-string-on-each-render is fast enough. By the way: I
am working on a netbook - so speed is quite relevant (not in critical way,
but relevant^^). In my opinion this approach (using equidistant character
width) might be useful for bitmap-based fonts as well.

I hope I described enough in detail [image: Smile] Anyway, thanks in
advance! [image: Smile]

Kind regards
Glocke


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

function renderString(texture t, string s, position xy):
for each character c in s:
calculate offset for c within t
render(t, offset, xy)
x += width of c (might be equidistant)

Is this approach useful?

Yes, this is called a “font atlas” and it’s how most things tend to
render dynamic text. One texture, one quad drawn per glyph.

(“One texture” may be “several textures” depending on how big the font
is, what glyphs are needed, etc. In this case, extra credit for
rendering everything needed from one texture before binding a new one,
even if you don’t render the string chars in order.)

You might get small wins if you prerender strings that never change to a
texture, but the overhead of a few more simple draw calls verses the
extra texture memory is probably negligible; you’d have to profile, but
the simpler code is probably way more desirable in any case.

–ryan.

I have the same advice as Jonathan, however, I’d backup and simply use TTF
as normal. Normal though, is where you don’t do work until you need to. If
you only update the parts of the screen that change, when they change, all
platforms are pretty fast. When I started out I would generate text every
iteration of my program . So my program cycle faster than the screen
refresh rate, and I would see the changes at the speed of the refresh until
I worked the program hard enough that I would see lag . Here’s an example.
Keep in mind that the basic form is correct here, but I have not started
trying to make it faster yet because it is still alpha. This means all of
the features are not even there yet, so I’m not worried about speed. If I
do my alpha works well , I may never need to. Whisper8.com/data/twin
dragon_sdl2_game_example.zipOn Feb 10, 2014 10:23 AM, “Glocke” wrote:

Hi, I migrated my SDL-wrapper from v1.2 to v2. Now I plan to improve my
text rendering api. Currently, I am caching TTF_Fonts and create surface
(and then the texture) each time I change a text.

My new approach might be pre-rendering all needed characters once,
creating the surface (and then texture), so I can render the parts of the
texture depending on the string I am rendering.

Here is some simplified pseudocode for the actual rendering

Code:

function renderString(texture t, string s, position xy):
for each character c in s:
calculate offset for c within t
render(t, offset, xy)
x += width of c (might be equidistant)

Is this approach useful? I’m not sure whether this
iteration-through-the-string-on-each-render is fast enough. By the way: I
am working on a netbook - so speed is quite relevant (not in critical way,
but relevant^^). In my opinion this approach (using equidistant character
width) might be useful for bitmap-based fonts as well.

I hope I described enough in detail [image: Smile] Anyway, thanks in
advance! [image: Smile]

Kind regards
Glocke


SDL mailing list
SDL at lists.libsdl.org
http://lists.libsdl.org/listinfo.cgi/sdl-libsdl.org

Okay, cool! Thanks :slight_smile:

What’s about fixed-width-fonts and non-fixed-width-fonts? If I assume a Bitmap Font might use fixed-width glyphs everything is quite easy. But when using True Type Fonts with different font widths I need to handle this in another way:
Either make them fixed-width and work with as described. Or I need to calculate each glyph’s size and need to lookup it while rendering. Sure: when using e.g. ASCII as template for the prerendering I can use a continuous array of length 256 to store each glyphs size, so I get constant seek/access time. This might be the better solution, isn’t it?

What’s about fixed-width-fonts and non-fixed-width-fonts? If I assume a
Bitmap Font might use fixed-width glyphs everything is quite easy. But
when using True Type Fonts with different font widths I need to handle
this in another way:
Either make them fixed-width and work with as described. Or I need to
calculate each glyph’s size and need to lookup it while rendering. Sure:
when using e.g. ASCII as template for the prerendering I can use a
continuous array of length 256 to store each glyphs size, so I get
constant seek/access time. This might be the better solution, isn’t it?

Here’s what we did for Dungeons of Dredmor.

Originally (as a software-rendered SDL 1.2 game), Dredmor used SDL_ttf
and rendered strings to a Surface and blitted that Surface appropriately.

This worked because the game isn’t CPU-intensive in general, and
everything was in a memory buffer waiting to be blitted to the screen,
so a little more memory bandwidth and overdraw wasn’t a big deal for
this title.

When we moved to SDL 2.0, and to its Render API, I wanted to get
everything onto the GPU, so this system would have been pushing lots of
new texture data to the GPU every frame, so I moved it to a font atlas.

I hacked up the utility here to fit my specific needs:

 https://code.google.com/p/freetype-gl/

So I gave it a font and it spit out a .png and a bunch of C code like this:

static const texture_font_t font8 =
{
//height, linegap, ascender, descender
10.750000f, 0.720000f, 7.770000f, -2.260000f,
{ // individual glyph details…
// tex_x, tex_y, width, height, offset_x, offset_y, advance_x
// […snip…]
{ 6, 2, 4, 4, 0, 4, 4.125000f },
{ 11, 2, 5, 4, 0, 4, 4.187500f },
{ 17, 2, 6, 4, 0, 4, 5.906250f },
{ 24, 2, 5, 4, 0, 4, 4.203125f },
{ 30, 2, 6, 6, -1, 4, 4.296875f },
{ 96, 3, 4, 4, 0, 4, 3.562500f },
// […snip…]
};

This system wasn’t made robust for Unicode (at this moment), but it did
let us render an ‘A’ in 8-point font by doing:

 const texture_font_t *myGlyph = &font8.glyphs['A'];

And then drawing from the right part of the texture and taking all the
other metrics into account.

Here’s the .png it spit out, with the background flattened to black so
you can see it in a web browser (normally the background is transparent)…

 https://icculus.org/~icculus/dotplan/Austin.png

As you can see, it’s not fixed width, and we stored multiple font sizes
in one texture. We could have stored multiple unrelated fonts in the
same way, too. If we were really fancy, we could have saved some pixels
by reusing pieces (the letter and the letter with an accent, for
example), but the software didn’t do that by default and we weren’t
desperate to save space here.

If we moved to proper Unicode and translated to, say, Japanese, we would
need bigger (and multiple) textures, and probably a hashtable of glyphs
instead of a flat array…and maybe generation of the font atlas at
runtime. As it stands now, the game doesn’t use SDL_ttf at all anymore,
as that utility that generated the font atlas did all that work offline.

–ryan.

Cool, thanks for your input!

At least at the moment, I will stick with a combination of fixed-sized bitmap fonts and individually-sized truetype fonts, pre-rendered, so I can push both to a texture and store the clipping size within the normal memory. So I will render parts of the currently selected font-texture by using the glyph’s corresponding clipping size.

By the way: You were also talking about Unicode-support… My plan until now was a combination of a continuous array and a hashmap for clipping size. So common glyphs like A-Z, a-z or 0-9 will be handled by the continous array to reach definitively constant access time for the (estimated) most common glyphs and constant (to linear) time to access less common glyphs like symbols, Japanese, German umlauts (ftw is that really the correct translation? xD) an other stuff. So on each look-up I need to check if the current char is “common”. But I think this overhead might be balanced by the constant access time if many common glyphs are used. Maybe moving some symbols like "!?.:,;()[] etc. to common would be a good idea, as well.

What’s your oppinion about this mixture? As I said: just an idea for getting the clipping size of a non-fixed-size font’s glyph :slight_smile:

Ryan C. Gordon wrote:

What’s about fixed-width-fonts and non-fixed-width-fonts? If I assume a
Bitmap Font might use fixed-width glyphs everything is quite easy. But
when using True Type Fonts with different font widths I need to handle
this in another way:
Either make them fixed-width and work with as described. Or I need to
calculate each glyph’s size and need to lookup it while rendering. Sure:
when using e.g. ASCII as template for the prerendering I can use a
continuous array of length 256 to store each glyphs size, so I get
constant seek/access time. This might be the better solution, isn’t it?

Here’s what we did for Dungeons of Dredmor.

Originally (as a software-rendered SDL 1.2 game), Dredmor used SDL_ttf
and rendered strings to a Surface and blitted that Surface appropriately.

This worked because the game isn’t CPU-intensive in general, and
everything was in a memory buffer waiting to be blitted to the screen,
so a little more memory bandwidth and overdraw wasn’t a big deal for
this title.

When we moved to SDL 2.0, and to its Render API, I wanted to get
everything onto the GPU, so this system would have been pushing lots of
new texture data to the GPU every frame, so I moved it to a font atlas.

I hacked up the utility here to fit my specific needs:

https://code.google.com/p/freetype-gl/

So I gave it a font and it spit out a .png and a bunch of C code like this:

static const texture_font_t font8 =
{
//height, linegap, ascender, descender
10.750000f, 0.720000f, 7.770000f, -2.260000f,
{ // individual glyph details…
// tex_x, tex_y, width, height, offset_x, offset_y, advance_x
// […snip…]
{ 6, 2, 4, 4, 0, 4, 4.125000f },
{ 11, 2, 5, 4, 0, 4, 4.187500f },
{ 17, 2, 6, 4, 0, 4, 5.906250f },
{ 24, 2, 5, 4, 0, 4, 4.203125f },
{ 30, 2, 6, 6, -1, 4, 4.296875f },
{ 96, 3, 4, 4, 0, 4, 3.562500f },
// […snip…]
};

This system wasn’t made robust for Unicode (at this moment), but it did
let us render an ‘A’ in 8-point font by doing:

const texture_font_t *myGlyph = &font8.glyphs[‘A’];

And then drawing from the right part of the texture and taking all the
other metrics into account.

Here’s the .png it spit out, with the background flattened to black so
you can see it in a web browser (normally the background is transparent)…

https://icculus.org/~icculus/dotplan/Austin.png

As you can see, it’s not fixed width, and we stored multiple font sizes
in one texture. We could have stored multiple unrelated fonts in the
same way, too. If we were really fancy, we could have saved some pixels
by reusing pieces (the letter and the letter with an accent, for
example), but the software didn’t do that by default and we weren’t
desperate to save space here.

If we moved to proper Unicode and translated to, say, Japanese, we would
need bigger (and multiple) textures, and probably a hashtable of glyphs
instead of a flat array…and maybe generation of the font atlas at
runtime. As it stands now, the game doesn’t use SDL_ttf at all anymore,
as that utility that generated the font atlas did all that work offline.

–ryan.

I had been writing a tool similar to Ryan’s (but it’s abandoned by now).

At some point, when supporting multiple script is needed, the font atlus might get surprisingly large (common kanji consists of 2000+ glyphs, for example). You might want to split a very large texture into smaller ones in the case.

Some script might need glyph metrics adjustment. Thai, for example, needs an adjustment for its ‘tone mark’ characters (as well as some vowel marks). If you use only glyph metric provided by the glyph, you might find that ‘tone mark’ floats way too high, or sinks into other characters. The adjustments should be kept in the font metrics as well, if you’re aiming localization in these kind of language. (well at least the market here in Thailand is not very large, you may not be interested :slight_smile: ). Many available fonts are designed to avoid this requirement altogether, but it results in imperfect output.

There are also some script that requires glyph substitution. This kind of feature usually works one level above the text renderer, but it might be interesting to consider as well.

Guess I was too much into the details (that not really necessary). Talking about text rendering is really fun.