The Wayback Machine - http://web.archive.org/web/20030511174315/http://www-106.ibm.com:80/developerworks/library/l-making-linux-fun/
IBMSkip to main content
    IBM home  |  Products & services  |  Support & downloads  |  My account

IBM developerWorks > Linux
developerWorks
SDL: Making Linux fun
e-mail it!
Contents:
What is SDL?
Origin of SDL
Related libraries
Contributing to SDL
Future of SDL
About the author
Rate this article
Related content:
Subscribe to the developerWorks newsletter
developerWorks Toolbox subscription
Also in the Linux zone:
Tutorials
Tools and products
Code and components
Articles
The Simple DirectMedia Layer library is bringing the best games to Linux

Sam Lantinga
Programmer, Loki Entertainment Software
September 1, 1999

Author of the Simple DirectMedia Layer (SDL) library and Loki Entertainment lead developer, Sam Lantinga, introduces you to an excellent tool for porting games to Linux. Supporting many platforms, including Linux, Solaris, IRIX, FreeBSD, and MacOS, SDL is an ideal tool for cross-platform code porting, and another notch on the belt for Linux developers who know the OS is a viable platform for developing commercial software. Learn from one of our community leaders how SDL has allowed Linux users to enjoy some of the best games available on any platform, and how SDL is helping developers keep pace with the demands of the next generation of computer gamers.

One of the most important elements in the development of Linux from the time Linus first hacked it, through its life as a hacker's dream and a worldwide phenomenon, has been the quality and availability of games on the OS. Games are what we do for fun, and what we do to relax. They enhance creativity and tone the mind. Games are also the measure of an operating system. As games get more and more complex, they stress each subsystem to the limits. Whenever I put together a system, my first priority is to load a game and play it, "testing" everything.

Games on Linux have been around for a long time. From the early reaches of NetTrek, to the highly acclaimed ports of DOOM! and Quake , people have been able to play games on Linux. The problem is, there just haven't been enough games. No multi-million dollar companies are producing blockbuster titles for Linux. This is starting to change, however, as the OS becomes increasingly popular.

Most early games on Linux used the X11 protocol. X11 is slow for games, because it was designed as a protocol for menu-based applications that run transparently over the network. Games that used it usually did not have fancy graphics, and often ran slowly. DOOM! was a notable exception, and while it used X11, it was able to take advantage of faster graphics by using the MIT shared memory extension and provide gut-wrenching 3D immersion. There were also a few games that used an SVGA graphics library, SVGAlib. One of my favorites was the old game Gravity Wars, which did great justice to the old Amiga game it was modeled after, Gravity Force. But programs using SVGAlib were limited to the handful of video cards supported.

A screenshot of an early X11 game, Craft.
Click here for larger image

Screenshot of Myth 2, from Loki
Click here for larger image

Today, more options are available for games developers. Games can still be written using the X toolkits, or using a full screen API such as SVGAlib or fbcon, but they can now also use one of the many game libraries available. One of the best low-level game development APIs available for Linux is the Simple DirectMedia Layer library.

