OpenGL TTF (theory)

Started by
8 comments, last by Nercury 11 years, 2 months ago

I need to make a TrueType/FreeType font renderer. So, I wanted to sort out my thoughts. I just want an overall theory how to make it.

Below are my thoughts how to make it. Please give feedback if it makes sense or not (or if it can be done easier/better). Even just one line answer would be enough (so I know if I'm going in the right direction).

Backstory and my requirements

I need basicly a typical 2D print(), without extras (I just setup an Ortho projection and use pixel perfect coordinates for everything, in practice not distinguishable from any 2D API, except speed). Right now I'm using SDL_TTF but it's soooo slow it's not bearable at all :) So, I mostly need just a relatively fast 2D TTF renderer that works with OpenGL 2.0 (note I don't need the fastest possible solution, just fast enough, I don't want to spend too much time on making YetAnotherFontRenderer, I just want one that is acceptable and then move on to making a game :) ). I was also considering using a library for this but after checking several I concluded it would be faster to write one (poor documentation, too high hardware requirements - use of shaders, overall bloated code, etc).

1. Data

After big disappointment of SDL_TTF's performance I think I should use strictly my internal font format (texture with glyphs + table with various metrics), a TTF library would be used only to create the initial internal font file (TTF is simply not suitable for real time rendering). The game would first try to load the internal font file, if not present it would create it, save it and then attempt to load again (fast load).

2. Font size

I think I will treat various sizes of the same font (like 12 and 16) as completely separate fonts. Checking how I use fonts in practice so far it's completelly sufficient. I would skip all OpenGL resize (not really needed in my case and a font rendered for exactly the destination size should be always a bit prettier).

3. Colours

I'm not sure how antialiasing works, but wouldn't it be sufficient to render white font to the texture and then use glColor() before rendering the text? Instead of preparing separate textures for each colour?

Stellar Monarch (4X, turn based, released): GDN forum topic - Twitter - Facebook - YouTube

Advertisement

Are you planning on rendering using vector or texture based rendering?

[quote name='Acharis' timestamp='1358354393' post='5022225']
I don't want to spend too much time on making YetAnotherFontRenderer, I just want one that is acceptable[/quote]

Text rendering is a the very definition of a rabbit hole: define 'acceptable'?

Will you ever need to localize for characters outside the Latin-1 codepage? Languages written right-to-left, or vertically? Languages with complicated ligatures?

[quote name='Acharis' timestamp='1358354393' post='5022225']
After big disappointment of SDL_TTF's performance[/quote]

Are you sure this is SDL_TTF's performance, versus the performance of your copying the resulting text into a texture?

Usually the main bottleneck here is copying and uploading the texture to the GPU. Make sure that your SDL text surface is power-of-two sized, that your SDL text surface has the same channel layout as your texture, and that you are updating an existing texture rather than uploading a new one each time (use glTexSubImage2D).

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

Requirements details:

- simpliest texture based rendering (it's just for simulating a traditional 2D text rendering)

- only 8 bit latin languages (256 chars max), left to right only. In around 99% cases I would not even need this and just use ASCII.

- needs to work under OpenGL 2.0 (would prefer 1.5 but that's not that important and I can live without it)

- decently fast (no need for the fastest possible) without being too troublesome to code (my goal is to make fun games, not efficient engines)

Are you sure this is SDL_TTF's performance, versus the performance of your copying the resulting text into a texture?

Usually the main bottleneck here is copying and uploading the texture to the GPU. Make sure that your SDL text surface is power-of-two sized, that your SDL text surface has the same channel layout as your texture, and that you are updating an existing texture rather than uploading a new one each time (use glTexSubImage2D).

Interesting... But even if, finetuning the copying part of the code would be at least as difficult, if not more, than making a simple texture based renderer. Plus it does not guarantee speed (it would still be slower in the end, since it has to go through SDL_surface before copying to a texture). One note I had SDL_TTF version of a library that way quite fast, but it was rendering it incorrectly. Then I switched to a newer version and it was correct but unacceptably slow. Anyway, it sounds to me as even more work than writing a texture based font renderer from scratch.

Stellar Monarch (4X, turn based, released): GDN forum topic - Twitter - Facebook - YouTube

you can use libfreetype to generate textures of a ttf font at any size. It's fairly easy to get these into GL

Have you considered using glfont? I found it was quite simple to integrate into my application and it works great (and fast).

[quote name='zacaj' timestamp='1358372514' post='5022314']
you can use libfreetype to generate textures of a ttf font at any size. It's fairly easy to get these into GL[/quote]

Or use the much simpler/smaller stb_truetype.h for the same purpose.

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

[quote name='Acharis' timestamp='1358372233' post='5022312']
Plus it does not guarantee speed (it would still be slower in the end, since it has to go through SDL_surface before copying to a texture).[/quote]

That pretty much depends whether you are bottlenecked on the GPU, CPU or bandwidth (and whether you need advanced text rendering capabilities).

Text rendering on the GPU is a bit of a misnomer, since you have to do all the text layout, kerning, etc. on the CPU anyway, and you are basically just using the GPU to push textured quads to the screen (the same as in the SDL_ttf case).

But assuming you do want to go the GPU route, it basically boils down to loading the glyphs for all of ascii into a single texture, and then writing some fancy CPU-side text layout code that outputs a vertex buffer with the texture coordinates adjusted as needed to pick the right portion of the texture for each quad...

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

One solution is also to use libRocket. The disadvantage is that it is a big library and takes some effort to interface. But the advantage is that you can create nice off-line definitions in a html/CSS-lookalike format. It can be used for both OpenGL 3+ and OpenGL 2+. It also has good support for decorations.

[size=2]Current project: Ephenation.
[size=2]Sharing OpenGL experiences: http://ephenationopengl.blogspot.com/

My approach is to lazy-render each separate glyph into opengl texture and update it if more glyphs are needed. Store information about every glyph and it's position on the texture. Rendering is amazingly fast, it is just mapping the right texture coordinates for each glyph. And it opens very nice possibilities for text effects.

Implementation consists of:

- Glyph object, which has glyph measurements and it's cached position of surface, as well as reference to opengl texture.

- A Factory object used to get glyph or return existing one based on char code. It manages unlimited surfaces for a specificly - sized font.

- A Surface to keep rendered glyphs on. I am always keeping SDL surface in memory, and refreshing opengl surface only on change or if opengl context is lost (resize).

Then I can have various text objects to render these glyphs in various interesting ways.

Color: I pre-render glyphs as white and use blending for color, as you said.

This is a crappy version of this approach written quite a long time ago: http://code.google.com/p/glstext/

Since I have rewrote all of it last week, I may share the code if anyone is interested. I even managed to get the kerning working, which is oh-so-amazing smile.png

This topic is closed to new replies.

Advertisement