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