Creating and Destroying Surfaces (TGO-02-C)Surfaces are the most important part of using SDL's video subsystem. Without them, there'd be nothing to see, and how good is an application you can't see? (Apologies to ZForm, LLC, whose clients can't read this article anyway--they make software for the blind). The first surface you should create in any SDL based application is the display surface. You can create it with the SDL_SetVideoMode function. SDL_Surface *SDL_SetVideoMode(int width, int height, int bpp, Uint32 flags); This function takes a width, height, bits per pixel, and flags, and spits out a pointer to an SDL_Surface. This pointer is to the display surface/primary surface. If you are doing a full-screen application, you will probably want to check out the modes with SDL_ListModes and/or SDL_VideoModeOK, but if you don't that's OK. If you aren't doing a full-screen application, then you should specify 0 for bpp, and have SDL_ANYFORMAT as part of your flags. This makes SDL use the current format of the display, which makes life easier for you. In windowed mode, you can use whatever width and height you like. In WIN32, this will give you a window that has a client area of the size you requested. After calling SDL_SetVideoMode, don't call SDL_FreeSurface on this pointer. SDL cleans up the display surface during SDL_Quit, so you don't have to worry about it. In fact, you don't even have to store this pointer anywhere if you don't want to. You can use SDL_GetVideoSurface (it takes no parameters) to retrieve a pointer to the display surface. Of course, you'll need more than simply a display surface to make your game, unless you plan on making a game with nothing but pixel plotting and filling rectangles. You'll need other surfaces as well. To create a blank surface of a particular size and format, you call SDL_CreateRGBSurface. SDL_Surface *SDL_CreateRGBSurface(Uint32 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask); To this function, you supply a size (height, width, depth--bpp), and masks for red, green, blue, and alpha, along with some flags, and this function gives you a pointer to a newly created surface that matches your specifications. Typically, you will want to use the same depth and masks as for the display surface, but even if you don't, SDL will be able to copy from one to the other, but it'll be a little slower. The only valid flags for SDL_CreateRGBSurface are SDL_HWSURFACE , SDL_SWSURFACE , SDL_SRCCOLORKEY, and SDL_SRCALPHA. If this function fails, it returns NULL. Another function for creating surfaces is SDL_CreateRGBSurfaceFrom. This function is much the same as SDL_CreateRGBSurface. SDL_Surface *SDL_CreateRGBSurfaceFrom(void *pixels, int width, int height, int depth, int pitch, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask); The notable differences are the lack of a flags parameter (the surface exists in system RAM), and the addition of the pixels parameter and the pitch parameter. The pixels parameter is a pointer to pixel data to use for this surface, and pitch is how many bytes exist in each scan line, which does not have to be width times depth. The other parameters are the same as for SDL_CreateRGBSurface. If this function fails, it returns NULL. Something to keep in mind if you are using SDL_CreateRGBSurfaceFrom: the pixels parameter should not be freed until you have freed the surface, since the pixel data you supply to this function is the actual pixel data used by the surface. It does not make a copy. The final function for creating a surface is SDL_LoadBMP. This is a damn handy function. It loads in a standard windows .bmp file onto a surface, and returns the new surface. SDL_Surface *SDL_LoadBMP(const char *file); This function takes a single parameter, a pointer to a string containing the name of the file you wish to load. It returns the newly created surface, or NULL if there is an error. The SDL_LoadBMP function is a godsend. If you've worked with either DirectDraw or GDI, you know how much of a pain it can be to get a stupid bitmap loaded. In SDL, its only a single function call! If that's not reason enough to move to SDL... I don't know what is. There are two more really cool functions that you can use to create surfaces, but they are used more for pixel format conversion rather than creating something in their own right. They take an already existing surface and create a new surface, with the same contents, but a different pixel format. The first of these is SDL_ConvertSurface. SDL_Surface *SDL_ConvertSurface(SDL_Surface *src, SDL_PixelFormat *fmt, Uint32 flags ) ; The parameters are fairly straightforward. You give this function a pointer to a surface that you need converted, a pointer to the format you want it converted to, and a combinatin of flags ( these flag are the same as those used in other surface creation functions). This function creates a surface in the requested format, with the requested flags (if possible), and gives you back a pointer to a new surface. If this function fails, it'll give you NULL. The second of these is SDL_DisplayFormat. SDL_Surface *SDL_DisplayFormat(SDL_Surface *surface); This function takes a surface, and converts it to the display format, so that you can make better use of hardware acceleration, if it exists. It returns a pointer to the newly converted surface, or NULL if it fails. Typically, after calling SDL_ConvertSurface or SDL_DisplayFormat to convert a surface, you will want to destroy the old, pre-converted, surface. Speaking of destroying surfaces, doing so is also quite easy. You simply call SDL_FreeSurface. void SDL_FreeSurface(SDL_Surface *surface); This function takes a pointer to a surface, and returns no values. The surface's refcount member is decremented, and if the refcount reaches 0, then the surface is deleted. |