]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/sky/cloudfield.cxx
Remove an extern SGSky *thesky reference that isn't used in the code anyway.
[simgear.git] / simgear / scene / sky / cloudfield.cxx
index a847c57a1bdc972233a593b3dd20dc15806f2b75..8d83037d918d1d9a7b5565e408bb6b7aacca1cbb 100644 (file)
@@ -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.
 //
 //
 
 #include <simgear/compiler.h>
 
 #include <plib/sg.h>
-#include <plib/ssg.h>
+#include <simgear/math/sg_random.h>
 #include <simgear/math/sg_geodesy.hxx>
+#include <simgear/math/polar3d.hxx>
 
 #include STL_ALGORITHM
-#include SG_GLUT_H
 #include <vector>
 
 SG_USING_STD(vector);
 
+#include <simgear/environment/visual_enviro.hxx>
+#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 <ieeefp.h>
+#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
 }
-