]> git.mxchange.org Git - simgear.git/commitdiff
Use node masks and shared state sets to manage ground lights
authortimoore <timoore>
Thu, 13 Dec 2007 23:30:24 +0000 (23:30 +0000)
committertimoore <timoore>
Thu, 13 Dec 2007 23:30:24 +0000 (23:30 +0000)
Do away with the switch in each terrain tile for the ground lights. They are
turned on by node masks now.

Share state sets among all the light nodes and manage the fog values through a
"GroundLightManager" instead of having separate state sets and callback
functions for each group in each tile.

simgear/scene/tgdb/GroundLightManager.cxx [new file with mode: 0644]
simgear/scene/tgdb/GroundLightManager.hxx [new file with mode: 0644]
simgear/scene/tgdb/Makefile.am
simgear/scene/tgdb/obj.cxx
simgear/scene/util/RenderConstants.hxx

diff --git a/simgear/scene/tgdb/GroundLightManager.cxx b/simgear/scene/tgdb/GroundLightManager.cxx
new file mode 100644 (file)
index 0000000..0930908
--- /dev/null
@@ -0,0 +1,73 @@
+#include <osg/Fog>
+
+#include <simgear/scene/util/RenderConstants.hxx>
+#include "GroundLightManager.hxx"
+
+
+
+using namespace osg;
+
+namespace
+{
+StateSet* makeLightSS()
+{
+    StateSet* ss = new StateSet;
+    Fog* fog = new Fog;
+    fog->setMode(Fog::EXP2);
+    ss->setAttribute(fog);
+    ss->setDataVariance(Object::DYNAMIC);
+    return ss;
+}
+}
+
+namespace simgear
+{
+GroundLightManager::GroundLightManager()
+{
+    osg::Fog* fog;
+    runwayLightSS = makeLightSS();
+    taxiLightSS = makeLightSS();
+    groundLightSS = makeLightSS();
+}
+
+GroundLightManager* GroundLightManager::instance()
+{
+    static ref_ptr<GroundLightManager> manager = new GroundLightManager;
+    return manager.get();
+}
+
+void GroundLightManager::update(const SGUpdateVisitor* updateVisitor)
+{
+    osg::Fog* fog;
+    SGVec4f fogColor = updateVisitor->getFogColor();
+    fog = static_cast<osg::Fog*>(runwayLightSS
+                                 ->getAttribute(StateAttribute::FOG));
+    fog->setColor(fogColor.osg());
+    fog->setDensity(updateVisitor->getRunwayFogExp2Density());
+    fog = static_cast<osg::Fog*>(taxiLightSS
+                                 ->getAttribute(StateAttribute::FOG));
+    fog->setColor(fogColor.osg());
+    fog->setDensity(updateVisitor->getTaxiFogExp2Density());
+    fog = static_cast<osg::Fog*>(groundLightSS
+                                 ->getAttribute(StateAttribute::FOG));
+    fog->setColor(fogColor.osg());
+    fog->setDensity(updateVisitor->getGroundLightsFogExp2Density());
+}
+
+unsigned GroundLightManager::getLightNodeMask(const SGUpdateVisitor* updateVisitor)
+{
+    unsigned mask = 0;
+    // The current sun angle in degree
+    float sun_angle = updateVisitor->getSunAngleDeg();
+    if (sun_angle > 85 || updateVisitor->getVisibility() < 5000)
+        mask |= RUNWAYLIGHTS_BIT;
+    // ground lights
+    if ( sun_angle > 95 )
+        mask |= GROUNDLIGHTS2_BIT;
+    if ( sun_angle > 92 )
+        mask |= GROUNDLIGHTS1_BIT;
+    if ( sun_angle > 89 )
+        mask |= GROUNDLIGHTS0_BIT;
+    return mask;
+}
+}
diff --git a/simgear/scene/tgdb/GroundLightManager.hxx b/simgear/scene/tgdb/GroundLightManager.hxx
new file mode 100644 (file)
index 0000000..f9bfdf7
--- /dev/null
@@ -0,0 +1,45 @@
+// GroundLightManager.hxx - manage StateSets for point lights
+//
+// Copyright (C) 2007  Tim Moore timoore@redhat.com
+// Copyright (C) 2006-2007 Mathias Froehlich 
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful, but
+// WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+// General Public License for more details.
+//
+// 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.
+//
+
+#include <osg/ref_ptr>
+#include <osg/Vec4>
+#include <osg/Referenced>
+#include <osg/StateSet>
+#include <simgear/scene/util/SGUpdateVisitor.hxx>
+
+namespace simgear
+{
+class GroundLightManager : public osg::Referenced {
+public:
+    GroundLightManager();
+    osg::StateSet* getRunwayLightStateSet() { return runwayLightSS.get(); }
+    osg::StateSet* getTaxiLightStateSet() { return taxiLightSS.get(); }
+    osg::StateSet* getGroundLightStateSet() { return groundLightSS.get(); }
+    // The SGUpdateVisitor manages various environmental properties,
+    // so use it.
+    void update (const SGUpdateVisitor* updateVisitor);
+    unsigned getLightNodeMask(const SGUpdateVisitor* updateVisitor);
+    static GroundLightManager* instance();
+protected:
+    osg::ref_ptr<osg::StateSet> runwayLightSS;
+    osg::ref_ptr<osg::StateSet> taxiLightSS;
+    osg::ref_ptr<osg::StateSet> groundLightSS;
+};
+}
index e66569893b5fc0e7401690f7b542761c08fb2bc7..6eba2549a029f0875e07141ce6e4399687f51806 100644 (file)
@@ -17,7 +17,8 @@ include_HEADERS = \
        SGReaderWriterBTGOptions.hxx \
        SGTexturedTriangleBin.hxx \
        SGTriangleBin.hxx \
