Jump to content

  • Log In with Google      Sign In   
  • Create Account

Bitmap Fonts performance issue.


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
6 replies to this topic

#1 Fara   Members   -  Reputation: 122

Like
0Likes
Like

Posted 31 August 2011 - 11:51 AM

Hi everyone

I simplified my project in order to work on the performance and I found out that Bitmap Font is responsible for some of the performance issues.
So what I have is a standard cube and some text (you can check the image below to see what i mean).
pav2dgl_snapshot.jpeg
When I render just cube everything responds fast (meaning translation and rotation of the cube), but once I add text it slows down depending from amount of text on screen (meaning if i have one or two its ok, but 15 or above performance drops a lot).

Here is the code from my project which is responsible for the text.


void GLFont::BuildBitmapFont(HDC &hdc)
{
	baseBitmap = glGenLists(96);	// Storage for 96 characters
	fontSize = -MulDiv(fontSize, GetDeviceCaps(hdc, LOGPIXELSY), 72);
	fontBitmap = CreateFont(   		-fontSize,        		// Height of font
						0,        			// Width of font
						0,        			// Angle of escapement
						0,        			// Orientation angle
						FW_NORMAL,        		// Font weight
						FALSE,  			// Italic
						FALSE,        			// Underline
						FALSE,        			// Strikeout
						ANSI_CHARSET,   		// Character set identifier
						OUT_TT_PRECIS,        		// Output precision
						CLIP_DEFAULT_PRECIS,    	// Clipping precision
						ANTIALIASED_QUALITY,        	// Output quality
						FF_DONTCARE|DEFAULT_PITCH,      // Family and pitch
						"Courier New");			// Font name

	oldfontBitmap = (HFONT)SelectObject(hdc, fontBitmap);   	// Selects the font we want
	wglUseFontBitmaps(hdc, 32, 96, baseBitmap);   		// Builds 96 characters starting at character 32
	SelectObject(hdc, oldfontBitmap);			// Selects the font we want
	DeleteObject(fontBitmap);				// Delete the font
}

void GLFont::glBitmapPrint(const char *fmt, int i, double size, double _x, double _y, double _z)
{
    float		length=0;			// Used To Find The Length Of The Text
	float 		heigth=0;			//Use To Find Heigth of the Text
	
	glPushMatrix();

	glColor3f(0.0f, 0.0f, 0.0f); // set Color 2 white
	char text[256];	                                        // Holds our string
	va_list ap;	        	                        // Pointer to list of arguments
		if (fmt == NULL)		                        // If there's no text
		return;			                        // Do nothing

	glRasterPos3d(_x, _y, _z);
	va_start(ap, fmt);		                        // Parses the string for variables
	vsprintf(text, fmt, ap);	                        // And converts symbols to actual numbers
	va_end(ap);			                        // Results are stored in text

	glPushAttrib(GL_LIST_BIT);	                        // Pushes the display list bits
	for (unsigned int loop=0;loop<(strlen(text));loop++)			// Loop To Find Text Length
	{
		length+=gmfBitmap[text[loop]].gmfCellIncX;				// Increase Length By Each Characters Width
		heigth+=gmfBitmap[text[loop]].gmfCellIncY;
	}

	if (size < 0.1)
		glTranslatef(-size/2,-0.01, 0.0);				// Center Our Text On The Screen
	else
		glTranslatef(-length/20,-0.03, 0.0);				// Center Our Text On The Screen
	glPushAttrib(GL_LIST_BIT);						// Pushes The Display List Bits
	glListBase(baseBitmap - 32);		                        // Sets the base character to 32
	glScalef(size, size, 0.0);
	glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);	// Draws the display list text
	glPopAttrib();
	glPopMatrix();
}





So my question: Are theare any better way to render text on the scene without sacrificing performance? Or I am doing something wrong which causes performance drop?

Any comment would be appreciated.
Thanks in advance.

Sponsor:

#2 kdmiller3   Members   -  Reputation: 176

Like
0Likes
Like

Posted 31 August 2011 - 02:29 PM

Many games draw text the same way they draw screen-aligned sprites: pack glyph bitmaps into a texture sheet and draw screen-aligned rectangles with appropriate texture coordinates. At a minimum you'll need texture coordinates (u0, v0, u1, v1) for each character, but you'll most likely want a position offset (x, y) so you can cut out empty space around glyph bitmaps and a width (w) so you can compute character positions and string widths more easily.

For text that doesn't change often, you can build a draw list from your text rendering and use that draw list to render text until it changes.

Protip: to ensure texels line up perfectly with pixels, subtract 0.5 from the integer vertex positions. (A half-texel shift compensates for bilinear filtering, but a half-pixel shift compensates for both bilinear filtering and multisampling.)

#3 mhagain   Crossbones+   -  Reputation: 8279

Like
0Likes
Like

Posted 31 August 2011 - 02:37 PM

NeHe strikes again.

