Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » Is there a more efficient way to reload/resize TTF fonts?

This thread is locked; no one can reply to it. rss feed Print
Is there a more efficient way to reload/resize TTF fonts?
henrycgs
Member #23,496
August 2022

Hello all.

I'm developing a game with Allegro 5.2.7, and I ran into a problem with fonts. It seems like fonts in Allegro must have a fixed size that you set when calling al_load_font. Now, my game must work at any screen resolution, with a resizable window, which means I must resize the text accordingly during runtime.

There are multiple ways to solve this problem. One is to use a temporary bitmap and draw that bitmap at whatever scale I want. It works alright, but the text will look pretty bad at big enough or small enough scales, even with linear filtering. Another is to deal with transformation matrices. It's faster, but looks even worse, as I'm stuck with nearest neighbour sampling.

So lately I've been exploring the idea of just... loading the font multiple times. It looks the best as the text is crisp at any size. However I run into the obvious issue of it being ridiculously slow. It does help a lot if I cache the font sizes, but whenever I drag to rescale the window, the poor thing will attempt to reload fonts tens of times per second, which is so bad it slows my system down.

This left me wondering if there is a smarter way of dealing with this. Is there a way to load a font once, and then "resample" it many times during runtime? I think that doing something crazy combining ALLEGRO_FILE_INTERFACE, fmemopen and al_load_ttf_font_f would be a lot faster as I wouldn't be acessing disk at every frame, but that is a can of worms I only want to dive in if I'm certain there is no better option.

Any help would be appreciated :)

amarillion
Member #940
January 2001
avatar

henrycgs said:

will attempt to reload fonts tens of times per second

Surely there is a middle ground here. If you cache the fonts per size, then you only need to reload fonts when the screen is actually resized.

In my games, I have a resource class that wraps a .ttf file. Then you can use it to request the font in any size.

// initialize
auto font = new TtfWrapper("data/Arial.ttf");
// get for a certain size
font->get(20);

The first time you make this call for a given font and size, it will load that font from disk, but keep a reference in memory. Any subsequent calls will just return the data that was loaded before.

Something like this:

#SelectExpand
1class TtfWrapper { 2private: 3 std::map<int, ALLEGRO_FONT*> fonts {}; 4 std::string fname; 5public: 6 TtfWrapper(const std::string &fname): fname(fname) {} 7 8 virtual ALLEGRO_FONT *get(int size = 12) { 9 if (fonts.find(size) == fonts.end()) { 10 ALLEGRO_FONT *font = al_load_font(fname.c_str(), size, 0); 11 if (!font) { 12 throw ResourceException(string_format("error loading TTF '%s' with size %i", fname.c_str(), size)); 13 } 14 fonts[size] = font; 15 } 16 return fonts[size]; 17 } 18 virtual ~TtfWrapper() { 19 for(auto &pair: fonts) { 20 al_destroy_font(pair.second); 21 } 22 } 23};

That's the simplified version, you can see the full version for my latest game here: https://github.com/amarillion/tins2022/blob/master/twist5/src/resources.cpp This has a few extra tricks, like transparently handling the builtin font and fixed-size fonts the same way.

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

Elias
Member #358
May 2000

I use a dual approach... when the window gets resized I use al_scale_transform and al_use_transform to immediately adjust font size. And I also store the current time. Then once there is no resize for one second I reload the font with the correct size and reset the scale to 1.

That way during resizing there's no slow reloading, and fonts always have the correct size (but some scaling artefacts). Then after a second (plus loading time) text also will look nice again but fonts never get reloaded more then once per second.

--
"Either help out or stop whining" - Evert

Chris Katko
Member #1,881
January 2002
avatar

Pretty much the same.

Just load every font you want, at every range of sizes you need. You're never going to need hundreds or thousands of them, and RAM is cheap. It's a font. Not a 128 GB megatexture.

-----sig:
“Programs should be written for people to read, and only incidentally for machines to execute.” - Structure and Interpretation of Computer Programs
"Political Correctness is fascism disguised as manners" --George Carlin

Edgar Reynaldo
Major Reynaldo
May 2007
avatar

You can load images and fonts in a separate thread, but you have to convert them to video bitmaps before you can use them in the main thread with the main display.

NOTE
There is a set of bitmaps for every font, so it does use some GPU memory after loading them into video bitmaps. Fonts respect the new bitmap flags, as they are made of bitmaps.

Go to: