Tag Archive: SDL


In the world of gaming, SDL provides the entire necessary infrastructure. This would have become clear from the past parts of the series. But infrastructure is to a game what skeleton is to a human body. But without muscles, no locomotion is possible. So working with the analogy of body, SDL provides the skeletal structure to build up the game whereas the flesh, blood and skin are provided by 2D and 3D graphics libraries. In the current plethora of 3D libraries, OpenGL stands out on various accounts. The most significant of them is its compatibility with almost all the platforms and graphics cards. This even reflects in the architecture of SDL as SDL can create and use OpenGL contexts on several platforms. Such architecture helps the game programmer to use all the sub-systems of SDL seamlessly in conjunction with OpenGL to provide most effective games and gaming environments. In this article I will discuss how to use SDL and OpenGL together where gaming infrastructure is provided by SDL and animation as well as rendering is being handled by OpenGL. The first section would discuss the steps required to integrate OpenGL with SDL. The second section would utilize the pointers provided in the first section to create an application having animation(basic) using OpenGL. That is the agenda for the current discussion.

Initialization- Bringing OpenGL into Picture:

 

In SDL all the sub-systems are initialized via SDL_Init(). OpenGL, being a part of graphics subsystem, is not directly initialized in this manner. For initializing OpenGL following are the steps:

1. Set OpenGL Attributes

2. Specify use of Double Buffering

3. Set the Video Mode

Of these second one is optional as it is used only when double buffering is a requirement. Lets have a detailed look at all of them.

1. Setting the OpenGL Attributes:

Before initializing the video, it is better to set up the OpenGL. These attributes are passed to the OpenGL via SDL calling the SDL_GL_SetAttribute() function. The parameters are the OpenGL attribute and their values. The most common attributes passed to this function are:

i. SDL_GL_RED_SIZE:

It sets the size of the red component of the frame buffer. The value is in bits. The commonly used value is 5. Similar parameters exist for blue and green components which are SDL_GL_BLUE_SIZE and SDL_GL_GREEN_SIZE respectively. To set green component to a bit value of 4 the code would be:

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 4 );

ii. SDL_GL_BUFFER_SIZE:

To set the size of the frame buffer this attribute is passed with the required Buffer size in bits. It is greater than or equal to the combined value i.e. sum of the red, green, blue and alpha components. If the requirement is 24 bit color depth and alpha channel of 32-bits then each color component must be given the size value as 8 and frame buffer must be given size as 32. In code it would be:

SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );

SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );

iii. SDL_GL_DEPTH_SIZE:

This attribute controls the size of depth buffer or Z buffers. Normally the graphics cards provide 16-bit or 24-bit depth. If the value is set more than what is available, the operation will fail. To make it more clear following is the code:

SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,16);

iv. SDL_GL_ACCUM_RED_SIZE:

To set the size of red component of accumulation buffer, this attribute is used.

The value is specified in bits. SDL_GL_ACCUM_BLUE_SIZE, SDL_GL_ACCUM_GREEN_SIZE controls the size of blue and green component of accumulation buffer. In code it would be:

SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE,5);

The question that would be arising in your mind would be that whether these attributes could be set after initializing the video mode. The answer is no. The reason is that these settings have to be initialized before invoking and configuring video mode. Next we have to setup the video mode.

2. Setting up double buffering:

This aspect has also to be covered before setting up the video mode as this     attribute goes as a flag parameter to the SDL_GL_SetAttribute. The attribute is     SDL_GL_DOUBLEBUFFER and the value is either 1 or 0. The point to be kept in     mind is that when working in conjunction with OpenGL, the flag specifying double     buffer must be passed as an attribute to the SDL_GL_SetAttribute function and not to the SDL_Set_VideoMode(). In code this would be:

SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);

would set the double buffering to one state.

3. Setting the Video Mode:

Once the OpenGL attributes are set, setting the video mode is similar to the     setting of video mode as described in last tutorials. For more details have a look     at Part-II of the tutorial. The only difference comes in flags being sent to the     SDL_Set_VideoMode(). Apart from other required flags the SDL_OPENGL would     also be set i.e.

int flags=0;

flags= SDL_OPENGL | SDL_FULLSCREEN;

