]> git.mxchange.org Git - simgear.git/blob - simgear/scene/sky/bbcache.cxx
Compile time fixes needed to build SimGear on recent cygwin versions.
[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, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 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         textureWH(0),
95         cacheSizeKb(0),
96         builtBBCount(0),
97         frameNumber(0),
98         rt(0),
99         rtAvailable(false),
100         maxImpostorRegenFrame(20)
101 {
102 }
103
104 SGBbCache::~SGBbCache(void) {
105         delete rt;
106         freeTextureMemory();
107 }
108
109
110 void SGBbCache::init(int cacheCount) {
111         GLint colorBits = 0;
112         glGetIntegerv( GL_BLUE_BITS, &colorBits );
113
114         rt = new RenderTexture();
115         // don't use default rtt on nvidia/win because of poor performance of glCopyTexSubImage2D
116         // wihtout default pattrib params - see opengl forum
117         if( colorBits < 8 )
118                 rt->Reset("rgba=5,5,5,1 ctt");
119         else
120                 rt->Reset("rgba ctt");
121
122 //      rt->Reset("rgba tex2D ctt");
123 //      rt->Reset("rgba tex2D");
124         if( rt->Initialize(256, 256, true) ) {
125                 SG_LOG(SG_ALL, SG_INFO, "bbcache:Initialize sucessfull");
126                 if (rt->BeginCapture())
127                 {
128                         SG_LOG(SG_ALL, SG_INFO, "bbcache:BeginCapture sucessfull, RTT available");
129                         rtAvailable = true;
130                         glViewport(0, 0, 256, 256);
131                         glMatrixMode(GL_PROJECTION);
132                         glLoadIdentity();
133                         gluPerspective(60.0,  1, 1, 5.0);
134                         glMatrixMode(GL_MODELVIEW);
135                         glLoadIdentity();
136                         glDisable(GL_LIGHTING);
137                         glEnable(GL_COLOR_MATERIAL);
138                         glDisable(GL_CULL_FACE);
139                         glDisable(GL_FOG);
140                         glDisable(GL_DEPTH_TEST);
141                         glClearColor(0.0, 0.0, 0.0, 0.0);
142                         glEnable(GL_TEXTURE_2D);
143                         glEnable(GL_ALPHA_TEST);
144                         glAlphaFunc(GL_GREATER, 0.0f);
145                         glEnable(GL_SMOOTH);
146                         glEnable(GL_BLEND);
147                         glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
148
149                         rt->EndCapture();
150                 } else
151                         SG_LOG(SG_ALL, SG_WARN, "bbcache:BeginCapture failed, RTT not available for 3D clouds");
152         } else
153                 SG_LOG(SG_ALL, SG_WARN, "bbcache:Initialize failed, RTT not available for 3D clouds");
154         if( cacheCount )
155                 allocTextureMemory( cacheCount, 64 );
156
157 }
158
159
160 bool SGBbCache::setCacheSize(int count, int textureDimension) {
161         if( count < 0 || count > 500)
162                 return false;
163         freeTextureMemory();
164         if( count == 0)
165                 return true;
166
167         // only allow some reasonable dimensions
168         switch(textureDimension) {
169                 case 0:
170                         // default size
171                         textureDimension = 256;
172                         break;
173                 case 64:
174                 case 128:
175                 case 256:
176                         break;
177                 case 512:
178                         // rt is 256 so higher texture size has no meaning
179                         textureDimension = 256;
180                         break;
181                 default:
182                         textureDimension = 128;
183                         break;
184         }
185         return allocTextureMemory( count, textureDimension);
186 }
187
188
189 bool SGBbCache::setCacheSize(int sizeKb) {
190         if( sizeKb < 0 || sizeKb > 256*1024)
191                 return false;
192         freeTextureMemory();
193         if( sizeKb == 0)
194                 return true;
195         int count = 1;
196         int textureDimension = 256;
197         if( sizeKb >= 8*1024 ) {
198                 // more than 32 256x256 textures
199                 textureDimension = 256;
200         } else  if( sizeKb >= 2*1024 ) {
201                 // more than 32 128x128 textures
202                 textureDimension = 128;
203         } else  {
204                 // don't go under 64x64 textures
205                 textureDimension = 64;
206         }
207         count = (sizeKb * 1024) / (textureDimension * textureDimension * 4);
208         if(count == 0)
209                 count = 1;
210         return allocTextureMemory( count, textureDimension);
211 }
212
213 int SGBbCache::queryCacheSize(void) {
214         return cacheSizeKb;
215 }
216
217 void SGBbCache::free(int bbId, int cldId) {
218         if( bbId < 0 || bbId >= bbListCount )
219                 return;
220         if( bbList[bbId].cldID != cldId )
221                 return;
222         bbList[bbId].cldID = 0;
223 }
224
225 int SGBbCache::alloc(int cldId) {
226         // pretend we have no more texture if render to texture is not available
227         if( ! rtAvailable )
228                 return -1;
229         for(int i = 0 ; i < bbListCount ; i++) {
230                 if( (bbList[i].cldID == 0) && (bbList[i].texID != 0) ) {
231             bbList[i].cldID = cldId;
232                         bbList[i].angleX = -999;
233                         bbList[i].angleY = -999;
234                         bbList[i].frameUsed = 0;
235                         bbList[i].needRedraw = true;
236                         return i;
237                 }
238         }
239         return -1;
240 }
241
242 GLuint SGBbCache::QueryTexID(int cldId, int bbId) {
243         if( bbId < 0 || bbId >= bbListCount )
244                 return 0;
245         if( bbList[bbId].cldID != cldId )
246                 return 0;
247         return bbList[bbId].texID;
248 }
249
250 int SGBbCache::queryImpostorAge(int bbId) {
251         if( bbId < 0 || bbId >= bbListCount )
252                 return 0;
253         return frameNumber - bbList[bbId].frame;
254 }
255
256 void SGBbCache::beginCapture(void) {
257
258         rt->BeginCapture();
259
260         glClear(GL_COLOR_BUFFER_BIT);
261
262 }
263
264
265
266 void SGBbCache::setRadius(float radius, float dist_center) {
267         float border;
268         //set viewport to texture resolution
269         //glViewport(0, 0, 256, 256);
270         glMatrixMode(GL_PROJECTION);
271     glLoadIdentity();
272
273     float near_ = dist_center - radius;
274     float far_ = dist_center + radius;
275         if( near_ <= 0 ) {
276         // we are in trouble
277         glFrustum(-1, 1, -1, 1, 1, 1 + radius * 2);
278         } else {
279         border = (near_ * radius) / sqrt(dist_center * dist_center - radius * radius);
280         glFrustum(-border, border, -border, border, near_, far_);
281         }
282     glMatrixMode(GL_MODELVIEW);
283     glLoadIdentity();
284 }
285 void SGBbCache::setTextureData(int bbId) {
286         if( bbId < 0 || bbId >= bbListCount )
287                 return;
288
289     glBindTexture(GL_TEXTURE_2D, bbList[bbId].texID);
290         glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, textureWH, textureWH);
291  
292 //    bbList[bbId].angleX = angleX;
293 //    bbList[bbId].angleY = angleY;
294     bbList[bbId].frame = frameNumber;
295         bbList[bbId].frameUsed = frameNumber;
296         bbList[bbId].needRedraw = false;
297     builtBBCount ++;
298         builtBBframe ++;
299 }
300
301 void SGBbCache::endCapture(void) {
302
303         rt->EndCapture();
304 //    glBindTexture(GL_TEXTURE_2D, rt->GetTextureID() );
305
306 }
307
308
309 bool SGBbCache::isBbValid( int cldId, int bbId, float angleY, float angleX) {
310         if( bbId < 0 || bbId >= bbListCount )
311                 return false;
312         if( bbList[bbId].cldID != cldId )
313                 return false;
314
315         // it was just allocated
316         if( bbList[bbId].frameUsed == 0)
317                 return false;
318
319         // we reuse old impostor to speed up things
320         if( builtBBframe >= maxImpostorRegenFrame )
321                 return true;
322
323         if( bbList[bbId].needRedraw )
324                 return false;
325
326 //    if( fabs(angleY - bbList[bbId].angleY) >= 4.0 )
327 //        return false;
328
329 //    if( fabs(angleX - bbList[bbId].angleX) >= 4.0 )
330 //        return false;
331
332         bbList[bbId].frameUsed = frameNumber;
333         return true;
334 }
335
336 // TODO:this is not the right way to handle that
337 void SGBbCache::setReference( int cldId, int bbId, float angleY, float angleX) {
338         if( bbId < 0 || bbId >= bbListCount )
339                 return;
340         if( bbList[bbId].cldID != cldId )
341                 return;
342         bbList[bbId].angleX = angleX;
343         bbList[bbId].angleY = angleY;
344 }
345
346 void SGBbCache::startNewFrame(void) {
347         builtBBframe = 0;
348         // TOTO:find reasonable value
349         int minFrameNumber = frameNumber - 100;
350         frameNumber++;
351         // cleanup of unused enties
352         for( int bbId = 0 ; bbId < bbListCount ; bbId++)
353                 if( (bbList[bbId].cldID != 0) && (bbList[bbId].frameUsed < minFrameNumber) ) {
354                         // entry is now free
355                         bbList[bbId].cldID = 0;
356                 }
357 }
358
359 // force all impostors to be rebuilt, this will enventually be done over several frames
360 void SGBbCache::invalidateCache(void) {
361
362         for( int bbId = 0 ; bbId < bbListCount ; bbId++)
363 //              bbList[bbId].cldID = 0;
364                 bbList[bbId].needRedraw = true;
365 }
366
367 // flag the impostor for a lazy update
368 void SGBbCache::invalidate(int cldId, int bbId) {
369         if( bbId < 0 || bbId >= bbListCount )
370                 return;
371         if( bbList[bbId].cldID != cldId )
372                 return;
373         bbList[bbId].needRedraw = true;
374 }
375