Page 1 of 1
A Resource Manager
Posted: Wed May 12, 2010 6:57 pm
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)
Re: A Resource Manager
Posted: Wed May 12, 2010 7:32 pm
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
Re: A Resource Manager
Posted: Wed May 12, 2010 7:35 pm
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?
Re: A Resource Manager
Posted: Wed May 12, 2010 7:42 pm
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
}
};
Re: A Resource Manager
Posted: Wed May 12, 2010 7:44 pm
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:
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.
Re: A Resource Manager
Posted: Wed May 12, 2010 7:45 pm
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.
Re: A Resource Manager
Posted: Wed May 12, 2010 7:46 pm
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!
Re: A Resource Manager
Posted: Wed May 12, 2010 7:52 pm
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
Re: A Resource Manager
Posted: Sat May 15, 2010 1:12 pm
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:
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?
Re: A Resource Manager
Posted: Sat May 15, 2010 2:21 pm
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];
}
Re: A Resource Manager
Posted: Sat May 15, 2010 2:35 pm
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).
Re: A Resource Manager
Posted: Sat May 15, 2010 4:17 pm
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!
Re: A Resource Manager
Posted: Sat May 15, 2010 4:38 pm
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