setting the SDL_OPENGL flag is a must.

That’s all there about the required steps. Now let the OpenGL play.

OpenGL in Action:

The theory is over. Its now time to see some real action. The example application would render a rotating triangle. The includes will contain one more header file.

#include <SDL/SDL.h>

#include <gl/gl.h>

 

gl.h contains function declarations necessary to work with OpenGL.

Next comes the main() and OpenGL attributes.

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

{

  SDL_Event event;

  float theta = 0.0f;

  SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );

  SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );

  SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );       

  SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );

 

:

:

}

Next initialize the video and video mode

 

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

{

SDL_Event event;

float theta = 0.0f;

SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );

SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );

SDL_Init(SDL_INIT_VIDEO);

  SDL_SetVideoMode(600, 300, 0, SDL_OPENGL | SDL_HWSURFACE | 

                               SDL_NOFRAME);

:

:

}

 

The video is initialized to 600×300 resolutions. And the hardware rendering mode is being used. This is done by SDL_HWSURFACE flag. Hence OpenGL would write on the graphic card’s memory instead of mapping it to software memory. After this step, the territory of OpenGL starts.

 

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

{

SDL_Event event;

float theta = 0.0f;

SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );

SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );

SDL_Init(SDL_INIT_VIDEO);

SDL_SetVideoMode(600, 300, 0, SDL_OPENGL | SDL_HWSURFACE |

SDL_NOFRAME);

glViewport(0, 0, 600, 300);

  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

  glClearDepth(1.0);

  glDepthFunc(GL_LESS);

  glEnable(GL_DEPTH_TEST);

  glShadeModel(GL_SMOOTH);

  glMatrixMode(GL_PROJECTION);

  glMatrixMode(GL_MODELVIEW);

:

:

}

to start working with OpenGL, the view port is initialized. Then the screen is cleared or rendered with the specified background color. Since the triangle would be rotating in 3D space hence the depth has to be set and depth testing has to be enabled. If smooth shading is not used, then the edges would seem jagged. Hence smooth shading model is used. This completes the setting up of OpenGL parameters after SDL video initialization. Drawing and rotation is taken care by the following code in bold:

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

{

SDL_Event event;

float theta = 0.0f;

SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );

SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );

SDL_Init(SDL_INIT_VIDEO);

SDL_SetVideoMode(600, 300, 0, SDL_OPENGL | SDL_HWSURFACE |

SDL_NOFRAME);

glViewport(0, 0, 600, 300);

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

glClearDepth(1.0);

glDepthFunc(GL_LESS);

glEnable(GL_DEPTH_TEST);

glShadeModel(GL_SMOOTH);

glMatrixMode(GL_PROJECTION);

glMatrixMode(GL_MODELVIEW);

int done;

  for(done = 0; !done;)

 {

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

 

    glLoadIdentity();

    glTranslatef(0.0f,0.0f,0.0f);

    glRotatef(theta, 0.0f, 0.0f, 1.0f);

   :

:

}

}

The focus is brought to the point of origin by translating it. Then rotation function is provided the theta value through which the triangle has to be rotated.

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

{

SDL_Event event;

float theta = 0.0f;

SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );

SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );

SDL_Init(SDL_INIT_VIDEO);

SDL_SetVideoMode(600, 300, 0, SDL_OPENGL | SDL_HWSURFACE |

SDL_NOFRAME);

glViewport(0, 0, 600, 300);

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

glClearDepth(1.0);

glDepthFunc(GL_LESS);

glEnable(GL_DEPTH_TEST);

glShadeModel(GL_SMOOTH);

glMatrixMode(GL_PROJECTION);

glMatrixMode(GL_MODELVIEW);

int done;

for(done = 0; !done;)

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

glTranslatef(0.0f,0.0f,0.0f);

glRotatef(theta, 0.0f, 0.0f, 1.0f);

glBegin(GL_TRIANGLES);

    glColor3f(1.0f, 0.0f, 0.0f);

    glVertex2f(0.0f, 1.0f);

    glColor3f(0.0f, 1.0f, 0.0f);

    glVertex2f(0.87f, -0.5f);

    glColor3f(0.0f, 0.0f, 1.0f);

    glVertex2f(-0.87f, -0.5f);

    glEnd();

 

    theta += .5f;

    SDL_GL_SwapBuffers();

   :

