]> git.mxchange.org Git - flightgear.git/blobdiff - src/Scenery/scenery.cxx
Prevention of the creation of multiple OSG scene graph roots.
[flightgear.git] / src / Scenery / scenery.cxx
index 4b787ddb3ff45c39d57d529f44e18e0c6fd04112..4b6d5f726790b055eba8bf5a2aba3e1b87fafedf 100644 (file)
 #include <osg/MatrixTransform>
 #include <osg/PositionAttitudeTransform>
 #include <osg/CameraView>
+#include <osg/LOD>
+
 #include <osgViewer/Viewer>
 
 #include <simgear/constants.h>
+#include <simgear/sg_inlines.h>
 #include <simgear/debug/logstream.hxx>
 #include <simgear/scene/tgdb/userdata.hxx>
 #include <simgear/scene/material/matlib.hxx>
 #include <simgear/scene/util/OsgMath.hxx>
 #include <simgear/scene/util/SGSceneUserData.hxx>
 #include <simgear/scene/model/CheckSceneryVisitor.hxx>
+#include <simgear/scene/sky/sky.hxx>
+
 #include <simgear/bvh/BVHNode.hxx>
 #include <simgear/bvh/BVHLineSegmentVisitor.hxx>
+#include <simgear/structure/commands.hxx>
 
 #include <Viewer/renderer.hxx>
 #include <Main/fg_props.hxx>
+#include <GUI/MouseCursor.hxx>
 
 #include "tilemgr.hxx"
 #include "scenery.hxx"
