diff --git a/simgear/props/props.cxx b/simgear/props/props.cxx index c662eb7f..acbcc92d 100644 --- a/simgear/props/props.cxx +++ b/simgear/props/props.cxx @@ -1027,17 +1027,22 @@ SGPropertyNode::getDisplayName (bool simplify) const } -const char * +string SGPropertyNode::getPath (bool simplify) const { - // Calculate the complete path only once. - if (_parent != 0 && _path.empty()) { - _path = _parent->getPath(simplify); - _path += '/'; - _path += getDisplayName(simplify); + typedef std::vector PList; + PList pathList; + for (const SGPropertyNode* node = this; node->_parent; node = node->_parent) + pathList.push_back(node); + string result; + for (PList::reverse_iterator itr = pathList.rbegin(), + rend = pathList.rend(); + itr != rend; + ++itr) { + result += '/'; + result += (*itr)->getDisplayName(simplify); } - - return _path.c_str(); + return result; } props::Type diff --git a/simgear/props/props.hxx b/simgear/props/props.hxx index 984bb1b5..b9ba6495 100644 --- a/simgear/props/props.hxx +++ b/simgear/props/props.hxx @@ -994,7 +994,7 @@ public: /** * Get the path to this node from the root. */ - const char * getPath (bool simplify = false) const; + std::string getPath (bool simplify = false) const; /** @@ -1675,7 +1675,6 @@ private: simgear::PropertyList _children; simgear::PropertyList _removedChildren; std::vector _linkedNodes; - mutable std::string _path; mutable std::string _buffer; hash_table * _path_cache; simgear::props::Type _type; diff --git a/simgear/scene/material/Effect.cxx b/simgear/scene/material/Effect.cxx index 9da202f7..400e350a 100644 --- a/simgear/scene/material/Effect.cxx +++ b/simgear/scene/material/Effect.cxx @@ -66,6 +66,7 @@ #include #include +#include #include #include #include @@ -143,7 +144,7 @@ Effect::~Effect() } void buildPass(Effect* effect, Technique* tniq, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { Pass* pass = new Pass; tniq->passes.push_back(pass); @@ -159,6 +160,10 @@ void buildPass(Effect* effect, Technique* tniq, const SGPropertyNode* prop, } } +// Default names for vector property components +const char* vec3Names[] = {"x", "y", "z"}; +const char* vec4Names[] = {"x", "y", "z", "w"}; + osg::Vec4f getColor(const SGPropertyNode* prop) { if (prop->nChildren() == 0) { @@ -188,12 +193,12 @@ osg::Vec4f getColor(const SGPropertyNode* prop) struct LightingBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterXMLOptions* options); }; void LightingBuilder::buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); if (!realProp) @@ -207,7 +212,7 @@ InstallAttributeBuilder installLighting("lighting"); struct ShadeModelBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); if (!realProp) @@ -229,7 +234,7 @@ InstallAttributeBuilder installShadeModel("shade-model"); struct CullFaceBuilder : PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); if (!realProp) { @@ -257,7 +262,7 @@ InstallAttributeBuilder installCullFace("cull-face"); struct ColorMaskBuilder : PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); if (!realProp) @@ -284,7 +289,7 @@ EffectPropertyMap renderingHints(renderingHintInit); struct HintBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); if (!realProp) @@ -300,7 +305,7 @@ InstallAttributeBuilder installHint("rendering-hint"); struct RenderBinBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, prop)) return; @@ -327,7 +332,7 @@ InstallAttributeBuilder installRenderBin("render-bin"); struct MaterialBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterXMLOptions* options); }; EffectNameValue colorModeInit[] = @@ -343,7 +348,7 @@ EffectPropertyMap colorModes(colorModeInit); void MaterialBuilder::buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, prop)) return; @@ -413,7 +418,7 @@ EffectPropertyMap blendFuncModes(blendFuncModesInit); struct BlendBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, prop)) return; @@ -526,7 +531,7 @@ EffectPropertyMap stencilOperation(stencilOperationInit); struct StencilBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, prop)) return; @@ -604,7 +609,7 @@ alphaComparison(alphaComparisonInit); struct AlphaTestBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, prop)) return; @@ -715,12 +720,12 @@ void reload_shaders() struct ShaderProgramBuilder : PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterXMLOptions* options); }; void ShaderProgramBuilder::buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* + const SGReaderWriterXMLOptions* options) { using namespace boost; @@ -807,15 +812,18 @@ EffectNameValue uniformTypesInit[] = {"float-vec3", Uniform::FLOAT_VEC3}, {"float-vec4", Uniform::FLOAT_VEC4}, {"sampler-1d", Uniform::SAMPLER_1D}, + {"sampler-1d-shadow", Uniform::SAMPLER_1D_SHADOW}, {"sampler-2d", Uniform::SAMPLER_2D}, - {"sampler-3d", Uniform::SAMPLER_3D} + {"sampler-2d-shadow", Uniform::SAMPLER_2D_SHADOW}, + {"sampler-3d", Uniform::SAMPLER_3D}, + {"sampler-cube", Uniform::SAMPLER_CUBE} }; EffectPropertyMap uniformTypes(uniformTypesInit); struct UniformBuilder :public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, prop)) return; @@ -861,18 +869,29 @@ struct UniformBuilder :public PassAttributeBuilder uniform->setType(uniformType); switch (uniformType) { case Uniform::FLOAT: - uniform->set(valProp->getValue()); + initFromParameters(effect, valProp, uniform.get(), + static_cast(&Uniform::set), + options); break; case Uniform::FLOAT_VEC3: - uniform->set(toOsg(valProp->getValue())); + initFromParameters(effect, valProp, uniform.get(), + static_cast(&Uniform::set), + vec3Names, options); break; case Uniform::FLOAT_VEC4: - uniform->set(toOsg(valProp->getValue())); + initFromParameters(effect, valProp, uniform.get(), + static_cast(&Uniform::set), + vec4Names, options); break; case Uniform::SAMPLER_1D: case Uniform::SAMPLER_2D: case Uniform::SAMPLER_3D: - uniform->set(valProp->getValue()); + case Uniform::SAMPLER_1D_SHADOW: + case Uniform::SAMPLER_2D_SHADOW: + case Uniform::SAMPLER_CUBE: + initFromParameters(effect, valProp, uniform.get(), + static_cast(&Uniform::set), + options); break; default: // avoid compiler warning break; @@ -889,7 +908,7 @@ InstallAttributeBuilder installUniform("uniform"); struct NameBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { // name can't use string name = prop->getStringValue(); @@ -911,7 +930,7 @@ EffectPropertyMap polygonModeModes(polygonModeModesInit); struct PolygonModeBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, prop)) return; @@ -939,7 +958,7 @@ InstallAttributeBuilder installPolygonMode("polygon-mode"); struct VertexProgramTwoSideBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); if (!realProp) @@ -956,7 +975,7 @@ installTwoSide("vertex-program-two-side"); struct VertexProgramPointSizeBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { const SGPropertyNode* realProp = getEffectPropertyNode(effect, prop); if (!realProp) @@ -986,7 +1005,7 @@ EffectPropertyMap depthFunction(depthFunctionInit); struct DepthBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, prop)) return; @@ -1017,7 +1036,7 @@ struct DepthBuilder : public PassAttributeBuilder InstallAttributeBuilder installDepth("depth"); void buildTechnique(Effect* effect, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { Technique* tniq = new Technique; effect->techniques.push_back(tniq); @@ -1123,7 +1142,7 @@ bool makeParametersFromStateSet(SGPropertyNode* effectRoot, const StateSet* ss) // Walk the techniques property tree, building techniques and // passes. -bool Effect::realizeTechniques(const osgDB::ReaderWriter::Options* options) +bool Effect::realizeTechniques(const SGReaderWriterXMLOptions* options) { if (_isRealized) return true; diff --git a/simgear/scene/material/Effect.hxx b/simgear/scene/material/Effect.hxx index 1f33b9e8..0690db3a 100644 --- a/simgear/scene/material/Effect.hxx +++ b/simgear/scene/material/Effect.hxx @@ -45,6 +45,7 @@ namespace simgear { class Technique; class Effect; +class SGReaderWriterXMLOptions; /** * Object to be initialized at some point after an effect -- and its @@ -89,7 +90,7 @@ public: /** * Build the techniques from the effect properties. */ - bool realizeTechniques(const osgDB::ReaderWriter::Options* options = 0); + bool realizeTechniques(const SGReaderWriterXMLOptions* options = 0); /** * Updaters that should be derefed when the effect is * deleted. Updaters arrange to be run by listening on properties @@ -144,7 +145,7 @@ protected: Cache* _cache; friend size_t hash_value(const Key& key); friend Effect* makeEffect(SGPropertyNode* prop, bool realizeTechniques, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterXMLOptions* options); bool _isRealized; }; // Automatic support for boost hash function @@ -153,11 +154,11 @@ size_t hash_value(const Effect::Key&); Effect* makeEffect(const std::string& name, bool realizeTechniques, - const osgDB::ReaderWriter::Options* options = 0); + const SGReaderWriterXMLOptions* options = 0); Effect* makeEffect(SGPropertyNode* prop, bool realizeTechniques, - const osgDB::ReaderWriter::Options* options = 0); + const SGReaderWriterXMLOptions* options = 0); bool makeParametersFromStateSet(SGPropertyNode* paramRoot, const osg::StateSet* ss); diff --git a/simgear/scene/material/EffectBuilder.cxx b/simgear/scene/material/EffectBuilder.cxx index 34f14ac8..338fc9aa 100644 --- a/simgear/scene/material/EffectBuilder.cxx +++ b/simgear/scene/material/EffectBuilder.cxx @@ -2,6 +2,7 @@ # include #endif +#include #include #include @@ -41,13 +42,29 @@ const SGPropertyNode* getEffectPropertyChild(Effect* effect, return getEffectPropertyNode(effect, child); } -string getGlobalProperty(const SGPropertyNode* prop) +string getGlobalProperty(const SGPropertyNode* prop, + const SGReaderWriterXMLOptions* options) { if (!prop) return string(); const SGPropertyNode* useProp = prop->getChild("use"); if (!useProp) return string(); + string propName = useProp->getStringValue(); + SGPropertyNode_ptr propRoot; + if (propName[0] == '/') { + return propName; + } else if ((propRoot = options->getPropRoot())) { + string result = propRoot->getPath(); + result.append("/"); + result.append(propName); + return result; + } else { + throw effect:: + BuilderException("No property root to use with relative name " + + propName); + } + return useProp->getStringValue(); } diff --git a/simgear/scene/material/EffectBuilder.hxx b/simgear/scene/material/EffectBuilder.hxx index be4b0345..54e959a1 100644 --- a/simgear/scene/material/EffectBuilder.hxx +++ b/simgear/scene/material/EffectBuilder.hxx @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -46,6 +47,7 @@ namespace simgear { class Effect; class Pass; +class SGReaderWriterXMLOptions; /** * Builder that returns an object, probably an OSG object. @@ -56,10 +58,10 @@ class EffectBuilder : public SGReferenced public: virtual ~EffectBuilder() {} virtual T* build(Effect* effect, const SGPropertyNode*, - const osgDB::ReaderWriter::Options* options) = 0; + const SGReaderWriterXMLOptions* options) = 0; static T* buildFromType(Effect* effect, const std::string& type, const SGPropertyNode*props, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { BuilderMap& builderMap = getMap(); typename BuilderMap::iterator iter = builderMap.find(type); @@ -154,6 +156,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: @@ -201,6 +218,42 @@ 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.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) { @@ -240,7 +293,45 @@ const SGPropertyNode* getEffectPropertyChild(Effect* effect, * @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 SGReaderWriterXMLOptions *); + +template +std::vector +getVectorProperties(const SGPropertyNode* prop, + const SGReaderWriterXMLOptions *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.size() == 0 || parentName[0] != '/') + parentName = options->getPropRoot()->getPath() + "/" + parentName; + if (parentName[parentName.size() - 1] != '/') + parentName.append("/"); + NameItr itr = defaultNames; + for (int 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.size() == 0 || childName[0] != '/') + result.push_back(parentName + childName); + else + result.push_back(childName); + } + } + return result; +} class PassAttributeBuilder : public SGReferenced { @@ -255,7 +346,7 @@ protected: public: virtual void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) = 0; static PassAttributeBuilder* find(const std::string& str) { @@ -289,64 +380,116 @@ 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 OSGBridge; +template struct Bridge; + +/** + * Default just passes on the same type. + * + */ +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 Bridge : public BridgeOSGVec { }; 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 +/** + * 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 { - 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&)) + 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 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) { @@ -359,7 +502,7 @@ public: } void valueChanged(SGPropertyNode* node) { - _obj->*setter(node->getValue()); + _setter(_obj.get(), node->getValue()); } void initOnAddImpl(Effect* effect, SGPropertyNode* propRoot) { @@ -371,7 +514,7 @@ public: } private: osg::ref_ptr _obj; - setter_type _setter; + F _setter; std::string* _propName; }; @@ -382,11 +525,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 +541,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,6 +562,15 @@ 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); +} + /** * Initialize the value and the possible updating of an effect * attribute. If the value is specified directly, set it. Otherwise, @@ -422,52 +579,97 @@ private: * 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 SGReaderWriterXMLOptions* 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); + std::string propName = getGlobalProperty(prop, 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 SGReaderWriterXMLOptions* 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 SGReaderWriterXMLOptions* 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; + 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 SGReaderWriterXMLOptions* options) +{ + initFromParameters(effect, prop, obj, + boost::bind(setter, _1, _2), nameItr, + options); +} extern const char* colorFields[]; } } diff --git a/simgear/scene/material/TextureBuilder.cxx b/simgear/scene/material/TextureBuilder.cxx index a924b955..7dc7aed6 100644 --- a/simgear/scene/material/TextureBuilder.cxx +++ b/simgear/scene/material/TextureBuilder.cxx @@ -35,6 +35,7 @@ #include #include +#include #include #include #include @@ -50,13 +51,14 @@ using namespace osg; using namespace effect; TexEnvCombine* buildTexEnvCombine(Effect* effect, - const SGPropertyNode* envProp); + const SGPropertyNode* envProp, + const SGReaderWriterXMLOptions* options); TexGen* buildTexGen(Effect* Effect, const SGPropertyNode* tgenProp); // Hack to force inclusion of TextureBuilder.cxx in library osg::Texture* TextureBuilder::buildFromType(Effect* effect, const string& type, const SGPropertyNode*props, - const osgDB::ReaderWriter::Options* + const SGReaderWriterXMLOptions* options) { return EffectBuilder::buildFromType(effect, type, props, options); @@ -98,7 +100,7 @@ TexEnv* buildTexEnv(Effect* effect, const SGPropertyNode* prop) void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, prop)) return; @@ -141,7 +143,8 @@ void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass, } const SGPropertyNode* combineProp = prop->getChild("texenv-combine"); TexEnvCombine* combiner = 0; - if (combineProp && ((combiner = buildTexEnvCombine(effect, combineProp)))) + if (combineProp && ((combiner = buildTexEnvCombine(effect, combineProp, + options)))) pass->setTextureAttributeAndModes(unit, combiner); const SGPropertyNode* tgenProp = prop->getChild("texgen"); TexGen* tgen = 0; @@ -177,7 +180,7 @@ EffectPropertyMap wrapModes(wrapModesInit); TexTuple makeTexTuple(Effect* effect, const SGPropertyNode* props, - const osgDB::ReaderWriter::Options* options, + const SGReaderWriterXMLOptions* options, const string& texType) { Texture::FilterMode minFilter = Texture::LINEAR_MIPMAP_LINEAR; @@ -213,7 +216,7 @@ TexTuple makeTexTuple(Effect* effect, const SGPropertyNode* props, } void setAttrs(const TexTuple& attrs, Texture* tex, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { const string& imageName = attrs.get<0>(); if (imageName.empty()) { @@ -253,7 +256,7 @@ class TexBuilder : public TextureBuilder public: TexBuilder(const string& texType) : _type(texType) {} Texture* build(Effect* effect, const SGPropertyNode*, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterXMLOptions* options); protected: typedef map > TexMap; TexMap texMap; @@ -262,7 +265,7 @@ protected: template Texture* TexBuilder::build(Effect* effect, const SGPropertyNode* props, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { TexTuple attrs = makeTexTuple(effect, props, options, _type); typename TexMap::iterator itr = texMap.find(attrs); @@ -286,11 +289,11 @@ class WhiteTextureBuilder : public TextureBuilder { public: Texture* build(Effect* effect, const SGPropertyNode*, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterXMLOptions* options); }; Texture* WhiteTextureBuilder::build(Effect* effect, const SGPropertyNode*, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { return StateAttributeFactory::instance()->getWhiteTexture(); } @@ -304,11 +307,11 @@ class TransparentTextureBuilder : public TextureBuilder { public: Texture* build(Effect* effect, const SGPropertyNode*, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterXMLOptions* options); }; Texture* TransparentTextureBuilder::build(Effect* effect, const SGPropertyNode*, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { return StateAttributeFactory::instance()->getTransparentTexture(); } @@ -368,14 +371,14 @@ class NoiseBuilder : public TextureBuilder { public: Texture* build(Effect* effect, const SGPropertyNode*, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterXMLOptions* options); protected: typedef map > NoiseMap; NoiseMap _noises; }; Texture* NoiseBuilder::build(Effect* effect, const SGPropertyNode* props, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { int texSize = 64; const SGPropertyNode* sizeProp = getEffectPropertyChild(effect, props, @@ -443,7 +446,8 @@ EffectNameValue opParamInit[] = EffectPropertyMap operandParams(opParamInit); -TexEnvCombine* buildTexEnvCombine(Effect* effect, const SGPropertyNode* envProp) +TexEnvCombine* buildTexEnvCombine(Effect* effect, const SGPropertyNode* envProp, + const SGReaderWriterXMLOptions* options) { if (!isAttributeActive(effect, envProp)) return 0; @@ -538,7 +542,8 @@ TexEnvCombine* buildTexEnvCombine(Effect* effect, const SGPropertyNode* envProp) const SGPropertyNode* colorNode = envProp->getChild("constant-color"); if (colorNode) initFromParameters(effect, colorNode, result, - &TexEnvCombine::setConstantColor, colorFields); + &TexEnvCombine::setConstantColor, colorFields, + options); return result; } diff --git a/simgear/scene/material/TextureBuilder.hxx b/simgear/scene/material/TextureBuilder.hxx index ca6c5494..55df2736 100644 --- a/simgear/scene/material/TextureBuilder.hxx +++ b/simgear/scene/material/TextureBuilder.hxx @@ -29,13 +29,13 @@ public: // Hack to force inclusion of TextureBuilder.cxx in library static osg::Texture* buildFromType(Effect* effect, const std::string& type, const SGPropertyNode*props, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterXMLOptions* options); }; struct TextureUnitBuilder : public PassAttributeBuilder { void buildAttribute(Effect* effect, Pass* pass, const SGPropertyNode* prop, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterXMLOptions* options); }; diff --git a/simgear/scene/material/makeEffect.cxx b/simgear/scene/material/makeEffect.cxx index 1a8efcdb..4ce5841f 100644 --- a/simgear/scene/material/makeEffect.cxx +++ b/simgear/scene/material/makeEffect.cxx @@ -31,6 +31,7 @@ #include #include +#include #include #include #include @@ -116,7 +117,7 @@ void mergePropertyTrees(SGPropertyNode* resultNode, Effect* makeEffect(const string& name, bool realizeTechniques, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { { OpenThreads::ScopedLock lock(effectMutex); @@ -159,7 +160,7 @@ Effect* makeEffect(const string& name, Effect* makeEffect(SGPropertyNode* prop, bool realizeTechniques, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { // Give default names to techniques and passes vector techniques = prop->getChildren("technique"); diff --git a/simgear/scene/material/mat.cxx b/simgear/scene/material/mat.cxx index 2fc7e9c8..5947579e 100644 --- a/simgear/scene/material/mat.cxx +++ b/simgear/scene/material/mat.cxx @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include @@ -68,12 +69,12 @@ using namespace simgear; //////////////////////////////////////////////////////////////////////// SGMaterial::_internal_state::_internal_state(Effect *e, const string &t, bool l, - const osgDB::ReaderWriter::Options* o ) : - effect(e), texture_path(t), effect_realized(l), options(o) + const SGReaderWriterXMLOptions* o) + : effect(e), texture_path(t), effect_realized(l), options(o) { } -SGMaterial::SGMaterial( const osgDB::ReaderWriter::Options* options, +SGMaterial::SGMaterial( const SGReaderWriterXMLOptions* options, const SGPropertyNode *props ) { init(); @@ -81,6 +82,17 @@ SGMaterial::SGMaterial( const osgDB::ReaderWriter::Options* options, buildEffectProperties(options); } +SGMaterial::SGMaterial( const osgDB::ReaderWriter::Options* options, + const SGPropertyNode *props ) +{ + osg::ref_ptr sgOptions; + if (options) + sgOptions = new SGReaderWriterXMLOptions(*options); + init(); + read_properties( sgOptions.get(), props ); + buildEffectProperties(sgOptions.get()); +} + SGMaterial::~SGMaterial (void) { } @@ -91,7 +103,7 @@ SGMaterial::~SGMaterial (void) //////////////////////////////////////////////////////////////////////// void -SGMaterial::read_properties(const osgDB::ReaderWriter::Options* options, +SGMaterial::read_properties(const SGReaderWriterXMLOptions* options, const SGPropertyNode *props) { // Gather the path(s) to the texture(s) @@ -245,10 +257,12 @@ Effect* SGMaterial::get_effect(int n) return _status[i].effect.get(); } -void SGMaterial::buildEffectProperties(const osgDB::ReaderWriter::Options* - options) +void SGMaterial::buildEffectProperties(const SGReaderWriterXMLOptions* options) { using namespace osg; + ref_ptr xmlOptions; + if (options) + xmlOptions = new SGReaderWriterXMLOptions(*options); ref_ptr user = new SGMaterialUserData(this); SGPropertyNode_ptr propRoot = new SGPropertyNode(); makeChild(propRoot, "inherits-from")->setStringValue(effect); @@ -279,7 +293,7 @@ void SGMaterial::buildEffectProperties(const osgDB::ReaderWriter::Options* ->setStringValue(wrapu ? "repeat" : "clamp"); makeChild(texProp, "wrap-t") ->setStringValue(wrapv ? "repeat" : "clamp"); - matState.effect = makeEffect(effectProp, false, options); + matState.effect = makeEffect(effectProp, false, xmlOptions.get()); matState.effect->setUserData(user.get()); } } diff --git a/simgear/scene/material/mat.hxx b/simgear/scene/material/mat.hxx index ac2e5f1b..619ae8da 100644 --- a/simgear/scene/material/mat.hxx +++ b/simgear/scene/material/mat.hxx @@ -39,13 +39,13 @@ #include #include -#include namespace osg { class StateSet; } +#include #include #include #include @@ -87,6 +87,8 @@ public: */ SGMaterial( const osgDB::ReaderWriter::Options*, const SGPropertyNode *props); + SGMaterial(const simgear::SGReaderWriterXMLOptions*, + const SGPropertyNode *props); /** * Destructor. */ @@ -271,11 +273,11 @@ protected: struct _internal_state { _internal_state(simgear::Effect *e, const std::string &t, bool l, - const osgDB::ReaderWriter::Options *o); + const simgear::SGReaderWriterXMLOptions *o); osg::ref_ptr effect; std::string texture_path; bool effect_realized; - osg::ref_ptr options; + osg::ref_ptr options; }; private: @@ -361,9 +363,9 @@ private: // Internal constructors and methods. //////////////////////////////////////////////////////////////////// - void read_properties(const osgDB::ReaderWriter::Options* options, + void read_properties(const simgear::SGReaderWriterXMLOptions* options, const SGPropertyNode *props); - void buildEffectProperties(const osgDB::ReaderWriter::Options* options); + void buildEffectProperties(const simgear::SGReaderWriterXMLOptions* options); }; diff --git a/simgear/scene/model/SGReaderWriterXMLOptions.hxx b/simgear/scene/model/SGReaderWriterXMLOptions.hxx index 17532aee..cca34824 100644 --- a/simgear/scene/model/SGReaderWriterXMLOptions.hxx +++ b/simgear/scene/model/SGReaderWriterXMLOptions.hxx @@ -18,7 +18,7 @@ #ifndef SGREADERWRITERXMLOPTIONS_HXX #define SGREADERWRITERXMLOPTIONS_HXX 1 -#include +#include #include #include diff --git a/simgear/scene/model/model.cxx b/simgear/scene/model/model.cxx index 59f33694..1ea486f0 100644 --- a/simgear/scene/model/model.cxx +++ b/simgear/scene/model/model.cxx @@ -33,6 +33,7 @@ #include #include +#include "SGReaderWriterXMLOptions.hxx" #include "model.hxx" using std::vector; @@ -209,7 +210,7 @@ class MakeEffectVisitor : public SplicingVisitor public: typedef std::map EffectMap; using SplicingVisitor::apply; - MakeEffectVisitor(const osgDB::ReaderWriter::Options* options = 0) + MakeEffectVisitor(const SGReaderWriterXMLOptions* options = 0) : _options(options) { } @@ -225,7 +226,7 @@ public: protected: EffectMap _effectMap; SGPropertyNode_ptr _currentEffectParent; - osg::ref_ptr _options; + osg::ref_ptr _options; }; void MakeEffectVisitor::apply(osg::Group& node) @@ -302,7 +303,7 @@ protected: ref_ptr instantiateEffects(osg::Node* modelGroup, PropertyList& effectProps, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { SGPropertyNode_ptr defaultEffectPropRoot; MakeEffectVisitor visitor(options); diff --git a/simgear/scene/model/model.hxx b/simgear/scene/model/model.hxx index 49dc0666..c2097fdc 100644 --- a/simgear/scene/model/model.hxx +++ b/simgear/scene/model/model.hxx @@ -23,6 +23,11 @@ #include #include +namespace simgear +{ +class SGReaderWriterXMLOptions; +} + osg::Texture2D* SGLoadTexture2D(bool staticTexture, const std::string& path, const osgDB::ReaderWriter::Options* options = 0, @@ -97,7 +102,7 @@ public: osg::ref_ptr instantiateEffects(osg::Node* model, PropertyList& effectProps, - const osgDB::ReaderWriter::Options* options); + const SGReaderWriterXMLOptions* options); /** * Transform an OSG subgraph by substituting the Effects and @@ -110,7 +115,7 @@ instantiateEffects(osg::Node* model, inline osg::ref_ptr instantiateEffects(osg::Node* model, - const osgDB::ReaderWriter::Options* options) + const SGReaderWriterXMLOptions* options) { PropertyList effectProps; return instantiateEffects(model, effectProps, options); diff --git a/simgear/scene/model/modellib.cxx b/simgear/scene/model/modellib.cxx index 6a13c516..4b457f5e 100644 --- a/simgear/scene/model/modellib.cxx +++ b/simgear/scene/model/modellib.cxx @@ -71,8 +71,12 @@ osg::Node* loadFile(const string& path, osgDB::ReaderWriter::Options* options) ref_ptr model = readRefNodeFile(path, options); if (!model) return 0; - if (boost::iends_with(path, ".ac")) - model = instantiateEffects(model.get(), options); + if (boost::iends_with(path, ".ac")) { + ref_ptr sgOptions; + if (options) + sgOptions = new SGReaderWriterXMLOptions(*options); + model = instantiateEffects(model.get(), sgOptions.get()); + } return model.release(); } } diff --git a/simgear/scene/sky/newcloud.cxx b/simgear/scene/sky/newcloud.cxx index 162f137a..6d35ad99 100644 --- a/simgear/scene/sky/newcloud.cxx +++ b/simgear/scene/sky/newcloud.cxx @@ -46,6 +46,7 @@ #include #include #include +#include #include #include @@ -108,9 +109,11 @@ SGNewCloud::SGNewCloud(string type, "texture"), "image"), texture); - osg::ref_ptr options + ref_ptr options = makeOptionsFromPath(tex_path); - if ((effect = makeEffect(pcloudEffect, true, options))) + ref_ptr sgOptions + = new SGReaderWriterXMLOptions(*options.get()); + if ((effect = makeEffect(pcloudEffect, true, sgOptions.get()))) effectMap.insert(EffectMap::value_type(texture, effect)); } else { effect = iter->second.get();