PDA

View Full Version : how to display chinese in OpenGL



pango
06-02-2003, 08:27 AM
Does anyone know how to do it?

satan
06-02-2003, 12:12 PM
Originally posted by pango:
Does anyone know how to do it?

I would think that texture fonts will do the trick.

OneSadCookie
06-02-2003, 12:32 PM
We just had a discussion on Arabic the other day. Search and ye shall find...

And Chinese is much easier than Arabic, since it's left-to-right and the character->glyph mapping is context-free.

Pop N Fresh
06-02-2003, 01:38 PM
The thread on Arabic is here. http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/009609.html

With English one of the usual ways to render text is too put all the glyphs (characters) into a single texture and then draw a quad for each glyph with texture coords corresponding to the glyph's positoin on the texture. This works fine since alphabet + punctuation isn't that many characters. This won't work for Chinese because there are too many different glyphs.

For Chinese you'll need to write some sort of caching system. Either creating glyphs on demand or complete phrases on demand and then reusing the results. On windows you can use GDI to render glyphs or phrases to a bitmap and then upload that bitmap into an OpenGL texture.

Other operating systems will likely have simular functionality. If not, you can use FreeType ( http://www.freetype.org/ ) to rasterize TrueType fonts.

I prefer to cache entire phrases myself. When working with English it allow me to have proper kerning and ligatures and it was simple to integrate into my UI library by having every Label widget keep track of its own texture without the need to hash for glyphs.

Zeno
06-02-2003, 08:08 PM
If you use 16x16 pixel characters (is that enough resolution for the complexity of the characters?), they should fit in a 2048x1024 texture...

jwatte
06-02-2003, 08:33 PM
"font textures" are seldom the best way to display text.

My standard answer:

Create a DIBSection with its own DC.
Select a font into this DIBSection and draw just like on the screen.
GDIFlush()
glTexSubImage() this data into a texture
Draw quad the size of the texture, with the texture pixels on it.

On Linux, use FreeType to draw text offscreen instead of a DC/DIBSection.

On MacOS, use an offscreen GWorld (I suppose?)

henryj
06-02-2003, 08:54 PM
Try this...
http://homepages.paradise.net.nz/~henryj/code/index.html#FTGL

It uses freetype and handles chinese OK including caching etc resulting in high quality glyphs for minimum resource use.

It doesn't handle complex scripts eg arabic

Robert Osfield
06-03-2003, 03:26 AM
Originally posted by Zeno:
If you use 16x16 pixel characters (is that enough resolution for the complexity of the characters?), they should fit in a 2048x1024 texture...

What I have found to be more efficient is use a list of 256x256 textures and subload the glyphs which are needed by the app rather than trying to load all the glyphs from a character table into one texture. You potentially end up using more textures, but this is small price to pay.

This technique cuts down on wasted texture usage as you only use what you need, and cuts down on load time both of which would be otherwsie probibitve. I only tested Japanese fonts but it this case there were tens of thosands of glyphs in a single font file, I presume Chinese fonts are too much different in the numbers of glyphs required.

jwatte
06-03-2003, 11:27 AM
What's this obsession with loading glyphs and rendering text with lots of little quads?

It's almost never actually better than drawing text directly to a texture. Certainly, any kind of kerning or ligatures that your font renderer would do for you, you'll have a hard time emulating with a glyph-based approach.

Typography is important, and hard. Let the libraries that do typography, do it, and you just need to display the results.

Zeno
06-03-2003, 11:54 AM
Originally posted by jwatte:
What's this obsession with loading glyphs and rendering text with lots of little quads?


I don't think it's an obsession, I think it's just easier. I, for one, didn't know that you could do what you suggested in the other thread in a straightforward way...I'm not terribly familiar with windows programming. Have you ever thought about making a tutorial on it?

henryj
06-03-2003, 01:40 PM
jwatte's suggestion is by far the most efficient depending on the update rate of your text which is most cases isn't very high. You're not trying to write a word processor in opengl http://www.opengl.org/discussion_boards/ubb/smile.gif

I have plans to add this 'feature' to FTGL, no idea when though.

mattc
06-04-2003, 12:34 AM
it may not look as good but it's miles faster when you're not relying on win32 to render the font (dunno about other os's)... win32 font rasteriser is just incredibly slow, especially with antialiasing enabled.

using a texture (or a set of textures if you can't fit all glyphs in one) allows you to rasterise a font once and simply plop quads around afterwards... considering that win32 font rasteriser scales very badly with increasing font sizes, it may simply be impractical to use underlying font services in real time. my 2p http://www.opengl.org/discussion_boards/ubb/smile.gif

V-man
06-04-2003, 04:21 AM
Originally posted by jwatte:
What's this obsession with loading glyphs and rendering text with lots of little quads?


It sounded to me that that is what you are doing.

Robbo
06-05-2003, 06:40 AM
We solved this problem as mentioned above by implementing a texture cache - rendering required strings into textures using GDI (dibs). I think its the best solution, although depending on how many strings you require/cache size, it can be a potential cause of lag.

Robert Osfield
06-05-2003, 12:41 PM
Originally posted by jwatte:
What's this obsession with loading glyphs and rendering text with lots of little quads?


Its more an obsession with efficiency.

If you have a lot of text to render you almost certainly will be repeating glyphs (just count how many different letter's I use in this post - its going to be around 26 no?). Also if your whole screen is filled with text, are you going to create a 1024x1024 or bigger texture?

And what happens when you text changes, or that you have multiple pages or text? You update all your image?

The osgText only uses texture resources it needs, by subloading into texture tiles the glyphs which are need. The typography is important of course, so the quads are position according to what freetype. This really isn't a great overhead.

Another advantage of rendering small quads is the reduction in fill rate requirements, important since our graphics cards are invariably limited by fill rather than T&L. They also often limited by bandwidth so you want to keep those textures small as possible and update them in small bits, rather than updating big textures all the time.

So I'm more than happy to be obsessed about drawing lots of little quads :-)

Robert.

jwatte
06-05-2003, 07:22 PM
I suggest you actually go benchmark the concepts of:

One texture per "text item"

vs

One font texture, and one quad per character

In our case, our application is very text intensive (chat bubbles, communicator windows, etc) and we found draw-to-texture to be faster. Unless you update your text items very often, GDI-to-texture is likely to come out ahead, AND it looks better.

The "cached strings" approach works well, too; "strings" treated loosely. As long as you make sure your cache is big enough that you don't need to re-generate every frame :-)

One 1024x1024 texture is likely to fit all text strings you'll need to display on the screen at a time; you can TexSubImage updated strings into this texture when strings change.

Robert Osfield
06-07-2003, 02:31 AM
Originally posted by jwatte:
I suggest you actually go benchmark the concepts of:

One texture per "text item"

vs

One font texture, and one quad per character

In our case, our application is very text intensive (chat bubbles, communicator windows, etc) and we found draw-to-texture to be faster. Unless you update your text items very often, GDI-to-texture is likely to come out ahead, AND it looks better.

The "cached strings" approach works well, too; "strings" treated loosely. As long as you make sure your cache is big enough that you don't need to re-generate every frame :-)

One 1024x1024 texture is likely to fit all text strings you'll need to display on the screen at a time; you can TexSubImage updated strings into this texture when strings change.

The implemention that I opted for with osgText was designed to handle 10,000's of text labels per second, I'm getting 20fps in such heavy loads, and this is with a Geforce3 Ti200, not the latest a greatest graphics hardware. You quite simply can't get the same peformance for having 1,000's seperate textures.

You can also get excellent image quality for using seperate Quads, the rendering everything to a single texture gains you nothing in image quality.

What's appropriate for a particular application will depend on the needs of that application. If you a really pushing heaving text loads than the approach of using seperate quads for each glyph, and sharing textures is essential. If you have modest needs for text then rendering whole strings to textures can work fine.

Robert.

jwatte
06-07-2003, 08:01 AM
I don't see why you believe I suggest "1000s of texture". I said use a single texture and sub-load.

I am writing this commentary more for whomever reads this thread to make a decision; you seem to have a system that works well for you and that's all good.

It would seem to me that the MORE text you want to draw, the BETTER pre-rendering strings to texture would be, because you won't go vertex transfer bound at all as easily. 10000 strings at 20 frames per second would be 200,000 quads using pre-rendered, and easily 8,000,000 quads if each string is on average 40 character.

If you think generating all those strings in software is expensive, then consider two things:
1) You can do it while the card is rendering, so it's no more expensive than waiting on a stalled geometry transfer bound card.
2) The user can only read maybe 100 characters per second, if he's REALLY good. If you find yourself updating more than that, then your design is probably not such that the user is intended to read all the text.



You can also get excellent image quality for using seperate Quads, the rendering everything to a single texture gains you nothing in image quality.


Please look up "kerning" and "ligatures" in your favourite typography book. It seems that you account for neither of those (but I haven't actually seen a screen shot, so I don't know for sure). Also, proper shape-based anti-aliasing with sub-pixel precision is not possible when just blitting a small quad with a single character. My pre-press background is haunting me here -- these are important, subtle things that are hard to get right.

henryj
06-07-2003, 09:51 PM
I don't think anyone thinks that putting all your glyphs into one texture isn't a good idea. In fact it's essential to get anything remotely like good performance.

Also, just because to are using one glyph per quad doesn't mean you can't kern the glyphs or draw ligatures and composites correctly. FTGL currently handles kerning using the multi quad technique. Correct anti aliasing isn't a problem either.

I have to agree with John though that 'string' caching is the fastest for the reasons stated as long as you don't blow your texture budget.

Robert Osfield
06-08-2003, 02:37 AM
Originally posted by jwatte:
I don't see why you believe I suggest "1000s of texture". I said use a single texture and sub-load.


If each text label has in indepent string then you'll need lots of texture space to fit them all in, with 10 or thousands of labels you're gunna many more than a single texture, you're gunna need hundreds or even thosands of textures depending on the resolution of your texture.


[B]
It would seem to me that the MORE text you want to draw, the BETTER pre-rendering strings to texture would be, because you won't go vertex transfer bound at all as easily. 10000 strings at 20 frames per second would be 200,000 quads using pre-rendered, and easily 8,000,000 quads if each string is on average 40 character.
[B]

Indeed you start become bound by bandwidth of passing all the quads down, but this is better than better than bandwidth of passing all the texure required.

A 16x16 res glyph with lumuniance and alpha takes 16x16x2 = 512 bytes.

A single quad takes 4x12 (for the coords) + 4*8 for the tex coords = 80 bytes.

This is for a small res of a glyph, and even here one can see thats going to be *alot* cheaper to send quads than the lots of texture.

One could save on texture bandwith by using bitmaps but this results in poor image quality, as one can't take advantage of the anti-aliasing quality options provide by the likes of freetype.

If you want text which scale to thosands of labels then the only sensible option is to load the glyphs into a small set of textures and then render them as quads. The OSG's osgText implemention will often be able to use a single texture for all the text labels, so is able to render them without state changes, this means we're getting near to about as optimal as one can get.

Robert.

Robert Osfield
06-08-2003, 02:54 AM
Originally posted by henryj:
I don't think anyone thinks that putting all your glyphs into one texture isn't a good idea. In fact it's essential to get anything remotely like good performance.


I'd like to re-interate one of my findings is that one should only download the glyphs one actually requires for rendering.

One of the bottlenecks that was hitting one of the OSG's users which needed Japanese fonts was that original osgText implement (which was based in FTGL) was trying to load the whole Japanese font file at once, freetype itself just ground to a halt trying to create all the glyphs - over 20,000 of them, let alone having to create texture space for them all.

The new osgText implement just loads what glyphs are needed, and then adds new ones on demand. This keeps the texture usage down, which in turns keeps the load and rendering peformance up.

It does make for a more complex back end to the text implemention, though.



I have to agree with John though that 'string' caching is the fastest for the reasons stated as long as you don't blow your texture budget.

For very low demands on the number of text labels, so that only a single texture is ever required, and the text doesn't change, then and only then might the rendering whole strings to a texture compete with the quad approach I've outlined.

Under these conditions state changes are equal between the two approaches, i.e. none, and we're left with more quads vs more fill for which will be faster. Now we're only taking about hundreds of quads here, but most likely millions of pixels to fill, so which one is most likely to win...

Robert.

jwatte
06-08-2003, 09:44 AM
A 16x16 res glyph with lumuniance and alpha takes 16x16x2 = 512 bytes.

A single quad takes 4x12 (for the coords) + 4*8 for the tex coords = 80 bytes.



The difference is that the texture is uploaded ONCE, but the vertex has to be re-sent each frame. From a fill rate perspective, the approaches should be equivalent. From a main RAM bandwidth perspective, the pre-rendered text clearly wins unless you change the text more often than once every 10 frames or so. If you change the text that often, the user is unlikely to actually be able to read it.

But, as I said, your system works for you; good for you! We found a system that runs faster for us; good for us!

henryj
06-08-2003, 02:43 PM
One of the bottlenecks that was hitting one of the OSG's users which needed Japanese fonts was that original osgText implement (which was based in FTGL) was trying to load the whole Japanese font file at once, freetype itself just ground to a halt trying to create all the glyphs - over 20,000 of them, let alone having to create texture space for them all.

The new osgText implement just loads what glyphs are needed, and then adds new ones on demand. This keeps the texture usage down, which in turns keeps the load and rendering peformance up.

I wish you had mentioned this to me. All glyphs except textures had this functionality from the start and this was fixed for textures a long time ago... 1.3b3 November 13 2001
In fact v2.0 has removed 'pre caching glyphs' altogether.

Robert Osfield
06-09-2003, 01:21 AM
Originally posted by jwatte:

The difference is that the texture is uploaded ONCE, but the vertex has to be re-sent each frame.
[\QUOTE]

Have you ever heard of display lists???

[QUOTE]From a fill rate perspective, the approaches should be equivalent. [QUOTE]

I'm really impressed that you can't see the wood from the trees.

When you render the whole string the size of the quad has to be the total width of the glyphs together* maximum height of any one of the glyphs. The maximu height is what gets you, you end with lots of white space to fill with all those small letters.

When you render glyphs individually the quads change size from glyph to glyph, you end you render much less white space. Fill is quite clearly less.

[QUOTE]
From a main RAM bandwidth perspective, the pre-rendered text clearly wins unless you change the text more often than once every 10 frames or so. [\B][\QUOTE]

You couragously deluded. Imagine rendering this post. How many glyphs would you need? Compare this to how much texture size you'd need if you just use one image? Please do the sums that I presented in a previous post, the memory footprint is much much smaller when rendering individual quads.

[QUOTE][B]
If you change the text that often, the user is unlikely to actually be able to read it.
[\B][\QUOTE]

The real strength of rendering indivudual glyphs, comes in scalability. There are users of the OSG that require 10 of thosands of unqiue labels, such as depths along a line, each label is unique.

If you use a seperate piece of texture for each label and each one is 32 pixels high, 128 wide, how much space will you need? Now you'll need 40 textures of 1024x1024 to pack them all in. That's one heck of texure usage, and if you're lucky and the user doesn't have any other requirements for your video cards memory then you might just get away without any thrashing. But lets face in the real world we have other things in our scene...

Contrast this with the need of individual glyphs, subloaded on demand. Numbers, well there only then of them. Add a comma and a decimal place and we have 12 glyphs in total. 32x32x12 = 8192 pixels. This is hefty saving in texture memory. And please remeber that the quads coords are only going to take up a meg for all this geometry, nothing compared to 80Meg you'll need above.

[QUOTE][B]
But, as I said, your system works for you; good for you! We found a system that runs faster for us; good for us!

You say it runs faster for you, but have you really tested the alternatives? Were the alternatives properly implemented?

It really doesn't take much to do the sums properly and realise that the individual glyph approach is going to much more efficient once you really start pushing your text needs there really isn't any comparison.

I don't have a problem with rendering whole text strings to textures. If you texts needs are modest, then it is probably the one of easier implementation to go for whilest still retaining high image quality. For a small number of text labels
peformance will also be more than adequate, in fact performance delta with the most efficient methods will be very small.

But PLEASE, don't tell me or anyone else its most efficient implementation once you start scaling things up, because its just plain mis-informed clap trap.

Robert.

jwatte
06-09-2003, 04:31 PM
I think you should use better language, as I don't see any reason why you should insult me like that.


To sum up: I believe that display lists live in AGP memory, and thus compete with CPU memory and vertex transfer. You believe display lists live in local video memory and compete with texture fetch and fill rate.

Robert Osfield
06-10-2003, 01:30 AM
Originally posted by jwatte:
I think you should use better language, as I don't see any reason why you should insult me like that.

I appologies if you feel insulted. It is my belief that the some of the advice you have provided has been misleading and unsubstantiated. Its difficult to put that politely or a cuddly form that will give you a warm glow.

Your suggestion of using rendering whole string with a single quad is good advice, given certain caveats - its works well for a modest number (10's to hundres) of text labels, its works well for static text but not for highly dynamic text, it works well when font resolution is modest.

The problems comes not because you hanv't enumerated the caverates, but when you try and punt the idea the rendering whole strings is optimimal for peformance and scales well. Even greater problems come when you try to claim that it peforms better and scales better than the alternative of seperate glyphs.

Please, remember I did't invent the sperate glyphs approach. When I implemented the latest version osgText I looked at the a whole set of alternatives, including the whole string approach, I did the sums and the seperate glyphs approach was the clearly the best for the peformance and scalability. The figures in above posts explain why.



To sum up: I believe that display lists live in AGP memory, and thus compete with CPU memory and vertex transfer. You believe display lists live in local video memory and compete with texture fetch and fill rate.

Actually this all depends on which machine, graphics card, and OGL drivers you're using, you just can't make genalizations - some machines don't even have AGP :-) However, one thing I can say is the one of key points of display list is that they are designed to be downloaded to memory local to the graphics card, so with a good OGL driver this is exactly what it will do.

Robert

Stephen_H
06-16-2003, 06:35 PM
Sorry to resurrect an old thread, but I was interested because I'm currently designing a full-fledged GUI in OpenGL and I do lots of text rendering.

Things are getting near completion now, and I've started profiling the GUI with Numega. Currently, I'm using immediate mode to render a textured quad per character. I've noticed that around 55% of the time in the GUI is spent rendering text and I've been thinking about ways to optimize this. Of the time rendering text, I've noticed a very large portion is used by glTexCoord2f() and glVertex2f().

Obviously, the function call overhead is killing performance. I was thinking about moving to vertex arrays of some kind, but I don't know if thats a good idea given that most of the strings I render average around 10 to 30 quads, and I'm not sure if this is enough to overcome the overhead of using vertex arrays. Some of the listboxes and textviews are larger though and I think they might benefit from this.

I was wondering what other people had tried, or if anyone has any opinions?

Best Regards,
Stephen

Edit - yes, I'm thinking about moving to cached strings for the small text widgets, but I was curious if anyone had encountered this problem before with single quads...

[This message has been edited by Stephen_H (edited 06-16-2003).]

OneSadCookie
06-16-2003, 07:10 PM
You generally don't need very large arrays before glDrawElements outperforms immediate mode.

Rendering the whole string to a texture will, of course, get you around this problem. This is what all word processors and text editors have effectively done for years, so there's no reason it should suddenly become too slow now. Just remember only to redraw the parts that have changed.

Robert Osfield
06-17-2003, 12:56 AM
Of the time rendering text, I've noticed a very large portion is used by glTexCoord2f() and glVertex2f().


The quick coding option would be to display list them, and then profle the results.

My own implementation uses vertex arrays + glDrawArrays as they fit very naturally with rendering a list of quads and its certainly fast enough - even with a million characters I still gettting v. good frame rate.

Robert.

Stephen_H
06-17-2003, 09:47 AM
Thanks for the replies!

Sort of unrelated question... maybe this should go in a separate thread:

I know VAR and compiled arrays use post T&L vertex caches when using the glDrawElements() and glDrawRangeElements() functions.

I would guess that display lists also use the vertex cache? And VBOs would use this cache in all states, or just in certain states?

Stephen

Pop N Fresh
06-17-2003, 12:28 PM
The vertex cache will only be used if your using DrawElement type calls. ie: you're using indexed vertices. When using indexed vertices display lists don't give any speed gains in my testing.

DrawElements and LockArrays were about 4 times faster than anything I could get out of display lists.

[This message has been edited by Pop N Fresh (edited 06-17-2003).]