Topic : A Simple Intro to SDL
Author : Barry Jacobsen
Page : 1

Writing a multi-platform game?  But that's a lot of complicated work, and I don't have time to do that.  Wrong!  Everything has changed thanks to a sweet little API called the SDL or Simple Directmedia Layer (which can be obtained at www.libsdl.org).  SDL is an easy to use library for Sound, Input, Timers, and 2D graphics (3D graphics are accomplised through the use of OpenGL).  In this quick little tutorial, I'll teach you how to make your basic SDL window that you can compile on any platform!  To make it even better, we'll add a little yellow pixel to the center of the screen, won't that be cool?  Okay, so maybe not "cool", but it's a start.  As with my previous tutorials I'll give you a big 'ol slab of code, then disect it for you.


#include "SDL.h"
#include <stdio.h>

void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel);

int main(int argc, char *argv[])
{
 SDL_Surface *screen;
 int quit = 0;
 SDL_Event event;
 int x, y;
 Uint32 yellow;

 // Initialize defaults, Video and Audio
 if((SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)==-1))
 {
  printf("Could not initialize SDL: %s.\n", SDL_GetError());
  return -1;
 }

 screen = SDL_SetVideoMode(800, 600, 24, SDL_SWSURFACE | SDL_FULLSCREEN);
 if ( screen == NULL )
 {
  fprintf(stderr, "Couldn't set 800x600x24 video mode: %s\n", SDL_GetError());
  return -2;
 }

 // Map the color yellow to this display (R=0xff, G=0xFF, B=0x00)
 yellow = SDL_MapRGB(screen->format, 0xff, 0xff, 0x00);
 
 // Make the dot at the center of the screen
 x = screen->w / 2;
 y = screen->h / 2;

 while( !quit )
 {
  // Poll for events
  while( SDL_PollEvent( &event ) )
  {
   switch( event.type )
   {
    case SDL_KEYUP:
     if(event.key.keysym.sym == SDLK_ESCAPE)
      quit = 1;
      break;
     if(event.key.keysym.sym == SDLK_F1)
      SDL_WM_ToggleFullScreen(screen); // Only on X11
      break;
    case SDL_QUIT:
     quit = 1;
     break;
    default:
     break;
   }
  }

  // Lock the screen for direct access to the pixels
  if ( SDL_MUSTLOCK(screen) )
  {
   if ( SDL_LockSurface(screen) < 0 )
   {
    fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
    return -3;
   }
  }

  // Plot the Pixel
  putpixel(screen, x, y, yellow);

  // Unlock Surface if necessary
  if ( SDL_MUSTLOCK(screen) )
  {
   SDL_UnlockSurface(screen);
  }

  // Update just the part of the display that we've changed
  SDL_UpdateRect(screen, x, y, 1, 1);
 }

 SDL_Quit();
 
 return 0;
}

void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
 int bpp = surface->format->BytesPerPixel;
 // Here p is the address to the pixel we want to set
 Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

 switch(bpp)
 {
  case 1:
   *p = pixel;
   break;
  case 2:
   *(Uint16 *)p = pixel;
   break;
  case 3:
   if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
   {
    p[0] = (pixel >> 16) & 0xff;
    p[1] = (pixel >> 8) & 0xff;
    p[2] = pixel & 0xff;
   } else {
    p[0] = pixel & 0xff;
    p[1] = (pixel >> 8) & 0xff;
    p[2] = (pixel >> 16) & 0xff;
   }
   break;
  case 4:
   *(Uint32 *)p = pixel;
   break;
 }
}




Now, if you are using Linux, you would compile that little piece of code with the command: gcc -o sdltest sdltest.c `sdl-config --cflags --libs`
*Note that the ` is not a ', but a ` (The key above Tab).  This also assumes you named the file 'sdltest.c'

Now it's time to dissect the code piece by piece.


#include "SDL.h"
#include <stdio.h>

Standard includes for an SDL Program.


void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel);
Forward declaration of the putpixel function.

