Effects in models working for transparent materials and chrome animation

Implementation of animated effect values via the property system.

Add names for TexEnvCombine attributes
This commit is contained in:
Tim Moore 2009-10-16 12:54:46 +02:00
parent cb07210bc7
commit 54c4055af3
20 changed files with 958 additions and 17 deletions

View File

@ -643,6 +643,15 @@
<Filter <Filter
Name="Lib_sgprops" Name="Lib_sgprops"
Filter=""> Filter="">
<File
RelativePath="..\..\simgear\props\AtomicChangeListener.cxx">
</File>
<File
RelativePath="..\..\simgear\props\AtomicChangeListener.hxx">
</File>
<File
RelativePath="..\..\simgear\props\ExtendedPropertyAdapter.hxx">
</File>
<File <File
RelativePath="..\..\simgear\props\condition.cxx"> RelativePath="..\..\simgear\props\condition.cxx">
</File> </File>
@ -1249,6 +1258,12 @@
<File <File
RelativePath="..\..\simgear\scene\util\StateAttributeFactory.hxx"> RelativePath="..\..\simgear\scene\util\StateAttributeFactory.hxx">
</File> </File>
<File
RelativePath="..\..\simgear\scene\util\UpdateOnceCallback.cxx">
</File>
<File
RelativePath="..\..\simgear\scene\util\UpdateOnceCallback.hxx">
</File>
</Filter> </Filter>
<Filter <Filter
Name="Lib_sgbvh" Name="Lib_sgbvh"

View File

@ -983,6 +983,14 @@
<Filter <Filter
Name="Lib_sgprops" Name="Lib_sgprops"
> >
<File
RelativePath="..\..\simgear\props\AtomicChangeListener.cxx"
>
</File>
<File
RelativePath="..\..\simgear\props\AtomicChangeListener.hxx"
>
</File>
<File <File
RelativePath="..\..\simgear\props\condition.cxx" RelativePath="..\..\simgear\props\condition.cxx"
> >
@ -991,6 +999,11 @@
RelativePath="..\..\simgear\props\condition.hxx" RelativePath="..\..\simgear\props\condition.hxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\props\ExtendedPropertyAdapter.hxx"
>
</File>
<File <File
RelativePath="..\..\simgear\props\props.cxx" RelativePath="..\..\simgear\props\props.cxx"
> >
@ -1809,6 +1822,14 @@
RelativePath="..\..\simgear\scene\util\StateAttributeFactory.hxx" RelativePath="..\..\simgear\scene\util\StateAttributeFactory.hxx"
> >
</File> </File>
<File
RelativePath="..\..\simgear\scene\util\UpdateOnceCallback.cxx"
>
</File>
<File
RelativePath="..\..\simgear\scene\util\UpdateOnceCallback.hxx"
>
</File>
</Filter> </Filter>
<Filter <Filter
Name="Lib_sgbvh" Name="Lib_sgbvh"

View File

@ -0,0 +1,71 @@
#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()
{
}
}

View File

@ -0,0 +1,105 @@
#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

View File

@ -0,0 +1,72 @@
#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

View File

@ -5,12 +5,15 @@ lib_LIBRARIES = libsgprops.a
include_HEADERS = \ include_HEADERS = \
condition.hxx \ condition.hxx \
props.hxx \ props.hxx \
props_io.hxx props_io.hxx \
AtomicChangeListener.hxx \
ExtendedPropertyAdapter.hxx
libsgprops_a_SOURCES = \ libsgprops_a_SOURCES = \
condition.cxx \ condition.cxx \
props.cxx \ props.cxx \
props_io.cxx props_io.cxx \
AtomicChangeListener.cxx
noinst_PROGRAMS = props_test noinst_PROGRAMS = props_test

View File

