]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/tgdb/pt_lights.cxx
pt_lights: softly fade in and out the blinking lights
[simgear.git] / simgear / scene / tgdb / pt_lights.cxx
index bfe3c5ae963544aaab92c694afc79d79cdce94e3..7e123a475da55583f31b65ba2dd59e28ae846fa8 100644 (file)
@@ -60,6 +60,7 @@
 #include <simgear/debug/logstream.hxx>
 #include <simgear/scene/util/RenderConstants.hxx>
 #include <simgear/scene/util/SGEnlargeBoundingBox.hxx>
+#include <simgear/scene/util/OsgMath.hxx>
 #include <simgear/scene/util/StateAttributeFactory.hxx>
 
 #include <simgear/scene/material/Effect.hxx>
@@ -158,7 +159,7 @@ gen_standard_light_sprite(void)
 namespace
 {
 typedef boost::tuple<float, osg::Vec3, float, float, bool> PointParams;
-typedef std::map<PointParams, ref_ptr<Effect> > EffectMap;
+typedef std::map<PointParams, observer_ptr<Effect> > EffectMap;
 
 EffectMap effectMap;
 
@@ -174,7 +175,11 @@ Effect* getLightEffect(float size, const Vec3& attenuation,
     ScopedLock<Mutex> lock(lightMutex);
     EffectMap::iterator eitr = effectMap.find(pointParams);
     if (eitr != effectMap.end())
-        return eitr->second.get();
+    {
+        ref_ptr<Effect> effect;
+        if (eitr->second.lock(effect))
+            return effect.release();
+    }
     // Basic stuff; no sprite or attenuation support
     Pass *basicPass = new Pass;
     basicPass->setRenderBinDetails(POINT_LIGHTS_BIN, "DepthSortedBin");
@@ -194,7 +199,7 @@ Effect* getLightEffect(float size, const Vec3& attenuation,
     point->setDistanceAttenuation(attenuation);
     attenuationPass->setAttributeAndModes(point);
     Pass *spritePass = clone(basicPass, CopyOp::SHALLOW_COPY);
-    spritePass->setTextureAttributeAndModes(0, pointSprite,
+    spritePass->setTextureAttributeAndModes(0, pointSprite.get(),
                                             osg::StateAttribute::ON);
     Texture2D* texture = gen_standard_light_sprite();
     spritePass->setTextureAttribute(0, texture);
@@ -203,22 +208,27 @@ Effect* getLightEffect(float size, const Vec3& attenuation,
     spritePass->setTextureAttribute(0, attrFact->getStandardTexEnv());
     Pass *combinedPass = clone(spritePass, CopyOp::SHALLOW_COPY);
     combinedPass->setAttributeAndModes(point);
-    Effect* effect = new Effect;
-    std::vector<std::string> combinedExtensions;
-    combinedExtensions.push_back("GL_ARB_point_sprite");
-    combinedExtensions.push_back("GL_ARB_point_parameters");
-    Technique* combinedTniq = new Technique;
-    combinedTniq->passes.push_back(combinedPass);
-    combinedTniq->setGLExtensionsPred(2.0, combinedExtensions);
-    effect->techniques.push_back(combinedTniq);
-    std::vector<std::string> spriteExtensions;
-    spriteExtensions.push_back(combinedExtensions.front());
-    Technique* spriteTniq = new Technique;
-    spriteTniq->passes.push_back(spritePass);
-    spriteTniq->setGLExtensionsPred(2.0, spriteExtensions);
-    effect->techniques.push_back(spriteTniq);
+    ref_ptr<Effect> effect = new Effect;
     std::vector<std::string> parameterExtensions;
-    parameterExtensions.push_back(combinedExtensions.back());
+
+    if (SGSceneFeatures::instance()->getEnablePointSpriteLights())
+    {
+        std::vector<std::string> combinedExtensions;
+        combinedExtensions.push_back("GL_ARB_point_sprite");
+        combinedExtensions.push_back("GL_ARB_point_parameters");
+        Technique* combinedTniq = new Technique;
+        combinedTniq->passes.push_back(combinedPass);
+        combinedTniq->setGLExtensionsPred(2.0, combinedExtensions);
+        effect->techniques.push_back(combinedTniq);
+        std::vector<std::string> spriteExtensions;
+        spriteExtensions.push_back(combinedExtensions.front());
+        Technique* spriteTniq = new Technique;
+        spriteTniq->passes.push_back(spritePass);
+        spriteTniq->setGLExtensionsPred(2.0, spriteExtensions);
+        effect->techniques.push_back(spriteTniq);
+        parameterExtensions.push_back(combinedExtensions.back());
+    }
+
     Technique* parameterTniq = new Technique;
     parameterTniq->passes.push_back(attenuationPass);
     parameterTniq->setGLExtensionsPred(1.4, parameterExtensions);
@@ -226,8 +236,11 @@ Effect* getLightEffect(float size, const Vec3& attenuation,
     Technique* basicTniq = new Technique(true);
     basicTniq->passes.push_back(basicPass);
     effect->techniques.push_back(basicTniq);
-    effectMap.insert(std::make_pair(pointParams, effect));
-    return effect;
+    if (eitr == effectMap.end())
+        effectMap.insert(std::make_pair(pointParams, effect));
+    else
+        eitr->second = effect; // update existing, but empty observer
+    return effect.release();
 }
 
 
@@ -402,8 +415,21 @@ buildVasi(const SGDirectionalLightBin& lights, const SGVec3f& up,
     drawable->addLight(lights.getLight(3).position,
                        lights.getLight(3).normal, up, 2.5);
     return drawable;
-  }
-  else if (count == 12) {
+
+  } else if (count == 6) {
+    SGVasiDrawable* drawable = new SGVasiDrawable(red, white);
+
+    // probably vasi, first 3 are downwind bar (2.5 deg)
+    for (unsigned i = 0; i < 3; ++i)
+      drawable->addLight(lights.getLight(i).position,
+                         lights.getLight(i).normal, up, 2.5);
+    // last 3 are upwind bar (3.0 deg)
+    for (unsigned i = 3; i < 6; ++i)
+      drawable->addLight(lights.getLight(i).position,
+                         lights.getLight(i).normal, up, 3.0);
+    return drawable;
+
+  } else if (count == 12) {
     SGVasiDrawable* drawable = new SGVasiDrawable(red, white);
     
     // probably vasi, first 6 are downwind bar (2.5 deg)
@@ -414,8 +440,8 @@ buildVasi(const SGDirectionalLightBin& lights, const SGVec3f& up,
     for (unsigned i = 6; i < 12; ++i)
       drawable->addLight(lights.getLight(i).position,
                          lights.getLight(i).normal, up, 3.0);
-    
     return drawable;
+
   } else {
     // fail safe
     SG_LOG(SG_TERRAIN, SG_ALERT,
@@ -514,3 +540,35 @@ SGLightFactory::getOdal(const SGLightBin& lights)
 
   return sequence;
 }
+
+// Blinking hold short line lights
+osg::Node*
+SGLightFactory::getHoldShort(const SGDirectionalLightBin& lights)
+{
+  if (lights.getNumLights() < 2)
+    return 0;
+
+  sg_srandom(unsigned(lights.getLight(0).position[0]));
+  float flashTime = 2 + 0.1 * sg_random();
+  osg::Sequence* sequence = new osg::Sequence;
+
+  // start with lights off
+  sequence->addChild(new osg::Group, flashTime);
+  // ...and increase the lights in steps
+  for (int i = 2; i < 7; i+=2) {
+      Effect* effect = getLightEffect(i, osg::Vec3(1, 0.001, 0.000002),
+                                      0, i, true);
+      EffectGeode* egeode = new EffectGeode;
+      for (unsigned int j = 0; j < lights.getNumLights(); ++j) {
+          egeode->addDrawable(getLightDrawable(lights.getLight(j)));
+          egeode->setEffect(effect);
+      }
+      sequence->addChild(egeode, (i==6) ? flashTime : 0.1);
+  }
+
+  sequence->setInterval(osg::Sequence::SWING, 0, -1);
+  sequence->setDuration(1.0f, -1);
+  sequence->setMode(osg::Sequence::START);
+
+  return sequence;
+}