diff --git a/simgear/scene/material/Effect.cxx b/simgear/scene/material/Effect.cxx index 72f5fba1..994adeab 100644 --- a/simgear/scene/material/Effect.cxx +++ b/simgear/scene/material/Effect.cxx @@ -77,6 +77,7 @@ #include #include #include +#include #include #include #include @@ -245,11 +246,12 @@ int Effect::getGenerator(Effect::Generator what) const // There should always be a valid technique in an effect. -Technique* Effect::chooseTechnique(RenderInfo* info) +Technique* Effect::chooseTechnique(RenderInfo* info, const std::string &scheme) { BOOST_FOREACH(ref_ptr& technique, techniques) { - if (technique->valid(info) == Technique::VALID) + if (technique->valid(info) == Technique::VALID && + technique->getScheme() == scheme) return technique.get(); } return 0; @@ -1308,6 +1310,7 @@ void buildTechnique(Effect* effect, const SGPropertyNode* prop, { Technique* tniq = new Technique; effect->techniques.push_back(tniq); + tniq->setScheme(prop->getStringValue("scheme")); const SGPropertyNode* predProp = prop->getChild("predicate"); if (!predProp) { tniq->setAlwaysValid(true); @@ -1411,12 +1414,60 @@ bool makeParametersFromStateSet(SGPropertyNode* effectRoot, const StateSet* ss) return true; } +SGPropertyNode_ptr schemeList; + +void mergeSchemesFallbacks(Effect *effect, const SGReaderWriterOptions *options) +{ + if (!schemeList) { + schemeList = new SGPropertyNode; + const string schemes_file("Effects/schemes.xml"); + string absFileName + = SGModelLib::findDataFile(schemes_file, options); + if (absFileName.empty()) { + SG_LOG(SG_INPUT, SG_ALERT, "Could not find '" << schemes_file << "'"); + return; + } + try { + readProperties(absFileName, schemeList, 0, true); + } catch (sg_io_exception& e) { + SG_LOG(SG_INPUT, SG_ALERT, "Error reading '" << schemes_file << + "': " << e.getFormattedMessage()); + return; + } + } + + PropertyList p_schemes = schemeList->getChildren("scheme"); + for (const auto &p_scheme : p_schemes) { + string scheme_name = p_scheme->getStringValue("name"); + string fallback_name = p_scheme->getStringValue("fallback"); + if (scheme_name.empty() || fallback_name.empty()) + continue; + vector techniques = effect->root->getChildren("technique"); + auto it = std::find_if(techniques.begin(), techniques.end(), + [&scheme_name](const SGPropertyNode_ptr &tniq) { + return tniq->getStringValue("scheme") == scheme_name; + }); + // Only merge the fallback effect if we haven't found a technique + // implementing the scheme + if (it == techniques.end()) { + ref_ptr fallback = makeEffect(fallback_name, false, options); + if (fallback) { + SGPropertyNode *new_root = new SGPropertyNode; + mergePropertyTrees(new_root, effect->root, fallback->root); + effect->root = new_root; + effect->parametersProp = effect->root->getChild("parameters"); + } + } + } +} + // Walk the techniques property tree, building techniques and // passes. static SGMutex realizeTechniques_lock; bool Effect::realizeTechniques(const SGReaderWriterOptions* options) { SGGuard g(realizeTechniques_lock); + mergeSchemesFallbacks(this, options); if (_isRealized) return true; diff --git a/simgear/scene/material/Effect.hxx b/simgear/scene/material/Effect.hxx index 56a84769..496805a2 100644 --- a/simgear/scene/material/Effect.hxx +++ b/simgear/scene/material/Effect.hxx @@ -92,7 +92,7 @@ public: SGPropertyNode_ptr root; // Pointer to the parameters node, if it exists SGPropertyNode_ptr parametersProp; - Technique* chooseTechnique(osg::RenderInfo* renderInfo); + Technique* chooseTechnique(osg::RenderInfo* renderInfo, const std::string &scheme); virtual void resizeGLObjectBuffers(unsigned int maxSize); virtual void releaseGLObjects(osg::State* state = 0) const; /** diff --git a/simgear/scene/material/EffectCullVisitor.cxx b/simgear/scene/material/EffectCullVisitor.cxx index a016a455..36c31653 100644 --- a/simgear/scene/material/EffectCullVisitor.cxx +++ b/simgear/scene/material/EffectCullVisitor.cxx @@ -34,9 +34,9 @@ namespace simgear using osgUtil::CullVisitor; -EffectCullVisitor::EffectCullVisitor(bool collectLights, Effect *effectOverride) : +EffectCullVisitor::EffectCullVisitor(bool collectLights, const std::string &effScheme) : _collectLights(collectLights), - _effectOverride(effectOverride) + _effScheme(effScheme) { } @@ -62,18 +62,12 @@ void EffectCullVisitor::apply(osg::Geode& node) if (_collectLights && ( eg->getNodeMask() & MODELLIGHT_BIT ) ) { _lightList.push_back( eg ); } - Effect *effect; - if (_effectOverride) { - effect = _effectOverride; - } else { - effect = eg->getEffect(); - if (!effect) { - CullVisitor::apply(node); - return; - } - } + Effect* effect = eg->getEffect(); Technique* technique = 0; - if (!(technique = effect->chooseTechnique(&getRenderInfo()))) { + if (!effect) { + CullVisitor::apply(node); + return; + } else if (!(technique = effect->chooseTechnique(&getRenderInfo(), _effScheme))) { return; } // push the node's state. diff --git a/simgear/scene/material/EffectCullVisitor.hxx b/simgear/scene/material/EffectCullVisitor.hxx index ef93baa3..340ce7c7 100644 --- a/simgear/scene/material/EffectCullVisitor.hxx +++ b/simgear/scene/material/EffectCullVisitor.hxx @@ -34,7 +34,7 @@ class EffectGeode; class EffectCullVisitor : public osgUtil::CullVisitor { public: - EffectCullVisitor(bool collectLights = false, Effect *effectOverride = 0); + EffectCullVisitor(bool collectLights = false, const std::string &effScheme = ""); EffectCullVisitor(const EffectCullVisitor&); virtual osgUtil::CullVisitor* clone() const; using osgUtil::CullVisitor::apply; @@ -49,7 +49,7 @@ private: std::map > _bufferList; std::vector > _lightList; bool _collectLights; - osg::ref_ptr _effectOverride; + std::string _effScheme; }; } #endif diff --git a/simgear/scene/material/Technique.hxx b/simgear/scene/material/Technique.hxx index b2895cd1..6cca0a05 100644 --- a/simgear/scene/material/Technique.hxx +++ b/simgear/scene/material/Technique.hxx @@ -98,6 +98,8 @@ public: void setGLExtensionsPred(float glVersion, const std::vector& extensions); void refreshValidity(); + const std::string &getScheme() const { return _scheme; } + void setScheme(const std::string &scheme) { _scheme = scheme; } protected: // Validity of technique in a graphics context. struct ContextInfo : public osg::Referenced @@ -117,6 +119,7 @@ protected: osg::ref_ptr _shadowingStateSet; SGSharedPtr _validExpression; int _contextIdLocation; + std::string _scheme; }; class TechniquePredParser : public expression::ExpressionParser diff --git a/simgear/scene/viewer/Compositor.cxx b/simgear/scene/viewer/Compositor.cxx index a86385b6..8d3bd9b7 100644 --- a/simgear/scene/viewer/Compositor.cxx +++ b/simgear/scene/viewer/Compositor.cxx @@ -274,7 +274,7 @@ Compositor::addPass(Pass *pass) identifier = sceneView->getCullVisitor()->getIdentifier(); sceneView->setCullVisitor( - new EffectCullVisitor(false, pass->effect_override)); + new EffectCullVisitor(false, pass->effect_scheme)); sceneView->getCullVisitor()->setIdentifier(identifier.get()); identifier = sceneView->getCullVisitorLeft()->getIdentifier(); diff --git a/simgear/scene/viewer/CompositorPass.cxx b/simgear/scene/viewer/CompositorPass.cxx index df28dfdf..939cc7b6 100644 --- a/simgear/scene/viewer/CompositorPass.cxx +++ b/simgear/scene/viewer/CompositorPass.cxx @@ -67,10 +67,7 @@ PassBuilder::build(Compositor *compositor, const SGPropertyNode *root, << " has no name. It won't be addressable by name!"); } pass->type = root->getStringValue("type"); - - std::string eff_override_file = root->getStringValue("effect-override"); - if (!eff_override_file.empty()) - pass->effect_override = makeEffect(eff_override_file, true, options); + pass->effect_scheme = root->getStringValue("effect-scheme"); osg::Camera *camera = new Camera; pass->camera = camera; diff --git a/simgear/scene/viewer/CompositorPass.hxx b/simgear/scene/viewer/CompositorPass.hxx index 09fe86f1..d8e26fa8 100644 --- a/simgear/scene/viewer/CompositorPass.hxx +++ b/simgear/scene/viewer/CompositorPass.hxx @@ -57,9 +57,8 @@ struct Pass : public osg::Referenced { int render_order; std::string name; std::string type; + std::string effect_scheme; osg::ref_ptr camera; - /** If null, there is no effect override for this pass. */ - osg::ref_ptr effect_override; bool useMastersSceneData; osg::Node::NodeMask cull_mask; /** Whether the cull mask is ANDed with the view master camera cull mask. */