How do You manage your textures?

Started by
11 comments, last by phb5000 17 years, 12 months ago
I would like some general information regarding texture management and implementation suggestions/advice. (Doesnt have to be API / Language specific)
Advertisement
What part are you referring to? Loading them and managing them in memory, uploading them to the graphics card, or something else?

I use D3D which manages uploading to the card for me, and I just reference count my textures. If a texture isn't loaded, the manager will loaded it when requested. At the moment, I never free the textures when they reach a reference count of 0 (for performance reasons), but it's easy enough to do.
I'm not sure if this is what PHB is asking about, but here's a (atleast very similiar) question.

If you have two objects with the same textures, then how do you avoid loading its texture twice and how do you make the same texture available to both objects?
I'm referring to the actual interaction with the textures. The project that I'm currently working on consists of a lot of different textures (not necessarily from different files, rather different regions in an image).

Therefore, I've built a small texture mananger class, containing an array of my own texture object classes. However, I'm having a hard time deciding whether to define them as structs or classes.

Since my project is designed as a reusable component it will be unwise to request a texture based on index. Currently I give each texture a name, and request a texture with that given name.

I think an ideal texture manager would organize textures in a 'tree' if, as in my case, I have a lot of textures to take care of.

For example:

|---Group 1
|---Texture 1
|---Texture 2
|---Texture 3
|---Group 2
|---Texture 1
|---Texture 2
|---Sub Group 1
|---Texture 1
|---Texture 2
|---Texture 3
|---Group 3
...


Good Idea?
Bad Idea?

Suggesions?
Code::Blocks IDE has a project tree that can be customized (ie., adding groups for certin file extensions).
heres what i have
struct Texture
{
string name; // filename
GLuint textureID; // its opengl texture id
...
};

struct TextureManager
{
vector<Texture> textureContainer;
....
};

i make sure that
textureContainer[ X ] == textureID
Something like zedzeek's is the easiest solution – store filename/textureID pairs, and when you're asked for a texture (by filename) look to see if it has already been loaded, returning the existing ID if so.

In C# you could do it simply with a Hashtable :) ... I'm sure there's something in the STL that would handle that, too.
std::map<std::string, Texture> myTextures; ;)

I use the same layout, works pretty neatly, though there are almost always better ways of doing it im sure :P
I also use the std::map<std::string, Texture> method. As for you question concerning how to implement the Texture object, I just made the image attributes and ID private, then created a variety of rendering functions that handle all of the binding and preparation required in OGL (and I'm sure D3D) to render a texture.
Pardon the slight mess. I wrote the majority while learning C#, and then hacked on a few bits as needed. This makes use of a number of classes which are not included.

public class d3d_image_manager: image_manager{        protected Dictionary<string, WeakReference>             texmap = new Dictionary<string, WeakReference>();        protected List<string>                                  LoadingInThread = new List<string>();        private   Dictionary<string, List<d3d_image> >          WaitingForThreadLoad = new Dictionary<string, List<d3d_image> >();        protected Dictionary<int, string>                       AirlockMap = new Dictionary<int, string>();                private delegate basero brstr(string s);        private Texture texturefromfile(string filename) {            Texture rtn;            lock (texmap) {                if (texmap.ContainsKey(filename)) {                    if (texmap[filename].IsAlive) {                        return (texmap[filename].Target as Texture);                    } else {                        texmap.Remove(filename);                    }                }                if (d3d_guiroot.d3droot != null) {                    rtn = TextureLoader.FromFile(d3d_guiroot.d3droot.d3ddev, filename);                    // TODO: catch exceptions;                    texmap.Add(filename, new WeakReference(rtn));                    return (rtn);                } else {                    local_log.log("Image manager unable to load from file \"" + filename + "\" d3droot uninitialized.\n");                    return (null);                }            }        }                protected void AirlockCallback(string filename, int locknum) {            lock (this) {                if (texmap.ContainsKey(filename)) {                    Airlock.Extract(locknum);                } else {                    texmap.Add(filename, new WeakReference(Airlock.Retrieve(locknum)));                    if (WaitingForThreadLoad.ContainsKey(filename)) {                        Texture t=Airlock.Retrieve(locknum) as Texture;                        foreach (d3d_image di in WaitingForThreadLoad[filename]) {                            oob_execs.Add(delegate() {                                di.reset_tex(t);                            });                        }                                                Airlock.Extract(locknum);                    } else {                        // hacky.                        //  Since this stores WeakRefs, the image we've painstakingly                        //  loaded in the background might be Collected                        //  by the time the app loads it properly.                        //                        //  This leaves the image in the airlock for 2 minutes if                         //  guiroot is non-null.                        //                        //  If it's not loaded by then, the airlock will release it.                        //                        if (ro_root.guiroot != null) {                            oob_execs.Add(new oob_execs.oob_type(delegate() {                                (new renderable.TimedEvent(delegate() { Airlock.Extract(locknum); }, 120000)).push_onto(ro_root.guiroot);                            }));                                                    } else {                            Airlock.Extract(locknum);                        }                    }                }                AirlockMap.Remove(locknum);                WaitingForThreadLoad.Remove(filename);                LoadingInThread.Remove(filename);            }        }                private basero Background(string filename){            if (AirlockMap.ContainsValue(filename)) {                return (null);            }            int lockn=Airlock.Alloc();            AirlockDepositLoader adl=new AirlockDepositLoader(filename,lockn);            Airlock.AddTrigger(lockn,delegate(int ln){this.AirlockCallback(filename,ln);});            AirlockMap.Add(lockn, filename);            LoadingInThread.Add(filename);            System.Threading.Thread adlthread=new System.Threading.Thread(adl.Main);            adlthread.Start();            return (null);        }        public basero full_image(string filename) {            //            // Loads texture and sets new d3dimage to display the entirety of it.            //            // TODO: investigate possible synch issues, and impact of this Contains.            d3d_image rtn;            if (LoadingInThread.Contains(filename)) {                rtn = new d3d_image();                if (WaitingForThreadLoad.ContainsKey(filename)) {                    WaitingForThreadLoad[filename].Add(rtn);                } else {                    List<d3d_image> l = new List<d3d_image>();                    l.Add(rtn);                    WaitingForThreadLoad.Add(filename, l);                }                return (rtn);            }            return (new d3d_image(texturefromfile(filename)));        }        protected delegate basero brvd();        public basero solid() {            return (new d3d_image());        }        public d3d_image_manager(logging_strategy ls)            : base(ls) {            def_interpreter.Add(new cmd_del("full_image",  new brstr(this.full_image)));            def_interpreter.Add(new cmd_del("solid", new brvd(this.solid)));            def_interpreter.Add(new cmd_del("background", new brstr(this.Background)));            Add(new resource_definition("solid", "solid"));            if (manager == null) {                manager = this;            }        }        public d3d_image_manager() : this(new logging_strategy()) { }    }

This topic is closed to new replies.

Advertisement