-       SGVertexArrayBin.hxx
+       SGVertexArrayBin.hxx \
+       GroundLightManager.hxx
 
 libsgtgdb_a_SOURCES = \
        apt_signs.cxx \
@@ -26,6 +27,7 @@ libsgtgdb_a_SOURCES = \
        userdata.cxx \
        SGOceanTile.cxx \
        SGReaderWriterBTG.cxx \
-       SGVasiDrawable.cxx
+       SGVasiDrawable.cxx \
+       GroundLightManager.cxx
 
 INCLUDES = -I$(top_srcdir)
index 89f19fc15a67aef45958943c6972f6d59df886ff..1f6cfd275fa269003415991cb749c46309d222ac 100644 (file)
 #include "SGTexturedTriangleBin.hxx"
 #include "SGLightBin.hxx"
 #include "SGDirectionalLightBin.hxx"
+#include "GroundLightManager.hxx"
+
 
 #include "pt_lights.hxx"
 
+using namespace simgear;
+
 typedef std::map<std::string,SGTexturedTriangleBin> SGMaterialTriangleMap;
 typedef std::list<SGLightBin> SGLightListBin;
 typedef std::list<SGDirectionalLightBin> SGDirectionalLightListBin;
@@ -449,92 +453,6 @@ struct SGTileGeometryBin {
   }
 };
 
