16 Software
Breevy: A text expander that lets you insert long words or phrases and launch apps, websites, and more just by typing abbreviations.
IcyScreen: Automatic screenshots. Have them saved, e-mailed, and uploaded.

Getting Your Feet Wet in SDL, Part 1

A few weeks ago I started playing around with SDL again, after months of "neglect". I've been considering making a game for some time now, but have been busy working on version 2.00 of IcyScreen. Well, we released it a few days ago, so now seems like as good a time as any to start. I needed a refresher; working on this little introduction got 'er done for me, and hopefully it'll help you out as well.

What's SDL?

SDL is a free, open-source, portable game programming API that makes writing games for multiple platforms pretty darn straightforward. According to Wikipedia, SDL is used by Second Life, DOOM 3, Quake 4, UT2K4, DOSBox, and other applications, so it's definitely popular. Anyway, SDL deals with all of the low-level, hardware/OS-specific stuff so the only thing you have to worry about is your game code.

SDL is implemented in a fairly modular fashion. The core library contains most necessary gaming-related functions -- those dealing with audio, video, joysticks, timers, threads, etc -- and the rest is left to add-on library files. For example, the SDL_image library adds support for a heckuva lot more image formats, SDL_TTF adds font rendering support, SDL_net adds portable networking functions, etc. To utilize these add-on libraries all you have to do is download them, point your compiler to them, and call one of the functions in your code.

In this part I'll be explaining the basic SDL functions and datatypes you need to know in order to make a basic game. I think most of you would agree that the only true way to learn is to code, so in the next part I'll get more technical and post a walk-through of a Pong clone I wrote that will deal with everything I talked about today, plus a lot more (including some basic game programming concepts). My hope is that this will give you a decent understanding of how SDL works and will provide you with the knowledge necessary to start creating games right away.

Prerequisites

To compile an SDL program, you'll need to download the core SDL library for your platform, and point your compiler to the header and library files you downloaded. For the heck of it, you may as well fetch the SDL_TTF library, because we'll be dealing with it in the next part of this introduction.

Edit (4/26): If you're having some issues getting SDL set up, check out this excellent comment.

You'd probably do well to get a copy of the official API documentation as well. This article isn't meant to replace the documentation; it's meant to make the documentation much less necessary, and easier to swallow.

Also note that I'm using C syntax, but SDL has wrappers for many other languages, including C++.

Getting Started

Now that we're set up, lets talk code. The most important SDL function is SDL_Init():

     if (SDL_Init(SDL_INIT_VIDEO) != 0) {
/* Get error string with SDL_GetError(). */
}

You should always call this before any other SDL function in your program; it initializes the subsystems specified in the argument passed to it. For the sake of simplicity, just pass SDL_INIT_VIDEO to this function and forget about it. SDL_Quit() is the polar opposite of this function; it shuts down all initialized SDL subsystems and frees any resources allocated by them.

SDL_Init() only initializes SDL. Now we need a video screen to put all of our graphics in -- what's a game without graphics? We can create a screen by calling SDL_SetVideoMode(), which returns a pointer to an SDL_Surface:

     SDL_Surface *screen = SDL_SetVideoMode(256, 256, 24, SDL_SWSURFACE);
if (screen == NULL) {
/* Get error string with SDL_GetError(). */
}

What the heck is an SDL_Surface?

In SDL, areas of "graphical" memory are represented by the SDL_Surface structure. So if you wanted to load an image with SDL, or create a video screen, it would be loaded into an SDL_Surface structure by SDL. The structure itself contains some useful information pertaining to the surface, such as it's width/height, the raw pixel data, etc. It should be noted, that all SDL_Surfaces should be freed with a call to SDL_FreeSurface() when you're done with them (except for the surface returned by SDL_SetVideoMode(), which is freed with a call to SDL_Quit()).

Back to the SDL_SetVideoMode() function... after you call it with your desired window width, height, bits-per-pixel value, and any desired flags (I passed SDL_SWSURFACE, to tell SDL to create the video surface in system, instead of video, memory), you'll get a pointer to an SDL_Surface that represents the video screen. Consider it the sandbox in which all of your toys (graphics) are placed.

Here's where it starts getting cool. Want to load an image from a file? Easy! Just call SDL_LoadBMP() with the path to the image, and it'll be loaded into an SDL_Surface:

     SDL_Surface *image = SDL_LoadBMP("image.bmp");
if (image == NULL) {
/* Error. You know the drill. */
}

If you want to load images that are in formats other than .BMP, just download the SDL_Image library and call IMG_Load() instead.

To draw that image on screen, make a call to SDL_BlitSurface() with the image's surface (SDL_Surface), the screen's surface, and the X/Y coordinate you'd like the image to be placed at on the screen. Here's a little convenience function to do just that:

int blit_surface(SDL_Surface *src, SDL_Surface *dest, Sint16 x, Sint16 y) {

SDL_Rect offset;
offset.x = x;
offset.y = y;
offset.w = offset.h = 0;

return SDL_BlitSurface(src, NULL, dest, &offset);
}

src is the source surface (in our case, our image); dest is the destination surface -- the screen -- and x and y are of course the X/Y coordinates that the source should start being drawn at on the destination. Note that in SDL, as the X coordinate increases, it moves to the right; as the Y coordinate increases, it moves downward.

After you blit the image onto the screen, you've gotta tell SDL to update the screen so you can see the changes. A simple call to SDL_UpdateRect() will do this:

     blit_surface(image, screen, 25, 30);
SDL_UpdateRect(screen, 25, 30, image->w, image->h);

The above snippet blits the image onto the screen at X/Y coordinate 25, 30, and then tells SDL to update the part of the screen that has changed. To update the entire screen, you can pass the screen, and then all zeros, to the function.

Finishing up

So that's basically that, as far as the basic video screen-creating and graphic loading/drawing functions are concerned. As you can see, SDL doesn't have much of a learning curve, which I find pretty attractive. That certainly doesn't mean game programming is easy; it just means that you don't have to worry about having to deal with an API that's a pain in the butt to use.

What now?

You may be wondering: "How do I detect when a certain key is pressed, make graphics move around on the screen, detect a collision, create a game loop, cap the frame rate, etc?" Don't worry, I'll be covering /all/ of those issues, plus a lot of other stuff, in the next part of the introduction, which will probably be posted in no more than a couple of days.

EDIT (4/22/09): The second part of this article can be read here.

EDIT (5/12/09): Fixed a broken link.

Posted by Patrick on April 20, 2009 at 5:39pm | 6 Comments
Tagged: , , and