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