]> git.mxchange.org Git - simgear.git/blob - simgear/scene/sky/clouds3d/SkyDynamicTextureManager.cpp
Clouds3D crashes because there is no Light
[simgear.git] / simgear / scene / sky / clouds3d / SkyDynamicTextureManager.cpp
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 
12 // restrictions. 
13 //
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 
17 // implied warranty.
18 /**
19  * @file SkyDynamicTextureManager.cpp
20  * 
21  * Implementation of a repository for check out and check in of dynamic textures.
22  */
23
24 #pragma warning( disable : 4786 )
25
26 #include "SkyDynamicTextureManager.hpp"
27 #include "SkyTexture.hpp"
28 #include "SkyContext.hpp"
29
30 #pragma warning( disable : 4786 )
31
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
36
37 //------------------------------------------------------------------------------
38 // Function               : SkyDynamicTextureManager::SkyDynamicTextureManager
39 // Description      : 
40 //------------------------------------------------------------------------------
41 /**
42  * @fn SkyDynamicTextureManager::SkyDynamicTextureManager()
43  * @brief Constructor.
44  */ 
45 SkyDynamicTextureManager::SkyDynamicTextureManager()
46 #ifdef SKYDYNTEXTURE_VERBOSE
47 : _iNumTextureBytesUsed(0),
48   _iNumTextureBytesCheckedIn(0),
49   _iNumTextureBytesCheckedOut(0)
50 #endif
51 {
52   for (int i = 0; i < 11; ++i)
53     for (int j = 0; j < 11; ++j)
54       _iAvailableSizeCounts[i][j] = 0;
55 }
56
57
58 //------------------------------------------------------------------------------
59 // Function               : SkyDynamicTextureManager::~SkyDynamicTextureManager
60 // Description      : 
61 //------------------------------------------------------------------------------
62 /**
63  * @fn SkyDynamicTextureManager::~SkyDynamicTextureManager()
64  * @brief Destructor.
65  */ 
66 SkyDynamicTextureManager::~SkyDynamicTextureManager()
67 {
68   for ( TextureSet::iterator subset = _availableTexturePool.begin();
69         subset != _availableTexturePool.end();
70         ++subset )
71   { // iterate over texture subsets.
72     for ( TextureSubset::iterator texture = (*subset).second->begin(); 
73           texture != (*subset).second->end(); 
74           ++texture )
75     {
76       texture->second->Destroy();
77       delete texture->second;
78     }
79     subset->second->clear();
80   }
81   _availableTexturePool.clear();
82
83   for ( TextureSubset::iterator texture = _checkedOutTexturePool.begin();
84         texture != _checkedOutTexturePool.end();
85         ++texture )
86   {
87     texture->second->Destroy();
88     delete texture->second;
89   }
90   _checkedOutTexturePool.clear();
91 }
92
93
94 //------------------------------------------------------------------------------
95 // Function               : SkyDynamicTextureManager::CheckOutTexture
96 // Description      : 
97 //------------------------------------------------------------------------------
98 /**
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.
101  * 
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.
108  */ 
109 SkyTexture* SkyDynamicTextureManager::CheckOutTexture(unsigned int iWidth, 
110                                                       unsigned int iHeight)
111 {
112   int iWidthLog, iHeightLog;
113   iWidthLog = SkyGetLogBaseTwo(iWidth);
114   iHeightLog = SkyGetLogBaseTwo(iHeight);
115
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())
124     { //  found one!
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));
132
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);
138 #endif
139       _iAvailableSizeCounts[iWidthLog][iHeightLog]--;
140       // we're now free to give this texture to the user
141       return pTexture;
142     }
143     else
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(), 
148                                                               pNewTexture));
149 #if SKYDYNTEXTURE_VERBOSE
150       _iNumTextureBytesCheckedOut += iWidth * iHeight * 4;
151 #endif
152
153       return pNewTexture;
154     }
155   }
156   else
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));
163    
164 #if SKYDYNTEXTURE_VERBOSE
165     _iNumTextureBytesCheckedOut += iWidth * iHeight * 4;
166 #endif
167     return pNewTexture;
168   }
169 }
170
171
172 //------------------------------------------------------------------------------
173 // Function               : SkyDynamicTextureManager::CheckInTexture
174 // Description      : 
175 //------------------------------------------------------------------------------
176 /**
177  * @fn SkyDynamicTextureManager::CheckInTexture(SkyTexture *pTexture)
178  * @brief Returns a checked-out texture to the available pool.
179  * 
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.
182  */ 
183 void SkyDynamicTextureManager::CheckInTexture(SkyTexture *pTexture)
184 {
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;
191   }
192
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)
198   {
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);
203 #endif
204
205     pTexture->Destroy();
206     SAFE_DELETE(pTexture);
207     return;
208   }
209
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;
217
218     _iAvailableSizeCounts[iWidthLog][iHeightLog]++;
219   }
220   else
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));
227
228 #if SKYDYNTEXTURE_VERBOSE
229     _iNumTextureBytesCheckedIn += pTexture->GetWidth() * pTexture->GetHeight() * 4;
230     _iAvailableSizeCounts[iWidthLog][iHeightLog]++;
231 #endif
232   }
233
234   pTexture = NULL;
235 }
236
237
238 //------------------------------------------------------------------------------
239 // Function               : SkyDynamicTextureManager::CreateDynamicTexture
240 // Description      : 
241 //------------------------------------------------------------------------------
242 /**
243  * @fn SkyDynamicTextureManager::CreateDynamicTexture(unsigned int iWidth, unsigned int iHeight)
244  * @brief Allocate a new dynamic texture object of the given resolution.
245  * 
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().
249  */ 
250 SkyTexture* SkyDynamicTextureManager::CreateDynamicTexture(unsigned int iWidth, unsigned int iHeight)
251 {
252   unsigned int iID;
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];
263
264   // allocate the texture
265   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, iWidth, iHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, pData );
266
267   delete [] pData;
268
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);
275 #endif
276
277   return pNewTexture;
278 }