X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=simgear%2Fscene%2Fmaterial%2FEffectBuilder.hxx;h=52e2cf1c98614a2e0c4dee3ea65ff3bf679d7584;hb=f33ad357e928b5210c87cb8977d3cc88deba811b;hp=833ff515a7844cf14c11181081fa2fc94a8ee7d9;hpb=11479cd8c386d8bf7e1fee7bed60ab4abefc5fad;p=simgear.git diff --git a/simgear/scene/material/EffectBuilder.hxx b/simgear/scene/material/EffectBuilder.hxx index 833ff515..52e2cf1c 100644 --- a/simgear/scene/material/EffectBuilder.hxx +++ b/simgear/scene/material/EffectBuilder.hxx @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -30,9 +31,9 @@ #include #include -#include #include #include +#include #include #include #include @@ -46,6 +47,7 @@ namespace simgear { class Effect; class Pass; +class SGReaderWriterOptions; /** * Builder that returns an object, probably an OSG object. @@ -55,16 +57,16 @@ class EffectBuilder : public SGReferenced { public: virtual ~EffectBuilder() {} - virtual T* build(Effect* effect, const SGPropertyNode*, - const osgDB::ReaderWriter::Options* options) = 0; - static T* buildFromType(Effect* effect, const std::string& type, + virtual T* build(Effect* effect, Pass* pass, const SGPropertyNode*, + const SGReaderWriterOptions* options) = 0; + static T* buildFromType(Effect* effect, Pass* pass, const std::string& type, const SGPropertyNode*props, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterOptions* options) { BuilderMap& builderMap = getMap(); typename BuilderMap::iterator iter = builderMap.find(type); if (iter != builderMap.end()) - return iter->second->build(effect, props, options); + return iter->second->build(effect, pass, props, options); else return 0; } @@ -119,13 +121,20 @@ struct EffectNameValue template struct bidirectional_map { +#if _MSC_VER >= 1600 + struct value_type { + FromType first; + ToType second; + value_type(FromType f, ToType s) : first(f),second(s){} + }; +#else typedef std::pair value_type; +#endif /* A bidirectional map can be simulated as a multi_index_container * of pairs of (FromType,ToType) with two unique indices, one * for each member of the pair. */ - typedef multi_index_container< value_type, indexed_by< @@ -154,6 +163,21 @@ EffectPropertyMap::EffectPropertyMap(const EffectNameValue (&attrs)[N]) _map.insert(typename BMap::value_type(attrs[i].first, attrs[i].second)); } +// A one-way map that can be initialized using an array +template +struct SimplePropertyMap +{ + typedef std::map map_type; + map_type _map; + template + SimplePropertyMap(const EffectNameValue (&attrs)[N]) + { + for (int i = 0; i < N; ++i) + _map.insert(typename map_type::value_type(attrs[i].first, + attrs[i].second)); + } +}; + class BuilderException : public sg_exception { public: @@ -171,10 +195,10 @@ void findAttr(const effect::EffectPropertyMap& pMap, { using namespace effect; typename EffectPropertyMap::BMap::iterator itr - = pMap._map.get().find(name); + = pMap._map.template get().find(name); if (itr == pMap._map.end()) { - throw effect::BuilderException(string("findAttr: could not find attribute ") - + string(name)); + throw effect::BuilderException(std::string("findAttr: could not find attribute ") + + std::string(name)); } else { result = itr->second; } @@ -201,14 +225,50 @@ void findAttr(const effect::EffectPropertyMap& pMap, findAttr(pMap, name, result); } +// Versions that don't throw an error + +template +const T* findAttr(const effect::EffectPropertyMap& pMap, + const char* name) +{ + using namespace effect; + typename EffectPropertyMap::BMap::iterator itr + = pMap._map.template get().find(name); + if (itr == pMap._map.end()) + return 0; + else + return &itr->second; +} + +template +const T* findAttr(const effect::SimplePropertyMap& pMap, + const char* name) +{ + using namespace effect; + typename SimplePropertyMap::map_type::const_iterator itr + = pMap._map.find(name); + if (itr == pMap._map.end()) + return 0; + else + return &itr->second; +} + +template class Map> +const T* findAttr(const Map& pMap, + const std::string& name) +{ + return findAttr(pMap, name.c_str()); +} + + template std::string findName(const effect::EffectPropertyMap& pMap, T value) { using namespace effect; std::string result; typename EffectPropertyMap::BMap::template index_iterator::type itr - = pMap._map.get().find(value); - if (itr != pMap._map.get().end()) + = pMap._map.template get().find(value); + if (itr != pMap._map.template get().end()) result = itr->first; return result; } @@ -235,12 +295,50 @@ const SGPropertyNode* getEffectPropertyChild(Effect* effect, const char* name); /** - * Get the name of a node mentioned in a clause from the global property + * 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 + * @return empty if prop doesn't contain a \ clause; otherwise the * mentioned node name. */ -std::string getGlobalProperty(const SGPropertyNode* prop); +std::string getGlobalProperty(const SGPropertyNode* prop, + const SGReaderWriterOptions *); + +template +std::vector +getVectorProperties(const SGPropertyNode* prop, + const SGReaderWriterOptions *options, size_t vecSize, + NameItr defaultNames) +{ + using namespace std; + vector result; + if (!prop) + return result; + PropertyList useProps = prop->getChildren("use"); + if (useProps.size() == 1) { + string parentName = useProps[0]->getStringValue(); + if (parentName.empty() || parentName[0] != '/') + parentName = options->getPropertyNode()->getPath() + "/" + parentName; + if (parentName[parentName.size() - 1] != '/') + parentName.append("/"); + NameItr itr = defaultNames; + for (size_t i = 0; i < vecSize; ++i, ++itr) + result.push_back(parentName + *itr); + } else if (useProps.size() == vecSize) { + string parentName = useProps[0]->getStringValue(); + parentName += "/"; + for (PropertyList::const_iterator itr = useProps.begin(), + end = useProps.end(); + itr != end; + ++itr) { + string childName = (*itr)->getStringValue(); + if (childName.empty() || childName[0] != '/') + result.push_back(parentName + childName); + else + result.push_back(childName); + } + } + return result; +} class PassAttributeBuilder : public SGReferenced { @@ -251,11 +349,14 @@ protected: struct PassAttrMapSingleton : public simgear::Singleton { PassAttrMap passAttrMap; + }; public: + virtual ~PassAttributeBuilder(); // anchor into the compilation unit. + virtual void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterOptions* options) = 0; static PassAttributeBuilder* find(const std::string& str) { @@ -266,13 +367,13 @@ public: else return itr->second.ptr(); } - template friend class InstallAttributeBuilder; + template friend struct InstallAttributeBuilder; }; template struct InstallAttributeBuilder { - InstallAttributeBuilder(const string& name) + InstallAttributeBuilder(const std::string& name) { PassAttributeBuilder::PassAttrMapSingleton::instance() ->passAttrMap.insert(make_pair(name, new T)); @@ -289,90 +390,144 @@ bool isAttributeActive(Effect* effect, const SGPropertyNode* prop); namespace effect { /** - * Bridge between types stored in properties and what OSG wants. + * Bridge between types stored in properties and what OSG or the + * effects code want. + */ +template struct Bridge; + +/** + * Default just passes on the same type. + * */ -template struct OSGBridge; +template +struct Bridge +{ + typedef T sg_type; + static T get(const T& val) { return val; } +}; template -struct OSGBridge : public OSGBridge +struct Bridge : public Bridge { }; +// Save some typing... +template +struct BridgeOSGVec +{ + typedef InType sg_type; + static OutType get(const InType& val) { return toOsg(val); } +}; template<> -struct OSGBridge +struct Bridge : public BridgeOSGVec { - typedef SGVec3d sg_type; - static osg::Vec3f getOsgType(const SGVec3d& val) { return toOsg(val); } }; template<> -struct OSGBridge +struct Bridge : public BridgeOSGVec { - typedef SGVec3d sg_type; - static osg::Vec3d getOsgType(const SGVec3d& val) { return toOsg(val); } }; template<> -struct OSGBridge +struct Bridge : public BridgeOSGVec { - typedef SGVec4d sg_type; - static osg::Vec4f getOsgType(const SGVec4d& val) { return toOsg(val); } }; template<> -struct OSGBridge +struct Bridge : public BridgeOSGVec { - typedef SGVec4d sg_type; - static osg::Vec4d getOsgType(const SGVec4d& val) { return toOsg(val); } }; -template -struct OSGFunctor : public OSGBridge +/** + * Functor for calling a function on an osg::Referenced object and a + * value (e.g., an SGVec4d from a property) which will be converted to + * the equivalent OSG type. + * + * General version, function takes obj, val + */ +template +struct OSGFunctor : public Bridge { - OSGFunctor(Obj* obj, void (Obj::*func)(const OSGParam&)) + OSGFunctor(Obj* obj, const Func& func) : _obj(obj), _func(func) {} - void operator()(const typename OSGBridge::sg_type& val) const + void operator()(const typename Bridge::sg_type& val) const { - ((_obj.get())->*_func)(this->getOsgType(val)); + _func(_obj, this->get(val)); } osg::ref_ptr_obj; - void (Obj::*_func)(const OSGParam&); + const Func _func; }; -template +/** + * Version which uses a pointer to member function instead. + */ +template +struct OSGFunctor + : public Bridge +{ + typedef void (Obj::*const MemFunc)(const OSGParam&); + OSGFunctor(Obj* obj, MemFunc func) + : _obj(obj), _func(func) {} + void operator()(const typename Bridge::sg_type& val) const + { + (_obj->*_func)(this->get(val)); + } + osg::ref_ptr_obj; + MemFunc _func; +}; + +/** + * Typical convenience constructors + */ +template +OSGFunctor make_OSGFunctor(Obj* obj, const Func& func) +{ + return OSGFunctor(obj, func); +} + +template +OSGFunctor +make_OSGFunctor(Obj* obj, void (Obj::*const func)(const OSGParam&)) +{ + return OSGFunctor(obj, func); +} + +template class ScalarChangeListener : public SGPropertyChangeListener, public InitializeWhenAdded, + public PropertyPoller, public Effect::Updater { public: - typedef void (ObjType::*setter_type)(const OSGParamType); - ScalarChangeListener(ObjType* obj, setter_type setter, + ScalarChangeListener(ObjType* obj, const F& setter, const std::string& propName) - : _obj(obj), _setter(setter) + : _obj(obj), _setter(setter), _propName(propName) { - _propName = new std::string(propName); } virtual ~ScalarChangeListener() { - delete _propName; - _propName = 0; } void valueChanged(SGPropertyNode* node) { - _obj->*setter(node->getValue()); + _setter(_obj.get(), node->getValue()); } void initOnAddImpl(Effect* effect, SGPropertyNode* propRoot) { - SGPropertyNode* listenProp = makeNode(propRoot, *_propName); - delete _propName; - _propName = 0; - if (listenProp) - listenProp->addChangeListener(this, true); + _listenProp = makeNode(propRoot, _propName); +// if ( _listenProp.valid() ) +// _listenProp->addChangeListener(this, true); + } + void pollProperties(Effect* effect) + { + if( false == _listenProp.valid() ) return; + valueChanged(_listenProp); } private: + SGPropertyNode_ptr _listenProp; osg::ref_ptr _obj; - setter_type _setter; - std::string* _propName; + F _setter; + std::string _propName; }; template @@ -382,11 +537,12 @@ class EffectExtendedPropListener : public InitializeWhenAdded, public: template EffectExtendedPropListener(const Func& func, - const std::string& propName, Itr childNamesBegin, + const std::string* propName, Itr childNamesBegin, Itr childNamesEnd) - : _func(func) + : _propName(0), _func(func) { - _propName = new std::string(propName); + if (propName) + _propName = new std::string(*propName); _childNames = new std::vector(childNamesBegin, childNamesEnd); } @@ -397,7 +553,11 @@ public: } void initOnAddImpl(Effect* effect, SGPropertyNode* propRoot) { - SGPropertyNode* parent = propRoot->getNode(*_propName, true); + SGPropertyNode* parent = 0; + if (_propName) + parent = propRoot->getNode(*_propName, true); + else + parent = propRoot; _propListener = new ExtendedPropListener(parent, _childNames->begin(), _childNames->end(), @@ -414,60 +574,129 @@ private: Func _func; }; +template +Effect::Updater* +new_EEPropListener(const Func& func, const std::string* propName, + const Itr& namesBegin, const Itr& namesEnd) +{ + return new EffectExtendedPropListener + (func, 0, namesBegin, namesEnd); +} + +/** + * Set DYNAMIC data variance on an osg::Object. + */ + +inline void setDynamicVariance(void* obj) +{ +} + +inline void setDynamicVariance(osg::Object* obj) +{ + obj->setDataVariance(osg::Object::DYNAMIC); +} + /** * 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 + * 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; + * own \ tag referring to a property in the global property tree; * install a change listener that will set the attribute when the * property changes. + * + * For relative property names, the property root found in options is + * used. */ -template +template void initFromParameters(Effect* effect, const SGPropertyNode* prop, ObjType* obj, - void (ObjType::*setter)(const OSGParamType)) + const F& setter, const SGReaderWriterOptions* options) { const SGPropertyNode* valProp = getEffectPropertyNode(effect, prop); if (!valProp) return; if (valProp->nChildren() == 0) { - obj->*setter(valProp->getValue()); + setter(obj, valProp->getValue()); } else { - std::string propName = getGlobalProperty(prop); - ScalarChangeListener* listener - = new ScalarChangeListener(obj, setter, - propName); + setDynamicVariance(obj); + std::string propName = getGlobalProperty(valProp, options); + ScalarChangeListener* listener + = new ScalarChangeListener(obj, setter, + propName); effect->addUpdater(listener); } } -template +template +inline void +initFromParameters(Effect* effect, const SGPropertyNode* prop, ObjType* obj, + SetterReturn (ObjType::*setter)(const OSGParamType), + const SGReaderWriterOptions* options) +{ + initFromParameters(effect, prop, obj, + boost::bind(setter, _1, _2), options); +} + +/* + * Initialize vector parameters from individual properties. + * The parameter may be updated at runtime. + * + * 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 one or several + * \ tags. If there is one tag, it is a property that is the root + * for the values needed to update the parameter; nameIter holds the + * names of the properties relative to the root. If there are several + * \ tags, they each hold the name of the property holding the + * value for the corresponding vector member. + * + * Install a change listener that will set the attribute when the + * property changes. + * + * For relative property names, the property root found in options is + * used. + */ +template void initFromParameters(Effect* effect, const SGPropertyNode* prop, ObjType* obj, - void (ObjType::*setter)(const OSGParamType&), - NameItrType nameItr) + const F& setter, + NameItrType nameItr, const SGReaderWriterOptions* options) { - typedef typename OSGBridge::sg_type sg_type; + typedef typename Bridge::sg_type sg_type; + const int numComponents = props::NumComponents::num_components; const SGPropertyNode* valProp = getEffectPropertyNode(effect, prop); if (!valProp) return; - if (valProp->nChildren() == 0) { - (obj->*setter)(OSGBridge - ::getOsgType(valProp->getValue())); + if (valProp->nChildren() == 0) { // Has ? + setter(obj, Bridge::get(valProp->getValue())); } else { - string listenPropName = getGlobalProperty(valProp); - if (listenPropName.empty()) - return; - typedef OSGFunctor Functor; + setDynamicVariance(obj); + std::vector paramNames + = getVectorProperties(valProp, options,numComponents, nameItr); + if (paramNames.empty()) + throw BuilderException(); + std::vector::const_iterator pitr = paramNames.begin(); Effect::Updater* listener - = new EffectExtendedPropListener - (Functor(obj, setter), listenPropName, nameItr, - nameItr + props::NumComponents::num_components); + = new_EEPropListener(make_OSGFunctor + (obj, setter), + 0, pitr, pitr + numComponents); effect->addUpdater(listener); } } +template +inline void +initFromParameters(Effect* effect, const SGPropertyNode* prop, ObjType* obj, + SetterReturn (ObjType::*setter)(const OSGParamType&), + NameItrType nameItr, const SGReaderWriterOptions* options) +{ + initFromParameters(effect, prop, obj, + boost::bind(setter, _1, _2), nameItr, + options); +} extern const char* colorFields[]; } }