From 3e57b5006664358c6f41757cf847901bdb0ec872 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Garc=C3=ADa=20Li=C3=B1=C3=A1n?= Date: Sat, 4 May 2019 19:15:22 +0200 Subject: [PATCH] Added support for Effect schemes Effect schemes are a way of rendering an object in different ways depending on the Compositor pipeline. A new tag in the Compositor pipeline definition allows the user to choose which Effect scheme is going to be used for that pass. Every Effect will then be rendered using the technique that has a matching scheme name. If no valid technique is found, it won't be rendered. Since it would be a pain to define a valid technique for every scheme and for every Effect, the file '$FG_ROOT/Effects/schemes.xml' is introduced: test Effects/test If an Effect doesn't have a valid technique for the 'test' scheme, the 'Effects/test.eff' Effect will be merged with it. This process is done at initialization when techniques are being realized. --- simgear/scene/material/Effect.cxx | 55 +++++++++++++++++++- simgear/scene/material/Effect.hxx | 2 +- simgear/scene/material/EffectCullVisitor.cxx | 20 +++---- simgear/scene/material/EffectCullVisitor.hxx | 4 +- simgear/scene/material/Technique.hxx | 3 ++ simgear/scene/viewer/Compositor.cxx | 2 +- simgear/scene/viewer/CompositorPass.cxx | 5 +- simgear/scene/viewer/CompositorPass.hxx | 3 +- 8 files changed, 69 insertions(+), 25 deletions(-) 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. */