#B There are basic two ways of letting this not happening. First: you can have pointers to different dependencies; you need to connect the "CImageManager" to the "CTextureManager". Second: if you're using the static classes approach (not the singleton one) you can just include your header file in the class if you want to make things "simple". The same applies to the "CModelManager". The "CTextureManager" should be connected to it. The Factory Pattern approach it is a good way of creating resources that are inherited. But it is just an example; a good way of saying I'll give you an ID and filepath and you can return a resource for me.
Connecting the managers together seems more natural (than connecting a type of resource to another type of manager). I did this in my sample code: CMeshManager defined on line 267 stores a pointer to CMaterialManager. This is then used in the load() method.
#C I know what you're saying. Since you know that you're not mixing responsibilities - you have to have that cognitive ability of the classes responsibility - you can do whatever you want to load the resources. But if you're talking about optimizations, it is impossible to answer because we don't know the overall architeture of your engine.
There are certain aspects of resource manager that need to be fast and some aspects that don't. For example, getting the actual resource data, say texture id, in hot rendering code should be fast. That's why I think that "single manager containing all type of resources" is potentially slow due to required dynamic type casts. One thing that does not need to be that fast is obtaining a handle to the resource by resource name/hash (my sample code line 148), because this is usualy done at load time. In my sample code, I experimented with the idea that at load time, handles to resources are retrieved. At active game time, handles are used to access the actual data. This data should always be usable, but it may not be the actual resource data, if some error occured or the data is still being loaded. This is why I invoked the idea of "dummy" data: each container would have to have one resource that is used in case of error. The engine would have to ensure that such resource is always added before anything else.
DATA_STRUCTURE RENDER_ITEM {
HANDLE Texture;
HANDLE Shader;
};
DATA_STRUCTURE RENDER_ITEM_QUEUE {
RETURN_VALUE Render();
Queue<AA_RENDER_ITEM> RenderQueue;
};
/*
Now it is time to render.
*/
for each RenderItem {
CTexture* Texture = TextureContainer.Get( RenderItem.Texture );
Texture->Activate( TextureSlot ); //This is virtual. The TextureSlot depends of other things such the "object" you have. Assumming a slot based engine.
}
The pseudo-code above is very high-level and just an example. But you got the idea. As with the reference counter and as your should know you must find a way of avoiding hash collision. Actually since you're talking about loading time, this is not a problem to compute because you're loading all resources. If you was doing this while playing the game you could have into problems.