X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Fmaterial%2FEffectBuilder.hxx;h=be4b03452d035e0e89ff8b592bbf78fae61244f5;hb=a050654b4cac8c4813bddfc6e376730339b678b7;hp=4b2ebad3eb029791deceb23f1f43b672e3bd31ca;hpb=cb07210bc7e61fe0a45836c4e614a0e43cfb33d1;p=simgear.git diff --git a/simgear/scene/material/EffectBuilder.hxx b/simgear/scene/material/EffectBuilder.hxx index 4b2ebad3..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. */ @@ -149,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) { @@ -205,14 +234,13 @@ const SGPropertyNode* getEffectPropertyChild(Effect* effect, const SGPropertyNode* prop, const char* name); -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(); -}; +/** + * 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 { @@ -238,7 +266,7 @@ public: else return itr->second.ptr(); } - template friend class InstallAttributeBuilder; + template friend struct InstallAttributeBuilder; }; template @@ -257,5 +285,190 @@ struct InstallAttributeBuilder // 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