# include <simgear_config.h>
#endif
+#include <osg/Fog>
+#include <osg/Texture2D>
+#include <osg/PositionAttitudeTransform>
+#include <osg/Vec4f>
+
#include <simgear/compiler.h>
-#include <plib/sg.h>
#include <simgear/math/sg_random.h>
#include <simgear/math/sg_geodesy.hxx>
-#include <simgear/math/polar3d.hxx>
+#include <simgear/scene/util/SGSceneUserData.hxx>
-#include STL_ALGORITHM
+#include <algorithm>
#include <vector>
+#include <iostream>
+
+using namespace std;
-SG_USING_STD(vector);
+using std::vector;
-#include <simgear/environment/visual_enviro.hxx>
+//#include <simgear/environment/visual_enviro.hxx>
+#include <simgear/scene/util/RenderConstants.hxx>
+#include <simgear/scene/util/SGUpdateVisitor.hxx>
#include "sky.hxx"
#include "newcloud.hxx"
#include "cloudfield.hxx"
# endif
#endif
+using namespace simgear;
-#if defined (__CYGWIN__)
-#include <ieeefp.h>
-#endif
-
-extern SGSky *thesky;
-
-static list_of_culledCloud inViewClouds;
-
-// visibility distance for clouds in meters
-float SGCloudField::CloudVis = 25000.0f;
-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 = 50000.0;
-float SGCloudField::density = 100.0;
+float SGCloudField::fieldSize = 50000.0f;
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;
+float SGCloudField::view_distance = 20000.0f;
+bool SGCloudField::wrap = true;
+float SGCloudField::RADIUS_LEVEL_1 = 5000.0f;
+float SGCloudField::RADIUS_LEVEL_2 = 1000.0f;
+
+SGVec3f SGCloudField::view_vec, SGCloudField::view_X, SGCloudField::view_Y;
+
+
+// Reposition the cloud layer at the specified origin and orientation
+bool SGCloudField::reposition( const SGVec3f& p, const SGVec3f& up, double lon, double lat,
+ double dt, int asl, float speed, float direction ) {
+ // Determine any movement of the placed clouds
+ if (placed_root->getNumChildren() == 0) return false;
+
+ SGVec3<double> cart;
+ SGGeod new_pos = SGGeod::fromRadFt(lon, lat, 0.0f);
+
+ SGGeodesy::SGGeodToCart(new_pos, cart);
+ osg::Vec3f osg_pos = toOsg(cart);
+ osg::Quat orient = toOsg(SGQuatd::fromLonLatRad(lon, lat) * SGQuatd::fromRealImag(0, SGVec3d(0, 1, 0)));
+
+ // Always update the altitude transform, as this allows
+ // the clouds to rise and fall smoothly depending on environment updates.
+ altitude_transform->setPosition(osg::Vec3f(0.0f, 0.0f, (float) asl));
+
+ // Similarly, always determine the effects of the wind
+ osg::Vec3f wind = osg::Vec3f(-cos((direction + 180)* SGD_DEGREES_TO_RADIANS) * speed * dt,
+ sin((direction + 180)* SGD_DEGREES_TO_RADIANS) * speed * dt,
+ 0.0f);
+ osg::Vec3f windosg = field_transform->getAttitude() * wind;
+ field_transform->setPosition(field_transform->getPosition() + windosg);
+
+ if (!wrap) {
+ // If we're not wrapping the cloudfield, then we make no effort to reposition
+ return false;
+ }
+
+ if ((old_pos - osg_pos).length() > fieldSize*2) {
+ // Big movement - reposition centered to current location.
+ field_transform->setPosition(osg_pos);
+ field_transform->setAttitude(orient);
+ old_pos = osg_pos;
+ } else {
+ osg::Quat fta = field_transform->getAttitude();
+ osg::Quat ftainv = field_transform->getAttitude().inverse();
+
+ // delta is the vector from the old position to the new position in cloud-coords
+ osg::Vec3f delta = ftainv * (osg_pos - old_pos);
+ old_pos = osg_pos;
+
+ // Check if any of the clouds should be moved.
+ for(CloudHash::const_iterator itr = cloud_hash.begin(), end = cloud_hash.end();
+ itr != end;
+ ++itr) {
+
+ osg::ref_ptr<osg::PositionAttitudeTransform> pat = itr->second;
+ osg::Vec3f currpos = field_transform->getPosition() + fta * pat->getPosition();
+
+ // Determine the vector from the new position to the cloud in cloud-space.
+ osg::Vec3f w = ftainv * (currpos - toOsg(cart));
+
+ // Determine a course if required. Note that this involves some axis translation.
+ float x = 0.0;
+ float y = 0.0;
+ if (w.x() > 0.6*fieldSize) { y = fieldSize; }
+ if (w.x() < -0.6*fieldSize) { y = -fieldSize; }
+ if (w.y() > 0.6*fieldSize) { x = -fieldSize; }
+ if (w.y() < -0.6*fieldSize) { x = fieldSize; }
+
+ if ((x != 0.0) || (y != 0.0)) {
+ removeCloudFromTree(pat);
+ SGGeod p = SGGeod::fromCart(toSG(field_transform->getPosition() +
+ fta * pat->getPosition()));
+ addCloudToTree(pat, p, x, y);
+ }
+ }
+ }
+
+ // Render the clouds in order from farthest away layer to nearest one.
+ field_root->getStateSet()->setRenderBinDetails(CLOUDS_BIN, "DepthSortedBin");
+ return true;
}
-void SGCloudField::set_CacheSize(int sizeKb) {
-#if 0
- // apply in rendering option dialog
- if(last_cache_size == sizeKb)
- return;
- if(sizeKb == 0)
- return;
- if(sizeKb)
- last_cache_size = 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) {
-#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) {
- 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
+SGCloudField::SGCloudField() :
+ field_root(new osg::Group),
+ field_transform(new osg::PositionAttitudeTransform),
+ altitude_transform(new osg::PositionAttitudeTransform)
+{
+ old_pos = osg::Vec3f(0.0f, 0.0f, 0.0f);
+ field_root->addChild(field_transform.get());
+ field_root->setName("3D Cloud field root");
+ osg::StateSet *rootSet = field_root->getOrCreateStateSet();
+ rootSet->setRenderBinDetails(CLOUDS_BIN, "DepthSortedBin");
+ rootSet->setAttributeAndModes(getFog());
+
+ field_transform->addChild(altitude_transform.get());
+ placed_root = new osg::Group();
+ altitude_transform->addChild(placed_root);
}
+
+SGCloudField::~SGCloudField() {
+ }
-// 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, float direction, float speed) {
-#if 0
- sgMat4 T1, LON, LAT;
- sgVec3 axis;
-
- sgMakeTransMat4( T1, p );
-
- sgSetVec3( axis, 0.0, 0.0, 1.0 );
- sgMakeRotMat4( LON, lon * SGD_RADIANS_TO_DEGREES, axis );
-
- sgSetVec3( axis, 0.0, 1.0, 0.0 );
- sgMakeRotMat4( LAT, 90.0 - lat * SGD_RADIANS_TO_DEGREES, axis );
-
- sgMat4 TRANSFORM;
- sgCopyMat4( TRANSFORM, T1 );
- sgPreMultMat4( TRANSFORM, LON );
- sgPreMultMat4( TRANSFORM, LAT );
+void SGCloudField::clear(void) {
- sgCoord layerpos;
- sgSetCoord( &layerpos, TRANSFORM );
+ for(CloudHash::const_iterator itr = cloud_hash.begin(), end = cloud_hash.end();
+ itr != end;
+ ++itr) {
+ removeCloudFromTree(itr->second);
+ }
+
+ cloud_hash.clear();
+}
- sgMakeCoordMat4( transform, &layerpos );
+void SGCloudField::applyVisRange(void)
+{
+ for (unsigned int i = 0; i < placed_root->getNumChildren(); i++) {
+ osg::ref_ptr<osg::LOD> lodnode1 = (osg::LOD*) placed_root->getChild(i);
+ for (unsigned int j = 0; j < lodnode1->getNumChildren(); j++) {
+ osg::ref_ptr<osg::LOD> lodnode2 = (osg::LOD*) lodnode1->getChild(j);
+ for (unsigned int k = 0; k < lodnode2->getNumChildren(); k++) {
+ lodnode2->setRange(k, 0.0f, view_distance);
+ }
+ }
+ }
+}
+
+bool SGCloudField::addCloud(float lon, float lat, float alt, int index, osg::ref_ptr<EffectGeode> geode) {
+ return addCloud(lon, lat, alt, 0.0f, 0.0f, index, geode);
+ }
+bool SGCloudField::addCloud(float lon, float lat, float alt, float x, float y, int index, osg::ref_ptr<EffectGeode> geode) {
+ // If this cloud index already exists, don't replace it.
+ if (cloud_hash[index]) return false;
- this->alt = alt;
+ osg::ref_ptr<osg::PositionAttitudeTransform> transform = new osg::PositionAttitudeTransform;
- // simulate clouds movement from wind
- double sp_dist = speed*dt;
- if (sp_dist > 0) {
- double bx = cos((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
- double by = sin((180.0-direction) * SGD_DEGREES_TO_RADIANS) * sp_dist;
- relative_position[SG_X] += bx;
- relative_position[SG_Y] += by;
+ transform->addChild(geode.get());
+ addCloudToTree(transform, lon, lat, alt, x, y);
+ cloud_hash[index] = transform;
+ return true;
}
-
- 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;
+
+// Remove a give cloud from inside the tree, without removing it from the cloud hash
+void SGCloudField::removeCloudFromTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform)
+{
+ osg::ref_ptr<osg::Group> lodnode = transform->getParent(0);
+ lodnode->removeChild(transform);
+
+ // Clean up the LOD nodes if required
+ if (lodnode->getNumChildren() == 0) {
+ osg::ref_ptr<osg::Group> lodnode1 = lodnode->getParent(0);
+
+ lodnode1->removeChild(lodnode);
+
+ if (lodnode1->getNumChildren() == 0) {
+ placed_root->removeChild(lodnode1);
}
+ }
+}
- // calculate cloud movement due to external forces
- double ax = 0.0, ay = 0.0;
+void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform,
+ float lon, float lat, float alt, float x, float y) {
+
+ // Get the base position
+ SGGeod loc = SGGeod::fromDegFt(lon, lat, alt);
+ addCloudToTree(transform, loc, x, y);
+}
- if (dist > 0.0) {
- ax = cos(course) * dist;
- ay = sin(course) * dist;
- }
- deltax += ax;
- deltay += ay;
+void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform,
+ SGGeod loc, float x, float y) {
+
+ float alt = loc.getElevationFt();
+ // Determine any shift by x/y
+ if ((x != 0.0f) || (y != 0.0f)) {
+ double crs = 90.0 - SG_RADIANS_TO_DEGREES * atan2(y, x);
+ double dst = sqrt(x*x + y*y);
+ double endcrs;
+
+ SGGeod base_pos = SGGeod::fromGeodFt(loc, 0.0f);
+ SGGeodesy::direct(base_pos, crs, dst, loc, endcrs);
+ }
+
+ // The direct call provides the position at 0 alt, so adjust as required.
+ loc.setElevationFt(alt);
+ addCloudToTree(transform, loc);
+}
+
+
+void SGCloudField::addCloudToTree(osg::ref_ptr<osg::PositionAttitudeTransform> transform, SGGeod loc) {
+ // Work out where this cloud should go in OSG coordinates.
+ SGVec3<double> cart;
+ SGGeodesy::SGGeodToCart(loc, cart);
+ osg::Vec3f pos = toOsg(cart);
+
+
+ if (old_pos == osg::Vec3f(0.0f, 0.0f, 0.0f)) {
+ // First setup.
+ SGVec3<double> fieldcenter;
+ SGGeodesy::SGGeodToCart(SGGeod::fromDegFt(loc.getLongitudeDeg(), loc.getLatitudeDeg(), 0.0f), fieldcenter);
+ // Convert to the scenegraph orientation where we just rotate around
+ // the y axis 180 degrees.
+ osg::Quat orient = toOsg(SGQuatd::fromLonLatDeg(loc.getLongitudeDeg(), loc.getLatitudeDeg()) * SGQuatd::fromRealImag(0, SGVec3d(0, 1, 0)));
+
+ osg::Vec3f osg_pos = toOsg(fieldcenter);
+
+ field_transform->setPosition(osg_pos);
+ field_transform->setAttitude(orient);
+ old_pos = osg_pos;
+ }
+
+ // Convert position to cloud-coordinates
+ pos = pos - field_transform->getPosition();
+ pos = field_transform->getAttitude().inverse() * pos;
+
+ // We have a two level dynamic quad tree which the cloud will be added
+ // to. If there are no appropriate nodes in the quad tree, they are
+ // created as required.
+ bool found = false;
+ osg::ref_ptr<osg::LOD> lodnode1;
+ osg::ref_ptr<osg::LOD> lodnode;
+
+ for (unsigned int i = 0; (!found) && (i < placed_root->getNumChildren()); i++) {
+ lodnode1 = (osg::LOD*) placed_root->getChild(i);
+ if ((lodnode1->getCenter() - pos).length2() < RADIUS_LEVEL_1*RADIUS_LEVEL_1) {
+ // New cloud is within RADIUS_LEVEL_1 of the center of the LOD node.
+ found = true;
+ }
+ }
- last_lon = lon;
- last_lat = lat;
+ if (!found) {
+ lodnode1 = new osg::LOD();
+ placed_root->addChild(lodnode1.get());
}
+ // Now check if there is a second level LOD node at an appropriate distance
+ found = false;
- // correct the frustum with the right far plane
- ssgContext *context = ssgGetCurrentContext();
- frustum = *context->getFrustum();
+ for (unsigned int j = 0; (!found) && (j < lodnode1->getNumChildren()); j++) {
+ lodnode = (osg::LOD*) lodnode1->getChild(j);
+ if ((lodnode->getCenter() - pos).length2() < RADIUS_LEVEL_2*RADIUS_LEVEL_2) {
+ // We've found the right leaf LOD node
+ found = true;
+ }
+ }
- float w, h;
- sgEnviro.getFOV( w, h );
- frustum.setFOV( w, h );
- frustum.setNearFar(1.0, CloudVis);
- timer_dt = dt;
-#endif
-}
+ if (!found) {
+ // No suitable leave node was found, so we need to add one.
+ lodnode = new osg::LOD();
+ lodnode1->addChild(lodnode, 0.0f, 4*RADIUS_LEVEL_1);
+ }
-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
-}
+ transform->setPosition(pos);
+ lodnode->addChild(transform.get(), 0.0f, view_distance);
-SGCloudField::~SGCloudField() {
-#if 0
- list_of_Cloud::iterator iCloud;
- for( iCloud = theField.begin() ; iCloud != theField.end() ; iCloud++ ) {
- delete iCloud->aCloud;
- }
- theField.clear();
-#endif
+ lodnode->dirtyBound();
+ lodnode1->dirtyBound();
+ field_root->dirtyBound();
}
-
-
-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
+
+bool SGCloudField::deleteCloud(int identifier) {
+ osg::ref_ptr<osg::PositionAttitudeTransform> transform = cloud_hash[identifier];
+ if (transform == NULL) return false;
+
+ removeCloudFromTree(transform);
+ cloud_hash.erase(identifier);
+
+ return true;
}
-
-// 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
+
+bool SGCloudField::repositionCloud(int identifier, float lon, float lat, float alt) {
+ return repositionCloud(identifier, lon, lat, alt, 0.0f, 0.0f);
}
-// add one cloud, data is not copied, ownership given
-void SGCloudField::addCloud( sgVec3 pos, SGNewCloud *cloud) {
-#if 0
- Cloud cl;
- cl.aCloud = cloud;
- cl.visible = true;
- cloud->SetPos( pos );
- sgCopyVec3( cl.pos, *cloud->getCenter() );
- theField.push_back( cl );
-#endif
-}
+bool SGCloudField::repositionCloud(int identifier, float lon, float lat, float alt, float x, float y) {
+ osg::ref_ptr<osg::PositionAttitudeTransform> transform = cloud_hash[identifier];
+
+ if (transform == NULL) return false;
+ removeCloudFromTree(transform);
+ addCloudToTree(transform, lon, lat, alt, x, y);
+ return true;
+ }
-static float Rnd(float n) {
- return n * (-0.5f + sg_random());
+bool SGCloudField::isDefined3D(void) {
+ return (cloud_hash.size() > 0);
}
-// for debug only
-// build a field of cloud of size 25x25 km, its a grid of 11x11 clouds
-void SGCloudField::buildTestLayer(void) {
-#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::CLFamilly_cu);
- cloud->new_cu();
- sgVec3 pos = {(x+Rnd(0.7)) * s, 750.0f, (z+Rnd(0.7)) * s};
- addCloud(pos, cloud);
- }
- }
- applyDensity();
-#endif
+SGCloudField::CloudFog::CloudFog() {
+ fog = new osg::Fog;
+ fog->setMode(osg::Fog::EXP2);
+ fog->setDataVariance(osg::Object::DYNAMIC);
}
-// cull all clouds of a tiled field
-void SGCloudField::cullClouds(sgVec3 eyePos, sgMat4 mat) {
-#if 0
- list_of_Cloud::iterator iCloud;
-
- 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] + 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];
- culledCloud tmp;
- tmp.aCloud = iCloud->aCloud;
- 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
+void SGCloudField::updateFog(double visibility, const osg::Vec4f& color) {
+ const double sqrt_m_log01 = sqrt(-log(0.01));
+ osg::Fog* fog = CloudFog::instance()->fog.get();
+ fog->setColor(color);
+ fog->setDensity(sqrt_m_log01 / visibility);
}
-
-// 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) {
-#if 0
- sgVec3 eyePos;
- double relx, rely;
-
- if( ! enable3D )
- return;
-
- if( last_density != density ) {
- last_density = density;
- applyDensity();
- }
-
- if( ! draw_in_3d )
- return;
-
- if( ! SGNewCloud::cldCache->isRttAvailable() )
- return;
-
- inViewClouds.clear();
-
-
- glPushMatrix();
-
- sgMat4 modelview, tmp, invtrans;
-
- // try to find the sun position
- sgTransposeNegateMat4( invtrans, transform );
- sgVec3 lightVec;
- ssgGetLight( 0 )->getPosition( lightVec );
- sgXformVec3( lightVec, invtrans );
-
- 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 , 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
- float *sun_color = thesky->get_sun_color();
- 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 );
-
- // 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] );
-
- ssgLoadModelviewMatrix( tmp );
-
-/* flat earth
-
- ^
- |
- | FFF
- | FoF
- | FFF
- |
- O----------->
- o = we are here
- F = adjacent fields
-*/
-
- for(int x = -1 ; x <= 1 ; x++)
- for(int y = -1 ; y <= 1 ; y++ ) {
- sgVec3 fieldPos;
- // pretend we are not where we are
- sgSetVec3(fieldPos, eyePos[0] + x*fieldSize, eyePos[1], eyePos[2] + y*fieldSize);
- cullClouds(fieldPos, tmp);
- }
- // sort all visible clouds back to front (because of transparency)
- 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);
- glEnable(GL_DEPTH_TEST);
- glDepthMask( GL_FALSE );
- glEnable(GL_SMOOTH);
- glEnable(GL_BLEND);
- glBlendFunc( GL_ONE, GL_ONE_MINUS_SRC_ALPHA );
- glEnable( GL_TEXTURE_2D );
- glDisable( GL_FOG );
- glDisable(GL_LIGHTING);
-
- // test data: field = 11x11 cloud, 9 fields
- // depending on position and view direction, perhaps 40 to 60 clouds not culled
- list_of_culledCloud::iterator iCloud;
- 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();
-#endif
-}