@ -1927,13 +1927,26 @@ inline bool SGPropertyNode::setValue(const T& val,
} }
/** /**
* 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, inline SGPropertyNode* makeChild(SGPropertyNode* parent, const char* name,
int index = 0) int index = 0)
{ {
return parent->getChild(name, index, true); 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 #endif // __PROPS_HXX
// end of props.hxx // end of props.hxx

View File

@ -20,6 +20,7 @@
#include "Effect.hxx" #include "Effect.hxx"
#include "EffectBuilder.hxx" #include "EffectBuilder.hxx"
#include "EffectGeode.hxx"
#include "Technique.hxx" #include "Technique.hxx"
#include "Pass.hxx" #include "Pass.hxx"
#include "TextureBuilder.hxx" #include "TextureBuilder.hxx"
@ -856,6 +857,8 @@ bool makeParametersFromStateSet(SGPropertyNode* effectRoot, const StateSet* ss)
} else { } else {
makeChild(blendNode, "active")->setValue(false); makeChild(blendNode, "active")->setValue(false);
} }
string renderingHint = findName(renderingHints, ss->getRenderingHint());
makeChild(paramRoot, "rendering-hint")->setStringValue(renderingHint);
makeTextureParameters(paramRoot, ss); makeTextureParameters(paramRoot, ss);
return true; return true;
} }
@ -872,6 +875,26 @@ bool Effect::realizeTechniques(const osgDB::ReaderWriter::Options* options)
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) bool Effect_writeLocalData(const Object& obj, osgDB::Output& fw)
{ {
const Effect& effect = static_cast<const Effect&>(obj); const Effect& effect = static_cast<const Effect&>(obj);

View File

@ -24,6 +24,7 @@
#include <osgDB/ReaderWriter> #include <osgDB/ReaderWriter>
#include <simgear/props/props.hxx> #include <simgear/props/props.hxx>
#include <simgear/scene/util/UpdateOnceCallback.hxx>
namespace osg namespace osg
{ {
@ -40,6 +41,32 @@ class CullVisitor;
namespace simgear namespace simgear
{ {
class Technique; 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 class Effect : public osg::Object
{ {
@ -56,12 +83,30 @@ public:
Technique* chooseTechnique(osg::RenderInfo* renderInfo); Technique* chooseTechnique(osg::RenderInfo* renderInfo);
virtual void resizeGLObjectBuffers(unsigned int maxSize); virtual void resizeGLObjectBuffers(unsigned int maxSize);
virtual void releaseGLObjects(osg::State* state = 0) const; virtual void releaseGLObjects(osg::State* state = 0) const;
/* /**
* Build the techniques from the effect properties. * Build the techniques from the effect properties.
*/ */
bool realizeTechniques(const osgDB::ReaderWriter::Options* options = 0); 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: protected:
std::vector<SGSharedPtr<Updater> > _extraData;
~Effect(); ~Effect();
}; };
Effect* makeEffect(const std::string& name, Effect* makeEffect(const std::string& name,

View File

@ -2,6 +2,8 @@
# include <simgear_config.h> # include <simgear_config.h>
#endif #endif
#include <simgear/scene/tgdb/userdata.hxx>
#include <simgear/math/SGMath.hxx> #include <simgear/math/SGMath.hxx>
#include "EffectBuilder.hxx" #include "EffectBuilder.hxx"
@ -39,6 +41,16 @@ const SGPropertyNode* getEffectPropertyChild(Effect* effect,
return getEffectPropertyNode(effect, child); 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() BuilderException::BuilderException()
{ {
} }
@ -66,4 +78,8 @@ bool isAttributeActive(Effect* effect, const SGPropertyNode* prop)
return !activeProp || activeProp->getValue<bool>(); return !activeProp || activeProp->getValue<bool>();
} }
namespace effect
{
const char* colorFields[] = {"red", "green", "blue", "alpha"};
}
} }

View File

