Sign in to follow this  

Handling images with SDL

This topic is 4560 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Im trying to write myself a sdl class which I can reuse in every sdl project I make... or this class is only going to be about graphics. The thing is I want to be able to dynamically load images (cause I want to reuse it, I dont know how many images its going to be). So first I tried with a vector <SDL_Surface> images; and used push_back() to load the new ones. It works but then I need to keep track of all the numbers. I want to be able to handle the images by names. So I think something like this:
stuct image {
    SDL_Surface *imageFile;
    string name;
};
But then I couldnt come up with a way to get the picture I wanted whitout some sort of search algoritm. I dont like that solution, waste of computer power. Anyone understanding what I want to do? If it isnt obvious, Im a beginner :P Is this the wrong way of thinking? Is there a correct way to do it?

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
what i did a couple years back for SDL image management is create a manager class. im assuming you are doing this so you dont load the image more then once? ( a waste of space ) or just a way to retrieve it after loading? either way.

you could create a class, say, TextureManager, that had stuff like this

TEXTURE_ID loadTexture( char* filename );

SDL_Surface* getTexture( TEXTURE_ID texture );

or something like that. the texture id is basically a integer typedef. when you load the texture, search through the std::map(filename, textureid) for that filename, and if it is already loaded, then return the texture id. if it isnt loaded, load it, finding the next free texture id (still basically an integer, and can be done by keeping track of the number of textures loaded) and adding that key and pair ot the map. then add the texture id as the key for another map, this time the data being a pointer to the loaded sdl_surface, this way, you have multiple ways of identifying a texture. so if you needed to create an enemy with a specific surface, you could do something like this

SDLSurface* surf = manager->getTexture( manager->loadTexture( "enemy.bmp" ) );

this way it will load the texture if it isnt already loaded, and then give you a pointer to it, you can of course get rid of the texture id all together, but for some reason when i did it i thought it would be a good idea. i guess because its harder to compare pointers then it is integers.

i know i had a real good texture manager for SDL, but im not at my personal work station to reference it, it was something along these lines though. you could even template this class to make it a sprite/texture/animation/sound manager ( ResourceManager textureManager; ResourceManager soundEffectManager; )


Share this post


Link to post
Share on other sites
Here's how I would do it: keep your std::vector list of the surfaces, but then use variables to determine which one it is. Here's an example:

int LoadBitmap (string path); // loads a bitmap and RETURNS THE INDEX NUMBER TO THE SURFACE IN THE LIST
void DrawBitmap (int bitmap_index); // draws a bitmap according to an index
//...
void DrawMenu (void)
{
int titlepic = 0, logopic = 0;

titlepic = LoadBitmap("title.bmp");
logopic = LoadBitmap("logo.bmp");

DrawBitmap(logopic);

// do rest of stuff here...
}



That should work, use it for sounds, too.

Share this post


Link to post
Share on other sites
Oberon_Command, I did something like that but what to do when the variables go out of focus? I could do that with the player image in the main loop.

Heres an example, on level one ive got some textures and on the next level I got a different set. I delete the old ones and load the new. But now I need a number to know where in the vectore theyre stored. I load images like this:


int Sdl_handle::LoadBmp(string filename) {
SDL_Surface *temp = SDL_LoadBMP(filename.c_str());
image.push_back(temp);

int id = image.size(); // the new one is the last one, so the size
// its the same as the id
return id;
}


Now I need somewhere to store the id numbers so all functions in the class knows which element is which image. Which kinda brings me back to square one?

Share this post


Link to post
Share on other sites
Quote:
Original post by Dave Hunt
Try using a hashmap with the name as the "index".


That's what I do [grin] I had some texture loading code on my other computer, but I think I accidently deleted it and my project I was working on [sad] Anyways I am trying to recover it from the drive. Here's a little sample of what you want to do:


#include <map>
#include <string>

