Jump to content
  • Advertisement
Sign in to follow this  
boejunda

OpenGL Speeding up text printing

This topic is 4001 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

So, I've got a text printing routine that outputs outline text to the screen. My problem is that with the amount of text I need to display, my framerate drops by several hundred frames. I've been using NeHe's OpenGL tutorials for guidance. Is there anything I can do to speed up what I'm doing here? I originally tried this with bitmap fonts, but I found the performance hit to be greater than what I'm doing now. One thing... I need the ability to display text that may contain the values of variables, hence the argument list on the printing routine. I realize that may be what's slowing things down, but it is neccesary. Loading a system font:

	LOGFONT logfont;

	logfont.lfHeight =			-12;
	logfont.lfWidth =			0;
	logfont.lfEscapement =		0;
	logfont.lfOrientation =		0;
	logfont.lfWeight =			FW_BOLD;
	logfont.lfItalic =			false;
	logfont.lfUnderline =		false;
	logfont.lfStrikeOut =		false;
	logfont.lfCharSet =			ANSI_CHARSET;
	logfont.lfOutPrecision =	OUT_TT_PRECIS;
	logfont.lfClipPrecision =	CLIP_DEFAULT_PRECIS;
	logfont.lfQuality =			ANTIALIASED_QUALITY;
	logfont.lfPitchAndFamily =	FF_DONTCARE | DEFAULT_PITCH;
	strcpy(logfont.lfFaceName, "Courier New");



	HFONT font = CreateFontIndirect(&logfont);
	SelectObject(deviceContext, font);
	fontList = glGenLists(256);
	wglUseFontOutlines(deviceContext, 0, 256, fontList, 0.0f, 0.0f, WGL_FONT_POLYGONS, gmf);
	DeleteObject(font);


... And writing text to screen.
void Renderer::print (GLfloat x, GLfloat y, const char * mess, ...) {

	if (mess != NULL) {

		/*	Set the color and position of the text. */

		glColor3f(0.9f, 0.9f, 0.9f);
		glTranslatef(x, y, 0.0f);

		va_list ap;
		char text [256];
		va_start(ap, mess);
			vsprintf(text, mess, ap);
		va_end(ap);

		float length = 0.0f;

		for (unsigned int loop = 0; loop < strlen(text); loop++)
			length += gmf[text[loop]].gmfCellIncX;

		glPushAttrib(GL_LIST_BIT);
		glListBase(fontList);
		glCallLists (strlen(text), GL_UNSIGNED_BYTE, text);
		glPopAttrib();
		
		glTranslatef(-(x + length), -y, 0.0f);
	}

}

Share this post


Link to post
Share on other sites
Advertisement
>>One thing... I need the ability to display text that may contain the values of variables, hence the argument list on the printing routine. I realize that may be what's slowing things down, but it is neccesary.

no thats not slowing it down, the reason its slow is cause u are calling a DL for each character
typically u create a texture containing all the alphabet in it + then do something

for ( all text )
{
glTexCoord2f( texcoords for this character )
draw character
}

Share this post


Link to post
Share on other sites
In China there are more than 10000 kinds of charactors (much more than 256), so we cannot store each charactor in a Display List at the program's initialization.
When you need to draw a string, use a texture. For example, use wglUseFontBitmap to build the Display List for each charactor that need's to draw, then draw the string to the GL_AUX0 buffer, destroy the Display list, copy the GL_AUX0 to a texture.

Share this post


Link to post
Share on other sites
I think the most flexible and efficient method of text rendering is to use some library like FreeType to render the string and store that (the entire rendered string) in a texture. Then store that texture in some rendered-string-texture cache for the font you're using. Since most strings will probably be static (or change relatively infrequently) the speed of having FreeType render the strings and storing them in a texture shouldn't matter that much because it won't happen very often.

EDIT: Instead of using C's variable argument list and vsprintf, I recommend having your Renderer::print function just take a std::string and using C++'s type-safe std::ostringstream for writing formatted info to a string. You most likely won't notice any speed difference, and it will be much safer and cleaner.

