} // Loop Until All 256 Are Built
}
KillFont is still the same. We created 256 display lists, so we need to destroy 256 display lists when the program closes.
GLvoid KillFont(GLvoid) // Delete The Font From Memory
{
glDeleteLists(base,256); // Delete All 256 Display Lists
}
The glPrint() code has only changed a bit. The letters are all stretched on the y axis. Making the letters very tall. I've explained the rest of the code in other tutorials. The stretching is accomplished with the glScalef(x,y,z) command. We leave the ratio at 1.0 on the x axis, we double the size on the y axis (2.0), and we leave it at 1.0 on the z axis.
GLvoid glPrint(GLint x, GLint y, int set, const char *fmt, …) // Where The Printing Happens
{
char text[1024]; // Holds Our String
va_list ap; // Pointer To List Of Arguments
if (fmt == NULL) // If There's No Text
return; // Do Nothing
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
if (set>1) // Did User Choose An Invalid Character Set?
{
set=1; // If So, Select Set 1 (Italic)
}
glEnable(GL_TEXTURE_2D); // Enable Texture Mapping
glLoadIdentity(); // Reset The Modelview Matrix
glTranslated(x,y,0); // Position The Text (0,0 – Top Left)
glListBase(base-32+(128*set)); // Choose The Font Set (0 or 1)
glScalef(1.0f,2.0f,1.0f); // Make The Text 2X Taller
glCallLists(strlen(text),GL_UNSIGNED_BYTE, text); // Write The Text To The Screen
glDisable(GL_TEXTURE_2D); // Disable Texture Mapping
}
ReSizeGLScene() sets up an ortho view. Nothing really new. 0,1 is the top left of the screen. 639,480 is the bottom right. This gives us exact screen coordinates in 640 x 480 resolution. Notice that we set the value of swidth to equal the windows current width, and we set the value of sheight to equal the windows current height. Whenever the window is resized or moved, sheight and swidth will be updated.
GLvoid ReSizeGLScene(GLsizei width, GLsizei height) // Resize And Initialize The GL Window
{
swidth=width; // Set Scissor Width To Window Width
sheight=height; // Set Scissor Height To Window Height
if (height==0) // Prevent A Divide By Zero By
{
height=1; // Making Height Equal One
}
glViewport(0,0,width,height); // Reset The Current Viewport
glMatrixMode(GL_PROJECTION); // Select The Projection Matrix
glLoadIdentity(); // Reset The Projection Matrix
glOrtho(0.0f,640,480,0.0f,-1.0f,1.0f); // Create Ortho 640x480 View (0,0 At Top Left)
glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix
glLoadIdentity(); // Reset The Modelview Matrix
}
The init code is very minimal. We load our TGA file. Notice that the first parameter passed is &textures[0]. The second parameter is the name of the file we want to load. In this case, we want to load the Font.TGA file. If LoadTGA() returns false for any reason, the if statement will also return false, causing the program to quit with an "initialization failed" message.
If you wanted to load a second texture you could use the following code: if ((!LoadTGA(&textures[0],"image1.tga")) || (!LoadTGA(&textures[1],"image2.tga"))) { }
After we load the TGA (creating our texture), we build our font, set shading to smooth, set the background color to black, enable clearing of the depth buffer, and select our font texture (bind to it).
Lastly we return true so that our program knows that initialization went ok.
int InitGL(GLvoid) // All Setup For OpenGL Goes Here
{
if (!LoadTGA(&textures[0],"Data/Font.TGA")) // Load The Font Texture
{
return false; // If Loading Failed, Return False
}
BuildFont(); // Build The Font
glShadeModel(GL_SMOOTH); // Enable Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
glClearDepth(1.0f); // Depth Buffer Setup
glBindTexture(GL_TEXTURE_2D, textures[0].texID); // Select Our Font Texture
return TRUE; // Initialization Went OK
}
The draw code is completely new :) we start off by creating a variable of type char called token. Token will hold parsed text later on in the code.
We have another variable called cnt. I use this variable both for counting the number of extensions supported, and for positioning the text on the screen. cnt is reset to zero every time we call DrawGLScene.
We clear the screen and depth buffer and then set the color to bright red (full red intensity, 50% green, 50% blue). at 50 on the x axis and 16 on the y axis we write teh word "Renderer". We also write "Vendor" and "Version" at the top of the screen. The reason each word does not start at 50 on the x axis is because I right justify the words (they all line up on the right side).
int DrawGLScene(GLvoid) // Here's Where We Do All The Drawing
{
char *token; // Storage For Our Token
int cnt=0; // Local Counter Variable
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear Screen And Depth Buffer
glColor3f(1.0f,0.5f,0.5f); // Set Color To Bright Red
glPrint(50,16,1,"Renderer"); // Display Renderer
glPrint(80,48,1,"Vendor"); // Display Vendor Name
glPrint(66,80,1,"Version"); // Display Version
Now that we have text on the screen, we change the color to orange, and grab the renderer, vendor name and version number from the video card. We do this by passing GL_RENDERER, GL_VENDOR & GL_VERSION to glGetString(). glGetString will return the requested renderer name, vendor name and version number. The information returned will be text so we need to cast the return information from glGetString as char. All this means is that we tell the program we want the information returned to be characters (text). If you don't include the (char *) you will get an error message. We're printing text, so we need text returned. We grab all three pieces of information and write the information we've grabbed to the right of the previous text.
The information we get from glGetString(GL_RENDERER) will be written beside the red text "Renderer", the information we get from glGetString(GL_VENDOR) will be written to the right of "Vendor", etc.
I'd like to explain casting in more detail, but I'm not really sure of a good way to explain it. If anyone has a good explanation, send it in, and I'll modify my explanation.
After we have the renderer information, vendor information and version number written to the screen, we change the color to a bright blue, and write "NeHe Productions" at the bottom of the screen :) Of course you can change this to anything you want.
glColor3f(1.0f,0.7f,0.4f); // Set Color To Orange
glPrint(200,16,1,(char *)glGetString(GL_RENDERER)); // Display Renderer