Jump to content
  • Advertisement
Sign in to follow this  
JL4453

Fonts & Frame Rate

This topic is 3655 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

***EDIT: Issue solved, see last post.*** Hello, I'm having a minor issue drawing fonts in OpenGL. Using either Bitmap fonts or GNU FreeType (texture mapped fonts), my framerate somewhat suffers when printing large amounts of text to the screen. Specifically, in a simple stress test of my GUI I went from 500 fps down to about 100 fps when drawing a little over the amount of text in this post to the screen each frame (rough guesstimate, around 200 words). I didn't think that simply getting text onto the screen would be such a huge hit to my framerate! I just want plain, boring 2D text for an in-game chat system. It seems that games like World of Warcraft are able to handle lots of in-game chat text without major problems, are there any tricks used in games like this to get simple 2D fonts printed efficiently? Or am I just worried about things beyond my control & should just try to limit the size of the chat-box? Thanks for any advice you are able to provide. ***EDIT: Issue solved, see last post.*** [Edited by - JL4453 on June 17, 2008 1:30:25 PM]

Share this post


Link to post
Share on other sites
Advertisement
For optimization, you could try rendering the text onto the OpenGL equivalent of an SDL_Surface* one time, and then just rendering that. That way, you don't have to rerender your fonts every frame. I bet this is what games like World Of Warcraft do also.

Share this post


Link to post
Share on other sites
You mean a texture? I do believe that's what you're supposed to do anyway.

How large is the texture? Does it cover the whole chatbox of text? One message? One line? One character?!

Share this post


