X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Fsky%2Fcloudfield.cxx;h=8d83037d918d1d9a7b5565e408bb6b7aacca1cbb;hb=ccbc5abec63e508261b6d4bdbd5b1f780d233fc8;hp=a847c57a1bdc972233a593b3dd20dc15806f2b75;hpb=b5e03030d1d9549104a936242f602a9a27198d01;p=simgear.git diff --git a/simgear/scene/sky/cloudfield.cxx b/simgear/scene/sky/cloudfield.cxx index a847c57a..8d83037d 100644 --- a/simgear/scene/sky/cloudfield.cxx +++ b/simgear/scene/sky/cloudfield.cxx @@ -16,7 +16,7 @@ // // You should have received a copy of the GNU General Public License // along with this program; if not, write to the Free Software -// Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. // // @@ -27,34 +27,83 @@ #include #include -#include +#include #include +#include #include STL_ALGORITHM -#include SG_GLUT_H #include SG_USING_STD(vector); +#include +#include "sky.hxx" #include "newcloud.hxx" #include "cloudfield.hxx" +#if defined(__MINGW32__) +#define isnan(x) _isnan(x) +#endif + +#if defined (__FreeBSD__) +# if __FreeBSD_version < 500000 + extern "C" { + inline int isnan(double r) { return !(r <= 0 || r >= 0); } + } +# endif +#endif + + +#if defined (__CYGWIN__) +#include +#endif + static list_of_culledCloud inViewClouds; // visibility distance for clouds in meters float SGCloudField::CloudVis = 25000.0f; -bool SGCloudField::enable3D = true; +bool SGCloudField::enable3D = false; // fieldSize must be > CloudVis or we can destroy the impostor cache // a cloud must only be seen once or the impostor will be generated for each of his positions -double SGCloudField::fieldSize = 30000.0; +double SGCloudField::fieldSize = 50000.0; float SGCloudField::density = 100.0; -static int last_cache_size = 4*1024; +double SGCloudField::timer_dt = 0.0; +sgVec3 SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y; + +static int last_cache_size = 1*1024; +static int cacheResolution = 64; +static sgVec3 last_sunlight={0.0f, 0.0f, 0.0f}; + +int SGCloudField::get_CacheResolution(void) { +#if 0 + return cacheResolution; +#endif + return 0; +} + +void SGCloudField::set_CacheResolution(int resolutionPixels) { +#if 0 + if(cacheResolution == resolutionPixels) + return; + cacheResolution = resolutionPixels; + if(enable3D) { + int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4); + if(count == 0) + count = 1; + SGNewCloud::cldCache->setCacheSize(count, cacheResolution); + } +#endif +} int SGCloudField::get_CacheSize(void) { +#if 0 return SGNewCloud::cldCache->queryCacheSize(); +#endif + return 0; } void SGCloudField::set_CacheSize(int sizeKb) { +#if 0 // apply in rendering option dialog if(last_cache_size == sizeKb) return; @@ -62,27 +111,44 @@ void SGCloudField::set_CacheSize(int sizeKb) { return; if(sizeKb) last_cache_size = sizeKb; - SGNewCloud::cldCache->setCacheSize(sizeKb); + if(enable3D) { + int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4); + if(count == 0) + count = 1; + SGNewCloud::cldCache->setCacheSize(count, cacheResolution); + } +#endif } void SGCloudField::set_CloudVis(float distance) { - SGCloudField::CloudVis = distance; +#if 0 + if( distance <= fieldSize ) + SGCloudField::CloudVis = distance; +#endif } void SGCloudField::set_density(float density) { +#if 0 SGCloudField::density = density; +#endif } void SGCloudField::set_enable3dClouds(bool enable) { +#if 0 if(enable3D == enable) return; enable3D = enable; if(enable) { - SGNewCloud::cldCache->setCacheSize(last_cache_size); + int count = last_cache_size * 1024 / (cacheResolution * cacheResolution * 4); + if(count == 0) + count = 1; + SGNewCloud::cldCache->setCacheSize(count, cacheResolution); } else { SGNewCloud::cldCache->setCacheSize(0); } +#endif } // reposition the cloud layer at the specified origin and orientation -void SGCloudField::reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt) { +void SGCloudField::reposition( sgVec3 p, sgVec3 up, double lon, double lat, double alt, double dt, float direction, float speed) { +#if 0 sgMat4 T1, LON, LAT; sgVec3 axis; @@ -105,20 +171,10 @@ void SGCloudField::reposition( sgVec3 p, sgVec3 up, double lon, double lat, doub sgMakeCoordMat4( transform, &layerpos ); - // TODO:use a simple sphere earth - double az1, az2, s; - geo_inverse_wgs_84( 0.0, 0.0, 0.0, lat*SG_RADIANS_TO_DEGREES , lon*SG_RADIANS_TO_DEGREES, &az1, &az2, &s); - az1 = az1 * SG_DEGREES_TO_RADIANS; - // compute the view position on a 'flat' earth - deltay = -cos(SG_PI/2+az1) * s; - deltax = -sin(SG_PI/2+az1) * s; -// deltax = cos(0.0) * s; -// deltay = sin(0.0) * s; + this->alt = alt; // simulate clouds movement from wind - double speed = 10.0f; - double direction = 45.0; double sp_dist = speed*dt; if (sp_dist > 0) { double bx = cos((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist; @@ -127,70 +183,194 @@ void SGCloudField::reposition( sgVec3 p, sgVec3 up, double lon, double lat, doub relative_position[SG_Y] += by; } + if ( lon != last_lon || lat != last_lat || sp_dist != 0 ) { + Point3D start( last_lon, last_lat, 0.0 ); + Point3D dest( lon, lat, 0.0 ); + double course = 0.0, dist = 0.0; + + calc_gc_course_dist( dest, start, &course, &dist ); + // if start and dest are too close together, + // calc_gc_course_dist() can return a course of "nan". If + // this happens, lets just use the last known good course. + // This is a hack, and it would probably be better to make + // calc_gc_course_dist() more robust. + if ( isnan(course) ) { + course = last_course; + } else { + last_course = course; + } + + // calculate cloud movement due to external forces + double ax = 0.0, ay = 0.0; + + if (dist > 0.0) { + ax = cos(course) * dist; + ay = sin(course) * dist; + } + + deltax += ax; + deltay += ay; + + last_lon = lon; + last_lat = lat; + } + + // correct the frustum with the right far plane ssgContext *context = ssgGetCurrentContext(); frustum = *context->getFrustum(); + + float w, h; + sgEnviro.getFOV( w, h ); + frustum.setFOV( w, h ); frustum.setNearFar(1.0, CloudVis); + timer_dt = dt; +#endif } -SGCloudField::SGCloudField() { +SGCloudField::SGCloudField() : + deltax(0.0), + deltay(0.0), + last_course(0.0), + last_density(0.0), + draw_in_3d(true) +{ +#if 0 sgSetVec3( relative_position, 0,0,0); theField.reserve(200); inViewClouds.reserve(200); + sg_srandom_time_10(); +#else + draw_in_3d = false; +#endif } SGCloudField::~SGCloudField() { +#if 0 list_of_Cloud::iterator iCloud; for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) { delete iCloud->aCloud; } theField.clear(); +#endif } +void SGCloudField::clear(void) { +#if 0 + list_of_Cloud::iterator iCloud; + for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) { + delete iCloud->aCloud; + } + theField.clear(); + // force a recompute of density on first redraw + last_density = 0.0; + // true to come back in set density after layer is built + draw_in_3d = true; +#endif +} + +// use a table or else we see poping when moving the slider... +static int densTable[][10] = { + {0,0,0,0,0,0,0,0,0,0}, + {1,0,0,0,0,0,0,0,0,0}, + {1,0,0,0,1,0,0,0,0,0}, + {1,0,0,0,1,0,0,1,0,0}, // 30% + {1,0,1,0,1,0,0,1,0,0}, + {1,0,1,0,1,0,1,1,0,0}, // 50% + {1,0,1,0,1,0,1,1,0,1}, + {1,0,1,1,1,0,1,1,0,1}, // 70% + {1,1,1,1,1,0,1,1,0,1}, + {1,1,1,1,1,0,1,1,1,1}, // 90% + {1,1,1,1,1,1,1,1,1,1} +}; + +// set the visible flag depending on density +void SGCloudField::applyDensity(void) { +#if 0 + int row = (int) (density / 10.0); + int col = 0; + sgBox fieldBox; + + list_of_Cloud::iterator iCloud; + for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) { + if(++col > 9) + col = 0; + if( densTable[row][col] ) { + iCloud->visible = true; + fieldBox.extend( *iCloud->aCloud->getCenter() ); + } else + iCloud->visible = false; + } + last_density = density; + draw_in_3d = ( theField.size() != 0); + sgVec3 center; + sgSubVec3( center, fieldBox.getMax(), fieldBox.getMin() ); + sgScaleVec3( center, 0.5f ); + center[1] = 0.0f; + field_sphere.setCenter( center ); + field_sphere.setRadius( fieldSize * 0.5f * 1.414f ); +#endif +} + // add one cloud, data is not copied, ownership given void SGCloudField::addCloud( sgVec3 pos, SGNewCloud *cloud) { +#if 0 Cloud cl; - sgCopyVec3( cl.pos, pos ); cl.aCloud = cloud; + cl.visible = true; cloud->SetPos( pos ); + sgCopyVec3( cl.pos, *cloud->getCenter() ); theField.push_back( cl ); +#endif } static float Rnd(float n) { - return n * (-0.5f + rand() / (float) RAND_MAX); + return n * (-0.5f + sg_random()); } // for debug only // build a field of cloud of size 25x25 km, its a grid of 11x11 clouds void SGCloudField::buildTestLayer(void) { - - const float s = 2200.0f; +#if 0 + const float s = 2250.0f; for( int z = -5 ; z <= 5 ; z++) { for( int x = -5 ; x <= 5 ; x++ ) { - SGNewCloud *cloud = new SGNewCloud; + SGNewCloud *cloud = new SGNewCloud(SGNewCloud::CLFamilly_cu); cloud->new_cu(); sgVec3 pos = {(x+Rnd(0.7)) * s, 750.0f, (z+Rnd(0.7)) * s}; addCloud(pos, cloud); } } - + applyDensity(); +#endif } // cull all clouds of a tiled field void SGCloudField::cullClouds(sgVec3 eyePos, sgMat4 mat) { +#if 0 list_of_Cloud::iterator iCloud; -// const float distVisCompare = CloudVis * CloudVis; - // TODO:cull the field before culling the clouds in the field (should eliminate 3 fields) + sgSphere tile_sphere; + tile_sphere.setRadius( field_sphere.getRadius() ); + sgVec3 tile_center; + sgSubVec3( tile_center, field_sphere.getCenter(), eyePos ); + tile_sphere.setCenter( tile_center ); + tile_sphere.orthoXform(mat); + if( frustum.contains( & tile_sphere ) == SG_OUTSIDE ) + return; + for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) { sgVec3 dist; sgSphere sphere; + if( ! iCloud->visible ) + continue; sgSubVec3( dist, iCloud->pos, eyePos ); - sphere.setCenter(dist[0], dist[2], dist[1]); - sphere.setRadius(iCloud->aCloud->getRadius()); + sphere.setCenter(dist[0], dist[2], dist[1] + eyePos[1]); + float radius = iCloud->aCloud->getRadius(); + sphere.setRadius(radius); sphere.orthoXform(mat); if( frustum.contains( & sphere ) != SG_OUTSIDE ) { float squareDist = dist[0]*dist[0] + dist[1]*dist[1] + dist[2]*dist[2]; @@ -199,74 +379,97 @@ void SGCloudField::cullClouds(sgVec3 eyePos, sgMat4 mat) { sgCopyVec3( tmp.eyePos, eyePos ); // save distance for later sort, opposite distance because we want back to front tmp.dist = - squareDist; + tmp.heading = -SG_PI/2.0 - atan2( dist[0], dist[2] ); // + SG_PI; + tmp.alt = iCloud->pos[1]; inViewClouds.push_back(tmp); + if( squareDist - radius*radius < 100*100 ) + sgEnviro.set_view_in_cloud(true); } } - +#endif } -static inline void myswap(float &a, float &b) { - float tmp = a; - a = b; - b = tmp; -} // Render a cloud field // because no field can have an infinite size (and we don't want to reach his border) // we draw this field and adjacent fields. // adjacent fields are not real, its the same field displaced by some offset -void SGCloudField::Render(void) { +void SGCloudField::Render(float *sun_color) { + // sun_color used to depend on an extern SGSky *thesky definition + // above. However, this is bad form for a library and it's much + // more clean to just pass in the needed value. For reference, here is + // the old way that sun_color was fetched ... + // float *sun_color = thesky->get_sun_color(); + +#if 0 sgVec3 eyePos; double relx, rely; if( ! enable3D ) return; - // ask the impostor cache to do some cleanup - // TODO:don't do that for every field - SGNewCloud::cldCache->startNewFrame(); + if( last_density != density ) { + last_density = density; + applyDensity(); + } + + if( ! draw_in_3d ) + return; + + if( ! SGNewCloud::cldCache->isRttAvailable() ) + return; inViewClouds.clear(); - // cloud fields are tiled on the flat earth - // compute the position in the tile - relx = -fmod( deltax + relative_position[SG_X], fieldSize ); - rely = -fmod( deltay + relative_position[SG_Y], fieldSize ); glPushMatrix(); sgMat4 modelview, tmp, invtrans; - // try to find the sun position (buggy) + // try to find the sun position sgTransposeNegateMat4( invtrans, transform ); sgVec3 lightVec; ssgGetLight( 0 )->getPosition( lightVec ); - sgNegateVec3( lightVec ); sgXformVec3( lightVec, invtrans ); - sgNormaliseVec3( lightVec ); - sgCopyVec3( SGNewCloud::modelSunDir, lightVec ); - // try to find the lighting data (buggy) + sgSetVec3( SGNewCloud::modelSunDir, lightVec[0], lightVec[2], lightVec[1]); + // try to find the lighting data (not accurate) sgVec4 diffuse, ambient; ssgGetLight( 0 )->getColour( GL_DIFFUSE, diffuse ); ssgGetLight( 0 )->getColour( GL_AMBIENT, ambient ); - sgScaleVec3 ( SGNewCloud::sunlight, diffuse , 0.70f); - sgScaleVec3 ( SGNewCloud::ambLight, ambient , 0.60f); +// sgScaleVec3 ( SGNewCloud::sunlight, diffuse , 1.0f); + sgScaleVec3 ( SGNewCloud::ambLight, ambient , 1.1f); + // trying something else : clouds are more yellow/red at dawn/dusk + // and added a bit of blue ambient + sgScaleVec3 ( SGNewCloud::sunlight, sun_color , 0.4f); + SGNewCloud::ambLight[2] += 0.1f; + + sgVec3 delta_light; + sgSubVec3(delta_light, last_sunlight, SGNewCloud::sunlight); + if( (fabs(delta_light[0]) + fabs(delta_light[1]) + fabs(delta_light[2])) > 0.05f ) { + sgCopyVec3( last_sunlight, SGNewCloud::sunlight ); + // force the redraw of all the impostors + SGNewCloud::cldCache->invalidateCache(); + } // voodoo things on the matrix stack ssgGetModelviewMatrix( modelview ); sgCopyMat4( tmp, transform ); sgPostMultMat4( tmp, modelview ); - sgSetVec3( eyePos, -relx, -tmp[3][2], -rely); - sgSetVec3( eyePos, -relx, 0, -rely); - sgSetVec3( eyePos, -relx, alt, -rely); -// sgSetVec3( eyePos, 0, - tmp[3][2], 0); -// sgSetVec3( eyePos, 20000, - tmp[3][2], 20000); + // cloud fields are tiled on the flat earth + // compute the position in the tile + relx = fmod( deltax + relative_position[SG_X], fieldSize ); + rely = fmod( deltay + relative_position[SG_Y], fieldSize ); + + relx = fmod( relx + fieldSize, fieldSize ); + rely = fmod( rely + fieldSize, fieldSize ); + sgSetVec3( eyePos, relx, alt, rely); + + sgSetVec3( view_X, tmp[0][0], tmp[1][0], tmp[2][0] ); + sgSetVec3( view_Y, tmp[0][1], tmp[1][1], tmp[2][1] ); + sgSetVec3( view_vec, tmp[0][2], tmp[1][2], tmp[2][2] ); - tmp[3][2] = 0; - tmp[3][0] = 0; - tmp[3][1] = 0; ssgLoadModelviewMatrix( tmp ); /* flat earth @@ -290,19 +493,18 @@ void SGCloudField::Render(void) { cullClouds(fieldPos, tmp); } // sort all visible clouds back to front (because of transparency) - sort( inViewClouds.begin(), inViewClouds.end() ); + std::sort( inViewClouds.begin(), inViewClouds.end() ); // TODO:push states glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GREATER, 0.0f); glDisable(GL_CULL_FACE); -// glDisable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST); + glDepthMask( GL_FALSE ); glEnable(GL_SMOOTH); glEnable(GL_BLEND); - glBlendFunc( GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); -// glEnable( GL_COLOR_MATERIAL ); + glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA ); glEnable( GL_TEXTURE_2D ); glDisable( GL_FOG ); glDisable(GL_LIGHTING); @@ -313,15 +515,18 @@ void SGCloudField::Render(void) { for( iCloud = inViewClouds.begin() ; iCloud != inViewClouds.end() ; iCloud++ ) { // iCloud->aCloud->drawContainers(); iCloud->aCloud->Render(iCloud->eyePos); + sgEnviro.callback_cloud(iCloud->heading, iCloud->alt, + iCloud->aCloud->getRadius(), iCloud->aCloud->getFamilly(), - iCloud->dist, iCloud->aCloud->getId()); } glBindTexture(GL_TEXTURE_2D, 0); glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ; + glEnable( GL_FOG ); + glEnable(GL_CULL_FACE); + glEnable(GL_DEPTH_TEST); ssgLoadModelviewMatrix( modelview ); glPopMatrix(); -// glEnable(GL_DEPTH_TEST); - +#endif } -