PDA

View Full Version : Diffuculty with character kerning and GL



mcsellski
11-25-2002, 11:47 PM
At least, I think that it's kerning that's the problem....

I've developed an IDE. One of the features is that strings can be added as annotations to the scene by the user. The app is UNICODE so I had to write a font manager to efficiently build the string with wglUseFontBitmaps() for each individual character. I then call the GDI method GetGlyphOutline() to get the extent of the character to that I can work out where to place the gl font bitmap. With me?

The reason I go to this trouble is that it's too expensive to load the complete unicode character set into a display list, it takes too long and too much memory.

The problem is that I cannot consistently get the character placement right, especially characters like 'i' and '.'. They tend to overlap other characters. It may be a kerning problem, but I don't know enough about it to be sure.

Can anyone suggest where I may be going wrong and the pitfalls that I need to watch out for?

Of course, I could just use fixed width fonts, but I'd rather try a bit harder and get a good result.

Thanks

matthew

richardve
11-26-2002, 12:18 AM
Why don't you use FTGL instead?

Much better..

(use google to find this library)

Endymio
11-26-2002, 02:20 AM
I wrote a font rendering engine similar to the FTGL and I don't think that the problem you are seeing comes from the kerning. One thing that looks a bit suspicious is the fact you are mixing outline and bitmap font dimensions. Remember that the bitmap font must be grid fitted to individual pixels and the resulting distances for bitmap glyphs can easily be longer than the distance for outline glyphs. In other words, you should use the bitmap glyph dimensions alone. For more information about what happens when a Truetype font is rendered into a bitmap, see the Freetype libary documentation at: http://www.freetype.org Especially the Freetype Glyph Conventions document is a good read.

If you need to render text with sub-pixel accuracy you will probably need to create a custom screen lay-out library, but this is a large project to undertake.

Disclaimer: I haven't actually used the windows api glyph functions, but instead the Freetype library. The underlying font dimension calculation and glyph placement algorithms should still be the same.

jwatte
11-26-2002, 08:15 PM
Just rasterize your text to a bitmap, and upload the bitmap to a texture. That's the only sane way of dealing with text in graphics, in my humble opinion. Make sure to render the texture at 1:1 relation to screen pixels, and it'll look as crisp as any word processor.

I use GDI to rasterize to bitmap. Other people use third-party libraries (FreeType, or whatever). Just don't go down the path of display lists; it'll drive you insane and never look good enough.

Julien Cayzac
11-27-2002, 02:14 AM
This whole subject is off-topic, but since we're speaking about unicode text rendering...

In my past experiences, I've implemented the following methods (chronologic order):
1/ All used glyphes are first rendered in one single texture. This can't be done when dealing with unicode and many non-latin characters.
2/ Each used glyph is rendered on-demand in a texture. Glyphs are cached so older one get removed when the glyph "pool" is full.
This drastically increase the number of textures, though.
3/ Like jwatte said before, I've ended up rendering each used text in a texture and using a cache on a per-text basis.

Although 3 is sufficient in many cases, I'm still not happy with it (e.g. 2 allowed me to implement printf()-like functions).

Anyone with thoughts about a more efficient design? My apps always use UTF-8 encoded strings that can have many different CJK characters, so it's all about several thousand glyphes http://www.opengl.org/discussion_boards/ubb/biggrin.gif

Julien.

jwatte
11-27-2002, 07:02 AM
Deepmind,

I don't understand why you couldn't implement printf() style functions? Just use vsprintf() to format your string into a buffer, and splat that buffer into a texture (using GDI or whatever). While you may have zillions of strings in your program, you're very unlikely to display them all at the same time.

So, allocate texture space for the area(s) that display text (name tags, overlay console window, scrolling chat, whatever) and render the text into textures for those areas, rather than trying to render all possible text and then matching up textures to places to render.

I don't think caching specific texts is all that useful, either. Caching a texture image (bitmap) from frame to frame gives you almost all of the benefit, at a fraction of the cost and complexity.

Julien Cayzac
11-27-2002, 08:01 AM
Originally posted by jwatte:
I don't think caching specific texts is all that useful, either. Caching a texture image (bitmap) from frame to frame gives you almost all of the benefit, at a fraction of the cost and complexity.

jwatte,

The problem comes from the TrueType rendering code (external, part of FreeType), which is not that fast. When I render many glyphes at a time my app is as fast as a snail trying to move on melted tar http://www.opengl.org/discussion_boards/ubb/biggrin.gif

So I try to minimize the number of calls to FreeType as much as possible, and I cache pre-rendered texts. When a text is rendered on deman, it gets cached as well so if it's needed on the next iteration (== next frame) it won't be rendered twice.

But having only one texture per "text" bothers me, since a text can be quite long and use one block of glyphes many times. This is a granularity problem: 1 glyph == 1 texture is far too small but 1 text == 1 texture is a bit too much... I should have a pattern-matching algorithm which dynamically manages blocks of rendered text depending of their frequence in processed sentences...

Julien.

rlskinner
11-27-2002, 08:58 AM
Why not render groups of characters into a single texture and keep track of their texture position & extent?

jwatte
11-27-2002, 09:36 AM
I'm not saying put the actual book into the texture. I'm saying put whatever will fit into the on-screen text representation (console, or what have you) into the texture.

If you scroll by line, then have your bitmap sized to account for an extra line of text, draw the extra line (only) and upload the new scrolled position every frame until the top line is gone; then memmove() your backing store to account for the scrolling.

Obviously, you can't render a full page of text anew per frame; nobody would be able to read that fast. If you want to, say, page-down in a display, consider scrolling one full line per frame, so that you only re-generate one line of text per frame. That will make the text smooth-scroll in your app, too.

Basically, I'm recommending creating one texture and backing-store bitmap per display surface in the scene, and treating these like you would a regular framebuffer that you're drawing text into in a regular 2D GUI application. The same optimizations for not re-drawing too much apply.

henryj
11-27-2002, 03:17 PM
jwatte's method is the best way to render 'screen aligned' text but wont work for text at arbitrary positions in space.

Anyway this isn't mcsellski's problem. I suspect that you are having float to int problems. Endymio's explanation sounds bang on. I struck this when writing FTGL. The advance in float may be 1.8, but as an int is 1.0, so your glyphs are too close. Bitmap renderers have hinters that compensate for this problem. I know nothing about windoze api but you should be able to enable hinting and then use the bitmap dimensions for positioning not the outline dimensions.

Caching your glyphs is a good way of dealing with unicode fonts. Only create the glyph the first time it's needed. The problem is that rendering individual characters is slow. Speed may not be a problem for a gui though. I'm working on a middle ground solution for FTGL at the moment.

mcsellski
11-29-2002, 05:13 AM
Originally posted by rlskinner:
Why not render groups of characters into a single texture and keep track of their texture position & extent?

I'm glad you suggested that as it is more or less what I do, so I can't be that far wrong. I don't render into a single texture as I have to cope with zooming and tranlsation in the viewport while keeping the console text and selection properties that I might be displaying a constant size.

I create a list for each character in the string and use GDI to work out the extents. It seems from henryj's suggestion that I need to pay more attention to any inadvertent type casting that I might be doing.

I had a good long go at using FTGL and had a lot of success. I'm a bit put off by its platform independence. I have made extensive use of Window's LOGFONT structure instead of ttf files which seems to make a bit more sense when you are trying to deploy software. If there was an interface between the LOGFONT structure and FTGL I'd use it I think. Is there one?

Anyhow, this seems to be an ongoing debate. Thanks to everyone who has added to this thread. It's greatly appreciated.

Regards

Matthew