:

}

}

The triangle is drawn by specifying the vertices. Then the theta value is increased. Next event handling part cometh.

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

{

SDL_Event event;

float theta = 0.0f;

SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );

SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );

SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );

SDL_Init(SDL_INIT_VIDEO);

SDL_SetVideoMode(600, 300, 0, SDL_OPENGL | SDL_HWSURFACE |

SDL_NOFRAME);

glViewport(0, 0, 600, 300);

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

glClearDepth(1.0);

glDepthFunc(GL_LESS);

glEnable(GL_DEPTH_TEST);

glShadeModel(GL_SMOOTH);

glMatrixMode(GL_PROJECTION);

glMatrixMode(GL_MODELVIEW);

int done;

for(done = 0; !done;)

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentity();

glTranslatef(0.0f,0.0f,0.0f);

glRotatef(theta, 0.0f, 0.0f, 1.0f);

 glBegin(GL_TRIANGLES);

glColor3f(1.0f, 0.0f, 0.0f);

glVertex2f(0.0f, 1.0f);

glColor3f(0.0f, 1.0f, 0.0f);

glVertex2f(0.87f, -0.5f);

glColor3f(0.0f, 0.0f, 1.0f);

glVertex2f(-0.87f, -0.5f);

glEnd();

theta += .5f;

SDL_GL_SwapBuffers();

SDL_PollEvent(&event);

    if(event.key.keysym.sym == SDLK_ESCAPE)

      done = 1;

}

}

That’s it. This is how SDL and OpenGL work together. The only piece missing in this puzzle is sound. It will be tackled in the next part which incidentally is the last part of this series. So till next time.

Graphics and handling user inputs- the combination that creates the symphony called game. A world (of game) where these two are out of phase ends in cacophony. In the last article I discussed about the various parameters that goes into creating a screen and loading bitmapped images on to the screen. That was pretty high-level as the work was done on structures that represent the actual screen and maps or sprites. But there are times when one has to get his/her hand dirty by working directly upon pixels. The creators of SDL had already anticipated this requirement and built the capacities to work at raw graphics level into the core itself. Thus developer is redeemed from understanding system, platform and architecture specific nitty-gritty about manipulating the pixels. The other aspect of gaming that gives sleepless nights to developers is handling the user input, as the handling of input devices changes from system to system. To remove this burden from the minds of the developers, SDL provides object-oriented approach in handling the events. In this article, I would be discussing these two aspects of SDL. In the first section, the discussion would focus on using pixel manipulation functions and their usages and the second section would focus on input handling. So now that the agenda for this article have been laid down lets get started.   Raw Graphics-Writing Directly onto the Display:  Though the SDL Graphics APIs provide pretty high level functionality abstracting off all the low-level details, yet, there are times when abstraction is not required. For this purpose also there are ways. These ways doesn’t exist as a library function but as separate functions that has to be embedded into your program. The functions are freely available. But for the completeness I am including them here. These functions are:

  1. getpixel():

This function is useful if pixel value have to be obtained from a given coordinates represented by X and Y values on the display. It works on a single pixel at a time. The first parameter is the surface from which the value has to be obtained. This is represented by a pointer to the SDL_Surface. The next two integer parameters represent the x and y coordinates from where the pixel value has to be obtained. The return value is an Uint32 representing the value of the pixel. Following is the code:   /*  * Return the pixel value at (x, y)  * NOTE: The surface must be locked before calling this!  */ Uint32 getpixel(SDL_Surface *surface, int x, int y) {     int bpp = surface->format->BytesPerPixel;     /* Here p is the address to the pixel we want to retrieve */     Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;       switch(bpp) {     case 1:         return *p;       case 2:         return *(Uint16 *)p;       case 3:         if(SDL_BYTEORDER == SDL_BIG_ENDIAN)             return p[0] << 16 | p[1] << 8 | p[2];         else             return p[0] | p[1] << 8 | p[2] << 16;       case 4:         return *(Uint32 *)p;       default:         return 0;       /* shouldn’t happen, but avoids warnings */     } }   The first thing to be done is to obtain the depth represented by BytesPerPixel. It is done by the first statement: int bpp = surface->format->BytesPerPixel;   Next statement is self explanatory. To get the address of the pixel, the pitch of the of the passed surface is multiplied by the value of Y- coordinate, the depth is multiplied by the X- coordinate and the resulting values are added with pixel data of the surface represented by pixels member of SDL_Surface. This calculation provides the actual address of the pixel. The SDL_Surface could be thought of as multi dimensional array. Hence the value could be accessed as row-major and column-major format. That is done in the second statement: Uint8 *p = (Uint8 *)surface->pixels + y * surface->pitch + x * bpp;  As the value returned by BytesPerPixels ranges from 1-4 according to the bytes needed to represent the pixel, it can be used for returning the values in the corresponding format i.e. 8, 16, 24 or 32. this is achieved by the switch-case block. That’s all about getpixel function.

  1. putpixel():