@ -18,21 +18,26 @@
#define SIMGEAR_EFFECTBUILDER_HXX 1 #define SIMGEAR_EFFECTBUILDER_HXX 1
#include <algorithm> #include <algorithm>
#include <iterator>
#include <map> #include <map>
#include <string> #include <string>
#include <cstring> #include <cstring>
#include <osgDB/Registry> #include <osgDB/Registry>
#include <boost/bind.hpp>
#include <boost/multi_index_container.hpp> #include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp> #include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.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/props/props.hxx>
#include <simgear/structure/exception.hxx> #include <simgear/structure/exception.hxx>
#include <simgear/structure/SGSharedPtr.hxx> #include <simgear/structure/SGSharedPtr.hxx>
#include <simgear/structure/Singleton.hxx> #include <simgear/structure/Singleton.hxx>
#include "Effect.hxx"
/** /**
* Support classes for parsing effects. * Support classes for parsing effects.
*/ */
@ -153,15 +158,10 @@ EffectPropertyMap<T>::EffectPropertyMap(const EffectNameValue<T> (&attrs)[N])
template<typename T> template<typename T>
bool findAttr(const effect::EffectPropertyMap<T>& pMap, bool findAttr(const effect::EffectPropertyMap<T>& pMap,
const SGPropertyNode* prop, const char* name,
T& result) T& result)
{ {
using namespace effect; using namespace effect;
if (!prop)
return false;
const char* name = prop->getStringValue();
if (!name)
return false;
typename EffectPropertyMap<T>::BMap::iterator itr typename EffectPropertyMap<T>::BMap::iterator itr
= pMap._map.get<from>().find(name); = pMap._map.get<from>().find(name);
if (itr == pMap._map.end()) { if (itr == pMap._map.end()) {
@ -172,6 +172,27 @@ bool findAttr(const effect::EffectPropertyMap<T>& pMap,
} }
} }
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> template<typename T>
std::string findName(const effect::EffectPropertyMap<T>& pMap, T value) std::string findName(const effect::EffectPropertyMap<T>& pMap, T value)
{ {
@ -205,6 +226,14 @@ const SGPropertyNode* getEffectPropertyChild(Effect* effect,
const SGPropertyNode* prop, const SGPropertyNode* prop,
const char* name); 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 class BuilderException : public sg_exception
{ {
public: public:
@ -257,5 +286,190 @@ struct InstallAttributeBuilder
// false, the OSG attribute is not built at all. This is different // false, the OSG attribute is not built at all. This is different
// from any OSG mode settings that might be around. // from any OSG mode settings that might be around.
bool isAttributeActive(Effect* effect, const SGPropertyNode* prop); 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 #endif

View File

@ -44,6 +44,14 @@ EffectGeode::EffectGeode(const EffectGeode& rhs, const osg::CopyOp& copyop) :
{ {
} }
void EffectGeode::setEffect(Effect* effect)
{
_effect = effect;
if (!_effect)
return;
addUpdateCallback(new Effect::InitializeCallback);
}
void EffectGeode::resizeGLObjectBuffers(unsigned int maxSize) void EffectGeode::resizeGLObjectBuffers(unsigned int maxSize)
{ {
if (_effect.valid()) if (_effect.valid())

View File

@ -31,7 +31,7 @@ public:
const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY); const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
META_Node(simgear,EffectGeode); META_Node(simgear,EffectGeode);
Effect* getEffect() const { return _effect.get(); } Effect* getEffect() const { return _effect.get(); }
void setEffect(Effect* effect) { _effect = effect; } void setEffect(Effect* effect);
virtual void resizeGLObjectBuffers(unsigned int maxSize); virtual void resizeGLObjectBuffers(unsigned int maxSize);
virtual void releaseGLObjects(osg::State* = 0) const; virtual void releaseGLObjects(osg::State* = 0) const;
typedef DrawableList::iterator DrawablesIterator; typedef DrawableList::iterator DrawablesIterator;

View File

@ -24,6 +24,7 @@
#include <osg/TexEnv> #include <osg/TexEnv>
#include <osg/TexEnvCombine> #include <osg/TexEnvCombine>
#include <osg/TexGen>
#include <osg/Texture1D> #include <osg/Texture1D>
#include <osg/Texture2D> #include <osg/Texture2D>
#include <osg/Texture3D> #include <osg/Texture3D>
@ -48,6 +49,10 @@ using namespace osg;
using namespace effect; 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 // Hack to force inclusion of TextureBuilder.cxx in library
osg::Texture* TextureBuilder::buildFromType(Effect* effect, const string& type, osg::Texture* TextureBuilder::buildFromType(Effect* effect, const string& type,
const SGPropertyNode*props, const SGPropertyNode*props,
@ -134,6 +139,14 @@ void TextureUnitBuilder::buildAttribute(Effect* effect, Pass* pass,
if (env) if (env)
pass->setTextureAttributeAndModes(unit, 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 // InstallAttributeBuilder call is in Effect.cxx to force this file to
@ -366,6 +379,197 @@ namespace
TextureBuilder::Registrar installNoise("noise", new NoiseBuilder); 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) bool makeTextureParameters(SGPropertyNode* paramRoot, const StateSet* ss)
{ {
SGPropertyNode* texUnit = makeChild(paramRoot, "texture"); SGPropertyNode* texUnit = makeChild(paramRoot, "texture");

View File

@ -170,7 +170,7 @@ Effect* makeEffect(SGPropertyNode* prop,
const SGPropertyNode* inheritProp = prop->getChild("inherits-from"); const SGPropertyNode* inheritProp = prop->getChild("inherits-from");
Effect* parent = 0; Effect* parent = 0;
if (inheritProp) { if (inheritProp) {
parent = makeEffect(inheritProp->getStringValue(), realizeTechniques, parent = makeEffect(inheritProp->getStringValue(), false,
options); options);
if(parent) if(parent)
{ {

View File

@ -20,6 +20,12 @@
# include <simgear_config.h> # include <simgear_config.h>
#endif #endif
#include <algorithm>
//yuck
#include <cstring>
#include <boost/bind.hpp>
#include <osg/Geode> #include <osg/Geode>
#include <osg/MatrixTransform> #include <osg/MatrixTransform>
#include <osgDB/WriteFile> #include <osgDB/WriteFile>
@ -132,6 +138,45 @@ public:
private: private:
osg::ref_ptr<osg::Referenced> mReferenced; 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 * static osg::Node *
@ -368,13 +413,14 @@ sgLoad3DModel_internal(const string &path,
options.get())); options.get()));
} }
PropertyList effect_nodes = props->getChildren("effect"); 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 ref_ptr<Node> modelWithEffects
= instantiateEffects(group.get(), effect_nodes, options.get()); = instantiateEffects(group.get(), effect_nodes, options.get());
group = static_cast<Group*>(modelWithEffects.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) for (unsigned i = 0; i < animation_nodes.size(); ++i)
/// OSGFIXME: duh, why not only model????? /// OSGFIXME: duh, why not only model?????
SGAnimation::animate(group.get(), animation_nodes[i], prop_root, SGAnimation::animate(group.get(), animation_nodes[i], prop_root,

View File

@ -212,7 +212,7 @@ public:
: _options(options) : _options(options)
{ {
} }
virtual void apply(osg::Node& node); virtual void apply(osg::Group& node);
virtual void apply(osg::Geode& geode); virtual void apply(osg::Geode& geode);
EffectMap& getEffectMap() { return _effectMap; } EffectMap& getEffectMap() { return _effectMap; }
const EffectMap& getEffectMap() const { return _effectMap; } const EffectMap& getEffectMap() const { return _effectMap; }
@ -227,7 +227,7 @@ protected:
osg::ref_ptr<const osgDB::ReaderWriter::Options> _options; osg::ref_ptr<const osgDB::ReaderWriter::Options> _options;
}; };
void MakeEffectVisitor::apply(osg::Node& node) void MakeEffectVisitor::apply(osg::Group& node)
{ {
SGPropertyNode_ptr savedEffectRoot; SGPropertyNode_ptr savedEffectRoot;
const string& nodeName = node.getName(); const string& nodeName = node.getName();

View File

@ -21,6 +21,7 @@ include_HEADERS = \
RenderConstants.hxx \ RenderConstants.hxx \
SplicingVisitor.hxx \ SplicingVisitor.hxx \
StateAttributeFactory.hxx \ StateAttributeFactory.hxx \
UpdateOnceCallback.hxx \
VectorArrayAdapter.hxx VectorArrayAdapter.hxx
@ -35,6 +36,7 @@ libsgutil_a_SOURCES = \
PrimitiveUtils.cxx \ PrimitiveUtils.cxx \
SplicingVisitor.cxx \ SplicingVisitor.cxx \
StateAttributeFactory.cxx \ StateAttributeFactory.cxx \
QuadTreeBuilder.cxx QuadTreeBuilder.cxx \
UpdateOnceCallback.cxx
INCLUDES = -I$(top_srcdir) INCLUDES = -I$(top_srcdir)

View File

@ -0,0 +1,39 @@
// 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);
}
}

View File

@ -0,0 +1,44 @@
// 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