]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/sky/dome.cxx
Merge branch 'ehofman/sound'
[simgear.git] / simgear / scene / sky / dome.cxx
index e6535091d5aa73e23a71ad154477eda3b5b508a7..cea4b6cffde9f1c55993758b03c7bb335bb2dd88 100644 (file)
@@ -3,7 +3,7 @@
 // Written by Curtis Olson, started December 1997.
 // SSG-ified by Curtis Olson, February 2000.
 //
-// Copyright (C) 1997-2000  Curtis L. Olson  - curt@flightgear.org
+// Copyright (C) 1997-2000  Curtis L. Olson  - http://www.flightgear.org/~curt
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Library General Public
 // 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.
-//
-// $Id$
-
+// 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.
 
 #ifdef HAVE_CONFIG_H
 #  include <simgear_config.h>
 #endif
 
-#ifdef HAVE_WINDOWS_H
-#  include <windows.h>
-#endif
-
 #include <math.h>
 
-#include GLUT_H
+#include <simgear/compiler.h>
 
-#include <plib/sg.h>
+#include <osg/Array>
+#include <osg/Geode>
+#include <osg/Geometry>
+#include <osg/Node>
+#include <osg/Math>
+#include <osg/MatrixTransform>
+#include <osg/Material>
+#include <osg/ShadeModel>
+#include <osg/PrimitiveSet>
 
 #include <simgear/debug/logstream.hxx>
-#include <simgear/sky/sunsky/sunsky.hxx>
+#include <simgear/math/Math.hxx>
+#include <simgear/scene/util/VectorArrayAdapter.hxx>
 
 #include "dome.hxx"
 
+using namespace osg;
+using namespace simgear;
 
-#ifdef __MWERKS__
-#  pragma global_optimizer off
-#endif
-
-
-// in meters of course
-static const float center_elev = 0.3125;
-
-static const float upper_radius = 0.6250;
-static const float upper_elev = 0.2500;
-
-static const float middle_radius = 0.8750;
-static const float middle_elev = 0.1000;
-
-static const float lower_radius = 0.8750;
-static const float lower_elev = 0.0000;
-
-static const float bottom_radius = 0.6250;
-static const float bottom_elev = -0.0250;
-
-
-// Set up dome rendering callbacks
-static int sgSkyDomePreDraw( ssgEntity *e ) {
-    /* cout << endl << "Dome Pre Draw" << endl << "----------------" 
-         << endl << endl; */
-
-    ssgLeaf *f = (ssgLeaf *)e;
-    if ( f -> hasState () ) f->getState()->apply() ;
+// proportions of max dimensions fed to the build() routine
+static const float center_elev = 1.0;
 
-    glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_FOG_BIT );
-    // cout << "push error = " << glGetError() << endl;
+namespace
+{
+struct DomeParam
+{
+    float radius;
+    float elev;
+} domeParams[] = {{.5, .8660},  // 60deg from horizon
+                  {.8660, .5},  // 30deg from horizon
+                  // Original dome horizon vertices
+                  {0.9701, 0.2425}, {0.9960, 0.0885},
+                  {1.0, 0.0}, {0.9922, -0.1240}};
+
+const int numRings = sizeof(domeParams) / sizeof(domeParams[0]);
+const int numBands = 12;
+const int halfBands = numBands/2;
+}
 
-    glDisable( GL_DEPTH_TEST );
-    glDisable( GL_FOG );
+static const float upper_radius = 0.9701; // (.6, 0.15)
+static const float upper_elev = 0.2425;
 
-    return true;
-}
+static const float middle_radius = 0.9960; // (.9, .08)
+static const float middle_elev = 0.0885;
 
-static int sgSkyDomePostDraw( ssgEntity *e ) {
-    /* cout << endl << "Dome Post Draw" << endl << "----------------" 
-         << endl << endl; */
+static const float lower_radius = 1.0;
+static const float lower_elev = 0.0;
 
-    glPopAttrib();
-    // cout << "pop error = " << glGetError() << endl;
-    
-    return true;
-}
+static const float bottom_radius = 0.9922; // (.8, -.1)
+static const float bottom_elev = -0.1240;
 
 
 // Constructor
 SGSkyDome::SGSkyDome( void ) {
+    asl = 0;
 }
 
 