Bitmap fonts use display lists internally; each character is a single display list (containing only 4 vertexes) and drawing many characters is going to result in many display list calls - in other words it's going to be not much faster than immediate mode. Additionally display lists will have some small overhead of their own, and your driver might just suck at them (an OpenGL driver is just obliged to support display lists - the spec says nothing about doing so efficiently!). Even assuming that your driver doesn't suck at display lists, in order to get value out of them you really need to be pushing a lot of commands and/or data in each list. And like I said, here we're talking about 4 vertexes tops (and who knows what kind of command wglUseFontBitmaps compiles into it's lists?)

There are plenty of ways of getting text onscreen in an OpenGL application, and the right answer depends on whether or not you want anything fancy. A simple 256x256 texture containing the characters in a 16x16 grid, with texture coords to use derived from the character to be drawn is probably the most basic; if you need anything beyond that there are other solutions available.

It appears that the gentleman thought C++ was extremely difficult and he was overjoyed that the machine was absorbing it; he understood that good C++ is difficult but the best C++ is well-nigh unintelligible.


#4 Fara   Members   -  Reputation: 122

Like
0Likes
Like

Posted 31 August 2011 - 02:55 PM

Many games draw text the same way they draw screen-aligned sprites: pack glyph bitmaps into a texture sheet and draw screen-aligned rectangles with appropriate texture coordinates. At a minimum you'll need texture coordinates (u0, v0, u1, v1) for each character, but you'll most likely want a position offset (x, y) so you can cut out empty space around glyph bitmaps and a width (w) so you can compute character positions and string widths more easily.

For text that doesn't change often, you can build a draw list from your text rendering and use that draw list to render text until it changes.

Protip: to ensure texels line up perfectly with pixels, subtract 0.5 from the integer vertex positions. (A half-texel shift compensates for bilinear filtering, but a half-pixel shift compensates for both bilinear filtering and multisampling.)


Thank you for your comment.

By using texture map you loose control over the text and text usually ends up mixing with the images on the screen. I need easy way to write text on the screen with ability to change position, size, color and etc.. and preferably not rotate with the object, for which Bitmap Font is perfect but for unknown reason to me it sacrifices performance.

I tried to using draw list but it didn't show any performance improvement, I am not sure either why it didn't.

Is there any other good implementation of the Bitmap Font which would work faster ? Or anything similar to the Bitmap Font that would work fast?

#5 Fara   Members   -  Reputation: 122

Like
0Likes
Like

Posted 31 August 2011 - 03:07 PM

NeHe strikes again.

Bitmap fonts use display lists internally; each character is a single display list (containing only 4 vertexes) and drawing many characters is going to result in many display list calls - in other words it's going to be not much faster than immediate mode. Additionally display lists will have some small overhead of their own, and your driver might just suck at them (an OpenGL driver is just obliged to support display lists - the spec says nothing about doing so efficiently!). Even assuming that your driver doesn't suck at display lists, in order to get value out of them you really need to be pushing a lot of commands and/or data in each list. And like I said, here we're talking about 4 vertexes tops (and who knows what kind of command wglUseFontBitmaps compiles into it's lists?)

There are plenty of ways of getting text onscreen in an OpenGL application, and the right answer depends on whether or not you want anything fancy. A simple 256x256 texture containing the characters in a 16x16 grid, with texture coords to use derived from the character to be drawn is probably the most basic; if you need anything beyond that there are other solutions available.


Thank you for your reply.

I need something simple and fast but preferably to be able to change position, size, color, and not rotate with object.


I think it might be that my driver suck at display list. But I am not in control of what hardware or software end user will have on they machine so something stable working on most of the Windows XP and Windows 7 machines would be good enough for me.


I have Intel HD Graphics 3000 with up to 1696MB total graphics memory
with OpenGL 3.0 if this is any help.

#6 kdmiller3   Members   -  Reputation: 176

Like
0Likes
Like

Posted 01 September 2011 - 09:11 AM

I suspect the Bitmap font display lists push an orthographic projection matrix, which you'll need to do yourself here. (Check out the OpenGL FAQ item 9.030)

The only thing you lose with a texture-based font is pixel-perfect accuracy when scaling or rotating. Everything else is achievable.
Position: push a translation matrix or simply add an offset when generating vertex positions
Size: build multiple textures from the font; most of the time you want only a few point sizes anyway
Color: use glColor to set the text color; this assumes modulate texture blend mode (the default),

I strongly recommend doing all your screen-space rendering at the same time near the end of the rendering process. You'll only need to push the projection matrix and related render state once instead of for every character. You'll may want to to disable Z-buffering so text always draws on top of everything else. Here's how I do it:

// push projection transform
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, windowWidth, windowHeight, 0, -1, 1);

// use screen coordinates
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

// disable depth testing
glDisable(GL_DEPTH_TEST);

// draw screen-space items
// ...

// restore depth testing
glEnable(GL_DEPTH_TEST);

// reset camera transform
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();

This is old-style (1.x) OpenGL and deprecated in the latest versions but shows the general principle.

#7 Geri   Members   -  Reputation: 196

Like
0Likes
Like

Posted 10 September 2011 - 05:28 AM

Do not use this.

I suggest not to use wglusefontbitmaps at all. Use simple textures, there is a texture generator called Bitmap Font Builder.exe, you maybee want that.

Create your 3D RPG: Maker3D

 





Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS