]> git.mxchange.org Git - flightgear.git/blobdiff - src/Main/renderer.cxx
Merge branch 'curt/replay' into next
[flightgear.git] / src / Main / renderer.cxx
index 3893f971fc01c5ad886c39afcc4c4b571bfbceb1..32d7953380b417271fbedd5aead6ba626d1ae3df 100644 (file)
@@ -47,6 +47,7 @@
 #include <osg/Notify>
 #include <osg/PolygonMode>
 #include <osg/PolygonOffset>
+#include <osg/Program>
 #include <osg/Version>
 #include <osg/TexEnv>
 
 #include <simgear/scene/sky/sky.hxx>
 #include <simgear/scene/util/SGUpdateVisitor.hxx>
 #include <simgear/scene/util/RenderConstants.hxx>
+#include <simgear/scene/util/SGSceneUserData.hxx>
 #include <simgear/scene/tgdb/GroundLightManager.hxx>
 #include <simgear/scene/tgdb/pt_lights.hxx>
+#include <simgear/structure/OSGUtils.hxx>
 #include <simgear/props/props.hxx>
 #include <simgear/timing/sg_time.hxx>
 #include <simgear/ephemeris/ephemeris.hxx>
 #include "main.hxx"
 #include "CameraGroup.hxx"
 #include "FGEventHandler.hxx"
-
-// XXX Make this go away when OSG 2.2 is released.
-#if (FG_OSG_VERSION >= 21004)
-#define UPDATE_VISITOR_IN_VIEWER 1
-#endif
+#include <Main/viewer.hxx>
 
 using namespace osg;
 using namespace simgear;
@@ -140,6 +139,7 @@ public:
   {
     // Dynamic stuff, do not store geometry
     setUseDisplayList(false);
+    setDataVariance(Object::DYNAMIC);
 
     osg::StateSet* stateSet = getOrCreateStateSet();
     stateSet->setRenderBinDetails(1001, "RenderBin");
@@ -185,6 +185,7 @@ public:
   {
     // Dynamic stuff, do not store geometry
     setUseDisplayList(false);
+    setDataVariance(Object::DYNAMIC);
 
     osg::StateSet* stateSet = getOrCreateStateSet();
     stateSet->setRenderBinDetails(1000, "RenderBin");
@@ -235,6 +236,18 @@ private:
 
 class FGLightSourceUpdateCallback : public osg::NodeCallback {
 public:
+  
+  /**
+   * @param isSun true if the light is the actual sun i.e., for
+   * illuminating the moon.
+   */
+  FGLightSourceUpdateCallback(bool isSun = false) : _isSun(isSun) {}
+  FGLightSourceUpdateCallback(const FGLightSourceUpdateCallback& nc,
+                              const CopyOp& op)
+    : NodeCallback(nc, op), _isSun(nc._isSun)
+  {}
+  META_Object(flightgear,FGLightSourceUpdateCallback);
+  
   virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
   {
     assert(dynamic_cast<osg::LightSource*>(node));
@@ -242,21 +255,22 @@ public:
     osg::Light* light = lightSource->getLight();
     
     FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
-    light->setAmbient(l->scene_ambient().osg());
-    light->setDiffuse(l->scene_diffuse().osg());
-    light->setSpecular(l->scene_specular().osg());
-    SGVec4f position(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2], 0);
-    light->setPosition(position.osg());
-    SGVec3f direction(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2]);
-    light->setDirection(direction.osg());
-    light->setSpotExponent(0);
-    light->setSpotCutoff(180);
-    light->setConstantAttenuation(1);
-    light->setLinearAttenuation(0);
-    light->setQuadraticAttenuation(0);
+    if (_isSun) {
+      light->setAmbient(Vec4(0.0f, 0.0f, 0.0f, 0.0f));
+      light->setDiffuse(Vec4(1.0f, 1.0f, 1.0f, 1.0f));
+      light->setSpecular(Vec4(0.0f, 0.0f, 0.0f, 0.0f));
+    } else {
+      light->setAmbient(toOsg(l->scene_ambient()));
+      light->setDiffuse(toOsg(l->scene_diffuse()));
+      light->setSpecular(toOsg(l->scene_specular()));
+    }
+    osg::Vec4f position(l->sun_vec()[0], l->sun_vec()[1], l->sun_vec()[2], 0);
+    light->setPosition(position);
 
     traverse(node, nv);
   }
+private:
+  const bool _isSun;
 };
 
 class FGWireFrameModeUpdateCallback : public osg::StateAttribute::Callback {
@@ -296,7 +310,7 @@ public:
 
 #if 0
     FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
-    lightModel->setAmbientIntensity(l->scene_ambient().osg());
+    lightModel->setAmbientIntensity(toOsg(l->scene_ambient());
 #else
     lightModel->setAmbientIntensity(osg::Vec4(0, 0, 0, 1));
 #endif
@@ -339,7 +353,7 @@ public:
     SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
     osg::Fog* fog = static_cast<osg::Fog*>(sa);
     fog->setMode(osg::Fog::EXP2);
-    fog->setColor(updateVisitor->getFogColor().osg());
+    fog->setColor(toOsg(updateVisitor->getFogColor()));
     fog->setDensity(updateVisitor->getFogExp2Density());
   }
 };