This is same as getpixel(). Apart from the parameters accepted by getpixel() function, this accepts one parameter extra- the address where the value has to be put. Following is the code for putpixel():   /*  * Set the pixel at (x, y) to the given value  * NOTE: The surface must be locked before calling this!  */ 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;     } }   The working of putpixel() is almost opposite to that of getpixel(). In case of later, the returned value is pixel value corresponding to the coordinates whereas the later places the pixel value according the coordinates. For this first the BytesPerPixel of the passed SDL_Suface is extracted just like before. Then pixel’s address (or pixel value) is calculated and according to the value returned by BytesPerPixels the value is placed. Since the calculated value is address of the pixel, hence the passed pixel value can be directly assigned and the display will be getting the new value.   Now that both the functions have been explained, lets see how to put one them to use i.e. putpixel(). For this I am defining a method called putyellowpixel() that places a yellow pixel at the center of the screen. It doesn’t accept any parameter nor does it returns any value.   void putyellowpixel() {     int x, y;     Uint32 yellow;       /* Map the color yellow to this display (R=0xff, G=0xFF, B=0×00)        Note:  If the display is palettized, you must set the palette first.     */     yellow = SDL_MapRGB(screen->format, 0xff, 0xff, 0×00);       x = screen->w / 2;     y = screen->h / 2;       /* 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;         }     }       putpixel(screen, x, y, yellow);       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);       return;   }   To get the yellow color, the SDL_MapRGB() has to be used. The SDL_PixelFormat is the first parameter. It stores surface format information. Next three parameters correspond to the red, blue and green components of the color. The return value is the actual color corresponding to the passed color components in hexadecimal format as follows: yellow = SDL_MapRGB(screen->format, 0xff, 0xff, 0×00);   Once the color has been retrieved, the next step is to get the required x and y coordinates which is achieved by the following statement: x = screen->w / 2; y = screen->h / 2; then screen surface is locked. If this is not done, then corruption of the SDL_Surface structure could get corrupted causing instability of the game as putpixel works on the address of pixel directly. This is done by:   SDL_MUSTLOCK(screen);   The next step is to call the putpixel. Once putpixel has returned, then unlock the surface and update the surface. That completes placing a pixel directly on to the surface. Next section would focus on even handling with reference to keyboard.   Handling the Key Board- the SDL way:Whatever has been discussed till now completes only one aspect of providing interactivity. Even now the application doesn’t have the ability to handle user gestures provided through different input devices such as keyboard, joy stick etc. So now the focus would be on the input handling. Two of the most common input devices are mouse and keyboard. SDL has wrappers for each of these. In this section I would be discussing about keyboard handling. Before entering the world of keyboard events, it is better to understand the most recurring structures in keyboard handling jargon. They are:

  1. SDLKey:

It is an enumerated type that represents various keys. For example SDLK_a represents lowercase ‘a’, SDLK_DELETE is for ‘delete’ key and so on.

  1. SDLMod:

SDLKey enumeration represents only keys. To represent key modifiers such as Shift and Ctrl, SDLMod enumeration is provided by the SDL. The KMOD_CAPS is one of the enumeration that can be used to find out whether caps key is down or not. Other modifiers also have representations in SDLMod.

  1. SDL_keysym:

It is a structure that contains the information of a key-press. The members of this structure include scan code in hardware dependent format, SDLKey value of the pressed key in sym field, the value of modifier key in mod field and the Unicode representation of the key in Unicode field.

  1. SDL_KeyboardEvent:

From the name itself it is obvious that this structure describes a keyboard event. The first member, type, tells that the event is key release or key press event. The second member gives the same info as the first but uses different values. The last member is a structure itself- the SDL_keysym structure.   Now that the structures have been brought into the picture, the next step is to use these in handling the keyboard events. For this the logic is simple. The SDL_PollEvent is used to read the events. This is placed within the while loop. Then the value of type member of SDL_Event variable, passed as the parameter to SDL_PollEvent, is checked to find the type of event and then event processing can be done. In code it is thus:   SDL_Event event;   .   .   /* Poll for events. SDL_PollEvent() returns 0 when there are no  */   /* more events on the event queue, our while loop will exit when */   /* that occurs.                                                  */   while( SDL_PollEvent( &event ) ){     /* We are only worried about SDL_KEYDOWN and SDL_KEYUP events */     switch( event.type ){       case SDL_KEYDOWN:         printf( “Key press detected\n” );         break;         case SDL_KEYUP:         printf( “Key release detected\n” );         break;         default:         break;     }   }   .   .   If this is used this in the program developed in last article, the exit condition of the program can be controlled. The new version would exit only at key press.     void display_bmp(char *file_name) { SDL_Surface *image;   /* Load the BMP file into a surface */ image = SDL_LoadBMP(file_name); if (image == NULL) { fprintf(stderr, “Couldn’t load %s: %s\n”, file_name, SDL_GetError()); return; }   /* * Palettized screen modes will have a default palette (a standard * 8*8*4 colour cube), but if the image is palettized as well we can * use that palette for a nicer colour matching */ if (image->format->palette && screen->format->palette) { SDL_SetColors(screen, image->format->palette->colors, 0, image->format->palette->ncolors); }   /* Blit onto the screen surface */ if(SDL_BlitSurface(image, NULL, screen, NULL) < 0) fprintf(stderr, “BlitSurface error: %s\n”, SDL_GetError());   SDL_UpdateRect(screen, 0, 0, image->w, image->h);   /* Free the allocated BMP surface */ SDL_FreeSurface(image); }   int main(int argc,char* argv[]) { /*variable to hold the file name of the image to be loaded *In real world error  handling  code would precede this                                                                          */ char* filename=”Tux.bmp”; /*The following code does the initialization for Audio and Video*/ int i_error=SDL_Init(SDL_INIT_VIDEO); /*If initialization is unsuccessful, then quit */ if(i_error==-1) exit(1); atexit(SDL_Quit); /* * Initialize the display in a 640×480 8-bit palettized mode, * requesting a software surface */ screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE); if ( screen == NULL ) { fprintf(stderr, “Couldn’t set 640x480x8 video mode: %s\n”, SDL_GetError()); exit(1); }   /*Handle the keyboards events here. Catch the SDL_Quit event to exit*/ done = 0;              while (!done)             {                SDL_Event event;                 /* Check for events */         while (SDL_PollEvent (&event))              {             switch (event.type)             {                           case SDL_KEYDOWN:                 break;                           case SDL_QUIT:                             done = 1;                            break;             default:                           break;             }         } /* Now call the function to load the image and copy it to the screen surface*/ load_bmp(filename); }   If you run the above code the window wont be closed until the close button is pressed. Though, this code does nothing much in area of interactivity but it’s a beginning. So as you can see, it is really easy to handle keyboard events using SDL. It totally removes the dependence of developer on Operating System for event handling. Also working at raw graphics level is not that difficult.   This brings us to the end of the third part of SDL programming. The next part would cover using OpenGL with SDL. Also using timers would be covered. Till next time.

Graphics manipulation is the core of any game programming library. Without graphics manipulation, games can never realize the actual potential of interactivity and environmental feedback- the two facets of any game that makes it engrossing. SDL provides for this through its graphics sub-system. In this part, I will be discussing about the graphics subsystem and the various functionalities provided by it. Though the routines to work with graphics are present in the corresponding sub-system yet, the graphics sub-subsystem itself is a part of the video subsystem. Hence all the graphics related routines are present in the Video sub-system. The first section would cover the basics covered with initializing the video for best resolution. The second section would detail about loading a bitmap onto the screen. That’s the agenda for the second part of SDL Programming in Linux.

Working with Video- the SDL way:

When working with gaming libraries, one has to drop into system specific APIs(Win SDK on Windows and Xlib and et al on *nix) to access the video related functionalities. These functionalities include initializing the video, setting the best video mode and loading the bitmapped images among other things. But SDL encapsulates all these within the Video sub-system. The functions that provides access to these are:

  1. SDL_Init():

This function had been discussed in the first part. This function initializes the sub-system that has been passed as parameter. To initialize video the parameter would be SDL_INIT_VIDEO. To elucidate:

SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO)

