SDL:Tutorials:Displaying a Bitmap from a Custom Resource File using SDL RWops

From GPWiki
Jump to: navigation, search

So, your images are safe and sound in your custom resource file, (I assume you've read the tutorial on Custom Resource Files!) now what? SDL_RWops! Gesundheit! No, I didn't just sneeze; SDL_RWops is a little-known SDL structure which allows us to load images and sounds in a very flexible manner. Instead of loading images using the standard SDL_LoadBMP function, we'll be using SDL_LoadBMP_RW, which accepts an SDL_RWops structure as a parameter. Observe:

SDL_Surface *LoadBitmap(char *resourcefilename, char *bitmapfilename) 
{
	//Get the bitmap's buffer and size from the resource file
	int filesize = 0;
	char *buffer = GetBufferFromResource(resourcefilename, bitmapfilename, &filesize);
 
	//Load the buffer into a surface using RWops
	SDL_RWops *rw = SDL_RWFromMem(buffer, filesize);
	SDL_Surface *temp = SDL_LoadBMP_RW(rw, 1);
 
	//Release the bitmap buffer memory
	free(buffer);
 
	//Were we able to load the bitmap?
	if (temp == NULL) 
	{
		printf("Unable to load bitmap: %s\n", SDL_GetError());
		exit(1);
	}
 
	//Convert the image to optimal display format
	SDL_Surface *image;
	image = SDL_DisplayFormat(temp);
 
	//Free the temporary surface
	SDL_FreeSurface(temp);
 
	//Return our loaded image
	return image;
}

This LoadBitmap routine uses SDL_RWops to load a bitmap from memory. The GetBufferFromResource function does some magic (explained below) and extracts a given bitmap from the specified custom resource file. The buffer returned by GetBufferFromResource is passed to SDL_RWFromMem which creates for us our very own SDL_RWops structure! This SDL_RWops structure is then passed to SDL_LoadBMP_RW along with a value of 1 as the second parameter. (Passing 1 means that we'd like SDL to automatically release the resource after it has been read. Better safe than sorry!) SDL_LoadBMP_RW spits out an SDL_Surface structure, and things then progress as normal (see the basic SDL bitmap display tutorial for info on how to display the image stored within an SDL_Surface structure).

So, what voodoo is performed by GetBufferFromResource?

char *GetBufferFromResource(char *resourcefilename, char *resourcename, int *filesize) 
{
	//Try to open the resource file in question
	int fd = open(resourcefilename, O_RDONLY);
	if (fd < 0) 
	{
		perror("Error opening resource file");
		exit(1);
	}
 
	//Make sure we're at the beginning of the file
	lseek(fd, 0, SEEK_SET);
 
	//Read the first INT, which will tell us how many files are in this resource
	int numfiles;
	read(fd, &numfiles, sizeof(int));
 
	//Get the pointers to the stored files
	int *filestart = (int *) malloc(sizeof(int) * numfiles);	// this is probably wrong in the zip
	read(fd, filestart, sizeof(int) * numfiles);
 
	//Loop through the files, looking for the file in question
	int filenamesize;
	char *buffer;
	int i;
	for(i=0;i<numfiles;i++) 
	{
		char *filename;
		//Seek to the location
		lseek(fd, filestart[i], SEEK_SET);
		//Get the filesize value
		read(fd, filesize, sizeof(int));
		//Get the size of the filename string
		read(fd, &filenamesize, sizeof(int));
		//Size the buffer and read the filename
		filename = (char *) malloc(filenamesize + 1);
		read(fd, filename, filenamesize);
		//Remember to terminate the string properly!
		filename[filenamesize] = '\0';
		//Compare to the string we're looking for
		if (strcmp(filename, resourcename) == 0) 
		{
			//Get the contents of the file
			buffer = (char *) malloc(*filesize);
			read(fd, buffer, *filesize);
			free(filename);
			break;
		}
		//Free the filename buffer
		free(filename);
	}
 
	//Release memory
	free(filestart);
 
	//Close the resource file!
	close(fd);
 
	//Did we find the file within the resource that we were looking for?
	if (buffer == NULL) 
	{
		printf("Unable to find '%s' in the resource file!\n", resourcename);
		exit(1);
	}
 
	//Return the buffer
	return buffer;
}

Phew! That's a whole lot of voodoo! But most of it should be familiar to you if you've read the Custom Resource Files tutorial. Basically, GetBufferFromResource loops through the various entries in our custom resource file, reading the filename strings to find one that matches the char *resourcename parameter. If it finds the file it's looking for, it loads the file data into a buffer of type char and returns it. GetBufferFromResource also modifies the data pointed to by filesize, as the size of the buffer must be known when using the SDL_RWFromMem function!

These two routines are all you need to extract a bitmap from a custom resource file (assuming you've formatted your resource file as we did in the Custom Resource Files tutorial) and load it into an SDL_Surface.

Source Code

  • Click here to download the full source code, which loads an image from a custom resource file and displays it to screen. The source code also plays a WAV sound file using SDL_mixer, so be sure to compile with an -lSDL_mixer link!