]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/sky/dome.cxx
Added some OSG headers for the correct evaluation of the OSG_VERSION_LESS_THAN macro.
[simgear.git] / simgear / scene / sky / dome.cxx
index cea4b6cffde9f1c55993758b03c7bb335bb2dd88..3cdc9923d4d9d3d4f545e1a4c157eb07d28e04e7 100644 (file)
@@ -24,6 +24,7 @@
 #endif
 
 #include <math.h>
+#include <iterator>
 
 #include <simgear/compiler.h>
 
 #include <osg/Material>
 #include <osg/ShadeModel>
 #include <osg/PrimitiveSet>
+#include <osg/CullFace>
+#include <osgDB/Registry>
 
 #include <simgear/debug/logstream.hxx>
-#include <simgear/math/Math.hxx>
+#include <simgear/scene/util/OsgMath.hxx>
+#include <simgear/scene/util/SGReaderWriterOptions.hxx>
 #include <simgear/scene/util/VectorArrayAdapter.hxx>
+#include <simgear/scene/material/Effect.hxx>
+#include <simgear/scene/material/EffectGeode.hxx>
 
 #include "dome.hxx"
 
 using namespace osg;
 using namespace simgear;
 
-// proportions of max dimensions fed to the build() routine
-static const float center_elev = 1.0;
-
 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;
-}
-
-static const float upper_radius = 0.9701; // (.6, 0.15)
-static const float upper_elev = 0.2425;
+  // proportions of max dimensions fed to the build() routine
+  const float center_elev = 1.0;
 
-static const float middle_radius = 0.9960; // (.9, .08)
-static const float middle_elev = 0.0885;
+  const int numRings = 64; //sizeof(domeParams) / sizeof(domeParams[0]);
+  const int numBands = 64; // 12
+  const int halfBands = numBands / 2;
 
-static const float lower_radius = 1.0;
-static const float lower_elev = 0.0;
+  // Make dome a bit over half sphere
+  const float domeAngle = 120.0;
 
-static const float bottom_radius = 0.9922; // (.8, -.1)
-static const float bottom_elev = -0.1240;
+  const float bandDelta = 360.0 / numBands;
+  const float ringDelta = domeAngle / (numRings+1);
 
+  // Which band is at horizon
+  const int halfRings = numRings * (90.0 / domeAngle);
+  const int upperRings = numRings * (60.0 / domeAngle); // top half
+  const int middleRings = numRings * (15.0 / domeAngle);
+}
 
 // Constructor
 SGSkyDome::SGSkyDome( void ) {
@@ -116,32 +110,29 @@ 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);  
+    for (int i = 0; i < bands; i++) {
+        *pusher = 0;  *pusher = grid(0, (i+1)%bands);  *pusher = grid(0, i);
         // 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, i);  *pusher = grid(j, (i + 1)%bands);
+            *pusher = grid(j + 1, (i + 1)%bands);
+            *pusher = grid(j, i);  *pusher =  grid(j + 1, (i + 1)%bands);
             *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);
     }
 }
 
 // initialize the sky object and connect it into our scene graph
 osg::Node*
-SGSkyDome::build( double hscale, double vscale ) {
+SGSkyDome::build( double hscale, double vscale, simgear::SGReaderWriterOptions *options ) {
 
-    osg::Geode* geode = new osg::Geode;
+    EffectGeode* geode = new EffectGeode;
+    geode->setName("Skydome");
+    geode->setCullingActive(false); // Prevent skydome from being culled away
+
+    Effect *effect = makeEffect("Effects/skydome", true, options);
+    if(effect)
+      geode->setEffect(effect);
 
     // set up the state
     osg::StateSet* stateSet = geode->getOrCreateStateSet();
@@ -153,9 +144,12 @@ SGSkyDome::build( double hscale, double vscale ) {
     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_CULL_FACE, osg::StateAttribute::ON);
     stateSet->setMode(GL_BLEND, osg::StateAttribute::OFF);
     stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::OFF);
+
+    stateSet->setAttribute(new osg::CullFace(osg::CullFace::BACK));
+
     osg::Material* material = new osg::Material;
     stateSet->setAttribute(material);
 
@@ -167,13 +161,13 @@ SGSkyDome::build( double hscale, double 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 theta = (i * bandDelta) * 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);
+            vertices(j, i).set(cTheta * sin((j+1)*ringDelta*SGD_DEGREES_TO_RADIANS), //domeParams[j].radius,
+                               sTheta * sin((j+1)*ringDelta*SGD_DEGREES_TO_RADIANS),// domeParams[j].radius,
+                               vscale * cos((j+1)*ringDelta*SGD_DEGREES_TO_RADIANS)); //domeParams[j].elev * vscale);
         }
     }
 
