]> git.mxchange.org Git - simgear.git/commitdiff
Effects for models
authorTim Moore <timoore@redhat.com>
Tue, 8 Sep 2009 11:09:05 +0000 (13:09 +0200)
committerTim Moore <timoore@redhat.com>
Fri, 13 Nov 2009 21:41:11 +0000 (22:41 +0100)
Basically working, at last. Among other things, create effects in
 models loaded directly from .ac files; this can happen, for example,
with the random models from the materials library.

15 files changed:
projects/VC7.1/SimGear.vcproj
projects/VC90/SimGear.vcproj
simgear/scene/material/Effect.cxx
simgear/scene/material/Effect.hxx
simgear/scene/material/EffectGeode.cxx
simgear/scene/material/Technique.cxx
simgear/scene/material/TextureBuilder.cxx
simgear/scene/material/makeEffect.cxx
simgear/scene/model/SGReaderWriterXML.cxx
simgear/scene/model/model.cxx
simgear/scene/model/model.hxx
simgear/scene/model/modellib.cxx
simgear/scene/util/CopyOp.cxx [new file with mode: 0644]
simgear/scene/util/CopyOp.hxx [new file with mode: 0644]
simgear/scene/util/Makefile.am

index bc1a2b66b8be7b51d581a20424a53734a41355a9..1139bc366ee7baf720d70b2a5812973a957b0e1f 100755 (executable)
                <Filter
                        Name="Lib_sgutil"
                        Filter="">
+                       <File
+                               RelativePath="..\..\simgear\scene\util\CopyOp.cxx">
+                       </File>
+                       <File
+                               RelativePath="..\..\simgear\scene\util\CopyOp.hxx">
+                       </File>
                        <File
                                RelativePath="..\..\simgear\scene\util\NodeAndDrawableVisitor.cxx">
                        </File>
index eab4385560781c3ae79d835422e7a0a035d3c65e..95d18ebbbf3d54514c03efb69f69ed7c2d87da42 100644 (file)
                <Filter
                        Name="Lib_sgutil"
                        >
+                       <File
+                               RelativePath="..\..\simgear\scene\util\CopyOp.cxx"
+                               >
+                       </File>
+                       <File
+                               RelativePath="..\..\simgear\scene\util\CopyOp.hxx"
+                               >
+                       </File>
                        <File
                                RelativePath="..\..\simgear\scene\util\NodeAndDrawableVisitor.cxx"
                                >
index 2e68223431718685d65d750251ae143ca70ba511..a94267fc6439d9e3071cb66ed0bec874be02a10f 100644 (file)
@@ -30,7 +30,6 @@
 #include <map>
 #include <utility>
 
-#include <boost/bind.hpp>
 #include <boost/foreach.hpp>
 #include <boost/lexical_cast.hpp>
 #include <boost/tuple/tuple.hpp>
@@ -85,10 +84,12 @@ Effect::Effect()
 Effect::Effect(const Effect& rhs, const CopyOp& copyop)
     : root(rhs.root), parametersProp(rhs.parametersProp)
 {
-    using namespace boost;
-    transform(rhs.techniques.begin(), rhs.techniques.end(),
-              back_inserter(techniques),
-              bind(simgear::clone_ref<Technique>, _1, copyop));
+    typedef vector<ref_ptr<Technique> > TechniqueList;
+    for (TechniqueList::const_iterator itr = rhs.techniques.begin(),
+             end = rhs.techniques.end();
+         itr != end;
+         ++itr)
+        techniques.push_back(static_cast<Technique*>(copyop(itr->get())));
 }
 
 // Assume that the last technique is always valid.
@@ -196,6 +197,19 @@ osg::Vec4f getColor(const SGPropertyNode* prop)
     }
 }
 
+// The description of an attribute may exist in a pass' XML, but a
+// derived effect might want to disable the attribute altogether. So,
+// some attributes have an "active" property; if it exists and is
+// false, the OSG attribute is not built at all. This is different
+// from any OSG mode settings that might be around.
+
+bool isAttributeActive(Effect* effect, const SGPropertyNode* prop)
+{
+    const SGPropertyNode* activeProp
+        = getEffectPropertyChild(effect, prop, "active");
+    return !activeProp || activeProp->getValue<bool>();
+}
+
 struct LightingBuilder : public PassAttributeBuilder
 {
     void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
@@ -265,6 +279,15 @@ struct CullFaceBuilder : PassAttributeBuilder
 
 InstallAttributeBuilder<CullFaceBuilder> installCullFace("cull-face");
 
+EffectNameValue<StateSet::RenderingHint> renderingHintInit[] =
+{
+    { "default", StateSet::DEFAULT_BIN },
+    { "opaque", StateSet::OPAQUE_BIN },
+    { "transparent", StateSet::TRANSPARENT_BIN }
+};
+
+EffectPropertyMap<StateSet::RenderingHint> renderingHints(renderingHintInit);
+
 struct HintBuilder : public PassAttributeBuilder
 {
     void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
@@ -273,11 +296,9 @@ struct HintBuilder : public PassAttributeBuilder
         const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
         if (!realProp)
             return;
-        string propVal = realProp->getStringValue();
-        if (propVal == "opaque")
-            pass->setRenderingHint(StateSet::OPAQUE_BIN);
-        else if (propVal == "transparent")
-            pass->setRenderingHint(StateSet::TRANSPARENT_BIN);
+        StateSet::RenderingHint renderingHint = StateSet::DEFAULT_BIN;
+        findAttr(renderingHints, realProp, renderingHint);
+        pass->setRenderingHint(renderingHint);
     }    
 };
 
