]> git.mxchange.org Git - simgear.git/blobdiff - simgear/scene/model/SGMaterialAnimation.cxx
Work around apparent OSG 3.2.0 normal binding bug.
[simgear.git] / simgear / scene / model / SGMaterialAnimation.cxx
index cce40c62248b2b1c06990e2f7196f80c6240ba68..cc5c660c6ae93355779e3f8600e1e6c2791b3f0c 100644 (file)
 
 #include <simgear/props/condition.hxx>
 #include <simgear/props/props.hxx>
+#include <simgear/scene/material/Effect.hxx>
+#include <simgear/scene/material/EffectGeode.hxx>
+#include <simgear/scene/material/Pass.hxx>
+#include <simgear/scene/material/Technique.hxx>
 #include <simgear/scene/model/model.hxx>
+#include <simgear/scene/model/ConditionNode.hxx>
+#include <simgear/scene/util/OsgMath.hxx>
+
+using namespace std;
+using namespace simgear;
 
 namespace {
 /**
@@ -98,9 +107,9 @@ struct ColorSpec {
     return v;
   }
 
-  osg::Vec4& rgbaVec4()
+  osg::Vec4 rgbaVec4()
   {
-    return rgba().osg();
+    return toOsg(rgba());
   }
   
   SGVec4f &initialRgba() {
@@ -209,7 +218,25 @@ public:
 
   virtual void apply(osg::Geode& node)
   {
-    maybeGetMaterialValues(node.getStateSet());
+    using namespace simgear;
+    EffectGeode* eg = dynamic_cast<EffectGeode*>(&node);
+    if (eg) {
+      const Effect* effect = eg->getEffect();
+      if (effect)
+        for (vector<osg::ref_ptr<Technique> >::const_iterator itr
+               = effect->techniques.begin(), end = effect->techniques.end();
+             itr != end;
+             ++itr) {
+          const Technique* tniq = itr->get();
+          for (vector<osg::ref_ptr<Pass> >::const_iterator pitr
+                 = tniq->passes.begin(), pend = tniq->passes.end();
+               pitr != pend;
+               ++pitr)
+            maybeGetMaterialValues(pitr->get());
+        }
+    } else {
+      maybeGetMaterialValues(node.getStateSet());
+    }
     int numDrawables = node.getNumDrawables();
     for (int i = 0; i < numDrawables; i++) {
       osg::Geometry* geom = dynamic_cast<osg::Geometry*>(node.getDrawable(i));
@@ -230,18 +257,20 @@ public:
     }
   }
   
-  void maybeGetMaterialValues(osg::StateSet* stateSet)
+  void maybeGetMaterialValues(const osg::StateSet* stateSet)
   {
     if (!stateSet)
       return;
-    osg::Material* nodeMat
-      = dynamic_cast<osg::Material*>(stateSet->getAttribute(osg::StateAttribute::MATERIAL));
+    const osg::Material* nodeMat
+      = dynamic_cast<const osg::Material*>(stateSet
+                                           ->getAttribute(osg::StateAttribute
+                                                          ::MATERIAL));
     if (!nodeMat)
       return;
     material = nodeMat;
   }
 
-  osg::ref_ptr<osg::Material> material;
+  osg::ref_ptr<const osg::Material> material;
   osg::Vec4 ambientDiffuse;
 };
 
@@ -313,9 +342,7 @@ public:
 class UpdateCallback : public osg::NodeCallback {
 public:
   UpdateCallback(const osgDB::FilePathList& texturePathList,
-                 const SGCondition* condition,
                  const SGPropertyNode* configNode, SGPropertyNode* modelRoot) :
-    _condition(condition),
     _materialProps(configNode, modelRoot),
     _texturePathList(texturePathList),
     _prevState(false)
@@ -333,7 +360,7 @@ public:
   virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
   {
     osg::StateSet* stateSet = node->getStateSet();
-    if ((!_condition || _condition->test()) && stateSet) {
+    if (stateSet) {
       if (_textureProp) {
         std::string textureName = _textureProp->getStringValue();
         if (_textureName != textureName) {
@@ -373,7 +400,6 @@ public:
     traverse(node, nv);
   }
 private:
-  SGSharedPtr<const SGCondition> _condition;
   SGSharedPtr<const SGPropertyNode> _textureProp;
   SGSharedPtr<const SGPropertyNode> _thresholdProp;
   std::string _textureName;
@@ -386,14 +412,15 @@ private:
 
 SGMaterialAnimation::SGMaterialAnimation(const SGPropertyNode* configNode,
                                          SGPropertyNode* modelRoot,
-                                         const osgDB::ReaderWriter::Options*
-                                         options) :
+                                         const osgDB::Options*
+                                         options, const string &path) :
   SGAnimation(configNode, modelRoot),
   texturePathList(options->getDatabasePathList())
 {
   if (configNode->hasChild("global"))
-    SG_LOG(SG_IO, SG_ALERT, "Use of <global> in material animation is "
-           "no longer supported");
+    SG_LOG(SG_IO, SG_ALERT, path <<
+           ": Use of <global> in material animation is "
+           "no longer supported.");
 }
 
 osg::Group*
@@ -406,16 +433,12 @@ SGMaterialAnimation::createAnimationGroup(osg::Group& parent)
   const SGPropertyNode* node = getConfig()->getChild("property-base");
   if (node)
     inputRoot = getModelRoot()->getNode(node->getStringValue(), true);
-  if (getConfig()->hasChild("texture-prop")) {
-      osg::StateSet* stateSet = group->getOrCreateStateSet();
-      stateSet->setDataVariance(osg::Object::DYNAMIC);
-  }
+  osg::StateSet* stateSet = group->getOrCreateStateSet();  
   if (getConfig()->hasChild("texture")) {
     std::string textureName = getConfig()->getStringValue("texture");
     std::string textureFile;
     textureFile = osgDB::findFileInPath(textureName, texturePathList);
     if (!textureFile.empty()) {
-      osg::StateSet* stateSet = group->getOrCreateStateSet();
       osg::Texture2D* texture2D = SGLoadTexture2D(textureFile);
       if (texture2D) {
         stateSet->setTextureAttribute(0, texture2D,
@@ -430,7 +453,6 @@ SGMaterialAnimation::createAnimationGroup(osg::Group& parent)
   }
   if (getConfig()->hasChild("threshold-prop") ||
       getConfig()->hasChild("threshold")) {
-    osg::StateSet* stateSet = group->getOrCreateStateSet();
     osg::AlphaFunc* alphaFunc = new osg::AlphaFunc;
     alphaFunc->setFunction(osg::AlphaFunc::GREATER);
     float threshold = getConfig()->getFloatValue("threshold", 0);
@@ -452,85 +474,106 @@ SGMaterialAnimation::createAnimationGroup(osg::Group& parent)
     suppliedColors |= SHININESS;
   if (getConfig()->hasChild("transparency"))
     suppliedColors |= TRANSPARENCY;
-
+  osg::Material* mat = 0;
   if (suppliedColors != 0) {
-      osg::StateSet* stateSet = group->getOrCreateStateSet();
-      osg::Material* mat;
+    if (defaultMaterial.valid()) {
+      mat = defaultMaterial.get();
 
-      if (defaultMaterial.valid()) {
-       mat = defaultMaterial.get();
-
-      } else {
-       mat = new osg::Material;
-       mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
-      }
-      mat->setDataVariance(osg::Object::DYNAMIC);
-      unsigned defaultColorModeMask = 0;
-      mat->setUpdateCallback(0); // Just to make sure.
-      switch (mat->getColorMode()) {
-      case osg::Material::OFF:
-       defaultColorModeMask = 0;
-       break;
-      case osg::Material::AMBIENT:
-       defaultColorModeMask = AMBIENT;
-       break;
-      case osg::Material::DIFFUSE:
-       defaultColorModeMask = DIFFUSE;
-       break;
-      case osg::Material::AMBIENT_AND_DIFFUSE:
-       defaultColorModeMask = AMBIENT | DIFFUSE;
-       break;
-      case osg::Material::SPECULAR:
-       defaultColorModeMask = SPECULAR;
-       break;
-      case osg::Material::EMISSION:
-       defaultColorModeMask = EMISSION;
-       break;
-      }
-      // Copy the color found by traversing geometry into the material
-      // in case we need to specify it (e.g., transparency) and it is
-      // not specified by the animation.
-      if (defaultAmbientDiffuse.x() >= 0) {
-       if (defaultColorModeMask & AMBIENT)
-         mat->setAmbient(osg::Material::FRONT_AND_BACK, defaultAmbientDiffuse);
-       if (defaultColorModeMask & DIFFUSE)
-         mat->setDiffuse(osg::Material::FRONT_AND_BACK, defaultAmbientDiffuse);
-      }
-      // Compute which colors in the animation override colors set via
-      // colorMode / glColor, and set the colorMode for the animation's
-      // material accordingly. 
-      if (suppliedColors & TRANSPARENCY) {
-       // All colors will be affected by the material. Hope all the
-       // defaults are fine, if needed.
-       mat->setColorMode(osg::Material::OFF);
-      } else if ((suppliedColors & defaultColorModeMask) != 0) {
-       // First deal with the complicated AMBIENT/DIFFUSE case.
-       if ((defaultColorModeMask & AMBIENT_DIFFUSE) != 0) {
-         // glColor can supply colors not specified by the animation.
-         unsigned matColorModeMask = ((~suppliedColors & defaultColorModeMask)
-                                      & AMBIENT_DIFFUSE);
-         if ((matColorModeMask & DIFFUSE) != 0)
-           mat->setColorMode(osg::Material::DIFFUSE);
-         else if ((matColorModeMask & AMBIENT) != 0)
-           mat->setColorMode(osg::Material::AMBIENT);
-         else
-           mat->setColorMode(osg::Material::OFF);
-       } else {
-         // The animation overrides the glColor color.
-         mat->setColorMode(osg::Material::OFF);
-       }
+    } else {
+      mat = new osg::Material;
+      mat->setColorMode(osg::Material::AMBIENT_AND_DIFFUSE);
+    }
+    mat->setDataVariance(osg::Object::DYNAMIC);
+    unsigned defaultColorModeMask = 0;
+    mat->setUpdateCallback(0); // Just to make sure.
+    // XXX This should probably go away, as ac3d models always have a
+    // DIFFUSE color mode.
+    switch (mat->getColorMode()) {
+    case osg::Material::OFF:
+      defaultColorModeMask = 0;
+      break;
+    case osg::Material::AMBIENT:
+      defaultColorModeMask = AMBIENT;
+      break;
+    case osg::Material::DIFFUSE:
+      defaultColorModeMask = DIFFUSE;
+      break;
+    case osg::Material::AMBIENT_AND_DIFFUSE:
+      defaultColorModeMask = AMBIENT | DIFFUSE;
+      break;
+    case osg::Material::SPECULAR:
+      defaultColorModeMask = SPECULAR;
+      break;
+    case osg::Material::EMISSION:
+      defaultColorModeMask = EMISSION;
+      break;
+    }
+    // Copy the color found by traversing geometry into the material
+    // in case we need to specify it (e.g., transparency) and it is
+    // not specified by the animation.
+    if (defaultAmbientDiffuse.x() >= 0) {
+      if (defaultColorModeMask & AMBIENT)
+        mat->setAmbient(osg::Material::FRONT_AND_BACK, defaultAmbientDiffuse);
+      if (defaultColorModeMask & DIFFUSE)
+        mat->setDiffuse(osg::Material::FRONT_AND_BACK, defaultAmbientDiffuse);
+    }
+    // Compute which colors in the animation override colors set via
+    // colorMode / glColor, and set the colorMode for the animation's
+    // material accordingly. 
+    if (suppliedColors & TRANSPARENCY) {
+      // All colors will be affected by the material. Hope all the
+      // defaults are fine, if needed.
+      mat->setColorMode(osg::Material::OFF);
+    } else if ((suppliedColors & defaultColorModeMask) != 0) {
+      // First deal with the complicated AMBIENT/DIFFUSE case.
+      if ((defaultColorModeMask & AMBIENT_DIFFUSE) != 0) {
+        // glColor can supply colors not specified by the animation.
+        unsigned matColorModeMask = ((~suppliedColors & defaultColorModeMask)
+                                     & AMBIENT_DIFFUSE);
+        if ((matColorModeMask & DIFFUSE) != 0)
+          mat->setColorMode(osg::Material::DIFFUSE);
+        else if ((matColorModeMask & AMBIENT) != 0)
+          mat->setColorMode(osg::Material::AMBIENT);
+        else
+          mat->setColorMode(osg::Material::OFF);
       } else {
-       // No overlap between the animation and color mode, so leave
-       // the color mode alone.
+        // The animation overrides the glColor color.
+        mat->setColorMode(osg::Material::OFF);
       }
-      stateSet->setAttribute(mat,(osg::StateAttribute::ON
-                                 | osg::StateAttribute::OVERRIDE));
+    } else {
+      // No overlap between the animation and color mode, so leave
+      // the color mode alone.
+    }
+    stateSet->setAttribute(mat,(osg::StateAttribute::ON
+                                | osg::StateAttribute::OVERRIDE));
+  }
+  bool matAnimated = false;
+  if (mat) {
+    MaterialPropertyAdapter adapter(getConfig(), inputRoot);
+    adapter.setMaterialValues(stateSet);
+    matAnimated = adapter.isAnimated();
+  }
+  if (matAnimated || getConfig()->hasChild("texture-prop")
+      || getConfig()->hasChild("threshold-prop") || getCondition()) {
+    stateSet->setDataVariance(osg::Object::DYNAMIC);
+    group->setUpdateCallback(new UpdateCallback(texturePathList,
+                                                getConfig(), inputRoot));
+  } else {
+    stateSet->setDataVariance(osg::Object::STATIC);
+  }
+  if (getCondition()) {
+    ConditionNode* cn = new ConditionNode;
+    cn->setCondition(getCondition());
+    osg::Group* modelGroup = new osg::Group;
+    group->addChild(modelGroup);
+    cn->addChild(group);
+    cn->addChild(modelGroup);
+    parent.addChild(cn);
+    return modelGroup;
+  } else {
+    parent.addChild(group);
+    return group;
   }
-  group->setUpdateCallback(new UpdateCallback(texturePathList,
-                                             getCondition(),
-                                             getConfig(), inputRoot));
-  parent.addChild(group);
-  return group;
 }
 
 void
@@ -546,3 +589,32 @@ SGMaterialAnimation::install(osg::Node& node)
     }
     defaultAmbientDiffuse = defaultsVisitor.ambientDiffuse;
 }
+
+const char* colorNames[] =
+{
+    "ambient",
+    "diffuse",
+    "specular",
+    "emission"
+};
+
+// Build an effect which mimics the material color mode in a
+// shader. The OpenGL material values will be overridden by the
+// material animation's material.
+//
+// This is a hack to get the effect to respect the values set in the
+// material, set up by the animation, which overrides the values in
+// the effect's material attributes. Things will be different when
+// material animations are implemented purely by manipulating effects.
+
+SGPropertyNode_ptr
+SGMaterialAnimation::makeEffectProperties(const SGPropertyNode* animProp)
+{
+    SGPropertyNode_ptr eRoot = new SGPropertyNode;
+    SGPropertyNode* inherit = makeNode(eRoot, "inherits-from");
+    if (animProp->hasChild("diffuse") || animProp->hasChild("transparency"))
+        inherit->setStringValue("Effects/material-off");
+    else
+        inherit->setStringValue("Effects/material-diffuse");
+    return eRoot;
+}