Implementation of animated effect values via the property system.
Add names for TexEnvCombine attributes
<Filter
Name="Lib_sgprops"
Filter="">
+ <File
+ RelativePath="..\..\simgear\props\AtomicChangeListener.cxx">
+ </File>
+ <File
+ RelativePath="..\..\simgear\props\AtomicChangeListener.hxx">
+ </File>
+ <File
+ RelativePath="..\..\simgear\props\ExtendedPropertyAdapter.hxx">
+ </File>
<File
RelativePath="..\..\simgear\props\condition.cxx">
</File>
<File
RelativePath="..\..\simgear\scene\util\StateAttributeFactory.hxx">
</File>
+ <File
+ RelativePath="..\..\simgear\scene\util\UpdateOnceCallback.cxx">
+ </File>
+ <File
+ RelativePath="..\..\simgear\scene\util\UpdateOnceCallback.hxx">
+ </File>
</Filter>
<Filter
Name="Lib_sgbvh"
<Filter
Name="Lib_sgprops"
>
+ <File
+ RelativePath="..\..\simgear\props\AtomicChangeListener.cxx"
+ >
+ </File>
+ <File
+ RelativePath="..\..\simgear\props\AtomicChangeListener.hxx"
+ >
+ </File>
<File
RelativePath="..\..\simgear\props\condition.cxx"
>
RelativePath="..\..\simgear\props\condition.hxx"
>
</File>
+ <File
+ RelativePath="..\..\simgear\props\ExtendedPropertyAdapter.hxx"
+ >
+ </File>
+
<File
RelativePath="..\..\simgear\props\props.cxx"
>
RelativePath="..\..\simgear\scene\util\StateAttributeFactory.hxx"
>
</File>
+ <File
+ RelativePath="..\..\simgear\scene\util\UpdateOnceCallback.cxx"
+ >
+ </File>
+ <File
+ RelativePath="..\..\simgear\scene\util\UpdateOnceCallback.hxx"
+ >
+ </File>
</Filter>
<Filter
Name="Lib_sgbvh"
--- /dev/null
+#include "AtomicChangeListener.hxx"
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+#include <boost/bind.hpp>
+
+#include <simgear/structure/Singleton.hxx>
+
+namespace simgear
+{
+using namespace std;
+
+MultiChangeListener::MultiChangeListener()
+{
+}
+
+void MultiChangeListener::valueChanged()
+{
+ valueChangedImplementation();
+}
+
+void MultiChangeListener::valueChangedImplementation()
+{
+}
+
+AtomicChangeListener::AtomicChangeListener(std::vector<SGPropertyNode*>& nodes)
+ : _dirty(false), _valid(true)
+{
+ listenToProperties(nodes.begin(), nodes.end());
+}
+
+void AtomicChangeListener::unregister_property(SGPropertyNode* node)
+{
+ _valid = false;
+ // not necessary, but good hygine
+ vector<SGPropertyNode*>::iterator itr
+ = find(_watched.begin(), _watched.end(), node);
+ if (itr != _watched.end())
+ *itr = 0;
+ MultiChangeListener::unregister_property(node);
+}
+
+void AtomicChangeListener::fireChangeListeners()
+{
+ vector<SGSharedPtr<AtomicChangeListener> >& listeners
+ = ListenerListSingleton::instance()->listeners;
+ for (vector<SGSharedPtr<AtomicChangeListener> >::iterator itr = listeners.begin(),
+ end = listeners.end();
+ itr != end;
+ ++itr) {
+ (*itr)->valuesChanged();
+ (*itr)->_dirty = false;
+ }
+ listeners.clear();
+}
+
+void AtomicChangeListener::valueChangedImplementation()
+{
+ if (!_dirty) {
+ _dirty = true;
+ if (_valid)
+ ListenerListSingleton::instance()->listeners.push_back(this);
+ }
+}
+
+void AtomicChangeListener::valuesChanged()
+{
+}
+}
--- /dev/null
+#ifndef SIMGEAR_ATOMICCHANGELISTENER_HXX
+#define SIMGEAR_ATOMICCHANGELISTENER_HXX 1
+
+#include <algorithm>
+#include <iterator>
+#include <vector>
+
+#include <boost/bind.hpp>
+
+#include <simgear/structure/Singleton.hxx>
+
+#include "props.hxx"
+#include "ExtendedPropertyAdapter.hxx"
+
+namespace simgear
+{
+// Performs an action when one of several nodes changes
+class MultiChangeListener : private SGPropertyChangeListener
+{
+public:
+ MultiChangeListener();
+ template<typename Pitr>
+ void listenToProperties(Pitr propsBegin, Pitr propsEnd)
+ {
+ for (Pitr itr = propsBegin, end = propsEnd; itr != end; ++itr)
+ (*itr)->addChangeListener(this);
+ }
+ void valueChanged();
+ using SGPropertyChangeListener::unregister_property;
+private:
+ virtual void valueChangedImplementation();
+
+};
+
+class AtomicChangeListener : public MultiChangeListener,
+ public virtual SGReferenced
+{
+public:
+ AtomicChangeListener(std::vector<SGPropertyNode*>& nodes);
+ /**
+ * Lookup / create child nodes from their relative names.
+ */
+ template<typename Itr>
+ AtomicChangeListener(SGPropertyNode* parent, Itr childNamesBegin,
+ Itr childNamesEnd)
+ : _dirty(false), _valid(true)
+ {
+ using namespace std;
+ for (Itr itr = childNamesBegin, end = childNamesEnd;
+ itr != end;
+ ++itr)
+ _watched.push_back(makeNode(parent, *itr));
+ listenToProperties(_watched.begin(), _watched.end());
+ }
+ bool isDirty() { return _dirty; }
+ bool isValid() { return _valid; }
+ void unregister_property(SGPropertyNode* node);
+ static void fireChangeListeners();
+private:
+ virtual void valueChangedImplementation();
+ virtual void valuesChanged();
+ bool _dirty;
+ bool _valid;
+ struct ListenerListSingleton : public Singleton<ListenerListSingleton>
+ {
+ std::vector<SGSharedPtr<AtomicChangeListener> > listeners;
+ };
+protected:
+ std::vector<SGPropertyNode*> _watched;
+};
+
+template<typename T, typename Func>
+class ExtendedPropListener : public AtomicChangeListener
+{
+public:
+ ExtendedPropListener(std::vector<SGPropertyNode*>& nodes, const Func& func,
+ bool initial = false)
+ : AtomicChangeListener(nodes), _func(func)
+ {
+ if (initial)
+ valuesChanged();
+
+ }
+ template<typename Itr>
+ ExtendedPropListener(SGPropertyNode* parent, Itr childNamesBegin,
+ Itr childNamesEnd, const Func& func,
+ bool initial = false)
+ : AtomicChangeListener(parent, childNamesBegin, childNamesEnd),
+ _func(func)
+ {
+ if (initial)
+ valuesChanged();
+ }
+ virtual void valuesChanged()
+ {
+ ExtendedPropertyAdapter<T, std::vector<SGPropertyNode*> > adaptor(_watched);
+ T val = adaptor();
+ _func(val);
+ }
+private:
+ Func _func;
+};
+
+}
+#endif
--- /dev/null
+#ifndef SIMGEAR_EXTENDEDPROPERTYADAPTER_HXX
+#define SIMGEAR_EXTENDEDPROPERTYADAPTER_HXX 1
+
+#include <algorithm>
+
+#include <boost/bind.hpp>
+
+#include <simgear/math/SGMath.hxx>
+#include <simgear/structure/exception.hxx>
+
+#include "props.hxx"
+
+namespace simgear
+{
+
+namespace props
+{
+// This should be in simgear/math/SGVec.hxx and friends
+
+template<typename T> struct NumComponents;
+
+template<> struct NumComponents<SGVec3d>
+{
+ enum { num_components = 3 };
+};
+
+template<> struct NumComponents<SGVec4d>
+{
+ enum { num_components = 4 };
+};
+
+}
+
+template<typename T, typename NodeContainer>
+class ExtendedPropertyAdapter
+{
+public:
+ enum { num_components = props::NumComponents<T>::num_components };
+ ExtendedPropertyAdapter(const NodeContainer& elements)
+ : _elements(elements)
+ {
+ }
+ T operator()() const
+ {
+ T result;
+ if (_elements.size() < num_components)
+ throw sg_exception();
+ for (int i = 0; i < num_components; ++i)
+ result[i] = _elements[i]->getValue<double>();
+ return result;
+ }
+ void set(const T& val)
+ {
+ if (_elements.size() < num_components)
+ throw sg_exception();
+ for (int i = 0; i < num_components; ++i)
+ _elements[i]->setValue(val[i]);
+ }
+private:
+ const NodeContainer& _elements;
+};
+
+template<typename InIterator, typename OutIterator>
+inline void makeChildList(SGPropertyNode* prop, InIterator inBegin,
+ InIterator inEnd, OutIterator outBegin)
+{
+ std::transform(inBegin, inEnd, outBegin,
+ boost::bind(static_cast<SGPropertyNode* (SGPropertyNode::*)(const char*, int, bool)>(&SGPropertyNode::getChild), prop, _1, 0, true));
+}
+
+}
+#endif
include_HEADERS = \
condition.hxx \
props.hxx \
- props_io.hxx
+ props_io.hxx \
+ AtomicChangeListener.hxx \
+ ExtendedPropertyAdapter.hxx
libsgprops_a_SOURCES = \
condition.cxx \
props.cxx \
- props_io.cxx
+ props_io.cxx \
+ AtomicChangeListener.cxx
noinst_PROGRAMS = props_test
}
/**
- * Utility function for creation of a child property node
+ * Utility function for creation of a child property node.
*/
inline SGPropertyNode* makeChild(SGPropertyNode* parent, const char* name,
int index = 0)
{
return parent->getChild(name, index, true);
}
+
+/**
+ * Utility function for creation of a child property node using a
+ * relative path.
+ */
+namespace simgear
+{
+template<typename StringType>
+inline SGPropertyNode* makeNode(SGPropertyNode* parent, const StringType& name)
+{
+ return parent->getNode(name, true);
+}
+}
#endif // __PROPS_HXX
// end of props.hxx
#include "Effect.hxx"
#include "EffectBuilder.hxx"
+#include "EffectGeode.hxx"
#include "Technique.hxx"
#include "Pass.hxx"
#include "TextureBuilder.hxx"
} else {
makeChild(blendNode, "active")->setValue(false);
}
+ string renderingHint = findName(renderingHints, ss->getRenderingHint());
+ makeChild(paramRoot, "rendering-hint")->setStringValue(renderingHint);
makeTextureParameters(paramRoot, ss);
return true;
}
return true;
}
+void Effect::InitializeCallback::doUpdate(osg::Node* node, osg::NodeVisitor* nv)
+{
+ EffectGeode* eg = dynamic_cast<EffectGeode*>(node);
+ if (!eg)
+ return;
+ Effect* effect = eg->getEffect();
+ if (!effect)
+ return;
+ SGPropertyNode* root = getPropertyRoot();
+ for (vector<SGSharedPtr<Updater> >::iterator itr = effect->_extraData.begin(),
+ end = effect->_extraData.end();
+ itr != end;
+ ++itr) {
+ InitializeWhenAdded* adder
+ = dynamic_cast<InitializeWhenAdded*>(itr->ptr());
+ if (adder)
+ adder->initOnAdd(effect, root);
+ }
+}
+
bool Effect_writeLocalData(const Object& obj, osgDB::Output& fw)
{
const Effect& effect = static_cast<const Effect&>(obj);
#include <osgDB/ReaderWriter>
#include <simgear/props/props.hxx>
+#include <simgear/scene/util/UpdateOnceCallback.hxx>
namespace osg
{
namespace simgear
{
class Technique;
+class Effect;
+
+/**
+ * Object to be initialized at some point after an effect -- and its
+ * containing effect geode -- are hooked into the scene graph. Some
+ * things, like manipulations of the global property tree, are are
+ * only safe in the update process.
+ */
+
+class InitializeWhenAdded
+{
+public:
+ InitializeWhenAdded() : _initialized(false) {};
+ virtual ~InitializeWhenAdded() {};
+ void initOnAdd(Effect* effect, SGPropertyNode* propRoot)
+ {
+ if (!_initialized) {
+ initOnAddImpl(effect, propRoot);
+ _initialized = true;
+ }
+ }
+ bool getInitialized() const { return _initialized; }
+private:
+ virtual void initOnAddImpl(Effect* effect, SGPropertyNode* propRoot) = 0;
+ bool _initialized;
+};
class Effect : public osg::Object
{
Technique* chooseTechnique(osg::RenderInfo* renderInfo);
virtual void resizeGLObjectBuffers(unsigned int maxSize);
virtual void releaseGLObjects(osg::State* state = 0) const;
- /*
+ /**
* Build the techniques from the effect properties.
*/
bool realizeTechniques(const osgDB::ReaderWriter::Options* options = 0);
+ /**
+ * Updaters that should be derefed when the effect is
+ * deleted. Updaters arrange to be run by listening on properties
+ * or something.
+ */
+ struct Updater : public virtual SGReferenced
+ {
+ virtual ~Updater() {}
+ };
+ void addUpdater(Updater* data) { _extraData.push_back(data); }
+ // Callback that is added to the effect geode to initialize the
+ // effect.
+ friend struct InitializeCallback;
+ struct InitializeCallback : public UpdateOnceCallback
+ {
+ void doUpdate(osg::Node* node, osg::NodeVisitor* nv);
+ };
protected:
+ std::vector<SGSharedPtr<Updater> > _extraData;
~Effect();
};
Effect* makeEffect(const std::string& name,
# include <simgear_config.h>
#endif
+#include <simgear/scene/tgdb/userdata.hxx>
+
#include <simgear/math/SGMath.hxx>
#include "EffectBuilder.hxx"
return getEffectPropertyNode(effect, child);
}
+string getGlobalProperty(const SGPropertyNode* prop)
+{
+ if (!prop)
+ return string();
+ const SGPropertyNode* useProp = prop->getChild("use");
+ if (!useProp)
+ return string();
+ return useProp->getStringValue();
+}
+
BuilderException::BuilderException()
{
}
return !activeProp || activeProp->getValue<bool>();
}
+namespace effect
+{
+const char* colorFields[] = {"red", "green", "blue", "alpha"};
+}
}
#define SIMGEAR_EFFECTBUILDER_HXX 1
#include <algorithm>
+#include <iterator>
#include <map>
#include <string>
#include <cstring>
#include <osgDB/Registry>
+#include <boost/bind.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
+#include <simgear/math/SGMath.hxx>
+#include <simgear/props/AtomicChangeListener.hxx>
#include <simgear/props/props.hxx>
#include <simgear/structure/exception.hxx>
#include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/structure/Singleton.hxx>
+#include "Effect.hxx"
/**
* Support classes for parsing effects.
*/
template<typename T>
bool findAttr(const effect::EffectPropertyMap<T>& pMap,
- const SGPropertyNode* prop,
+ const char* name,
T& result)
{
using namespace effect;
- if (!prop)
- return false;
- const char* name = prop->getStringValue();
- if (!name)
- return false;
typename EffectPropertyMap<T>::BMap::iterator itr
= pMap._map.get<from>().find(name);
if (itr == pMap._map.end()) {
}
}
+template<typename T>
+inline bool findAttr(const effect::EffectPropertyMap<T>& pMap,
+ const std::string& name,
+ T& result)
+{
+ return findAttr(pMap, name.c_str(), result);
+}
+
+template<typename T>
+bool findAttr(const effect::EffectPropertyMap<T>& pMap,
+ const SGPropertyNode* prop,
+ T& result)
+{
+ if (!prop)
+ return false;
+ const char* name = prop->getStringValue();
+ if (!name)
+ return false;
+ return findAttr(pMap, name, result);
+}
+
template<typename T>
std::string findName(const effect::EffectPropertyMap<T>& pMap, T value)
{
const SGPropertyNode* prop,
const char* name);
+/**
+ * Get the name of a node mentioned in a <use> clause from the global property
+ * tree.
+ * @return empty if prop doesn't contain a <use> clause; otherwise the
+ * mentioned node name.
+ */
+std::string getGlobalProperty(const SGPropertyNode* prop);
+
class BuilderException : public sg_exception
{
public:
// 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<typename T> struct OSGBridge;
+
+template<typename T>
+struct OSGBridge<const T> : public OSGBridge<T>
+{
+};
+
+template<>
+struct OSGBridge<osg::Vec3f>
+{
+ typedef SGVec3d sg_type;
+ static osg::Vec3f getOsgType(const SGVec3d& val) { return toOsg(val); }
+};
+
+template<>
+struct OSGBridge<osg::Vec3d>
+{
+ typedef SGVec3d sg_type;
+ static osg::Vec3d getOsgType(const SGVec3d& val) { return toOsg(val); }
+};
+
+template<>
+struct OSGBridge<osg::Vec4f>
+{
+ typedef SGVec4d sg_type;
+ static osg::Vec4f getOsgType(const SGVec4d& val) { return toOsg(val); }
+};
+
+template<>
+struct OSGBridge<osg::Vec4d>
+{
+ typedef SGVec4d sg_type;
+ static osg::Vec4d getOsgType(const SGVec4d& val) { return toOsg(val); }
+};
+
+template<typename Obj, typename OSGParam>
+struct OSGFunctor : public OSGBridge<OSGParam>
+{
+ OSGFunctor(Obj* obj, void (Obj::*func)(const OSGParam&))
+ : _obj(obj), _func(func) {}
+ void operator()(const typename OSGBridge<OSGParam>::sg_type& val) const
+ {
+ ((_obj.get())->*_func)(this->getOsgType(val));
+ }
+ osg::ref_ptr<Obj>_obj;
+ void (Obj::*_func)(const OSGParam&);
+};
+
+template<typename ObjType, typename OSGParamType>
+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<OSGParamType>());
+ }
+ 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<ObjType> _obj;
+ setter_type _setter;
+ std::string* _propName;
+};
+
+template<typename T, typename Func>
+class EffectExtendedPropListener : public InitializeWhenAdded,
+ public Effect::Updater
+{
+public:
+ template<typename Itr>
+ EffectExtendedPropListener(const Func& func,
+ const std::string& propName, Itr childNamesBegin,
+ Itr childNamesEnd)
+ : _func(func)
+ {
+ _propName = new std::string(propName);
+ _childNames = new std::vector<std::string>(childNamesBegin,
+ childNamesEnd);
+ }
+ virtual ~EffectExtendedPropListener()
+ {
+ delete _propName;
+ delete _childNames;
+ }
+ void initOnAddImpl(Effect* effect, SGPropertyNode* propRoot)
+ {
+ SGPropertyNode* parent = propRoot->getNode(*_propName, true);
+ _propListener
+ = new ExtendedPropListener<T, Func>(parent, _childNames->begin(),
+ _childNames->end(),
+ _func, true);
+ delete _propName;
+ _propName = 0;
+ delete _childNames;
+ _childNames = 0;
+ }
+private:
+ std::string* _propName;
+ std::vector<std::string>* _childNames;
+ SGSharedPtr<ExtendedPropListener<T, Func> > _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 <use> tag to look at the parameters. Again, if there is a
+ * value there set it directly. Otherwise, the parameter contains its
+ * own <use> tag referring to a property in the global property tree;
+ * install a change listener that will set the attribute when the
+ * property changes.
+ */
+template<typename ObjType, typename OSGParamType>
+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<OSGParamType>());
+ } else {
+ std::string propName = getGlobalProperty(prop);
+ ScalarChangeListener<ObjType, OSGParamType>* listener
+ = new ScalarChangeListener<ObjType, OSGParamType>(obj, setter,
+ propName);
+ effect->addUpdater(listener);
+ }
+}
+
+template<typename ObjType, typename OSGParamType, typename NameItrType>
+void
+initFromParameters(Effect* effect, const SGPropertyNode* prop, ObjType* obj,
+ void (ObjType::*setter)(const OSGParamType&),
+ NameItrType nameItr)
+{
+ typedef typename OSGBridge<OSGParamType>::sg_type sg_type;
+ const SGPropertyNode* valProp = getEffectPropertyNode(effect, prop);
+ if (!valProp)
+ return;
+ if (valProp->nChildren() == 0) {
+ (obj->*setter)(OSGBridge<OSGParamType>
+ ::getOsgType(valProp->getValue<sg_type>()));
+ } else {
+ string listenPropName = getGlobalProperty(valProp);
+ if (listenPropName.empty())
+ return;
+ typedef OSGFunctor<ObjType, OSGParamType> Functor;
+ Effect::Updater* listener
+ = new EffectExtendedPropListener<sg_type, Functor>
+ (Functor(obj, setter), listenPropName, nameItr,
+ nameItr + props::NumComponents<sg_type>::num_components);
+ effect->addUpdater(listener);
+ }
+}
+
+extern const char* colorFields[];
+}
}
#endif
{
}
+void EffectGeode::setEffect(Effect* effect)
+{
+ _effect = effect;
+ if (!_effect)
+ return;
+ addUpdateCallback(new Effect::InitializeCallback);
+}
+
void EffectGeode::resizeGLObjectBuffers(unsigned int maxSize)
{
if (_effect.valid())
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
META_Node(simgear,EffectGeode);
Effect* getEffect() const { return _effect.get(); }
- void setEffect(Effect* effect) { _effect = effect; }
+ void setEffect(Effect* effect);
virtual void resizeGLObjectBuffers(unsigned int maxSize);
virtual void releaseGLObjects(osg::State* = 0) const;
typedef DrawableList::iterator DrawablesIterator;
#include <osg/TexEnv>
#include <osg/TexEnvCombine>
+#include <osg/TexGen>
#include <osg/Texture1D>
#include <osg/Texture2D>
#include <osg/Texture3D>
using namespace effect;
+TexEnvCombine* buildTexEnvCombine(Effect* effect,
+ const SGPropertyNode* envProp);
+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,
if (env)
pass->setTextureAttributeAndModes(unit, env);
}
+ const SGPropertyNode* combineProp = prop->getChild("texenv-combine");
+ TexEnvCombine* combiner = 0;
+ if (combineProp && ((combiner = buildTexEnvCombine(effect, combineProp))))
+ pass->setTextureAttributeAndModes(unit, combiner);
+ const SGPropertyNode* tgenProp = prop->getChild("texgen");
+ TexGen* tgen = 0;
+ if (tgenProp && (tgen = buildTexGen(effect, tgenProp)))
+ pass->setTextureAttributeAndModes(unit, tgen);
}
// InstallAttributeBuilder call is in Effect.cxx to force this file to
TextureBuilder::Registrar installNoise("noise", new NoiseBuilder);
}
+EffectNameValue<TexEnvCombine::CombineParam> combineParamInit[] =
+{
+ {"replace", TexEnvCombine::REPLACE},
+ {"modulate", TexEnvCombine::MODULATE},
+ {"add", TexEnvCombine::ADD},
+ {"add-signed", TexEnvCombine::ADD_SIGNED},
+ {"interpolate", TexEnvCombine::INTERPOLATE},
+ {"subtract", TexEnvCombine::SUBTRACT},
+ {"dot3-rgb", TexEnvCombine::DOT3_RGB},
+ {"dot3-rgba", TexEnvCombine::DOT3_RGBA}
+};
+
+EffectPropertyMap<TexEnvCombine::CombineParam> combineParams(combineParamInit);
+
+EffectNameValue<TexEnvCombine::SourceParam> sourceParamInit[] =
+{
+ {"constant", TexEnvCombine::CONSTANT},
+ {"primary_color", TexEnvCombine::PRIMARY_COLOR},
+ {"previous", TexEnvCombine::PREVIOUS},
+ {"texture", TexEnvCombine::TEXTURE},
+ {"texture0", TexEnvCombine::TEXTURE0},
+ {"texture1", TexEnvCombine::TEXTURE1},
+ {"texture2", TexEnvCombine::TEXTURE2},
+ {"texture3", TexEnvCombine::TEXTURE3},
+ {"texture4", TexEnvCombine::TEXTURE4},
+ {"texture5", TexEnvCombine::TEXTURE5},
+ {"texture6", TexEnvCombine::TEXTURE6},
+ {"texture7", TexEnvCombine::TEXTURE7}
+};
+
+EffectPropertyMap<TexEnvCombine::SourceParam> sourceParams(sourceParamInit);
+
+EffectNameValue<TexEnvCombine::OperandParam> opParamInit[] =
+{
+ {"src_color", TexEnvCombine::SRC_COLOR},
+ {"one_minus_src_color", TexEnvCombine::ONE_MINUS_SRC_COLOR},
+ {"src_alpha", TexEnvCombine::SRC_ALPHA},
+ {"one_minus_src_alpha", TexEnvCombine::ONE_MINUS_SRC_ALPHA}
+};
+
+EffectPropertyMap<TexEnvCombine::OperandParam> operandParams(opParamInit);
+
+TexEnvCombine* buildTexEnvCombine(Effect* effect, const SGPropertyNode* envProp)
+{
+ if (!isAttributeActive(effect, envProp))
+ return 0;
+ TexEnvCombine* result = new TexEnvCombine;
+ const SGPropertyNode* p = 0;
+ if ((p = getEffectPropertyChild(effect, envProp, "combine-rgb"))) {
+ TexEnvCombine::CombineParam crgb = TexEnvCombine::MODULATE;
+ findAttr(combineParams, p, crgb);
+ result->setCombine_RGB(crgb);
+ }
+ if ((p = getEffectPropertyChild(effect, envProp, "combine-alpha"))) {
+ TexEnvCombine::CombineParam calpha = TexEnvCombine::MODULATE;
+ findAttr(combineParams, p, calpha);
+ result->setCombine_RGB(calpha);
+ }
+ if ((p = getEffectPropertyChild(effect, envProp, "source0-rgb"))) {
+ TexEnvCombine::SourceParam source = TexEnvCombine::TEXTURE;
+ findAttr(sourceParams, p, source);
+ result->setSource0_RGB(source);
+ }
+ if ((p = getEffectPropertyChild(effect, envProp, "source1-rgb"))) {
+ TexEnvCombine::SourceParam source = TexEnvCombine::PREVIOUS;
+ findAttr(sourceParams, p, source);
+ result->setSource1_RGB(source);
+ }
+ if ((p = getEffectPropertyChild(effect, envProp, "source2-rgb"))) {
+ TexEnvCombine::SourceParam source = TexEnvCombine::CONSTANT;
+ findAttr(sourceParams, p, source);
+ result->setSource2_RGB(source);
+ }
+ if ((p = getEffectPropertyChild(effect, envProp, "source0-alpha"))) {
+ TexEnvCombine::SourceParam source = TexEnvCombine::TEXTURE;
+ findAttr(sourceParams, p, source);
+ result->setSource0_Alpha(source);
+ }
+ if ((p = getEffectPropertyChild(effect, envProp, "source1-alpha"))) {
+ TexEnvCombine::SourceParam source = TexEnvCombine::PREVIOUS;
+ findAttr(sourceParams, p, source);
+ result->setSource1_Alpha(source);
+ }
+ if ((p = getEffectPropertyChild(effect, envProp, "source2-alpha"))) {
+ TexEnvCombine::SourceParam source = TexEnvCombine::CONSTANT;
+ findAttr(sourceParams, p, source);
+ result->setSource2_Alpha(source);
+ }
+ if ((p = getEffectPropertyChild(effect, envProp, "operand0-rgb"))) {
+ TexEnvCombine::OperandParam op = TexEnvCombine::SRC_COLOR;
+ findAttr(operandParams, p, op);
+ result->setOperand0_RGB(op);
+ }
+ if ((p = getEffectPropertyChild(effect, envProp, "operand1-rgb"))) {
+ TexEnvCombine::OperandParam op = TexEnvCombine::SRC_COLOR;
+ findAttr(operandParams, p, op);
+ result->setOperand1_RGB(op);
+ }
+ if ((p = getEffectPropertyChild(effect, envProp, "operand2-rgb"))) {
+ TexEnvCombine::OperandParam op = TexEnvCombine::SRC_ALPHA;
+ findAttr(operandParams, p, op);
+ result->setOperand2_RGB(op);
+ }
+ if ((p = getEffectPropertyChild(effect, envProp, "operand0-alpha"))) {
+ TexEnvCombine::OperandParam op = TexEnvCombine::SRC_ALPHA;
+ findAttr(operandParams, p, op);
+ result->setOperand0_Alpha(op);
+ }
+ if ((p = getEffectPropertyChild(effect, envProp, "operand1-alpha"))) {
+ TexEnvCombine::OperandParam op = TexEnvCombine::SRC_ALPHA;
+ findAttr(operandParams, p, op);
+ result->setOperand1_Alpha(op);
+ }
+ if ((p = getEffectPropertyChild(effect, envProp, "operand2-alpha"))) {
+ TexEnvCombine::OperandParam op = TexEnvCombine::SRC_ALPHA;
+ findAttr(operandParams, p, op);
+ result->setOperand2_Alpha(op);
+ }
+ if ((p = getEffectPropertyChild(effect, envProp, "scale-rgb"))) {
+ result->setScale_RGB(p->getValue<float>());
+ }
+ if ((p = getEffectPropertyChild(effect, envProp, "scale-alpha"))) {
+ result->setScale_Alpha(p->getValue<float>());
+ }
+#if 0
+ if ((p = getEffectPropertyChild(effect, envProp, "constant-color"))) {
+ SGVec4d color = p->getValue<SGVec4d>();
+ result->setConstantColor(toOsg(color));
+ } else if ((p = getEffectPropertyChild(effect, envProp,
+ "light-direction"))) {
+ SGVec3d direction = p->getValue<SGVec3d>();
+ result->setConstantColorAsLightDirection(toOsg(direction));
+ }
+#endif
+ const SGPropertyNode* colorNode = envProp->getChild("constant-color");
+ if (colorNode)
+ initFromParameters(effect, colorNode, result,
+ &TexEnvCombine::setConstantColor, colorFields);
+ return result;
+}
+
+EffectNameValue<TexGen::Mode> tgenModeInit[] =
+{
+ { "object-linear", TexGen::OBJECT_LINEAR},
+ { "eye-linear", TexGen::EYE_LINEAR},
+ { "sphere-map", TexGen::SPHERE_MAP},
+ { "normal-map", TexGen::NORMAL_MAP},
+ { "reflection-map", TexGen::REFLECTION_MAP}
+};
+
+EffectPropertyMap<TexGen::Mode> tgenModes(tgenModeInit);
+
+EffectNameValue<TexGen::Coord> tgenCoordInit[] =
+{
+ {"s", TexGen::S},
+ {"t", TexGen::T},
+ {"r", TexGen::R},
+ {"q", TexGen::Q}
+};
+
+EffectPropertyMap<TexGen::Coord> tgenCoords(tgenCoordInit);
+
+TexGen* buildTexGen(Effect* effect, const SGPropertyNode* tgenProp)
+{
+ if (!isAttributeActive(effect, tgenProp))
+ return 0;
+ TexGen* result = new TexGen;
+ const SGPropertyNode* p = 0;
+ TexGen::Mode mode = TexGen::OBJECT_LINEAR;
+ if (findAttr(tgenModes, getEffectPropertyChild(effect, tgenProp, "mode"),
+ mode))
+ result->setMode(mode);
+ const SGPropertyNode* planesNode = tgenProp->getChild("planes");
+ if (planesNode) {
+ for (int i = 0; i < planesNode->nChildren(); ++i) {
+ const SGPropertyNode* planeNode = planesNode->getChild(i);
+ TexGen::Coord coord;
+ if (!findAttr(tgenCoords, planeNode->getName(), coord)) {
+ SG_LOG(SG_INPUT, SG_ALERT, "Unknown TexGen plane "
+ << planeNode->getName());
+ } else {
+ const SGPropertyNode* realNode
+ = getEffectPropertyNode(effect, planeNode);
+ SGVec4d plane = realNode->getValue<SGVec4d>();
+ result->setPlane(coord, toOsg(plane));
+ }
+ }
+ }
+ return result;
+}
+
bool makeTextureParameters(SGPropertyNode* paramRoot, const StateSet* ss)
{
SGPropertyNode* texUnit = makeChild(paramRoot, "texture");
const SGPropertyNode* inheritProp = prop->getChild("inherits-from");
Effect* parent = 0;
if (inheritProp) {
- parent = makeEffect(inheritProp->getStringValue(), realizeTechniques,
+ parent = makeEffect(inheritProp->getStringValue(), false,
options);
if(parent)
{
# include <simgear_config.h>
#endif
+#include <algorithm>
+//yuck
+#include <cstring>
+
+#include <boost/bind.hpp>
+
#include <osg/Geode>
#include <osg/MatrixTransform>
#include <osgDB/WriteFile>
private:
osg::ref_ptr<osg::Referenced> mReferenced;
};
+
+void makeEffectAnimations(PropertyList& animation_nodes,
+ PropertyList& effect_nodes)
+{
+ for (PropertyList::iterator itr = animation_nodes.begin();
+ itr != animation_nodes.end();
+ ++itr) {
+ SGPropertyNode* animProp = itr->ptr();
+ SGPropertyNode* typeProp = animProp->getChild("type");
+ if (!typeProp || strcmp(typeProp->getStringValue(), "shader"))
+ continue;
+ SGPropertyNode* shaderProp = animProp->getChild("shader");
+ if (!shaderProp || strcmp(shaderProp->getStringValue(), "chrome"))
+ continue;
+ *itr = 0;
+ SGPropertyNode* textureProp = animProp->getChild("texture");
+ if (!textureProp)
+ continue;
+ SGPropertyNode_ptr effectProp = new SGPropertyNode();
+ makeChild(effectProp.ptr(), "inherits-from")
+ ->setValue("Effects/chrome");
+ SGPropertyNode* paramsProp = makeChild(effectProp.get(), "parameters");
+ makeChild(paramsProp, "chrome-texture")
+ ->setValue(textureProp->getStringValue());
+ PropertyList objectNameNodes = animProp->getChildren("object-name");
+ for (PropertyList::iterator objItr = objectNameNodes.begin(),
+ end = objectNameNodes.end();
+ objItr != end;
+ ++objItr)
+ effectProp->addChild("object-name")
+ ->setStringValue((*objItr)->getStringValue());
+ effect_nodes.push_back(effectProp);
+ }
+ animation_nodes.erase(remove_if(animation_nodes.begin(),
+ animation_nodes.end(),
+ !boost::bind(&SGPropertyNode_ptr::valid,
+ _1)),
+ animation_nodes.end());
+}
}
static osg::Node *
options.get()));
}
PropertyList effect_nodes = props->getChildren("effect");
+ PropertyList animation_nodes = props->getChildren("animation");
+ // Some material animations (eventually all) are actually effects.
+ makeEffectAnimations(animation_nodes, effect_nodes);
{
ref_ptr<Node> modelWithEffects
= instantiateEffects(group.get(), effect_nodes, options.get());
group = static_cast<Group*>(modelWithEffects.get());
}
- std::vector<SGPropertyNode_ptr> animation_nodes;
- animation_nodes = props->getChildren("animation");
for (unsigned i = 0; i < animation_nodes.size(); ++i)
/// OSGFIXME: duh, why not only model?????
SGAnimation::animate(group.get(), animation_nodes[i], prop_root,
: _options(options)
{
}
- virtual void apply(osg::Node& node);
+ virtual void apply(osg::Group& node);
virtual void apply(osg::Geode& geode);
EffectMap& getEffectMap() { return _effectMap; }
const EffectMap& getEffectMap() const { return _effectMap; }
osg::ref_ptr<const osgDB::ReaderWriter::Options> _options;
};
-void MakeEffectVisitor::apply(osg::Node& node)
+void MakeEffectVisitor::apply(osg::Group& node)
{
SGPropertyNode_ptr savedEffectRoot;
const string& nodeName = node.getName();
RenderConstants.hxx \
SplicingVisitor.hxx \
StateAttributeFactory.hxx \
+ UpdateOnceCallback.hxx \
VectorArrayAdapter.hxx
PrimitiveUtils.cxx \
SplicingVisitor.cxx \
StateAttributeFactory.cxx \
- QuadTreeBuilder.cxx
+ QuadTreeBuilder.cxx \
+ UpdateOnceCallback.cxx
INCLUDES = -I$(top_srcdir)
--- /dev/null
+// UpdateOnceCallback.hxx
+//
+// Copyright (C) 2009 Tim Moore timoore@redhat.com
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+
+#include "UpdateOnceCallback.hxx"
+
+#include <osg/Node>
+
+namespace simgear
+{
+using namespace osg;
+
+void UpdateOnceCallback::operator()(Node* node, NodeVisitor* nv)
+{
+ doUpdate(node, nv);
+ node->removeUpdateCallback(this);
+ // The callback could be deleted now.
+}
+
+void UpdateOnceCallback::doUpdate(Node* node, NodeVisitor* nv)
+{
+ traverse(node, nv);
+}
+}
--- /dev/null
+// UpdateOnceCallback.hxx
+//
+// Copyright (C) 2009 Tim Moore timoore@redhat.com
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Library General Public
+// License as published by the Free Software Foundation; either
+// version 2 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Library General Public License for more details.
+//
+// You should have received a copy of the GNU Library General Public
+// License along with this library; if not, write to the
+// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+// Boston, MA 02111-1307, USA.
+
+#ifndef SIMGEAR_UPDATEONCECALLBACK_HXX
+#define SIMGEAR_UPDATEONCECALLBACK_HXX 1
+#include <osg/NodeCallback>
+
+namespace simgear
+{
+class UpdateOnceCallback : public osg::NodeCallback
+{
+public:
+ UpdateOnceCallback() {}
+ UpdateOnceCallback(const UpdateOnceCallback& nc, const osg::CopyOp& copyop)
+ : osg::NodeCallback(nc, copyop)
+ {
+ }
+
+ META_Object(simgear,UpdateOnceCallback);
+
+ virtual void doUpdate(osg::Node* node, osg::NodeVisitor* nv);
+ /**
+ * Do not override; use doUpdate instead!
+ */
+ virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
+};
+}
+#endif