@@ -288,6 +309,8 @@ struct RenderBinBuilder : public PassAttributeBuilder
     void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
                         const osgDB::ReaderWriter::Options* options)
     {
+        if (!isAttributeActive(effect, prop))
+            return;
         const SGPropertyNode* binProp = prop->getChild("bin-number");
         binProp = getEffectPropertyNode(effect, binProp);
         const SGPropertyNode* nameProp = prop->getChild("bin-name");
@@ -329,6 +352,8 @@ void MaterialBuilder::buildAttribute(Effect* effect, Pass* pass,
                                      const SGPropertyNode* prop,
                                      const osgDB::ReaderWriter::Options* options)
 {
+    if (!isAttributeActive(effect, prop))
+        return;
     Material* mat = new Material;
     const SGPropertyNode* color = 0;
     if ((color = getEffectPropertyChild(effect, prop, "ambient")))
@@ -397,6 +422,8 @@ struct BlendBuilder : public PassAttributeBuilder
     void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
                         const osgDB::ReaderWriter::Options* options)
     {
+        if (!isAttributeActive(effect, prop))
+            return;
         // XXX Compatibility with early <blend> syntax; should go away
         // before a release
         const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
@@ -417,8 +444,8 @@ struct BlendBuilder : public PassAttributeBuilder
             pass->setMode(GL_BLEND, StateAttribute::OFF);
             return;
         }
-        const SGPropertyNode* psource = getEffectPropertyChild(effect, prop,
-                                                              "source");
+        const SGPropertyNode* psource
+            = getEffectPropertyChild(effect, prop, "source");
         const SGPropertyNode* pdestination
             = getEffectPropertyChild(effect, prop, "destination");
         const SGPropertyNode* psourceRGB
@@ -493,6 +520,8 @@ struct AlphaTestBuilder : public PassAttributeBuilder
     void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
                         const osgDB::ReaderWriter::Options* options)
     {
+        if (!isAttributeActive(effect, prop))
+            return;
         // XXX Compatibility with early <alpha-test> syntax; should go away
         // before a release
         const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop);
@@ -577,7 +606,8 @@ void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass,
                                         const SGPropertyNode* prop,
                                         const osgDB::ReaderWriter::Options* options)
 {
-
+    if (!isAttributeActive(effect, prop))
+        return;
     // Decode the texture unit
     int unit = 0;
     const SGPropertyNode* pUnit = prop->getChild("unit");
@@ -593,7 +623,7 @@ void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass,
                        << lex.what());
             }
     }
-    const SGPropertyNode* pType = prop->getChild("type");
+    const SGPropertyNode* pType = getEffectPropertyChild(effect, prop, "type");
     string type;
     if (!pType)
         type = "2d";
