]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/material/Effect.cxx
Partial fix for crash in SGPropertyNode::fireValueChanged
[simgear.git] / simgear / scene / material / Effect.cxx
index c934815760ced8359c0c3678fde2e9b865544deb..f94be67ac615270af87030291aa0640f98f9a1e7 100644 (file)
@@ -24,6 +24,7 @@
 #include "Technique.hxx"
 #include "Pass.hxx"
 #include "TextureBuilder.hxx"
+#include "parseBlendFunc.hxx"
 
 #include <algorithm>
 #include <functional>
@@ -47,6 +48,7 @@
 #include <osg/Math>
 #include <osg/PolygonMode>
 #include <osg/PolygonOffset>
+#include <osg/Point>
 #include <osg/Program>
 #include <osg/Referenced>
 #include <osg/RenderInfo>
@@ -264,8 +266,8 @@ struct CullFaceBuilder : PassAttributeBuilder
             pass->setMode(GL_CULL_FACE, StateAttribute::OFF);
         else
             SG_LOG(SG_INPUT, SG_ALERT,
-                   "invalid cull face property " << propVal);            
-    }    
+                   "invalid cull face property " << propVal);
+    }
 };
 
 InstallAttributeBuilder<CullFaceBuilder> installCullFace("cull-face");
@@ -283,7 +285,7 @@ struct ColorMaskBuilder : PassAttributeBuilder
         Vec4 m = getColor(realProp);
         mask->setMask(m.r() > 0.0, m.g() > 0.0, m.b() > 0.0, m.a() > 0.0);
         pass->setAttributeAndModes(mask);
-    }    
+    }
 };
 
 InstallAttributeBuilder<ColorMaskBuilder> installColorMask("color-mask");
@@ -308,7 +310,7 @@ struct HintBuilder : public PassAttributeBuilder
         StateSet::RenderingHint renderingHint = StateSet::DEFAULT_BIN;
         findAttr(renderingHints, realProp, renderingHint);
         pass->setRenderingHint(renderingHint);
-    }    
+    }
 };
 
 InstallAttributeBuilder<HintBuilder> installHint("rendering-hint");
@@ -386,9 +388,9 @@ void MaterialBuilder::buildAttribute(Effect* effect, Pass* pass,
     if ((color = getEffectPropertyChild(effect, prop, "emissive")))
         mat->setEmission(Material::FRONT_AND_BACK, getColor(color));
     if ((color = getEffectPropertyChild(effect, prop, "emissive-front")))
-        mat->setEmission(Material::FRONT, getColor(color));        
+        mat->setEmission(Material::FRONT, getColor(color));
     if ((color = getEffectPropertyChild(effect, prop, "emissive-back")))
-        mat->setEmission(Material::BACK, getColor(color));        
+        mat->setEmission(Material::BACK, getColor(color));
     const SGPropertyNode* shininess = 0;
     mat->setShininess(Material::FRONT_AND_BACK, 0.0f);
     if ((shininess = getEffectPropertyChild(effect, prop, "shininess")))
@@ -453,58 +455,16 @@ struct BlendBuilder : public PassAttributeBuilder
             pass->setMode(GL_BLEND, StateAttribute::OFF);
             return;
         }
