A Resource Manager

Whether you're a newbie or an experienced programmer, any questions, help, or just talk of any language will be welcomed here.

Moderator: Coders of Rage

Post Reply
XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

A Resource Manager

Post by XianForce »

Well, looking at my framework (or engine I guess you could call it... I personally prefer to call it a framework, because it isn't full blown haha) the one thing it REALLY needs, is some unified way to manage resources. So my thoughts so far are to have a Resource Manager, which holds an ImageBank and a SoundBank.

But where I'm stuck, is organizing the images into the Bank. I'll obviously need to be able to reference each image so I've thought of either:
A) Use a vector of images
B) Use a map with a string key, and a surface

The problem with A, is finding a way to make sure everything is correctly referenced. I would think I would have to make some type of enumeration to reference everything... And that just seems like a terrible way of handling things.

My question is, how good is the second version? Is there a much better way of handling it? Am I just being a dumb ass? (Very likely haha)
User avatar
Ginto8
ES Beta Backer
ES Beta Backer
Posts: 1064
Joined: Tue Jan 06, 2009 4:12 pm
Programming Language of Choice: C/C++, Java

Re: A Resource Manager

Post by Ginto8 »

Have an array in the manager, and give out const pointers or references so that they can use the data without being able to modify it ;)
Quit procrastinating and make something awesome.
Ducky wrote:Give a man some wood, he'll be warm for the night. Put him on fire and he'll be warm for the rest of his life.
XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

Re: A Resource Manager

Post by XianForce »

Ginto8 wrote:Have an array in the manager, and give out const pointers or references so that they can use the data without being able to modify it ;)
So that's more like the first method... But my problem comes from knowing which image is which?
User avatar
GroundUpEngine
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 835
Joined: Sun Nov 08, 2009 2:01 pm
Current Project: mixture
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Location: UK

Re: A Resource Manager

Post by GroundUpEngine »

I learned this style from a different Engine, hope it helps you ;)

The style applied to your needs->

Code: Select all

#define MAX_IMAGES 100
#define MAX_SOUNDS 100

class ResourceManager {
  public:
	map<string, Image*> Images;
	map<string, Sound*> Sounds;

	ResourceManager();
	virtual ~ResourceManager();

	void ResourceManager::Reset()
	{
		// Reset std::maps
		for(map<string, Image*>::iterator iter = Images.begin(); iter != Images.end(); iter++)
		{
			delete (*iter).second;
		}
		Images.clear();
		for(map<string, Sound*>::iterator iter = Sounds.begin(); iter != Sounds.end(); iter++)
		{
			delete (*iter).second;
		}
		Sounds.clear();
	}
	Image* GetImage(const string &name) {
		// Check if the Image is not already loaded
		map<string, Image*>::iterator iter = Images.find(name);
		if((Images.size() < MAX_IMAGES) && (iter == Images.end()))
		{
			Image* act = new Image();
                   act->name = name;
			Images[name] = act;

			cout << name << " is new Image!\n";
		}
		return Images[name];
	}
	Sound* GetSound(const string &name); {
		..etc
	}
};
Last edited by GroundUpEngine on Wed May 12, 2010 7:45 pm, edited 2 times in total.
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: A Resource Manager

Post by Falco Girgis »

In libGyro, we basically use reference counting. Lets say you allocate an image:

Code: Select all

gyro::Texture *image = TexturePNG("whatever.jpg");
"whatever.jpg" is allocated and added to a linked list (I'm not using STL in libGyro) containing all images. Now, if something else uses TexturePNG:

Code: Select all

gyro::Texture *image2 = TexturePNG("whatever.jpg");
TexturePNG(char * const) returns the same texture allocated by the first call. When the code is finished with the texture, it calls delete like so:

Code: Select all

gyro::FreeTexture(image);
The internal reference counter associated with each image is now decremented (to 1), but the image remains in memory until another Free() is called on the same texture.
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: A Resource Manager

Post by Falco Girgis »

GroundUpEngine wrote:I learned this style from a different Engine, hope it helps you ;)

The style applied to your needs->

Code: Select all

#define MAX_IMAGES 100
#define MAX_SOUNDS 100

class ResourceManager {
  public:
	map<string, Image*> Images;
	map<string, Sound*> Sounds;

	ResourceManager();
	virtual ~ResourceManager();

