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