Sign in to follow this  
phb5000

How do You manage your textures?

Recommended Posts

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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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()) { }
}

Share this post


Link to post
Share on other sites
Quote:
Original post by phb5000
Just wondering one thing though. Whats the technical advantage of using for example a hashtable compared to a normal array of objects?

Speed. When looking for a texture in a normal array, the time to search increases lineary with the amount of objects. So, when there are 10 times more objects, it takes 10 times the time to search through them. (Jargon: linear search is a O(n)-algorithm).

Now say we sort this list of objects. You can then look in the middle of the array, see if your search objects is before or after the current object and go on that way. This way it takes less time to search. (Jargon: binary search is O(log n)).

In a hashtable this search time is even less, because of the way the objects are stored.

Share this post


Link to post
Share on other sites
Hashtables seem like the clear choice,
Thanks for the info!

One more question regarding the actual management of textures. Do textures need to be reloaded when for example the D3D OnDeviceReset callback is received? Or does this only apply to vertex/index buffers etc. How about Sprites?

I never really understood What was to be reset during a device reset.

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