A Crash Course in SDL

An adaptation of a chapter from the author's upcoming book entitled Programming Linux Games.
Drawing with Blits

We've seen how to draw pixels directly to a surface, and there's no reason one couldn't create an entire game with this alone. However, there is a much better way to draw large amounts of data to the screen. Our next example will load an entire surface from a file and draw it with a single SDL surface copying function. The code can be seen in Listing 3.

Listing 3. Drawing Large Amounts of Data to the Screen

As you can see, the bitmap file is loaded into memory with the SDL_LoadBMP function. This function returns a pointer to an SDL_Surface structure containing the image, or a NULL pointer if the image cannot be loaded. Once this file has been successfully loaded, the bitmap is represented as an ordinary SDL surface, and a program can draw it onto the screen or any other surface. Bitmaps use dynamically allocated memory, and they should be freed when they are no longer needed. The SDL_FreeSurface function frees the memory allocated to a bitmap.

The SDL_BlitSurface function performs a blit of one surface onto another, converting between pixel formats as necessary. This function takes four arguments: a source surface (the image to copy from), an SDL_Rect structure defining the rectangular region of the source surface to copy, a destination surface (the image to copy to), and another SDL_Rect structure indicating the coordinates on the destination that the image should be drawn to. These two rectangles must be of the same width and height (SDL does not currently perform stretching), but the x and y starting coordinates of the regions may be different.

Colorkeys and Transparency

Games often need to simulate transparency. For instance, suppose that we have a bitmap of a game character against a solid background, and we want to draw the character in a game level. It would look silly to draw the character as is; the background would be drawn too, and the character would be surrounded by a block of solid color. It would be much better to draw only the pixels that are actually part of the character and not its solid background. We can do this with a colorkey blit. SDL provides support for this, and it even provides support for run-length colorkey acceleration (a nice trick for speeding up drawing). RLE acceleration provides an enormous performance boost for blitting colorkeyed images, but this is only practical for bitmaps that will not be modified during the course of the program (since modifying an RLE image necessitates unpacking and repacking the image).

A colorkey is a particular pixel value that a program declares to be transparent (in SDL, this is done with the SDL_SetColorKey function). Pixels that match an image's colorkey are not copied when the image is blitted. In our example of a game character, we could set the colorkey to the color of the solid background, and it would not be drawn. Colorkeys make it simple to combine rectangular images of non-rectangular objects.

In the next example we will use a colorkey blit to draw an image of Tux against another image [see Listing 4, available at ftp.linuxjournal.com.pub/lj/listings/issue81/]. Tux is stored against a solid blue background, and so we will use blue (RGB 0, 0, 255) as our colorkey. For comparison, we will also draw the same penguin image without a colorkey.

Figure 1. Tux.bmp

Figure 2. Colorkey-Output

Simple Keyboard Handling

SDL assigns a “virtual keysym” to each key on the keyboard. These codes (integers) map at some level to the operating system's keyboard scan codes (which in term map to the codes produced by the keyboard's hardware), but SDL takes care of the mapping behind the scenes. SDL provides a preprocessor symbol for each virtual keysym; for instance, the Escape key corresponds to the symbol SDLK_ESCAPE. (You can find a list of valid keysyms in SDL's documentation.) We use these codes whenever we need to directly check the state (up or down) of a particular key, and SDL uses them when it reports key events. Virtual keysyms are represented by the SDLKey data type.

Since we won't be messing with the event interface for now (indeed, we haven't really even mentioned it), we'll need to ask the keyboard explicity for its current state whenever we need to know about a key. A program can obtain a snapshot of the entire keyboard in the form of an array. The SDL_GetKeyState function returns a pointer to SDL's internal keyboard state array, which is indexed with the SDLK_ keysym constants. You only need to call this function once; the pointer remains valid for the duration of the program. Each entry in the array is a simple Uint8 flag indicating whether that key is currently down. You should call SDL_PumpEvents periodically to update the data in the array.