@@ -58,7 +65,12 @@ using namespace simgear;
 
 class FGGroundPickCallback : public SGPickCallback {
 public:
-  virtual bool buttonPressed(int button, const Info& info)
+  FGGroundPickCallback() : SGPickCallback(PriorityScenery)
+  { }
+    
+  virtual bool buttonPressed( int button,
+                              const osgGA::GUIEventAdapter&,
+                              const Info& info )
   {
     // only on left mouse button
     if (button != 0)
@@ -210,23 +222,90 @@ private:
     bool _haveHit;
 };
 
+class FGScenery::ScenerySwitchListener : public SGPropertyChangeListener
+{
+public:
+  ScenerySwitchListener(FGScenery* scenery) :
+    _scenery(scenery)
+  {
+    SGPropertyNode_ptr maskNode = fgGetNode("/sim/rendering/draw-mask", true);
+    maskNode->getChild("terrain", 0, true)->addChangeListener(this, true);
+    maskNode->getChild("models", 0, true)->addChangeListener(this, true);
+    maskNode->getChild("aircraft", 0, true)->addChangeListener(this, true);
+    maskNode->getChild("clouds", 0, true)->addChangeListener(this, true);
+    
+    // legacy compatability option
+    fgGetNode("/sim/rendering/draw-otw")->addChangeListener(this);
+    
+    // badly named property, this is what is set by --enable/disable-clouds
+    fgGetNode("/environment/clouds/status")->addChangeListener(this);
+  }
+  
+  ~ScenerySwitchListener()
+  {
+    SGPropertyNode_ptr maskNode = fgGetNode("/sim/rendering/draw-mask");
+    for (int i=0; i < maskNode->nChildren(); ++i) {
+      maskNode->getChild(i)->removeChangeListener(this);
+    }
+    
+    fgGetNode("/sim/rendering/draw-otw")->removeChangeListener(this);
+    fgGetNode("/environment/clouds/status")->removeChangeListener(this);
+  }
+  
+  virtual void valueChanged (SGPropertyNode * node)
+  {
+    bool b = node->getBoolValue();
+    std::string name(node->getNameString());
+  
+    if (name == "terrain") {
+      _scenery->scene_graph->setChildValue(_scenery->terrain_branch, b);
+    } else if (name == "models") {
+      _scenery->scene_graph->setChildValue(_scenery->models_branch, b);
+    } else if (name == "aircraft") {
+      _scenery->scene_graph->setChildValue(_scenery->aircraft_branch, b);
+    } else if (name == "clouds") {
+      // clouds live elsewhere in the scene, but we handle them here
+      globals->get_renderer()->getSky()->set_clouds_enabled(b);
+    } else if (name == "draw-otw") {
+      // legacy setting but let's keep it working
+      fgGetNode("/sim/rendering/draw-mask")->setBoolValue("terrain", b);
+      fgGetNode("/sim/rendering/draw-mask")->setBoolValue("models", b);
+    } else if (name == "status") {
+      fgGetNode("/sim/rendering/draw-mask")->setBoolValue("clouds", b);
+    }
+  }
+private:
+  FGScenery* _scenery;
+};
+
+////////////////////////////////////////////////////////////////////////////
+
 // Scenery Management system
-FGScenery::FGScenery()
+FGScenery::FGScenery() :
+    _listener(NULL)
 {
-    SG_LOG( SG_TERRAIN, SG_INFO, "Initializing scenery subsystem" );
     // keep reference to pager singleton, so it cannot be destroyed while FGScenery lives
     _pager = FGScenery::getPagerSingleton();
+
+    // Initialise the state of the scene graph.
+    _inited = false;
 }
 
-FGScenery::~FGScenery() {
+FGScenery::~FGScenery()
+{
+    delete _listener;
 }
 
 
 // Initialize the Scenery Management system
 void FGScenery::init() {
+    // Already set up.
+    if (_inited)
+        return;
+
     // Scene graph root
-    scene_graph = new osg::Group;
-    scene_graph->setName( "Scene" );
+    scene_graph = new osg::Switch;
+    scene_graph->setName( "FGScenery" );
 
     // Terrain branch
     terrain_branch = new osg::Group;
@@ -244,12 +323,52 @@ void FGScenery::init() {
     aircraft_branch->setName( "Aircraft" );
     scene_graph->addChild( aircraft_branch.get() );
 
-    // Initials values needed by the draw-time object loader
-    sgUserDataInit( globals->get_props() );
+// choosing to make the interior branch a child of the main
+// aircraft group, for the moment. This simplifes places which
+// assume all aircraft elements are within this group - principally
+// FGODGuage::set_aircraft_texture.
+    interior_branch = new osg::Group;
+    interior_branch->setName( "Interior" );
+    
+    osg::LOD* interiorLOD = new osg::LOD;
+    interiorLOD->addChild(interior_branch.get(), 0.0, 50.0);
+    aircraft_branch->addChild( interiorLOD );
+    
+    // Set up the particle system as a directly accessible branch of the scene graph.
+    particles_branch = simgear::Particles::getCommonRoot();
+    particles_branch->setName("Particles");
+    scene_graph->addChild(particles_branch.get());
+    simgear::GlobalParticleCallback::setSwitch(fgGetNode("/sim/rendering/particles", true));
+  
+    // Set up the precipitation system.
+    precipitation_branch = new osg::Group;
+    precipitation_branch->setName("Precipitation");
+    scene_graph->addChild(precipitation_branch.get());
+
+    _listener = new ScenerySwitchListener(this);
+
+    // Toggle the setup flag.
+    _inited = true;
+}
+
+void FGScenery::shutdown()
+{
+    scene_graph = NULL;
+    terrain_branch = NULL;
+    models_branch = NULL;
+    aircraft_branch = NULL;
+    particles_branch = NULL;
+
+    // Toggle the setup flag.
+    _inited = false;
 }
 
 
-void FGScenery::update(double dt) {
+void FGScenery::update(double dt)
+{
+    SG_UNUSED(dt);
+    // nothing here, don't call again
+    suspend();
 }
 
 
@@ -337,16 +456,28 @@ bool FGScenery::scenery_available(const SGGeod& position, double range_m)
     // while the splashscreen is there, so CheckSceneryVisitor force-loads
     // missing objects in the main thread
     get_scene_graph()->accept(csnv);
-    if(!csnv.isLoaded())
+    if(!csnv.isLoaded()) {
+        SG_LOG(SG_TERRAIN, SG_DEBUG, "FGScenery::scenery_available: waiting on CheckSceneryVisitor");
         return false;
+    }
     return true;
+  } else {
+    SG_LOG(SG_TERRAIN, SG_DEBUG, "FGScenery::scenery_available: waiting on tile manager");
   }
   return false;
 }
 
+static osg::ref_ptr<SceneryPager> pager;
+
 SceneryPager* FGScenery::getPagerSingleton()
 {
-    static osg::ref_ptr<SceneryPager> pager = new SceneryPager;
+    if (!pager)
+        pager = new SceneryPager;
     return pager.get();
 }
 
+void FGScenery::resetPagerSingleton()
+{
+    pager = NULL;
+}
+