-        const SGPropertyNode* psource
-            = getEffectPropertyChild(effect, prop, "source");
-        const SGPropertyNode* pdestination
-            = getEffectPropertyChild(effect, prop, "destination");
-        const SGPropertyNode* psourceRGB
-            = getEffectPropertyChild(effect, prop, "source-rgb");
-        const SGPropertyNode* psourceAlpha
-            = getEffectPropertyChild(effect, prop, "source-alpha");
-        const SGPropertyNode* pdestRGB
-            = getEffectPropertyChild(effect, prop, "destination-rgb");
-        const SGPropertyNode* pdestAlpha
-            = getEffectPropertyChild(effect, prop, "destination-alpha");
-        BlendFunc::BlendFuncMode sourceMode = BlendFunc::ONE;
-        BlendFunc::BlendFuncMode destMode = BlendFunc::ZERO;
-        if (psource)
-            findAttr(blendFuncModes, psource, sourceMode);
-        if (pdestination)
-            findAttr(blendFuncModes, pdestination, destMode);
-        if (psource && pdestination
-            && !(psourceRGB || psourceAlpha || pdestRGB || pdestAlpha)
-            && sourceMode == BlendFunc::SRC_ALPHA
-            && destMode == BlendFunc::ONE_MINUS_SRC_ALPHA) {
-            pass->setAttributeAndModes(StateAttributeFactory::instance()
-                                       ->getStandardBlendFunc());
-            return;
-        }
-        BlendFunc* blendFunc = new BlendFunc;
-        if (psource)
-            blendFunc->setSource(sourceMode);
-        if (pdestination)
-            blendFunc->setDestination(destMode);
-        if (psourceRGB) {
-            BlendFunc::BlendFuncMode sourceRGBMode;
-            findAttr(blendFuncModes, psourceRGB, sourceRGBMode);
-            blendFunc->setSourceRGB(sourceRGBMode);
-        }
-        if (pdestRGB) {
-            BlendFunc::BlendFuncMode destRGBMode;
-            findAttr(blendFuncModes, pdestRGB, destRGBMode);
-            blendFunc->setDestinationRGB(destRGBMode);
-        }
-        if (psourceAlpha) {
-            BlendFunc::BlendFuncMode sourceAlphaMode;
-            findAttr(blendFuncModes, psourceAlpha, sourceAlphaMode);
-            blendFunc->setSourceAlpha(sourceAlphaMode);
-        }
-        if (pdestAlpha) {
-            BlendFunc::BlendFuncMode destAlphaMode;
-            findAttr(blendFuncModes, pdestAlpha, destAlphaMode);
-            blendFunc->setDestinationAlpha(destAlphaMode);
-        }
-        pass->setAttributeAndModes(blendFunc);
+
+        parseBlendFunc(
+          pass,
+          getEffectPropertyChild(effect, prop, "source"),
+          getEffectPropertyChild(effect, prop, "destination"),
+          getEffectPropertyChild(effect, prop, "source-rgb"),
+          getEffectPropertyChild(effect, prop, "destination-rgb"),
+          getEffectPropertyChild(effect, prop, "source-alpha"),
+          getEffectPropertyChild(effect, prop, "destination-alpha")
+        );
     }
 };
 
@@ -579,7 +539,7 @@ struct StencilBuilder : public PassAttributeBuilder
             findAttr(stencilFunction, pfunction, func);
         if (pvalue)
             ref = pvalue->getIntValue();
-        if (pmask) 
+        if (pmask)
             mask = pmask->getIntValue();
 
         if (psfail)
@@ -602,6 +562,28 @@ struct StencilBuilder : public PassAttributeBuilder
 
 InstallAttributeBuilder<StencilBuilder> installStencil("stencil");
 
+struct AlphaToCoverageBuilder : public PassAttributeBuilder
+{
+    void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
+                        const SGReaderWriterOptions* options);
+};
+
+#ifndef GL_SAMPLE_ALPHA_TO_COVERAGE_ARB
+#define GL_SAMPLE_ALPHA_TO_COVERAGE_ARB 0x809E
+#endif
+
+void AlphaToCoverageBuilder::buildAttribute(Effect* effect, Pass* pass,
+                                     const SGPropertyNode* prop,
+                                     const SGReaderWriterOptions* options)
+{
+    const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
+    if (!realProp)
+        return;
+    pass->setMode(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB, (realProp->getValue<bool>() ?
+                                    StateAttribute::ON : StateAttribute::OFF));
+}
+
+InstallAttributeBuilder<AlphaToCoverageBuilder> installAlphaToCoverage("alpha-to-coverage");
 
 EffectNameValue<AlphaFunc::ComparisonFunction> alphaComparisonInit[] =
 {
@@ -648,6 +630,7 @@ struct AlphaTestBuilder : public PassAttributeBuilder
                                                              "comparison");
         const SGPropertyNode* pRef = getEffectPropertyChild(effect, prop,
                                                              "reference");
+
         AlphaFunc::ComparisonFunction func = AlphaFunc::ALWAYS;
         float refValue = 1.0f;
         if (pComp)
@@ -1080,19 +1063,19 @@ struct PolygonOffsetBuilder : public PassAttributeBuilder
     {
         if (!isAttributeActive(effect, prop))
             return;
-        
+
         const SGPropertyNode* factor
            = getEffectPropertyChild(effect, prop, "factor");
         const SGPropertyNode* units
            = getEffectPropertyChild(effect, prop, "units");
-        
+
         ref_ptr<PolygonOffset> polyoffset = new PolygonOffset;
-        
+
         polyoffset->setFactor(factor->getFloatValue());
         polyoffset->setUnits(units->getFloatValue());
 
         SG_LOG(SG_INPUT, SG_BULK,
-                   "Set PolygonOffset to " << polyoffset->getFactor() << polyoffset->getUnits() );            
+                   "Set PolygonOffset to " << polyoffset->getFactor() << polyoffset->getUnits() );
 
         pass->setAttributeAndModes(polyoffset.get(),
                                    StateAttribute::OVERRIDE|StateAttribute::ON);
