Working with fonts

Until now, we embedded any text that we needed inside of an existing texture. However, there are times when we may want to have the code decide what text to display. For example, on our credits screen, we don't want to make a graphic for each person's name who took part in creating the game.

Creating the font

We need a way to render text directly to the screen, and this means that we also need a way to define the font that we want to use when rendering the text. First, we need to add a global variable that services as a handle to our fonts. Add the following line to the variable declarations in the code:

GLuint fontBase;

Now, we need to add the following code to create the font:

GLvoid BuildFont(GLvoid)
{
  HFONT newFont;
  HFONT tempFont;
  
  fontBase = glGenLists(96);
  
  tempFont = CreateFont(-26, // Height
  0,                        // Width
  0,                        // Escapement
  0,                        // Orientation
  FW_BOLD,                  // Weight
  FALSE,                    // Italic
  FALSE,                    // Underline
  FALSE,                    // Strikeout
  ANSI_CHARSET,         // Character Set
  OUT_TT_PRECIS,            // Output Precision
  CLIP_DEFAULT_PRECIS, // Clipping Precision
  ANTIALIASED_QUALITY,// Output Quality
  FF_DONTCARE | DEFAULT_PITCH, // Family/Pitch
  "Courier New");           // Font Name
  
  newFont = (HFONT)SelectObject(hDC, tempFont);
  wglUseFontBitmaps(hDC, 32, 96, fontBase);
  SelectObject(hDC, newFont);
  DeleteObject(tempFont);
}

This code creates a font using three main elements.

First, we use glGenLists to create 96 display lists to hold each letter of our font. A display list is basically a buffer that can hold rendering data. Next, we call CreateFont to create a Windows font. The parameters of the CreateFont function specify the type of font that we want to create. Finally, we use wglUseFontBitmaps to assign our new font to the font handle that we created earlier.

One little twist is that we have to create a temporary HFONT object called tempFont with all the properties, then we assign tempFont to newFont and delete tempFont.

We will want to delete the display lists when the program closes down, so add the following utility function:

GLvoid KillFont(GLvoid)
{
  glDeleteLists(fontBase, 96);
}

This code simply uses glDeleteLists to delete the display lists that we created to hold our font.

Drawing text

Now that we have a font, we need to have a function that will render text to the screen. Add the following function to the code:

void DrawText(const char* p_text, const float p_x, const float p_y, const float r, const float g, const float b)
{
 glBindTexture(GL_TEXTURE_2D, 0);
 glColor3f(r, g, b);

 glRasterPos2f(p_x, p_y);
 if (p_text != NULL)
 {
  glPushAttrib(GL_LIST_BIT);
  glListBase(fontBase - 32);
  glCallLists(strlen(p_text), GL_UNSIGNED_BYTE, p_text);
  glPopAttrib();
 }
 glColor3f(1.0f, 1.0f, 1.0f);

}

This code takes a string and an x and y position, and draws the text at that position. It also takes r, g, and b parameters to define the text color:

  • glBindTexture(GL_TEXTURE_2D, 0): This tells OpenGL that we are going to be working with 2D textures (i.e. the fonts) glColor3f(r, g, b): This sets the color of the font.
  • glRasterPos2f: This is used to set the current draw position on the screen.
  • glPushAttrib(GL_LIST_BIT): This tells OpenGL that we are going to render using display lists.
  • glListBase: This sets the current start of the list. We subtract 32 because the ASCII value for a space is 32, and we don't use any characters with lower ASCII values.
  • glCallLists: This is used to retrieve the lists for each character in the text.
  • glPopAttrib: This returns the OpenGL attribute to its previous value.

Now, we are ready to draw our credits text:

void DrawCredits()
{
 float startX = 325.0f;
 float startY = 250.0f;
 float spaceY = 30.0f;
 DrawText("Robert Madsen", startX, startY, 0.0f, 0.0f, 1.0f);
 DrawText("Author", startX, startY + spaceY, 0.0f, 0.0f, 1.0f);
}

First, we set the position on the screen where we want to draw, then we use the DrawText function to actually perform the drawing. The first line adds me (a subtle indulgence), and the second line is for you!

Wiring in the font support

We have a few more book keeping tasks to perform to get the font support to work. First, modify the GameLoop code, adding the highlighted line:

if (m_gameState == GameState::GS_Splash)
{
  BuildFont();
  LoadTextures();
  m_gameState = GameState::GS_Loading;
}

This will create our fonts when the game starts up.

Next, fill out the GS_Credits case of the m_gameState switch in the Render function:

 case GameState::GS_Credits:
 {
  creditsScreen->Update(p_deltaTime);
  menuButton->IsActive(true);
  menuButton->Update(p_deltaTime);
  inputManager->Update(p_deltaTime);
  ProcessInput(p_deltaTime);
 }
 break;

This draws the credits text when the game state changes to GS_Credits. Congratulations! You can finally get the credit that you deserve!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.117.119.206