Hello everyone,
I am currently in the process of restructuring our current engine into multiple projects/library modules to improve compilation time and to better allow different modules to be selectively reused as needed in engine utilities. This posed a few questions in general architecture design however :
1. Where does resource loading actually occur? In the file module? In a special module dedicated to resource factories (like a "modelLoader" or "audioStream" etc.? Currently the file module only provides a basic file manager that allows loading files from ZIP/PAK and disk directories as it were a single abstract file system. Under the Single Responsibility Principle I would expect the actual loaders to be elsewhere in their own dedicated modules (note that by "module" here I am referring to a project in a Visual Studio solution that compiles as a static or dynamic library.)
That is, what I was considering was having different projects for different loaders; such as imageLoaderTGA, imageLoaderDDS, modelLoaderHG etc. These would inherit from some base class defined in another more abstract module, such as hgImage or hgModel. For example,
Project : LoaderDDS
#include <hgimage/loader.h>
class HgLoaderDDS : public HgImageLoader {
//...
};
Project : HgImage
class HgImageLoader {
// abstract class for load,save for creating HgImage objects.
};
This of course works I am just not sure if its good nor where it fits in with resource management.
2. Is it common to have a single module that is itself a library that links all the major libraries together? That is, I currently have an Hg module that has the HgKernel class. This would provide system startup and shutdown as well as the main loop; it is the only singleton in the entire engine that allows a single access point to all systems. In order for this design to stay (I can rewrite it if needed) we need a single library that imports all major other engine libraries/projects and basically provides a very thin interface like so,
class HgKernel {
private:
static HgKernel* singleton;
gfx::HgVideoDriver* pkVideo;
public:
HgKernel ();
/*** KERNEL ACCESSOR METHODS ***/
virtual ~HgKernel () {
if (singleton) {
shutdown ();
}
}
static inline HgKernel* get () {
if (! singleton)
singleton = new HgKernel;
return singleton;
}
/*** ACCESSOR METHODS ***/
inline gfx::HgVideoDriver* getVideoDriver () {return pkVideo;}
inline double getFramesPerSecond ();
/*** SYSTEM METHODS ***/
virtual bool initialize ();
virtual bool initialize (std::string caption, int w, int h, int bpp=16, bool fullscreen=false);
virtual void shutdown ();
virtual bool run ();
};
The concern is that HgVideoDriver is implemented in a completely different library. If we extend this example to include an inputManager, audioManager, scriptManager, networkManager, etc., etc., all implemented in other libraries. Although the editor and game only need to link to this one HgKernel class, the HgKernel class would need to be able to link to all other main systems. To make it worse, the whole point of this setup was to allow any major system to call any other major system as needed; this would thus make this design impossible anymore - for example, the kernel object cant depend on the videoManager when the videoManager also needs to depend on HgKernel::get() -- we would have a circular dependency.
So the question for (2) is, how do you allow the major components to communicate with each other as needed without using a central setup like the above? Or is there a better alternative or way to implement the above that does not result in circular dependencies?
Thanks for any help!