Sol's Graphics for Beginners

(ch14.cpp)

(prebuilt win32 exe)

14 - Printing Simple Text

(Last revised 6. April 2005)

Feel free to make a copy of the project, or continue from the last one.

Like last time, we need a new bmp file - font.bmp (right-click, save as), to the same place as before, ie. the place where your main.cpp is. You can see part of the image on the left as a gif file.

As you can see, the font is arranged pretty much the same way as our tiles were. Each character is in the center of one 16x16 tile, and the image is 16 pixels wide.

Another thing about the font is that the characters are arranged in ASCII order, starting from character 33, which is the exclamation point. Character 32 would be space, which we're not including for a reason that will become apparent in next chapter.

The web is full of ASCII table definitions, so I won't reproduce it here.

First, add a new variable (near top, where the other surfaces are):

// Surface that contains the font
SDL_Surface *gFont;

And we'll load it exactly the same way as the tiles. Paste the following in init(), after the tile loading code:

temp = SDL_LoadBMP("font.bmp");
gFont = SDL_ConvertSurface(temp, gScreen->format, SDL_SWSURFACE);
SDL_FreeSurface(temp);

Since the font has been arranged very much like the tile graphics were, the code to draw one character is (for now), very similar to the tile-drawing code. Paste the following after the drawtile() function:

void drawcharacter(int x, int y, int character)
{
  if (character == 32)
    return;
  
  character -= 33; // our font does not have the first 33 characters.

  // Lock surface if needed
  if (SDL_MUSTLOCK(gFont))
    if (SDL_LockSurface(gFont) < 0) 
      return;

  int i, j;
  for (i = 0; i < gFont->w; i++)
  {
    int screenofs = x + (y + i) * PITCH;
    int charofs = (i + character * gFont->w) * (gFont->pitch / 4);
    for (j = 0; j < gFont->w; j++)
    {
      ((unsigned int*)gScreen->pixels)[screenofs] = 
        ((unsigned int*)gFont->pixels)[charofs];
      screenofs++;
      charofs++;
    }
  }

  // Unlock if needed
    if (SDL_MUSTLOCK(gFont)) 
        SDL_UnlockSurface(gFont);
}

Like I mentioned, the font itself is layed out in ASCII order, starting from the '!' character. ASCII code for '!' is 33. You should also notice that we're using the font surface's width to figure out the size of one character tile.

Okay, so we could use drawcharacter to draw single letters on the screen (like drawcharacter(50, 50, 'E')), but that wouldn't be too useful. Paste the following function after the drawcharacter() one:

void drawstring(int x, int y, char *s)
{
  while (*s != 0)
  {
    drawcharacter(x, y, *s);
    s++;
    x += gFont->w;
  }
}

This code runs through the 's' string, calling drawcharacter for each character in it. After each character, the x offset is moved to the right by the character width.

Remember that our character drawing code does not have clipping, so you must be careful not to draw outside the screen with it (or you could, of course, implement the clipping).

Since this is the very first time we're drawing text in this whole tutorial, let's do it the traditional way. Paste the following line in render(), after the player's object has been drawn:

drawstring(100, 100, "Hello world!");

So, now we have text. As you can see, the text has a couple of problems: First, the letters have varying amount of black space between them. Second, the text badly obscures the background.

To resolve these problems, we'll change the printing code to do 15 - Slightly Improved Text.

Having problems? Improvement ideas? Just want to discuss this tutorial? Try the forums!

Any comments etc. can be emailed to me.