@@ -650,6 +680,8 @@ void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass,
                                           const osgDB::ReaderWriter::Options*
                                           options)
 {
+    if (!isAttributeActive(effect, prop))
+        return;
     PropertyList pVertShaders = prop->getChildren("vertex-shader");
     PropertyList pFragShaders = prop->getChildren("fragment-shader");
     string programKey;
@@ -724,6 +756,8 @@ struct UniformBuilder :public PassAttributeBuilder
     void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
                         const osgDB::ReaderWriter::Options* options)
     {
+        if (!isAttributeActive(effect, prop))
+            return;
         const SGPropertyNode* nameProp = prop->getChild("name");
         const SGPropertyNode* typeProp = prop->getChild("type");
         const SGPropertyNode* valProp
@@ -818,6 +852,8 @@ struct PolygonModeBuilder : public PassAttributeBuilder
     void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop,
                         const osgDB::ReaderWriter::Options* options)
     {
+        if (!isAttributeActive(effect, prop))
+            return;
         const SGPropertyNode* frontProp
             = getEffectPropertyChild(effect, prop, "front");
         const SGPropertyNode* backProp
@@ -876,8 +912,9 @@ void buildTechnique(Effect* effect, const SGPropertyNode* prop,
 }
 
 // Specifically for .ac files...
-bool makeParametersFromStateSet(SGPropertyNode* paramRoot, const StateSet* ss)
+bool makeParametersFromStateSet(SGPropertyNode* effectRoot, const StateSet* ss)
 {
+    SGPropertyNode* paramRoot = makeChild(effectRoot, "parameters");
     SGPropertyNode* matNode = paramRoot->getChild("material", 0, true);
     Vec4f ambVal, difVal, specVal, emisVal;
     float shininess = 0.0f;
@@ -888,13 +925,16 @@ bool makeParametersFromStateSet(SGPropertyNode* paramRoot, const StateSet* ss)
         specVal = mat->getSpecular(Material::FRONT_AND_BACK);
         emisVal = mat->getEmission(Material::FRONT_AND_BACK);
         shininess = mat->getShininess(Material::FRONT_AND_BACK);
+        makeChild(matNode, "active")->setValue(true);
+        makeChild(matNode, "ambient")->setValue(toVec4d(toSG(ambVal)));
+        makeChild(matNode, "diffuse")->setValue(toVec4d(toSG(difVal)));
+        makeChild(matNode, "specular")->setValue(toVec4d(toSG(specVal)));
+        makeChild(matNode, "emissive")->setValue(toVec4d(toSG(emisVal)));
+        makeChild(matNode, "shininess")->setValue(shininess);
+        matNode->getChild("color-mode", 0, true)->setStringValue("diffuse");
+    } else {
+        makeChild(matNode, "active")->setValue(false);
     }
-    matNode->getChild("ambient", 0, true)->setValue(toVec4d(toSG(ambVal)));
-    matNode->getChild("diffuse", 0, true)->setValue(toVec4d(toSG(difVal)));
-    matNode->getChild("specular", 0, true)->setValue(toVec4d(toSG(specVal)));
-    matNode->getChild("emissive", 0, true)->setValue(toVec4d(toSG(emisVal)));
-    matNode->getChild("shininess", 0, true)->setValue(shininess);
-    matNode->getChild("color-mode", 0, true)->setStringValue("diffuse");
     const ShadeModel* sm = getStateAttribute<ShadeModel>(ss);
     string shadeModelString("smooth");
     if (sm) {
@@ -902,8 +942,7 @@ bool makeParametersFromStateSet(SGPropertyNode* paramRoot, const StateSet* ss)
         if (smMode == ShadeModel::FLAT)
             shadeModelString = "flat";
     }
-    paramRoot->getChild("shade-model", 0, true)
-        ->setStringValue(shadeModelString);
+    makeChild(paramRoot, "shade-model")->setStringValue(shadeModelString);
     string cullFaceString("off");
     const CullFace* cullFace = getStateAttribute<CullFace>(ss);
     if (cullFace) {
@@ -921,15 +960,18 @@ bool makeParametersFromStateSet(SGPropertyNode* paramRoot, const StateSet* ss)
             break;
         }
     }
-    paramRoot->getChild("cull-face", 0, true)->setStringValue(cullFaceString);
+    makeChild(paramRoot, "cull-face")->setStringValue(cullFaceString);
     const BlendFunc* blendFunc = getStateAttribute<BlendFunc>(ss);
+    SGPropertyNode* blendNode = makeChild(paramRoot, "blend");
     if (blendFunc) {
         string sourceMode = findName(blendFuncModes, blendFunc->getSource());
         string destMode = findName(blendFuncModes, blendFunc->getDestination());
-        SGPropertyNode* blendNode = paramRoot->getChild("blend", 0, true);
-        blendNode->getChild("source", 0, true)->setStringValue(sourceMode);
-        blendNode->getChild("destination", 0, true)->setStringValue(destMode);
-        blendNode->getChild("mode", 0, true)->setValue(true);
+        makeChild(blendNode, "active")->setValue(true);
+        makeChild(blendNode, "source")->setStringValue(sourceMode);
+        makeChild(blendNode, "destination")->setStringValue(destMode);
+        makeChild(blendNode, "mode")->setValue(true);
+    } else {
+        makeChild(blendNode, "active")->setValue(false);
     }
     makeTextureParameters(paramRoot, ss);
     return true;
index 2b3942fee89dec17040d2bfdf320bfc6ed36bf19..594d02ebeb7580fe7715e5d470c158cdc784502c 100644 (file)
@@ -74,5 +74,15 @@ Effect* makeEffect(SGPropertyNode* prop,
 
 bool makeParametersFromStateSet(SGPropertyNode* paramRoot,
                                 const osg::StateSet* ss);
+
+namespace effect
+{
+/**
+ * The function that implements effect property tree inheritance.
+ */
+void mergePropertyTrees(SGPropertyNode* resultNode,
+                        const SGPropertyNode* left,
+                        const SGPropertyNode* right);
+}
 }
 #endif