class TextureManager
{
private:
std::map<std::string, SDL_Surface*> textures;
public:
// At the end release any textures left
~TextureManager()
{
for( std::map<std::string, SDL_Surface*>::iterator itr = textures.begin(); itr != textures.end(); itr++ )
{
SDL_FreeSurface( itr->second );
}
}

// This version is for if you happen to use custom resources and have constructed a SDL_Surface in memory
bool Add( const std::string &refname, SDL_Surface* image )
{
// See if it exists
if( textures.find(refname) != textures.end())
return false;

// Add in the texture
textures.insert( std::pair<std::string, SDL_Surface*>(refname,image) );

// Lazy old way
// textures[refname] = image;

// Success
return true;
}

bool Add( const std::string &refname, const std::string &imagename )
{
// See if it exists
if( textures.find(refname) != textures.end())
return false;

// Add in the texture, assumes BMP
// You will want to use:
// IMG_Load( imagename.c_str() ) isntead [wink]
textures.insert( std::pair<std::string, SDL_Surface*>( refname, SDL_LoadBMP( imagename.c_str() ) ) );

// Lazy old way
// textures[refname] = image;

// Success
return true;
}

bool Remove( const std::string &refname )
{
// find the texture
std::map<std::string, SDL_Surface*>::iterator itr = textures.find(refname);

// Texture was not found
if( itr == textures.end())
return false;

// Free the memory
SDL_FreeSurface( itr->second );

// Remove it from the map
textures.erase(itr);

// Success
return true;
}

SDL_Surface* Get( const std::string &refname )
{
// find the texture
std::map<std::string, SDL_Surface*>::iterator itr = textures.find(refname);

// Texture was not found
if( itr == textures.end())
return 0;

// Return the texture
return itr->second;
}
};





Well that can be improved a lot, but that's just a sample of what you can do. By using a hash map rather than a map, like I did, you will get better performance when you have a lot of textures stored. Taking it a few steps further, you could even add in a 'cache' system where you track the number a texture is used, so you can make an optimized map that you can access from to improve performance even more if you needed it.

Share this post


Link to post
Share on other sites
Drew, that was a little bit above my level :P Is that the only good way of doing what I want? I tried to google some for it but all I found out is that its like another form of vector. Could really get that much out of it.

[edit] Im thinking of doind some kind of that function myself. Or, I make that struct I talked about earlier, with one SDL surface and one string with the name. And then a vector with that struct. I then loop through it until I find the name I want and then take the image that is in the same element. But then I would loop through the entire vector each and every time I am to draw something. Quite hard on the computer... or is it so little so Im not going to see it? Maybe if I make some variables so it only searches for each unique texture once... hmm... hard this is

Share this post


Link to post
Share on other sites
Quote:
Original post by Mizipzor
Drew, that was a little bit above my level :P Is that the only good way of doing what I want? I tried to google some for it but all I found out is that its like another form of vector. Could really get that much out of it.


Well then I must say you will need to bite the bullet and take a look at the standard C++ library [smile] I know at first it looks daunting, I know because I was in the same position a few months ago, but take a look at this tutorial, one that I used, and it makes everything a lot more clear. The std::map is definitly what you want to use though, otherwise you will always end up at square one with vectors and indices.

That first example is a complete example with error checking and all, that's why it looks like 'a lot'. Here it is in the most basic format:


#include <map>
#include <string>

class TextureManager
{
private:
std::map<std::string, SDL_Surface*> textures;
public:
// At the end release any textures left
~TextureManager()
{
// Iteratre though the entire map and free the surfaces
for( std::map<std::string, SDL_Surface*>::iterator itr = textures.begin(); itr != textures.end(); itr++ )
{
SDL_FreeSurface( itr->second );
}
}

void Add( const std::string &refname, const std::string &imagename )
{
// Lazy old way
textures[refname] = IMG_Load( imagename.c_str() );
}

SDL_Surface* Get( const std::string &refname )
{
// Return the texture
return textures.find(refname)->second;
}
};




That's the simple compact version without error checking or additional features. Using it is quite simple:

// Global
TextureManager texMgr;
...
// Init code
texMgr.Add("Player1","data/models/p1.bmp");
texMgr.Add("Enemy1","data/models/e1.bmp");
texMgr.Add("Enemy2","data/models/e2.bmp");
...
// Draw code
DrawIMG( texMgr.Get("Player1"), PlayerX, PlayerY );




Now ideally you will not be calling texMgr.Get every frame. Instead you will want to have a design such as this:

// Object is a base clase for all objects
class Object
{
SDL_Surface* image;
public:
void Create( const std::string &imageName)
{
// See how it's used now?
image = texMgr.Get(imageName);
}
void Draw()
{
// Fake draw code, add in real code
SDL_Blit( image, screen, 0, 0 );
}
};




Just some more ideas. If you don't want to use the std::map, you don't have to [wink] Just know that if you do use something else, you will not be able to atain that ease on the computer you are talking about. Good luck!

Share this post


Link to post
Share on other sites

This topic is 4560 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this