So it could look something like this...
void Renderer::print (GLfloat x, GLfloat y, const std::string &mess)
{
...
}

//Then when using it...
std::ostringstream ss;
ss << "Rendered " << numVertices << " vertices and " << numTriangles << " triangles.";
renderer->print(x, y, ss.str());



[Edited by - Kalidor on September 27, 2007 10:05:25 AM]

Share this post


Link to post
Share on other sites
Quote:

I think the most flexible and efficient method of text rendering is to use some library like FreeType to render the string and store that (the entire rendered string) in a texture. Then store that texture in some rendered-string-texture cache for the font you're using. Since most strings will probably be static (or change relatively infrequently) the speed of having FreeType render the strings and storing them in a texture shouldn't matter that much because it won't happen very often.

This is basically what I do (except I don't even use FreeType right now, I just have .NET's System.Drawing stuff do it).

I keep, on average, two "texture sheets" around (although the font renderer will dynamically add more if they're needed, in practice I rarely even fill both). One is for long-term strings, and the other for strings that will likely change rapidly (such as a string containing your score, or something). The first time a string is submitted, I ask the underlying font renderer (so FreeType, GDI, whatever) for the bounds of the string, use a rectangle-fitting routine to find a suitable spot on the appropriate texture sheet, and draw the string to the sheet. I update the texture from the sheet once per frame if the sheet was changed that frame.

There are some extra little tricks involved -- I can split strings across sheets or within a sheet to achieve better packing, et cetera, and there's a minor bit of work involved in recomputing texture coordinates for the strings, but it's not too bad.

One of the biggest advantages to this system (the general system of rendering the strings via a dedicated font renderer versus doing the typical quad-per-glyph bitmap font approach) is that you get all the benefits of the underlying renderer for free. GDI handles my Unicode inputs flawlessly, it handles nice word-wrapping if I specify a desired target rectangle, it handles locale issues like left-to-right or vertical text, and it handles (dynamic!) font sizes. All of that stuff can be very useful (the word wrapping, in particular, is almost required and really rather boring to write yourself), but none of it is very fun to implement yourself. Trust me, I've done it.

The method might seem less efficient because of the frequency of texture updates, but that's not as bad as you might think. I've never had a performance problem that I was able to attribute to the font system yet. This method is also more vertex-load friendly -- traditional bitmap font implementations require four vertices per glyph, this requires four per string (except in the case of large strings that must be split across sheets) on average.

Share this post


Link to post
Share on other sites
Hi,

If texture is not that important (esp for GUI), you could also try raster fonts.

Pros:
- not subject to maximum texture size.
- faster than textured fonts using the DL method.

Cons:
- no texture: the color is uniform (no color effect possible on letters).
- not suitable for 3D printing at arbitrary angles.
- need to precompile the font for rastering.

If it is RPG text, you could use a mixed approach (like medieval writing) where the first character is a textured letter and the rest is written with a simple raster font.

my 2 cents ...

Ghostly yours,
Red.

Share this post


Link to post
Share on other sites
Just as a side note to complete my previous post, I timed three text blitting functions on my system. Aside from the pros and cons of each blitting method, I wanted to check what were the speed gains of the method described by jptrie and Kalidor. Here are the three rendering methods:

1 - Textured font using quads in display lists (classical method)
2 - Bitmap (or Raster) font
3 - Fast textured font (sytem described by jpetrie and kalidor)

I use three GUI windows with text in it. Two windows display the same text labels. There are two testing conditions:

A - only one window
B - all three windows

Note that I have tested on a low end system (IBM PC with integrated Intel Graphics chipset). Here are the results:

Textured font
1 + A : 68 FPS
1 + B : 49 FPS
bitmap font
2 + A : 80 FPS
2 + B : 60 FPS
fast textured font
3 + A : 80 FPS
3 + B : 66 FPS

This means that bitmapped fonts are a good alternative for GUI text display. But the fastest text display is reached with the 3rd method (jptrie and Kalidor) any time there are redundant strings to display.

Ghostly yours,
Red.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!