index 799b567c76a8adf5b7399ae1c8cab6cdd265051a..949055b58f5e61ec3a0efb4ce78fd5aff03ae80c 100644 (file)
@@ -38,10 +38,10 @@ EffectGeode::EffectGeode()
 {
 }
 
-EffectGeode::EffectGeode(const EffectGeode& rhs, const CopyOp& copyop) :
-    Geode(rhs, copyop)
+EffectGeode::EffectGeode(const EffectGeode& rhs, const osg::CopyOp& copyop) :
+    Geode(rhs, copyop),
+    _effect(static_cast<Effect*>(copyop(rhs._effect.get())))
 {
-    _effect = static_cast<Effect*>(rhs._effect->clone(copyop));
 }
 
 void EffectGeode::resizeGLObjectBuffers(unsigned int maxSize)
index 4c1dbe169c3a6f0eef2f5009fe168ccdcc086f87..4258b46422e6c825d27261b7a6b5f7f57e30d5b9 100644 (file)
@@ -6,7 +6,6 @@
 #include "Technique.hxx"
 #include "Pass.hxx"
 
-#include <boost/bind.hpp>
 #include <boost/foreach.hpp>
 
 #include <iterator>
@@ -59,16 +58,15 @@ Technique::Technique(bool alwaysValid)
 
 Technique::Technique(const Technique& rhs, const osg::CopyOp& copyop) :
     _contextMap(rhs._contextMap), _alwaysValid(rhs._alwaysValid),
-    _shadowingStateSet(rhs._shadowingStateSet),
+    _shadowingStateSet(copyop(rhs._shadowingStateSet)),
     _validExpression(rhs._validExpression),
     _contextIdLocation(rhs._contextIdLocation)
 {
-    using namespace std;
-    using namespace boost;
-    transform(rhs.passes.begin(), rhs.passes.end(),
-              back_inserter(passes),
-              bind(simgear::clone_ref<Pass>, _1, copyop));
-
+    for (std::vector<ref_ptr<Pass> >::const_iterator itr = rhs.passes.begin(),
+             end = rhs.passes.end();
+         itr != end;
+         ++itr)
+        passes.push_back(static_cast<Pass*>(copyop(itr->get())));
 }
 
 Technique::~Technique()