would initialize video as well as audio.

  1. SDL_SetVideoMode():

Once the video is initialized, the next obvious step is setting the best video mode. To achieve this end, SDL contains a method SDL_SetVideoMode. This method sets up a video mode with specified width, height and bits per pixel i.e. depth. In short using this function one could set up the required resolution. The parameters are:

  1. width
  2. height
  3. bpp(bits-per-pixel)
  4. flags

The first three parameters take integer values. They represent height, width and depth of the screen respectively. The fourth parameters need some considerations. The flags parameter defines the properties of the surface of the screen. They are eleven in number. The important and most commonly used are:

  1. SDL_SWSURFACE:

This instructs SDL to create the surface in the system memory. In other words, the rendering area is created using software renderer. This is useful in case support for software based acceleration is on cards.

  1. SDL_HWSURFACE:

To create surface in hardware memory i.e. memory of the graphics card, use this value as the flag value. This means to support hardware acceleration use this value. It can be or’d with SDL_SWSURFACE to support both.

  1. SDL_ANYFORMAT:

When the passed depth value is unsupported on the target machine, then SDL emulates it with a shadow surface i.e. to emulate required depth, SDL would use shadows. To prevent this pass SDL_ANYFORMAT as the flag value. By using SDL_ANYFORMAT SDL can be instructed to use the video surface even if the required depth is not available.

  1. SDL_DOUBLEBUF:

