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

 {

  length+=gmf[text[loop]].gmfCellIncX; // Increase Length By Each Characters Width

 }

Finally we take the length that we calculate and make it a negative number (because we have to move left of center to center our text). We then divide the length by 2. We don't want all the text to move left of center, just half the text!

 glTranslatef(-length/2,0.0f,0.0f); // Center Our Text On The Screen

We then push the GL_LIST_BIT, this prevents glListBase from affecting any other display lists we may be using in our program.

The command glListBase(base) tells OpenGL where to find the proper display list for each character.

 glPushAttrib(GL_LIST_BIT); // Pushes The Display List Bits

 glListBase(base); // Sets The Base Character to 0

Now that OpenGL knows where the characters are located, we can tell it to write the text to the screen. glCallLists writes the entire string of text to the screen at once by making multiple display list calls for you.

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 still not sending any more than 255 characters. So we can use an UNSIGNED_BYTE. (A byte represents a number from 0–255 which is exactly what we need). Finally we tell it what to display by passing the string text.

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 character is. After the letter is drawn to the screen, 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).

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

 glPopAttrib(); // Pops The Display List Bits

}

Resizing code is exactly the same as the code in Lesson 1 so we'll skip over it.

There are a few new lines at the end of the InitGL code. The line BuildFont() from lesson 13 is still there, along with new code to do quick and dirty lighting. Light0 is predefined on most video cards and will light up the scene nicely with no effort on my part :)

I've also added the command glEnable(GL_Color_Material). Because the characters are 3D objects you need to enable Material Coloring, otherwise changing the color with glColor3f(r,g,b) will not change the color of the text. If you're drawing shapes of your own to the screen while you write text enable material coloring before you write the text, and disable it after you've drawn the text, otherwise all the object on your screen will be colored.

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

 glEnable(GL_LIGHT0); // Enable Default Light (Quick And Dirty) ( NEW )

 glEnable(GL_LIGHTING); // Enable Lighting ( NEW )

 glEnable(GL_COLOR_MATERIAL); // Enable Coloring Of Material ( NEW )

 BuildFont(); // Build The Font ( ADD )

 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 ten units into the screen. Outline fonts look great in perspective mode. The further into the screen you translate, the smaller the font becomes. The closer you translate, the larger the font becomes.

Outline fonts can also be manipulated by using the glScalef(x,y,z) command. If you want the font 2 times taller, use glScalef(1.0f,2.0f,1.0f). the 2.0f is on the y axis, which tells OpenGL to draw the list twice as tall. If the 2.0f was on the x axis, the character would be twice as wide.

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,-10.0f); // Move Ten Units Into The Screen

After we've translated into the screen, we want the text to spin. The next 3 lines rotate the screen on all three axes. I multiply rot by different numbers to make each rotation happen at a different speed.

 glRotatef(rot,1.0f,0.0f,0.0f); // Rotate On The X Axis

 glRotatef(rot*1.5f,0.0f,1.0f,0.0f); // Rotate On The Y Axis

 glRotatef(rot*1.4f,0.0f,0.0f,1.0f); // Rotate On The Z Axis

Now for the crazy color cycling. As usual, I make use of the only variable that counts up (rot). The colors pulse up and down using COS and SIN. I divide the value of rot by different numbers so that each color isn't increasing at the same speed. The final results are nice.

 // Pulsing Colors Based On The Rotation

 glColor3f(1.0f*float(cos(rot/20.0f)), 1.0f*float(sin(rot/25.0f)), 1.0f-0.5f*float(cos(rot/17.0f)));

My favorite part… Writing the text to the screen. I've used the same command we used to write Bitmap fonts to the screen. All you have to do to write the text to the screen is glPrint("{any text you want}"). It's that easy!

In the code below we'll print NeHe, a space, a dash, a space, and then whatever number is stored in rot divided by 50 (to slow down the counter a bit). If the number is larger that 999.99 the 4th digit to the left will be cut off (we're requesting only 3 digits to the left of the decimal place). Only 2 digits will be displayed after the decimal place.

 glPrint("NeHe – %3.2f",rot/50); // Print GL Text To The Screen

Then we increase the rotation variable so the colors pulse and the text spins.

 rot+=0.5f; // Increase The Rotation Variable

 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

}

At the end of this tutorial you should be able to use Outline Fonts in your own OpenGL projects. Just like lesson 13, I've searched the net looking for a tutorial similar to this one, and have found nothing. Could my site be the first to cover this topic in great detail while explaining everything in easy to understand C code? Enjoy the tutorial, and happy coding!

Jeff Molofee (NeHe)

* DOWNLOAD Visual C++ Code For This Lesson.

* DOWNLOAD Borland C++ Code For This Lesson. (Conversion by Patrick Salmons)