Link to post
Share on other sites
The way I was hoping it would work (and the way it works in most online games I've seen, incl. WoW) is that the chat text area has no opaque background, so I imagine it almost has to be re-rendered somehow every frame or else you'd have to pick out all the little areas in between letters to re-render action going on behind the text.

@c4c0d3m0n, are you saying that there is a way to somehow assemble one giant bitmap created by displaying the few hundred/thousand single-letter bitmaps, and then call that single giant bitmap on a single giant quad instead of doing all the letters individually?

Thanks for the replies so far, I get the impression that this framerate drop for drawing text is unusual and this encourages me that there might be a better way. I counted and my stress-test involved printing approximately 2000 characters in about 35 lines of text. The font used is Lucida Fax Demibold, cell size 15 if that makes a difference.



In case it also makes a difference here is my print code:

void GUIbitmapfont::print(float x, float y, const string str, ...){
if (str.size()==0) return;
glPushAttrib(GL_LIST_BIT);
glListBase(base);
glRasterPos2f(x,y);
glCallLists(str.size(), GL_UNSIGNED_BYTE, str.c_str());
glPopAttrib();
}

... and the construction of the display lists:

GUIbitmapfont::GUIbitmapfont(char *name, int height, CW_Window *wind){
h = height;
HFONT font;
base = glGenLists(128);
font = CreateFont(-height,0,0,0,0,FALSE,FALSE,FALSE,ANSI_CHARSET,
OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
FF_DONTCARE|DEFAULT_PITCH,name);
SelectObject(wind->hDC, font);
wglUseFontBitmaps(wind->hDC, 0, 128, base);
DeleteObject(font);
}

... and the code that makes the call(s) to print every frame (vadjr/hadjr are just pre-calculated horizontal and vertical adjustments for alignment, if the addition symbols are not showing up they are being added to x, y):

void GUIlabel::draw(){
if(!visible) return;
glColor3f(COLOR[color][0],COLOR[color][1],COLOR[color][2]);
for(int i=0;i<text.size();i++){ // text is a vector of strings/lines
if(f->getHeight()*(i+1) > h) break;
switch(align){
case LEFT:
f->print(x,y + vadjr,text);
break;
case CENTER:
f->print(x + hadjc,y + vadjc,text);
break;
case RIGHT:
f->print(x + hadjr,y + vadjr,text);
break;
}
}
}

Share this post


Link to post
Share on other sites
I don't want to waste any more of my own or anyone else's time on this than is necessary; I am reading on the net that "the fastest way to do fonts in openGL is to use bitmap fonts" & I realize I may well be going as fast as is possible. After doing some tests in World of Warcraft it seems that I can put the maximum amount of text allowable on screen (approx. 10500 characters in 7 max-size chat windows - it appears WoW does indeed limit the amount of text on screen), and frame rate appears to drop from 30 to 25. This is not orders of magnitude different (computationally speaking) from my framerate drop:

If we say the computer can process 100 imaginary "operation-units" per second, then at 400 fps for no text printing we can say we are doing 0.25 op-units per frame. At 100 fps, printing 2000 characters per frame, this is 1.0 op-units per frame, indicating that drawing 2000 characters in my program takes 0.75 op-units (1.0 for doing everything - 0.25 for non-printing stuff = 0.75 for printing).

In WoW, 30 fps would be 3.33 op-units per frame, and 25 fps is 4.0. Thus WoW seems to take 0.66 op-units to draw the 10000 characters, and presumably 0.132 op-units to draw 2000 characters.

This apparent 5-fold difference in font printing efficiency is irksome but I suppose it isn't crippling. Perhaps once the rest of my code is running the printing of 2000 characters will likewise only cause a 5 fps drop. And I can always limit the system to a maximum of less than 2000 characters.

Share this post


Link to post
Share on other sites
Who told you the fastest way to do fonts is bitmap? It's the slowest!

Read this page: http://www.sjbaker.org/steve/omniv/opengl_text.html

The problem is you're trying to draw using an entirely software solution, but it would be faster to use a hardware (graphics card/gpu) solution.

Quote:
The way I was hoping it would work (and the way it works in most online games I've seen, incl. WoW) is that the chat text area has no opaque background, so I imagine it almost has to be re-rendered somehow every frame or else you'd have to pick out all the little areas in between letters to re-render action going on behind the text.


Everything you see on screen has to be rerendered every frame. However, you don't have to rerender the text box unless it's altered. The stuff behind the text box, however, does. The semi-opaque background has little to do with it.

Quote:
@c4c0d3m0n, are you saying that there is a way to somehow assemble one giant bitmap created by displaying the few hundred/thousand single-letter bitmaps, and then call that single giant bitmap on a single giant quad instead of doing all the letters individually?


Doing them individually is why it's so slow.

Share this post


Link to post
Share on other sites
Awesome, so there is some room for improvement... I see there is still much I have to learn about openGL optimization.

My impression was that using display lists are stored on the gpu & thus constitute a hardware solution; it seems that you are saying that there is further hardware optimization possible, I'm guessing by somehow storing a buffer with the exact pixel map from all those displayed display lists, and then somehow overlaying that buffer on top of a dynamically changing scene. Your last comment "Doing them individually is why it's so slow" seems to reinforce the notion that combining my individual-letter display lists is possible.

Just to make sure I understand the gist: we still have to put the text onto the screen every frame, but instead of sending transformation coords for each letter from the CPU we can "remember" it all on the GPU unless something changes.

I admit I'm new to openGL, I don't immediately see how to do this. Make a single display list calling all the little ones with appropriate coordinates, and simply calling that one big display list every frame? This didnt seem to speed things up when I tried it but maybe I did it incorrectly.

I thank you for pointing me in a useful direction and I will be scanning the 'net for related articles; any more specific info would be greatly appreciated.

Share this post


Link to post
Share on other sites
I don't know how you'd expect to use display lists, but I only yesterday learned what they are, so I'll assume it's my own ignorance.

Unfortunately, I'm also new, so any further is too technical for me to assist. But, I do want to note: The CPU and GPU store NOTHING. There are certain things they store, true, but I won't know what they are until I learn assembly, and you certainly can't access them without it. You store things on RAM: technically hardware, but in this context, it's software. The GPU is only involved for calculations involving graphics (I think), so when you bitmap something, meaning no calculation is done--since they can't be scaled, rotated, or anything--it doesn't use the GPU and we consider it a software solution. Has its uses, but it sounds like not for you.

Good luck.

Share this post


Link to post
Share on other sites
Thanks for the quick replies.

Using a display list for each letter pre-compiles the openGL commands used to draw that letter and stores it in graphics card memory, so that when you "call" the display list it already has the letter drawn & only needs to translate it to the right position. I am thinking that this is close to what you mean when you say to use a graphics card/gpu solution.

And yes, I did not mean to say that data was being stored on the CPU or GPU itself but rather I meant to distinguish main memory vs graphics card memory. It is my impression that storing something in graphics card memory allows for quicker access during rendering, than does storing it in the computer's own main memory.

"When you bitmap something"... I am thinking this is what I want to do, 'bitmap' as a verb; I only need a static, 2D non-changing image (bitmap?) of the chat text I want to display, and to paste that image on top of everything else once I'm done rendering a scene. Can you "bitmap" a bunch of texture mapped quads (or any subset of stuff on the frame buffer) into one big texture or pixel buffer somehow? Store it in graphics memory and just paste it on top of the scene each frame, updating as necessary? By my current in-head model of how the rendering pipeline works, this seems like it would be the fastest solution possible.

I suppose I will post here if I find a solution that significantly improves the rendering speed. Once again thanks for all of your help. I rated you guys up in the forum rating thingy.

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.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!