A Resource manager design.

Started by
1 comment, last by AgustinAlvarez 10 years, 7 months ago

Hello!, i'm trying to design my own resource/asset manager for my own game engine. I would like feedbacks or any opinion on how may i improve it. The design is:

IResourceLocator: A class that represent a place where to look for the files.
Examples: FileLocator, ZipLocator, UrlLocator.

Code: https://github.com/Ghrum/Ghrum/blob/master/include/Resource/IResourceLocator.hpp
Example Code: https://github.com/Ghrum/Ghrum/blob/master/include/Resource/Locator/File/FileResourceLocator.hpp

IResourceLoader: A class that define how an resource is loaded.
Examples: ImageLoader, AudioMP3Loader, AudioOGGLoader.

Code: https://github.com/Ghrum/Ghrum/blob/master/include/Resource/IResourceLoader.hpp

IResourceCache: A class that define how is the resource stored.
Example: WeakReferenceCache, ContignousMemoryCache.

Code: https://github.com/Ghrum/Ghrum/blob/master/include/Resource/IResourceCache.hpp

And finally the resource manager that keeps track of every IResourceLocator, IResourceLoader and IResourceCache. Each module is comunicated using a ResourceKey that contain the name and file of the resource.

Code: https://github.com/Ghrum/Ghrum/blob/master/include/Resource/IResourceManager.hpp

An example of usage:


void onInitialization(IResourceManager & manager)
{
    manager.registerLocator<FileLocator>("." + PATH_SEPARATOR + "cache");
    manager.registerLocator<ZipLocator>("." + PATH_SEPARATOR + "data" + PATH_SEPARATOR + "textures.zip");
    manager.registerLoader<ImageLocator>("png", "jpg", "jpeg");
}


void onSomethingElse(IResourceManager & manager)
{
   auto & resource = manager.getResource<Image>("texture.png");
}

Any feedback or tip will be appreciated.

Feel free to comment and star my project! <https://github.com/Ghrum/Ghrum>

Advertisement

I recently finished my Resource Module as well, I'm going to post the design here so you can get your own thoughts of it.

It's very similar to yours too.

Resource Classes:

First, I have these [Basic Types]: MeshClass, MaterialClass, TextureClass, and anything else that I might add.

They contain only the resource data of how a Mesh if defined, the values of a Material, the Texture image, etc

Then I have the [Info Types]: ImageClass, ModelClass, and still adding new stuff.

These don't contain any data except the IDs/Names of what compose a Image or a Model.

Each one of the above have their own functions to load and save their data.

So I can create new Texture objects from BMPs, PNGs or anything else, and I save them in a format of my own.

And finally, the actual resource classes of: Sprite, Image, Model, etc

An Image has an imageClass variable that describes what composes it: a TextureClass, a Material and a Canvas.

Resource Cache:

This class accepts any template, gives it an int for ID and a string for name, and puts it in a vector.

Actually I have two vectors in this one, one for headers, another one for objects.

When I open a resource file in my format from, I read only the headers and save them in the vector.

Then when a resource is requested, I'm surely to return a pointer to the resource, and I go through these steps:

- First, look in the loadedResources vector. If the requested ID/name is already there, return it.

- If not, look in the headerResources vector. I'll find the header based on ID/name, if not I'll throw an error to my error module and return 0;

- If I found the header, I'll create a new object of the requested type, call it's LoadFromResource() function, add to my loadedResources vector, and return it's pointer.

I also left an AddResource() function if I want to load outside the resource manager for some (weird) reason, so it can start to manage it.

It'll free the memory/destroy the objects when it goes out of scope, so I don't have about leaks (I just have to properly delete stuff I allocated in these objects).

Also, this class has a Save() function that will loop through all loaded objects and save it to a file by calling each of the object's SaveToResource() function.

This is so I can get a single file with all resources of the same type, organized with headers, for easier loading the next time.

It also have the Load() (obviously) to accompany it...

Resource Manager:

Then I have this Resources class that has a bunch of template functions, and it's the class that knows how to load each type of resource.

For example, when I call Resources.Load<Image>("imageName"); it'll need to know how an image is loaded:

- First, look in the ResourceCache<ImageClass> to get that particular image's texture, material and canvas size.

