// 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$
#include <simgear/compiler.h>
-#include <stdio.h>
-#include STL_IOSTREAM
-
-#include <plib/sg.h>
-#include <plib/ssg.h>
-
-// define the following to enable a cheesy lens flare effect for the sun
-// #define FG_TEST_CHEESY_LENS_FLARE
-
-#ifdef FG_TEST_CHEESY_LENS_FLARE
-# include <plib/ssgaLensFlare.h>
-#endif
-
+#include <osg/AlphaFunc>
+#include <osg/BlendFunc>
+#include <osg/Fog>
+#include <osg/Geode>
+#include <osg/Geometry>
+#include <osg/Material>
+#include <osg/ShadeModel>
+#include <osg/TexEnv>
+#include <osg/Texture2D>
+#include <osgDB/ReadFile>
+
+#include <simgear/misc/PathOptions.hxx>
#include <simgear/screen/colors.hxx>
-
-#include "sphere.hxx"
+#include <simgear/scene/model/model.hxx>
#include "oursun.hxx"
-// Set up sun rendering call backs
-static int sgSunOrbPreDraw( ssgEntity *e ) {
- /* cout << endl << "Sun orb pre draw" << endl << "----------------"
- << endl << endl; */
-
- ssgLeaf *f = (ssgLeaf *)e;
- if ( f -> hasState () ) f->getState()->apply() ;
-
- glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_FOG_BIT );
- // cout << "push error = " << glGetError() << endl;
-
- glDisable( GL_DEPTH_TEST );
- glDisable( GL_FOG );
-
- return true;
-}
-
-static int sgSunOrbPostDraw( ssgEntity *e ) {
- /* cout << endl << "Sun orb post draw" << endl << "----------------"
- << endl << endl; */
-
- glPopAttrib();
- // cout << "pop error = " << glGetError() << endl;
-
- // glEnable( GL_DEPTH_TEST );
- // glEnable( GL_FOG );
-
- return true;
-}
-
-static int sgSunHaloPreDraw( ssgEntity *e ) {
- /* cout << endl << "Sun halo pre draw" << endl << "----------------"
- << endl << endl; */
-
- ssgLeaf *f = (ssgLeaf *)e;
- if ( f -> hasState () ) f->getState()->apply() ;
-
- glPushAttrib( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_FOG_BIT );
- // cout << "push error = " << glGetError() << endl;
-
- glDisable( GL_DEPTH_TEST );
- // glDisable( GL_FOG );
- glFogf (GL_FOG_DENSITY, sun_exp2_punch_through);
- glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ) ;
-
- return true;
-}
-
-static int sgSunHaloPostDraw( ssgEntity *e ) {
- /* cout << endl << "Sun halo post draw" << endl << "----------------"
- << endl << endl; */
-
- glPopAttrib();
- // cout << "pop error = " << glGetError() << endl;
-
- // glEnable( GL_DEPTH_TEST );
- // glEnable( GL_FOG );
-
- return true;
-}
-
+using namespace simgear;
// Constructor
-SGSun::SGSun( void ) {
- prev_sun_angle = -9999.0;
- visibility = -9999.0;
+SGSun::SGSun( void ) :
+ visibility(-9999.0), prev_sun_angle(-9999.0), path_distance(60000.0),
+ sun_exp2_punch_through(7.0e-06)
+{
+
}
}
-#if 0
-// this might be nice to keep, just as an example of how to generate a
-// texture on the fly ...
-static GLuint makeHalo( GLubyte *sun_texbuf, int width ) {
- int texSize;
- GLuint texid;
- GLubyte *p;
- int i,j;
- double radius;
-
- // create a texture id
-#ifdef GL_VERSION_1_1
- glGenTextures(1, &texid);
- glBindTexture(GL_TEXTURE_2D, texid);
-#elif GL_EXT_texture_object
- glGenTexturesEXT(1, &texid);
- glBindTextureEXT(GL_TEXTURE_2D, texid);
-#else
-# error port me
-#endif
-
- glPixelStorei( GL_UNPACK_ALIGNMENT, 4 );
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
- glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
- glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE ) ;
-
- // create the actual texture contents
- texSize = width * width;
-
- if ( !sun_texbuf ) {
- SG_LOG( SG_EVENT, SG_ALERT,
- "Could not allocate memroy for the sun texture");
- exit(-1); // Ugly!
- }
-
- p = sun_texbuf;
-
- radius = (double)(width / 2);
-
- GLubyte value;
- double x, y, d;
- for ( i = 0; i < width; i++ ) {
- for ( j = 0; j < width; j++ ) {
- x = fabs((double)(i - (width / 2)));
- y = fabs((double)(j - (width / 2)));
- d = sqrt((x * x) + (y * y));
- if (d < radius) {
- // t is 1.0 at center, 0.0 at edge
- double t = 1.0 - (d / radius);
-
- // inverse square looks nice
- value = (int)((double) 0xff * (t*t));
- } else {
- value = 0x00;
- }
- *p = value;
- *(p+1) = value;
- *(p+2) = value;
- // *(p+3) = value;
-
- p += 3;
- }
- }
-
- /* glTexImage2D( GL_TEXTURE_2D,
- 0,
- GL_RGBA,
- width, width,
- 0,
- GL_RGBA, GL_UNSIGNED_BYTE,
- sun_texbuf ); */
-
- return texid;
-}
-
-
-#define RGB 3 // 3 bytes of color info per pixel
-#define RGBA 4 // 4 bytes of color+alpha info
-void my_glWritePPMFile(const char *filename, GLubyte *buffer, int win_width, int win_height, int mode)
-{
- int i, j, k, q;
- unsigned char *ibuffer;
- FILE *fp;
- int pixelSize = mode==GL_RGBA?4:3;
-
- ibuffer = (unsigned char *) malloc(win_width*win_height*RGB);
-
- fp = fopen(filename, "wb");
- fprintf(fp, "P6\n# CREATOR: glReadPixel()\n%d %d\n%d\n",
- win_width, win_height, UCHAR_MAX);
- q = 0;
- for (i = 0; i < win_height; i++) {
- for (j = 0; j < win_width; j++) {
- for (k = 0; k < RGB; k++) {
- ibuffer[q++] = (unsigned char)
- *(buffer + (pixelSize*((win_height-1-i)*win_width+j)+k));
- }
- }
- }
+// initialize the sun object and connect it into our scene graph root
+osg::Node*
+SGSun::build( SGPath path, double sun_size, SGPropertyNode *property_tree_Node ) {
- // *(buffer + (pixelSize*((win_height-1-i)*win_width+j)+k));
+ env_node = property_tree_Node;
- fwrite(ibuffer, sizeof(unsigned char), RGB*win_width*win_height, fp);
- fclose(fp);
- free(ibuffer);
+ osg::ref_ptr<osgDB::ReaderWriter::Options> options
+ = makeOptionsFromPath(path);
+ // build the ssg scene graph sub tree for the sky and connected
+ // into the provide scene graph branch
+ sun_transform = new osg::MatrixTransform;
+ osg::StateSet* stateSet = sun_transform->getOrCreateStateSet();
- printf("wrote file (%d x %d pixels, %d bytes)\n",
- win_width, win_height, RGB*win_width*win_height);
-}
-#endif
+ osg::TexEnv* texEnv = new osg::TexEnv;
+ texEnv->setMode(osg::TexEnv::MODULATE);
+ stateSet->setTextureAttribute(0, texEnv, osg::StateAttribute::ON);
+
+ osg::Material* material = new osg::Material;
+ material->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
+ material->setEmission(osg::Material::FRONT_AND_BACK, osg::Vec4(0,0,0,1));
+ material->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(0,0,0,1));
+ stateSet->setAttribute(material);
+
+ osg::ShadeModel* shadeModel = new osg::ShadeModel;
+ shadeModel->setMode(osg::ShadeModel::SMOOTH);
+ stateSet->setAttributeAndModes(shadeModel);
+
+ osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
+ alphaFunc->setFunction(osg::AlphaFunc::ALWAYS);
+ stateSet->setAttributeAndModes(alphaFunc);
+
+ osg::BlendFunc* blendFunc = new osg::BlendFunc;
+ blendFunc->setSource(osg::BlendFunc::SRC_ALPHA);
+ blendFunc->setDestination(osg::BlendFunc::ONE_MINUS_SRC_ALPHA);
+ stateSet->setAttributeAndModes(blendFunc);
+
+ stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
+ stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
+ stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
+ stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
+
+ osg::Geode* geode = new osg::Geode;
+ stateSet = geode->getOrCreateStateSet();
+
+ stateSet->setRenderBinDetails(-6, "RenderBin");
+
+ // set up the sun-state
+ osg::Texture2D* texture = SGLoadTexture2D("sun.png", options.get());
+ stateSet->setTextureAttributeAndModes(0, texture);
+
+ // Build scenegraph
+ sun_cl = new osg::Vec4Array;
+ sun_cl->push_back(osg::Vec4(1, 1, 1, 1));
+
+ scene_cl = new osg::Vec4Array;
+ scene_cl->push_back(osg::Vec4(1, 1, 1, 1));
+
+ osg::Vec3Array* sun_vl = new osg::Vec3Array;
+ sun_vl->push_back(osg::Vec3(-sun_size, 0, -sun_size));
+ sun_vl->push_back(osg::Vec3(sun_size, 0, -sun_size));
+ sun_vl->push_back(osg::Vec3(-sun_size, 0, sun_size));
+ sun_vl->push_back(osg::Vec3(sun_size, 0, sun_size));
+
+ osg::Vec2Array* sun_tl = new osg::Vec2Array;
+ sun_tl->push_back(osg::Vec2(0, 0));
+ sun_tl->push_back(osg::Vec2(1, 0));
+ sun_tl->push_back(osg::Vec2(0, 1));
+ sun_tl->push_back(osg::Vec2(1, 1));
+
+ osg::Geometry* geometry = new osg::Geometry;
+ geometry->setUseDisplayList(false);
+ geometry->setVertexArray(sun_vl);
+ geometry->setColorArray(sun_cl.get());
+ geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
+ geometry->setNormalBinding(osg::Geometry::BIND_OFF);
+ geometry->setTexCoordArray(0, sun_tl);
+ geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 4));
+ geode->addDrawable(geometry);
+
+ sun_transform->addChild( geode );
+
+ // set up the inner-halo state
+ geode = new osg::Geode;
+ stateSet = geode->getOrCreateStateSet();
+ stateSet->setRenderBinDetails(-7, "RenderBin");
+
+ texture = SGLoadTexture2D("inner_halo.png", options.get());
+ stateSet->setTextureAttributeAndModes(0, texture);
+ // Build ssg structure
+ ihalo_cl = new osg::Vec4Array;
+ ihalo_cl->push_back(osg::Vec4(1, 1, 1, 1));
+
+ float ihalo_size = sun_size * 2.0;
+ osg::Vec3Array* ihalo_vl = new osg::Vec3Array;
+ ihalo_vl->push_back(osg::Vec3(-ihalo_size, 0, -ihalo_size));
+ ihalo_vl->push_back(osg::Vec3(ihalo_size, 0, -ihalo_size));
+ ihalo_vl->push_back(osg::Vec3(-ihalo_size, 0, ihalo_size));
+ ihalo_vl->push_back(osg::Vec3(ihalo_size, 0, ihalo_size));
+
+ osg::Vec2Array* ihalo_tl = new osg::Vec2Array;
+ ihalo_tl->push_back(osg::Vec2(0, 0));
+ ihalo_tl->push_back(osg::Vec2(1, 0));
+ ihalo_tl->push_back(osg::Vec2(0, 1));
+ ihalo_tl->push_back(osg::Vec2(1, 1));
+
+ geometry = new osg::Geometry;
+ geometry->setUseDisplayList(false);
+ geometry->setVertexArray(ihalo_vl);
+ geometry->setColorArray(ihalo_cl.get());
+ geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
+ geometry->setNormalBinding(osg::Geometry::BIND_OFF);
+ geometry->setTexCoordArray(0, ihalo_tl);
+ geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 4));
+ geode->addDrawable(geometry);
+
+ sun_transform->addChild( geode );
+
+ // set up the outer halo state
+
+ geode = new osg::Geode;
+ stateSet = geode->getOrCreateStateSet();
+ stateSet->setRenderBinDetails(-8, "RenderBin");
+
+ texture = SGLoadTexture2D("outer_halo.png", options.get());
+ stateSet->setTextureAttributeAndModes(0, texture);
-// initialize the sun object and connect it into our scene graph root
-ssgBranch * SGSun::build( SGPath path, double sun_size ) {
-
- // set up the orb state
- orb_state = new ssgSimpleState();
- orb_state->setShadeModel( GL_SMOOTH );
- orb_state->disable( GL_LIGHTING );
- // orb_state->enable( GL_LIGHTING );
- orb_state->disable( GL_CULL_FACE );
- orb_state->disable( GL_TEXTURE_2D );
- orb_state->enable( GL_COLOR_MATERIAL );
- orb_state->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
- orb_state->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
- orb_state->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
- orb_state->disable( GL_BLEND );
- orb_state->disable( GL_ALPHA_TEST );
-
- cl = new ssgColourArray( 1 );
- sgVec4 color;
- sgSetVec4( color, 1.0, 1.0, 1.0, 1.0 );
- cl->add( color );
-
- ssgBranch *orb = ssgMakeSphere( orb_state, cl, sun_size, 10, 10,
- sgSunOrbPreDraw, sgSunOrbPostDraw );
+ // Build ssg structure
+ ohalo_cl = new osg::Vec4Array;
+ ohalo_cl->push_back(osg::Vec4(1, 1, 1, 1));
+
+ double ohalo_size = sun_size * 8.0;
+ osg::Vec3Array* ohalo_vl = new osg::Vec3Array;
+ ohalo_vl->push_back(osg::Vec3(-ohalo_size, 0, -ohalo_size));
+ ohalo_vl->push_back(osg::Vec3(ohalo_size, 0, -ohalo_size));
+ ohalo_vl->push_back(osg::Vec3(-ohalo_size, 0, ohalo_size));
+ ohalo_vl->push_back(osg::Vec3(ohalo_size, 0, ohalo_size));
+
+ osg::Vec2Array* ohalo_tl = new osg::Vec2Array;
+ ohalo_tl->push_back(osg::Vec2(0, 0));
+ ohalo_tl->push_back(osg::Vec2(1, 0));
+ ohalo_tl->push_back(osg::Vec2(0, 1));
+ ohalo_tl->push_back(osg::Vec2(1, 1));
+
+ geometry = new osg::Geometry;
+ geometry->setUseDisplayList(false);
+ geometry->setVertexArray(ohalo_vl);
+ geometry->setColorArray(ohalo_cl.get());
+ geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
+ geometry->setNormalBinding(osg::Geometry::BIND_OFF);
+ geometry->setTexCoordArray(0, ohalo_tl);
+ geometry->addPrimitiveSet(new osg::DrawArrays(GL_TRIANGLE_STRIP, 0, 4));
+ geode->addDrawable(geometry);
+
+ sun_transform->addChild( geode );
// force a repaint of the sun colors with arbitrary defaults
repaint( 0.0, 1.0 );
- // build the halo
- // sun_texbuf = new GLubyte[64*64*3];
- // sun_texid = makeHalo( sun_texbuf, 64 );
- // my_glWritePPMFile("sunhalo.ppm", sun_texbuf, 64, 64, RGB);
-
- // set up the halo state
- path.append( "halo.rgba" );
- halo_state = new ssgSimpleState();
- halo_state->setTexture( (char *)path.c_str() );
- halo_state->enable( GL_TEXTURE_2D );
- halo_state->disable( GL_LIGHTING );
- // halo_state->enable( GL_LIGHTING );
- halo_state->setShadeModel( GL_SMOOTH );
- halo_state->disable( GL_CULL_FACE );
- halo_state->enable( GL_COLOR_MATERIAL );
- halo_state->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
- halo_state->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
- halo_state->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
- halo_state->enable( GL_ALPHA_TEST );
- halo_state->setAlphaClamp(0.01);
- halo_state->enable ( GL_BLEND ) ;
-
- // Build ssg structure
- double size = sun_size * 10.0;
- sgVec3 v3;
- halo_vl = new ssgVertexArray;
- sgSetVec3( v3, -size, 0.0, -size );
- halo_vl->add( v3 );
- sgSetVec3( v3, size, 0.0, -size );
- halo_vl->add( v3 );
- sgSetVec3( v3, -size, 0.0, size );
- halo_vl->add( v3 );
- sgSetVec3( v3, size, 0.0, size );
- halo_vl->add( v3 );
-
- sgVec2 v2;
- halo_tl = new ssgTexCoordArray;
- sgSetVec2( v2, 0.0f, 0.0f );
- halo_tl->add( v2 );
- sgSetVec2( v2, 1.0, 0.0 );
- halo_tl->add( v2 );
- sgSetVec2( v2, 0.0, 1.0 );
- halo_tl->add( v2 );
- sgSetVec2( v2, 1.0, 1.0 );
- halo_tl->add( v2 );
-
- ssgLeaf *halo =
- new ssgVtxTable ( GL_TRIANGLE_STRIP, halo_vl, NULL, halo_tl, cl );
- halo->setState( halo_state );
-
- // build the ssg scene graph sub tree for the sky and connected
- // into the provide scene graph branch
- sun_transform = new ssgTransform;
-
- halo->setCallback( SSG_CALLBACK_PREDRAW, sgSunHaloPreDraw );
- halo->setCallback( SSG_CALLBACK_POSTDRAW, sgSunHaloPostDraw );
- sun_transform->addKid( halo );
- sun_transform->addKid( orb );
-
-#ifdef FG_TEST_CHEESY_LENS_FLARE
- // cheesy lens flair
- sun_transform->addKid( new ssgaLensFlare );
-#endif
-
- return sun_transform;
+ return sun_transform.get();
}
// 90 degrees = sun rise/set
// 180 degrees = darkest midnight
bool SGSun::repaint( double sun_angle, double new_visibility ) {
+
if ( visibility != new_visibility ) {
visibility = new_visibility;
- static double sqrt_m_log01 = sqrt( -log( 0.01 ) );
- sun_exp2_punch_through = sqrt_m_log01 / (visibility * 15);
+ if (new_visibility < 100.0) new_visibility = 100.0;
+ else if (new_visibility > 45000.0) new_visibility = 45000.0;
+ sun_exp2_punch_through = 2.0/log(visibility);
}
- if (prev_sun_angle != sun_angle) {
+ if ( prev_sun_angle != sun_angle ) {
prev_sun_angle = sun_angle;
- float sun_factor = 4*cos(sun_angle);
-
- if (sun_factor > 1) sun_factor = 1.0;
- if (sun_factor < -1) sun_factor = -1.0;
- sun_factor = sun_factor/2 + 0.5;
-
- sgVec4 color;
- color[1] = sqrt(sun_factor);
- color[0] = sqrt(color[1]);
- color[2] = sun_factor * sun_factor;
- color[2] *= color[2];
- color[3] = 1.0;
-
- gamma_correct_rgb( color );
-
- // cout << "color = " << color[0] << " " << color[1] << " "
- // << color[2] << endl;
-
- float *ptr;
- ptr = cl->get( 0 );
- sgCopyVec4( ptr, color );
+ // determine how much aerosols are in the air (rough guess)
+ double aerosol_factor;
+ if ( visibility < 100 ) {
+ aerosol_factor = 8000;
+ }
+ else {
+ aerosol_factor = 80.5 / log( visibility / 100 );
+ }
+
+ // get environmental data from property tree or use defaults
+ double rel_humidity, density_avg;
+
+ if ( !env_node ) {
+ rel_humidity = 0.5;
+ density_avg = 0.7;
+ }
+ else {
+ rel_humidity = env_node->getFloatValue( "relative-humidity" );
+ density_avg = env_node->getFloatValue( "atmosphere/density-tropo-avg" );
+ }
+
+ // ok, now let's go and generate the sun and scene color
+ osg::Vec4 i_halo_color, o_halo_color, scene_color, sun_color;
+
+ // Some comments:
+ // * When the sunangle changes, light has to travel a longer
+ // distance through the atmosphere. So it's scattered more due
+ // to raleigh scattering, which affects blue more than green
+ // light.
+ // * Red is almost not scattered and effectively only get's
+ // touched when the sun is near the horizon.
+ // * Visability also affects suncolor inasmuch as more particles
+ // are in the air that cause more scattering.
+ // * We base our calculation on the halo's color, which is most
+ // scattered.
+ double red_scat_f, red_scat_corr_f, green_scat_f, blue_scat_f;
+
+ // Red - is almost not scattered
+ // Lambda is 700 nm
+
+ red_scat_f = (aerosol_factor * path_distance * density_avg)/5E+07;
+ red_scat_corr_f = sun_exp2_punch_through / (1 - red_scat_f);
+ sun_color[0] = 1;
+ scene_color[0] = 1 - red_scat_f;
+
+ // Green - 546.1 nm
+ green_scat_f = (aerosol_factor * path_distance * density_avg)/8.8938E+06;
+ sun_color[1] = 1 - green_scat_f * red_scat_corr_f;
+ scene_color[1] = 1 - green_scat_f;
+
+ // Blue - 435.8 nm
+ blue_scat_f = (aerosol_factor * path_distance * density_avg)/3.607E+06;
+ sun_color[2] = 1 - blue_scat_f * red_scat_corr_f;
+ scene_color[2] = 1 - blue_scat_f;
+
+ // Alpha
+ sun_color[3] = 1;
+ scene_color[3] = 1;
+
+ // Now that we have the color calculated
+ // let's consider the saturation which is produced by mie scattering
+ double saturation = 1 - ( rel_humidity / 200 );
+ scene_color[1] += (( 1 - saturation ) * ( 1 - scene_color[1] ));
+ scene_color[2] += (( 1 - saturation ) * ( 1 - scene_color[2] ));
+
+ if (sun_color[0] > 1.0) sun_color[0] = 1.0;
+ if (sun_color[0] < 0.0) sun_color[0] = 0.0;
+ if (sun_color[1] > 1.0) sun_color[1] = 1.0;
+ if (sun_color[1] < 0.0) sun_color[1] = 0.0;
+ if (sun_color[2] > 1.0) sun_color[2] = 1.0;
+ if (sun_color[2] < 0.0) sun_color[2] = 0.0;
+
+ if (scene_color[0] > 1.0) scene_color[0] = 1.0;
+ if (scene_color[0] < 0.0) scene_color[0] = 0.0;
+ if (scene_color[1] > 1.0) scene_color[1] = 1.0;
+ if (scene_color[1] < 0.0) scene_color[1] = 0.0;
+ if (scene_color[2] > 1.0) scene_color[2] = 1.0;
+ if (scene_color[2] < 0.0) scene_color[2] = 0.0;
+
+ double scene_f = 0.5 * (1 / (1 - red_scat_f));
+ double sun_f = 1.0 - scene_f;
+ i_halo_color[0] = sun_f * sun_color[0] + scene_f * scene_color[0];
+ i_halo_color[1] = sun_f * sun_color[1] + scene_f * scene_color[1];
+ i_halo_color[2] = sun_f * sun_color[2] + scene_f * scene_color[2];
+ i_halo_color[3] = 1;
+
+ o_halo_color[0] = 0.2 * sun_color[0] + 0.8 * scene_color[0];
+ o_halo_color[1] = 0.2 * sun_color[1] + 0.8 * scene_color[1];
+ o_halo_color[2] = 0.2 * sun_color[2] + 0.8 * scene_color[2];
+ o_halo_color[3] = blue_scat_f;
+ if ((new_visibility < 10000) && (blue_scat_f > 1)) {
+ o_halo_color[3] = 2 - blue_scat_f;
+ }
+ if (o_halo_color[3] > 1) o_halo_color[3] = 1;
+ if (o_halo_color[3] < 0) o_halo_color[3] = 0;
+
+ gamma_correct_rgb( i_halo_color._v );
+ gamma_correct_rgb( o_halo_color._v );
+ gamma_correct_rgb( scene_color._v );
+ gamma_correct_rgb( sun_color._v );
+
+ (*sun_cl)[0] = sun_color;
+ sun_cl->dirty();
+ (*scene_cl)[0] = scene_color;
+ scene_cl->dirty();
+ (*ihalo_cl)[0] = i_halo_color;
+ ihalo_cl->dirty();
+ (*ohalo_cl)[0] = o_halo_color;
+ ohalo_cl->dirty();
}
return true;
// declination, offset by our current position (p) so that it appears
// fixed at a great distance from the viewer. Also add in an optional
// rotation (i.e. for the current time of day.)
-bool SGSun::reposition( sgVec3 p, double angle,
- double rightAscension, double declination,
- double sun_dist )
+// Then calculate stuff needed for the sun-coloring
+bool SGSun::reposition( double rightAscension, double declination,
+ double sun_dist, double lat, double alt_asl, double sun_angle)
{
- sgMat4 T1, T2, GST, RA, DEC;
- sgVec3 axis;
- sgVec3 v;
-
- sgMakeTransMat4( T1, p );
-
- sgSetVec3( axis, 0.0, 0.0, -1.0 );
- sgMakeRotMat4( GST, angle, axis );
+ // GST - GMT sidereal time
+ osg::Matrix T2, RA, DEC;
// xglRotatef( ((SGD_RADIANS_TO_DEGREES * rightAscension)- 90.0),
// 0.0, 0.0, 1.0);
- sgSetVec3( axis, 0.0, 0.0, 1.0 );
- sgMakeRotMat4( RA, (rightAscension * SGD_RADIANS_TO_DEGREES) - 90.0, axis );
+ RA.makeRotate(rightAscension - 90*SGD_DEGREES_TO_RADIANS, osg::Vec3(0, 0, 1));
// xglRotatef((SGD_RADIANS_TO_DEGREES * declination), 1.0, 0.0, 0.0);
- sgSetVec3( axis, 1.0, 0.0, 0.0 );
- sgMakeRotMat4( DEC, declination * SGD_RADIANS_TO_DEGREES, axis );
+ DEC.makeRotate(declination, osg::Vec3(1, 0, 0));
// xglTranslatef(0,sun_dist);
- sgSetVec3( v, 0.0, sun_dist, 0.0 );
- sgMakeTransMat4( T2, v );
+ T2.makeTranslate(osg::Vec3(0, sun_dist, 0));
+
+ sun_transform->setMatrix(T2*DEC*RA);
- sgMat4 TRANSFORM;
- sgCopyMat4( TRANSFORM, T1 );
- sgPreMultMat4( TRANSFORM, GST );
- sgPreMultMat4( TRANSFORM, RA );
- sgPreMultMat4( TRANSFORM, DEC );
- sgPreMultMat4( TRANSFORM, T2 );
+ // Suncolor related things:
+ if ( prev_sun_angle != sun_angle ) {
+ if ( sun_angle == 0 ) sun_angle = 0.1;
+ const double r_earth_pole = 6356752.314;
+ const double r_tropo_pole = 6356752.314 + 8000;
+ const double epsilon_earth2 = 6.694380066E-3;
+ const double epsilon_tropo2 = 9.170014946E-3;
+
+ double r_tropo = r_tropo_pole / sqrt ( 1 - ( epsilon_tropo2 * pow ( cos( lat ), 2 )));
+ double r_earth = r_earth_pole / sqrt ( 1 - ( epsilon_earth2 * pow ( cos( lat ), 2 )));
+
+ double position_radius = r_earth + alt_asl;
- sgCoord skypos;
- sgSetCoord( &skypos, TRANSFORM );
+ double gamma = SG_PI - sun_angle;
+ double sin_beta = ( position_radius * sin ( gamma ) ) / r_tropo;
+ if (sin_beta > 1.0) sin_beta = 1.0;
+ double alpha = SG_PI - gamma - asin( sin_beta );
- sun_transform->setTransform( &skypos );
+ // OK, now let's calculate the distance the light travels
+ path_distance = sqrt( pow( position_radius, 2 ) + pow( r_tropo, 2 )
+ - ( 2 * position_radius * r_tropo * cos( alpha ) ));
+
+ double alt_half = sqrt( pow ( r_tropo, 2 ) + pow( path_distance / 2, 2 ) - r_tropo * path_distance * cos( asin( sin_beta )) ) - r_earth;
+
+ if ( alt_half < 0.0 ) alt_half = 0.0;
+
+ // Push the data to the property tree, so it can be used in the enviromental code
+ if ( env_node ){
+ env_node->setDoubleValue( "atmosphere/altitude-troposphere-top", r_tropo - r_earth );
+ env_node->setDoubleValue( "atmosphere/altitude-half-to-sun", alt_half );
+ }
+ }
return true;
}
+
+SGVec4f
+SGSun::get_color()
+{
+ return SGVec4f((*sun_cl)[0][0], (*sun_cl)[0][1], (*sun_cl)[0][2], (*sun_cl)[0][3]);
+}
+
+SGVec4f
+SGSun::get_scene_color()
+{
+ return SGVec4f((*scene_cl)[0][0], (*scene_cl)[0][1], (*scene_cl)[0][2], (*scene_cl)[0][3]);
+}