Resource manager question

Started by
7 comments, last by Gage64 15 years, 11 months ago
I normally do things the inefficient way and break things up, but I'm interested in doing one of them resource factory approaches on a resource manager, to handle 2d textures, 3d models, and audio - now my questions is, does anyone have a good template shell, of one would look like, the coding part isn't a problem, but I don't want to blindly just hope I can correctly put it together. One of the things I want to be able to do is just, be able to access all my resources regardless of type, and just OnLostDevice & OnResetDevice, which I can do with a data structure, list/vector, or whatever it may be -- I just need to know of a general template on how it may look. /shrug Thanks. Hopefully, this makes sense - I'm posting on 2 hours of sleep.
[size="2"][size="1"][size="2"]- Quinn
[size="2"][size="1"][size="2"]Software Developer, Mintrus
Advertisement
I'm in the middle of designing one right now, but its far from finished. I too, would like to look at any templates people post so that I may learn about them, and correct my design if need be.

EDIT: my manager works like this:

1. My resource manager class has several functions, of which are: add(ResourceObj *), remove (ResourceObj *), onDeviceLost(), and onDeviceRestored();
2. This class uses a singleton pattern.
3. I have a ResourceObj class. It is abstract but it has a constructor and destructor and two other functions: invalidate() and restore();
4. The constructor of this class adds itself to the resource manager upon creation: resourceManager::getInstance()->add(this);
5. The destructor removes itself from the resource manager much like the constructor.