	void ResourceManager::Reset()
	{
		// Reset std::maps
		for(map<string, Image*>::iterator iter = Images.begin(); iter != Images.end(); iter++)
		{
			delete (*iter).second;
		}
		Images.clear();
		for(map<string, Sound*>::iterator iter = Sounds.begin(); iter != Sounds.end(); iter++)
		{
			delete (*iter).second;
		}
		Sounds.clear();
	}
	Image* GetImage(const string &name) {
		// Check if the Image is not already loaded
		map<string, Image*>::iterator iter = Images.find(name);
		if((Images.size() < MAX_IMAGES) && (iter == Images.end()))
		{
			Image* act = new Image();
                   act->name = name;
			Images[name] = act;

			cout << name << " is new Image!\n";
		}
		return Actors[name];
	}
	Sound* GetSound(const string &name); {
		..etc
	}
};
My method is implemented essentially the same way, except for I provide a moderately intelligent way of freeing resources.
XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

Re: A Resource Manager

Post by XianForce »

GroundUpEngine wrote:I learned this style from a different Engine, hope it helps you ;)

The style applied to your needs->

Code: Select all

#define MAX_IMAGES 100
#define MAX_SOUNDS 100

class ResourceManager {
  public:
	map<string, Image*> Images;
	map<string, Sound*> Sounds;

	ResourceManager();
	virtual ~ResourceManager();

	void ResourceManager::Reset()
	{
		// Reset std::maps
		for(map<string, Image*>::iterator iter = Images.begin(); iter != Images.end(); iter++)
		{
			delete (*iter).second;
		}
		Images.clear();
		for(map<string, Sound*>::iterator iter = Sounds.begin(); iter != Sounds.end(); iter++)
		{
			delete (*iter).second;
		}
		Sounds.clear();
	}
	Image* GetImage(const string &name) {
		// Check if the Image is not already loaded
		map<string, Image*>::iterator iter = Images.find(name);
		if((Images.size() < MAX_IMAGES) && (iter == Images.end()))
		{
			Image* act = new Image();
                   act->name = name;
			Images[name] = act;

			cout << name << " is new Image!\n";
		}
		return Images[name];
	}
	Sound* GetSound(const string &name); {
		..etc
	}
};
EXACTLY what I was looking for =D Thanks!
User avatar
GroundUpEngine
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 835
Joined: Sun Nov 08, 2009 2:01 pm
Current Project: mixture
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Location: UK

Re: A Resource Manager

Post by GroundUpEngine »

XianForce wrote:
GroundUpEngine wrote:I learned this style from a different Engine, hope it helps you ;)

The style applied to your needs->

Code: Select all

#define MAX_IMAGES 100
#define MAX_SOUNDS 100

class ResourceManager {
  public:
	map<string, Image*> Images;
	map<string, Sound*> Sounds;

	ResourceManager();
	virtual ~ResourceManager();

	void ResourceManager::Reset()
	{
		// Reset std::maps
		for(map<string, Image*>::iterator iter = Images.begin(); iter != Images.end(); iter++)
		{
			delete (*iter).second;
		}
		Images.clear();
		for(map<string, Sound*>::iterator iter = Sounds.begin(); iter != Sounds.end(); iter++)
		{
			delete (*iter).second;
		}
		Sounds.clear();
	}
	Image* GetImage(const string &name) {
		// Check if the Image is not already loaded
		map<string, Image*>::iterator iter = Images.find(name);
		if((Images.size() < MAX_IMAGES) && (iter == Images.end()))
		{
			Image* act = new Image();
                   act->name = name;
			Images[name] = act;

			cout << name << " is new Image!\n";
		}
		return Images[name];
	}
	Sound* GetSound(const string &name); {
		..etc
	}
};
EXACTLY what I was looking for =D Thanks!
No prob :)

@Gyro
I see, that's better I gotta admit. btw I try to use STL when I can so it's abstracted away, I like teh OOP hehe :roll: ;)
XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

Re: A Resource Manager

Post by XianForce »

Well I've pretty much finished it, but for the past few days I've been running into a problem.

So basically, I want to reference each image like:

Code: Select all

ImageBank->GetSurface("Ship");
That's great and all, but if the surface isn't there, I don't want errors to happen, so I want it to load the surface solely by the string "Ship".

So I imagine I'd have a default graphics directory, and it would load the file named "Ship" from there. My only problem is getting the extension. I don't want to have to worry about putting in the extension, kind of like how it's done in XNA's Content Pipeline, I suppose... But the only thing I could think of to get the extension, is retrieving a list of all the file names in that folder, and finding which one contains "Ship", and then grab the extension from that and load it in.

But, this seems to be platform specific, and I want to maintain portability... So, any ideas? Is this even possible?
User avatar
GroundUpEngine
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 835
Joined: Sun Nov 08, 2009 2:01 pm
Current Project: mixture
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Location: UK

Re: A Resource Manager