@@ -1135,6 +1118,52 @@ struct VertexProgramPointSizeBuilder : public PassAttributeBuilder
 InstallAttributeBuilder<VertexProgramPointSizeBuilder>
 installPointSize("vertex-program-point-size");
 
+struct PointBuilder : public PassAttributeBuilder
+{
+    void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
+                        const SGReaderWriterOptions* options)
+    {
+        float minsize = 1.0;
+        float maxsize = 1.0;
+        float size    = 1.0;
+        osg::Vec3f attenuation = osg::Vec3f(1.0, 1.0, 1.0);
+
+        const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
+        if (!realProp)
+            return;
+
+        const SGPropertyNode* pminsize
+            = getEffectPropertyChild(effect, prop, "min-size");
+        const SGPropertyNode* pmaxsize
+            = getEffectPropertyChild(effect, prop, "max-size");
+        const SGPropertyNode* psize
+            = getEffectPropertyChild(effect, prop, "size");
+        const SGPropertyNode* pattenuation
+            = getEffectPropertyChild(effect, prop, "attenuation");
+
+        if (pminsize)
+            minsize = pminsize->getFloatValue();
+        if (pmaxsize)
+            maxsize = pmaxsize->getFloatValue();
+        if (psize)
+            size = psize->getFloatValue();
+        if (pattenuation)
+            attenuation = osg::Vec3f(pattenuation->getChild("x")->getFloatValue(),
+                                     pattenuation->getChild("y")->getFloatValue(),
+                                     pattenuation->getChild("z")->getFloatValue());
+
+        osg::Point* point = new osg::Point;
+        point->setMinSize(minsize);
+        point->setMaxSize(maxsize);
+        point->setSize(size);
+        point->setDistanceAttenuation(attenuation);
+        pass->setAttributeAndModes(point);
+    }
+};
+
+InstallAttributeBuilder<PointBuilder>
+installPoint("point");
+
 EffectNameValue<Depth::Function> depthFunctionInit[] =
 {
     {"never", Depth::NEVER},
@@ -1327,6 +1356,28 @@ void Effect::InitializeCallback::doUpdate(osg::Node* node, osg::NodeVisitor* nv)
     }
 }
 
+void Effect::UpdateCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
+{
+    EffectGeode* eg = dynamic_cast<EffectGeode*>(node);
+    if (!eg)
+        return;
+    Effect* effect = eg->getEffect();
+    if (!effect)
+        return;
+
+    for (vector<SGSharedPtr<Updater> >::iterator itr = effect->_extraData.begin(),
+             end = effect->_extraData.end();
+         itr != end;
+         ++itr) {
+        PropertyPoller * poller
+            = dynamic_cast<PropertyPoller*>(itr->ptr());
+        if (poller)
+            poller->pollProperties(effect);
+    }
+
+    traverse(node, nv);
+}
+
 bool Effect::Key::EqualTo::operator()(const Effect::Key& lhs,
                                       const Effect::Key& rhs) const
 {
@@ -1376,26 +1427,40 @@ template<typename T>
 class PropertyExpression : public SGExpression<T>
 {
 public:
-    PropertyExpression(SGPropertyNode* pnode) : _pnode(pnode) {}
-    
+    PropertyExpression(SGPropertyNode* pnode) : _pnode(pnode), _listener(NULL) {}
+
+    ~PropertyExpression()
+    {
+        delete _listener;
+    }
+
     void eval(T& value, const expression::Binding*) const
     {
         value = _pnode->getValue<T>();
     }
+
+    void setListener(SGPropertyChangeListener* l)
+    {
+        _listener = l;
+    }
 protected:
     SGPropertyNode_ptr _pnode;
+    SGPropertyChangeListener* _listener;
 };
 
 class EffectPropertyListener : public SGPropertyChangeListener
 {
 public:
     EffectPropertyListener(Technique* tniq) : _tniq(tniq) {}
-    
+
     void valueChanged(SGPropertyNode* node)
     {
         if (_tniq.valid())
             _tniq->refreshValidity();
     }
+
+    virtual ~EffectPropertyListener() { }
+
 protected:
     osg::observer_ptr<Technique> _tniq;
 };
@@ -1409,9 +1474,12 @@ Expression* propertyExpressionParser(const SGPropertyNode* exp,
     PropertyExpression<T>* pexp = new PropertyExpression<T>(pnode);
     TechniquePredParser* predParser
         = dynamic_cast<TechniquePredParser*>(parser);
-    if (predParser)
-        pnode->addChangeListener(new EffectPropertyListener(predParser
-                                                            ->getTechnique()));
+    if (predParser) {
+        EffectPropertyListener* l = new EffectPropertyListener(predParser
+                                                               ->getTechnique());
+        pexp->setListener(l);
+        pnode->addChangeListener(l);
+    }
     return pexp;
 }