An Introduction to SDL Programming in Linux

Game programming has come a long way since the early Linux and Windows days. The time when games were limited to Windows or an extend Mac is long gone. Today, as Linux strengthens its presence in the desktop market, the demand for Linux-based games is growing. This has brought portability to the forefront even in the gaming segment. The birth of OpenGL was the first step in this regard, but OpenGL addressed only the rendering aspect of game programming. The major part, i.e. communicating with varied input devices, was left to the operating system. This is the main reason for the existence of various extensions to OpenGL, including GLUT (platform independent), MESA (OpenGL extension for *nix systems) and WOGL (OpenGL extension for Windows). Each has its own pros and cons. If a library is OS independent, then it has limited capability for utilizing the available resources. On the other hand, if the library were able to harness the power of the underlying system, then such a library would be platform dependent.

It was during such times of extreme choices that SDL came into the picture. SDL is a library “by the game programmers for the game programmers”. Hence, it does not try to achieve the ‘unachievable’ by starting from the scratch. Instead, it is built upon existing libraries for each OS, i.e. it uses DirectX for Windows and XWindows APIs for *nix systems. So, the obvious question that arises is how to harness the power of SDL on Linux?

In this article, the first in a series of four, we will discuss the steps to be followed in order to setup your Linux box for SDL programming. We shall even develop a small application that would not only test the setup but also introduce you to the world of SDL programming. Let’s get started!

What is SDL?

As already stated, SDL is a library developed by the game programmers themselves. Hence, implementation is such that it never gets in the way of the programmer/s code. For the sake of brevity, one can say that it follows the philosophy of SMILE (Simple Makes It Lot Easier). This philosophy is evident in the functionalities provided by it, which are:

a. Initialization and Shutdown;
b. Input processing;
c. Timers;
d. Sound effects;
e. Graphics manipulation;
f. Network integration; and
g. Threading requirements.

All the above functionalities come into the gaming scenario now and then; especially the first five are essential in any game. SDL makes dealing with each of them easier. Let’s see how.

a. Initialization and Shutdown:
Whenever a game starts it must perform initialization routines, including memory allocation, resource acquisition, loading any required data from the disk, etc. For performing these routines, the programmer has to query the underlying OS to know the boundaries set by it. To achieve this end, some code has to be written and again code has to be written to use the result of the query. SDL abstracts this with a single function: SDL_Init(). We will look it up more deeply in the next section.

b. Input Processing:
In a gaming environment, the input can be in the form of keyboard input, joystick, mouse and so on. The processing model provided by SDL is event based. Anyone who has worked in VB, Delphi or Xlib (or any of its variants) would feel at home with SDL’s event model. The base of this model is SDL_WaitEvent() method that takes SDL_Event as the reference.

c. Timers:
Without timers, it is nearly impossible to imagine any challenging game. If one goes by standard methods, one would have to rely on the Timers provided by the platform. With SDL, this is a thing of the past. The Time and Timer APIs provided by it are lean, mean and clean in a platform and OS independent way. SDL_getTicks() is the core of SDL timer API.

d. Sound Effects:
As with other functionalities provided by SDL, functionalities related to sound is provided with minimum hassles. Sound support as a core subsystem is minimal in nature, adhering to the keep-it-lean philosophy of SDL. However, there are other libraries that provide extended capabilities around SDL’s APIs.

e. Graphics Manipulation:
With SDL, one has the option to work either at the raw pixel level or at a higher level using OpenGL. Since OpenGL is available for every platform and it can render both 2D and 3D graphics in hardware-accelerated mode, it is better to use OpenGL in conjunction with SDL.

f. Networking Requirements:
Like other functionalities, networking is also important in the current genre of games. Understanding the importance of this feature, developers of SDL provided APIs that do the ground-level work to set up the network connections and manage them, thus making networked multiplayer game less of an enigma.

g. Threading Requirements:
The pthreads library provided by POSIX is a platform independent way of working with threads. However, the API works at low level, which can be confusing. In order to make threading simpler, SDL provides all the required functionalities in a high-level manner.

