Designing a Resource Manager Framework

Started by
14 comments, last by nicba 21 years, 2 months ago
It''s not at all impossible to have the same resource manager manage the audio, animation, meshes, textures, etc...

With Java you could just use multiple interfaces.

Essentially, all the resource manager does is accept a moniker and produce a concrete object that supports the IResource interface. Whatever request the resource, ought to know what type of resource it is requesting. A dynamic cast will be performed from the IResource to the ITexture, or IAnimation, etc... interface. (In C++ you could use a static cast for most scenarios.) The classic COM name for this interface is IPersistStream.

If the resource manager is responible for loading the items off disk, it makes sense to use one for all resource types. It would be the RM''s job to read the header/index of some wad files, search the index for the moniker token, then load and decompress the data. For all resources this process is the same. To even have multiple objects of the same resource class will result in a duplication of the index in memory, or at the least loading the index multiple times.

To use mutliple interfaces in Delphi, you have to make COM objects. It will perform the "dynamic cast" through the QueryInterface method for you, if you just assign a pointer of one interface to another.
- The trade-off between price and quality does not exist in Japan. Rather, the idea that high quality brings on cost reduction is widely accepted.-- Tajima & Matsubara
Advertisement
quote:I wouldn''t use inheritance like AP suggested. [...]

In fact my suggestion is a generic RSM (resource storage manager). It only handles id giving, ref counting, and access. Your loader asks the RSM to return a space, take the id and use the id to access the data from the RSM. So your RSM is sort of a global singeleton (doesn''t have to be a singleton).

For even greater reusability, you parameterise the storage type in the RSM, but all these requires C++ template.


as i said, i wanted to provide a perspective, not suggest a design. i like your RSM-concept. one question though:
when using templates to parameterise the storage did you mean using a concept like "policy classes"?


  struct ZipAccessPolicy { ... }struct DiskAccessPolicy { ... }template <class AccessPolicy = DiskAccessPolicy>class ResourceManager : private AccessPolicy{ ... };  


if so, wouldn''t the only difference between using inheritance and templates be the kind of polymorphism (run-time vs. compile-time)?

No, there is no concept of DiskAccess in the RSM.


  // Resource ID manager with ref counting, blahtemplate <class Param>  class ResourceMangaer{   std::vector<Param> p_;   // a list of the resourcepublic:  typdef int ID;   // id for accessing  ID  Create();  Param& Access( ID id ) const;};class SurfaceData;class AnimatationData;class SoundData;// imagine global singletong availabletypedef ResourceManager<SurfaceData>   SurfaceRM;typedef ResourceManager<AnimationData> AnimRM;typedef ResourceManager<SoundData>     SoundRM;// Higher level loaders.void LoadBMP( ifstream &is ){   SurfaceRM::ID id = SurfaceRM_.Create();   SurfaceData &data = SurfaceRM_.Access(id);   // parse bmp}void LoadJPG( ifstream &is ){   SurfaceRM::ID id = SurfaceRM_.Create();   SurfaceData &data = SurfaceRM_.Access(id);   // parse jpg}  
ok, then i misunderstood what you meant by "storage type". i thought you were referring to the actual location.

it seems to me as if you didn''t really address the problem of
resource location but instead provided a solution to
the problem of where to store the loaded data...

how does your design handle the requested independency of
resource location (zip, hd, exe)?

if you wanted to accomplish it by using iostreams wouldn''t it be better to use istream& instead of ifstream& ?
and wouldn''t you need to use inheritance again?

(please note that english is not my first language and keep that in mind when interpreting the "tone" of my reply.)
quote:Original post by Anonymous Poster
how does your design handle the requested independency of
resource location (zip, hd, exe)?

if you wanted to accomplish it by using iostreams wouldn''t it be better to use istream& instead of ifstream& ?
and wouldn''t you need to use inheritance again?


Yes. You are rite. It should be istream. My bad.

Bascially, the code for parsing specific file format as just in a function. I have not worked with .zip files before but I assume you can get the data in a stream of bytes. In that case, you subclass istream to read a zip file in a stream format using operator >> like ifstream. Similarly for resource loading in exe.

Your zip_stream, exe_stream and file parsers can be reused in a mix and match way. Yes, there is inheritance but in this way the loading and where they are located are loosely coupled.
quote:
Bascially, the code for parsing specific file format as just in a function.


But by making the code for parsing a specific file format just a function, like in the code above, isn''t you turning the pyramid upside down?

If the loader functions is the "upper layer" that the client needs to access when loading resources, then it would require the client to duplicate code for determinding precisly what fileformat it is about to load, everywhere the application happens to load something. Everywhere the application loads a texture/image it must use an ''if...then...else...'' statement to find out wether to call LadBMP or LoadJPEG. I would rather abstract that by hiding that descision inside a single Load method of the resource manager. The resource manager may then call the appropiate Load function for the client, instead of the other way around. Also makes it easier to add/remove support for new formats, I would think.

quote:
Your zip_stream, exe_stream and file parsers can be reused in a mix and match way. Yes, there is inheritance but in this way the loading and where they are located are loosely coupled.


Yes, that was my thought also. But still, it might be a good idea to encapsulate the actual streams inside the DataAccessStrategy suggested by AP. It would make it easier to pre-configure the location of the resources once and for all. For example it would allow you to do something like the following:


  void initResourceManager() {  ZipAccessStrategy zip = new ZipAccessStrategy();  zip.addResourceLocation(./resources/tiles.zip);  zip.addResourceLocation(./resources/objecttextures.zip);  ...  resourceManager.setDataAccessStrategy(zip);  ...}void ResourceManager::Load(filename) {  // Open the file from one of the pre-configured locations...  stream = this.getDataAccessStrategy().open(filename);  if fileExtension(filename) = ''.bmp'' {    LoadBMP(stream);  }  else if...}  


I think that would have been a bit harder if you restricted yourself to work only with the stream interface. A stream would typically be instantiated only right before data is to be read, and destroyed when finished. So there wouldn''t be much possibility of setting it up and configuring it.

This topic is closed to new replies.

Advertisement