A Crash Course in SDL

An adaptation of a chapter from the author's upcoming book entitled Programming Linux Games.
Setting up the Display

Before we can begin blitting surfaces to the screen, we need to initialize the SDL library and switch the display into an appropriate mode. Take a look at Listing 1, the equivalent of “Hello, world!” in SDL.

Listing 1. Setting Up the Display

This program includes the SDL.h header file, which is the master header for SDL. Every SDL application should include this file. The program also includes two standard headers, for the printf and atexit functions.

We begin by calling SDL_Init to initialize SDL. This function takes an ORed list of arguments to indicate which subsystems should be initialized; we are only interested in the video subsystem, so we pass SDL_INIT_VIDEO (if we wanted audio, for instance, we would call this function with SDL_INIT_VIDEO | SDL_INIT_AUDIO). Unless a fatal error occurs, this function should return zero. We also use C's atexit facility to request that SDL_Quit be called before the program exits. This function makes sure that SDL has a chance to shut down properly (which becomes especially important if a fullscreen application crashes).

Next, we use the SDL_SetVideoMode function to inform the display of our desired resolution (in this case 640 pixels across by 480 pixels down) and color depth (16-bit packed pixel). There is a catch here: SDL will try to set up the display as requested, but it might fail. If this happens, SDL won't tell us, but it will instead emulate the requested mode internally. This is usually acceptable, since the emulation code is relatively fast, and we would usually rather not deal with multiple modes internally. SDL_SetVideoMode returns a pointer to the surface that represents the display. If something goes wrong, this function returns NULL.

Finally, we report success and exit. The C library calls SDL_Quit automatically (since we registered it with atexit), and SDL returns the video display to its original mode. (We could also call SDL_Quit explicitly if we wanted to shut the system down before exiting our application; there's no harm in calling it more than once.)

Now that we've created an SDL application, we need to compile it. SDL applications are easy to build; assuming a proper installation of SDL, they just require a few flags and libraries. The standard SDL distribution includes a program called sdl-config (similar to the gtk-config and glib-config programs that ship with the GTK+ toolkit) for supplying the appropriate commandline arguments to gcc. The command sdl-config --cflags produces a list of the options that should be passed to the compiler, and sdl-config --libs produces a list of libraries that should be linked in. We can use backtick substitution to drop this into the gcc command line. If SDL is installed on your system, you can compile this example with the following command:

$ gcc sdltest.c -o sdltest `sdl-config --cflags --libs`
Drawing Pixels Directly

Putting data into an SDL surface is simple. Each SDL_Surface structure contains a pixels member. This is a void pointer to the raw graphic image, and we can write to it directly if we know which type of pixel the surface is set up for. We must call the SDL_LockSurface function before we access this data (because some surfaces reside in special memory areas and require special handling). When we are finished with the surface, we must call SDL_UnlockSurface to release it. The width and the height of the image are given by the w and h members of the structure, and the pixel format is specified by the format member (which is of type SDL_PixelFormat). SDL often emulates nonstandard screen resolutions with higher resolutions, and the pitch member of the pixel format structure indicates the actual width of the frame buffer. You should always use pitch instead of w for calculating offsets into the pixels buffer, or else your application might not work on some display devices.

The example shown in Listing 2 will use the SDL pixel format information to draw individual pixels on the screen. We have chosen to use a 16-bit (hicolor) mode for demonstration purposes, but other modes are equally simple to program.

Listing 2. Drawing Individual Pixels on the Screen

The code's comments give the play-by-play, but a few things might not be obvious. This program employs a very general routine for constructing hicolor pixel values; this routine will work with any hicolor (16-bit) pixel format that SDL recognizes. Although we could write a separate (faster) routine for each possible hicolor data layout, this would require a lot of work and would only marginally improve performance. The hicolor 565 (5 red bits, 6 green bits, and 5 blue bits) pixel format is perhaps the most widely used and could be reasonably optimized, but 556 and 555 are not uncommon. In addition, there is no guarantee that the bit fields will be in the red-green-blue order. Our CreateHicolorPixel routine solves this problem by referring to the data in the SDL_PixelFormat structure. For instance, the routine uses the Rloss member of the structure to determine how many bits to drop from the 8-bit red component, and it then uses the Rshift member to determine where the red bits should be located within the 16-bit pixel value.

Another important issue involves the SDL_UpdateRect function. As we mentioned earlier, SDL sometimes emulates video modes if the video card is unable to provide a certain mode itself. If the video card does not support a requested 24-bit mode, for instance, SDL might select a 16-bit mode instead and return a fake frame buffer setup for 24-bit pixels. This would allow your program to continue normally, and SDL would handle the conversion from 24-bits to 16-bits on the fly (with a slight performance loss). The SDL_UpdateRect function informs SDL that a portion of the screen has been updated and that it should perform the appropriate conversions to display that area. If a program does not use this function, there is a chance that it will still work. It is better to be on the safe side and call this function whenever the frame buffer surface has been changed.

Finally, if you run the program you might notice that it runs in a window instead of taking over the entire screen. To change this, replace the zero in the SDL_SetVideoMode call with the constant SDL_FULLSCREEN. Be careful, though; fullscreen applications are harder to debug, and they tend to mess things up badly when they crash.

______________________

Webcast
How to Build an Optimal Hadoop Cluster to Store and Maintain Unlimited Amounts of Data Using Microservers

Realizing the promise of Apache® Hadoop® requires the effective deployment of compute, memory, storage and networking to achieve optimal results. With its flexibility and multitude of options, it is easy to over or under provision the server infrastructure, resulting in poor performance and high TCO. Join us for an in depth, technical discussion with industry experts from leading Hadoop and server companies who will provide insights into the key considerations for designing and deploying an optimal Hadoop cluster.

Learn More

Sponsored by AMD

White Paper
Red Hat White Paper: Using an Open Source Framework to Catch the Bad Guy

Built-in forensics, incident response, and security with Red Hat Enterprise Linux 6

Every security policy provides guidance and requirements for ensuring adequate protection of information and data, as well as high-level technical and administrative security requirements for a system in a given environment. Traditionally, providing security for a system focuses on the confidentiality of the information on it. However, protecting the data integrity and system and data availability is just as important. For example, when processing United States intelligence information, there are three attributes that require protection: confidentiality, integrity, and availability.

Learn more about catching the bad guy in this free white paper.

Learn More

Sponsored by DLT Solutions