the Fiddler's picture

New text renderer

Project:The Open Toolkit library
Assigned:the Fiddler

I have just committed a WIP implementation of a new text renderer to the text branch. Improvements:

  1. Simpler to use.
  2. More modular. It is now possible to have different GL1/GL2/GL3-level output or text layout providers. It is also possible to specify your own implementations (for example if you wish to integrate this into your engine).
  3. More accurate rendering (better grid fitting).
  4. Improved speed and reduced GC pressure through caching.
  5. Lower texture memory consumption.

The new implementation is based on GdiPMeasureCharacterRanges, which provides better control over text layout, when compared to MeasureString (the old implementation). Text is now cached on two levels, rasterized glyphs (loaded in texture memory) and laid out text. The public API looks like this:

// No TextureFonts, TextHandles or anything.
TextPrinter text = new TextPrinter();
text.Print("Hello, World!", font);
text.Print(fps.ToString(), font, TextPrinterOptions.NoCache);
TextExtents extents = text.Measure("ABC", font);
RectangleF bbox = extents.BoundingBox;
RectangleF char_pos = extents[1];  // Returns the position of "B" - useful for e.g. drawing a caret or selecting text.

The implementation in SVN is still under heavy development. Caveats:

  • (Fixed) Single texture sheet limitation remains. This is proving more difficult than expected.
  • (Fixed) Sometimes binds the wrong texture for glyphs (funky results!)
  • Trying to draw / measure uncached strings with newlines will cause GC pressure. This is the unfortunate result of a bug in Mono's GdiPMeasureCharacterRanges implementation. Fortunately, this is unlikely to cause problems in real life (you don't usually create dynamic text with newlines in a tight loop).

Anyone still interested despite these problems, you can test the code from the text branch. Expect screenshots shortly.

Edit: Clarified GC-pressure caveat.


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture


Sure, here comes. Old method first, new method second. Sizes are 8, 10, 12, 14, 16, 18 and 20 points (96 DPI), font is Times New Roman:

Notice how much better defined the text is at 10 and 12 pts. 8pt text suffers a little with the new method (long story), but you shouldn't use such small sizes anyway. Text quality is even better under Linux with a properly configured FreeType or Windows 7, both of which support y-direction antialiasing.

(edited to give more information)

objarni's picture


GdiPMeasureRanges - it sounds Windows..? Is this a .NET function or native Windows thing? I'm thinking about linux ...

the Fiddler's picture


It's GDI+, which ships with both .Net and Mono.

objarni's picture


Cool. Just wanted to be sure :)

Inertia's picture


Thanks! The difference is quite noticable, the old method looks like the font is bold, compared to the new method. The "rld" in the new methods 8pt font is not legible, but also with the old method is was just barely legible, so not much of a change. The new method handles the border cases (where the fragment cannot be clearly assigned to a single pixel) much better. Therefore the new method looks much more subtle and better, good job :)

Don't want to nag, but could you redo the magnification without bilinear filter? Would be good if pixels are doubled, i.e. nearest filter. The windows magnifying glass gives quite a different result compared to your magnification. (My observations rely on the magnifying glass, not the blurred magnification)

the Fiddler's picture


The magnification is handled by your browser. Sorry, too lazy to crop resize and upload 4 pictures :)

Edit: The filtering seems a Windows thingy - both Firefox and Opera magnify without filtering on Linux.

Edit 2: Internet Explorer doesn't filter either. (Guess I could have just uploaded new images instead of testing all browsers - I was a curious)

Edit 3: Serif fonts, such as Times New Roman, aren't really legible at small point sizes. Verdana, Arial et al stay legible down to 7 pt.

JTalton's picture


This is wonderful! I was hoping for something like this to happen. :)

Inertia's picture


I've got the magnifying glass in the quickbar so it's np. Don't bother, I didn't know you did the scaling with html tags until you mentioned it, just looked too blurred to give any real information about how the rastered font looks at pixel level.

What's the magic that lead to this improvement?

the Fiddler's picture


No magic - I just realized that subpixel antialiased fonts simply contain three alpha channels (one per color) instead of a single one. Which means it's just a matter of setting up the correct blending mode / shader.

This doesn't give 100% correct results, since it doesn't gamma-correct the subpixel intensities according to the background and foreground colors. Since we cannot know the background color beforehand, we just assume white text on black background - the gamma will be a liitle off, but the result is good enough. As far as I know, only WPF is able to draw gamma-correct text on non-uniform backgrounds.

Inertia's picture


3 alpha channels ... hadn't heard of that before.

I don't think the gamma correction is possible in GL without grabbing a copy of the framebuffer first :| Nevertheless, a great improvement!