-
-class SGTileUpdateCallback : public osg::NodeCallback {
-public:
-  virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
-  {
-    assert(dynamic_cast<osg::Switch*>(node));
-    assert(dynamic_cast<SGUpdateVisitor*>(nv));
-
-    osg::Switch* lightSwitch = static_cast<osg::Switch*>(node);
-    SGUpdateVisitor* updateVisitor = static_cast<SGUpdateVisitor*>(nv);
-
-    // The current sun angle in degree
-    float sun_angle = updateVisitor->getSunAngleDeg();
-
-    // vasi is always on
-    lightSwitch->setValue(0, true);
-    if (sun_angle > 85 || updateVisitor->getVisibility() < 5000) {
-      // runway and taxi
-      lightSwitch->setValue(1, true);
-      lightSwitch->setValue(2, true);
-    } else {
-      // runway and taxi
-      lightSwitch->setValue(1, false);
-      lightSwitch->setValue(2, false);
-    }
-    
-    // ground lights
-    if ( sun_angle > 95 )
-      lightSwitch->setValue(5, true);
-    else
-      lightSwitch->setValue(5, false);
-    if ( sun_angle > 92 )
-      lightSwitch->setValue(4, true);
-    else
-      lightSwitch->setValue(4, false);
-    if ( sun_angle > 89 )
-      lightSwitch->setValue(3, true);
-    else
-      lightSwitch->setValue(3, false);
-
-    traverse(node, nv);
-  }
-};
-
-class SGRunwayLightFogUpdateCallback : public osg::StateAttribute::Callback {
-public:
-  virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
-  {
-    assert(dynamic_cast<SGUpdateVisitor*>(nv));
-    assert(dynamic_cast<osg::Fog*>(sa));
-    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->setDensity(updateVisitor->getRunwayFogExp2Density());
-  }
-};
-
-class SGTaxiLightFogUpdateCallback : public osg::StateAttribute::Callback {
-public:
-  virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
-  {
-    assert(dynamic_cast<SGUpdateVisitor*>(nv));
-    assert(dynamic_cast<osg::Fog*>(sa));
-    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->setDensity(updateVisitor->getTaxiFogExp2Density());
-  }
-};
-
-class SGGroundLightFogUpdateCallback : public osg::StateAttribute::Callback {
-public:
-  virtual void operator () (osg::StateAttribute* sa, osg::NodeVisitor* nv)
-  {
-    assert(dynamic_cast<SGUpdateVisitor*>(nv));
-    assert(dynamic_cast<osg::Fog*>(sa));
-    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->setDensity(updateVisitor->getGroundLightsFogExp2Density());
-  }
-};
-
 osg::Node*
 SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool use_random_objects)
 {
@@ -550,67 +468,9 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
   SGGeod geodPos = SGGeod::fromCart(center);
   SGQuatd hlOr = SGQuatd::fromLonLat(geodPos);
   SGVec3f up = toVec3f(hlOr.backTransform(SGVec3d(0, 0, -1)));
+  GroundLightManager* lightManager = GroundLightManager::instance();
 
-  osg::Group* vasiLights = new osg::Group;
-  vasiLights->setCullCallback(new SGPointSpriteLightCullCallback(osg::Vec3(1, 0.0001, 0.000001), 6));
-  osg::StateSet* stateSet = vasiLights->getOrCreateStateSet();
-  osg::Fog* fog = new osg::Fog;
-  fog->setUpdateCallback(new SGRunwayLightFogUpdateCallback);
-  stateSet->setAttribute(fog);
-
-  osg::Group* rwyLights = new osg::Group;
-  rwyLights->setCullCallback(new SGPointSpriteLightCullCallback);
-  stateSet = rwyLights->getOrCreateStateSet();
-  fog = new osg::Fog;
-  fog->setUpdateCallback(new SGRunwayLightFogUpdateCallback);
-  stateSet->setAttribute(fog);
-
-  osg::Group* taxiLights = new osg::Group;
-  taxiLights->setCullCallback(new SGPointSpriteLightCullCallback);
-  stateSet = taxiLights->getOrCreateStateSet();
-  fog = new osg::Fog;
-  fog->setUpdateCallback(new SGTaxiLightFogUpdateCallback);
-  stateSet->setAttribute(fog);
-
-  osg::Group* groundLights0 = new osg::Group;
-  stateSet = groundLights0->getOrCreateStateSet();
-  fog = new osg::Fog;
-  fog->setUpdateCallback(new SGGroundLightFogUpdateCallback);
-  stateSet->setAttribute(fog);
-
-  osg::Group* groundLights1 = new osg::Group;
-  stateSet = groundLights1->getOrCreateStateSet();
-  fog = new osg::Fog;
-  fog->setUpdateCallback(new SGGroundLightFogUpdateCallback);
-  stateSet->setAttribute(fog);
-
-  osg::Group* groundLights2 = new osg::Group;
-  stateSet = groundLights2->getOrCreateStateSet();
-  fog = new osg::Fog;
-  fog->setUpdateCallback(new SGGroundLightFogUpdateCallback);
-  stateSet->setAttribute(fog);
-
-  osg::Switch* lightSwitch = new osg::Switch;
-  lightSwitch->setUpdateCallback(new SGTileUpdateCallback);
-  lightSwitch->addChild(vasiLights, true);
-  lightSwitch->addChild(rwyLights, true);
-  lightSwitch->addChild(taxiLights, true);
-  lightSwitch->addChild(groundLights0, true);
-  lightSwitch->addChild(groundLights1, true);
-  lightSwitch->addChild(groundLights2, true);
-
-  osg::Group* lightGroup = new SGOffsetTransform(0.94);
-  lightGroup->addChild(lightSwitch);
-
-  osg::LOD* lightLOD = new osg::LOD;
-  lightLOD->addChild(lightGroup, 0, 30000);
-  unsigned nodeMask = ~0u;
-  nodeMask &= ~SG_NODEMASK_CASTSHADOW_BIT;
-  nodeMask &= ~SG_NODEMASK_RECIEVESHADOW_BIT;
-  nodeMask &= ~SG_NODEMASK_PICK_BIT;
-  nodeMask &= ~SG_NODEMASK_TERRAIN_BIT;
-  lightLOD->setNodeMask(nodeMask);
-
+  osg::ref_ptr<osg::Group> lightGroup = new SGOffsetTransform(0.94);
   osg::Group* terrainGroup = new osg::Group;
   osg::Node* node = tileGeometryBin.getSurfaceGeometry(matlib);
   if (node)
@@ -620,21 +480,36 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
     // FIXME: ugly, has a side effect
     tileGeometryBin.computeRandomSurfaceLights(matlib);
 
-    osg::Geode* geode = new osg::Geode;
-    groundLights0->addChild(geode);
-    geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.tileLights));
-    geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights, 4, -0.3f));
-
-    geode = new osg::Geode;
-    groundLights1->addChild(geode);
-    geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights, 2, -0.15f));
-
-    geode = new osg::Geode;
-    groundLights2->addChild(geode);
-    geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights));
+    if (tileGeometryBin.tileLights.getNumLights() > 0
+        || tileGeometryBin.randomTileLights.getNumLights() > 0) {
+      osg::Group* groundLights0 = new osg::Group;
+      groundLights0->setStateSet(lightManager->getGroundLightStateSet());
+      groundLights0->setNodeMask(GROUNDLIGHTS0_BIT);
+      osg::Geode* geode = new osg::Geode;
+      geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.tileLights));
+      geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights, 4, -0.3f));
+      groundLights0->addChild(geode);
+      lightGroup->addChild(groundLights0);
+    }
+    if (tileGeometryBin.randomTileLights.getNumLights() > 0) {
+      osg::Group* groundLights1 = new osg::Group;
+      groundLights1->setStateSet(lightManager->getGroundLightStateSet());
+      groundLights1->setNodeMask(GROUNDLIGHTS1_BIT);
+      osg::Group* groundLights2 = new osg::Group;
+      groundLights2->setStateSet(lightManager->getGroundLightStateSet());
+      groundLights2->setNodeMask(GROUNDLIGHTS2_BIT);
+      osg::Geode* geode = new osg::Geode;
+      geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights, 2, -0.15f));
+      groundLights1->addChild(geode);
+      lightGroup->addChild(groundLights1);
+      geode = new osg::Geode;
+      geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.randomTileLights));
+      groundLights2->addChild(geode);
+      lightGroup->addChild(groundLights2);
+    }
   }
 
-  {
+  if (!tileGeometryBin.vasiLights.empty()) {
     SGVec4f red(1, 0, 0, 1);
     SGMaterial* mat = matlib->find("RWY_RED_LIGHTS");
     if (mat)
@@ -643,18 +518,35 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
     mat = matlib->find("RWY_WHITE_LIGHTS");
     if (mat)
       white = mat->get_light_color();
-    osg::Geode* geode;
-    geode = new osg::Geode;
-    vasiLights->addChild(geode);
+
+    osg::Geode* geode = new osg::Geode;
     SGDirectionalLightListBin::const_iterator i;
     for (i = tileGeometryBin.vasiLights.begin();
          i != tileGeometryBin.vasiLights.end(); ++i) {
       geode->addDrawable(SGLightFactory::getVasi(up, *i, red, white));
     }
-    
-    geode = new osg::Geode;
-    rwyLights->addChild(geode);
-    geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.runwayLights));
+    osg::Group* vasiLights = new osg::Group;
+    vasiLights->setCullCallback(new SGPointSpriteLightCullCallback(osg::Vec3(1, 0.0001, 0.000001), 6));
+    vasiLights->setStateSet(lightManager->getRunwayLightStateSet());
+    vasiLights->addChild(geode);
+    lightGroup->addChild(vasiLights);
+  }
+
+  if (tileGeometryBin.runwayLights.getNumLights() > 0
+      || !tileGeometryBin.rabitLights.empty()
+      || !tileGeometryBin.reilLights.empty()
+      || !tileGeometryBin.odalLights.empty()) {
+    osg::Group* rwyLights = new osg::Group;
+    rwyLights->setCullCallback(new SGPointSpriteLightCullCallback);
+    rwyLights->setStateSet(lightManager->getRunwayLightStateSet());
+    rwyLights->setNodeMask(RUNWAYLIGHTS_BIT);
+    if (tileGeometryBin.runwayLights.getNumLights() != 0) {
+      osg::Geode* geode = new osg::Geode;
+      geode->addDrawable(SGLightFactory::getLights(tileGeometryBin
+                                                   .runwayLights));
+      rwyLights->addChild(geode);
+    }
+    SGDirectionalLightListBin::const_iterator i;
     for (i = tileGeometryBin.rabitLights.begin();
          i != tileGeometryBin.rabitLights.end(); ++i) {
       rwyLights->addChild(SGLightFactory::getSequenced(*i));
@@ -663,16 +555,23 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
          i != tileGeometryBin.reilLights.end(); ++i) {
       rwyLights->addChild(SGLightFactory::getSequenced(*i));
     }
-
     SGLightListBin::const_iterator j;
     for (j = tileGeometryBin.odalLights.begin();
          j != tileGeometryBin.odalLights.end(); ++j) {
       rwyLights->addChild(SGLightFactory::getOdal(*j));
     }
+    lightGroup->addChild(rwyLights);
+  }
 
