A Possible SolutionEnter the Singleton. A Singleton is an object that has at most one instance of itself in memory at any given time. Voodoo witchcraft?! Arcane magic's!? Not really. In code, a Singleton looks like this: // In the header file class CSingleton { static class CSingleton *m_Singleton; static Csingleton *GetSingleton (void); }; // In the implementation file CSingleton *CSingleton::m_Singleton = 0; CSingleton *CSingleton::GetSingleton (void) { if (m_Singleton == 0) m_Singleton = new CSingleton; return m_Singleton; } By keeping a pointer itself as a static variable, the Singleton object isn't 're-created' with every instance of the class. So with the first call to GetSingleton, a Csingleton object pointer is allocated in memory, or the static variable m_Singleton. Does that make any sense? If not, don't worry, these links might help explain things a little better... http://www.codeproject.com/tips/singleton.asp
Well now that you are a complete expert on the concept of a Singleton, let's start working on our OpenGL texture manager, shall we? The Codeclass CTextureManager { public : CTextureManager (void); ~CTextureManager (void); static CTextureManager &GetSingleton (void); private : // This is called automaticaly! Don't do it yourself! static void Initialize (void); public : static void Destroy (void); public : // Usage / Implumentation int LoadTexture (const char *szFilename, int nTextureID = -1); int LoadTextureFromMemory (UBYTE *pData, int nWidth, int nHeight, int nBPP, int nTextureID = -1); void FreeTexture (int nID); void FreeAll (void); public : // Debug / Utilitarian char *GetErrorMessage (void); int GetNumTextures (void); int GetAvailableSpace (void); int GetTexID (int nIndex); private : static CTextureManager *m_Singleton; UBYTE *LoadBitmapFile (const char *filename, int &nWidth, int &nHeight, int &nBPP); UBYTE *LoadTargaFile (const char *filename, int &nWidth, int &nHeight, int &nBPP); int GetNewTextureID (int nPossibleTextureID); // get a new one if one isn't provided bool CheckSize (int nDimension); private : char szErrorMessage [80]; // they arn't bugs, their features! int nNumTextures; int nAvailable; // available space in the nTexID array int *nTexIDs; }; Get the full class header and implementation here. As you can see, the code itself is very self-explanatory. In fact, the only crucial functions are LoadTexture(), LoadTextureFromMemory(), FreeTexture(), and FreeAll(). The first two (as you would guess) load and register new textures into OpenGL, while the last two free textures from memory. Within those four methods lies the code to handle the variables nNumTextures, nAvailable and nTexIDs. These variables respectively hold the number of loaded textures, amount of available slots in the texture ID list, and the lift itself. The class itself has the functionality to load Targa (TGA) files and 24-bit color Bitmaps (BMP), however, it can be easily expanded to incorporate other file types via new methods for loading the graphics files internally or via the LoadTextureFromMemory() function. Either way, this Singleton class will all but "hold your hand" when dealing with textures in OpenGL. The most crucial part of the code is that all of the 'real' data is in the CTextureManager::m_Singleton object. In other words, if you want to access nNumTextures, you actually want m_Singleton->nNumTextures! This is all because the class is still a Singleton, and to be such, all of the data must be stored in one place: the Singleton pointer. In ConclusionThe topics covered in this article may seem overwhelming at first, but keep in mind that having a Singleton texture manager is a good idea in the long run. As the number of graphics and textures used in your game begins to grow exponentially, a solid ID convention and an object to oversee texture operations will save MANY hours of bug tracking. Questions? Comments? Flames?
|