00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifdef HAVE_CONFIG_H
00024 # include <simgear_config.h>
00025 #endif
00026
00027 #include <simgear/compiler.h>
00028
00029 #include <plib/sg.h>
00030 #include <plib/ssg.h>
00031 #include <simgear/math/sg_random.h>
00032 #include <simgear/math/sg_geodesy.hxx>
00033 #include <simgear/math/polar3d.hxx>
00034
00035 #include STL_ALGORITHM
00036 #include <vector>
00037
00038 SG_USING_STD(vector);
00039
00040 #include <simgear/environment/visual_enviro.hxx>
00041 #include "sky.hxx"
00042 #include "newcloud.hxx"
00043 #include "cloudfield.hxx"
00044
00045 #if defined(__MINGW32__)
00046 #define isnan(x) _isnan(x)
00047 #endif
00048
00049 #if defined (__FreeBSD__)
00050 # if __FreeBSD_version < 500000
00051 extern "C" {
00052 inline int isnan(double r) { return !(r <= 0 || r >= 0); }
00053 }
00054 # endif
00055 #endif
00056
00057
00058 #if defined (__CYGWIN__)
00059 #include <ieeefp.h>
00060 #endif
00061
00062 static list_of_culledCloud inViewClouds;
00063
00064
00065 float SGCloudField::CloudVis = 25000.0f;
00066 bool SGCloudField::enable3D = false;
00067
00068
00069 double SGCloudField::fieldSize = 50000.0;
00070 float SGCloudField::density = 100.0;
00071 double SGCloudField::timer_dt = 0.0;
00072 sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
00073
00074 static int last_cache_size = 1*1024;
00075 static int cacheResolution = 64;
00076 static sgVec3 last_sunlight={0.0f, 0.0f, 0.0f};
00077
00078 int SGCloudField::get_CacheResolution(void) {
00079 return cacheResolution;
00080 }
00081
00082 void SGCloudField::set_CacheResolution(int resolutionPixels) {
00083 if (resolutionPixels == 0)
00084 resolutionPixels = 64;
00085 if(cacheResolution == resolutionPixels)
00086 return;
00087 cacheResolution = resolutionPixels;
00088 if(enable3D) {
00089 int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
00090 if(count == 0)
00091 count = 1;
00092 SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
00093 }
00094 }
00095
00096 int SGCloudField::get_CacheSize(void) {
00097 return SGNewCloud::cldCache->queryCacheSize();
00098 }
00099
00100 void SGCloudField::set_CacheSize(int sizeKb) {
00101
00102 if (sizeKb == 0)
00103 sizeKb = 1024;
00104 if(last_cache_size == sizeKb)
00105 return;
00106 if(sizeKb)
00107 last_cache_size = sizeKb;
00108 if(enable3D) {
00109 int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
00110 if(count == 0)
00111 count = 1;
00112 SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
00113 }
00114 }
00115 void SGCloudField::set_CloudVis(float distance) {
00116 if( distance <= fieldSize )
00117 SGCloudField::CloudVis = distance;
00118 }
00119 void SGCloudField::set_density(float density) {
00120 SGCloudField::density = density;
00121 }
00122 void SGCloudField::set_enable3dClouds(bool enable) {
00123 if(enable3D == enable)
00124 return;
00125 enable3D = enable;
00126 if(enable) {
00127 int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4);
00128 if(count == 0)
00129 count = 1;
00130 SGNewCloud::cldCache->setCacheSize(count, cacheResolution);
00131 } else {
00132 SGNewCloud::cldCache->setCacheSize(0);
00133 }
00134 }
00135
00136
00137 void SGCloudField::reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt, float direction, float speed) {
00138 sgMat4 T1, LON, LAT;
00139 sgVec3 axis;
00140
00141 sgMakeTransMat4( T1, p );
00142
00143 sgSetVec3( axis, 0.0, 0.0, 1.0 );
00144 sgMakeRotMat4( LON, lon * SGD_RADIANS_TO_DEGREES, axis );
00145
00146 sgSetVec3( axis, 0.0, 1.0, 0.0 );
00147 sgMakeRotMat4( LAT, 90.0 - lat * SGD_RADIANS_TO_DEGREES, axis );
00148
00149 sgMat4 TRANSFORM;
00150
00151 sgCopyMat4( TRANSFORM, T1 );
00152 sgPreMultMat4( TRANSFORM, LON );
00153 sgPreMultMat4( TRANSFORM, LAT );
00154
00155 sgCoord layerpos;
00156 sgSetCoord( &layerpos, TRANSFORM );
00157
00158 sgMakeCoordMat4( transform, &layerpos );
00159
00160
00161 this->alt = alt;
00162
00163
00164 double sp_dist = speed*dt;
00165 if (sp_dist > 0) {
00166 double bx = cos((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
00167 double by = sin((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
00168 relative_position[SG_X] += bx;
00169 relative_position[SG_Y] += by;
00170 }
00171
00172 if ( lon != last_lon || lat != last_lat || sp_dist != 0 ) {
00173 Point3D start( last_lon, last_lat, 0.0 );
00174 Point3D dest( lon, lat, 0.0 );
00175 double course = 0.0, dist = 0.0;
00176
00177 calc_gc_course_dist( dest, start, &course, &dist );
00178
00179
00180
00181
00182
00183 if ( isnan(course) ) {
00184 course = last_course;
00185 } else {
00186 last_course = course;
00187 }
00188
00189
00190 double ax = 0.0, ay = 0.0;
00191
00192 if (dist > 0.0) {
00193 ax = cos(course) * dist;
00194 ay = sin(course) * dist;
00195 }
00196
00197 deltax += ax;
00198 deltay += ay;
00199
00200 last_lon = lon;
00201 last_lat = lat;
00202 }
00203
00204
00205
00206 ssgContext *context = ssgGetCurrentContext();
00207 frustum = *context->getFrustum();
00208
00209 float w, h;
00210 sgEnviro.getFOV( w, h );
00211 frustum.setFOV( w, h );
00212 frustum.setNearFar(1.0, CloudVis);
00213 timer_dt = dt;
00214 }
00215
00216 SGCloudField::SGCloudField() :
00217 deltax(0.0),
00218 deltay(0.0),
00219 last_course(0.0),
00220 last_density(0.0),
00221 draw_in_3d(true)
00222 {
00223 sgSetVec3( relative_position, 0,0,0);
00224 theField.reserve(200);
00225 inViewClouds.reserve(200);
00226 sg_srandom_time_10();
00227 }
00228
00229 SGCloudField::~SGCloudField() {
00230 list_of_Cloud::iterator iCloud;
00231 for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
00232 delete iCloud->aCloud;
00233 }
00234 theField.clear();
00235 }
00236
00237
00238 void SGCloudField::clear(void) {
00239 list_of_Cloud::iterator iCloud;
00240 for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
00241 delete iCloud->aCloud;
00242 }
00243 theField.clear();
00244
00245 last_density = 0.0;
00246
00247 draw_in_3d = true;
00248 }
00249
00250
00251 static int densTable[][10] = {
00252 {0,0,0,0,0,0,0,0,0,0},
00253 {1,0,0,0,0,0,0,0,0,0},
00254 {1,0,0,0,1,0,0,0,0,0},
00255 {1,0,0,0,1,0,0,1,0,0},
00256 {1,0,1,0,1,0,0,1,0,0},
00257 {1,0,1,0,1,0,1,1,0,0},
00258 {1,0,1,0,1,0,1,1,0,1},
00259 {1,0,1,1,1,0,1,1,0,1},
00260 {1,1,1,1,1,0,1,1,0,1},
00261 {1,1,1,1,1,0,1,1,1,1},
00262 {1,1,1,1,1,1,1,1,1,1}
00263 };
00264
00265
00266 void SGCloudField::applyDensity(void) {
00267 int row = (int) (density / 10.0);
00268 int col = 0;
00269 sgBox fieldBox;
00270
00271 list_of_Cloud::iterator iCloud;
00272 for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
00273 if(++col > 9)
00274 col = 0;
00275 if( densTable[row][col] ) {
00276 iCloud->visible = true;
00277 fieldBox.extend( *iCloud->aCloud->getCenter() );
00278 } else
00279 iCloud->visible = false;
00280 }
00281 last_density = density;
00282 draw_in_3d = ( theField.size() != 0);
00283 sgVec3 center;
00284 sgSubVec3( center, fieldBox.getMax(), fieldBox.getMin() );
00285 sgScaleVec3( center, 0.5f );
00286 center[1] = 0.0f;
00287 field_sphere.setCenter( center );
00288 field_sphere.setRadius( fieldSize * 0.5f * 1.414f );
00289 }
00290
00291
00292 void SGCloudField::addCloud( sgVec3 pos, SGNewCloud *cloud) {
00293 Cloud cl;
00294 cl.aCloud = cloud;
00295 cl.visible = true;
00296 cloud->SetPos( pos );
00297 sgCopyVec3( cl.pos, *cloud->getCenter() );
00298 theField.push_back( cl );
00299 }
00300
00301
00302 static float Rnd(float n) {
00303 return n * (-0.5f + sg_random());
00304 }
00305
00306
00307
00308 void SGCloudField::buildTestLayer(void) {
00309
00310 const float s = 2250.0f;
00311
00312 for( int z = -5 ; z <= 5 ; z++) {
00313 for( int x = -5 ; x <= 5 ; x++ ) {
00314 SGNewCloud *cloud = new SGNewCloud(SGNewCloud::CLFamilly_cu);
00315 cloud->new_cu();
00316 sgVec3 pos = {(x+Rnd(0.7)) * s, 750.0f, (z+Rnd(0.7)) * s};
00317 addCloud(pos, cloud);
00318 }
00319 }
00320 applyDensity();
00321 }
00322
00323
00324 void SGCloudField::cullClouds(sgVec3 eyePos, sgMat4 mat) {
00325 list_of_Cloud::iterator iCloud;
00326
00327 sgSphere tile_sphere;
00328 tile_sphere.setRadius( field_sphere.getRadius() );
00329 sgVec3 tile_center;
00330 sgSubVec3( tile_center, field_sphere.getCenter(), eyePos );
00331 tile_sphere.setCenter( tile_center );
00332 tile_sphere.orthoXform(mat);
00333 if( frustum.contains( & tile_sphere ) == SG_OUTSIDE )
00334 return;
00335
00336 for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
00337 sgVec3 dist;
00338 sgSphere sphere;
00339 if( ! iCloud->visible )
00340 continue;
00341 sgSubVec3( dist, iCloud->pos, eyePos );
00342 sphere.setCenter(dist[0], dist[2], dist[1] + eyePos[1]);
00343 float radius = iCloud->aCloud->getRadius();
00344 sphere.setRadius(radius);
00345 sphere.orthoXform(mat);
00346 if( frustum.contains( & sphere ) != SG_OUTSIDE ) {
00347 float squareDist = dist[0]*dist[0] + dist[1]*dist[1] + dist[2]*dist[2];
00348 culledCloud tmp;
00349 tmp.aCloud = iCloud->aCloud;
00350 sgCopyVec3( tmp.eyePos, eyePos );
00351
00352 tmp.dist = - squareDist;
00353 tmp.heading = -SG_PI/2.0 - atan2( dist[0], dist[2] );
00354 tmp.alt = iCloud->pos[1];
00355 inViewClouds.push_back(tmp);
00356 if( squareDist - radius*radius < 100*100 )
00357 sgEnviro.set_view_in_cloud(true);
00358 }
00359 }
00360
00361 }
00362
00363
00364
00365
00366
00367
00368 void SGCloudField::Render( float *sun_color ) {
00369 sgVec3 eyePos;
00370 double relx, rely;
00371
00372 if( ! enable3D )
00373 return;
00374
00375 if( last_density != density ) {
00376 last_density = density;
00377 applyDensity();
00378 }
00379
00380 if( ! draw_in_3d )
00381 return;
00382
00383 if( ! SGNewCloud::cldCache->isRttAvailable() )
00384 return;
00385
00386 inViewClouds.clear();
00387
00388
00389 glPushMatrix();
00390
00391 sgMat4 modelview, tmp, invtrans;
00392
00393
00394 sgTransposeNegateMat4( invtrans, transform );
00395 sgVec3 lightVec;
00396 ssgGetLight( 0 )->getPosition( lightVec );
00397 sgXformVec3( lightVec, invtrans );
00398
00399 sgSetVec3( SGNewCloud::modelSunDir, lightVec[0], lightVec[2], lightVec[1]);
00400
00401 sgVec4 diffuse, ambient;
00402 ssgGetLight( 0 )->getColour( GL_DIFFUSE, diffuse );
00403 ssgGetLight( 0 )->getColour( GL_AMBIENT, ambient );
00404
00405 sgScaleVec3 ( SGNewCloud::ambLight, ambient , 1.1f);
00406
00407
00408 sgScaleVec3 ( SGNewCloud::sunlight, sun_color , 0.4f);
00409 SGNewCloud::ambLight[2] += 0.1f;
00410
00411 sgVec3 delta_light;
00412 sgSubVec3(delta_light, last_sunlight, SGNewCloud::sunlight);
00413 if( (fabs(delta_light[0]) + fabs(delta_light[1]) + fabs(delta_light[2])) > 0.05f ) {
00414 sgCopyVec3( last_sunlight, SGNewCloud::sunlight );
00415
00416 SGNewCloud::cldCache->invalidateCache();
00417 }
00418
00419
00420 ssgGetModelviewMatrix( modelview );
00421 sgCopyMat4( tmp, transform );
00422 sgPostMultMat4( tmp, modelview );
00423
00424
00425
00426 relx = fmod( deltax + relative_position[SG_X], fieldSize );
00427 rely = fmod( deltay + relative_position[SG_Y], fieldSize );
00428
00429 relx = fmod( relx + fieldSize, fieldSize );
00430 rely = fmod( rely + fieldSize, fieldSize );
00431 sgSetVec3( eyePos, relx, alt, rely);
00432
00433 sgSetVec3( view_X, tmp[0][0], tmp[1][0], tmp[2][0] );
00434 sgSetVec3( view_Y, tmp[0][1], tmp[1][1], tmp[2][1] );
00435 sgSetVec3( view_vec, tmp[0][2], tmp[1][2], tmp[2][2] );
00436
00437 ssgLoadModelviewMatrix( tmp );
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452 for(int x = -1 ; x <= 1 ; x++)
00453 for(int y = -1 ; y <= 1 ; y++ ) {
00454 sgVec3 fieldPos;
00455
00456 sgSetVec3(fieldPos, eyePos[0] + x*fieldSize, eyePos[1], eyePos[2] + y*fieldSize);
00457 cullClouds(fieldPos, tmp);
00458 }
00459
00460 std::sort( inViewClouds.begin(), inViewClouds.end() );
00461
00462
00463 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00464 glEnable(GL_ALPHA_TEST);
00465 glAlphaFunc(GL_GREATER, 0.0f);
00466 glDisable(GL_CULL_FACE);
00467 glEnable(GL_DEPTH_TEST);
00468 glDepthMask( GL_FALSE );
00469 glEnable(GL_SMOOTH);
00470 glEnable(GL_BLEND);
00471 glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
00472 glEnable( GL_TEXTURE_2D );
00473 glDisable( GL_FOG );
00474 glDisable(GL_LIGHTING);
00475
00476
00477
00478 list_of_culledCloud::iterator iCloud;
00479 for( iCloud = inViewClouds.begin() ; iCloud != inViewClouds.end() ; iCloud++ ) {
00480
00481 iCloud->aCloud->Render(iCloud->eyePos);
00482 sgEnviro.callback_cloud(iCloud->heading, iCloud->alt,
00483 iCloud->aCloud->getRadius(), iCloud->aCloud->getFamilly(), - iCloud->dist, iCloud->aCloud->getId());
00484 }
00485
00486 glBindTexture(GL_TEXTURE_2D, 0);
00487 glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
00488 glEnable( GL_FOG );
00489 glEnable(GL_CULL_FACE);
00490 glEnable(GL_DEPTH_TEST);
00491
00492 ssgLoadModelviewMatrix( modelview );
00493
00494 glPopMatrix();
00495
00496 }
00497