It enables hardware double buffering. The double buffering works only if called with SDL_HWSURFACE. Otherwise when flipping function is called only updation of the surface takes place.

  1. SDL_OPENGL:

It creates an OpenGL rendering context. This is useful when SDL is used in conjunction with OpenGL.

  1. SDL_FULLSCREEN:

By passing it as the flag value, the mode could be change to full screen. If SDL is unable to do so, then it will use the next available higher resolution. But the window will be centered on black screen.

  1. SDL_NOFRAME:

To set have the window without decoration (without title bar and frame decoration), use this as the value. Setting SDL_FULLSCREEN as the flag value, this flag is automatically set.

All the above values are same as that of SDL_Surface. The SDL_SetVideoMode() function returns a pointer to the structure SDL_Surface. Now lets see how to use it in a program.

#include “SDL.h”

#include<stdio.h>

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

{

SDL_Surface *screen;

/*The following code does the initialization for Audio and Video*/

int i_error=SDL_Init(SDL_INIT_VIDEO);

/*If initialization is unsuccessful, then quit */

if(i_error==-1)

exit(1);

atexit(SDL_Quit);

/*

* Initialize the display in a 640×480 8-bit palettized mode,

* requesting a software surface

*/

screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE);

if ( screen == NULL )

{

fprintf(stderr, “Couldn’t set 640x480x8 video mode: %s\n”,

SDL_GetError());

exit(1);

}

}

If you recall, most of the above code is same as the one I discussed in first part. The changes are set in bold. First a point to the structure SDL_Surface is declared. When the video mode is set, this comes into picture. Then the video is initialized using SDL_Init(). This part is not much different. If initialization fails, then exit the application.

