]> git.mxchange.org Git - simgear.git/blob - simgear/scene/sky/bbcache.cxx
55a2562d0d6feeabe5d3d13f18cd1a6db400c524
[simgear.git] / simgear / scene / sky / bbcache.cxx
1 // Billboard helper class
2 //
3 // Written by Harald JOHNSEN, started April 2005.
4 //
5 // Copyright (C) 2005  Harald JOHNSEN - hjohnsen@evc.net
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
20 //
21 //
22
23 #ifdef HAVE_CONFIG_H
24 #  include <simgear_config.h>
25 #endif
26
27 #include <simgear/compiler.h>
28 #include <simgear/debug/logstream.hxx>
29
30 #include <plib/sg.h>
31 #include <plib/ssg.h>
32 #include <simgear/screen/extensions.hxx>
33 #include <simgear/screen/RenderTexture.h>
34 #include SG_GLU_H
35
36 #include "bbcache.hxx"
37
38
39 /*
40 memory usage :
41 size          1 tex       8 tex       32 tex      64 tex
42 64x64x4        16k        128k        512k         1Mo
43 128x128x4      64k        512k        2Mo          4Mo
44 256x256x4     256k        2Mo         8Mo         16Mo
45 */
46
47 void SGBbCache::freeTextureMemory(void) {
48
49         if( bbListCount ) {
50                 for(int i = 0 ; i < bbListCount ; i++) {
51                         bbList[i].cldID = 0;
52                         if(bbList[i].texID)
53                                 glDeleteTextures(1, & bbList[i].texID);
54                 }
55                 delete [] bbList;
56         }
57         bbListCount = 0;
58         cacheSizeKb = 0;
59         textureWH   = 0;
60 }
61
62 bool SGBbCache::allocTextureMemory(int cacheCount, int textureDimension) {
63         textureWH = textureDimension;
64         bbListCount = cacheCount;
65         bbList = new bbInfo[bbListCount];
66         for(int i = 0 ; i < bbListCount ; i++) {
67                 bbList[i].cldID = 0;
68                 bbList[i].texID = 0;
69         glGenTextures(1, &bbList[i].texID);
70         glBindTexture(GL_TEXTURE_2D, bbList[i].texID);
71         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 
72                          textureDimension, textureDimension, 0, GL_RGB, GL_FLOAT, NULL);
73
74         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
75         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
76         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
77         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
78         }
79     glBindTexture(GL_TEXTURE_2D, 0);
80         cacheSizeKb = (textureDimension * textureDimension * 4);
81         cacheSizeKb *= cacheCount;
82         cacheSizeKb /= 1024;
83         if(rtAvailable) {
84                 if( rt->BeginCapture() ) {
85                         glViewport(0, 0, textureDimension, textureDimension);
86                         rt->EndCapture();
87                 }
88         }
89         return true;
90 }
91
92 SGBbCache::SGBbCache(void) :
93         bbListCount(0),
94         cacheSizeKb(0),
95         textureWH(0),
96         builtBBCount(0),
97         rt(0),
98         rtAvailable(false),
99         frameNumber(0),
100         maxImpostorRegenFrame(20)
101 {
102 }
103
104 SGBbCache::~SGBbCache(void) {
105         if(rt)
106                 delete rt;
107         freeTextureMemory();
108 }
109
110
111 void SGBbCache::init(int cacheCount) {
112         int colorBits = 0;
113         glGetIntegerv( GL_BLUE_BITS, &colorBits );
114
115         rt = new RenderTexture();
116         // don't use default rtt on nvidia/win because of poor performance of glCopyTexSubImage2D
117         // wihtout default pattrib params - see opengl forum
118         if( colorBits < 8 )
119                 rt->Reset("rgba=5,5,5,1 ctt");
120         else
121                 rt->Reset("rgba ctt");
122
123 //      rt->Reset("rgba tex2D ctt");
124 //      rt->Reset("rgba tex2D");
125         if( rt->Initialize(256, 256, true) ) {
126                 SG_LOG(SG_ALL, SG_INFO, "bbcache:Initialize sucessfull");
127                 if (rt->BeginCapture())
128                 {
129                         SG_LOG(SG_ALL, SG_INFO, "bbcache:BeginCapture sucessfull, RTT available");
130                         rtAvailable = true;
131                         glViewport(0, 0, 256, 256);
132                         glMatrixMode(GL_PROJECTION);
133                         glLoadIdentity();
134                         gluPerspective(60.0,  1, 1, 5.0);
135                         glMatrixMode(GL_MODELVIEW);
136                         glLoadIdentity();
137                         glDisable(GL_LIGHTING);
138                         glEnable(GL_COLOR_MATERIAL);
139                         glDisable(GL_CULL_FACE);
140                         glDisable(GL_FOG);
141                         glDisable(GL_DEPTH_TEST);
142                         glClearColor(0.0, 0.0, 0.0, 0.0);
143                         glEnable(GL_TEXTURE_2D);
144                         glEnable(GL_ALPHA_TEST);
145                         glAlphaFunc(GL_GREATER, 0.0f);
146                         glEnable(GL_SMOOTH);
147                         glEnable(GL_BLEND);
148                         glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
149
150                         rt->EndCapture();
151                 } else
152                         SG_LOG(SG_ALL, SG_WARN, "bbcache:BeginCapture failed, RTT not available for 3D clouds");
153         } else
154                 SG_LOG(SG_ALL, SG_WARN, "bbcache:Initialize failed, RTT not available for 3D clouds");
155         if( cacheCount )
156                 allocTextureMemory( cacheCount, 64 );
157
158 }
159
160
161 bool SGBbCache::setCacheSize(int count, int textureDimension) {
162         if( count < 0 || count > 500)
163                 return false;
164         freeTextureMemory();
165         if( count == 0)
166                 return true;
167
168         // only allow some reasonable dimensions
169         switch(textureDimension) {
170                 case 0:
171                         // default size
172                         textureDimension = 256;
173                         break;
174                 case 64:
175                 case 128:
176                 case 256:
177                         break;
178                 case 512:
179                         // rt is 256 so higher texture size has no meaning
180                         textureDimension = 256;
181                         break;
182                 default:
183                         textureDimension = 128;
184                         break;
185         }
186         return allocTextureMemory( count, textureDimension);
187 }
188
189
190 bool SGBbCache::setCacheSize(int sizeKb) {
191         if( sizeKb < 0 || sizeKb > 256*1024)
192                 return false;
193         freeTextureMemory();
194         if( sizeKb == 0)
195                 return true;
196         int count = 1;
197         int textureDimension = 256;
198         if( sizeKb >= 8*1024 ) {
199                 // more than 32 256x256 textures
200                 textureDimension = 256;
201         } else  if( sizeKb >= 2*1024 ) {
202                 // more than 32 128x128 textures
203                 textureDimension = 128;
204         } else  {
205                 // don't go under 64x64 textures
206                 textureDimension = 64;
207         }
208         count = (sizeKb * 1024) / (textureDimension * textureDimension * 4);
209         if(count == 0)
210                 count = 1;
211         return allocTextureMemory( count, textureDimension);
212 }
213
214 int SGBbCache::queryCacheSize(void) {
215         return cacheSizeKb;
216 }
217
218 void SGBbCache::free(int bbId, int cldId) {
219         if( bbId < 0 || bbId >= bbListCount )
220                 return;
221         if( bbList[bbId].cldID != cldId )
222                 return;
223         bbList[bbId].cldID = 0;
224 }
225
226 int SGBbCache::alloc(int cldId) {
227         // pretend we have no more texture if render to texture is not available
228         if( ! rtAvailable )
229                 return -1;
230         for(int i = 0 ; i < bbListCount ; i++) {
231                 if( (bbList[i].cldID == 0) && (bbList[i].texID != 0) ) {
232             bbList[i].cldID = cldId;
233                         bbList[i].angleX = -999;
234                         bbList[i].angleY = -999;
235                         bbList[i].frameUsed = 0;
236                         bbList[i].needRedraw = true;
237                         return i;
238                 }
239         }
240         return -1;
241 }
242
243 GLuint SGBbCache::QueryTexID(int cldId, int bbId) {
244         if( bbId < 0 || bbId >= bbListCount )
245                 return 0;
246         if( bbList[bbId].cldID != cldId )
247                 return 0;
248         return bbList[bbId].texID;
249 }
250
251 int SGBbCache::queryImpostorAge(int bbId) {
252         if( bbId < 0 || bbId >= bbListCount )
253                 return 0;
254         return frameNumber - bbList[bbId].frame;
255 }
256
257 void SGBbCache::beginCapture(void) {
258
259         rt->BeginCapture();
260
261         glClear(GL_COLOR_BUFFER_BIT);
262
263 }
264
265
266
267 void SGBbCache::setRadius(float radius, float dist_center) {
268         float border;
269         //set viewport to texture resolution
270         //glViewport(0, 0, 256, 256);
271         glMatrixMode(GL_PROJECTION);
272     glLoadIdentity();
273
274     float near_ = dist_center - radius;
275     float far_ = dist_center + radius;
276         if( near_ <= 0 ) {
277         // we are in trouble
278         glFrustum(-1, 1, -1, 1, 1, 1 + radius * 2);
279         } else {
280         border = (near_ * radius) / sqrt(dist_center * dist_center - radius * radius);
281         glFrustum(-border, border, -border, border, near_, far_);
282         }
283     glMatrixMode(GL_MODELVIEW);
284     glLoadIdentity();
285 }
286 void SGBbCache::setTextureData(int bbId) {
287         if( bbId < 0 || bbId >= bbListCount )
288                 return;
289
290     glBindTexture(GL_TEXTURE_2D, bbList[bbId].texID);
291         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, textureWH, textureWH);
292  
293 //    bbList[bbId].angleX = angleX;
294 //    bbList[bbId].angleY = angleY;
295     bbList[bbId].frame = frameNumber;
296         bbList[bbId].frameUsed = frameNumber;
297         bbList[bbId].needRedraw = false;
298     builtBBCount ++;
299         builtBBframe ++;
300 }
301
302 void SGBbCache::endCapture(void) {
303
304         rt->EndCapture();
305 //    glBindTexture(GL_TEXTURE_2D, rt->GetTextureID() );
306
307 }
308
309
310 bool SGBbCache::isBbValid( int cldId, int bbId, float angleY, float angleX) {
311         if( bbId < 0 || bbId >= bbListCount )
312                 return false;
313         if( bbList[bbId].cldID != cldId )
314                 return false;
315
316         // it was just allocated
317         if( bbList[bbId].frameUsed == 0)
318                 return false;
319
320         // we reuse old impostor to speed up things
321         if( builtBBframe >= maxImpostorRegenFrame )
322                 return true;
323
324         if( bbList[bbId].needRedraw )
325                 return false;
326
327 //    if( fabs(angleY - bbList[bbId].angleY) >= 4.0 )
328 //        return false;
329
330 //    if( fabs(angleX - bbList[bbId].angleX) >= 4.0 )
331 //        return false;
332
333         bbList[bbId].frameUsed = frameNumber;
334         return true;
335 }
336
337 // TODO:this is not the right way to handle that
338 void SGBbCache::setReference( int cldId, int bbId, float angleY, float angleX) {
339         if( bbId < 0 || bbId >= bbListCount )
340                 return;
341         if( bbList[bbId].cldID != cldId )
342                 return;
343         bbList[bbId].angleX = angleX;
344         bbList[bbId].angleY = angleY;
345 }
346
347 void SGBbCache::startNewFrame(void) {
348         builtBBframe = 0;
349         // TOTO:find reasonable value
350         int minFrameNumber = frameNumber - 100;
351         frameNumber++;
352         // cleanup of unused enties
353         for( int bbId = 0 ; bbId < bbListCount ; bbId++)
354                 if( (bbList[bbId].cldID != 0) && (bbList[bbId].frameUsed < minFrameNumber) ) {
355                         // entry is now free
356                         bbList[bbId].cldID = 0;
357                 }
358 }
359
360 // force all impostors to be rebuilt, this will enventually be done over several frames
361 void SGBbCache::invalidateCache(void) {
362
363         for( int bbId = 0 ; bbId < bbListCount ; bbId++)
364 //              bbList[bbId].cldID = 0;
365                 bbList[bbId].needRedraw = true;
366 }
367
368 // flag the impostor for a lazy update
369 void SGBbCache::invalidate(int cldId, int bbId) {
370         if( bbId < 0 || bbId >= bbListCount )
371                 return;
372         if( bbList[bbId].cldID != cldId )
373                 return;
374         bbList[bbId].needRedraw = true;
375 }
376