The Simple DirectMedia Layer from a Win32 Perspective
Part 1: Setting Up Your System for SDL
by Ernest S. Pazera
November 19, 2001

Mission Statement

Lots of people dislike DirectX, for one reason or another. Some say it is too complicated, others don't like being locked into a single development platform. For whatever reason, people look for alternatives. For a long time, the alternatives available have been a bunch of separate systems that were not built to work together in the same way that DirectX's components do. However, there is SDL, the Simple DirectMedia Layer. It is a cross-platform library for creating multi-media applications. For our purposes, this means games. Since it is cross-platform, and I mean TRULY cross platform, it doesn't matter what platform you are developing on. If you develop carefully, you will be able to take the exact same source code onto a different platform, and it will compile and work in exactly the same manner.

The mission of this article is to get you up and running in SDL on the WIN32 platform. For a long time, I have been primarily a WIN32 programmer, and while this might change in the future, I know that many of you are also WIN32 programmers, so we at least have that in common. During this article, we won't do a whole heck of a lot. We'll get SDL installed and a simple example program that shows a blank window. Believe it or not, that is the hardest part of SDL development. The rest is incredibly easy.

So, to begin, here are the Topical Guide Objectives for this article:

TGO-01-A   Know where to get SDL.
TGO-01-BKnow how to set up Visual C++ 6.0 for SDL development.
TGO-01-CKnow how to start an SDL based project in Visual C++ 6.0.
TGO-01-DMake a very simple program to test your setup.
TGO-01-EMake a very simplistic program with SDL

Getting SDL(TGO-01-A)

Naturally, the first part of the process is to download SDL. You can find it at http://www.libsdl.org. At the time of this writing, the most current version of the API is 1.2.3, and that is the version this article deals with. On the SDL site, you want to download the development libraries for WIN32. The site is well laid out, and it should be really easy for you to find it. They distribute the API as a zip file, so you'll need a copy of WinZip or some other type of archive utility to extract the files. Once you have it downloaded, unzip it somewhere, and take a look at the contents.

In the folder you unzip to, there are three subfolders: docs, include, and lib. These are fairly obvious, and we'll take a look at them a little later.

There are also a number of files, like Bugs, Copying, Readme, and so forth. You should take the time to read all of these, especially Bugs and Copying. SDL is released under the LGPL license, and if you intend to use SDL for creating applications that you wish to sell, you'll need to follow the license. See http://www.gnu.org for more information on the LGPL.

Setting up Visual C++(TGO-01-B)

The API comes with good documentation for setting up projects in WIN32 with SDL, but the docs lack just a little bit in that you have to go through the entire setup EVERY TIME you want to make an SDL base project. Well, you don't have to. There are some things that you only need to do once, and other things that you have to do for each project (which we shall cover in TGO-01-C).

The tasks you only have to do once are to set up the include path and library path for your development environment. In VC++6 you simply call up Tools->Options..., select the Directories tab, and add the appropriate directories to the Include Files and Library Files list and you are done. You will never ever have to do this again unless you uninstall VC++.

Setting up an SDL Project(TGO-01-C)

To set up a project to use SDL, you will have to go through a few steps every time. This isn't terribly uncommon-- you have to do the same thing if you are using DirectX. The type of project you want to create is a WIN32 Application, and have it start with an empty project.

Select the Project->Settings... menu item, and select the "C/C++" tab of the dialog that comes up. In the top combo box (with the word "Category" next to it on the left), select "Code Generation". Next, go over to the combo box entitled "Use Run-Time Library", and select "Multithreaded DLL".

Still in the Settings dialog, move over to the "Link" tab. In the "General" category, you want to edit the content of the "Object/Library Modules" text box. At the beginning of this text box, add "SDLmain.lib" and "SDL.lib".

Now click OK. The last step is to copy SDL.dll from the lib directory of SDL into the directory of your project. Without this dll, your application won't work.

And you are done with the SDL set up for this project. Every time you want to create a project using SDL, you have to do this. It's not too much, really.

Testing the Environment(TGO-01-D)

Now you've got the development environment set, and the project set, and it's time to test everything out to make sure it works. Create a new .cpp file for the project called main.cpp, and add the following code.

#include "SDL.h"
int main ( int argc , char* argv [] )
{
  return ( 0 ) ;
}

The first question to pop into your head is likely "Where did WinMain go?" This is a WIN32 Application, after all, and in WIN32 Applications, we always have to put in a WinMain, right? Well, no. In the .lib files that come with SDL all of the platform dependent stuff like WinMain are taken care of. The entry point for all SDL based applications will be main. Also, you will never want to include windows.h into any of your projects, because to do so would make it platform dependent, which nullifies one of the main goals of using SDL in the first place.

So, of course, this program does approximately nothing, but it is good for testing out the development environment. Attempt to compile and run this code. If it works, you know you've set up the environment and project successfully. If it doesn't, you forgot to do something. Don't be surprised when you run the application and nothing happens. Nothing is SUPPOSED to happen. As long as you don't get some sort of run-time error, you're OK.

A Simple SDL Application (TGO-01-E)

