1

So I have a rendering engine, and I have a resource manager that adds classes that derive from type 'Resource'. It's a very flexible and generic resource manager, of which only one can exist (it is a static class). Thus, a class ShaderProgram or Camera can easily be added like so:

    rm::add("textShader",
        new ShaderProgram("assets/shaders/renderText.vert",
                          "assets/shaders/renderText.frag", true, true));

    rm::add("fpsCamera",
            new FPSCamera(glm::vec3(0.f, 0.f, 20.f), 45.f, 4.f / 3.f, 1.f, 1000.f));

Now, this may seem quite straightforward; but a theoretical question I ask myself is: when is a resource a resource? How does one differentiate between something that ought to be stored (e.g. a resource) vs. something that should not be stored (e.g. non-resource)?

For instance, I know that I will be using my ShaderProgram and Camera as well as Texture (all of type Resource) a lot. In order for me to get the explicit type of a Resource, I do the following:

convert(Camera*, rm::get("fpsCamera"))->func(); // call Camera's func()

Thus, I know that it if I need to reuse something over and over again I would have to store it in the resource manager.

When it comes to another class, however, it gets a bit more complicated. I have two other classes: Renderable and Scene. The relationship between the two is very intimate insofar that a Renderable is an abstract class for renderables such as Sprite, Model etc; and Scene is simply a container of a number of Renderables. Thus, in a graphics application it is likely that I will be loading scenes and unloading them to free up resources when required. But I am not sure whether Renderable should derive from type Resource or whether Scene should derive from type Resource (thereby calling Scene a resource) or whether both should simply be a Resource. If a Renderable were a resource then that means it can be accessed by anyone as easy as:

convert(Model*, rm::get("someRandomModel"))->randomFunc();

Now before you yell at me about type-safety in the above function, I'd like to reassure everyone that the compiler checks against the type and sees if the called function is resolved. It's a dynamic_cast after all.

Anyway, the dilemma thus continues and at first thought I can only assert that Renderable could be a Resource only IF we want to reuse the renderables in question. Thus, if I were to add a Model to the resource manager then that means it is available everywhere in the program. But, it can't be retrieved unless you know the ID of that Resource. Thus, it is entirely possible for me to reuse a Model object to replace an existing Mesh inside it.

Without getting too technical, I again ask the simple question: When is a resource a resource, and where do we draw the line?

4

Though there is no "official" definition of a "resource", the term is generally used for anything that your program has to explicitly acquire before use, and possibly release after use, where the act of acquiring and releasing is either expensive or complicated enough that we want to avoid doing it more than we have to. Typically, this includes any file we have to open (image, model, mesh, sound, music, data, etc.), any hardware we need (audio context, graphics context, etc), and any network connections we need.

Generic resource managers are useful because they can abstract away the need to worry about exactly when to acquire and release the resource, instead enforcing some straightforward rule like "acquire it the first time someone asks for it and release it after no references to it remain in scope" which prevents performance problems like reopening the same file every single time we want to use it, instead of simply leaving it open until we're done with it.

Given this definition of a "resource", your Renderables probably do not qualify. Many Renderables will need to refer to a resource, but that doesn't mean they are resources themselves. A Scene may need lots of data to be rendered properly, but it doesn't have to contain all of that data itself. For instance, it can refer to graphics assets via filenames, or via some custom object the resource manager provides. That way, the Scene itself is a relatively lightweight object that's no harder to construct than any other C++ object, so it would not benefit from being managed as if it was a heavyweight resource.

In addition to that theoretical argument, I see two other red flags with your specific proposal. It's possible you didn't mean these that seriously and these responses will amount to nitpicks, but I believe they're worth mentioning regardless.

First, the only benefit you cite for making Renderable or Scene derive from Resource is that "it can be accessed by anyone". That is not a benefit. While "global variables are evil" may be overly dogmatic and simplistic, you should generally make an effort to restrict access to a variable to those parts of the code which actually need it. Does the Scene rendering logic need to know about the resource manager? Probably not. The code to draw individual Renderables probably does, but not the code to traverse scene graphs.

Second, in most cases, the whole point of making a base class B for classes X and Y is so that you can call b->foo() without caring whether b is of type X, Y or Potato. If you have to do a dynamic_cast to ensure "type safety", that means you probably do care what concrete type b has, which means you probably aren't gaining anything from the common base class. If the resource manager is requiring you to do dynamic_casts to use the resources it managers, I would consider that a serious flaw with the manager; generic code in C++ should usually rely on templates rather than dynamic_casts for its type safety.

  • Interesting explanation, and I have deliberated regarding the type-safety of the ResourceManager Thus, how I could construct a version of a 'get' function which relies on templates instead of dynamic_casts from Resource* to the class a user wants? – Poriferous Aug 21 '15 at 12:16
  • @Poriferous The example I'm most familiar with is the ResourceHolder from the Thor library (an add-on to SFML), which is described here: bromeon.ch/libraries/thor/v2.0/tutorial-resources.html – Ixrec Aug 21 '15 at 12:33
  • Well, what I did was just return dynamic_cast<T>(rm::get(id)); which casts the Resource* to the desired class represented by the template T. An interesting resource manager though what you shared; but I disagree with a few requirements the developer has advanced. – Poriferous Aug 21 '15 at 12:48

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.