PDA

View Full Version : Multiple fonts problem



kaysoft
10-10-2002, 02:02 AM
Hi everyone!
I am using an std::vector to make a dynamic array of my fonts and be able to search by name. For example, i have this function called int Fonts(LPCTSTR name) which searches in the vector and returns the current index. Anyway, this works excellent after a lot of tries. But my problem is more complicated. Lets say, I create a font:
gfx.CreateNewFont("font1","Arial",12,false,false,false);

and I render it using RenderFont("font1",Vec2(10,10),"Hello from font1!!");

In my render routine, I have wglUseFontBitmaps(hdc, 32,96,font[h].base) (h is the return integer from Fonts(name))
and SelectObject(hdc, font[h].hf);

then I render the font based on Nehe's example on bitmap fonts. The problem comes when I have 2 or more fonts. Then, the fonts seems to switch attributes, for example the first font becomes the second font, etc. Uhh, it is hard to explain, but I hope you can help me here.
Thanks!

mikael_aronsson
10-10-2002, 02:09 AM
Hi !

Are you sure that you set the fontbase so that there are no collisions between the two fonts ?, that's the only thing I can think of that might give you trouble.

Mikael

kaysoft
10-10-2002, 02:12 AM
Hey Mikael,
Yes I do set the font base.

in my CreateNewFont method, i use:

gfx.nFonts++;
font[gfx.nFonts-1].base = glGenLists(96);

This is correct, right?

kaysoft
10-10-2002, 05:12 AM
Any help please?

Jambolo
10-10-2002, 08:21 AM
Originally posted by kaysoft:
gfx.nFonts++;
font[gfx.nFonts-1].base = glGenLists(96);


This code is suspicious. Are you using vector correctly? Did you set the size of the vector somewhere? Why don't you use push_back?

*Aaron*
10-10-2002, 09:23 AM
You need to call glListBase(font[h].base) each time you switch fonts. Read the documentation, and you will figure out why.


...and I render it using RenderFont("font1",Vec2(10,10),"Hello from font1!!");

In my render routine, I have wglUseFontBitmaps(hdc, 32,96,font[h].base)...
Why are you calling wglUseFontBitmaps in the render routine? This function generates a bitmap for each character within the specified range. You don't need to do this every time you render a string. Call this in the CreateNewFont routine.

kaysoft
10-10-2002, 10:18 AM
Yup, im using push_back:
rtFont f;
font.push_back(f);
in my createnewfont routine.

Ok, I will try everything you said!

kaysoft
10-10-2002, 10:41 AM
Bah.. it didnt work. I think I should post my entire code here:

//---Header file-------//
struct rtFont
{
TCHAR fName[30];
TCHAR FaceName[30];
int size;
bool bold;
bool italic;
bool underline;
HFONT hf;
GLuint base;
};

class CRT2D
{
public:
.....
.....

private:
int nFonts;
vector<rtFont> font;
};

//----Source file----//
void CRT2D::CreateBitmapFont(LPCTSTR Name, LPCTSTR FontName, int size, bool bold, bool italic, bool underline)
{
nFonts++;
rtFont f;
font.push_back(f);
strcpy (font[nFonts-1].fName, Name);
strcpy (font[nFonts-1].FaceName,FontName);
font[nFonts-1].bold=bold;
font[nFonts-1].underline=underline;
font[nFonts-1].italic=italic;
font[nFonts-1].size=size;

font[nFonts-1].base = glGenLists(96);

font[nFonts-1].hf = CreateFont(-size,0,0,0,bold?FW_BOLD:FW_NORMAL,italic?TRUE:FALS E,underline?TRUE:FALSE,FALSE,ANSI_CHARSET,OUT_TT_P RECIS, CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY,FF_DONTCAR E|DEFAULT_PITCH,FontName);

wglUseFontBitmaps(hdc,32,96,font[nFonts-1].base);
}

void CRT2D::RenderText(LPCTSTR Name, LPCTSTR Text, Vec2 pos, RGBA color)
{
if (text==NULL)
return;

int h = Fonts(Name);
if (h<0) return;

char t[256];
glColor4f(color);
//font to use
SelectObject(hdc, font[h].hf);
glRasterPos2f(pos.x,pos.y);

sprintf(t,"%s",text);
glPushAttrib(GL_LIST_BIT);
glListBase(font[h].base-32);

glCallLists(strlen(t),GL_UNSIGNED_BYTE,t);
glPopAttrib();
}

//the search routine
int CRT2D::Fonts(LPCTSTR name)
{
int nIndex=0;
vector<rtFont>::const_iterator ib=font.begin();
vector<rtFont>::const_iterator ie=font.end();
vector<rtFont>::const_iterator i;

for (i=ib; i!=ie; i++,nIndex++)
{
if (strcmp((*i).fName,name)==0)
return nIndex;
}
return -1;
}

Thats it. This rendering code shows nothing on the screen. If I place the wglUseFontBitmaps(...) inside the render loop, it works, but it is all messed up.



[This message has been edited by kaysoft (edited 10-10-2002).]

*Aaron*
10-10-2002, 12:20 PM
void CRT2D::RenderText(LPCTSTR Name, LPCTSTR Text, Vec2 pos, RGBA color)
{
...
//font to use
SelectObject(hdc, font[h].hf);
glRasterPos2f(pos.x,pos.y)
...;
SelectObject is what selects the font, right? This should be called right before wglCreateFontBitmaps. It does no good to select the GDI font after the display lists are already created. I don't see any other problems with the code.

kaysoft
10-10-2002, 12:57 PM
Thank you so much, that was it!!

*Aaron*
10-10-2002, 04:25 PM
No problem. Unless you're going to use the fonts in GDI calls, you should probably also call DeleteObject on the fonts after calling wglUseFontBitmaps.

kaysoft
10-11-2002, 03:51 AM
One thing though: It seems that I have to call SelectObject, wglUseFontBitmaps in the render loop. Otherwise, if I call them in the createwindow, it wont render anything. Is this the way its supposed to be?

*Aaron*
10-11-2002, 06:56 AM
wglUseFontBitmaps creates OpenGL display lists, so you have to call it after you create and select the GL resource context. Is this the problem?

kaysoft
10-11-2002, 07:20 AM
No, that is not the problem. It just seems that I need to call wglUseFontBitmaps in each frame.

Also, this text rendering method is very slow, does anyone know where I can find a faster one? Or point to some tutorials?

*Aaron*
10-11-2002, 09:03 AM
Let me explain what wglUseFontBitmaps does. It generates a bitmap (i.e., one bit for each pixel) for each of the characters in the specified range using the currently selected font. Then it calls glBitmap in a display list once for each character. Calling these display lists will then draw the character on the screen at the current raster position. Just like any other display lists, these will still be valid until you delete them or delete the GL resource context. Of course it will be slow if you go through this whole process every time you draw a string. Check the return value of wglUseFontBitmaps to see if it succeeded.

However, drawing bitmaps in OpenGL can still be a bit slow on some implementations. The fastest way I know of to draw text is to load all of the characters for a font into a single texture. Then figure out how to calculate the texture coords for a character. If you understand how to load a texture and use texture mapping, this should be straightforward.

kaysoft
10-11-2002, 11:03 AM
Ok, thanks Aaron for the information!

I think I will go for texture fonts.
Cya

10-12-2002, 08:35 PM
Texture fonts are by far the fastest implementation. Have you tried putting a significant amount of text on the screen with the bitmap font you're using? It will slow to a crawl.

I use glfont, a free easy to use font generating tool by Brad Fish. glfont can be downloaded here:

http://students.cs.byu.edu/~bfish/glfont.php#glFont