Sign in to follow this  
Squirm

Texture manager

Recommended Posts

This post isn't a request for help, it's a couple of classes for texture handling which you are more than welcome to take and do what you like with. I would most appreciate people tearing my coding style to bits and improving on it, but the idea is that any beginner can simply take it and run. I wasn't sure if OpenGL or Graphics or even just Software Engineering weren't better forums for this, but decided I had aimed at beginner level and would go here.
A (fairly) common question I see amongst beginners is "why doesn't my TGA loading code work". Personally, I've never written any - I like DevIL, and it lets me load jpegs, bitmaps, and all the rest as well. Wrapped around DevIL, for a long time, I had a texture managing class which kept a reference count of each texture so that I didn't load it twice, but this still left me with the possibility of forgetting to unload it when I had finished with it, and generally having to remember to do cleanup code. In the world of memory management, auto_ptr and shared pointers take care of this for me, so I have wrapped my texture manager up still further, and come up with something similar to what I am posting here. The idea is to be able to write code which really is as simple as this:
#include "Texture.h"
...
Texture brickWallTexture("brickwall.tga");
brickWallTexture.Apply();
...




and not actually leak resources, load them twice, or anything else. There is no cleanup code, so you can't forget to add it. You can copy textures, pass them to classes, store them, forget them, load the same file twice, whatever, and you still only load each texture once, and the resources are released when you stop using it.
The source is only very slightly too long to inline in this post, so I've put it on a web page and linked it here. It is (intentionally!) missing the associated makefile. There are 2 pairs of .h/.cpp files, and one example.cpp file containing a main function. To use the classes yourself, you need DevIL. To use the example program, you also need SDL.
Things missing: No control over wrapping and filtering. No control over internal GL texture type (always uses RGBA). No multitexturing support. Some of these I have actually removed to make the code simpler and easier to read.
Have fun!

Share this post


Link to post
Share on other sites
Its doesnt look to bad, not really being an opengl. Lookin through the code seemed pretty straight forward Only one thing caught my eye as odd. Is there a reason why TexturePool has 2 public and 2 protected blocks?

Share this post


Link to post
Share on other sites
Thanks ;)

No, there's no particular reason, I just tend to keep my enums and embedded types at the top, my functions in the middle, and my data at the end, and even if two of them are public side by side, I still separate them.

Share this post


Link to post
Share on other sites
First, I'd like to name this approach to resource management as an "Implicit Resource Management" (IRM).
I've looked through the code and came up to several thoughts.
With this approach each resource type has a distinct hidden resource manager. Currently I'm dealing with Lightfeather 3D engine which has a resource manager too, a "typical" resource manager everyone seen in most 3D game/render engines.
A general visible resource manager can group various resources into groups. I use it to group various resources into a theme and load/unload it when I change the theme in my not-yet-finished Mahjong game.
This is the first drawback. Although, may be there is any way to solve it?
Apart from that, the example usage code in Example.cpp looks so much cool that I want to implement my sound manager as an IRM.
Thanks for the manager, squirm :)

PS. Also, I wanted to call the TexturePool an implicit singleton, but then recalled the "Design patterns" and understood it's just a static variable. Still cool.

[Edited by - kornerr on January 16, 2010 11:53:07 AM]

Share this post


Link to post
Share on other sites
I tried to implement sound manager as an IRM and faced two problems.

The first is RAII. We usually want to load resources used by a game before it starts to eliminate delays while playing. And we do not want them removed when refcount reaches zero, because five seconds later the resource may be needed again.
One solution to this is not to remove a resource when refcount reaches zero. But then we shift responsibility for loading/unloading a resource away from the resource class. This moves us back to a general resource manager.

The second is resource naming, or aliasing. In Lightfeather each resource can be given a name, i.e., an alias. This allows us to change path to a resource without a need to recompile the game if we keep alias to path mapping in some INI/XML file.
One solution to this, I think, is to introduce a virtual file system that will simply keep the mapping between alias and path.

Share this post


Link to post
Share on other sites
--- I think this is my record for oldest reanimated thread!
--- Also, the "squirm" entity appears to have died, so squirmy it is.

RAII vs preloading:
--- Create a <favourite container> of preloaded resources and stick all the ones you want to keep in it. They will unload again once the container is deleted. That way they can be preloaded per execution, or per level, or per character, or an appropriate mixture of those.


Resource naming, or aliasing:
--- That should just work, just change to using an alias instead of a path?

--- I will add a third problem - the main advantage from this is nice tidy succinct code and noone except the resource objects ever sees the manager. Encapsulation is good, right? Sadly, I do need the manager, because I sometimes want to see a list of all loaded resources. Making it available kills a lot of the elegance :/

--- I've not written my own manager for a while (I use other peoples) and I'm not sure what I'd do if I had to write one now from scratch. I like smart pointers so any manager would likely boil down to std::map<ResourceId, shared_ptr<Resource>> and it becomes a question of instantiation and ownership.

Share this post


Link to post
Share on other sites
While implementing SoundManager I faced another problem with the approach. It doesn't work with empty resources (when id = 0). On destructor call the manager will bark. And on copying it won't work either. But I need empty resources.

Share this post


Link to post
Share on other sites
What do you need empty resources for - and how exactly does that cause problems?


Either way, having a manager/cache hidden underwater like this is not a very flexible approach: it ties resources to always use a cache - and to always use that one hidden cache.

It's better to keep the cache visible, and to keep resources unaware of it. This allows you to cache resources when you need to, or to use multiple caches, or to avoid caching certain specific resources (such as, say, generated textures, or sound buffers used for recording).


And yeah, 5 years... I thought old threads were locked by default?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this