--- /dev/null
+#include "Effect.hxx"
+#include "Technique.hxx"
+
+#include <algorithm>
+#include <functional>
+#include <iterator>
+
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+
+#include <osg/Drawable>
+#include <osg/RenderInfo>
+#include <osg/StateSet>
+
+#include <osgUtil/CullVisitor>
+
+#include <simgear/structure/OSGUtils.hxx>
+
+
+
+namespace simgear
+{
+using namespace osg;
+using namespace osgUtil;
+
+Effect::Effect(const Effect& rhs, const CopyOp& copyop)
+{
+ using namespace std;
+ using namespace boost;
+ transform(rhs.techniques.begin(), rhs.techniques.end(),
+ backRefInsertIterator(techniques),
+ bind(simgear::clone_ref<Technique>, _1, copyop));
+}
+// There should always be a valid technique in an effect.
+
+Technique* Effect::chooseTechnique(RenderInfo* info)
+{
+ BOOST_FOREACH(ref_ptr<Technique>& technique, techniques)
+ {
+ if (technique->valid(info) == Technique::VALID)
+ return technique.get();
+ }
+ return 0;
+}
+
+void Effect::resizeGLObjectBuffers(unsigned int maxSize)
+{
+ BOOST_FOREACH(const ref_ptr<Technique>& technique, techniques)
+ {
+ technique->resizeGLObjectBuffers(maxSize);
+ }
+}
+
+void Effect::releaseGLObjects(osg::State* state) const
+{
+ BOOST_FOREACH(const ref_ptr<Technique>& technique, techniques)
+ {
+ technique->releaseGLObjects(state);
+ }
+}
+}
--- /dev/null
+// Copyright (C) 2008 Timothy Moore timoore@redhat.com
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+#ifndef SIMGEAR_EFFECT_HXX
+#define SIMGEAR_EFFECT_HXX 1
+
+#include <vector>
+
+#include <osg/Object>
+
+namespace osg
+{
+class Drawable;
+class StateSet;
+class RenderInfo;
+}
+
+namespace osgUtil
+{
+class CullVisitor;
+}
+
+namespace simgear
+{
+class Technique;
+
+class Effect : public osg::Object
+{
+public:
+ META_Object(simgear,Effect)
+ Effect() {}
+ Effect(const Effect& rhs,
+ const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
+ osg::StateSet* getDefaultStateSet();
+ std::vector<osg::ref_ptr<Technique> > techniques;
+ Technique* chooseTechnique(osg::RenderInfo* renderInfo);
+ virtual void resizeGLObjectBuffers(unsigned int maxSize);
+ virtual void releaseGLObjects(osg::State* state = 0) const;
+protected:
+ ~Effect() {}
+};
+}
+#endif
--- /dev/null
+#include "EffectData.hxx"
+
--- /dev/null
+// Copyright (C) 2008 Timothy Moore timoore@redhat.com
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef SIMGEAR_EFFECT_DATA_HXX
+#define SIMGEAR_EFFECT_DATA_HXX 1
+
+#include <osg/Vec4f>
+
+#include "EffectElement.hxx"
+#include "EffectElementBuilder.hxx"
+
+namespace simgear
+{
+class ParamaterContext;
+
+template<typename T>
+class EffectData : public EffectElement
+{
+public:
+ EffectData() {}
+ EffectData(const EffectData& rhs) _value(rhs._value) {}
+ virtual ~EffectData() {}
+ T getValue(const ParameterContext*) const {return _value};
+ void setValue(const T& value) { _value = value; }
+private:
+ T _value;
+};
+
+typedef EffectData<float> EffectFloat;
+typedef EffectData<osg::Vec4f> EffectVec4f;
+
+
+}
+#endif
--- /dev/null
+// Copyright (C) 2008 Timothy Moore timoore@redhat.com
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef SIMGEAR_EFFECT_ELEMENT_HXX
+#define SIMGEAR_EFFECT_ELEMENT_HXX 1
+
+namespace simgear
+{
+class EffectElement
+{
+protected:
+ ~EffectElement() {}
+};
+}
+#endif
--- /dev/null
+// Copyright (C) 2008 Timothy Moore timoore@redhat.com
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef SIMGEAR_EFFECT_BUILDER_HXX
+#define SIMGEAR_EFFECT_BUILDER_HXX 1
+
+#include <simgear/xml/easyxml.hxx>
+#include "EffectElement.hxx"
+
+namespace simgear
+{
+class ElementBuilder;
+
+class EffectElementBuilder
+{
+public:
+ EffectElementBuilder(ElementBuilder* builder);
+ EffectElementBuilder(const EffectElementBuilder& rhs);
+ virtual ~EffectElementBuilder();
+ virtual void initialize(const XMLAttributes& attributes);
+ virtual void processSubElement(EffectElement* subElement);
+ virtual void processData(const char* data, int length);
+ virtual EffectElement* finalize();
+
+};
+}
+
+#endif
--- /dev/null
+// Copyright (C) 2008 Timothy Moore timoore@redhat.com
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#include "EffectGeode.hxx"
+#include "Effect.hxx"
+#include "Technique.hxx"
+
+#include <osgUtil/CullVisitor>
+
+namespace simgear
+{
+
+using namespace osg;
+using namespace osgUtil;
+
+void EffectGeode::traverse(NodeVisitor& nv)
+{
+ CullVisitor* cv = dynamic_cast<CullVisitor*>(&nv);
+ if (!cv || !_effect.valid()) {
+ Geode::traverse(nv);
+ return;
+ }
+ Technique* technique = _effect->chooseTechnique(&cv->getRenderInfo());
+ if (!technique) {
+ Geode::traverse(nv);
+ return;
+ }
+ for (DrawablesIterator beginItr = _drawables.begin();
+ beginItr != _drawables.end();
+ beginItr = technique->processDrawables(beginItr, _drawables.end(), cv,
+ isCullingActive()))
+ ;
+}
+
+void EffectGeode::resizeGLObjectBuffers(unsigned int maxSize)
+{
+ if (_effect.valid())
+ _effect->resizeGLObjectBuffers(maxSize);
+ Geode::resizeGLObjectBuffers(maxSize);
+}
+
+void EffectGeode::releaseGLObjects(osg::State* state) const
+{
+ if (_effect.valid())
+ _effect->releaseGLObjects(state);
+ Geode::releaseGLObjects(state);
+}
+
+}
--- /dev/null
+// Copyright (C) 2008 Timothy Moore timoore@redhat.com
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef SIMGEAR_EFFECT_GEODE_HXX
+#define SIMGEAR_EFFECT_GEODE_HXX 1
+
+#include <osg/Geode>
+
+#include "Effect.hxx"
+
+namespace simgear
+{
+class EffectGeode : public osg::Geode
+{
+public:
+ EffectGeode();
+ EffectGeode(const EffectGeode& rhs,
+ const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
+ META_Node(simgear,EffectGeode);
+ virtual void traverse(osg::NodeVisitor& nv);
+ Effect* getEffect() const { return _effect.get(); }
+ void setEffect(Effect* effect);
+ virtual void resizeGLObjectBuffers(unsigned int maxSize);
+ virtual void releaseGLObjects(osg::State* = 0) const;
+ typedef DrawableList::iterator DrawablesIterator;
+private:
+ osg::ref_ptr<Effect> _effect;
+};
+}
+#endif
--- /dev/null
+#include "ElementBuilder.hxx"
+
+
+
--- /dev/null
+#ifndef SIMGEAR_ELEMENT_BUILDER_HXX
+#define SIMGEAR_ELEMENT_BUILDER_HXX 1
+
+#include <simgear/xml/XMLStaticParser.hxx>
+
+namespace simgear
+{
+}
+#endif
noinst_HEADERS =
include_HEADERS = \
+ Effect.hxx \
+ EffectGeode.hxx \
+ Pass.hxx \
+ Technique.hxx \
mat.hxx \
matlib.hxx \
matmodel.hxx
libsgmaterial_a_SOURCES = \
+ Effect.cxx \
+ EffectGeode.cxx \
+ Pass.cxx \
+ Technique.cxx \
mat.cxx \
matlib.cxx \
matmodel.cxx
--- /dev/null
+#include "Pass.hxx"
+
+#include <simgear/structure/OSGUtils.hxx>
+
+#include <osg/StateSet>
+
+namespace simgear
+{
+
+Pass::Pass(const Pass& rhs, const osg::CopyOp& copyop) :
+ _stateSet(clone_ref(rhs._stateSet, copyop))
+{
+}
+
+void Pass::resizeGLObjectBuffers(unsigned int maxSize)
+{
+ if (_stateSet.valid())
+ _stateSet->resizeGLObjectBuffers(maxSize);
+}
+
+void Pass::releaseGLObjects(osg::State* state) const
+{
+ if (_stateSet.valid())
+ _stateSet->releaseGLObjects(state);
+}
+
+}
--- /dev/null
+// Copyright (C) 2008 Timothy Moore timoore@redhat.com
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef SIMGEAR_PASS_HXX
+#define SIMGEAR_PASS_HXX 1
+
+#include <osg/ref_ptr>
+#include <osg/Object>
+
+namespace osg
+{
+class StateSet;
+}
+
+namespace simgear
+{
+
+class Pass : public osg::Object
+{
+public:
+ META_Object(simgear,Pass);
+ Pass() {}
+ Pass(const Pass& rhs,
+ const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
+ osg::StateSet* getStateSet() { return _stateSet.get(); }
+ void setStateSet(osg::StateSet* stateSet) { _stateSet = stateSet; }
+ virtual void resizeGLObjectBuffers(unsigned int maxSize);
+ virtual void releaseGLObjects(osg::State* state = 0) const;
+protected:
+ osg::ref_ptr<osg::StateSet> _stateSet;
+};
+
+}
+
+#endif
--- /dev/null
+#include "Technique.hxx"
+#include "Pass.hxx"
+
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+
+#include <string>
+
+#include <osg/GLExtensions>
+#include <osg/Math>
+#include <osgUtil/CullVisitor>
+
+#include <simgear/structure/OSGUtils.hxx>
+
+namespace simgear
+{
+using namespace osg;
+using namespace osgUtil;
+
+namespace
+{
+
+struct ValidateOperation : GraphicsOperation
+{
+ ValidateOperation(Technique* technique_)
+ : GraphicsOperation(opName, false), technique(technique_)
+ {
+ }
+ virtual void operator() (GraphicsContext* gc);
+ osg::ref_ptr<Technique> technique;
+ static const std::string opName;
+};
+
+const std::string ValidateOperation::opName("ValidateOperation");
+
+
+void ValidateOperation::operator() (GraphicsContext* gc)
+{
+ technique->validateInContext(gc);
+}
+}
+
+Technique::Technique() : _glVersion(1.1f)
+{
+}
+
+Technique::Technique(const Technique& rhs, const osg::CopyOp& copyop) :
+ _contextMap(rhs._contextMap), _shadowingStateSet(rhs._shadowingStateSet),
+ _glVersion(rhs._glVersion)
+{
+ using namespace std;
+ using namespace boost;
+ transform(rhs.passes.begin(), rhs.passes.end(),
+ backRefInsertIterator(passes),
+ bind(simgear::clone_ref<Pass>, _1, copyop));
+
+}
+
+Technique::~Technique()
+{
+}
+
+Technique::Status Technique::valid(osg::RenderInfo* renderInfo)
+{
+ unsigned contextID = renderInfo->getContextID();
+ ContextInfo& contextInfo = _contextMap[contextID];
+ Status status = contextInfo.valid();
+ if (status != UNKNOWN)
+ return status;
+ Status newStatus = QUERY_IN_PROGRESS;
+ // lock and spawn validity check.
+ if (!contextInfo.valid.compareAndSwap(status, newStatus)) {
+ // Lost the race with another thread spawning a request
+ return contextInfo.valid();
+ }
+ ref_ptr<ValidateOperation> validOp = new ValidateOperation(this);
+ renderInfo->getState()->getGraphicsContext()->getGraphicsThread()
+ ->add(validOp.get());
+ return newStatus;
+}
+
+Technique::Status Technique::getValidStatus(const RenderInfo* renderInfo) const
+{
+ ContextInfo& contextInfo = _contextMap[renderInfo->getContextID()];
+ return contextInfo.valid();
+}
+
+void Technique::validateInContext(GraphicsContext* gc)
+{
+ ContextInfo& contextInfo = _contextMap[gc->getState()->getContextID()];
+ Status oldVal = contextInfo.valid();
+ Status newVal = INVALID;
+ if (getGLVersionNumber() >= _glVersion)
+ newVal = VALID;
+ contextInfo.valid.compareAndSwap(oldVal, newVal);
+}
+
+namespace
+{
+enum NumDrawables {NUM_DRAWABLES = 128};
+}
+
+EffectGeode::DrawablesIterator
+Technique::processDrawables(const EffectGeode::DrawablesIterator& begin,
+ const EffectGeode::DrawablesIterator& end,
+ CullVisitor* cv,
+ bool isCullingActive)
+{
+ RefMatrix& matrix = *cv->getModelViewMatrix();
+ float depth[NUM_DRAWABLES];
+ EffectGeode::DrawablesIterator itr = begin;
+ bool computeNearFar
+ = cv->getComputeNearFarMode() != CullVisitor::DO_NOT_COMPUTE_NEAR_FAR;
+ for (int i = 0; i < NUM_DRAWABLES && itr != end; ++itr, ++i) {
+ Drawable* drawable = itr->get();
+ const BoundingBox& bb = drawable->getBound();
+ if ((drawable->getCullCallback()
+ && drawable->getCullCallback()->cull(cv, drawable,
+ &cv->getRenderInfo()))
+ || (isCullingActive && cv->isCulled(bb))) {
+ depth[i] = FLT_MAX;
+ continue;
+ }
+ if (computeNearFar && bb.valid()) {
+ if (!cv->updateCalculatedNearFar(matrix, *drawable, false)) {
+ depth[i] = FLT_MAX;
+ continue;
+ }
+ }
+ depth[i] = (bb.valid()
+ ? cv->getDistanceFromEyePoint(bb.center(), false)
+ : 0.0f);
+ if (isNaN(depth[i]))
+ depth[i] = FLT_MAX;
+ }
+ EffectGeode::DrawablesIterator drawablesEnd = itr;
+ BOOST_FOREACH(ref_ptr<Pass>& pass, passes)
+ {
+ cv->pushStateSet(pass->getStateSet());
+ int i = 0;
+ for (itr = begin; itr != drawablesEnd; ++itr, ++i) {
+ if (depth[i] != FLT_MAX)
+ cv->addDrawableAndDepth(itr->get(), &matrix, depth[i]);
+ }
+ cv->popStateSet();
+ }
+ return drawablesEnd;
+}
+
+void Technique::resizeGLObjectBuffers(unsigned int maxSize)
+{
+ if (_shadowingStateSet.valid())
+ _shadowingStateSet->resizeGLObjectBuffers(maxSize);
+ BOOST_FOREACH(ref_ptr<Pass>& pass, passes) {
+ pass->resizeGLObjectBuffers(maxSize);
+ }
+ _contextMap.resize(maxSize);
+}
+
+void Technique::releaseGLObjects(osg::State* state) const
+{
+ if (_shadowingStateSet.valid())
+ _shadowingStateSet->releaseGLObjects(state);
+ BOOST_FOREACH(const ref_ptr<Pass>& pass, passes)
+ {
+ pass->releaseGLObjects(state);
+ }
+ if (state == 0) {
+ for (int i = 0; i < _contextMap.size(); ++i) {
+ ContextInfo& info = _contextMap[i];
+ Status oldVal = info.valid();
+ info.valid.compareAndSwap(oldVal, UNKNOWN);
+ }
+ } else {
+ ContextInfo& info = _contextMap[state->getContextID()];
+ Status oldVal = info.valid();
+ info.valid.compareAndSwap(oldVal, UNKNOWN);
+ }
+}
+}
--- /dev/null
+// Copyright (C) 2008 Timothy Moore timoore@redhat.com
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 2 of the
+// License, or (at your option) any later version.
+//
+// This program 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
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#ifndef SIMGEAR_TECHNIQUE_HXX
+#define SIMGEAR_TECHNIQUE_HXX 1
+
+#include "EffectGeode.hxx"
+
+#include <simgear/structure/SGAtomic.hxx>
+
+#include <map>
+#include <vector>
+#include <string>
+
+#include <OpenThreads/Mutex>
+#include <osg/buffered_value>
+#include <osg/Geode>
+#include <osg/Object>
+#include <osg/GraphicsThread>
+
+namespace osg
+{
+class CopyOp;
+class Drawable;
+class RenderInfo;
+class StateSet;
+}
+
+namespace osgUtil
+{
+class CullVisitor;
+}
+
+namespace simgear
+{
+class Pass;
+
+class Technique : public osg::Object
+{
+public:
+ META_Object(simgear,Technique);
+ Technique();
+ Technique(const Technique& rhs,
+ const osg::CopyOp& copyop = osg::CopyOp::SHALLOW_COPY);
+ virtual ~Technique();
+ enum Status
+ {
+ UNKNOWN,
+ QUERY_IN_PROGRESS,
+ INVALID,
+ VALID
+ };
+ /** Returns the validity of a technique in a state. If we don't
+ * know, a query will be launched.
+ */
+ virtual Status valid(osg::RenderInfo* renderInfo);
+ /** Returns the validity of the technique without launching a
+ * query.
+ */
+ Status getValidStatus(const osg::RenderInfo* renderInfo) const;
+ /** Tests and sets the validity of the Technique. Must be run in a
+ *graphics context.
+ */
+ virtual void validateInContext(osg::GraphicsContext* gc);
+
+ virtual EffectGeode::DrawablesIterator
+ processDrawables(const EffectGeode::DrawablesIterator& begin,
+ const EffectGeode::DrawablesIterator& end,
+ osgUtil::CullVisitor* cv,
+ bool isCullingActive);
+ std::vector<osg::ref_ptr<Pass> > passes;
+ osg::StateSet* getShadowingStateSet() { return _shadowingStateSet.get(); }
+ void setShadowingStateSet(osg::StateSet* ss) { _shadowingStateSet = ss; }
+ virtual void resizeGLObjectBuffers(unsigned int maxSize);
+ virtual void releaseGLObjects(osg::State* state = 0) const;
+ // Initial validity testing. Either the minimum OpenGL version
+ // must be supported, or the list of extensions must be supported.
+ float getGLVersion() { return _glVersion; }
+ void setGLVersion(float glVersion) { _glVersion = glVersion; }
+ std::vector<std::string> glExtensions;
+protected:
+ // Validity of technique in a graphics context.
+ struct ContextInfo : public osg::Referenced
+ {
+ ContextInfo() : valid(UNKNOWN) {}
+ ContextInfo(const ContextInfo& rhs) : valid(rhs.valid()) {}
+ ContextInfo& operator=(const ContextInfo& rhs)
+ {
+ valid = rhs.valid();
+ }
+ Swappable<Status> valid;
+ };
+ typedef osg::buffered_object<ContextInfo> ContextMap;
+ mutable ContextMap _contextMap;
+ osg::ref_ptr<osg::StateSet> _shadowingStateSet;
+ float _glVersion;
+};
+}
+#endif
unsigned mValue;
};
+// Value that can be atomically compared and swapped.
+class SGSwappable
+{
+public:
+ typedef unsigned long value_type;
+ SGSwappable(unsigned long value = 0) : mValue(value) {}
+ operator unsigned long() const
+ {
+#if defined(SGATOMIC_USE_GCC4_BUILTINS)
+ __sync_synchronize();
+ return mValue;
+#elif defined(SGATOMIC_USE_MIPOSPRO_BUILTINS)
+ __synchronize();
+ return mValue;
+#elif defined(SGATOMIC_USE_WIN32_INTERLOCKED)
+ return static_cast<long const volatile &>(mValue);
+#else
+ SGGuard<SGMutex> lock(mMutex);
+ return mValue;
+#endif
+ }
+
+ bool compareAndSwap(unsigned long oldVal, unsigned long newVal)
+ {
+#if defined(SGATOMIC_USE_GCC4_BUILTINS)
+ return __sync_bool_compare_and_swap(&mValue, oldVal, newVal);
+#elif defined(SGATOMIC_USE_MIPOSPRO_BUILTINS)
+ return __compare_and_swap(&mValue, oldVal, newVal);
+#elif defined(SGATOMIC_USE_WIN32_INTERLOCKED)
+ long previous
+ = InterlockedCompareExchange(reinterpret_cast<long volatile*>(&mValue),
+ (long)newVal,
+ (long)oldVal);
+ return previous == (long)oldVal;
+#else
+ SGGuard<SGMutex> lock(mMutex);
+ if (oldVal == mValue) {
+ mValue = newVal;
+ return true;
+ } else {
+ return false;
+ }
+#endif
+ }
+
+private:
+ SGSwappable(const SGAtomic&);
+ SGSwappable& operator=(const SGAtomic&);
+
+#if !defined(SGATOMIC_USE_GCC4_BUILTINS) \
+ && !defined(SGATOMIC_USE_MIPOSPRO_BUILTINS) \
+ && !defined(SGATOMIC_USE_WIN32_INTERLOCKED)
+ mutable SGMutex mMutex;
+#endif
+#ifdef SGATOMIC_USE_WIN32_INTERLOCKED
+ __declspec(align(32))
+#endif
+ value_type mValue;
+
+};
+
+namespace simgear
+{
+// Typesafe wrapper around SGSwappable
+template <typename T>
+class Swappable : private SGSwappable
+{
+public:
+ Swappable(const T& value) : SGSwappable(static_cast<value_type>(value))
+ {
+ }
+ T operator() () const
+ {
+ return static_cast<T>(SGSwappable::operator unsigned long ());
+ }
+ bool compareAndSwap(const T& oldVal, const T& newVal)
+ {
+ return SGSwappable::compareAndSwap(static_cast<value_type>(oldVal),
+ static_cast<value_type>(newVal));
+ }
+};
+}
#endif
--- /dev/null
+// Template for defining an XML parser based on an element type and
+// builder classes
+
+#ifndef SIMGEAR_XMLSTATICPARSER_HXX
+#define SIMGEAR_XMLSTATICPARSER_HXX 1
+
+#include <string>
+#include <map>
+#include <stack>
+#include <auto_ptr>
+
+#include <osg/ref_ptr>
+#include <osg/Referenced>
+
+#include "easyxml.hxx"
+
+namespace simgear
+{
+
+template <typename Element> class XMLStaticParser;
+
+// Parser object. Instantiated for each new element encountered.
+
+template<typename Element>
+struct ElementBuilder : public osg::Referenced
+{
+ ElementBuilder(XMLStaticParser<Element>* builder) {}
+ ElementBuilder(const ElementBuilder& rhs) const {}
+ virtual ~ElementBuilder() {}
+ virtual void initialize(const XMLAttributes& attributes) = 0;
+ virtual void processSubElement(Element* subElement) = 0;
+ virtual void processData(const char* data, int length) = 0;
+ virtual Element* finalize() = 0;
+ // Create element parser from prototype
+ virtual ElementBuilder* clone() const = 0;
+};
+
+template<typename Element>
+struct BuilderFactory : public osg::Referenced
+{
+ typedef ElementBuilder<Element> builder_type;
+ typedef std::map<std::string, osg::ref_ptr<const ElementBuilder> >
+ BuilderMap;
+ BuilderMap builderMap;
+ ~virtual BuilderFactory() {}
+ static void registerBuilder(const std::string& name,
+ const builder_type* prototype)
+ {
+ if (!builderFactory.valid())
+ builderFactory = new BuilderFactory;
+ builderFactory->builderMap[name] = prototype;
+ }
+};
+
+template <typename Element>
+class XMLStaticParser : public XMLVisitor
+{
+public:
+
+
+ static osg::ref_ptr<BuilderFactory> builderFactory;
+
+
+
+ static ElementBuilder* makeBuilder(const std::string& name)
+ {
+ BuilderMap::iterator iter = builderFactory->builderMap.find(name);
+ if (iter == builderFactory->builderMap.end())
+ return 0;
+ return iter->second->clone();
+ }
+
+ typedef std::stack<osg::ref_ptr<ElementBuilder> > BuilderStack;
+ BuilderStack builderStack;
+
+ Element* result;
+
+ XMLStaticParser() : result(0) {}
+ virtual ~XMLStaticParser() {}
+
+ virtual void startXML()
+ {
+ builderStack.push(makeBuilder(""));
+ }
+
+ virtual void endXML()
+ {
+ // Stack should have only the initial builder
+ result = builderStack.top()->finalize();
+ }
+
+ virtual void startElement(const char* name, const XMLAttributes& atts)
+ {
+ ElementBuilder* builder = makeBuilder(name);
+ if (builder) {
+ builderStack.push(builder);
+ builder->initialize(atts);
+ }
+ }
+
+ virtual void endElement(const char* name)
+ {
+ Element* result = builderStack.top()->finalize();
+ builderStack.pop();
+ if (!builderStack.empty())
+ builderStack.top()->processSubElement(result);
+ }
+
+ virtual void data(const char* s, int length)
+ {
+ builderStack.top()->processData(s, length);
+ }
+
+ struct RegisterBuilderProxy
+ {
+ RegisterBuilderProxy(const char* name, ElementBuilder* builder)
+ {
+ registerBuilder(name, builder);
+ }
+ };
+};
+
+template <typename E>
+static osg::ref_ptr<BuilderFactory<E> > builderFactory;
+}
+#endif