What is SDL?
The Simple DirectMedia Layer library, or SDL for short, is one of the few freely available libraries available that is being used by commercial game development companies. It provides 2D framebuffer graphics and audio services in a cross-platform manner, supporting Linux, Win32, and BeOS. Other platforms, including Solaris, IRIX, FreeBSD, and MacOS also have varying degrees of support. SDL provides a simple API that allows you to get as close to the native hardware as possible, in addition to a large range of other services, including threads, endian independence macros, and CD audio. The advantages of using SDL are threefold: stability, simplicity, and flexibility.

  • Stability. SDL couldn't be used by enthusiasts and commercial companies alike if it did not provide solid support for the API. As it is used, bug fixes and enhancements are added, strengthening the robustness of the API. The development of SDL is split, in much the same way the kernel development is split, with one branch being a solid, stable API, and the other branch being a sandbox for new features and ideas.
  • Simplicity. SDL is designed to be a simple API, with the minimum code between you and what you want to do. As an example, I recently ported the demos from the Linux demo group Optimum, and I replaced their X11 code with SDL code (see list below). As you can see, the SDL code is quite a bit simpler to write and understand.
     int init_x (int X, int Y, int W, int H, int bpp, const char *Name) { XPixmapFormatValues *formatList; int formatCount; int i; int formatOk; int scanlineLength; XGCValues gcVal; unsigned long gcMask; dis = XOpenDisplay ( NULL ); if ( dis == NULL) { fprintf ( stderr , "Error :\n" ); fprintf ( stderr , " Cannot connect to Display.\n"); exit (1); } screen = DefaultScreen ( dis ); depth = DefaultDepth ( dis , screen ); width = DisplayWidth ( dis , screen ); height = DisplayHeight ( dis , screen ); winRoot = DefaultRootWindow ( dis ); winAttr.border_pixel = BlackPixel ( dis , screen ); winAttr.background_pixel = BlackPixel ( dis , screen ); winMask = CWBackPixel | CWBorderPixel; formatList = XListPixmapFormats( dis, &formatCount); if (formatList == NULL){ fprintf ( stderr , " Cannot get pixmap list\n"); exit (1); } formatOk=-1; for (i=0; i<formatCount; i++) if ( formatList[i].depth == depth) formatOk=i; if (formatOk == -1){ fprintf ( stderr , " PROUT\n"); exit(1); } memcpy(&pixmapFormat,&formatList[formatOk], sizeof (pixmapFormat)); XFree(formatList); /* taille utile */ scanlineLength = pixmapFormat.bits_per_pixel * W /8; /* padding eventuel */ if ( (scanlineLength & (pixmapFormat.scanline_pad/8 -1)) != 0){ scanlineLength&=~(pixmapFormat.scanline_pad/8 -1); scanlineLength+=pixmapFormat.scanline_pad/8; } win = XCreateWindow ( dis , winRoot , X , Y , W , H , 0 , depth , InputOutput , CopyFromParent , winMask , &winAttr ); XStoreName ( dis , win , Name ); XSelectInput ( dis , win , KeyPressMask ); winHint.flags = PPosition | PMinSize | PMaxSize ; winHint.x = X; winHint.y = Y; winHint.max_width = winHint.min_width = W; winHint.max_height = winHint.min_height = H; XSetWMNormalHints ( dis , win , &winHint ); XClearWindow ( dis , win ); XMapRaised ( dis , win ); XFlush ( dis ); depth = DefaultDepth ( dis , screen ); width = W; height = H; #ifdef USE_SHM /* SHM */ xim = XShmCreateImage(dis,CopyFromParent,depth,ZPixmap,0,&SHMInfo,W,H); if (xim == NULL){ fprintf(stderr, " Couldnt create Ximage..\n"); exit(-1); } SHMInfo.shmid = shmget(IPC_PRIVATE, xim->bytes_per_line*xim->height, IPC_CREAT|0777); xim->data = SHMInfo.shmaddr = (char *)shmat(SHMInfo.shmid, 0, 0); SHMInfo.readOnly = False; XShmAttach(dis, &SHMInfo); XSync(dis, False); buffer=(unsigned char *)xim->data; #else buffer = (unsigned char *)calloc(W*H, pixmapFormat.bits_per_pixel/8); xim = XCreateImage ( dis , CopyFromParent , depth , ZPixmap , 0 , (char *) buffer , W , H , pixmapFormat.scanline_pad, scanlineLength); if (xim == NULL){ fprintf(stderr, " Couldnt create Ximage..\n"); exit(-1); } #endif gcVal.foreground = 0; gcVal.background = 0; gcMask = GCForeground | GCBackground; gc = XCreateGC ( dis , win , gcMask , &gcVal ); if (depth==24) depth = pixmapFormat.bits_per_pixel; return (depth); }
     int init_x (int X, int Y, int W, int H, int bpp, const char *Name) { int i; if ( SDL_Init(SDL_INIT_VIDEO) < 0 ) { fprintf ( stderr , "Erreur :\n" ); fprintf ( stderr , " Impossible de se connecter au Display\n"); exit (1); } screen = SDL_SetVideoMode(W, H, bpp, SDL_SWSURFACE|SDL_HWPALETTE); if ( screen == NULL ) { fprintf ( stderr , "Erreur :\n" ); fprintf ( stderr , " Impossible de se connecter au Display\n"); exit (1); } SDL_WM_SetCaption ( Name, Name ); for ( i=SDL_NOEVENT; i<SDL_NUMEVENTS; ++i ) if ( (i != SDL_KEYDOWN) && (i != SDL_QUIT) ) SDL_EventState(i, SDL_IGNORE); depth = screen->format->BitsPerPixel; width = screen->w; height = screen->h; buffer = (unsigned char *)screen->pixels; return (depth); }
  • Flexibility. Returning to the Optimum demos code examples above, just by porting to SDL and fixing a few data assumptions, the demos now run on Win32, BeOS, and the Linux console with absolutely no code changes. Another aspect of the flexibility is that even though the code is completely cross-platform, you are not locked away from the underlying implementation. SDL provides the function SDL_GetWMInfo(), which gives you access to the private window information for the underlying driver. This is used extensively by Loki Entertainment Software to provide intelligent window manager interaction for their games.

    Screenshots from the Optimum demos

This blend of rock-solid stability, simplicity, and power has given rise to some of the most spectacular games available on Linux to date, including Maelstrom , Hopkins F.B.I. , Civilization: Call To Power , Descent 2 , MythII: Soulblighter , Railroad Tycoon II , and more! The fact that both programming enthusiasts and commercial companies are using the library means that it is improving in features and stability by the day. It is meeting the real needs of real games.

Screenshot of Civilization: Call To Power Screenshot of Descent 2
Click here for larger imageClick here for larger image

Origin of SDL
SDL came about two years ago, when I was working on the Win32 port of the Macintosh emulator Executor. I noticed that essentially the same functionality was being implemented in the same way for several platforms. All the targets required a way of accessing the screen, mapping mouse and keyboard input, and playing sound. I thought: why not write a cross-platform library that provided these basic services that could be used by many people? Application developers would only have to write to a single API, greatly simplifying their task, and suddenly their code could run on more than one platform, reaching the largest audience possible. I set out to do just that, and a little over a year later, the first stable release of SDL was born.

The first step in creating SDL was identifying the functionality needed. I already had a good idea of this from analyzing Executor and my previous porting experience. The next step was building a working prototype, running on both Win32 and Linux. I knew that the greatest test of an API is to work under real applications, so the first thing that I did was use it to complete the port of Executor to Win32. During that time, I fleshed out the API and ported it to BeOS. I then took the newly available DOOM! source code, and in three days had it running flawlessly on all three supported platforms.

A year later, I am now using it to port some of the best games in the world to one of our favorite operating systems in the world: Linux. Though I work for a commercial company, the library itself remains free and a testimony to the strength of the open source concept.

Related libraries
SDL stands as one in a large toolset you have available to you. As a video API, SDL provides a simple framebuffer, suitable for custom blitting routines, or special effects. There is a whole archive of special demo effects and eye candy you can achieve using SDL, but you can also check out the GGI and PTC libraries, which are also popular among the game and demo community. As a sound API, SDL supports automatic audio conversion and transparent ESound support. There is even a complete sample mixer implementation in the examples archive, but you can also look at the ALSA and GSI libraries. For 3D rendering, Mesa is definitely the way to go. For a windowing toolkit, GTk is immensely popular. Part of the freedom in Linux is the freedom to choose, and the freedom to contribute. It is a testament to the ideal of Linux and freedom.

Contributing to SDL
SDL is available under the GNU Lesser General Public License, which means that both free software and commercial programs can use it, and changes to the source code go back to the common source to be shared by everybody. You are welcome to contribute to SDL by sending me patches for inclusion in the development version of SDL. There is a mailing list for developers, which you can subscribe to by sending the line "subscribe sdl" to majordomo@lokigames.com. The mailing list is mirrored as a newsgroup at news://news.lokigames.com/loki.open-source.sdl. Join the mailing list for hints on using SDL, up-to-date announcements of bug fixes, and new features, and previews of projects using SDL.

Future of SDL
Here's a hint of some of the exciting new directions for SDL in the coming year:

  • Joystick support. Linux has a very good joystick API built into the latest kernels. I plan to integrate that support into the SDL event model, which allows arbitrary event filtering, callbacks, and asynchronous event dispatch. Garrett Banuk has already coded the initial implementation, which will be added to the latest SDL development branch.
  • Linux framebuffer console support. The latest Linux kernels include native graphic console support in the form of the framebuffer console driver, written by Geert Uytterhoeven. SDL has an initial driver supporting this with the native console keyboard and PS/2 mouse drivers.
  • SciTech MGL support. SciTech has a very good graphics library for Win32, DOS, Linux, OS/2, and QNX. It is a commercial library, but the VESA console drivers are freely available for Linux. It would be nice to support this under SDL.
  • Mesa integration as a GLX layer. OpenGL is definitely the way to go for 3D games of the future on Linux. However, the GLX API is not as flexible as SDL in the way that it handles events. There is demand for the integration of a GLX-like extension for SDL that allows it to be used as the input interface for GL-based games.
  • Architecture redesign to allow multiple displays and multiple inputs. The current architecture compiles the SDL functions as stubs, and dynamically loads the low-level drivers from disk at run-time. The cross-platform way of doing this resulted in an awkward build process and complicated header files. One of the highest priorities for me is to redesign the build process so all drivers can be compiled into a single library, and then dynamically selected at run-time. One of the beneficial side-effects of this is the ability to have multiple displays and input methods active at the same time. Imagine a game that runs on the console and on a remote X11 display simultaneously!
  • More games! As always, improvements to SDL result in more people using the library, and more games coming out on Linux. A good introduction to the SDL API, and a list of projects using it can be found at http://www.devolution.com/~slouken/SDL/intro/toc.html.

I'm very excited to be a part of the Linux game scene today, and I look forward to continuing my job in bringing enjoyment to the Linux community, one which has treated me so well. Because, as they say, even penguins like to have fun.

In a follow-up article, coming soon, I'll give you a tutorial on how to write a game using SDL.

About the author
Sam Lantinga is the author of the Simple DirectMedia Layer library, and is currently employed as lead programmer at Loki Entertainment Software, a company dedicated to bringing best-selling games to Linux. His involvement with Linux and games began in 1995 with various DOOM! tool ports and the port of the Macintosh game Maelstrom to Linux. He is currently working on the port of Railroad Tycoon II, which uses SDL extensively and will be available soon from Loki Entertainment Software.


e-mail it!

IBM developerWorks > Linux
developerWorks
  About IBM  |  Privacy  |  Legal  |  Contact
close