I currently have a
ResourceManager class which is responsible for searching for resources with a given identifier, returning a reference counted pointer to the resource if a valid resource is found, and instantiating a new object if none has been found. Often a resource itself depends on other resources, which are requested from the resource manager. For example, Window may depend on
SdlMain (which initializes and shuts down SDL), and thus the constructor of Window would ask
ResourceManager for the
ResourceManager resources; //the return type is std::shared_ptr<Window>, the first argument "MainWindow" is the //..ID to search for, the rest of the arguments are simply forwarded to the constructor //..of class Window if needed. auto mainWindow = resources.make<Window>("MainWindow", "Hello World", 512, 512, SDL_WINDOW_SHOWN, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); //The Window object contains the renderer, too, so the ID of the current window //"MainWindow" must be passed to the texture's constructor auto tex1 = resources.make<Texture>("tex/tex1.png", "tex/tex1.png", "MainWindow"); //This renders the texture to the screen. tex1->renderToBuffer(0,0); mainWindow->bufferToDisplay();
However, the requirement of knowing the actual ID of the Window when creating a texture becomes a problem when writing a sprite class, if multiple window objects are to be supported:
//Unlike Texture, a Sprite is not a resource but it's lifetime is bound to the object //..owning it (and there may be many sprites using the same Texture). Thanks to //..how Texture is implemented, now everything that wishes to use a sprite must be //..aware of the ID of the window "MainWindow" in order to initialize a Sprite. Sprite sprite(resources, "tex/tex1.png", "MainWindow");
I recently came up a solution for this. I would give the identifiers a context, similar to the "scope" of programming languages. SdlMain would be found in global context, with it's ID "SdlMain" available and meaningful anywhere, while one window may reside in context Game, and a second window may reside in the context Editor. Both Window instances would have the name "Window", but there would be no conflict since they reside in a different contexts. The resulting system might look somewhat like this:
ResourceManager resources; //Set the scope to "Game" resources.setContext("Game"); auto mainWindow = resources.make<Window>("Window", "Hello World", 512, 512, SDL_WINDOW_SHOWN, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC); //Texture asks ResourceManager simply for a "Window", with no idea about the current //context. Sprite sprite(resources, "tex/tex1.png"); sprite.draw(); mainWindow->bufferToDisplay(); //Set the context back to global resources.setContext();
The actual ID search would function as follows: First the ID is searched for in the current context, if there are no matches the preceding context is evaluated too, until the search arrives at the global context.
Note that the final version would use integer ID:s instead of strings. I do realize that this might be the best example of overengineering ever, but I'm mostly doing this for its learning value.
Before fully committing to such a system, I would like to know some opinions on the matter from more experienced programmers:
Is this a practicable solution? Are there any blatant flaws in this concept? Any suggestions?