@@ -101,478 +89,211 @@ SGSkyDome::SGSkyDome( void ) {
 SGSkyDome::~SGSkyDome( void ) {
 }
 
+// Generate indices for a dome mesh. Assume a center vertex at 0, then
+// rings of vertices. Each ring's vertices are stored together. An
+// even number of longitudinal bands are assumed.
 
-// initialize the sky object and connect it into our scene graph
-ssgBranch * SGSkyDome::build( double hscale, double vscale ) {
-//  sgVec4 color;
-
-    float theta;
-    int i;
-
-    // set up the state
-    dome_state = new ssgSimpleState();
-    dome_state->setShadeModel( GL_SMOOTH );
-    dome_state->disable( GL_LIGHTING );
-    dome_state->disable( GL_CULL_FACE );
-    dome_state->enable( GL_TEXTURE_2D );
-    dome_state->disable( GL_COLOR_MATERIAL );
-    dome_state->setColourMaterial( GL_AMBIENT_AND_DIFFUSE );
-    dome_state->setMaterial( GL_EMISSION, 0, 0, 0, 1 );
-    dome_state->setMaterial( GL_SPECULAR, 0, 0, 0, 1 );
-    dome_state->disable( GL_BLEND );
-    dome_state->disable( GL_ALPHA_TEST );
-
-    // initialize arrays
-    center_disk_vl = new ssgVertexArray( 14 );
-    center_disk_cl = new ssgColourArray( 14 );
-                                      
-    upper_ring_vl = new ssgVertexArray( 26 );
-    upper_ring_cl = new ssgColourArray( 26 );
-
-    middle_ring_vl = new ssgVertexArray( 26 );
-    middle_ring_cl = new ssgColourArray( 26 );
-
-    lower_ring_vl = new ssgVertexArray( 26 );
-    lower_ring_cl = new ssgColourArray( 26 );
-
-    // initially seed to all blue
-//  sgSetVec4( color, 0.0, 0.0, 1.0, 1.0 );
-
-    // generate the raw vertex data
-    sgVec3 center_vertex;
-    sgVec3 upper_vertex[12];
-    sgVec3 middle_vertex[12];
-    sgVec3 lower_vertex[12];
-    sgVec3 bottom_vertex[12];
-
-    sgSetVec3( center_vertex, 0.0, 0.0, center_elev * vscale );
-
-    for ( i = 0; i < 12; i++ ) {
-        theta = (i * 30.0) * SGD_DEGREES_TO_RADIANS;
-
-        sgSetVec3( upper_vertex[i],
-                  cos(theta) * upper_radius * hscale,
-                  sin(theta) * upper_radius * hscale,
-                  upper_elev * vscale );
-        
-        sgSetVec3( middle_vertex[i],
-                  cos((double)theta) * middle_radius * hscale,
-                  sin((double)theta) * middle_radius * hscale,
-                  middle_elev * vscale );
-
-        sgSetVec3( lower_vertex[i],
-                  cos((double)theta) * lower_radius * hscale,
-                  sin((double)theta) * lower_radius * hscale,
-                  lower_elev * vscale );
-
-        sgSetVec3( bottom_vertex[i],
-                  cos((double)theta) * bottom_radius * hscale,
-                  sin((double)theta) * bottom_radius * hscale,
-                  bottom_elev * vscale );
+namespace
+{
+// Calculate the index of a vertex in the grid by using its address in
+// the array that holds its location.
+struct GridIndex
+{
+    VectorArrayAdapter<Vec3Array> gridAdapter;
+    Vec3Array& grid;
+    GridIndex(Vec3Array& array, int rowStride, int baseOffset) :
+        gridAdapter(array, rowStride, baseOffset), grid(array)
+    {
     }
-
-    // generate the center disk vertex/color arrays
-    center_disk_vl->add( center_vertex );
-//  center_disk_cl->add( color );
-    for ( i = 11; i >= 0; i-- ) {
-        center_disk_vl->add( upper_vertex[i] );
-//      center_disk_cl->add( color );
+    unsigned short operator() (int ring, int band)
+    {
+        return (unsigned short)(&gridAdapter(ring, band) - &grid[0]);
     }
-    center_disk_vl->add( upper_vertex[11] );
-//  center_disk_cl->add( color );
-
-    // generate the upper ring
-    for ( i = 0; i < 12; i++ ) {
-        upper_ring_vl->add( middle_vertex[i] );
-//      upper_ring_cl->add( color );
-
-        upper_ring_vl->add( upper_vertex[i] );
-//      upper_ring_cl->add( color );
+};
+}
+void SGSkyDome::makeDome(int rings, int bands, DrawElementsUShort& elements)
+{
+    std::back_insert_iterator<DrawElementsUShort> pusher
+        = std::back_inserter(elements);
+    GridIndex grid(*dome_vl, numBands, 1);
+    for (int i = 0; i < bands; i += 2) {
+        *pusher = 0;  *pusher = grid(0, i);  *pusher = grid(0, i + 1);  
+        // down a band
+        for (int j = 0; j < rings - 1; ++j) {
+            *pusher = grid(j, i);  *pusher = grid(j, i + 1);
+            *pusher = grid(j + 1, i + 1);
+            *pusher = grid(j, i);  *pusher =  grid(j + 1, i + 1);
+            *pusher =  grid(j + 1, i);
+        }
+        // and up the next one
+        for (int j = rings - 1; j > 0; --j) {
+            *pusher = grid(j, i + 1);  *pusher = grid(j - 1, i + 1);
+            *pusher = grid(j, (i + 2) % bands);
+            *pusher = grid(j, (i + 2) % bands); *pusher = grid(j - 1, i + 1);
+            *pusher = grid(j - 1, (i + 2) % bands);
+        }
+        *pusher = grid(0, i + 1);  *pusher = 0;
+        *pusher = grid(0, (i + 2) % bands);
     }
-    upper_ring_vl->add( middle_vertex[0] );
-//  upper_ring_cl->add( color );
-
-    upper_ring_vl->add( upper_vertex[0] );
-//  upper_ring_cl->add( color );
-
-    // generate middle ring
-    for ( i = 0; i < 12; i++ ) {
-        middle_ring_vl->add( lower_vertex[i] );
-//      middle_ring_cl->add( color );
+}
 
-        middle_ring_vl->add( middle_vertex[i] );
-//      middle_ring_cl->add( color );
-    }
-    middle_ring_vl->add( lower_vertex[0] );
-//  middle_ring_cl->add( color );
+// initialize the sky object and connect it into our scene graph
+osg::Node*
+SGSkyDome::build( double hscale, double vscale ) {
 
-    middle_ring_vl->add( middle_vertex[0] );
-//  middle_ring_cl->add( color );
+    osg::Geode* geode = new osg::Geode;
 
-    // generate lower ring
-    for ( i = 0; i < 12; i++ ) {
-        lower_ring_vl->add( bottom_vertex[i] );
-//      lower_ring_cl->add( color );
+    // set up the state
+    osg::StateSet* stateSet = geode->getOrCreateStateSet();
+    stateSet->setRenderBinDetails(-10, "RenderBin");
+
+    osg::ShadeModel* shadeModel = new osg::ShadeModel;
+    shadeModel->setMode(osg::ShadeModel::SMOOTH);
+    stateSet->setAttributeAndModes(shadeModel);
+    stateSet->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
+    stateSet->setMode(GL_FOG, osg::StateAttribute::OFF);
+    stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
+    stateSet->setMode(GL_CULL_FACE, osg::StateAttribute::OFF);
+    stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
+    stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
+    osg::Material* material = new osg::Material;
+    stateSet->setAttribute(material);
+
+    dome_vl = new osg::Vec3Array(1 + numRings * numBands);
+    dome_cl = new osg::Vec3Array(1 + numRings * numBands);
+    // generate the raw vertex data
 
-        lower_ring_vl->add( lower_vertex[i] );
-//      lower_ring_cl->add( color );
+    (*dome_vl)[0].set(0.0, 0.0, center_elev * vscale);
+    simgear::VectorArrayAdapter<Vec3Array> vertices(*dome_vl, numBands, 1);
+
+    for ( int i = 0; i < numBands; ++i ) {
+        double theta = (i * 30) * SGD_DEGREES_TO_RADIANS;
+        double sTheta = hscale*sin(theta);
+        double cTheta = hscale*cos(theta);
+        for (int j = 0; j < numRings; ++j) {
+            vertices(j, i).set(cTheta * domeParams[j].radius,
+                               sTheta * domeParams[j].radius,
+                               domeParams[j].elev * vscale);
+        }
     }
-    lower_ring_vl->add( bottom_vertex[0] );
-//  lower_ring_cl->add( color );
-
-    lower_ring_vl->add( lower_vertex[0] );
-//  lower_ring_cl->add( color );
 
+    DrawElementsUShort* domeElements
+        = new osg::DrawElementsUShort(GL_TRIANGLES);
+    makeDome(numRings, numBands, *domeElements);
+    osg::Geometry* geom = new Geometry;
+    geom->setName("Dome Elements");
+    geom->setUseDisplayList(false);
+    geom->setVertexArray(dome_vl.get());
+    geom->setColorArray(dome_cl.get());
+    geom->setColorBinding(osg::Geometry::BIND_PER_VERTEX);
+    geom->setNormalBinding(osg::Geometry::BIND_OFF);
+    geom->addPrimitiveSet(domeElements);
+    geode->addDrawable(geom);
     // force a repaint of the sky colors with ugly defaults
-//  sgVec4 fog_color;
-//  sgSetVec4( fog_color, 1.0, 1.0, 1.0, 1.0 );
-//  repaint( color, fog_color, 0.0, 5000.0 );
-
-    // build the ssg scene graph sub tree for the sky and connected
-    // into the provide scene graph branch
-    ssgVtxTable *center_disk, *upper_ring, *middle_ring, *lower_ring;
-
-    center_disk = new ssgVtxTable( GL_TRIANGLE_FAN, 
-                                  center_disk_vl, NULL, NULL, center_disk_cl );
-
-    upper_ring = new ssgVtxTable( GL_TRIANGLE_STRIP, 
-                                 upper_ring_vl, NULL, NULL, upper_ring_cl );
-
-    middle_ring = new ssgVtxTable( GL_TRIANGLE_STRIP, 
-                                  middle_ring_vl, NULL, NULL, middle_ring_cl );
-
-    lower_ring = new ssgVtxTable( GL_TRIANGLE_STRIP, 
-                                 lower_ring_vl, NULL, NULL, lower_ring_cl );
-
-    center_disk->setState( dome_state );
-    upper_ring->setState( dome_state );
-    middle_ring->setState( dome_state );
-    lower_ring->setState( dome_state );
-
-    dome_transform = new ssgTransform;
-    dome_transform->addKid( center_disk );
-    dome_transform->addKid( upper_ring );
-    dome_transform->addKid( middle_ring );
-    dome_transform->addKid( lower_ring );
+    repaint(SGVec3f(1, 1, 1), SGVec3f(1, 1, 1), SGVec3f(1, 1, 1), 0.0, 5000.0 );
+    dome_transform = new osg::MatrixTransform;
+    dome_transform->addChild(geode);
 
-    // not entirely satisfying.  We are depending here that the first
-    // thing we add to a parent is the first drawn
-    center_disk->setCallback( SSG_CALLBACK_PREDRAW, sgSkyDomePreDraw );
-    center_disk->setCallback( SSG_CALLBACK_POSTDRAW, sgSkyDomePostDraw );
-
-    upper_ring->setCallback( SSG_CALLBACK_PREDRAW, sgSkyDomePreDraw );
-    upper_ring->setCallback( SSG_CALLBACK_POSTDRAW, sgSkyDomePostDraw );
-
-    middle_ring->setCallback( SSG_CALLBACK_PREDRAW, sgSkyDomePreDraw );
-    middle_ring->setCallback( SSG_CALLBACK_POSTDRAW, sgSkyDomePostDraw );
-
-    lower_ring->setCallback( SSG_CALLBACK_PREDRAW, sgSkyDomePreDraw );
-    lower_ring->setCallback( SSG_CALLBACK_POSTDRAW, sgSkyDomePostDraw );
-
-    return dome_transform;
+    return dome_transform.get();
 }
 
+static void fade_to_black(osg::Vec3 sky_color[], float asl, int count) {
+    const float ref_asl = 10000.0f;
+    const float d = exp( - asl / ref_asl );
+    for(int i = 0; i < count ; i++)
+        sky_color[i] *= d;
+}
 
-/**
- * regenerate the sky texture based on the current position and time
- *
- * lat: the current latitude (0 ... 360)
- * lon: the current longitude (-90 ... 90) south to north
- * zone: standard meredian
- * julianDay: julian day (1 ... 365)
- * time: time of day (0.0 ... 23.99 - 14.25 = 2:15pm)
- * turbidity: (1.0 ... 30+) 2-6 are most useful for clear days.
- * atmEffects: if atm effects are not initialized, bad things will
- *              happen if you try to use them....
- */
-#define SG_SKYTEXTURE_WIDTH    128
-#define SG_SKYTEXTURE_HEIGHT   128
-
-// produce theta-distorted map suitable for texture mapping
-static const bool thetaMap = false;
-
-bool SGSkyDome::repaint( float lat, float lon, int zone, int julianDay,
-                         int time, float turbidity, bool atmEffects )
+inline void clampColor(osg::Vec3& color)
 {
-    SGSunSky sunSky(lat, lon, zone, julianDay, time, turbidity, atmEffects);
-
-    float  sunAngle = sqrt(sunSky.GetSunSolidAngle() / SG_PI);
-    sgVec3 *sunColour = sunSky.GetSunSpectralRadiance().To_XYZ();
-    sgVec3 *sunDir = sunSky.GetSunPosition();
-
-    for (unsigned int i = 0; i < 128; i++ ) {
-        for (unsigned int j = 0; j < 128; j++ ) {
-
-           sgVec2 hemiPos, normVec2;
-           sgVec3 hemiDir;
-           sgVec3 *hemiColour;
-
-           sgSetVec2( normVec2, 1.0, 1.0 );
-           sgSetVec2( hemiPos, (j + 0.5)/SG_SKYTEXTURE_WIDTH,
-                               (i + 0.5)/SG_SKYTEXTURE_WIDTH );
-
-           sgScaleVec2(hemiPos, 2.0);
-           sgAddVec2(hemiPos, normVec2);
-
-           if (sgDistanceSquaredVec2(hemiPos, normVec2) <= 1.0)
-           {
-               // North = Up, East = left, so hemisphere is 'above' viewer:
-               // imagine lying on your back looking up at the sky,
-               // head oriented towards north
-
-               if (thetaMap)
-               {
-                   // remap to theta-based coords
-                   float  r = sgLengthVec2(hemiPos);
-                   sgScaleVec2(hemiPos, cos(SG_PI * (1 - r) / 2.0) / r);
-               }
-
-               sgSetVec3( hemiDir, -hemiPos[1], -hemiPos[0],
-                          sqrt(1.0-sgDistanceSquaredVec2(hemiPos, normVec2)) );
-
-               if (acos(sgScalarProductVec2(hemiDir, *sunDir)) < sunAngle)
-               {
-                   // this is actually a little beside the point: as
-                   // the sun subtends about 0.5 degrees, at an image
-                   // size of 400x400 pixels, the sun will only cover a
-                   // pixel or so.
-                   hemiColour = sunColour;
-               }
-               else
-               {
-                   hemiColour = sunSky.GetSkyXYZRadiance(&hemiDir);
-                   // hemiColour = csDisplay.ToGamut(hemiColour);
-               }
-
-               radImage.SetPixel(j, i, hemiColour);
-           }
-           else
-               radImage.SetPixel(j, i, cBlack);
-       }
-   }
+    color.x() = osg::clampTo(color.x(), 0.0f, 1.0f);
+    color.y() = osg::clampTo(color.y(), 0.0f, 1.0f);
+    color.z() = osg::clampTo(color.z(), 0.0f, 1.0f);
 }
 
-
 // repaint the sky colors based on current value of sun_angle, sky,
 // and fog colors.  This updates the color arrays for ssgVtxTable.
 // sun angle in degrees relative to verticle
 // 0 degrees = high noon
 // 90 degrees = sun rise/set
 // 180 degrees = darkest midnight
-bool SGSkyDome::repaint( sgVec4 sky_color, sgVec4 fog_color, double sun_angle,
-                         double vis )
+bool
+SGSkyDome::repaint( const SGVec3f& sun_color, const SGVec3f& sky_color,
+                    const SGVec3f& fog_color, double sun_angle, double vis )
 {
-#if 0
-    double diff;
-    sgVec3 outer_param, outer_amt, outer_diff;
-    sgVec3 middle_param, middle_amt, middle_diff;
-    int i, j;
+    SGVec3f outer_param, outer_diff;
+    SGVec3f middle_param, middle_diff;
 
     // Check for sunrise/sunset condition
-    if ( (sun_angle > 80.0) && (sun_angle < 100.0) ) {
-        // 0.0 - 0.4
-        sgSetVec3( outer_param,
-                  (10.0 - fabs(90.0 - sun_angle)) / 20.0,
-                  (10.0 - fabs(90.0 - sun_angle)) / 40.0,
-                  -(10.0 - fabs(90.0 - sun_angle)) / 30.0 );
-
-        sgSetVec3( middle_param,
-                  (10.0 - fabs(90.0 - sun_angle)) / 40.0,
-                  (10.0 - fabs(90.0 - sun_angle)) / 80.0,
-                  0.0 );
-
-        sgScaleVec3( outer_diff, outer_param, 1.0 / 6.0 );
-
-        sgScaleVec3( middle_diff, middle_param, 1.0 / 6.0 );
+    if (sun_angle > 80) {
+       // 0.0 - 0.4
+        double sunAngleFactor = 10.0 - fabs(90.0 - sun_angle);
+        static const SGVec3f outerConstant(1.0 / 20.0, 1.0 / 40.0, -1.0 / 30.0);
+        static const SGVec3f middleConstant(1.0 / 40.0, 1.0 / 80.0, 0.0);
+        outer_param = sunAngleFactor * outerConstant;
+        middle_param = sunAngleFactor * middleConstant;
+       outer_diff = (1.0 / 6.0) * outer_param;
+       middle_diff = (1.0 / 6.0) * middle_param;
     } else {
-        sgSetVec3( outer_param, 0.0, 0.0, 0.0 );
-        sgSetVec3( middle_param, 0.0, 0.0, 0.0 );
-
-        sgSetVec3( outer_diff, 0.0, 0.0, 0.0 );
-        sgSetVec3( middle_diff, 0.0, 0.0, 0.0 );
+        outer_param = SGVec3f(0, 0, 0);
+       middle_param = SGVec3f(0, 0, 0);
+       outer_diff = SGVec3f(0, 0, 0);
+       middle_diff = SGVec3f(0, 0, 0);
     }
     // printf("  outer_red_param = %.2f  outer_red_diff = %.2f\n", 
     //        outer_red_param, outer_red_diff);
 
     // calculate transition colors between sky and fog
-    sgCopyVec3( outer_amt, outer_param );
-    sgCopyVec3( middle_amt, middle_param );
+    SGVec3f outer_amt = outer_param;
+    SGVec3f middle_amt = middle_param;
 
     //
     // First, recalulate the basic colors
     //
 
-    sgVec4 center_color;
-    sgVec4 upper_color[12];
-    sgVec4 middle_color[12];
-    sgVec4 lower_color[12];
-    sgVec4 bottom_color[12];
-
-    double vis_factor;
-
-    if ( vis < 3000.0 ) {
-        vis_factor = (vis - 1000.0) / 2000.0;
-        if ( vis_factor < 0.0 ) {
-            vis_factor = 0.0;
-        }
-    } else {
-        vis_factor = 1.0;
-    }
-
-    for ( j = 0; j < 3; j++ ) {
-        diff = sky_color[j] - fog_color[j];
-        center_color[j] = sky_color[j] - diff * ( 1.0 - vis_factor );
-    }
-    center_color[3] = 1.0;
-
-    for ( i = 0; i < 6; i++ ) {
-        for ( j = 0; j < 3; j++ ) {
-            diff = sky_color[j] - fog_color[j];
-
-            // printf("sky = %.2f  fog = %.2f  diff = %.2f\n", 
-            //        l->sky_color[j], l->fog_color[j], diff);
-
-            upper_color[i][j] = sky_color[j] - diff * ( 1.0 - vis_factor * 0.7);
-            middle_color[i][j] = sky_color[j] - diff * ( 1.0 - vis_factor * 0.1)
-               + middle_amt[j];
-            lower_color[i][j] = fog_color[j] + outer_amt[j];
-
-            if ( upper_color[i][j] > 1.0 ) { upper_color[i][j] = 1.0; }
-            if ( upper_color[i][j] < 0.0 ) { upper_color[i][j] = 0.0; }
-            if ( middle_color[i][j] > 1.0 ) { middle_color[i][j] = 1.0; }
-            if ( middle_color[i][j] < 0.0 ) { middle_color[i][j] = 0.0; }
-            if ( lower_color[i][j] > 1.0 ) { lower_color[i][j] = 1.0; }
-            if ( lower_color[i][j] < 0.0 ) { lower_color[i][j] = 0.0; }
-        }
-        upper_color[i][3] = middle_color[i][3] = lower_color[i][3] = 1.0;
-
-        for ( j = 0; j < 3; j++ ) {
-            outer_amt[j] -= outer_diff[j];
-            middle_amt[j] -= middle_diff[j];
-        }
-
-        /*
-        printf("upper_color[%d] = %.2f %.2f %.2f %.2f\n", i, upper_color[i][0],
-               upper_color[i][1], upper_color[i][2], upper_color[i][3]);
-        printf("middle_color[%d] = %.2f %.2f %.2f %.2f\n", i, 
-               middle_color[i][0], middle_color[i][1], middle_color[i][2], 
-               middle_color[i][3]);
-        printf("lower_color[%d] = %.2f %.2f %.2f %.2f\n", i, 
-               lower_color[i][0], lower_color[i][1], lower_color[i][2], 
-               lower_color[i][3]);
-        */
-    }
-
-    sgSetVec3( outer_amt, 0.0, 0.0, 0.0 );
-    sgSetVec3( middle_amt, 0.0, 0.0, 0.0 );
-
-    for ( i = 6; i < 12; i++ ) {
-        for ( j = 0; j < 3; j++ ) {
-            diff = sky_color[j] - fog_color[j];
-
-            // printf("sky = %.2f  fog = %.2f  diff = %.2f\n", 
-            //        sky_color[j], fog_color[j], diff);
-
-            upper_color[i][j] = sky_color[j] - diff * ( 1.0 - vis_factor * 0.7);
-            middle_color[i][j] = sky_color[j] - diff * ( 1.0 - vis_factor * 0.1)
-               + middle_amt[j];
-            lower_color[i][j] = fog_color[j] + outer_amt[j];
-
-            if ( upper_color[i][j] > 1.0 ) { upper_color[i][j] = 1.0; }
-            if ( upper_color[i][j] < 0.0 ) { upper_color[i][j] = 0.0; }
-            if ( middle_color[i][j] > 1.0 ) { middle_color[i][j] = 1.0; }
-            if ( middle_color[i][j] < 0.0 ) { middle_color[i][j] = 0.0; }
-            if ( lower_color[i][j] > 1.0 ) { lower_color[i][j] = 1.0; }
-            if ( lower_color[i][j] < 0.0 ) { lower_color[i][j] = 0.0; }
-        }
-        upper_color[i][3] = middle_color[i][3] = lower_color[i][3] = 1.0;
-
-        for ( j = 0; j < 3; j++ ) {
-            outer_amt[j] += outer_diff[j];
-            middle_amt[j] += middle_diff[j];
-        }
-
-        /*
-        printf("upper_color[%d] = %.2f %.2f %.2f %.2f\n", i, upper_color[i][0],
-               upper_color[i][1], upper_color[i][2], upper_color[i][3]);
-        printf("middle_color[%d] = %.2f %.2f %.2f %.2f\n", i, 
-               middle_color[i][0], middle_color[i][1], middle_color[i][2], 
-               middle_color[i][3]);
-        printf("lower_color[%d] = %.2f %.2f %.2f %.2f\n", i, 
-               lower_color[i][0], lower_color[i][1], lower_color[i][2], 
-               lower_color[i][3]);
-       */
-   }
-
-    for ( i = 0; i < 12; i++ ) {
-        sgCopyVec4( bottom_color[i], fog_color );
-    }
-
-    //
-    // Second, assign the basic colors to the object color arrays
-    //
-
-    float *slot;
-    int counter;
-
-    // update the center disk color arrays
-    counter = 0;
-    slot = center_disk_cl->get( counter++ );
-    // sgVec4 red;
-    // sgSetVec4( red, 1.0, 0.0, 0.0, 1.0 );
-    sgCopyVec4( slot, center_color );
-    for ( i = 11; i >= 0; i-- ) {
-        slot = center_disk_cl->get( counter++ );
-        sgCopyVec4( slot, upper_color[i] );
-    }
-    slot = center_disk_cl->get( counter++ );
-    sgCopyVec4( slot, upper_color[11] );
-
-    // generate the upper ring
-    counter = 0;
-    for ( i = 0; i < 12; i++ ) {
-        slot = upper_ring_cl->get( counter++ );
-        sgCopyVec4( slot, middle_color[i] );
-
-        slot = upper_ring_cl->get( counter++ );
-        sgCopyVec4( slot, upper_color[i] );
-    }
-    slot = upper_ring_cl->get( counter++ );
-    sgCopyVec4( slot, middle_color[0] );
-
-    slot = upper_ring_cl->get( counter++ );
-    sgCopyVec4( slot, upper_color[0] );
-
-    // generate middle ring
-    counter = 0;
-    for ( i = 0; i < 12; i++ ) {
-        slot = middle_ring_cl->get( counter++ );
-        sgCopyVec4( slot, lower_color[i] );
-
-        slot = middle_ring_cl->get( counter++ );
-        sgCopyVec4( slot, middle_color[i] );
+    // Magic factors for coloring the sky according visibility and
+    // zenith angle.
+    const double cvf = osg::clampBelow(vis, 45000.0);
+    const double vis_factor = osg::clampTo((vis - 1000.0) / 2000.0, 0.0, 1.0);
+    const float upperVisFactor = 1.0 - vis_factor * (0.7 + 0.3 * cvf/45000);
+    const float middleVisFactor = 1.0 - vis_factor * (0.1 + 0.85 * cvf/45000);
+
+    (*dome_cl)[0] = toOsg(sky_color);
+    simgear::VectorArrayAdapter<Vec3Array> colors(*dome_cl, numBands, 1);
+    const double saif = sun_angle/SG_PI;
+    static const SGVec3f blueShift(0.8, 1.0, 1.2);
+    const SGVec3f skyFogDelta = sky_color - fog_color;
+    const SGVec3f sunSkyDelta = sun_color - sky_color;
+    // For now the colors of the upper two rings are linearly
+    // interpolated between the zenith color and the first horizon
+    // ring color.
+    
+    for (int i = 0; i < halfBands+1; i++) {
+        SGVec3f diff = mult(skyFogDelta, blueShift);
+        diff *= (0.8 + saif - ((halfBands-i)/10));
+        colors(2, i) = toOsg(sky_color - upperVisFactor * diff);
+        colors(3, i) = toOsg(sky_color - middleVisFactor * diff + middle_amt);
+        colors(4, i) = toOsg(fog_color + outer_amt);
+        colors(0, i) = simgear::math::lerp(toOsg(sky_color), colors(2, i), .3942);
+        colors(1, i) = simgear::math::lerp(toOsg(sky_color), colors(2, i), .7885);
+        for (int j = 0; j < numRings - 1; ++j)
+            clampColor(colors(j, i));
+        outer_amt -= outer_diff;
+        middle_amt -= middle_diff;
     }
-    slot = middle_ring_cl->get( counter++ );
-    sgCopyVec4( slot, lower_color[0] );
-
-    slot = middle_ring_cl->get( counter++ );
-    sgCopyVec4( slot, middle_color[0] );
 
-    // generate lower ring
-    counter = 0;
-    for ( i = 0; i < 12; i++ ) {
-        slot = lower_ring_cl->get( counter++ );
-        sgCopyVec4( slot, bottom_color[i] );
+    for (int i = halfBands+1; i < numBands; ++i)
+        for (int j = 0; j < 5; ++j)
+            colors(j, i) = colors(j, numBands - i);
 
-        slot = lower_ring_cl->get( counter++ );
-        sgCopyVec4( slot, lower_color[i] );
-    }
-    slot = lower_ring_cl->get( counter++ );
-    sgCopyVec4( slot, bottom_color[0] );
+    fade_to_black(&(*dome_cl)[0], asl * center_elev, 1);
+    for (int i = 0; i < numRings - 1; ++i)
+        fade_to_black(&colors(i, 0), (asl+0.05f) * domeParams[i].elev,
+                      numBands);
 
-    slot = lower_ring_cl->get( counter++ );
-    sgCopyVec4( slot, lower_color[0] );
-#endif
+    for ( int i = 0; i < numBands; i++ )
+        colors(numRings - 1, i) = toOsg(fog_color);
+    dome_cl->dirty();
     return true;
 }
 
@@ -582,15 +303,17 @@ bool SGSkyDome::repaint( sgVec4 sky_color, sgVec4 fog_color, double sun_angle,
 // lat specifies a rotation about the new Y axis
 // spin specifies a rotation about the new Z axis (and orients the
 // sunrise/set effects
-bool SGSkyDome::reposition( sgVec3 p, double lon, double lat, double spin ) {
-#if 0
-    sgMat4 T, LON, LAT, SPIN;
-    sgVec3 axis;
+bool
+SGSkyDome::reposition( const SGVec3f& p, double _asl,
+                       double lon, double lat, double spin ) {
+    asl = _asl;
+
+    osg::Matrix T, LON, LAT, SPIN;
 
     // Translate to view position
     // Point3D zero_elev = current_view.get_cur_zero_elev();
     // xglTranslatef( zero_elev.x(), zero_elev.y(), zero_elev.z() );
-    sgMakeTransMat4( T, p );
+    T.makeTranslate( toOsg(p) );
 
     // printf("  Translated to %.2f %.2f %.2f\n", 
     //        zero_elev.x, zero_elev.y, zero_elev.z );
@@ -600,29 +323,15 @@ bool SGSkyDome::reposition( sgVec3 p, double lon, double lat, double spin ) {
     //        lon * SGD_RADIANS_TO_DEGREES,
     //        lat * SGD_RADIANS_TO_DEGREES);
     // xglRotatef( lon * SGD_RADIANS_TO_DEGREES, 0.0, 0.0, 1.0 );
-    sgSetVec3( axis, 0.0, 0.0, 1.0 );
-    sgMakeRotMat4( LON, lon * SGD_RADIANS_TO_DEGREES, axis );
+    LON.makeRotate(lon, osg::Vec3(0, 0, 1));
 
     // xglRotatef( 90.0 - f->get_Latitude() * SGD_RADIANS_TO_DEGREES,
     //             0.0, 1.0, 0.0 );
-    sgSetVec3( axis, 0.0, 1.0, 0.0 );
-    sgMakeRotMat4( LAT, 90.0 - lat * SGD_RADIANS_TO_DEGREES, axis );
+    LAT.makeRotate(90.0 * SGD_DEGREES_TO_RADIANS - lat, osg::Vec3(0, 1, 0));
 
     // xglRotatef( l->sun_rotation * SGD_RADIANS_TO_DEGREES, 0.0, 0.0, 1.0 );
-    sgSetVec3( axis, 0.0, 0.0, 1.0 );
-    sgMakeRotMat4( SPIN, spin * SGD_RADIANS_TO_DEGREES, axis );
-
-    sgMat4 TRANSFORM;
+    SPIN.makeRotate(spin, osg::Vec3(0, 0, 1));
 
-    sgCopyMat4( TRANSFORM, T );
-    sgPreMultMat4( TRANSFORM, LON );
-    sgPreMultMat4( TRANSFORM, LAT );
-    sgPreMultMat4( TRANSFORM, SPIN );
-
-    sgCoord skypos;
-    sgSetCoord( &skypos, TRANSFORM );
-
-    dome_transform->setTransform( &skypos );
-#endif
+    dome_transform->setMatrix( SPIN*LAT*LON*T );
     return true;
 }