Выбрать главу

The line below does the following. First it tells OpenGL we're going to be displaying lists to the screen. strlen(text) finds out how many letters we're going to send to the screen. Next it needs to know what the largest list number were sending to it is going to be. We're not sending any more than 255 characters. The lists parameter is treated as an array of unsigned bytes, each in the range 0 through 255. Finally we tell it what to display by passing text (pointer to our string).

In case you're wondering why the letters don't pile on top of eachother. Each display list for each character knows where the right side of the letter is. After the letter is drawn, OpenGL translates to the right side of the drawn letter. The next letter or object drawn will be drawn starting at the last location GL translated to, which is to the right of the last letter.

Finally we pop the GL_LIST_BIT setting GL back to how it was before we set our base setting using glListBase(base-32).

 glCallLists(strlen(text), GL_UNSIGNED_BYTE, text); // Draws The Display List Text ( NEW )

 glPopAttrib(); // Pops The Display List Bits ( NEW )

}

The only thing different in the Init code is the line BuildFont(). This jumps to the code above that builds the font so OpenGL can use it later on.

int InitGL(GLvoid) // All Setup For OpenGL Goes Here

{

 glShadeModel(GL_SMOOTH); // Enable Smooth Shading

 glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background

 glClearDepth(1.0f); // Depth Buffer Setup

 glEnable(GL_DEPTH_TEST); // Enables Depth Testing

 glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do

 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations

 BuildFont(); // Build The Font

 return TRUE; // Initialization Went OK

}

Now for the drawing code. We start off by clearing the screen and the depth buffer. We call glLoadIdentity() to reset everything. Then we translate one unit into the screen. If we don't translate, the text wont show up. Bitmap fonts work better when you use an ortho projection rather than a perspective projection, but ortho looks bad, so to make it work in projection, translate.

You'll notice that if you translate even deeper into the screen the size of the font does not shrink like you'd expect it to. What actually happens when you translate deeper is that you have more control over where the text is on the screen. If you tranlate 1 unit into the screen, you can place the text anywhere from –0.5 to +0.5 on the X axis. If you tranlate 10 units into the screen, you place the text from –5 to +5. It just gives you more control instead of using decimal places to position the text at exact locations. Nothing will change the size of the text. Not even glScalef(x,y,z). If you want the font bigger or smaller, make it bigger or smaller when you create it!

int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing

{

 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer

 glLoadIdentity(); // Reset The View

 glTranslatef(0.0f,0.0f,-1.0f); // Move One Unit Into The Screen

Now we use some fancy math to make the colors pulse. Don't worry if you don't understand what I'm doing. I like to take advantage of as many variables and stupid tricks as I can to achieve results :)

In this case I'm using the two counters we made to move the text around the screen to change the red, green and blue colors. Red will go from –1.0 to 1.0 using COS and counter 1. Green will also go from –1.0 to 1.0 using SIN and counter 2. Blue will go from 0.5 to 1.5 using COS and counter 1 and 2. That way blue will never be 0, and the text should never completely fade out. Stupid, but it works :)

 // Pulsing Colors Based On Text Position

 glColor3f(1.0f*float(cos(cnt1)), 1.0f*float(sin(cnt2)), 1.0f-0.5f*float(cos(cnt1+cnt2))); 

Now for a new command. glRasterPos2f(x,y) will position the Bitmapped Font on the screen. The center of the screen is still 0,0. Notice there's no Z position. Bitmap Fonts only use the X axis (left/right) and Y axis (up/down). Because we translate one unit into the screen, the far left is –0.5, and the far right is +0.5. You'll notice that I move 0.45 pixels to the left on the X axis. This moves the text into the center of the screen. Otherwise it would be more to the right of the screen because it would be drawn from the center to the right.

The fancy(?) math does pretty much the same thing as the color setting math does. It moves the text on the x axis from –0.50 to –0.40 (remember, we subtract 0.45 right off the start). This keeps the text on the screen at all times. It swings left and right using COS and counter 1. It moves from –0.35 to +0.35 on the Y axis using SIN and counter 2.

// Position The Text On The Screen

glRasterPos2f(-0.45f+0.05f*float(cos(cnt1)), 0.35f*float(sin(cnt2)));

Now for my favorite part… Writing the actual text to the screen. I tried to make it super easy, and very user friendly. You'll notice it looks alot like an OpenGL call, combined with the good old fashioned Print statement :) All you do to write the text to the screen is glPrint("{any text you want}"). It's that easy. The text will be drawn onto the screen at the exact spot you positioned it.

Shawn T. sent me modified code that allows glPrint to pass variables to the screen. This means that you can increase a counter and display the results on the screen! It works like this… In the line below you see our normal text. Then there's a space, a dash, a space, then a "symbol" (%7.2f). Now you may look at %7.2f and say what the heck does that mean. It's very simple. % is like a marker saying don't print 7.2f to the screen, because it represents a variable. The 7 means a maximum of 7 digits will be displayed to the left of the decimal place. Then the decimal place, and right after the decimal place is a 2. The 2 means that only two digits will be displayed to the right of the decimal place. Finally, the f. The f means that the number we want to display is a floating point number. We want to display the value of cnt1 on the screen. As an example, if cnt1 was equal to 300.12345f the number we would end up seeing on the screen would be 300.12. The 3, 4, and 5 after the decimal place would be cut off because we only want 2 digits to appear after the decimal place.

I know if you're an experienced C programmer, this is absolute basic stuff, but there may be people out there that have never used printf. If you're interested in learning more about symbols, buy a book, or read through the MSDN.

 glPrint("Active OpenGL Text With NeHe – %7.2f", cnt1); // Print GL Text To The Screen

The last thing to do is increase both the counters by different amounts so the colors pulse and the text moves.

 cnt1+=0.051f; // Increase The First Counter

 cnt2+=0.005f; // Increase The Second Counter

 return TRUE; // Everything Went OK

}

The last thing to do is add KillFont() to the end of KillGLWindow() just like I'm showing below. It's important to add this line. It cleans things up before we exit our program.

 if (!UnregisterClass("OpenGL",hInstance)) // Are We Able To Unregister Class

 {

  MessageBox(NULL, "Could Not Unregister Class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);

  hInstance=NULL; // Set hInstance To NULL

 }

 KillFont(); // Destroy The Font

}

That's it… Everything you need to know in order to use Bitmap Fonts in your own OpenGL projects. I've searched the net looking for a tutorial similar to this one, and have found nothing. Perhaps my site is the first to cover this topic in easy to understand C code? Anyways. Enjoy the tutorial, and happy coding!