Effects framework

This commit is contained in:
timoore
2009-07-15 23:09:19 +00:00
committed by Tim Moore
parent 0793c2cb8c
commit d320a6facb
17 changed files with 937 additions and 0 deletions

View File

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

View File

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

View File

@@ -0,0 +1,2 @@
#include "EffectData.hxx"

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -0,0 +1,4 @@
#include "ElementBuilder.hxx"

View File

@@ -0,0 +1,9 @@
#ifndef SIMGEAR_ELEMENT_BUILDER_HXX
#define SIMGEAR_ELEMENT_BUILDER_HXX 1
#include <simgear/xml/XMLStaticParser.hxx>
namespace simgear
{
}
#endif

View File

@@ -5,11 +5,19 @@ lib_LIBRARIES = libsgmaterial.a
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

View File

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

View File

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

View File

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

View File

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

View File

@@ -113,4 +113,86 @@ private:
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

View File

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