// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
-// You should have received a copy of the GNU Library General Public
-// License along with this library; if not, write to the
-// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
-// Boston, MA 02111-1307, USA.
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
+#ifdef HAVE_CONFIG_H
+# include <simgear_config.h>
+#endif
-#include <plib/sg.h>
-#include <plib/ssg.h>
+#include "sky.hxx"
+#include "cloudfield.hxx"
+#include "newcloud.hxx"
#include <simgear/math/sg_random.h>
+#include <simgear/scene/util/RenderConstants.hxx>
+#include <simgear/sg_inlines.h>
-#include "sky.hxx"
-
+#include <osg/StateSet>
+#include <osg/Depth>
// Constructor
SGSky::SGSky( void ) {
puff_progression = 0;
ramp_up = 0.15;
ramp_down = 0.15;
- // ramp_up = 4.0;
- // ramp_down = 4.0;
in_cloud = -1;
+
+ clouds_3d_enabled = false;
+ clouds_3d_density = 0.8;
+
+ pre_root = new osg::Group;
+ pre_root->setNodeMask(simgear::BACKGROUND_BIT);
+ osg::StateSet* preStateSet = new osg::StateSet;
+ preStateSet->setAttribute(new osg::Depth(osg::Depth::LESS, 0.0, 1.0,
+ false));
+ pre_root->setStateSet(preStateSet);
+ cloud_root = new osg::Group;
+ cloud_root->setNodeMask(simgear::MODEL_BIT);
+
+ pre_selector = new osg::Switch;
+
+ pre_transform = new osg::Group;
+
+ _ephTransform = new osg::MatrixTransform;
}
// Destructor
SGSky::~SGSky( void )
{
- for (unsigned int i = 0; i < cloud_layers.size(); i++)
- delete cloud_layers[i];
}
// the provided branch
void SGSky::build( double h_radius_m, double v_radius_m,
double sun_size, double moon_size,
- int nplanets, sgdVec3 *planet_data,
- int nstars, sgdVec3 *star_data )
+ const SGEphemeris& eph, SGPropertyNode *property_tree_node )
{
- pre_root = new ssgRoot;
- post_root = new ssgRoot;
-
- pre_selector = new ssgSelector;
- post_selector = new ssgSelector;
-
- pre_transform = new ssgTransform;
- post_transform = new ssgTransform;
-
dome = new SGSkyDome;
- pre_transform -> addKid( dome->build( h_radius_m, v_radius_m ) );
+ pre_transform->addChild( dome->build( h_radius_m, v_radius_m ) );
+ pre_transform->addChild(_ephTransform.get());
planets = new SGStars;
- pre_transform -> addKid(planets->build(nplanets, planet_data, h_radius_m));
+ _ephTransform->addChild( planets->build(eph.getNumPlanets(), eph.getPlanets(), h_radius_m) );
stars = new SGStars;
- pre_transform -> addKid( stars->build(nstars, star_data, h_radius_m) );
+ _ephTransform->addChild( stars->build(eph.getNumStars(), eph.getStars(), h_radius_m) );
moon = new SGMoon;
- pre_transform -> addKid( moon->build(tex_path, moon_size) );
+ _ephTransform->addChild( moon->build(tex_path, moon_size) );
oursun = new SGSun;
- pre_transform -> addKid( oursun->build(tex_path, sun_size) );
-
- pre_selector->addKid( pre_transform );
- pre_selector->clrTraversalMaskBits( SSGTRAV_HOT );
+ _ephTransform->addChild( oursun->build(tex_path, sun_size, property_tree_node ) );
- post_selector->addKid( post_transform );
- post_selector->clrTraversalMaskBits( SSGTRAV_HOT );
+ pre_selector->addChild( pre_transform.get() );
- pre_root->addKid( pre_selector );
- post_root->addKid( post_selector );
+ pre_root->addChild( pre_selector.get() );
}
// 0 degrees = high noon
// 90 degrees = sun rise/set
// 180 degrees = darkest midnight
-bool SGSky::repaint( const SGSkyColor &sc )
+bool SGSky::repaint( const SGSkyColor &sc, const SGEphemeris& eph )
{
if ( effective_visibility > 1000.0 ) {
enable();
- dome->repaint( sc.sky_color, sc.fog_color, sc.sun_angle,
- effective_visibility );
-
- stars->repaint( sc.sun_angle, sc.nstars, sc.star_data );
- planets->repaint( sc.sun_angle, sc.nplanets, sc.planet_data );
+ dome->repaint( sc.adj_sky_color, sc.sky_color, sc.fog_color,
+ sc.sun_angle, effective_visibility );
+ stars->repaint( sc.sun_angle, eph.getNumStars(), eph.getStars() );
+ planets->repaint( sc.sun_angle, eph.getNumPlanets(), eph.getPlanets() );
oursun->repaint( sc.sun_angle, effective_visibility );
moon->repaint( sc.moon_angle );
- for ( int i = 0; i < (int)cloud_layers.size(); ++i ) {
+ for ( unsigned i = 0; i < cloud_layers.size(); ++i ) {
if (cloud_layers[i]->getCoverage() != SGCloudLayer::SG_CLOUD_CLEAR){
cloud_layers[i]->repaint( sc.cloud_color );
}
// turn off sky
disable();
}
-
+ SGCloudField::updateFog((double)effective_visibility,
+ osg::Vec4f(toOsg(sc.fog_color), 1.0f));
return true;
}
-
// reposition the sky at the specified origin and orientation
//
// lon specifies a rotation about the Z axis
// spin specifies a rotation about the new Z axis (this allows
// additional orientation for the sunrise/set effects and is used by
// the skydome and perhaps clouds.
-bool SGSky::reposition( SGSkyState &st, double dt )
+bool SGSky::reposition( const SGSkyState &st, const SGEphemeris& eph, double dt )
{
-
double angle = st.gst * 15; // degrees
+ double angleRad = SGMiscd::deg2rad(angle);
- dome->reposition( st.zero_elev, st.lon, st.lat, st.spin );
+ SGVec3f zero_elev, view_up;
+ double lon, lat, alt;
- stars->reposition( st.view_pos, angle );
- planets->reposition( st.view_pos, angle );
+ SGGeod geodZeroViewPos = SGGeod::fromGeodM(st.pos_geod, 0);
+ zero_elev = toVec3f( SGVec3d::fromGeod(geodZeroViewPos) );
- oursun->reposition( st.view_pos, angle,
- st.sun_ra, st.sun_dec, st.sun_dist );
+ // calculate the scenery up vector
+ SGQuatd hlOr = SGQuatd::fromLonLat(st.pos_geod);
+ view_up = toVec3f(hlOr.backTransform(-SGVec3d::e3()));
- moon->reposition( st.view_pos, angle,
- st.moon_ra, st.moon_dec, st.moon_dist );
-
- for ( int i = 0; i < (int)cloud_layers.size(); ++i ) {
- if ( cloud_layers[i]->getCoverage() != SGCloudLayer::SG_CLOUD_CLEAR ) {
- cloud_layers[i]->reposition( st.zero_elev, st.view_up,
- st.lon, st.lat, st.alt, dt );
- }
- }
-
- return true;
-}
+ // viewer location
+ lon = st.pos_geod.getLongitudeRad();
+ lat = st.pos_geod.getLatitudeRad();
+ alt = st.pos_geod.getElevationM();
+ dome->reposition( zero_elev, alt, lon, lat, st.spin );
-// draw background portions of the sky ... do this before you draw the
-// rest of your scene.
-void SGSky::preDraw( float alt, float fog_exp2_density ) {
- ssgCullAndDraw( pre_root );
+ osg::Matrix m = osg::Matrix::rotate(angleRad, osg::Vec3(0, 0, -1));
+ m.postMultTranslate(toOsg(st.pos));
+ _ephTransform->setMatrix(m);
- // if we are closer than this to a cloud layer, don't draw clouds
- static const float slop = 5.0;
- int i;
+ double sun_ra = eph.getSunRightAscension();
+ double sun_dec = eph.getSunDeclination();
+ oursun->reposition( sun_ra, sun_dec, st.sun_dist, lat, alt, st.sun_angle );
- // check where we are relative to the cloud layers
- in_cloud = -1;
- for ( i = 0; i < (int)cloud_layers.size(); ++i ) {
- float asl = cloud_layers[i]->getElevation_m();
- float thickness = cloud_layers[i]->getThickness_m();
-
- if ( alt < asl - slop ) {
- // below cloud layer
- } else if ( alt < asl + thickness + slop ) {
- // in cloud layer
-
- // bail now and don't draw any clouds
- in_cloud = i;
- } else {
- // above cloud layer
- }
- }
-
- // determine rendering order
- cur_layer_pos = 0;
- while ( cur_layer_pos < (int)cloud_layers.size() &&
- alt > cloud_layers[cur_layer_pos]->getElevation_m())
- {
- ++cur_layer_pos;
- }
-
- // FIXME: This should not be needed, but at this time (08/15/2003)
- // certain NVidia drivers don't seem to implement
- // glPushAttrib(FG_FOG_BIT) properly. The result is that
- // there is not fog when looking at the sun.
- glFogf ( GL_FOG_DENSITY, fog_exp2_density );
-}
+ double moon_ra = eph.getMoonRightAscension();
+ double moon_dec = eph.getMoonDeclination();
+ moon->reposition( moon_ra, moon_dec, st.moon_dist );
-void SGSky::drawUpperClouds( ) {
- // draw the cloud layers that are above us, top to bottom
- for ( int i = (int)cloud_layers.size() - 1; i >= cur_layer_pos; --i ) {
- if ( i != in_cloud ) {
- cloud_layers[i]->draw( false );
- }
+ for ( unsigned i = 0; i < cloud_layers.size(); ++i ) {
+ if ( cloud_layers[i]->getCoverage() != SGCloudLayer::SG_CLOUD_CLEAR ) {
+ cloud_layers[i]->reposition( zero_elev, view_up, lon, lat, alt, dt);
+ } else
+ cloud_layers[i]->getNode()->setAllChildrenOff();
}
-}
-
-// draw translucent clouds ... do this after you've drawn all the
-// oapaque elements of your scene.
-void SGSky::drawLowerClouds() {
-
- // draw the cloud layers that are below us, bottom to top
- for ( int i = 0; i < cur_layer_pos; ++i ) {
- if ( i != in_cloud ) {
- cloud_layers[i]->draw( true );
- }
- }
+ return true;
}
void
SGSky::add_cloud_layer( SGCloudLayer * layer )
{
cloud_layers.push_back(layer);
+ cloud_root->addChild(layer->getNode());
+
+ layer->set_enable3dClouds(clouds_3d_enabled);
}
const SGCloudLayer *
return cloud_layers.size();
}
+double SGSky::get_3dCloudDensity() const {
+ return SGNewCloud::getDensity();
+}
+
+void SGSky::set_3dCloudDensity(double density)
+{
+ SGNewCloud::setDensity(density);
+}
+
+float SGSky::get_3dCloudVisRange() const {
+ return SGCloudField::getVisRange();
+}
+
+void SGSky::set_3dCloudVisRange(float vis)
+{
+ SGCloudField::setVisRange(vis);
+ for ( int i = 0; i < (int)cloud_layers.size(); ++i ) {
+ cloud_layers[i]->get_layer3D()->applyVisRange();
+ }
+}
+
+void SGSky::texture_path( const string& path ) {
+ tex_path = SGPath( path );
+}
+
// modify the current visibility based on cloud layers, thickness,
// transition range, and simulated "puffs".
void SGSky::modify_vis( float alt, float time_factor ) {
double ratio = 1.0;
if ( cloud_layers[i]->getCoverage() == SGCloudLayer::SG_CLOUD_CLEAR ) {
- // clear layer
+ // less than 50% coverage -- assume we're in the clear for now
ratio = 1.0;
} else if ( alt < asl - transition ) {
// below cloud layer
ratio = 1.0;
}
- // accumulate effects from multiple cloud layers
- effvis *= ratio;
+ if ( cloud_layers[i]->getCoverage() == SGCloudLayer::SG_CLOUD_CLEAR ||
+ cloud_layers[i]->get_layer3D()->defined3D) {
+ // do nothing, clear layers aren't drawn, don't affect
+ // visibility andn dont' need to be faded in or out.
+ } else if ( (cloud_layers[i]->getCoverage() ==
+ SGCloudLayer::SG_CLOUD_FEW)
+ || (cloud_layers[i]->getCoverage() ==
+ SGCloudLayer::SG_CLOUD_SCATTERED) )
+ {
+ // set the alpha fade value for the cloud layer. For less
+ // dense cloud layers we fade the layer to nothing as we
+ // approach it because we stay clear visibility-wise as we
+ // pass through it.
+ float temp = ratio * 2.0;
+ if ( temp > 1.0 ) { temp = 1.0; }
+ cloud_layers[i]->setAlpha( temp );
+
+ // don't touch visibility
+ } else {
+ // maintain full alpha for denser cloud layer types.
+ // Let's set the value explicitly in case someone changed
+ // the layer type.
+ cloud_layers[i]->setAlpha( 1.0 );
+
+ // lower visibility as we approach the cloud layer.
+ // accumulate effects from multiple cloud layers
+ effvis *= ratio;
+ }
+#if 0
if ( ratio < 1.0 ) {
if ( ! in_puff ) {
// calc chance of entering cloud puff
// modify actual_visibility based on puff envelope
if ( puff_progression <= ramp_up ) {
- double x = 0.5 * SGD_PI * puff_progression / ramp_up;
+ double x = SGD_PI_2 * puff_progression / ramp_up;
double factor = 1.0 - sin( x );
// cout << "ramp up = " << puff_progression
// << " factor = " << factor << endl;
effvis = effvis * factor;
} else if ( puff_progression >= ramp_up + puff_length ) {
- double x = 0.5 * SGD_PI *
+ double x = SGD_PI_2 *
(puff_progression - (ramp_up + puff_length)) /
ramp_down;
double factor = sin( x );
in_puff = false;
}
}
-
- // never let visibility drop below 25 meters
- if ( effvis <= 25.0 ) {
- effvis = 25.0;
- }
}
+#endif
+
+ // never let visibility drop below the layer's configured visibility
+ effvis = SG_MAX2<float>(cloud_layers[i]->getVisibility_m(), effvis );
+
} // for
effective_visibility = effvis;
}
+
+