Delete everything in main.cpp, and replace it with the following code:

#include "SDL.h"
int main( int argc, char* argv[] )
{
  //initialize systems
  SDL_Init ( SDL_INIT_VIDEO ) ;
  //set our at exit function
  atexit ( SDL_Quit ) ;
  //create a window
  SDL_Surface* pSurface = SDL_SetVideoMode ( 512 , 384 , 0, SDL_ANYFORMAT ) ;
  //declare event variable
  SDL_Event event ;
  //message pump
  for ( ; ; )
  {
    //look for an event
    if ( SDL_PollEvent ( &event ) )
    {
      //an event was found
      if ( event.type == SDL_QUIT ) break ;
    }
  }//end of message pump
  //done
  return ( 0 ) ;
}

Compile this and run it (we'll go though each of the lines in a moment). If you've done everything correctly, you will be met with a blank, black window with "SDL_App" in the title bar. You can move this window around, and hit the X button in the corner to close it. It is a pretty minimal application, but it's a lot easier than the equivalent WIN32 application that uses DirectX, I guarantee.

Now for a bit of explanation. We'll start with the first line of the program.

SDL_Init ( SDL_INIT_VIDEO ) ;

As you might imagine, SDL_Init is used to initialize the various subsystems of SDL. In this case, we are only initializing the video subsystem. Calling SDL_Init is akin to making use of an IDirectDraw or IDirectSound object, all rolled into one.

atexit ( SDL_Quit ) ;

If you've never used the atexit function before, it sets up another function to be called when the program terminates. This is an old C function that was used before C++ came around and made garbage collection a bit easier with the use of destructors. This line sets up SDL_Quit to be called after the program has terminated. SDL_Quit uninitializes all of SDL for you, so you don't have to. Alternately, you could call SDL_Quit at the end of your program, and you would accomplish the same thing. SDL_Quit is akin to calling IDirectDraw::Release and IDirectSound::Release all in one.

SDL_Surface* pSurface = SDL_SetVideoMode ( 512 , 384 , 0, SDL_ANYFORMAT ) ;

It's only the third line of the program, and already we are setting up the video mode. In a normal WIN32 program, we wouldn't even be half way through setting up our WNDCLASSEX structure. Without over explaining, SDL_Surface is a structure that abstracts a rectangular set of pixels on which you can draw. It is roughly akin to an HDC or an IDirectDrawSurface. The SDL_SetVideoMode function sets up your display. Despite the functions name, it doesn't always set a different display mode, and it certainly doesn't in this case. The parameters are width, height, bits per pixel, and flags. In this case, I am creating a 512x384 surface, but I have a 0 for the bits per pixel. This is because I am using the SDL_ANYFORMAT flag. With this flag, the current format of the display is taken as the format for the surface, so it doesn't really matter what is placed into the third parameter. I could indeed specify a number for this parameter and leave off the SDL_ANYFORMAT flag, and SDL would accommodate me by giving me a surface in the format I requested, regardless of the screen's format. This isn't a good idea, because it requires SDL to "fake" the format if it doesn't match the screen's format. So, if you are making a windowed application, use the SDL_ANYFORMAT flag.

SDL_Event event ;
//message pump
for ( ; ; )
{
  //look for an event
  if ( SDL_PollEvent ( &event ) )
  {
    //an event was found
    if ( event.type == SDL_QUIT ) break ;
  }
}//end of message pump

We will take a look at the rest of the code (minus the line with return on it... I assume you know what THAT does) all at once. SDL_Event is another SDL structure. This time, it abstracts events, something you are likely more than used to in WIN32 programming. Like WIN32, SDL is event driven, and so we have a message pump. The SDL message pump is a lot simpler than the equivalent WIN32 message pump, of course.

Some folks prefer while(1) for their message pump, but I'm one of those who prefer for(;;). I feel it more accurately describes what I'm doing. Both statements are equivalent, of course, so it doesn't really matter which way you do it.

The SDL_PollEvent function checks for a event in the queue. If there is no message waiting, it returns 0. If a message is waiting, it returns 1, and copies the event into the parameter passed to it, in this case the variable I have so aptly named "event".

Only if SDL_PollEvent returns non-zero (i.e. an event has occurred) does the next line get called. In this case, the type member of SDL_Event is checked to see if it is SDL_QUIT, which is the event for exiting the application. If this has happened, we break out of the message pump loop and proceed to exit the application.

Summary

So, is everything about SDL this easy? Yes, pretty much. As I said earlier, the hardest part is setting up the environment. After that, everything is mostly the same as a regular WIN32 application, just with different functions. The key is that this API is called the SIMPLE DirectMedia Layer. From here, I suggest taking a look at some of the SDL docs and playing around with the API, at least until someone convinces me to get off my duff and write another tutorial.

Discuss this article in the forums


Date this article was posted to GameDev.net: 12/4/2001
(Note that this date does not necessarily correspond to the date the article was written)

See Also:
Featured Articles
Simple DirectMedia Layer

© 1999-2011 Gamedev.net. All rights reserved. Terms of Use Privacy Policy
Comments? Questions? Feedback? Click here!