As I said before, the function to set video mode returns a pointer to the initialized SDL_Surface structure. The above code sets the resolution at 640×480 at 8 bit depth. It also sets the rendering to software based i.e. the surface is created in system memory and not in graphics card’s memory. Now that video mode has been set we can move to the next section. That is loading a bitmap on to the returned surface.

Loading Bitmap – the SDL way:

To load a bitmap onto the surface following functions come handy:

  1. SDL_LoadBMP:

This function forms the basis of loading a bitmap. It returns a pointer to surface for name of the bitmap given as the parameter. If the loading of bitmap has not been successful, null is returned. For example, if the file parameter is “Tux.bmp”, then following code will load it:

SDL_Surface *image=SDL_LoadBMP(“Tux.bmp”);

  1. SDL_SetColors:

The default palette would be an 8x8x4 color cube. To get a better color matching it is required to palletize the image itself. For this SDL_Setcolors function is quite useful. The first parameters is the surface for  which the palette has to be created, second parameter is the SDL color component which decides the number of the displayable colors. Third and fourth parameters sets the range of colors to be used. To palletize the loaded image the first parameter would be the surface returned by the SDL’s initialization routine, the second is the color component of the image to be palletized, the third would be 0 that would be lower range of the colors to be used, and the maximum value of the color palette of the image would be the fourth parameter. To put in code:

SDL_SetColors(screen, image->format->palette->colors, 0,

image->format->palette->ncolors);

where screen is the surface returned by the initialization and image is the loaded bitmap.

  1. SDL_BlitSurface:

This function performs a fast blit from source surface to the destination surface. The parameters are source surface, source rectangle, destination surface and destination rectangle. If the source and destination rectangle are specified as null then the entire surface is copied. For example the following code copies loaded image surface to the screen surface:

SDL_BlitSurface(image, NULL, screen, NULL);

  1. SDL_UpdateRect:

Once the loaded image surface is copied onto the screen surface, it must be ensured that the screen display is updated accordingly. The surface to be updated is the first parameter, the rectangle of the screen to be updated is specified is the second parameter. The following fragment updates the screen according to the height and width of the loaded image:

SDL_UpdateRect(screen, 0, 0, image->w, image->h);

  1. SDL_FreeSurface:

Once work is completed with the loaded image, then the surface has to be freed so that the memory occupied by the surface is released. To free a surface SDL library contains SDL_FreeSurface. The parameter is the surface to be freed. In code it would be:

SDL_FreeSurface(image);

Where image is the surface to be freed.

Now that the functions to be used have been introduced, lets see them in action. First define a function that loads a bitmap image passed to it as parameter.

void display_bmp(char *file_name)

{

SDL_Surface *image;

/* Load the BMP file into a surface */

image = SDL_LoadBMP(file_name);

if (image == NULL) {

fprintf(stderr, “Couldn’t load %s: %s\n”, file_name, SDL_GetError());

return;

}

/*

* Palettized screen modes will have a default palette (a standard

* 8*8*4 colour cube), but if the image is palettized as well we can

* use that palette for a nicer colour matching

*/

if (image->format->palette && screen->format->palette) {

SDL_SetColors(screen, image->format->palette->colors, 0,

image->format->palette->ncolors);

}

/* Blit onto the screen surface */

if(SDL_BlitSurface(image, NULL, screen, NULL) < 0)

fprintf(stderr, “BlitSurface error: %s\n”, SDL_GetError());

SDL_UpdateRect(screen, 0, 0, image->w, image->h);

/* Free the allocated BMP surface */

SDL_FreeSurface(image);

}

As you can observe the code is a compilation of all the functions I had discussed earlier. The only difference is the error handling code has been used. To use it first declare a global variable of the type SDL_Surface:

SDL_Surface *screen=NULL;

Then call the display_bmp() as follows:

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

{

/*variable to hold the file name of the image to be loaded

*In real world error  handling  code would precede this                                                                          */

char* filename=”Tux.bmp”;

/*The following code does the initialization for Audio and Video*/

int i_error=SDL_Init(SDL_INIT_VIDEO);

/*If initialization is unsuccessful, then quit */

if(i_error==-1)

exit(1);

atexit(SDL_Quit);

/*

* Initialize the display in a 640×480 8-bit palettized mode,

* requesting a software surface

*/

screen = SDL_SetVideoMode(640, 480, 8, SDL_SWSURFACE);

if ( screen == NULL )

{

fprintf(stderr, “Couldn’t set 640x480x8 video mode: %s\n”,

SDL_GetError());

exit(1);

}

/* Now call the function to load the image and copy it to the screen surface*/

load_bmp(filename);

}

