#include <functional>
#include <iterator>
#include <map>
+#include <queue>
#include <utility>
#include <boost/tr1/unordered_map.hpp>
#include <simgear/structure/OSGUtils.hxx>
#include <simgear/structure/SGExpression.hxx>
#include <simgear/props/vectorPropTemplates.hxx>
-
+#include <simgear/threads/SGThread.hxx>
+#include <simgear/threads/SGGuard.hxx>
namespace simgear
{
Uniform::Type uniformType,
SGConstPropertyNode_ptr valProp,
const SGReaderWriterOptions* options );
+ void updateListeners( SGPropertyNode* propRoot );
+ void addListener(DeferredPropertyListener* listener);
private:
// Default names for vector property components
static const char* vec3Names[];
static const char* vec4Names[];
- std::map<std::string,ref_ptr<Uniform> > uniformCache;
+ SGMutex _mutex;
+
+ typedef boost::tuple<std::string, Uniform::Type, std::string> UniformCacheKey;
+ typedef boost::tuple<ref_ptr<Uniform>, SGPropertyChangeListener*> UniformCacheValue;
+ //std::map<UniformCacheKey,UniformCacheValue > uniformCache;
+ std::map<UniformCacheKey,ref_ptr<Uniform> > uniformCache;
+
+ typedef std::queue<DeferredPropertyListener*> DeferredListenerList;
+ DeferredListenerList deferredListenerList;
};
const char* UniformFactoryImpl::vec3Names[] = {"x", "y", "z"};
SGConstPropertyNode_ptr valProp,
const SGReaderWriterOptions* options )
{
-
- ref_ptr<Uniform> uniform = uniformCache[name];
- if( !uniform.valid() ) {
- SG_LOG(SG_ALL,SG_ALERT,"new uniform '" << name << "'");
- uniformCache[name] = uniform = new Uniform;
- } else {
- SG_LOG(SG_ALL,SG_ALERT,"reusing uniform '" << name << "'");
- return uniform;
+ SGGuard<SGMutex> scopeLock(_mutex);
+ std::string val = "0";
+
+ if (valProp->nChildren() == 0) {
+ // Completely static value
+ val = valProp->getStringValue();
+ } else {
+ // Value references <parameters> section of Effect
+ const SGPropertyNode* prop = getEffectPropertyNode(effect, valProp);
+
+ if (prop) {
+ if (prop->nChildren() == 0) {
+ // Static value in parameters section
+ val = prop->getStringValue();
+ } else {
+ // Dynamic property value in parameters section
+ val = getGlobalProperty(prop, options);
+ }
+ } else {
+ SG_LOG(SG_GL,SG_DEBUG,"Invalid parameter " << valProp->getName() << " for uniform " << name << " in Effect ");
+ }
+ }
+
+ UniformCacheKey key = boost::make_tuple(name, uniformType, val);
+ //UniformCacheValue value = uniformCache[key];
+ //ref_ptr<Uniform> uniform = value.get_head();
+ ref_ptr<Uniform> uniform = uniformCache[key];
+
+ if (uniform.valid()) {
+ // We've got a hit to cache - simply return it
+ return uniform;
}
+ SG_LOG(SG_GL,SG_DEBUG,"new uniform " << name << " value " << uniformCache.size());
+ uniformCache[key] = uniform = new Uniform;
+ DeferredPropertyListener* updater = 0;
+
uniform->setName(name);
uniform->setType(uniformType);
switch (uniformType) {
case Uniform::BOOL:
- initFromParameters(effect, valProp, uniform.get(),
+ updater = initFromParameters(effect, valProp, uniform.get(),
static_cast<bool (Uniform::*)(bool)>(&Uniform::set),
options);
break;
case Uniform::FLOAT:
- initFromParameters(effect, valProp, uniform.get(),
+ updater = initFromParameters(effect, valProp, uniform.get(),
static_cast<bool (Uniform::*)(float)>(&Uniform::set),
options);
break;
case Uniform::FLOAT_VEC3:
- initFromParameters(effect, valProp, uniform.get(),
+ updater = initFromParameters(effect, valProp, uniform.get(),
static_cast<bool (Uniform::*)(const Vec3&)>(&Uniform::set),
vec3Names, options);
break;
case Uniform::FLOAT_VEC4:
- initFromParameters(effect, valProp, uniform.get(),
+ updater = initFromParameters(effect, valProp, uniform.get(),
static_cast<bool (Uniform::*)(const Vec4&)>(&Uniform::set),
vec4Names, options);
break;
case Uniform::SAMPLER_1D_SHADOW:
case Uniform::SAMPLER_2D_SHADOW:
case Uniform::SAMPLER_CUBE:
- initFromParameters(effect, valProp, uniform.get(),
+ updater = initFromParameters(effect, valProp, uniform.get(),
static_cast<bool (Uniform::*)(int)>(&Uniform::set),
options);
break;
default: // avoid compiler warning
+ SG_LOG(SG_ALL,SG_ALERT,"UNKNOWN Uniform type '" << uniformType << "'");
break;
}
+ addListener(updater);
return uniform;
}
+void UniformFactoryImpl::addListener(DeferredPropertyListener* listener)
+{
+ if (listener != 0) {
+ // Uniform requires a property listener. Add it to the list to be
+ // created when the main thread gets to it.
+ deferredListenerList.push(listener);
+ }
+}
+
+void UniformFactoryImpl::updateListeners( SGPropertyNode* propRoot )
+{
+ SGGuard<SGMutex> scopeLock(_mutex);
+
+ if (deferredListenerList.empty()) return;
+
+ SG_LOG(SG_GL,SG_DEBUG,"Adding " << deferredListenerList.size() << " listeners for effects.");
+
+ // Instantiate all queued listeners
+ while (! deferredListenerList.empty()) {
+ DeferredPropertyListener* listener = deferredListenerList.front();
+ listener->activate(propRoot);
+ deferredListenerList.pop();
+ }
+}
typedef Singleton<UniformFactoryImpl> UniformFactory;
techniques.push_back(static_cast<Technique*>(copyop(itr->get())));
generator = rhs.generator;
+ _name = rhs._name;
+ _name += " clone";
}
// Assume that the last technique is always valid.
if (!effect)
return;
SGPropertyNode* root = getPropertyRoot();
+
+ // Initialize all queued listeners
+ UniformFactory::instance()->updateListeners(root);
+
for (vector<SGSharedPtr<Updater> >::iterator itr = effect->_extraData.begin(),
end = effect->_extraData.end();
itr != end;
template<typename OSGParamType, typename ObjType, typename F>
class ScalarChangeListener
- : public SGPropertyChangeListener, public InitializeWhenAdded,
- public Effect::Updater
+ : public SGPropertyChangeListener, public DeferredPropertyListener
{
public:
ScalarChangeListener(ObjType* obj, const F& setter,
: _obj(obj), _setter(setter)
{
_propName = new std::string(propName);
+ SG_LOG(SG_GL,SG_DEBUG,"Creating ScalarChangeListener for " << *_propName );
}
virtual ~ScalarChangeListener()
{
{
_setter(_obj.get(), node->getValue<OSGParamType>());
}
- void initOnAddImpl(Effect* effect, SGPropertyNode* propRoot)
+ void activate(SGPropertyNode* propRoot)
{
- SG_LOG(SG_ALL,SG_ALERT,"Adding change listener to " << *_propName );
+ SG_LOG(SG_GL,SG_DEBUG,"Adding change listener to " << *_propName );
SGPropertyNode* listenProp = makeNode(propRoot, *_propName);
delete _propName;
_propName = 0;
};
template<typename T, typename Func>
-class EffectExtendedPropListener : public InitializeWhenAdded,
- public Effect::Updater
+class EffectExtendedPropListener : public DeferredPropertyListener
{
public:
template<typename Itr>
delete _propName;
delete _childNames;
}
- void initOnAddImpl(Effect* effect, SGPropertyNode* propRoot)
+ void activate(SGPropertyNode* propRoot)
{
SGPropertyNode* parent = 0;
if (_propName)
};
template<typename T, typename Func, typename Itr>
-Effect::Updater*
+DeferredPropertyListener*
new_EEPropListener(const Func& func, const std::string* propName,
const Itr& namesBegin, const Itr& namesEnd)
{
* used.
*/
template<typename OSGParamType, typename ObjType, typename F>
-void
+DeferredPropertyListener*
initFromParameters(Effect* effect, const SGPropertyNode* prop, ObjType* obj,
const F& setter, const SGReaderWriterOptions* options)
{
const SGPropertyNode* valProp = getEffectPropertyNode(effect, prop);
+ ScalarChangeListener<OSGParamType, ObjType, F>* listener = 0;
if (!valProp)
- return;
+ return listener;
if (valProp->nChildren() == 0) {
setter(obj, valProp->getValue<OSGParamType>());
} else {
setDynamicVariance(obj);
std::string propName = getGlobalProperty(valProp, options);
- ScalarChangeListener<OSGParamType, ObjType, F>* listener
+ listener
= new ScalarChangeListener<OSGParamType, ObjType, F>(obj, setter,
propName);
- effect->addUpdater(listener);
}
+ return listener;
}
template<typename OSGParamType, typename ObjType, typename SetterReturn>
-inline void
+inline DeferredPropertyListener*
initFromParameters(Effect* effect, const SGPropertyNode* prop, ObjType* obj,
SetterReturn (ObjType::*setter)(const OSGParamType),
const SGReaderWriterOptions* options)
{
- initFromParameters<OSGParamType>(effect, prop, obj,
+ return initFromParameters<OSGParamType>(effect, prop, obj,
boost::bind(setter, _1, _2), options);
}
*/
template<typename OSGParamType, typename ObjType, typename NameItrType,
typename F>
-void
+DeferredPropertyListener*
initFromParameters(Effect* effect, const SGPropertyNode* prop, ObjType* obj,
const F& setter,
NameItrType nameItr, const SGReaderWriterOptions* options)
{
typedef typename Bridge<OSGParamType>::sg_type sg_type;
+ DeferredPropertyListener* listener = 0;
const int numComponents = props::NumComponents<sg_type>::num_components;
const SGPropertyNode* valProp = getEffectPropertyNode(effect, prop);
if (!valProp)
- return;
+ return listener;
if (valProp->nChildren() == 0) { // Has <use>?
setter(obj, Bridge<OSGParamType>::get(valProp->getValue<sg_type>()));
} else {
if (paramNames.empty())
throw BuilderException();
std::vector<std::string>::const_iterator pitr = paramNames.begin();
- Effect::Updater* listener
+ listener
= new_EEPropListener<sg_type>(make_OSGFunctor<OSGParamType>
(obj, setter),
0, pitr, pitr + numComponents);
- effect->addUpdater(listener);
}
+ return listener;
}
template<typename OSGParamType, typename ObjType, typename NameItrType,
typename SetterReturn>
-inline void
+inline DeferredPropertyListener*
initFromParameters(Effect* effect, const SGPropertyNode* prop, ObjType* obj,
SetterReturn (ObjType::*setter)(const OSGParamType&),
NameItrType nameItr, const SGReaderWriterOptions* options)
{
- initFromParameters<OSGParamType>(effect, prop, obj,
+ return initFromParameters<OSGParamType>(effect, prop, obj,
boost::bind(setter, _1, _2), nameItr,
options);
}