@@ -184,8 +178,7 @@ SGSkyDome::build( double hscale, double vscale ) {
     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->setColorArray(dome_cl.get(), osg::Array::BIND_PER_VERTEX);
     geom->setNormalBinding(osg::Geometry::BIND_OFF);
     geom->addPrimitiveSet(domeElements);
     geode->addDrawable(geom);
@@ -204,7 +197,7 @@ static void fade_to_black(osg::Vec3 sky_color[], float asl, int count) {
         sky_color[i] *= d;
 }
 
-inline void clampColor(osg::Vec3& color)
+static inline void clampColor(osg::Vec3& color)
 {
     color.x() = osg::clampTo(color.x(), 0.0f, 1.0f);
     color.y() = osg::clampTo(color.y(), 0.0f, 1.0f);
@@ -232,15 +225,15 @@ SGSkyDome::repaint( const SGVec3f& sun_color, const SGVec3f& sky_color,
         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;
+       outer_diff = (1.0 / numRings) * outer_param;
+       middle_diff = (1.0 / numRings) * middle_param;
     } else {
         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", 
+    // printf("  outer_red_param = %.2f  outer_red_diff = %.2f\n",
     //        outer_red_param, outer_red_diff);
 
     // calculate transition colors between sky and fog
@@ -258,41 +251,75 @@ SGSkyDome::repaint( const SGVec3f& sun_color, const SGVec3f& sky_color,
     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 top is always sky_color
     (*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;
+//    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.
-    
+    // ring color. Means angles from top to 30 degrees
+
     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);
+        diff *= (0.8 + saif - ((halfBands-i)/(float)(numBands-2)));
+
+        // Color the ~60 deg ring
+        colors(upperRings, i) = toOsg(sky_color - upperVisFactor * diff);
+
+        int j=0;
+        // Color top half by linear interpolation (90...60 degrees)
+        for (; j < upperRings; j++)
+            colors(j, i) = SGMiscf::lerp(toOsg(sky_color), colors(upperRings, i), j / (float)upperRings);
+
+        j++; // Skip the 60 deg ring
+        // From 60 to ~85 degrees
+        for (int l = 0; j < upperRings + middleRings + 1; j++, l++)
+            colors(j, i) = SGMiscf::lerp(colors(upperRings, i),
+                       toOsg(sky_color - middleVisFactor * diff + middle_amt), l / (float)middleRings);
+
+        // 85 to 90 degrees
+        for (int l = 0; j < halfRings; j++, l++)
+            colors(j, i) = SGMiscf::lerp(colors(upperRings + middleRings, i), toOsg(fog_color + outer_amt),
+                        l / (float)(halfRings - upperRings - middleRings));
+
+        // Original colors
+        //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;
     }
 
+    // Other side of dome is mirror of the other
     for (int i = halfBands+1; i < numBands; ++i)
-        for (int j = 0; j < 5; ++j)
+        for (int j = 0; j < numRings-1; ++j)
             colors(j, i) = colors(j, numBands - i);
 
+    // Fade colors to black when going to space
+    // Center of dome is blackest and then fade decreases towards horizon
     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,
+    for (int i = 0; i < numRings - 1; ++i) {
+        float fadeValue = (asl+0.05f) * cos(i*ringDelta*SGD_DEGREES_TO_RADIANS);
+        if(fadeValue < 0.0) fadeValue = 0.0; // Prevent brightening up if dome is over 90 degrees
+        fade_to_black(&colors(i, 0), fadeValue, //domeParams[i].elev,
                       numBands);
+    }
+
+    // All rings below horizon are fog color
+    for ( int i = halfRings; i < numRings; i++)
+        for ( int j = 0; j < numBands; j++ )
+            colors(i, j) = toOsg(fog_color);
 
-    for ( int i = 0; i < numBands; i++ )
-        colors(numRings - 1, i) = toOsg(fog_color);
     dome_cl->dirty();
     return true;
 }
@@ -315,7 +342,7 @@ SGSkyDome::reposition( const SGVec3f& p, double _asl,
     // xglTranslatef( zero_elev.x(), zero_elev.y(), zero_elev.z() );
     T.makeTranslate( toOsg(p) );
 
-    // printf("  Translated to %.2f %.2f %.2f\n", 
+    // printf("  Translated to %.2f %.2f %.2f\n",
     //        zero_elev.x, zero_elev.y, zero_elev.z );
 
     // Rotate to proper orientation