@@ -398,12 +412,7 @@ FGRenderer::splashinit( void ) {
     // Scene doesn't seem to pass the frame stamp to the update
     // visitor automatically.
     mUpdateVisitor->setFrameStamp(mFrameStamp.get());
-#ifdef UPDATE_VISITOR_IN_VIEWER
     viewer->setUpdateVisitor(mUpdateVisitor.get());
-#else
-    osgViewer::Scene* scene = viewer->getScene();
-    scene->setUpdateVisitor(mUpdateVisitor.get());
-#endif
 }
 
 void
@@ -474,16 +483,39 @@ FGRenderer::init( void )
     stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
 
     // need to update the light on every frame
-    osg::LightSource* lightSource = new osg::LightSource;
-    lightSource->setUpdateCallback(new FGLightSourceUpdateCallback);
+    // OSG LightSource objects are rather confusing. OSG only supports
+    // the 10 lights specified by OpenGL itself; if more than one
+    // LightSource in the scene graph have the same light number, it's
+    // indeterminate which values will be used to render geometry that
+    // has that light number enabled. Also, adding children to a
+    // LightSource is just a shortcut for setting up a state set that
+    // has the corresponding OpenGL light enabled: a LightSource will
+    // affect geometry anywhere in the scene graph that has its light
+    // number enabled in a state set. 
+    LightSource* lightSource = new LightSource;
+    lightSource->getLight()->setDataVariance(Object::DYNAMIC);
     // relative because of CameraView being just a clever transform node
     lightSource->setReferenceFrame(osg::LightSource::RELATIVE_RF);
     lightSource->setLocalStateSetModes(osg::StateAttribute::ON);
-    
-    lightSource->addChild(sceneGroup);
-    lightSource->addChild(thesky->getPreRoot());
-    mRoot->addChild(lightSource);
-
+    lightSource->setUpdateCallback(new FGLightSourceUpdateCallback);
+    mRealRoot->addChild(lightSource);
+    // we need a white diffuse light for the phase of the moon
+    osg::LightSource* sunLight = new osg::LightSource;
+    sunLight->getLight()->setDataVariance(Object::DYNAMIC);
+    sunLight->getLight()->setLightNum(1);
+    sunLight->setUpdateCallback(new FGLightSourceUpdateCallback(true));
+    sunLight->setReferenceFrame(osg::LightSource::RELATIVE_RF);
+    sunLight->setLocalStateSetModes(osg::StateAttribute::ON);
+    // Hang a StateSet above the sky subgraph in order to turn off
+    // light 0
+    Group* skyGroup = new Group;
+    StateSet* skySS = skyGroup->getOrCreateStateSet();
+    skySS->setMode(GL_LIGHT0, StateAttribute::OFF);
+    skyGroup->addChild(thesky->getPreRoot());
+    sunLight->addChild(skyGroup);
+    mRoot->addChild(sceneGroup);
+    mRoot->addChild(sunLight);
+    // Clouds are added to the scene graph later
     stateSet = globals->get_scenery()->get_scene_graph()->getOrCreateStateSet();
     stateSet->setMode(GL_ALPHA_TEST, osg::StateAttribute::ON);
     stateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON);
@@ -518,8 +550,15 @@ FGRenderer::init( void )
     sw->setUpdateCallback(new FGScenerySwitchCallback);
     sw->addChild(mRoot.get());
     mRealRoot->addChild(sw);
+    // The clouds are attached directly to the scene graph root
+    // because, in theory, they don't want the same default state set
+    // as the rest of the scene. This may not be true in practice.
     mRealRoot->addChild(thesky->getCloudRoot());
     mRealRoot->addChild(FGCreateRedoutNode());
+    // Attach empty program to the scene root so that shader programs
+    // don't leak into state sets (effects) that shouldn't have one.
+    stateSet = mRealRoot->getOrCreateStateSet();
+    stateSet->setAttributeAndModes(new osg::Program, osg::StateAttribute::ON);
 }
 
 