That brings us to the end of this part of the discussion on SDL. In the next part I would discuss about working at pixel level and handling keyboard events. Till next time.

Game programming has come a long way since early Linux and Windows days. The time is gone when games were limited to Windows or to an extend Mac. Today, as Linux is gaining foothold in desktop market, the demand for Linux based games is growing. This has brought portability to the forefront even in the gaming segment. Birth of OpenGL was the first step in this regard. But OpenGL addressed only the rendering aspect of game programming. The major part that is communicating with varied input devices was left to the operating system. That is reason for the existence of various extensions to the OpenGL including GLUT(platform independent), MESA(OpenGL extension for *nix systems) and WOGL(OpenGL extension for Windows). Each of them has its own pros and cons. If a library is OS independent, then it was limited in utilization of all the available resources. If it was able to harness the power of underlying system, then such a library would be platform dependent. It was during such times of extreme choices that SDL came into picture. SDL is a library “by the game programmers for the game programmers”. Hence it doesn’t try to achieve the ‘unachievable’ by starting from the scratch. Instead it is built upon the existing libraries for each OS i.e. it uses DirectX for Windows and XWindows APIs for *nix systems. So the obvious question arises is how to harness the power of SDL on Linux? In this article, first in the series of four, I would discuss the steps to be followed in order to setup your Linux box for SDL programming and then a small application would be developed that would not only test the setup but also introduce you to the world of SDL programming. So lets get started.

What is SDL?

As already stated, SDL is library developed by the game programmers themselves. Hence the implementation is in such a way that it never gets in the way of programmers code. In nutshell 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:

  1. Initialization and Shutdown

  2. Input processing

  3. Timers

  4. Sound effects

  5. Graphics manipulation

  6. Network integration

  7. Threading requirements

All of these functionalities come into the gaming scenario now and again especially first five are the basis of any game. SDL makes dealing with each of them easier. Lets see how.

  1. 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. To perform 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(). More about it in the next section.

  1. 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 reference.

  1. Timers:

Without timers it is nearly impossible to imagine any challenging game. If one goes by standard methods, one would have to relay on the Timers provided by the platform. But with SDL, this is a thing of 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.

  1. Sound Effects:

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

  1. Graphics Manipulation:

With SDL one has option to work at raw pixel level or at 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.

  1. Networking Requirements:

Like other functionalities, networking is also important in the current genre of games. Understanding this importance, the developers of SDL provided APIs that does the ground-level works to setup the network connections and managing them, thus making networked multiplayer game less of enigma.

  1. Threading Requirements:

The pthreads library provided by POSIX is a platform independent way of working with threads. But 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 real world.

Entering the world of SDL:

Now lets get into some coding using SDL for which following are steps:

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 doesn’t return anything, then you will have to download either the binaries or the source from the following site:

http://www.libsdl.org/

If the planning is to use OpenGL then do the same for it(just check out for MESA).

2. Initialization and Shutting down:

In this article, I will deal with initialization and shutting down of a game system. Before starting lets include the required headers:

#include “SDL.h”

#include<stdio.h>

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

#include “SDL.h”

#include<stdio.h>

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

{

:

:

}

As stated earlier, 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, the atexit can be used for small programs. Otherwise before calling quits, the dynamically loaded memory have to be freed using custom cleanup code. The atexit() function is passed the SDL_Quit function.

Now its time to find out how many CDROM drives are there in the system. Following code deals with it:

#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));

}

}

The SDL_CDNumDrives() returns the no. 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 following command:

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

the `sdl-config –-libs` would include the necessary libraries. On the otherhand 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

Thus this brings us to the end of first part of this series. In this part I have just given you a taste of SDL programming and an entry point into the world of SDL. In the coming articles I will take up each subsystem and will take you deep into the world of SDL. So until next time.

Follow

Get every new post delivered to your Inbox.