1 // Billboard helper class
3 // Written by Harald JOHNSEN, started April 2005.
5 // Copyright (C) 2005 Harald JOHNSEN - hjohnsen@evc.net
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.
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.
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.
24 # include <simgear_config.h>
27 #include <simgear/compiler.h>
28 #include <simgear/debug/logstream.hxx>
32 #include <simgear/screen/extensions.hxx>
33 #include <simgear/screen/RenderTexture.h>
36 #include "bbcache.hxx"
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
47 void SGBbCache::freeTextureMemory(void) {
50 for(int i = 0 ; i < bbListCount ; i++) {
53 glDeleteTextures(1, & bbList[i].texID);
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++) {
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);
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);
79 glBindTexture(GL_TEXTURE_2D, 0);
80 cacheSizeKb = (textureDimension * textureDimension * 4);
81 cacheSizeKb *= cacheCount;
84 if( rt->BeginCapture() ) {
85 glViewport(0, 0, textureDimension, textureDimension);
92 SGBbCache::SGBbCache(void) :
100 maxImpostorRegenFrame(20)
104 SGBbCache::~SGBbCache(void) {
110 void SGBbCache::init(int cacheCount) {
112 glGetIntegerv( GL_BLUE_BITS, &colorBits );
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
118 rt->Reset("rgba=5,5,5,1 ctt");
120 rt->Reset("rgba ctt");
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())
128 SG_LOG(SG_ALL, SG_INFO, "bbcache:BeginCapture sucessfull, RTT available");
130 glViewport(0, 0, 256, 256);
131 glMatrixMode(GL_PROJECTION);
133 gluPerspective(60.0, 1, 1, 5.0);
134 glMatrixMode(GL_MODELVIEW);
136 glDisable(GL_LIGHTING);
137 glEnable(GL_COLOR_MATERIAL);
138 glDisable(GL_CULL_FACE);
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);
147 glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
151 SG_LOG(SG_ALL, SG_WARN, "bbcache:BeginCapture failed, RTT not available for 3D clouds");
153 SG_LOG(SG_ALL, SG_WARN, "bbcache:Initialize failed, RTT not available for 3D clouds");
155 allocTextureMemory( cacheCount, 64 );
160 bool SGBbCache::setCacheSize(int count, int textureDimension) {
161 if( count < 0 || count > 500)
167 // only allow some reasonable dimensions
168 switch(textureDimension) {
171 textureDimension = 256;
178 // rt is 256 so higher texture size has no meaning
179 textureDimension = 256;
182 textureDimension = 128;
185 return allocTextureMemory( count, textureDimension);
189 bool SGBbCache::setCacheSize(int sizeKb) {
190 if( sizeKb < 0 || sizeKb > 256*1024)
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;
204 // don't go under 64x64 textures
205 textureDimension = 64;
207 count = (sizeKb * 1024) / (textureDimension * textureDimension * 4);
210 return allocTextureMemory( count, textureDimension);
213 int SGBbCache::queryCacheSize(void) {
217 void SGBbCache::free(int bbId, int cldId) {
218 if( bbId < 0 || bbId >= bbListCount )
220 if( bbList[bbId].cldID != cldId )
222 bbList[bbId].cldID = 0;
225 int SGBbCache::alloc(int cldId) {
226 // pretend we have no more texture if render to texture is not available
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;
242 GLuint SGBbCache::QueryTexID(int cldId, int bbId) {
243 if( bbId < 0 || bbId >= bbListCount )
245 if( bbList[bbId].cldID != cldId )
247 return bbList[bbId].texID;
250 int SGBbCache::queryImpostorAge(int bbId) {
251 if( bbId < 0 || bbId >= bbListCount )
253 return frameNumber - bbList[bbId].frame;
256 void SGBbCache::beginCapture(void) {
260 glClear(GL_COLOR_BUFFER_BIT);
266 void SGBbCache::setRadius(float radius, float dist_center) {
268 //set viewport to texture resolution
269 //glViewport(0, 0, 256, 256);
270 glMatrixMode(GL_PROJECTION);
273 float near_ = dist_center - radius;
274 float far_ = dist_center + radius;
277 glFrustum(-1, 1, -1, 1, 1, 1 + radius * 2);
279 border = (near_ * radius) / sqrt(dist_center * dist_center - radius * radius);
280 glFrustum(-border, border, -border, border, near_, far_);
282 glMatrixMode(GL_MODELVIEW);
285 void SGBbCache::setTextureData(int bbId) {
286 if( bbId < 0 || bbId >= bbListCount )
289 glBindTexture(GL_TEXTURE_2D, bbList[bbId].texID);
290 glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, textureWH, textureWH);
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;
301 void SGBbCache::endCapture(void) {
304 // glBindTexture(GL_TEXTURE_2D, rt->GetTextureID() );
309 bool SGBbCache::isBbValid( int cldId, int bbId, float angleY, float angleX) {
310 if( bbId < 0 || bbId >= bbListCount )
312 if( bbList[bbId].cldID != cldId )
315 // it was just allocated
316 if( bbList[bbId].frameUsed == 0)
319 // we reuse old impostor to speed up things
320 if( builtBBframe >= maxImpostorRegenFrame )
323 if( bbList[bbId].needRedraw )
326 // if( fabs(angleY - bbList[bbId].angleY) >= 4.0 )
329 // if( fabs(angleX - bbList[bbId].angleX) >= 4.0 )
332 bbList[bbId].frameUsed = frameNumber;
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 )
340 if( bbList[bbId].cldID != cldId )
342 bbList[bbId].angleX = angleX;
343 bbList[bbId].angleY = angleY;
346 void SGBbCache::startNewFrame(void) {
348 // TOTO:find reasonable value
349 int minFrameNumber = frameNumber - 100;
351 // cleanup of unused enties
352 for( int bbId = 0 ; bbId < bbListCount ; bbId++)
353 if( (bbList[bbId].cldID != 0) && (bbList[bbId].frameUsed < minFrameNumber) ) {
355 bbList[bbId].cldID = 0;
359 // force all impostors to be rebuilt, this will enventually be done over several frames
360 void SGBbCache::invalidateCache(void) {
362 for( int bbId = 0 ; bbId < bbListCount ; bbId++)
363 // bbList[bbId].cldID = 0;
364 bbList[bbId].needRedraw = true;
367 // flag the impostor for a lazy update
368 void SGBbCache::invalidate(int cldId, int bbId) {
369 if( bbId < 0 || bbId >= bbListCount )
371 if( bbList[bbId].cldID != cldId )
373 bbList[bbId].needRedraw = true;