Allegro.cc - Online Community

Allegro.cc Forums » Allegro Development » Font Sub-Pixel Rendering

This thread is locked; no one can reply to it. rss feed Print
 1   2 
Font Sub-Pixel Rendering
Todd Cope
Member #998
November 2000
avatar

A while back I saw this subject mentioned (I couldn't find the thread). Allegro adjusts the coordinates when rendering text so that it will always be drawn aligned to the nearest pixel. I'm not sure why it was implemented this way, but I'm sure the developers had a good reason.

I am having a problem when I use transformations while rendering text and other graphics, or more generally, when drawing moving objects that contain text. The text movement and scaling appears jittery compared to the rest of the graphics.

When this issue was brought up before, it was mentioned that a way to disable the coordinate adjustments might be added. I haven't heard anything since.

While looking at the code I noticed that al_draw_justified_* does not do this integer pixel alignment. This means there is an inconsistency in the text rendering functions.

I don't see why the integer pixel alignment should be done at all, myself. The user should be doing that in their own code if they desire it. If we did away with the integer pixel alignment altogether, that would make the library's drawing functions consistent and easier to understand.

At the very least, there should be a way to disable the integer pixel alignment via a flag passed to the text rendering functions. As it is, I'm stuck having to come up with a convoluted solution to get my text and objects to line up and move smoothly together.

amarillion
Member #940
January 2001
avatar

I sort of agree with your argument, but can't you work around the issue by rendering text to a temporary bitmap, and using that to move the text around?

Trent Gamblin
Member #261
April 2000
avatar

I'm curious what the reason is for it to be the way it is now, if it was purposefully made that way.

Elias
Member #358
May 2000

It was done to have text look pixel-by-pixel exactly the same as other applications using the same font and size. Basically when freetype does anti aliasing it expects each output pixel to, well, be one pixel. If anti-aliasing is applied a second time while drawing the texture the result looks a lot worse.

Justified text should also do that, if not it's a bug.

For transformed text it often makes no sense doing it, neither when you use multi sampling and actually need sub-pixel positions. So yes, I think there should be a (per-font, most likely) way to disable it.

[edit:] Ok, looking at the code [1] it looks like only the glyph widths are truncated to integer. This allows perfect looking glyphs as long as you render your text to integer positions.

However using sub-pixel rendering should also work. If you draw the text at x = 0.1, y = 0.1 it will be shifted by 0.1 pixels and all glyph distances will remain the same.

What will not work is scaling though - there basically is an implicit assumption that when the font is loaded one FreeType pixel also is one real pixel.

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

Todd Cope
Member #998
November 2000
avatar

... can't you work around the issue by rendering text to a temporary bitmap, and using that to move the text around?

That's exactly the kind of convoluted solution I am trying to avoid. I shouldn't have to resort to that.

The TTF code works just fine. I am referring to this code being applied to all coordinates passed into al_draw_ustr() and, by extension, al_draw_text() and al_draw_textf().

I can't see the reason for Allegro to force me to draw at integer-aligned pixels. If I want that alignment, I can apply it myself. Otherwise, the text rendering should work like the rest of the drawing functions.

Thomas Fjellstrom
Member #476
June 2000
avatar

Todd Cope said:

That's exactly the kind of convoluted solution I am trying to avoid. I shouldn't have to resort to that.

You might want to think about doing that at some point anyhow as text rendering is a bit slower than some people would like.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Elias
Member #358
May 2000

So, what about a new font loading flag ALLEGRO_TTF_NO_ALIGNMENT? Fonts created with it would not do that integer alignment. (And probably also not truncate the glyph distance to integer.)

Also, would be nice if the patch for it could include a simple example demonstrating the difference between two such fonts.

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

Todd Cope
Member #998
November 2000
avatar

I don't like the font loading flag as much as a flag to pass to al_draw_* font functions. With the drawing flag I can use the same font for both situations.

I don't think it makes sense to not truncate the glyph distance, since it was designed that way to get the same output as other applications using Freetype. That behavior is not at issue here.

There are also bitmap fonts, so the loading flag should have a more general name (ALLEGRO_FONT_NO_ALIGNMENT) if we were to go that route.

I already have a patch ready (see attachment) for the drawing flag method. It adds a new flag, ALLEGRO_NO_INTEGER_ALIGN, that disables the alignment in al_draw_ustr(). I wouldn't mind adding an example to show the difference.

Edit: The font loading flag would also be fine, and I will do a patch for that instead if that's what everyone else wants. I think it has more to do with rendering than loading so, naturally, I went with the drawing flag.

Trent Gamblin
Member #261
April 2000
avatar

You can use the same font with the loading flag too. Just pass integers to the drawing functions.

Elias
Member #358
May 2000

Just pass integers to the drawing functions.

Well, not quite since there can be a transformation. But it would be interesting finding the thread where it was added. It does not sound terribly useful and none of the current examples shows it being used.

[Edit:]
What about using an ALLEGRO_ALIGN_INTEGER flag instead and changing the default behavior to not do it? If someone draws text to 0.5/0.5, we should assume that's what they want and not adjust it to 0.0/0.0 behind their back.

Also, I remember a certain dislike for NO flags by some other devs, so we'd solve that as well :)

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

Todd Cope
Member #998
November 2000
avatar

Sounds good to me.

Edit: Attached a patch for this.

Edit 2: With sub-pixel rendering of fonts I am having a small issue. With filtering on, some characters have distortion at the edge due to the glyph bitmaps being positioned at the edge of the page. This only affects TTF fonts. Would you guys be opposed to leaving a 1 pixel transparent border on the page(s) to prevent this from happening?

Trent Gamblin
Member #261
April 2000
avatar

I wouldn't. I thought we already had something like that in fact, but if not we should.

Todd Cope
Member #998
November 2000
avatar

It currently just leaves a 1 pixel space between the glyphs. It starts filling the page at (0, 0). I've attached a patch to make it start at (1, 1) instead.

Trent Gamblin
Member #261
April 2000
avatar

Have you looked at the bottom edge and the possibility that glyphs may reach all the way down to the last pixel?

Todd Cope
Member #998
November 2000
avatar

Yeah, the bottom and right are already padded due to the glyph spacing code so it will never render on the right or bottom edges. Glyph widths are padded with 1 pixel on the right and bottom, and that extra pixel is included in the test for when it is time to go to the next row or make a new page.

Trent Gamblin
Member #261
April 2000
avatar

Ok, just making sure... I'll apply your patch. Thanks!

Elias
Member #358
May 2000

Does that keep the locking aligned to 4-pixel boundaries?

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

Todd Cope
Member #998
November 2000
avatar

Yes, the alignment happens after the pixel is added so it will start at 4 after the alignment.

Edit: Actually, let me verify that before saying it for certain.

Edit 2: Okay, it doesn't. I've attached a new patch which uses the align4() function to align to 4 pixels if ALIGN_TO_4_PIXEL is defined.

Elias
Member #358
May 2000

I applied an alternate patch which does this.

Just out of curiosity, why do you want a one-pixel border against the bitmap edge? It seemed to me that only the space between glyphs is required.

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

Todd Cope
Member #998
November 2000
avatar

Glyphs that lie at the edge of the bitmap get distorted when rendering to sub-pixel coordinates when filtering is turned on.

Elias
Member #358
May 2000

Distorted in what way?

I'd assume texels at the border do whatever the edge clamp mode tells them to. We probably should set it to GL_REPEAT so the transparent pixels from the other side of the texture get used. Anyway, the 1-pixel gap we have there now is no problem.

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

Todd Cope
Member #998
November 2000
avatar

{"name":"606674","src":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/3\/4\/346d624367bf7798be4243f71887cf2b.png","w":256,"h":140,"tn":"\/\/djungxnpq2nug.cloudfront.net\/image\/cache\/3\/4\/346d624367bf7798be4243f71887cf2b"}606674

Both characters in the image are rendered halfway between a pixel. The one on the left is a character that is at the edge of bitmap. The one on the right is a character that is offset from the edge by one pixel in the bitmap.

When I am moving the objects in my project, the characters will look similar to the one on the left when the object is between pixels if the character happens to be on the edge of the glyph page.

The problem is exacerbated by the fact that the characters will behave differently depending on where they happen to be in the glyph page. When I have a string of text, some of the characters move smoothly while others jump to the nearest pixel. This looks really bad.

Elias
Member #358
May 2000

I see. And yes, I guess setting the repeat mode to GL_REPEAT instead of GL_CLAMP_TO_EDGE would also solve it. The way it's done now is still better since then we don't have to mess with the texture repeat mode.

Of course, this now has me thinking about a function to change the texture repeat mode, both for OpenGL as well as Direct3D...

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

Trent Gamblin
Member #261
April 2000
avatar

You wouldn't have to "mess around" much. Texture repeat mode is part of a textures state. So you'd set it for those textures that need it then set it back to whatever it was before.

EDIT: Seems you don't have to set it back? glTexParameter just works on the currently bound texture, and when they're created they have default values. I think.

Thomas Fjellstrom
Member #476
June 2000
avatar

This may be a n00b question, but does glTexParameter work on the texture itself? Or the texture unit? If the latter it'd need to be saved/restored with each texture wouldn't it?

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

 1   2 


Go to: