From 68c1cfed46fd65d3a1a8f60311f5394ebc68e574 Mon Sep 17 00:00:00 2001 From: timoore Date: Thu, 13 Dec 2007 23:30:24 +0000 Subject: [PATCH] Use node masks and shared state sets to manage ground lights 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 | 73 +++++++ simgear/scene/tgdb/GroundLightManager.hxx | 45 ++++ simgear/scene/tgdb/Makefile.am | 6 +- simgear/scene/tgdb/obj.cxx | 250 +++++++--------------- simgear/scene/util/RenderConstants.hxx | 8 +- 5 files changed, 208 insertions(+), 174 deletions(-) create mode 100644 simgear/scene/tgdb/GroundLightManager.cxx create mode 100644 simgear/scene/tgdb/GroundLightManager.hxx diff --git a/simgear/scene/tgdb/GroundLightManager.cxx b/simgear/scene/tgdb/GroundLightManager.cxx new file mode 100644 index 00000000..09309087 --- /dev/null +++ b/simgear/scene/tgdb/GroundLightManager.cxx @@ -0,0 +1,73 @@ +#include + +#include +#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 manager = new GroundLightManager; + return manager.get(); +} + +void GroundLightManager::update(const SGUpdateVisitor* updateVisitor) +{ + osg::Fog* fog; + SGVec4f fogColor = updateVisitor->getFogColor(); + fog = static_cast(runwayLightSS + ->getAttribute(StateAttribute::FOG)); + fog->setColor(fogColor.osg()); + fog->setDensity(updateVisitor->getRunwayFogExp2Density()); + fog = static_cast(taxiLightSS + ->getAttribute(StateAttribute::FOG)); + fog->setColor(fogColor.osg()); + fog->setDensity(updateVisitor->getTaxiFogExp2Density()); + fog = static_cast(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 index 00000000..f9bfdf79 --- /dev/null +++ b/simgear/scene/tgdb/GroundLightManager.hxx @@ -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 +#include +#include +#include +#include + +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 runwayLightSS; + osg::ref_ptr taxiLightSS; + osg::ref_ptr groundLightSS; +}; +} diff --git a/simgear/scene/tgdb/Makefile.am b/simgear/scene/tgdb/Makefile.am index e6656989..6eba2549 100644 --- a/simgear/scene/tgdb/Makefile.am +++ b/simgear/scene/tgdb/Makefile.am @@ -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) diff --git a/simgear/scene/tgdb/obj.cxx b/simgear/scene/tgdb/obj.cxx index 89f19fc1..1f6cfd27 100644 --- a/simgear/scene/tgdb/obj.cxx +++ b/simgear/scene/tgdb/obj.cxx @@ -55,9 +55,13 @@ #include "SGTexturedTriangleBin.hxx" #include "SGLightBin.hxx" #include "SGDirectionalLightBin.hxx" +#include "GroundLightManager.hxx" + #include "pt_lights.hxx" +using namespace simgear; + typedef std::map SGMaterialTriangleMap; typedef std::list SGLightListBin; typedef std::list 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(node)); - assert(dynamic_cast(nv)); - - osg::Switch* lightSwitch = static_cast(node); - SGUpdateVisitor* updateVisitor = static_cast(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(nv)); - assert(dynamic_cast(sa)); - SGUpdateVisitor* updateVisitor = static_cast(nv); - osg::Fog* fog = static_cast(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(nv)); - assert(dynamic_cast(sa)); - SGUpdateVisitor* updateVisitor = static_cast(nv); - osg::Fog* fog = static_cast(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(nv)); - assert(dynamic_cast(sa)); - SGUpdateVisitor* updateVisitor = static_cast(nv); - osg::Fog* fog = static_cast(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 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; } diff --git a/simgear/scene/util/RenderConstants.hxx b/simgear/scene/util/RenderConstants.hxx index 91ff7721..2cbd1d5b 100644 --- a/simgear/scene/util/RenderConstants.hxx +++ b/simgear/scene/util/RenderConstants.hxx @@ -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 -- 2.39.5