Last night I just lost my whole library of loader classes by accident, texture loaders, material loaders, mesh loaders ect.
Instead of just sitting down and coding them all up again as they were, I thought I would make things a bit interesting by designing myself a proper resource management framework (not that I actually need such a monster for the small games I write, but it''ll be more fun than just re-doing my ball of mud!).
Here''s some of the things I have thought of until now:
1) A couple of different ResourceManagers, which can be assembled into a composite structure (the pattern). So I have a global ResourceManager to retrieve my resources from in-game, but also access to different sub-managers for configuring specific things about certain kind of resources. For example a TextureManager that lets me set the filtering method (mipmapped ect.) on the textures to be loaded.
2) This setup would even allow me to attach different strategies to the different managers for implementing various memory-management/disk swapping algorithms for each kind of resource (by use of the strategy pattern).
I would like to separate the management of the resources from the actual loading of them. Also, I would like the framework to be extensible enough to load resources from .res files included in the .exe (screensavers), plain from the file system and from archive files (ex.: .zip). I like my resource loading code to receive just a stream (any kind of stream) and parse that into the requested resource type "transparently."
My question is how to accomplish this best. I''m not sure how I ought to divide the responsibility among my classes.
In my first solution I have two kinds of classes: ResourceManagers and Resources. The resource managers derive from AbstractResourceManager and the resources derive from AbstractResource. The inheritance hierachy for resources is three levels deep. For example I could have a concrete TGATexture, which derives from an abstract Texture type, which in turn derives from the AbstractResource class. My resource managers should be flexible with regards to supported file formats, so instead of hardcoding them to operate with the concrete resource classes, they only know about the abstract types at compile time. At run-time one should be able to register support for different file formats by passing references to the concrete classes to the managers. Ex:
ATextureManger = new(TextureManager);
ATextureManager.registerFileType(TGATexture); ATextureManager.registerFileType(BMPTexture);
....
When the game requests a resource from a resource manager, it should attempt to load it by querying all its registered file types classes for one capable of handling it, in a Chian-of-Responsibility like fashion. A TGATexture class would thus know how to handle a ''.tga'' file type and respond to this.
By consequence, each concrete resource type should therefore know how to load/unload the resource from memory, using their choosen file format. A TGATexture might therefore have an interface like the following:
class TGATexture : Texture
{
load(stream); // Load a ''.tga'' file into a Texture structure
unload(); // Unload the texture (temporarily) from mem.
}
Where the stream is opened by a resource manager to that managers respective repository (a file in a specific directory, in a .zip file ect.).
There is, however, at least one problem with this approach to resource loading. Tying the the loading of resources directly to subclasses of the abstract resource types, such as with the TGATexture subclass, creates a one-to-one mapping between resource types and files (that is, there is an abstract resource type Texture and one or more concrete implementations that fills Texture with data). The problem arrives with "library" files, as the .mtl files used to store materials for a wavefront .obj model. A .mtl file does not correspond directly to a material, so we can''t have a Material type with a MTLMaterial subclass loading from a .mtl file. The .ntl files contains a collection of materials. Therefore, in order to support these files it would be necessary to define a new resource type, a MaterialLibrary resource. This resource, I feel, would be kind of articficial. The rest of the game/application does not care about material libraries. It cares only about a single material at a time, when its going to render it on a face.
Maybe a viable alternative is to have not two but three kinds of classes: ResourceManagers, Resources and Loaders. That is, to split the loading code out in its own class hierachy. There would only be a few kinds of resources: AbstractResource, TextureResource, MaterialResource, MeshResource and AudioResource, for example. And these would all be entirely passive, only storing the data put into them. Instead of registering file types with the resource managers, one would register Loaders. For example there would be a only one TextureResource class, but more loaders: TGATextureLoader, BMPTextureLoader ect. Loaders would be a kind of factory classes, hiding the complexity of instantiating and loading a resource from a file (or a stream, rather). But they would be very thightly coupled to the resource classes storing the textures, materials or whatever.
I kind of like the conceptual picture: ResourceMangers in which you registers Loaders for different file format, which in turn instantiates and loads resource for the managers. But then again its another, separate class hierachy. That model would also mean an increase in complexity. I can''t decide which approach I like best....
Any of you done anything like this before? Comments, feedback, tips and ideas are very much welcome.
Regards
Nicolai