Building an Object Pool for Textures


Next, you should think about a problem that wasn't all that important when you were writing the Blockers game but could present itself as a problem now. What if you had three or four different objects that all used the same texture? In the Blockers game, you simply would have loaded the same texture three or four times, which does indeed work; however, I'm sure you can realize that the extra "wasted" space can't be a good thing. Instead of having a system like that, wouldn't it be so much nicer if you had a "cache" of textures so that whenever you created one, you would never re-create it again? That's what you should do now.

Building this object pool is actually pretty easy because you can use one of the existing classes in the .NET Framework to do the majority of the work for you, and that object is the HashTable. This class essentially maintains a "dictionary" (a key and pair value) using the hash code of the key (which theoretically is unique). You should use the filename of the texture you are trying to load as the key (because that will be unique), and naturally, the texture will be the value. Add a new code file to your application called ObjectPool.cs and add the code in Listing 11.7 to this new code file.

Listing 11.7. The Texture Pool Class
 using System; using System.IO; using System.Collections; using Microsoft.DirectX; using Microsoft.DirectX.Direct3D; namespace Tankers {     /// <summary>     /// The texture pool class     /// </summary>     class TexturePool     {         // Constant texture path         private const string TexturePath = "Textures\\";         // The hash table of valid textures         private static Hashtable textureTable = new Hashtable();         /// <summary>         /// Create a new texture, or return one from the pool         /// </summary>         /// <param name="file">Texture file to create</param>         /// <returns>A texture</returns>         public static Texture CreateTexture(Device renderDevice, string file)         {             // Make sure a texture was passed in             if ((file == null) || (file.Length == 0))             {                 // No texture                 return null;             }             // Before we create a texture, return one from the             // pool if it exists             string lowerCaseFile = file.ToLower();             if (textureTable.ContainsKey(lowerCaseFile))             {                 return textureTable[lowerCaseFile] as Texture;             }             // We've made it here, this is a new texture,             // Create the texture and add it to the pool             Texture t = TextureLoader.FromFile(renderDevice,                    GameEngine.MediaPath + TexturePath + file);             System.Diagnostics.Debug.Assert(t != null, "Created Texture is null",                 "Textures being loaded by the pool should never be null");             // Add it to the pool             textureTable.Add(lowerCaseFile, t);             return t;         }     } } 

That's an exceedingly simple method actually. You have a single static member variable, which is the hash table you're using to maintain the pool. If you've installed the code and media from the CD already, you'll notice that all the textures are stored within a Textures folder within the media folder. A constant defines that folder name from within this class. The class then defines a single public function, which takes in the name of the texture you're trying to create and returns the texture object.

Notice that (after a basic check to make sure you really are asking for a file) the code checks the hash table to see whether it contains the key already (the filename in all lowercase letters). If it does, it simply returns that texture to the caller, and it isn't created again. However, if that texture does not exist, it is created and then added to the hash table. The next time this method is called for the same file, the texture is returned from the cache rather than re-created.

The last thing you want to do is add some cleanup code. Because the hash table and textures are stored in a static variable, they don't really have a "lifetime" outside of the application's lifetime. It's logical to assume that you want to release all the textures simultaneously and only when the application is about to quit. You can add a single method (from Listing 11.8) to this class to perform this operation for you.

Listing 11.8. Releasing Textures from the Pool
 public static void ReleaseAllTextures() {     foreach(string s in textureTable.Keys)     {         // Simply dispose of each texture in the list         (textureTable[s] as Texture).Dispose();     }     // Clear the texture list     textureTable.Clear(); } 

Pretty basic stuff here: it simply goes through each "key" in the hash table, gets the texture from that, disposes it, and then clears the hash table. You should ensure that this code always gets called by adding this line to your OnDestroyDevice override back in the main game engine class. (It doesn't matter that you don't create any textures yet; when you do, they'll "automagically" get cleaned up.)

 // Clean up all textures TexturePool.ReleaseAllTextures(); 



Beginning 3D Game Programming
Beginning 3D Game Programming
ISBN: 0672326612
EAN: 2147483647
Year: 2003
Pages: 191
Authors: Tom Miller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net