int main(int argc, char *argv[]) {
I sincerely hope you know what this line does.

SDL_Surface *screen;
int quit = 0;
SDL_Event event;
int x, y;
Uint32 yellow;

These are the only variables used in the program.  screen is a pointer to the screen so we can draw on it.  quit is a flag so we know when the user wants to exit.  event is used to process events like key presses.  x, y, and yellow are used to draw our pixel.

if((SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)==-1))
{
 printf("Could not initialize SDL: %s.\n", SDL_GetError());
 return -1;
}

This is how you initialize SDL to use Video and Audio (Even though we don't discuss audio in this tutorial).

screen = SDL_SetVideoMode(800, 600, 24, SDL_SWSURFACE | SDL_FULLSCREEN);
if ( screen == NULL )
{
 fprintf(stderr, "Couldn't set 800x600x24 video mode: %s\n", SDL_GetError());
 return -2;
}

Here we tell SDL that we want a Fullscreen window that is 800 by 600 pixels and had 24 bits per pixel.

yellow = SDL_MapRGB(screen->format, 0xff, 0xff, 0x00);
This line stores the color for yellow in our variable.  Yellow is full red and full green.
 
x = screen->w / 2;
y = screen->h / 2;

Puts a dot in the middle of the screen.

while( !quit )
This is the main loop of the program.

while( SDL_PollEvent( &event ) )
This line will get any events that have occured, like key presses or the user closing the application through some other means.

switch( event.type )
Here we start out event handling.

case SDL_KEYUP:
 if(event.key.keysym.sym == SDLK_ESCAPE)
  quit = 1;
  break;
 if(event.key.keysym.sym == SDLK_F1)
  SDL_WM_ToggleFullScreen(screen); // Only on X11
  break;

If the user pressed and release a key, this part of the code will execute.  If the key pressed was Escape, we exit the app.  If the key pressed was F1 then we switch from Fullscreen to Windowed mode(Currently this only works on X11(Linux/Unix) systems, but support for this to work on Windows will be added in future versions of the SDL).

case SDL_QUIT:
 quit = 1;
 break;

If the user closed the window through some other means, i.e. clicked the X in the corner of the window.

if ( SDL_MUSTLOCK(screen) )
{
 if ( SDL_LockSurface(screen) < 0 )
 {
  fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
  return -3;
 }
}

Some Operating Systems and video cards require that you "Lock" the video surface before you draw on it.  This code will Lock the surface if necessary and report an error if something goes wrong.

putpixel(screen, x, y, yellow);
The code to actually draw the pixel.

if ( SDL_MUSTLOCK(screen) )
{
 SDL_UnlockSurface(screen);
}

Unlock the surface, if necessary.

SDL_UpdateRect(screen, x, y, 1, 1);
Since we've made changes to the video in memory, we need to tell the SDL to update the screen, this is how we do so.

SDL_Quit();
This tells SDL that we're done and to start cleaning up. 

return 0;
I pray you know what that line does.  I really do...


void putpixel(SDL_Surface *surface, int x, int y, Uint32 pixel)
{
 int bpp = surface->format->BytesPerPixel;
 // Here p is the address to the pixel we want to set
 Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;

 switch(bpp)
 {
  case 1:
   *p = pixel;
   break;
  case 2:
   *(Uint16 *)p = pixel;
   break;
  case 3:
   if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
   {
    p[0] = (pixel >> 16) & 0xff;
    p[1] = (pixel >> 8) & 0xff;
    p[2] = pixel & 0xff;
   } else {
    p[0] = pixel & 0xff;
    p[1] = (pixel >> 8) & 0xff;
    p[2] = (pixel >> 16) & 0xff;
   }
   break;
  case 4:
   *(Uint32 *)p = pixel;
   break;
 }
}



This function is a general Draw Pixel function for the SDL.  Hopefully most of it makes sense at least to some extent.  If not you can e-mail me (BarryJ@cpp-home.com) and ask for a better explaination.  For right now, it's probably just best to say "Use it".  This putpixel function was taken right out of the SDL Doc Project.

Hopefully that explained everything well enough, if not send me an e-mail and complain.  BarryJ@cpp-home.com

This tutorial is Copyright 2001 to Barry Jacobsen.  All Rights Reserved.  Written for www.Cpp-Home.com.  Steal = Bad.  Ask for permission.


Page : 1