- Then load every one of the resources that compose it from the other (Basic Types) ResourceCaches: Texture, Material, Canvas (this one actually I don't keep track, I create a new one everytime a new image is loaded so I can change it without worrying about messing with other images).

I had a hard time coming up with something to handle composite resources, and that's what I came up with.

For example, I might want to have two of the same 3D Model but with a different texture each, so I also had to keep track of each of these models remembering which texture/mesh they had.

For the case that I want a new copy of something that will be changed (such as material), I just create a new one in the Resources's Load function:

template <> Image* Load(int imageID)
{
    Image* image = new Image();
    image->_imageInfo = _imageInfoVector.GetResource(imageID);
 
    //imageInfo contains everything about this image
    if(image->_imageInfo != 0)
    {
        image->Texture = _textures.GetResource(image->_imageInfo.textureID);
        //Texture shares the same pointer since I won't change them per image
 
        image->Material = new Material(_materials.GetResource(image->_imageInfo.materialID));
        //But I will for the material, so I create a new one, and I copy it through a constructor overload
        //So I can change this image's material without it affecting any other images
 
        //Whatever else my image will have
    }
 
   return image;
};

Hope this help give you some ideas on how to design yours.

I recently finished my Resource Module as well, I'm going to post the design here so you can get your own thoughts of it.

It's very similar to yours too.

Resource Classes:

First, I have these [Basic Types]: MeshClass, MaterialClass, TextureClass, and anything else that I might add.

They contain only the resource data of how a Mesh if defined, the values of a Material, the Texture image, etc

Then I have the [Info Types]: ImageClass, ModelClass, and still adding new stuff.

These don't contain any data except the IDs/Names of what compose a Image or a Model.

Each one of the above have their own functions to load and save their data.

So I can create new Texture objects from BMPs, PNGs or anything else, and I save them in a format of my own.

And finally, the actual resource classes of: Sprite, Image, Model, etc

An Image has an imageClass variable that describes what composes it: a TextureClass, a Material and a Canvas.

Resource Cache:

This class accepts any template, gives it an int for ID and a string for name, and puts it in a vector.

Actually I have two vectors in this one, one for headers, another one for objects.

When I open a resource file in my format from, I read only the headers and save them in the vector.

Then when a resource is requested, I'm surely to return a pointer to the resource, and I go through these steps:

- First, look in the loadedResources vector. If the requested ID/name is already there, return it.

- If not, look in the headerResources vector. I'll find the header based on ID/name, if not I'll throw an error to my error module and return 0;

- If I found the header, I'll create a new object of the requested type, call it's LoadFromResource() function, add to my loadedResources vector, and return it's pointer.

I also left an AddResource() function if I want to load outside the resource manager for some (weird) reason, so it can start to manage it.

It'll free the memory/destroy the objects when it goes out of scope, so I don't have about leaks (I just have to properly delete stuff I allocated in these objects).

Also, this class has a Save() function that will loop through all loaded objects and save it to a file by calling each of the object's SaveToResource() function.

This is so I can get a single file with all resources of the same type, organized with headers, for easier loading the next time.

It also have the Load() (obviously) to accompany it...

Resource Manager:

Then I have this Resources class that has a bunch of template functions, and it's the class that knows how to load each type of resource.

For example, when I call Resources.Load<Image>("imageName"); it'll need to know how an image is loaded:

- First, look in the ResourceCache<ImageClass> to get that particular image's texture, material and canvas size.

- Then load every one of the resources that compose it from the other (Basic Types) ResourceCaches: Texture, Material, Canvas (this one actually I don't keep track, I create a new one everytime a new image is loaded so I can change it without worrying about messing with other images).

I had a hard time coming up with something to handle composite resources, and that's what I came up with.

For example, I might want to have two of the same 3D Model but with a different texture each, so I also had to keep track of each of these models remembering which texture/mesh they had.

For the case that I want a new copy of something that will be changed (such as material), I just create a new one in the Resources's Load function:


template <> Image* Load(int imageID)
{
    Image* image = new Image();
    image->_imageInfo = _imageInfoVector.GetResource(imageID);
 
    //imageInfo contains everything about this image
    if(image->_imageInfo != 0)
    {
        image->Texture = _textures.GetResource(image->_imageInfo.textureID);
        //Texture shares the same pointer since I won't change them per image
 
        image->Material = new Material(_materials.GetResource(image->_imageInfo.materialID));
        //But I will for the material, so I create a new one, and I copy it through a constructor overload
        //So I can change this image's material without it affecting any other images
 
        //Whatever else my image will have
    }
 
   return image;
};

Hope this help give you some ideas on how to design yours.

Thank you, that gave me a lots of ideas on how could i improve my design.

Feel free to comment and star my project! <https://github.com/Ghrum/Ghrum>

This topic is closed to new replies.

Advertisement