Writing an SDL Hello World
relcozelvar
IMPORTANT: see the TALK page, because we said so: http://wiki.gp2x.org/wiki/Talk:Writing_an_SDL_Hello_World
The best way to learn SDL is to take a look at the examples in the SDL documentation]. After that you can continue here (loading a BMP via one SDL function) and here (drawing that image to the screen) maybe with understanding of the data structure behind that.
Because the pixel drawing example in the SDL documentation is very sophisticated our first hello pixel is a bit more light hearted (ie: we don't care about color depth (bpp - bits per pixel).
Hello Pixel
This example shows how wonderful SDL is. With just a few lines of code we initialize a window (the screen on the GP2X) and draw a pixel to it.
#include "SDL.h" #define SCREEN_WIDTH 320 #define SCREEN_HEIGHT 240 #define SCREEN_DEPTH 8 int main(int argc, char *argv[]) { SDL_Surface *screen; Uint8 *p; int x = 10; //x coordinate of our pixel int y = 20; //y coordinate of our pixel /* Initialize SDL */ SDL_Init(SDL_INIT_VIDEO); /* Initialize the screen / window */ screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_DEPTH, SDL_SWSURFACE); /* Make p point to the place we want to draw the pixel */ p = (Uint8 *)screen->pixels + y * screen->pitch + x * screen->format->BytesPerPixel; /* Draw the pixel! */ *p=0xff; /* update the screen (aka double buffering) */ SDL_Flip(screen); while(1); }
To build it you'll need to run something similar to:
gcc sdltest.c -I /usr/include/SDL -lSDL -o sdltest
So, that's an example, but I'm sure it makes very little sense to some. Let's break it down a little.
SDL_Init(SDL_INIT_VIDEO);
This line initialises SDL so we can do things. The SDL_INIT_VIDEO flag makes SDL initialise video. In order to play audio you'd need the SDL_INIT_AUDIO flag, and to get joystick events you'd need the SDL_INIT_JOYSTICK flag.
screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_DEPTH, SDL_SWSURFACE);
Next up, we initialise the screen. The first argument is SCREEN_WIDTH, which is defined as 320, the x resolution of the GP2X's screen. The second is the height of the screen, defined as the y resolution of the GP2X's screen, 240. The third is the bit depth, which should always be 16, as this is fastest. The final flag is SDL_SWSURFACE, which should be the only flag used for surfaces with standard SDL.
p = (Uint8 *)screen->pixels + y * screen->pitch + x * screen->format->BytesPerPixel;
Some basic C here, p becomes a pointer to the value in the screen's pixel area where we want to draw our pixel. screen->pixels is the memory address of the pixels on the screen surface. Adding to that the line number we want to place our pixel in (the y co-ordinate) multiplied by the number of pixels in a line, plus the x co-ordinate multiplied by the number of bytes in a pixel, gives us a pointer to the pixel we want to turn white.
*p=0xff;
This is where the action happens. We take the pointer to our pixel and write the value 0xff to it. This is a hexadecimal value (base 16, so 0 would be 0x00, 1 would be 0x01 and 11 would be 0x0A) that signifies the decimal value 255. 255, in this case, means white. So, writing that to p means that the pixel at x,y will become white. Simple, eh?
SDL_Flip(screen); while(1);
And finally we show off our hard work. SDL_Flip(screen) takes the screen and dumps it in the framebuffer, making the GP2X screen show what's on it. All the while(1) does is tell it to do nothing for as long as 1 is true, which it always is, so the program will just sit at that, showing our pixel.
Hello BMP
SDL rocks! Why? Because we can draw a BMP in no time.
#include "SDL.h" #define SCREEN_WIDTH 320 #define SCREEN_HEIGHT 240 #define SCREEN_DEPTH 8 int main(int argc, char *argv[]) { SDL_Surface *screen; SDL_Surface *bmp; SDL_Rect targetarea; /* Initialize SDL */ SDL_Init(SDL_INIT_VIDEO); /* Initialize the screen / window */ screen = SDL_SetVideoMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_DEPTH, SDL_SWSURFACE); /* Load test.bmp */ bmp = SDL_LoadBMP("test.bmp"); /* Draw the image to 10, 20 */ targetarea.x = 10; targetarea.y = 20; targetarea.w = bmp->w; targetarea.h = bmp->h; SDL_BlitSurface(bmp, NULL, screen, &targetarea); /* update the screen (aka double buffering) */ SDL_Flip(screen); while(1); }
Easy, ain't it? Note: the bmp loaded must have 8bpp (bits per pixel). Otherwise SDL will convert the image to 8bpp everytime it's blitted. This is slow.
However SDL is cool, thus after loading you can call:
SDL_Surface *old = bmp; bmp = SDL_ConvertSurface(bmp, screen->format, SDL_SWSURFACE); SDL_FreeSurface(old); //the old bpp'ed surface is no longer needed.