@@ -551,9 +590,6 @@ FGRenderer::update( bool refresh_camera_settings ) {
     SGConfigureDirectionalLights( use_point_sprites, enhanced_lighting,
                                   distance_attenuation );
 
-    static const SGPropertyNode *groundlevel_nearplane
-        = fgGetNode("/sim/current-view/ground-level-nearplane-m");
-
     FGLight *l = static_cast<FGLight*>(globals->get_subsystem("lighting"));
 
     // update fog params
@@ -583,11 +619,11 @@ FGRenderer::update( bool refresh_camera_settings ) {
        
         if ( fgGetBool("/sim/rendering/textures") ) {
             SGVec4f clearColor(l->adj_fog_color());
-            camera->setClearColor(clearColor.osg());
+            camera->setClearColor(toOsg(clearColor));
         }
     } else {
         SGVec4f clearColor(l->sky_color());
-        camera->setClearColor(clearColor.osg());
+        camera->setClearColor(toOsg(clearColor));
     }
 
     // update fog params if visibility has changed
@@ -622,42 +658,16 @@ FGRenderer::update( bool refresh_camera_settings ) {
         }
 
         SGSkyState sstate;
-
-        SGVec3d viewPos = current__view->getViewPosition();
-        sstate.view_pos  = toVec3f(viewPos);
-        SGGeod geodViewPos = SGGeod::fromCart(viewPos);
-        SGGeod geodZeroViewPos = SGGeod::fromGeodM(geodViewPos, 0);
-        sstate.zero_elev = toVec3f(SGVec3d::fromGeod(geodZeroViewPos));
-        SGQuatd hlOr = SGQuatd::fromLonLat(geodViewPos);
-        sstate.view_up   = toVec3f(hlOr.backTransform(-SGVec3d::e3()));
-        sstate.lon       = geodViewPos.getLongitudeRad();
-        sstate.lat       = geodViewPos.getLatitudeRad();
-        sstate.alt       = geodViewPos.getElevationM();
+        sstate.pos       = current__view->getViewPosition();
+        sstate.pos_geod  = current__view->getPosition();
+        sstate.ori       = current__view->getViewOrientation();
         sstate.spin      = l->get_sun_rotation();
         sstate.gst       = globals->get_time_params()->getGst();
         sstate.sun_dist  = 50000.0 * sun_horiz_eff;
         sstate.moon_dist = 40000.0 * moon_horiz_eff;
         sstate.sun_angle = l->get_sun_angle();
 
-
-        /*
-         SG_LOG( SG_GENERAL, SG_BULK, "thesky->repaint() sky_color = "
-         << l->sky_color()[0] << " "
-         << l->sky_color()[1] << " "
-         << l->sky_color()[2] << " "
-         << l->sky_color()[3] );
-        SG_LOG( SG_GENERAL, SG_BULK, "    fog = "
-         << l->fog_color()[0] << " "
-         << l->fog_color()[1] << " "
-         << l->fog_color()[2] << " "
-         << l->fog_color()[3] );
-        SG_LOG( SG_GENERAL, SG_BULK,
-                "    sun_angle = " << l->sun_angle
-         << "    moon_angle = " << l->moon_angle );
-        */
-
         SGSkyColor scolor;
-
         scolor.sky_color   = SGVec3f(l->sky_color().data());
         scolor.adj_sky_color = SGVec3f(l->adj_sky_color().data());
         scolor.fog_color   = SGVec3f(l->adj_fog_color().data());
@@ -771,21 +781,10 @@ FGRenderer::resize( int width, int height ) {
     }
 }
 
-void FGRenderer::setCameraParameters(float vfov, float aspectRatio,
-                                     float zNear, float zFar)
-{
-    zNear = .1;
-    osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
-    viewer->getCamera()->setProjectionMatrixAsPerspective(vfov,
-                                                          1.0f / aspectRatio,
-                                                          zNear, zFar);
-    
-}
 bool
 FGRenderer::pick(std::vector<SGSceneryPick>& pickList,
                  const osgGA::GUIEventAdapter* ea)
 {
-    osgViewer::Viewer* viewer = globals->get_renderer()->getViewer();
     // wipe out the return ...
     pickList.clear();
     typedef osgUtil::LineSegmentIntersector::Intersections Intersections;
@@ -808,8 +807,8 @@ FGRenderer::pick(std::vector<SGSceneryPick>& pickList,
                 if (!pickCallback)
                     continue;
                 SGSceneryPick sceneryPick;
-                sceneryPick.info.local = SGVec3d(hit->getLocalIntersectPoint());
-                sceneryPick.info.wgs84 = SGVec3d(hit->getWorldIntersectPoint());
+                sceneryPick.info.local = toSG(hit->getLocalIntersectPoint());
+                sceneryPick.info.wgs84 = toSG(hit->getWorldIntersectPoint());
                 sceneryPick.callback = pickCallback;
                 pickList.push_back(sceneryPick);
             }