X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Fmaterial%2FEffectBuilder.hxx;h=be4b03452d035e0e89ff8b592bbf78fae61244f5;hb=a050654b4cac8c4813bddfc6e376730339b678b7;hp=e263f6efb2fb01f3a8188fc56d0a0ae452370935;hpb=6db9138eeb183d8ad00f0ccaf6a4e6ecb49e0197;p=simgear.git diff --git a/simgear/scene/material/EffectBuilder.hxx b/simgear/scene/material/EffectBuilder.hxx index e263f6ef..be4b0345 100644 --- a/simgear/scene/material/EffectBuilder.hxx +++ b/simgear/scene/material/EffectBuilder.hxx @@ -18,21 +18,26 @@ #define SIMGEAR_EFFECTBUILDER_HXX 1 #include +#include #include #include #include #include +#include #include #include #include +#include +#include #include #include #include #include +#include "Effect.hxx" /** * Support classes for parsing effects. */ @@ -40,6 +45,7 @@ namespace simgear { class Effect; +class Pass; /** * Builder that returns an object, probably an OSG object. @@ -148,29 +154,53 @@ EffectPropertyMap::EffectPropertyMap(const EffectNameValue (&attrs)[N]) _map.insert(typename BMap::value_type(attrs[i].first, attrs[i].second)); } +class BuilderException : public sg_exception +{ +public: + BuilderException(); + BuilderException(const char* message, const char* origin = 0); + BuilderException(const std::string& message, const std::string& = ""); + virtual ~BuilderException() throw(); +}; } template -bool findAttr(const effect::EffectPropertyMap& pMap, - const SGPropertyNode* prop, +void findAttr(const effect::EffectPropertyMap& pMap, + const char* name, T& result) { using namespace effect; - if (!prop) - return false; - const char* name = prop->getStringValue(); - if (!name) - return false; typename EffectPropertyMap::BMap::iterator itr = pMap._map.get().find(name); if (itr == pMap._map.end()) { - return false; + throw effect::BuilderException(string("findAttr: could not find attribute ") + + string(name)); } else { result = itr->second; - return true; } } +template +inline void findAttr(const effect::EffectPropertyMap& pMap, + const std::string& name, + T& result) +{ + findAttr(pMap, name.c_str(), result); +} + +template +void findAttr(const effect::EffectPropertyMap& pMap, + const SGPropertyNode* prop, + T& result) +{ + if (!prop) + throw effect::BuilderException("findAttr: empty property"); + const char* name = prop->getStringValue(); + if (!name) + throw effect::BuilderException("findAttr: no name for lookup"); + findAttr(pMap, name, result); +} + template std::string findName(const effect::EffectPropertyMap& pMap, T value) { @@ -204,13 +234,241 @@ const SGPropertyNode* getEffectPropertyChild(Effect* effect, const SGPropertyNode* prop, const char* name); -class BuilderException : public sg_exception +/** + * Get the name of a node mentioned in a clause from the global property + * tree. + * @return empty if prop doesn't contain a clause; otherwise the + * mentioned node name. + */ +std::string getGlobalProperty(const SGPropertyNode* prop); + +class PassAttributeBuilder : public SGReferenced { +protected: + typedef std::map > + PassAttrMap; + + struct PassAttrMapSingleton : public simgear::Singleton + { + PassAttrMap passAttrMap; + }; public: - BuilderException(); - BuilderException(const char* message, const char* origin = 0); - BuilderException(const std::string& message, const std::string& = ""); - virtual ~BuilderException() throw(); + virtual void buildAttribute(Effect* effect, Pass* pass, + const SGPropertyNode* prop, + const osgDB::ReaderWriter::Options* options) + = 0; + static PassAttributeBuilder* find(const std::string& str) + { + PassAttrMap::iterator itr + = PassAttrMapSingleton::instance()->passAttrMap.find(str); + if (itr == PassAttrMapSingleton::instance()->passAttrMap.end()) + return 0; + else + return itr->second.ptr(); + } + template friend struct InstallAttributeBuilder; +}; + +template +struct InstallAttributeBuilder +{ + InstallAttributeBuilder(const string& name) + { + PassAttributeBuilder::PassAttrMapSingleton::instance() + ->passAttrMap.insert(make_pair(name, new T)); + } +}; + +// 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); + +namespace effect +{ +/** + * Bridge between types stored in properties and what OSG wants. + */ +template struct OSGBridge; + +template +struct OSGBridge : public OSGBridge +{ +}; + +template<> +struct OSGBridge +{ + typedef SGVec3d sg_type; + static osg::Vec3f getOsgType(const SGVec3d& val) { return toOsg(val); } +}; + +template<> +struct OSGBridge +{ + typedef SGVec3d sg_type; + static osg::Vec3d getOsgType(const SGVec3d& val) { return toOsg(val); } +}; + +template<> +struct OSGBridge +{ + typedef SGVec4d sg_type; + static osg::Vec4f getOsgType(const SGVec4d& val) { return toOsg(val); } +}; + +template<> +struct OSGBridge +{ + typedef SGVec4d sg_type; + static osg::Vec4d getOsgType(const SGVec4d& val) { return toOsg(val); } }; + +template +struct OSGFunctor : public OSGBridge +{ + OSGFunctor(Obj* obj, void (Obj::*func)(const OSGParam&)) + : _obj(obj), _func(func) {} + void operator()(const typename OSGBridge::sg_type& val) const + { + ((_obj.get())->*_func)(this->getOsgType(val)); + } + osg::ref_ptr_obj; + void (Obj::*_func)(const OSGParam&); +}; + +template +class ScalarChangeListener + : public SGPropertyChangeListener, public InitializeWhenAdded, + public Effect::Updater +{ +public: + typedef void (ObjType::*setter_type)(const OSGParamType); + ScalarChangeListener(ObjType* obj, setter_type setter, + const std::string& propName) + : _obj(obj), _setter(setter) + { + _propName = new std::string(propName); + } + virtual ~ScalarChangeListener() + { + delete _propName; + _propName = 0; + } + void valueChanged(SGPropertyNode* node) + { + _obj->*setter(node->getValue()); + } + void initOnAddImpl(Effect* effect, SGPropertyNode* propRoot) + { + SGPropertyNode* listenProp = makeNode(propRoot, *_propName); + delete _propName; + _propName = 0; + if (listenProp) + listenProp->addChangeListener(this, true); + } +private: + osg::ref_ptr _obj; + setter_type _setter; + std::string* _propName; +}; + +template +class EffectExtendedPropListener : public InitializeWhenAdded, + public Effect::Updater +{ +public: + template + EffectExtendedPropListener(const Func& func, + const std::string& propName, Itr childNamesBegin, + Itr childNamesEnd) + : _func(func) + { + _propName = new std::string(propName); + _childNames = new std::vector(childNamesBegin, + childNamesEnd); + } + virtual ~EffectExtendedPropListener() + { + delete _propName; + delete _childNames; + } + void initOnAddImpl(Effect* effect, SGPropertyNode* propRoot) + { + SGPropertyNode* parent = propRoot->getNode(*_propName, true); + _propListener + = new ExtendedPropListener(parent, _childNames->begin(), + _childNames->end(), + _func, true); + delete _propName; + _propName = 0; + delete _childNames; + _childNames = 0; + } +private: + std::string* _propName; + std::vector* _childNames; + SGSharedPtr > _propListener; + Func _func; +}; + +/** + * Initialize the value and the possible updating of an effect + * attribute. If the value is specified directly, set it. Otherwise, + * use the tag to look at the parameters. Again, if there is a + * value there set it directly. Otherwise, the parameter contains its + * own tag referring to a property in the global property tree; + * install a change listener that will set the attribute when the + * property changes. + */ +template +void +initFromParameters(Effect* effect, const SGPropertyNode* prop, ObjType* obj, + void (ObjType::*setter)(const OSGParamType)) +{ + const SGPropertyNode* valProp = getEffectPropertyNode(effect, prop); + if (!valProp) + return; + if (valProp->nChildren() == 0) { + obj->*setter(valProp->getValue()); + } else { + std::string propName = getGlobalProperty(prop); + ScalarChangeListener* listener + = new ScalarChangeListener(obj, setter, + propName); + effect->addUpdater(listener); + } +} + +template +void +initFromParameters(Effect* effect, const SGPropertyNode* prop, ObjType* obj, + void (ObjType::*setter)(const OSGParamType&), + NameItrType nameItr) +{ + typedef typename OSGBridge::sg_type sg_type; + const SGPropertyNode* valProp = getEffectPropertyNode(effect, prop); + if (!valProp) + return; + if (valProp->nChildren() == 0) { + (obj->*setter)(OSGBridge + ::getOsgType(valProp->getValue())); + } else { + string listenPropName = getGlobalProperty(valProp); + if (listenPropName.empty()) + return; + typedef OSGFunctor Functor; + Effect::Updater* listener + = new EffectExtendedPropListener + (Functor(obj, setter), listenPropName, nameItr, + nameItr + props::NumComponents::num_components); + effect->addUpdater(listener); + } +} + +extern const char* colorFields[]; +} } #endif