Post by GroundUpEngine »

On initialization ya function could try to load "Ship" or whatever as one of the supported formats if no success then it loads the default Texture, or something like that ;)

Off the top of my head code ->

Code: Select all

Image* GetSurface(const string &name)
{
	// Check if the Image is not already loaded
	map<string, Image*>::iterator iter = Images.find(name);
	if((Images.size() < MAX_IMAGES) && (iter == Images.end()))
	{
		Image* img = new Image();
			   img->name = name;
		Images[name] = img;

		/// <--------------- mod ---------------> ///
		bool loaded = false;
		for(int type = 0; loaded != true; type++)
		{
			if(type == 0)
				if(Images[name]->Load(name+".png")) loaded = true;
			else if(type == 1)
				if(Images[name]->Load(name+".jpg")) loaded = true;
			else if(type == 2)
				if(Images[name]->Load(name+"..etc")) loaded = true;
			else
				if(Images[name]->Load("DefaultTexture.jpg")) loaded = true;
		}
		/// <--------------- mod ---------------> ///

		cout << name << " is new Image!\n";
	}
	return Images[name];
}
User avatar
Falco Girgis
Elysian Shadows Team
Elysian Shadows Team
Posts: 10294
Joined: Thu May 20, 2004 2:04 pm
Current Project: Elysian Shadows
Favorite Gaming Platforms: Dreamcast, SNES, NES
Programming Language of Choice: C/++
Location: Studio Vorbis, AL
Contact:

Re: A Resource Manager

Post by Falco Girgis »

GroundUpEngine wrote:On initialization ya function could try to load "Ship" or whatever as one of the supported formats if no success then it loads the default Texture, or something like that ;)

Off the top of my head code ->

Code: Select all

Image* GetSurface(const string &name)
{
	// Check if the Image is not already loaded
	map<string, Image*>::iterator iter = Images.find(name);
	if((Images.size() < MAX_IMAGES) && (iter == Images.end()))
	{
		Image* img = new Image();
			   img->name = name;
		Images[name] = img;

		/// <--------------- mod ---------------> ///
		bool loaded = false;
		for(int type = 0; loaded != true; type++)
		{
			if(type == 0)
				if(Images[name]->Load(name+".png")) loaded = true;
			else if(type == 1)
				if(Images[name]->Load(name+".jpg")) loaded = true;
			else if(type == 2)
				if(Images[name]->Load(name+"..etc")) loaded = true;
			else
				if(Images[name]->Load("DefaultTexture.jpg")) loaded = true;
		}
		/// <--------------- mod ---------------> ///

		cout << name << " is new Image!\n";
	}
	return Images[name];
}
That's also how libGyro handles it. Not necessarily even if you try to load a texture that isn't there--but also if we run out of VRAM on DC/PSP, the resource manager returns a default 32x32 texture that says "NO VRAM!"
XianForce wrote:But, this seems to be platform specific, and I want to maintain portability... So, any ideas? Is this even possible?
Sure. It might not be exactly what you wanted, though. Maybe try something like this:

Code: Select all

bool LoadShit(char * const name) {
    char buffer[200];
    ifstream file;
    strcpy(buffer, name);
    strcat(buffer, ".jpg");
    file.open(buffer);
    if(file.is_open()) {
        load shit and return true;
    }
   file.close();
   //It's not a jpg, try png:
   strcpy(buffer, name);
   strcat(buffer, ".png");
   file.open(buffer);
   if(file.is_open()) {
        //load shit + return true;
    }
    file.close();
    //do the same for GIF/whatever else
}
It's not pretty, but it's just using the C and C++ standard libraries, so it's definitely platform independent (whereas ANYTHING having to do with directory searching/scanning is not and should be avoided).
User avatar
GroundUpEngine
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 835
Joined: Sun Nov 08, 2009 2:01 pm
Current Project: mixture
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Location: UK

Re: A Resource Manager

Post by GroundUpEngine »

GyroVorbis wrote:It's not pretty, but it's just using the C and C++ standard libraries, so it's definitely platform independent (whereas ANYTHING having to do with directory searching/scanning is not and should be avoided).
AGREED!
XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

Re: A Resource Manager

Post by XianForce »

Thanks Gyro! I thought about doing that, but I thought it would end up being balls haha.

Really I didn't care about it for the images, because I'll probably only use PNGs, it's more useful to me in loading audio files, but I'd use the same method, so thanks for the tips guys =D

EDIT:
I think I'll do almost exactly as you did Groundup, except I think I'll use a switch statement, cause I think it looks cleaner haha

Oh, and I'll probably make an enum for the different extensions as well
Post Reply