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