]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/sky/oursun.cxx
Merge branch 'ehofman/sound'
[simgear.git] / simgear / scene / sky / oursun.cxx
index 2024cbe116198548574e07b5479a6e2cad18d623..db7e73198cb69c8cf47c7ed0d738fed41cdfe8f4 100644 (file)
 // 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/math/SGMath.hxx>
+#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 ) {
+SGSun::SGSun( void ) :
+    visibility(-9999.0), prev_sun_angle(-9999.0), path_distance(60000.0),
+    sun_exp2_punch_through(7.0e-06)
+{
+
 }
 
 
@@ -122,211 +63,166 @@ SGSun::~SGSun( void ) {
 }
 
 
-#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();
 }
 
 
@@ -336,40 +232,126 @@ ssgBranch * SGSun::build( SGPath path, double sun_size ) {
 // 90 degrees = sun rise/set
 // 180 degrees = darkest midnight
 bool SGSun::repaint( double sun_angle, double new_visibility ) {
-    static float prev_sun_angle = 9999.0;
 
     if ( visibility != new_visibility ) {
-        static double sqrt_m_log01 = sqrt( -log( 0.01 ) );
+        if (new_visibility < 100.0) new_visibility = 100.0;
+        else if (new_visibility > 45000.0) new_visibility = 45000.0;
         visibility = new_visibility;
-        sun_exp2_punch_through = sqrt_m_log01 / (visibility * 15);
+        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 / 99.9 );
+        }
+
+        // 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 ((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;
@@ -380,43 +362,69 @@ bool SGSun::repaint( double sun_angle, double new_visibility ) {
 // 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);
+
+    // 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;
 
-    sgMat4 TRANSFORM;
-    sgCopyMat4( TRANSFORM, T1 );
-    sgPreMultMat4( TRANSFORM, GST );
-    sgPreMultMat4( TRANSFORM, RA );
-    sgPreMultMat4( TRANSFORM, DEC );
-    sgPreMultMat4( TRANSFORM, T2 );
+         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;
+
+         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 );
+
+         // 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 ) ));
 
-    sgCoord skypos;
-    sgSetCoord( &skypos, TRANSFORM );
+         double alt_half = sqrt( pow ( r_tropo, 2 ) + pow( path_distance / 2, 2 ) - r_tropo * path_distance * cos( asin( sin_beta )) ) - r_earth;
 
-    sun_transform->setTransform( &skypos );
+         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]);
+}