   texture handling
  Hi,I wanted to change the way that textures are loaded and handled in my game. The way it is know changing image filename requies me to change all object files using it. Moreover if I load few objects using same image file, it will be loaded multiple times into memory.I was thinking on a way improve this and i came up with few ideas:1. Make object files refer textures by texture name not an image filepath. This would allow game to easily check which of textures are already loaded.2. Make simple config file containig relations between texture name and image file it relates to, or even definition of texture sections(image filepath + mapping data). This would move mapping stuff out off object files so i could work on mapping and images without touching object files.And here i got stuck unable to decide how to refer to this texture sections. (Note: now i'm talking about situation after everything is loaded, and game enters main loop). First way is to refer to them by giving each texture section an id and putting it in - for example - map. Then give every object which needs partcular section it's id. Although it would be safe it seems pretty slow.Second way is to give object pointers to texture sections, it seems much faster to access but on the other hand it might cause some nasty bugs(if i find out that there's no section with given id i can simply handle the situation, but trying to access unexisting object by pointer... well i guess you know what happens ;) ).So which solution do you use/advice to use.Texture section once loaded is represened as a structure containing array of mapping coordinates and an id assigned to texture by opengl.I'm using C++ and OpenGL.[Edited by - Shuger on September 7, 2007 9:50:28 AM]
Quote:Original post by Shuger1. Make object files refer textures by texture name not an image filepath. This would allow game to easily check which of textures are already loaded.Does that really help you? If you change the texture name still you have to change all references to it just as you did before.Quote:2. Make simple config file containig relations between texture name and image file it relates to, or even definition of texture sections(image filepath + mapping data). This would move mapping stuff out off object files so i could work on mapping and images without touching object files.When you say 'mapping' do you mean texture-mapping?Do you keep your texture-coordinates associated with the texture?  Normally the tex-coords are kept with the vertices in the mesh data.Quote:First way is to refer to them by giving each texture section an id and putting it in - for example - map. Then give every object which needs partcular section it's id. Although it would be safe it seems pretty slow.It's probably not as slow as you imagine it to be.Quote:Second way is to give object pointers to texture sections, it seems much faster to access but on the other hand it might cause some nasty bugs(if i find out that there's no section with given id i can simply handle the situation, but trying to access unexisting object by pointer... well i guess you know what happens ;) ).Are you saying an object could own a pointer that wasnt valid?  If so, then I would ask: Where did it get this pointer from and why did it get given a duff pointer?Quote:So which solution do you use/advice to use.I would create a map that relates a file-path (or the texture name) to the texture itself, like std::map<std::string, Texture>.  Everytime an attempt to load a texture is made I first check to see whether it has already been loaded and if so I just return a pointer/iterator to the texture thus preventing the same texture being loaded more than once.Every object knows the name of the texture they want and they need only one time retrieve a pointer to it from the map and then they just use that pointer from that point on.This works provided you don't unload any textures (becuase that would invalidate pointers).  If you need to do this then you can change to use smart-pointers (or just use them in the first place).   ;  This is how I do it:1. Loading resources (including textures) and keeping them in memoryI use STL's map class to map strings which are full resource paths to resource pointers. The reason is because checking a map to see if a resource is already loaded is extremely fast, and since this check will be made every time you are loading a resource it makes a difference. The reason I use full paths is because it is possible to load two resources from two different paths and they might end up having the same relative name, which will cause the wrong resource to be returned.#include <map>using namespace std;template <class TResource*> class ResourceManager{private:    map<string, TResource*> m_mapResources;public:    // Skipping c-tor and d-tor, not interesting...    // Resource Management    TResource* LoadResource(LPCWSTR pszPath)    {// Make sure pszPath is a full path in case it's relative// ...// Check m_mapResources to see if this resource is already loadedmap<string, TResource*>::iterator pos = m_mapResources.find(pszPath);if(pos != m_mapResources.end()) return *pos;// If not loaded, do soTResource* pResource = new TResource;if(!pResource->Load(pszPath)){// Error handling code removedreturn NULL;}m_mapResources[pszPath] = pResource;return pResource;}// Other resource management functions...}Every resource is derived from a special Resource base class with a Load() function. Each resource overloads this function to properly load itself from a file given file path.Also, the ResourceManager is instantiated from a template once for every resource type, as you can tell from the fact that it's a template. I personally keep several objects of this class in my Engine class. Some people think that having an Engine class is lame, if you are one of them, just make it global or something.2. Using resources with levelsI use the "indices" method already described. My level has resource tables - one for textures, one for ambient sounds, one for background music, etc. These tables contain pointers to resources. The objects on the level, in turn, have indices to entries in the tables. For example, one of the tiles might have a texture index of 1, which will refer to the second entry in the level's texture table.This is done because this mechanism makes is very easy to load and save levels - every tile only needs to read/write an index when the level is serialized. If there was no index (if you used a pointer), you would have to write out full name of resource as a string. Even for a map of 256x256 tiles, that's a lot of strings. It would increase your load time and level file size. With indices, all you have to do is store each resource filename used in a level once in the level's resource table, and at load time replace the filename with a pointer to that resource once its loaded.Now to mention the optimization. If you ever seen the 2D tile map sample from directX SDK you will know that they used a "cached tile buffer" optimization. Basically, every time the visible portion of world changes (i.e. you scroll the view), you take every visible tile from your 2-d array of tiles and copy it into a 1-d array, which is a tile buffer. This has an advantage of a faster access time because the tile buffer is contiguous, and it might even fit into CPU's L2 cache.I use this optimization in my engine, and I take advantage of it to introduce further optimizations: when I cache a tile into a tile buffer I not only copy the tile's data, but I also 'expand' it. Firstly, I cache the tile's pixel coordinates on screen so that I don't have to re-calculate them. I also turn the index-to-texture into a pointer-to-texture, so that once the tile is cached, I can directly use the pointer, which addresses your speed concerns about using indices versus pointers.3. Where to store texture coordinates?I am assuming we are talking about a 2-d game engine. In my engine, I use "texture sheets" which are basically texture atlasses. A texture sheet is a resource, just like a texture. It contains a texture, as well as an array of "cells". And each of those cells has texture coordinates. My engine is 2D, so I use pixel coordinates. The concept of texture sheets allows two things:a) Reuse of texture coordinates, which saves memory spaceb) (Again) Reuse of texture coordinates, so that people who design levels don't constantly have to re-enter themThe texture sheet file simply contains the texture filename and a serialized array of cells with their texture coordinates. When it's read into memory, it ends up with a pointer to the texture it uses.Each tile on the level then contains two indices: one index that references an entry in level's texturesheet table, and a second index that references a specific cell on the texturesheet, that has the texture coordinates. When the tile is cached into a buffer, both of these indices simply become one pointer to the texturesheet cell that tile uses. Each texturesheet cell contains a pointer to its parent texturesheet (which in turn contains a pointer to texture). So you have the pointer to texture, texture coordinates, and the destination coordinates (remember, each tile caches its pixel position on screen when it gets copied into the buffer). That's enough info to render a tile.   