-    geode = new osg::Geode;
-    taxiLights->addChild(geode);
+  if (tileGeometryBin.taxiLights.getNumLights() > 0) {
+    osg::Group* taxiLights = new osg::Group;
+    taxiLights->setCullCallback(new SGPointSpriteLightCullCallback);
+    taxiLights->setStateSet(lightManager->getTaxiLightStateSet());
+    taxiLights->setNodeMask(RUNWAYLIGHTS_BIT);
+    osg::Geode* geode = new osg::Geode;
     geode->addDrawable(SGLightFactory::getLights(tileGeometryBin.taxiLights));
+    taxiLights->addChild(geode);
+    lightGroup->addChild(taxiLights);
   }
 
   // The toplevel transform for that tile.
@@ -680,7 +579,16 @@ SGLoadBTG(const std::string& path, SGMaterialLib *matlib, bool calc_lights, bool
   transform->setName(path);
   transform->setMatrix(osg::Matrix::translate(center.osg()));
   transform->addChild(terrainGroup);
-  transform->addChild(lightLOD);
-
+  if (lightGroup->getNumChildren() > 0) {
+    osg::LOD* lightLOD = new osg::LOD;
+    lightLOD->addChild(lightGroup.get(), 0, 30000);
+    unsigned nodeMask = ~0u;
+    nodeMask &= ~SG_NODEMASK_CASTSHADOW_BIT;
+    nodeMask &= ~SG_NODEMASK_RECIEVESHADOW_BIT;
+    nodeMask &= ~SG_NODEMASK_PICK_BIT;
+    nodeMask &= ~SG_NODEMASK_TERRAIN_BIT;
+    lightLOD->setNodeMask(nodeMask);
+    transform->addChild(lightLOD);
+  }
   return transform;
 }
index 91ff7721aacebc5383d140a472e5d2dabc0f5da3..2cbd1d5bd39efa1fc41ec2c1c1fe25f698750282 100644 (file)
@@ -31,8 +31,14 @@ enum NodeMask {
     RECEIVESHADOW_BIT = (1 << 3),
     GUI_BIT = (1 << 4),
     PANEL2D_BIT = (1 << 5),
-    PICK_BIT = (1 << 6)
+    PICK_BIT = (1 << 6),
     // Different classes of lights turned on by node masks
+    GROUNDLIGHTS0_BIT = (1 << 7),
+    GROUNDLIGHTS1_BIT = (1 << 8),
+    GROUNDLIGHTS2_BIT = (1 << 9),
+    RUNWAYLIGHTS_BIT = (1 << 10),
+    LIGHTS_BITS = (GROUNDLIGHTS0_BIT | GROUNDLIGHTS1_BIT | GROUNDLIGHTS2_BIT
+                   | RUNWAYLIGHTS_BIT)
 };
 }
 #endif