From 3e40d624a81d3737a2cce7438c9b83852c087558 Mon Sep 17 00:00:00 2001 From: Tim Moore Date: Tue, 8 Sep 2009 13:09:05 +0200 Subject: [PATCH] Effects for models 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. --- projects/VC7.1/SimGear.vcproj | 6 + projects/VC90/SimGear.vcproj | 8 ++ simgear/scene/material/Effect.cxx | 98 ++++++++++---- simgear/scene/material/Effect.hxx | 10 ++ simgear/scene/material/EffectGeode.cxx | 6 +- simgear/scene/material/Technique.cxx | 14 +- simgear/scene/material/TextureBuilder.cxx | 18 ++- simgear/scene/material/makeEffect.cxx | 4 + simgear/scene/model/SGReaderWriterXML.cxx | 29 ++-- simgear/scene/model/model.cxx | 154 ++++++++++++++++++++-- simgear/scene/model/model.hxx | 29 ++++ simgear/scene/model/modellib.cxx | 22 +++- simgear/scene/util/CopyOp.cxx | 40 ++++++ simgear/scene/util/CopyOp.hxx | 37 ++++++ simgear/scene/util/Makefile.am | 2 + 15 files changed, 411 insertions(+), 66 deletions(-) create mode 100644 simgear/scene/util/CopyOp.cxx create mode 100644 simgear/scene/util/CopyOp.hxx diff --git a/projects/VC7.1/SimGear.vcproj b/projects/VC7.1/SimGear.vcproj index bc1a2b66..1139bc36 100755 --- a/projects/VC7.1/SimGear.vcproj +++ b/projects/VC7.1/SimGear.vcproj @@ -1171,6 +1171,12 @@ + + + + diff --git a/projects/VC90/SimGear.vcproj b/projects/VC90/SimGear.vcproj index eab43855..95d18ebb 100644 --- a/projects/VC90/SimGear.vcproj +++ b/projects/VC90/SimGear.vcproj @@ -1705,6 +1705,14 @@ + + + + diff --git a/simgear/scene/material/Effect.cxx b/simgear/scene/material/Effect.cxx index 2e682234..a94267fc 100644 --- a/simgear/scene/material/Effect.cxx +++ b/simgear/scene/material/Effect.cxx @@ -30,7 +30,6 @@ #include #include -#include #include #include #include @@ -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, _1, copyop)); + typedef vector > TechniqueList; + for (TechniqueList::const_iterator itr = rhs.techniques.begin(), + end = rhs.techniques.end(); + itr != end; + ++itr) + techniques.push_back(static_cast(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(); +} + struct LightingBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, @@ -265,6 +279,15 @@ struct CullFaceBuilder : PassAttributeBuilder InstallAttributeBuilder installCullFace("cull-face"); +EffectNameValue renderingHintInit[] = +{ + { "default", StateSet::DEFAULT_BIN }, + { "opaque", StateSet::OPAQUE_BIN }, + { "transparent", StateSet::TRANSPARENT_BIN } +}; + +EffectPropertyMap 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 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 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(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(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(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; diff --git a/simgear/scene/material/Effect.hxx b/simgear/scene/material/Effect.hxx index 2b3942fe..594d02eb 100644 --- a/simgear/scene/material/Effect.hxx +++ b/simgear/scene/material/Effect.hxx @@ -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 diff --git a/simgear/scene/material/EffectGeode.cxx b/simgear/scene/material/EffectGeode.cxx index 799b567c..949055b5 100644 --- a/simgear/scene/material/EffectGeode.cxx +++ b/simgear/scene/material/EffectGeode.cxx @@ -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(copyop(rhs._effect.get()))) { - _effect = static_cast(rhs._effect->clone(copyop)); } void EffectGeode::resizeGLObjectBuffers(unsigned int maxSize) diff --git a/simgear/scene/material/Technique.cxx b/simgear/scene/material/Technique.cxx index 4c1dbe16..4258b464 100644 --- a/simgear/scene/material/Technique.cxx +++ b/simgear/scene/material/Technique.cxx @@ -6,7 +6,6 @@ #include "Technique.hxx" #include "Pass.hxx" -#include #include #include @@ -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, _1, copyop)); - + for (std::vector >::const_iterator itr = rhs.passes.begin(), + end = rhs.passes.end(); + itr != end; + ++itr) + passes.push_back(static_cast(copyop(itr->get()))); } Technique::~Technique() diff --git a/simgear/scene/material/TextureBuilder.cxx b/simgear/scene/material/TextureBuilder.cxx index 9103fe59..2623c4a7 100644 --- a/simgear/scene/material/TextureBuilder.cxx +++ b/simgear/scene/material/TextureBuilder.cxx @@ -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(0, ss); const Texture2D* texture = dynamic_cast(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); diff --git a/simgear/scene/material/makeEffect.cxx b/simgear/scene/material/makeEffect.cxx index 786fc2f5..56bc1636 100644 --- a/simgear/scene/material/makeEffect.cxx +++ b/simgear/scene/material/makeEffect.cxx @@ -39,6 +39,7 @@ namespace simgear { using namespace std; using namespace osg; +using namespace effect; typedef vector RawPropVector; typedef map > 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, diff --git a/simgear/scene/model/SGReaderWriterXML.cxx b/simgear/scene/model/SGReaderWriterXML.cxx index 2a4d612e..c19d7e82 100644 --- a/simgear/scene/model/SGReaderWriterXML.cxx +++ b/simgear/scene/model/SGReaderWriterXML.cxx @@ -20,6 +20,7 @@ # include #endif +#include #include #include #include @@ -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 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 submodel_final=submodel.get(); + osg::ref_ptr 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 modelWithEffects + = instantiateEffects(group.get(), effect_nodes, options.get()); + group = static_cast(modelWithEffects.get()); + } std::vector animation_nodes; animation_nodes = props->getChildren("animation"); for (unsigned i = 0; i < animation_nodes.size(); ++i) diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index 5672ece6..b9d0d89e 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -9,6 +9,8 @@ #include +#include + #include #include #include @@ -16,10 +18,16 @@ #include #include +#include +#include #include #include +#include +#include + #include +#include #include #include #include @@ -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(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 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 _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(&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 +{ +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 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 objectNames = + configNode->getChildren("object-name"); + SGPropertyNode* defaultNode = configNode->getChild("default"); + if (defaultNode && defaultNode->getValue()) + 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(result[0].get()); +} } // end of model.cxx diff --git a/simgear/scene/model/model.hxx b/simgear/scene/model/model.hxx index 238b385c..49dc0666 100644 --- a/simgear/scene/model/model.hxx +++ b/simgear/scene/model/model.hxx @@ -20,6 +20,7 @@ #include #include +#include #include 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 +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 +instantiateEffects(osg::Node* model, + const osgDB::ReaderWriter::Options* options) +{ + PropertyList effectProps; + return instantiateEffects(model, effectProps, options); +} } #endif // __MODEL_HXX diff --git a/simgear/scene/model/modellib.cxx b/simgear/scene/model/modellib.cxx index a3a779fd..6a13c516 100644 --- a/simgear/scene/model/modellib.cxx +++ b/simgear/scene/model/modellib.cxx @@ -19,6 +19,8 @@ # include #endif +#include + #include #include #include @@ -26,6 +28,7 @@ #include #include #include +#include #include #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 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 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 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 index 00000000..48a5bd0d --- /dev/null +++ b/simgear/scene/util/CopyOp.cxx @@ -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 +#include + +namespace simgear +{ +osg::Object* CopyOp::operator()(const osg::Object* obj) const +{ + if (dynamic_cast(obj) + || dynamic_cast(obj)) { + if (_flags & DEEP_COPY_STATESETS) + return obj->clone(*this); + else + return const_cast(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 index 00000000..891b5a08 --- /dev/null +++ b/simgear/scene/util/CopyOp.hxx @@ -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 + +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 diff --git a/simgear/scene/util/Makefile.am b/simgear/scene/util/Makefile.am index 8ac69565..d8ca92ad 100644 --- a/simgear/scene/util/Makefile.am +++ b/simgear/scene/util/Makefile.am @@ -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 \ -- 2.39.5