1 //------------------------------------------------------------------------------
2 // File : SkyDynamicTextureManager.cpp
3 //------------------------------------------------------------------------------
4 // SkyWorks : Copyright 2002 Mark J. Harris and
5 // The University of North Carolina at Chapel Hill
6 //------------------------------------------------------------------------------
7 // Permission to use, copy, modify, distribute and sell this software and its
8 // documentation for any purpose is hereby granted without fee, provided that
9 // the above copyright notice appear in all copies and that both that copyright
10 // notice and this permission notice appear in supporting documentation.
11 // Binaries may be compiled with this software without any royalties or
14 // The author(s) and The University of North Carolina at Chapel Hill make no
15 // representations about the suitability of this software for any purpose.
16 // It is provided "as is" without express or
19 * @file SkyDynamicTextureManager.cpp
21 * Implementation of a repository for check out and check in of dynamic textures.
24 #pragma warning( disable : 4786 )
26 #include "SkyDynamicTextureManager.hpp"
27 #include "SkyTexture.hpp"
28 #include "SkyContext.hpp"
30 #pragma warning( disable : 4786 )
32 //! Set this to 1 to print lots of dynamic texture usage messages.
33 #define SKYDYNTEXTURE_VERBOSE 0
34 //! The maximum number of textures of each resolution to allow in the checked in pool.
35 #define SKYDYNTEXTURE_TEXCACHE_LIMIT 32
37 //------------------------------------------------------------------------------
38 // Function : SkyDynamicTextureManager::SkyDynamicTextureManager
40 //------------------------------------------------------------------------------
42 * @fn SkyDynamicTextureManager::SkyDynamicTextureManager()
45 SkyDynamicTextureManager::SkyDynamicTextureManager()
46 #ifdef SKYDYNTEXTURE_VERBOSE
47 : _iNumTextureBytesUsed(0),
48 _iNumTextureBytesCheckedIn(0),
49 _iNumTextureBytesCheckedOut(0)
52 for (int i = 0; i < 11; ++i)
53 for (int j = 0; j < 11; ++j)
54 _iAvailableSizeCounts[i][j] = 0;
58 //------------------------------------------------------------------------------
59 // Function : SkyDynamicTextureManager::~SkyDynamicTextureManager
61 //------------------------------------------------------------------------------
63 * @fn SkyDynamicTextureManager::~SkyDynamicTextureManager()
66 SkyDynamicTextureManager::~SkyDynamicTextureManager()
68 for ( TextureSet::iterator subset = _availableTexturePool.begin();
69 subset != _availableTexturePool.end();
71 { // iterate over texture subsets.
72 for ( TextureSubset::iterator texture = (*subset).second->begin();
73 texture != (*subset).second->end();
76 texture->second->Destroy();
77 delete texture->second;
79 subset->second->clear();
81 _availableTexturePool.clear();
83 for ( TextureSubset::iterator texture = _checkedOutTexturePool.begin();
84 texture != _checkedOutTexturePool.end();
87 texture->second->Destroy();
88 delete texture->second;
90 _checkedOutTexturePool.clear();
94 //------------------------------------------------------------------------------
95 // Function : SkyDynamicTextureManager::CheckOutTexture
97 //------------------------------------------------------------------------------
99 * @fn SkyDynamicTextureManager::CheckOutTexture(unsigned int iWidth, unsigned int iHeight)
100 * @brief Returns a texture from the available pool, creating a new one if necessary.
102 * Thi texture returned by this method is checked out: it will be maintained in a
103 * checked out pool until it is checked in with CheckInTexture(). The texture is owned
104 * by the SkyDynamicTextureManager -- it should not be deleted by another object. Checked out
105 * textures can be modified (copied, or rendered to, etc.), but should not be reallocated
106 * or resized. All checked out textures will be deleted when the SkyDynamicTextureManager
107 * is destroyed, so this manager should be destroyed only after rendering ceases.
109 SkyTexture* SkyDynamicTextureManager::CheckOutTexture(unsigned int iWidth,
110 unsigned int iHeight)
112 int iWidthLog, iHeightLog;
113 iWidthLog = SkyGetLogBaseTwo(iWidth);
114 iHeightLog = SkyGetLogBaseTwo(iHeight);
116 // first see if a texture of this resolution is available:
117 // find the subset of textures with width = iWidth, if it exists.
118 TextureSet::iterator subset = _availableTexturePool.find(iWidth);
119 if (subset != _availableTexturePool.end())
120 { // found the iWidth subset
121 // now find a texture with height = iHeight:
122 TextureSubset::iterator texture = (*subset).second->find(iHeight);
123 if (texture != (*subset).second->end())
125 // extract the texture
126 SkyTexture *pTexture = (*texture).second;
127 (*texture).second = NULL;
128 // first remove it from this set.
129 (*subset).second->erase(texture);
130 // now add it to the checked out texture set.
131 _checkedOutTexturePool.insert(TextureSubset::value_type(pTexture->GetID(), pTexture));
133 // update checked out/in amount.
134 #if SKYDYNTEXTURE_VERBOSE
135 _iNumTextureBytesCheckedIn -= iWidth * iHeight * 4;
136 _iNumTextureBytesCheckedOut += iWidth * iHeight * 4;
137 printf("CHECKOUT: %d x %d\n", iWidth, iHeight);
139 _iAvailableSizeCounts[iWidthLog][iHeightLog]--;
140 // we're now free to give this texture to the user
144 { // we didn't find an iWidth x iHeight texture, although the iWidth subset exists
145 // create a new texture of the appropriate dimensions and return it.
146 SkyTexture *pNewTexture = CreateDynamicTexture(iWidth, iHeight);
147 _checkedOutTexturePool.insert(TextureSubset::value_type(pNewTexture->GetID(),
149 #if SKYDYNTEXTURE_VERBOSE
150 _iNumTextureBytesCheckedOut += iWidth * iHeight * 4;
157 { // we don't yet have a subset for iWidth textures. Create one.
158 TextureSubset *pSubset = new TextureSubset;
159 _availableTexturePool.insert(TextureSet::value_type(iWidth, pSubset));
160 // now create a new texture of the appropriate dimensions and return it.
161 SkyTexture *pNewTexture = CreateDynamicTexture(iWidth, iHeight);
162 _checkedOutTexturePool.insert(TextureSubset::value_type(pNewTexture->GetID(), pNewTexture));
164 #if SKYDYNTEXTURE_VERBOSE
165 _iNumTextureBytesCheckedOut += iWidth * iHeight * 4;
172 //------------------------------------------------------------------------------
173 // Function : SkyDynamicTextureManager::CheckInTexture
175 //------------------------------------------------------------------------------
177 * @fn SkyDynamicTextureManager::CheckInTexture(SkyTexture *pTexture)
178 * @brief Returns a checked-out texture to the available pool.
180 * This method removes the checked out texture from the checked out pool if it is
181 * checked out, and then checks it in to the available pool.
183 void SkyDynamicTextureManager::CheckInTexture(SkyTexture *pTexture)
185 // first see if the texture is in the checked out pool.
186 TextureSubset::iterator coTexture = _checkedOutTexturePool.find(pTexture->GetID());
187 if (coTexture != _checkedOutTexturePool.end())
188 { // if it is there, remove it.
189 _checkedOutTexturePool.erase(coTexture);
190 _iNumTextureBytesCheckedOut -= pTexture->GetWidth() * pTexture->GetHeight() * 4;
193 // Don't cache too many unused textures.
194 int iWidthLog, iHeightLog;
195 iWidthLog = SkyGetLogBaseTwo(pTexture->GetWidth());
196 iHeightLog = SkyGetLogBaseTwo(pTexture->GetHeight());
197 if (_iAvailableSizeCounts[iWidthLog][iHeightLog] >= SKYDYNTEXTURE_TEXCACHE_LIMIT)
199 #if SKYDYNTEXTURE_VERBOSE
200 _iNumTextureBytesUsed -= pTexture->GetWidth() * pTexture->GetHeight() * 4;
201 printf("%dx%d texture DESTROYED.\n\t Total memory used: %d bytes.\n",
202 pTexture->GetWidth(), pTexture->GetHeight(), _iNumTextureBytesUsed);
206 SAFE_DELETE(pTexture);
210 // now check the texture into the available pool.
211 // find the width subset:
212 TextureSet::iterator subset = _availableTexturePool.find(pTexture->GetWidth());
213 if (subset != _availableTexturePool.end())
214 { // the subset exists. Add the texture to it
215 (*subset).second->insert(TextureSubset::value_type(pTexture->GetHeight(), pTexture));
216 _iNumTextureBytesCheckedIn += pTexture->GetWidth() * pTexture->GetHeight() * 4;
218 _iAvailableSizeCounts[iWidthLog][iHeightLog]++;
221 { // subset not found. Create it.
222 TextureSubset *pSubset = new TextureSubset;
223 // insert the texture.
224 pSubset->insert(TextureSubset::value_type(pTexture->GetHeight(), pTexture));
225 // insert the subset into the available pool
226 _availableTexturePool.insert(TextureSet::value_type(pTexture->GetWidth(), pSubset));
228 #if SKYDYNTEXTURE_VERBOSE
229 _iNumTextureBytesCheckedIn += pTexture->GetWidth() * pTexture->GetHeight() * 4;
230 _iAvailableSizeCounts[iWidthLog][iHeightLog]++;
238 //------------------------------------------------------------------------------
239 // Function : SkyDynamicTextureManager::CreateDynamicTexture
241 //------------------------------------------------------------------------------
243 * @fn SkyDynamicTextureManager::CreateDynamicTexture(unsigned int iWidth, unsigned int iHeight)
244 * @brief Allocate a new dynamic texture object of the given resolution.
246 * This method is used by CheckOutTexture() when it can't find an available texture of
247 * the requested resolution. It can also be called externally, but will result in an
248 * unmanaged texture unless the new texture is subsequently checked in using CheckInTexture().
250 SkyTexture* SkyDynamicTextureManager::CreateDynamicTexture(unsigned int iWidth, unsigned int iHeight)
253 glGenTextures(1, &iID);
254 SkyTexture *pNewTexture = new SkyTexture(iWidth, iHeight, iID);
255 glBindTexture(GL_TEXTURE_2D, pNewTexture->GetID());
256 // set default filtering.
257 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
258 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
259 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
260 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
261 // create an empty buffer
262 unsigned char *pData = new unsigned char[iWidth * iHeight * 4];
264 // allocate the texture
265 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, iWidth, iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pData );
269 // update the used texture bytes...
270 _iNumTextureBytesUsed += iWidth * iHeight * 4;
271 #if SKYDYNTEXTURE_VERBOSE
272 printf("New %dx%d texture created.\n\t Total memory used: %d bytes\n", iWidth, iHeight, _iNumTextureBytesUsed);
273 printf("\tTotal memory checked in: %d\n", _iNumTextureBytesCheckedIn);
274 printf("\tTotal memory checked out: %d\n", _iNumTextureBytesCheckedOut);