index 9103fe59ba099934f8512333da6acecbe631d05a..2623c4a73a2b76458b9e2db98fae420fa48dacc4 100644 (file)
@@ -285,19 +285,29 @@ TextureBuilder::Registrar installNoise("noise", new NoiseBuilder);
 
 bool makeTextureParameters(SGPropertyNode* paramRoot, const StateSet* ss)
 {
+    SGPropertyNode* texUnit = makeChild(paramRoot, "texture");
     const Texture* tex = getStateAttribute<Texture>(0, ss);
     const Texture2D* texture = dynamic_cast<const Texture2D*>(tex);
-    if (!tex)
+    makeChild(texUnit, "unit")->setValue(0);
+    if (!tex) {
+        makeChild(texUnit, "active")->setValue(false);
+        makeChild(texUnit, "type")->setValue("white");
         return false;
+    }
     const Image* image = texture->getImage();
     string imageName;
-    if (image)
+    if (image) {
         imageName = image->getFileName();
+    } else {
+        makeChild(texUnit, "active")->setValue(false);
+        makeChild(texUnit, "type")->setValue("white");
+        return false;
+    }
+    makeChild(texUnit, "active")->setValue(true);
+    makeChild(texUnit, "type")->setValue("2d");
     string wrapS = findName(wrapModes, texture->getWrap(Texture::WRAP_S));
     string wrapT = findName(wrapModes, texture->getWrap(Texture::WRAP_T));
     string wrapR = findName(wrapModes, texture->getWrap(Texture::WRAP_R));
-    SGPropertyNode* texUnit = makeChild(paramRoot, "texture-unit");
-    makeChild(texUnit, "unit")->setValue(0);
     makeChild(texUnit, "image")->setStringValue(imageName);
     makeChild(texUnit, "wrap-s")->setStringValue(wrapS);
     makeChild(texUnit, "wrap-t")->setStringValue(wrapT);
index 786fc2f579411bffc7d2bdfb759602762eed62fe..56bc1636e45d0becece7564f63f573c05b551fa2 100644 (file)
@@ -39,6 +39,7 @@ namespace simgear
 {
 using namespace std;
 using namespace osg;
+using namespace effect;
 
 typedef vector<const SGPropertyNode*> RawPropVector;
 typedef map<const string, ref_ptr<Effect> > EffectMap;
@@ -72,6 +73,8 @@ struct PropPredicate
     const SGPropertyNode* node;
 };
 
+namespace effect
+{
 void mergePropertyTrees(SGPropertyNode* resultNode,
                         const SGPropertyNode* left, const SGPropertyNode* right)
 {
@@ -108,6 +111,7 @@ void mergePropertyTrees(SGPropertyNode* resultNode,
         copyProperties(*itr, newChild);
     }
 }
+}
 
 Effect* makeEffect(const string& name,
                    bool realizeTechniques,
index 2a4d612e6f2f485939dc79499b6a438993a430d4..c19d7e82e7dc690364b2126839e5500b299c888d 100644 (file)
@@ -20,6 +20,7 @@
 #  include <simgear_config.h>
 #endif
 
+#include <osg/Geode>
 #include <osg/MatrixTransform>
 #include <osgDB/WriteFile>
 #include <osgDB/Registry>
@@ -43,7 +44,9 @@
 #include "model.hxx"
 #include "SGText.hxx"
 
+using namespace std;
 using namespace simgear;
+using namespace osg;
 
 static osg::Node *
 sgLoad3DModel_internal(const std::string& path,
@@ -210,13 +213,13 @@ sgLoad3DModel_internal(const string &path,
             texturepath = texturepath.dir();
 
         options->setDatabasePath(texturepath.str());
-        osg::Node* origModel
-            = osgDB::readNodeFile(modelpath.str(), options.get());
-
-        if (!origModel)
+        osgDB::ReaderWriter::ReadResult modelResult
+            = osgDB::Registry::instance()->readNode(modelpath.str(),
+                                                    options.get());
+        if (!modelResult.validNode())
             throw sg_io_exception("Failed to load 3D model",
                                   sg_location(modelpath.str()));
-        model = copyModel(origModel);
+        model = copyModel(modelResult.getNode());
         // Add an extra reference to the model stored in the database.
         // That is to avoid expiring the object from the cache even if
         // it is still in use. Note that the object cache will think
@@ -224,7 +227,7 @@ sgLoad3DModel_internal(const string &path,
         // clone all structural nodes here we need that extra
         // reference to the original object
         SGDatabaseReference* databaseReference;
-        databaseReference = new SGDatabaseReference(origModel);
+        databaseReference = new SGDatabaseReference(modelResult.getNode());
         model->addObserver(databaseReference);
 
         // Update liveries
@@ -274,7 +277,8 @@ sgLoad3DModel_internal(const string &path,
         SGPath submodelpath;
         osg::ref_ptr<osg::Node> submodel;
         string submodelFileName = sub_props->getStringValue("path");
-        if ( submodelFileName.size() > 2 && submodelFileName.substr( 0, 2 ) == "./" ) {
+        if (submodelFileName.size() > 2
+            && !submodelFileName.compare(0, 2, "./" )) {
             submodelpath = modelpath.dir();
             submodelpath.append( submodelFileName.substr( 2 ) );
         } else {
@@ -292,7 +296,7 @@ sgLoad3DModel_internal(const string &path,
             throw;
         }
 
-        osg::ref_ptr<osg::Node> submodel_final=submodel.get();
+        osg::ref_ptr<osg::Node> submodel_final = submodel;
         SGPropertyNode *offs = sub_props->getNode("offsets", false);
         if (offs) {
             osg::Matrix res_matrix;
@@ -314,7 +318,7 @@ sgLoad3DModel_internal(const string &path,
                                offs->getDoubleValue("z-m", 0));
             align->setMatrix(res_matrix*tmat);
             align->addChild(submodel.get());
-            submodel_final=align.get();
+            submodel_final = align;
         }
         submodel_final->setName(sub_props->getStringValue("name", ""));
 
@@ -363,7 +367,12 @@ sgLoad3DModel_internal(const string &path,
                         prop_root,
                         options.get()));
     }
-
+    PropertyList effect_nodes = props->getChildren("effect");
+    {
+        ref_ptr<Node> modelWithEffects
+            = instantiateEffects(group.get(), effect_nodes, options.get());
+        group = static_cast<Group*>(modelWithEffects.get());
+    }
     std::vector<SGPropertyNode_ptr> animation_nodes;
     animation_nodes = props->getChildren("animation");
     for (unsigned i = 0; i < animation_nodes.size(); ++i)
index 5672ece6b810bf1940d035ae0b9b7442c832a342..b9d0d89e502574a07696a283a1e0f80b218d8311 100644 (file)
@@ -9,6 +9,8 @@
 
 #include <utility>
 
+#include <boost/foreach.hpp>
+
 #include <osg/ref_ptr>
 #include <osgDB/FileNameUtils>
 #include <osgDB/FileUtils>
 #include <osgDB/ReadFile>
 #include <osgDB/SharedStateManager>
 
+#include <simgear/scene/material/Effect.hxx>
+#include <simgear/scene/material/EffectGeode.hxx>
 #include <simgear/scene/util/SGSceneFeatures.hxx>
 #include <simgear/scene/util/SGSceneUserData.hxx>
+#include <simgear/scene/util/CopyOp.hxx>
+#include <simgear/scene/util/SplicingVisitor.hxx>
+
 
 #include <simgear/structure/exception.hxx>
+#include <simgear/structure/Singleton.hxx>
 #include <simgear/props/props.hxx>
 #include <simgear/props/props_io.hxx>
 #include <simgear/props/condition.hxx>
@@ -67,21 +75,23 @@ SGLoadTexture2D(bool staticTexture, const std::string& path,
 
 namespace simgear
 {
+using namespace std;
 using namespace osg;
+using simgear::CopyOp;
 
 Node* copyModel(Node* model)
 {
-    CopyOp::CopyFlags flags = CopyOp::DEEP_COPY_ALL;
-    flags &= ~CopyOp::DEEP_COPY_TEXTURES;
-    flags &= ~CopyOp::DEEP_COPY_IMAGES;
-    flags &= ~CopyOp::DEEP_COPY_STATESETS;
-    flags &= ~CopyOp::DEEP_COPY_STATEATTRIBUTES;
-    flags &= ~CopyOp::DEEP_COPY_ARRAYS;
-    flags &= ~CopyOp::DEEP_COPY_PRIMITIVES;
-    // This will preserve display lists ...
-    flags &= ~CopyOp::DEEP_COPY_DRAWABLES;
-    flags &= ~CopyOp::DEEP_COPY_SHAPES;
-    return static_cast<Node*>(model->clone(CopyOp(flags)));
+    const CopyOp::CopyFlags flags = (CopyOp::DEEP_COPY_ALL
+                                     & ~CopyOp::DEEP_COPY_TEXTURES
+                                     & ~CopyOp::DEEP_COPY_IMAGES
+                                     & ~CopyOp::DEEP_COPY_STATESETS
+                                     & ~CopyOp::DEEP_COPY_STATEATTRIBUTES
+                                     & ~CopyOp::DEEP_COPY_ARRAYS
+                                     & ~CopyOp::DEEP_COPY_PRIMITIVES
+                                     // This will preserve display lists ...
+                                     & ~CopyOp::DEEP_COPY_DRAWABLES
+                                     & ~CopyOp::DEEP_COPY_SHAPES);
+    return (CopyOp(flags))(model);
 }
 
 TextureUpdateVisitor::TextureUpdateVisitor(const osgDB::FilePathList& pathList) :
@@ -191,5 +201,127 @@ void UserDataCopyVisitor::apply(Node& node)
     node.traverse(*this);
 }
 
+namespace
+{
+class MakeEffectVisitor : public SplicingVisitor
+{
+public:
+    typedef std::map<string, SGPropertyNode_ptr> EffectMap;
+    using SplicingVisitor::apply;
+    MakeEffectVisitor(const osgDB::ReaderWriter::Options* options = 0)
+        : _options(options)
+    {
+    }
+    virtual void apply(osg::Node& node);
+    virtual void apply(osg::Geode& geode);
+    EffectMap& getEffectMap() { return _effectMap; }
+    const EffectMap& getEffectMap() const { return _effectMap; }
+    void setDefaultEffect(SGPropertyNode* effect)
+    {
+        _currentEffectParent = effect;
+    }
+    SGPropertyNode* getDefaultEffect() { return _currentEffectParent; }
+protected:
+    EffectMap _effectMap;
+    SGPropertyNode_ptr _currentEffectParent;
+    osg::ref_ptr<const osgDB::ReaderWriter::Options> _options;
+};
+
+void MakeEffectVisitor::apply(osg::Node& node)
+{
+    SGPropertyNode_ptr savedEffectRoot;
+    const string& nodeName = node.getName();
+    bool restoreEffect = false;
+    if (!nodeName.empty()) {
+        EffectMap::iterator eitr = _effectMap.find(nodeName);
+        if (eitr != _effectMap.end()) {
+            savedEffectRoot = _currentEffectParent;
+            _currentEffectParent = eitr->second;
+            restoreEffect = true;
+        }
+    }
+    SplicingVisitor::apply(node);
+    if (restoreEffect)
+        _currentEffectParent = savedEffectRoot;
+}
+
+void MakeEffectVisitor::apply(osg::Geode& geode)
+{
+    if (pushNode(getNewNode(geode)))
+        return;
+    osg::StateSet* ss = geode.getStateSet();
+    if (!ss) {
+        pushNode(&geode);
+        return;
+    }
+    SGPropertyNode_ptr ssRoot = new SGPropertyNode;
+    makeParametersFromStateSet(ssRoot, ss);
+    SGPropertyNode_ptr effectRoot = new SGPropertyNode;
+    effect::mergePropertyTrees(effectRoot, ssRoot, _currentEffectParent);
+    Effect* effect = makeEffect(effectRoot, true, _options);
+    EffectGeode* eg = dynamic_cast<EffectGeode*>(&geode);
+    if (eg) {
+        eg->setEffect(effect);
+    } else {
+        eg = new EffectGeode;
+        eg->setEffect(effect);
+        for (int i = 0; i < geode.getNumDrawables(); ++i)
+            eg->addDrawable(geode.getDrawable(i));
+    }
+    pushResultNode(&geode, eg);
+
+}
+
+}
+
+namespace
+{
+class DefaultEffect : public simgear::Singleton<DefaultEffect>
+{
+public:
+    DefaultEffect()
+    {
+        _effect = new SGPropertyNode;
+        makeChild(_effect.ptr(), "inherits-from")
+            ->setStringValue("Effects/model-default");
+    }
+    virtual ~DefaultEffect() {}
+    SGPropertyNode* getEffect() { return _effect.ptr(); }
+protected:
+    SGPropertyNode_ptr _effect;
+};
+}
+
+ref_ptr<Node> instantiateEffects(osg::Node* modelGroup,
+                                 PropertyList& effectProps,
+                                 const osgDB::ReaderWriter::Options* options)
+{
+    SGPropertyNode_ptr defaultEffectPropRoot;
+    MakeEffectVisitor visitor(options);
+    MakeEffectVisitor::EffectMap& emap = visitor.getEffectMap();
+    for (PropertyList::iterator itr = effectProps.begin(),
+             end = effectProps.end();
+         itr != end;
+        ++itr)
+    {
+        SGPropertyNode_ptr configNode = *itr;
+        std::vector<SGPropertyNode_ptr> objectNames =
+            configNode->getChildren("object-name");
+        SGPropertyNode* defaultNode = configNode->getChild("default");
+        if (defaultNode && defaultNode->getValue<bool>())
+            defaultEffectPropRoot = configNode;
+        BOOST_FOREACH(SGPropertyNode_ptr objNameNode, objectNames) {
+            emap.insert(make_pair(objNameNode->getStringValue(), configNode));
+        }
+        configNode->removeChild("default");
+        configNode->removeChildren("object-name");
+    }
+    if (!defaultEffectPropRoot)
+        defaultEffectPropRoot = DefaultEffect::instance()->getEffect();
+    visitor.setDefaultEffect(defaultEffectPropRoot.ptr());
+    modelGroup->accept(visitor);
+    osg::NodeList& result = visitor.getResults();
+    return ref_ptr<Node>(result[0].get());
+}
 }
 // end of model.cxx
index 238b385c7fff73f6dbf8edce4e31009d171b558b..49dc0666e1307ee9245ab0e4f93bde30c9624915 100644 (file)
@@ -20,6 +20,7 @@
 #include <osgDB/ReaderWriter>
 
 #include <simgear/misc/sg_path.hxx>
+#include <simgear/props/props.hxx>
 #include <simgear/scene/util/NodeAndDrawableVisitor.hxx>
 
 osg::Texture2D*
@@ -86,5 +87,33 @@ public:
     virtual void apply(osg::Node& node);
 };
 
+/**
+ * Transform an OSG subgraph by substituting Effects and EffectGeodes
+ * for osg::Geodes with osg::StateSets. This is only guaranteed to
+ * work for models prouced by the .ac loader.
+ *
+ * returns a copy if any nodes are changed
+ */
+osg::ref_ptr<osg::Node>
+instantiateEffects(osg::Node* model,
+                   PropertyList& effectProps,
+                   const osgDB::ReaderWriter::Options* options);
+
+/**
+ * Transform an OSG subgraph by substituting the Effects and
+ * EffectGeodes for osg::Geodes with osg::StateSets, inheriting from
+ * the default model effect. This is only guaranteed to work for
+ * models prouced by the .ac loader.
+ *
+ * returns a copy if any nodes are changed
+ */
+
+inline osg::ref_ptr<osg::Node>
+instantiateEffects(osg::Node* model,
+                   const osgDB::ReaderWriter::Options* options)
+{
+    PropertyList effectProps;
+    return instantiateEffects(model, effectProps, options);
+}
 }
 #endif // __MODEL_HXX
index a3a779fdff63c03c1e2291bc2773dc4d70d70052..6a13c516fdfbe5a10a15f870665d823a6be70535 100644 (file)
@@ -19,6 +19,8 @@
 #  include <simgear_config.h>
 #endif
 
+#include <boost/algorithm/string.hpp>
+
 #include <osgDB/ReadFile>
 #include <osgDB/WriteFile>
 #include <osgDB/Registry>
@@ -26,6 +28,7 @@
 #include <simgear/constants.h>
 #include <simgear/props/props.hxx>
 #include <simgear/props/props_io.hxx>
+#include <simgear/scene/model/model.hxx>
 #include <simgear/scene/model/ModelRegistry.hxx>
 
 #include "SGPagedLOD.hxx"
@@ -59,6 +62,21 @@ SGModelLib::~SGModelLib()
 {
 }
 
+namespace
+{
+osg::Node* loadFile(const string& path, osgDB::ReaderWriter::Options* options)
+{
+    using namespace osg;
+    using namespace osgDB;
+    ref_ptr<Node> model = readRefNodeFile(path, options);
+    if (!model)
+        return 0;
+    if (boost::iends_with(path, ".ac"))
+        model = instantiateEffects(model.get(), options);
+     return model.release();
+}
+}
+
 osg::Node*
 SGModelLib::loadModel(const string &path,
                        SGPropertyNode *prop_root,
@@ -67,7 +85,7 @@ SGModelLib::loadModel(const string &path,
     osg::ref_ptr<SGReaderWriterXMLOptions> opt = new SGReaderWriterXMLOptions(*(osgDB::Registry::instance()->getOptions()));
     opt->setPropRoot(prop_root);
     opt->setModelData(data);
-    osg::Node *n = readNodeFile(path, opt.get());
+    osg::Node *n = loadFile(path, opt.get());
     if (n && n->getName().empty())
         n->setName("Direct loaded model \"" + path + "\"");
     return n;
@@ -82,7 +100,7 @@ SGModelLib::loadModel(const string &path,
     osg::ref_ptr<SGReaderWriterXMLOptions> opt = new SGReaderWriterXMLOptions(*(osgDB::Registry::instance()->getOptions()));
     opt->setPropRoot(prop_root);
     opt->setLoadPanel(pf);
-    return readNodeFile(path, opt.get());
+    return loadFile(path, opt.get());
 }
 
 osg::Node*
diff --git a/simgear/scene/util/CopyOp.cxx b/simgear/scene/util/CopyOp.cxx
new file mode 100644 (file)
index 0000000..48a5bd0
--- /dev/null
@@ -0,0 +1,40 @@
+// CopyOp.cxx - Simgear CopyOp for copying our own classes
+//
+// Copyright (C) 2009  Tim Moore timoore@redhat.com
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA  02111-1307, USA.
+
+#include "CopyOp.hxx"
+
+#include <simgear/scene/material/Effect.hxx>
+#include <simgear/scene/material/Technique.hxx>
+
+namespace simgear
+{
+osg::Object* CopyOp::operator()(const osg::Object* obj) const
+{
+    if (dynamic_cast<const Effect*>(obj)
+        || dynamic_cast<const Technique*>(obj)) {
+        if (_flags & DEEP_COPY_STATESETS)
+            return obj->clone(*this);
+        else
+            return const_cast<osg::Object*>(obj);
+    }
+    else {
+        return osg::CopyOp::operator()(obj);
+    }
+}
+}
diff --git a/simgear/scene/util/CopyOp.hxx b/simgear/scene/util/CopyOp.hxx
new file mode 100644 (file)
index 0000000..891b5a0
--- /dev/null
@@ -0,0 +1,37 @@
+// CopyOp.hxx - Simgear CopyOp for copying our own classes
+//
+// Copyright (C) 2009  Tim Moore timoore@redhat.com
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library 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
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA  02111-1307, USA.
+
+#ifndef SIMGEAR_COPYOP_HXX
+#define SIMGEAR_COPYOP_HXX 1
+#include <osg/CopyOp>
+
+namespace simgear
+{
+class CopyOp : public osg::CopyOp
+{
+public:
+    CopyOp(osg::CopyOp::CopyFlags flags = osg::CopyOp::SHALLOW_COPY)
+        : osg::CopyOp(flags)
+    {
+    }
+    using osg::CopyOp::operator();
+    virtual osg::Object* operator()(const osg::Object* obj) const;
+};
+}
+#endif
index 8ac69565a6e7f93f131db81e0353b038e31a0445..d8ca92ad1ec9630341a194375d6d356002c1ae17 100644 (file)
@@ -14,6 +14,7 @@ include_HEADERS = \
        SGStateAttributeVisitor.hxx \
        SGTextureStateAttributeVisitor.hxx \
        SGUpdateVisitor.hxx \
+       CopyOp.hxx \
        NodeAndDrawableVisitor.hxx \
        PrimitiveUtils.hxx \
        QuadTreeBuilder.hxx \
@@ -29,6 +30,7 @@ libsgutil_a_SOURCES = \
        SGSceneUserData.cxx \
        SGStateAttributeVisitor.cxx \
        SGTextureStateAttributeVisitor.cxx \
+       CopyOp.cxx \
        NodeAndDrawableVisitor.cxx \
        PrimitiveUtils.cxx \
        SplicingVisitor.cxx \