Here is some code:
class ResourceManager{  vector<ResourceObj *> objList;public:  ResourceManager *getInstance(); //Singleton Pattern  bool add(ResourceObj *);  bool remove(ResourceObj *);  void onDeviceList();  void onDeviceRestored();};


class ResourceObj{public:  ResourceObj();  virtual ~ResourceObj();  void invalidate() = 0;  void restore() = 0;};


Implementation:
bool ResourceManager::add(ResourceObj *obj){  // Add this object to the list  objList.push_back(obj);}bool ResourceManager::remove(ResourceObj *obj){  // Remove object from the list  objList.erase(obj);}bool ResourceManager::onDeviceLost(){  // Invalidate all objects  for (int i = 0; i < objList.size(); i++)    objList->invalidate();}bool ResourceManager::onDeviceRestored(){  // Restore all objects  for (int i = 0; i < objList.size(); i++)    objList->restore();}


ResourceObj::ResourceObj(){  // Auto-add myself  ResourceManager::getInstance()->add(this);}ResourceObj::~ResourceObj(){  ResourceManager::getInstance()->remove(this);}


Once you have this basic pattern down, you can easily tell the manager that the device is lost, or regained. The manager will do the rest.

Once you get the basics down, you can easily derive from ResourceObj. This is not bound to any specific API because it does not implement the restore and invalidate functions, rather thats left to any specific derivations of this class.

I'll give a free lolly pop to anyone that guesses all the patterns used in this example :P.
------------Anything prior to 9am should be illegal.
Why dont you take your best stab at the template yourself. Then show us and we'll critique it?

You'll want to use reference counting and some kind of smart pointer to your resources. This will allow for async resource creation.

My resource looks kind of like this
class Resource : public RefCounted{public: virtual ResourceStatus InitialLoad( InitialLoadParams& params ) = 0; virtual ResourceStatus ContinueLoad( ContinueLoadParams& params ) = 0; const ResourceStatus GetStatus() const; const InitialLoadParams& GetInitialParams() const; int CompareResources( const Resource& other ) const;};

A resource pool is not a place for a singleton. What if you wanted to load resources for the next level as you were nearing the end of the current one? Why limit things to just one instance, eventually down the road you will realize how dumb it was but how nearly impossible to undo it is. There have been enough discussions by much smarter people then I on why the singleton is completely wrong so search the forums and enjoy the ride! If you need just one, make just one (specify this in the documentation). If you need a global, make it a global (or research far better ways of doing this, the OO way or whatever).

@OP: Just hit up google there are hundreds of examples of templated factories out there. It's nothing special for game development, its just a factory.

And like bzroom said, just write it up and post it, we'll look it over for you.

@bzroom: Why not use boost smart pointers? Or weak pointers. They're automatically reference counted and highly debugged already (instead of reinventing the wheel and having a more then likely bugger one)?

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

Quote:Original post by Mike2343
@bzroom: Why not use boost smart pointers? Or weak pointers. They're automatically reference counted and highly debugged already (instead of reinventing the wheel and having a more then likely bugger one)?



Because reInventing the wheel is fuun!

I agree that if you just change your ResourceManager to ResourcePool and make it non singleton it would be a wise move.

I never thought of having resources pooled by zone or level. Usually I just assume that the entire game will reuse at least some content. But to drop a whole level of the entire spectrum of content would be sweet. I think i'm going to make a resource pool and add one to each of my "Scenes" so it can be dropped as a whole and preserve the other scenes resources.

To give you a bit more info about my system. I use template specialization to create a mapping between resource type and an enumeration. I use this enumeration to index a map of different resources.

Example:

//ResourceTypes.h - Client Defined
enum ResourceTypes{ RESOURCE_TEXTURE = 0, RESOURCE_MODEL, //ADD ADDITIONAL RESOURCE TYPES HERE RESOURCE_TYPE_COUNT};//specializationtemplate < typename T > struct ToResourceType;template <> struct ToResourceType<Renderer::Texture> {  static const ResourceType Enum = RESOURCE_TEXTURE;  static const char *SubFolder() { return "Textures\\"; } };template <> struct ToResourceType<Renderer::Model> {  static const ResourceType Enum = RESOURCE_MODEL;  static const char *SubFolder() { return "Models\\"; } };//ghetto hacking//called on resource manager intializationstatic ResourceListBase *CreateResourceList( ResourceTypes type ){ switch(type) {  case RESOURCE_TEXTURE:   return new ResourceList<Renderer::Texture>;  case RESOURCE_MODEL:   return new ResourceList<Renderer::Model>; }};


//ResourceManager.h
#include "ResourceTypes.h"class ResourceManager{public: ResourceManager() { SetupLists(); } ~ResourceManager() { DestroyLists(); } template<class T> ResourceHandle<T> GetResource(const std::string &filename, ...) {  ResourceList<T> *list = dynamic_cast<ResourceList<T>*>(m_Resources[ToResourceType<T>::Enum]);  //invalid list  if (!list)    return ResourceHandle<T>();  std::string path = m_Path + ToResourceType<T>::SubFolder() + filename;  CreateResourceParams createParams(path, ...);			  return list->GetResource(createParams); }private: void SetupLists() {   for( int i = 0; i < RESOURCE_TYPE_COUNT; ++i)     m_Resources = CreateResourceList((ResourceTypes)i); } void DestroyLists(); ResourceListBase *m_Resources[RESOURCE_TYPE_COUNT]};


[Edited by - bzroom on May 26, 2008 11:04:55 PM]
@bzroom: Not sure if you're coming back to this thread again but if you do. You could also pole other resource pools (older ones) for existing data instead of reloading it off the slow HDD again. I have it so one pool can do a full copy to another pool to save cycles and load times. Just an idea :)

"Those who would give up essential liberty to purchase a little temporary safety deserve neither liberty nor safety." --Benjamin Franklin

Do these help :
Gem: A Generic Handle-Based Resource Manager
yordan gyurchev : articles (check for "Can we handle it?"
A little while ago I had some thoughts on this and wrote them down in my journal.

I admit, I never got around to implimenting them but there might be a few ideas worth considering; mostly I'm happy with the 'weak pointer' method of doing things, where your resource pool doesn't hold a strong pointer to the object but a weak one so that you automatically clean up the resource once the thing using them goes out of scope.

Of course, there are pros and cons to strong vs weak.

anyways, my ponderings start here with "Resource Manager Design Part 1".

I should probably revist this subject at some point...

edit:
Turns out this carries on into July as well, where we get into a bit more meat around the subject.. so yeah, don't just stop on the couple of entries in June if you do read it
This post also looks like it has some interesting notes on the subject.

This topic is closed to new replies.

Advertisement