In essence, SDL provides for all the gaming requirements in a simple and portable way. Now that the intro to the functionalities is out of our way, we can actually see how the theory works out in the real world.

Entering the world of SDL

Now let us get into some coding using SDL. The steps to be followed are:

1. Checking SDL configuration:

The best thing about Linux is that it is configured for various development environments if the selections are done correctly (and if a distro is being used). To check whether the SDL library is present or not, just use the locate command at the prompt - raj@linuxden# locate SDL.h

If locate does not return anything, then you will have to download either the binaries or source from http://www.libsdl.org/
If the plan is to use OpenGL, then do the same for it also (just check out for MESA).

2. Initialization and Shutting down:

In this article, we will deal with initialization and shutting down of a game system. Before starting, let’s include the required headers

#include “SDL.h”
#include<stdio.h>


All the required functions are declared within SDL.h. Next comes the well-known function main().

#include “SDL.h”
#include<stdio.h>

int main(int argc,char* argv[])
{
:
:
}


SDL provides two functions to perform initialization and shutdown routines. For initialization, the method provided is SDL_Init(), which has to be used thus:

#include “SDL.h”
#include<stdio.h>

int main(int argc,char* argv[])
{

/*The following code does the initialization for Audio and Video*/
int i_error=SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|
SDL_INIT_CDROM);

:
}

The SDL_Init takes as a parameter the subsystems that need to be initialized apart from the default subsystems. Here, I am initializing Video, audio and CDROM subsystems. If the initialization is unsuccessful then -1 will be returned i.e.

#include “SDL.h”
#include<stdio.h>

int main(int argc,char* argv[])
{

/*The following code does the initialization for Audio and Video*/
int i_error=SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|
SDL_INIT_CDROM);

/*If initialization is unsuccessful, then quit */ 
if(i_error==-1)
exit(1);

atexit(SDL_Quit);

:
}

To cleanup while exiting, atexit can be used for small programs. Otherwise, before calling quits, the dynamically loaded memory has to be freed using the custom cleanup code. The atexit() function is passed into SDL_Quit function.

Now, it is time to find out how many CDROM drives are there in the system. The following code deals with this task.

#include “SDL.h”
#include<stdio.h>

int main(int argc,char* argv[])
{

/*The following code does the initialization for Audio and Video*/
int i_error=SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO|
SDL_INIT_CDROM);
int i_num=-1;
/*If initialization is unsuccessful, then quit */ 
if(i_error==-1)
exit(1);

atexit(SDL_Quit);

/*Enumerate the CDROM drives in the system*/
printf("Drives available: %d\n", SDL_CDNumDrives());

for ( i_num=0; i_num<SDL_CDNumDrives(); ++i_num ) 
{
printf("Drive %d: \"%s\"\n", i_num, SDL_CDName(i_num));
}
}


SDL_CDNumDrives() returns the number of CD drives present in a system. The next one, i.e. SDL_CDName(), takes an integer parameter and returns the corresponding drive name. That concludes our code section.

To run the code, I have used the command

gcc `sdl-config --libs` enumCD.c -o enumCD

The `sdl-config –-libs` would include the necessary libraries. On the other hand, if make file is being used, then:

all: enumCD

enumCD: enumCD.o
gcc `sdl-config --libs` enumCD.o -o enumCD

enumCD.o: enumCD.c
gcc -c `sdl-config --cflags` enumCD.c


This brings us to the end of the first part of this article series. In this section, you have just tasted SDL programming, an entry point into the world of SDL. In forthcoming articles, I will delve into each subsystem and will take you deep into the world of SDL. Until next time...


(Author’s picture available)
Project Engineer,
Center for Development of Advanced Computing (C-DAC),
Hyderabad (A.P).
Email: id - a_p_rajshekhar@yahoo.co.in



Added on June 12, 2007 Comment

Comments

Post a comment