From: timoore Date: Wed, 15 Jul 2009 23:09:19 +0000 (+0000) Subject: Effects framework X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=d320a6facba71227454375c3dea80df330b31ca9;p=simgear.git Effects framework --- diff --git a/simgear/scene/material/Effect.cxx b/simgear/scene/material/Effect.cxx new file mode 100644 index 00000000..646a0096 --- /dev/null +++ b/simgear/scene/material/Effect.cxx @@ -0,0 +1,61 @@ +#include "Effect.hxx" +#include "Technique.hxx" + +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +#include + + + +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, _1, copyop)); +} +// There should always be a valid technique in an effect. + +Technique* Effect::chooseTechnique(RenderInfo* info) +{ + BOOST_FOREACH(ref_ptr& 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, techniques) + { + technique->resizeGLObjectBuffers(maxSize); + } +} + +void Effect::releaseGLObjects(osg::State* state) const +{ + BOOST_FOREACH(const ref_ptr& technique, techniques) + { + technique->releaseGLObjects(state); + } +} +} diff --git a/simgear/scene/material/Effect.hxx b/simgear/scene/material/Effect.hxx new file mode 100644 index 00000000..c6752343 --- /dev/null +++ b/simgear/scene/material/Effect.hxx @@ -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 + +#include + +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 > techniques; + Technique* chooseTechnique(osg::RenderInfo* renderInfo); + virtual void resizeGLObjectBuffers(unsigned int maxSize); + virtual void releaseGLObjects(osg::State* state = 0) const; +protected: + ~Effect() {} +}; +} +#endif diff --git a/simgear/scene/material/EffectData.cxx b/simgear/scene/material/EffectData.cxx new file mode 100644 index 00000000..3483f8df --- /dev/null +++ b/simgear/scene/material/EffectData.cxx @@ -0,0 +1,2 @@ +#include "EffectData.hxx" + diff --git a/simgear/scene/material/EffectData.hxx b/simgear/scene/material/EffectData.hxx new file mode 100644 index 00000000..c5482837 --- /dev/null +++ b/simgear/scene/material/EffectData.hxx @@ -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 + +#include "EffectElement.hxx" +#include "EffectElementBuilder.hxx" + +namespace simgear +{ +class ParamaterContext; + +template +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 EffectFloat; +typedef EffectData EffectVec4f; + + +} +#endif diff --git a/simgear/scene/material/EffectElement.hxx b/simgear/scene/material/EffectElement.hxx new file mode 100644 index 00000000..3a7fdd4d --- /dev/null +++ b/simgear/scene/material/EffectElement.hxx @@ -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 diff --git a/simgear/scene/material/EffectElementBuilder.hxx b/simgear/scene/material/EffectElementBuilder.hxx new file mode 100644 index 00000000..41c82406 --- /dev/null +++ b/simgear/scene/material/EffectElementBuilder.hxx @@ -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 +#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 diff --git a/simgear/scene/material/EffectGeode.cxx b/simgear/scene/material/EffectGeode.cxx new file mode 100644 index 00000000..62a56d32 --- /dev/null +++ b/simgear/scene/material/EffectGeode.cxx @@ -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 + +namespace simgear +{ + +using namespace osg; +using namespace osgUtil; + +void EffectGeode::traverse(NodeVisitor& nv) +{ + CullVisitor* cv = dynamic_cast(&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); +} + +} diff --git a/simgear/scene/material/EffectGeode.hxx b/simgear/scene/material/EffectGeode.hxx new file mode 100644 index 00000000..209a4a1c --- /dev/null +++ b/simgear/scene/material/EffectGeode.hxx @@ -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 + +#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; +}; +} +#endif diff --git a/simgear/scene/material/ElementBuilder.cxx b/simgear/scene/material/ElementBuilder.cxx new file mode 100644 index 00000000..43984784 --- /dev/null +++ b/simgear/scene/material/ElementBuilder.cxx @@ -0,0 +1,4 @@ +#include "ElementBuilder.hxx" + + + diff --git a/simgear/scene/material/ElementBuilder.hxx b/simgear/scene/material/ElementBuilder.hxx new file mode 100644 index 00000000..e8752061 --- /dev/null +++ b/simgear/scene/material/ElementBuilder.hxx @@ -0,0 +1,9 @@ +#ifndef SIMGEAR_ELEMENT_BUILDER_HXX +#define SIMGEAR_ELEMENT_BUILDER_HXX 1 + +#include + +namespace simgear +{ +} +#endif diff --git a/simgear/scene/material/Makefile.am b/simgear/scene/material/Makefile.am index fc0059c3..c81bdbcc 100644 --- a/simgear/scene/material/Makefile.am +++ b/simgear/scene/material/Makefile.am @@ -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 diff --git a/simgear/scene/material/Pass.cxx b/simgear/scene/material/Pass.cxx new file mode 100644 index 00000000..dc882d4c --- /dev/null +++ b/simgear/scene/material/Pass.cxx @@ -0,0 +1,27 @@ +#include "Pass.hxx" + +#include + +#include + +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); +} + +} diff --git a/simgear/scene/material/Pass.hxx b/simgear/scene/material/Pass.hxx new file mode 100644 index 00000000..e6b3dc90 --- /dev/null +++ b/simgear/scene/material/Pass.hxx @@ -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 +#include + +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 _stateSet; +}; + +} + +#endif diff --git a/simgear/scene/material/Technique.cxx b/simgear/scene/material/Technique.cxx new file mode 100644 index 00000000..38b463b4 --- /dev/null +++ b/simgear/scene/material/Technique.cxx @@ -0,0 +1,180 @@ +#include "Technique.hxx" +#include "Pass.hxx" + +#include +#include + +#include + +#include +#include +#include + +#include + +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; + 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, _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 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, 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, 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, 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); + } +} +} diff --git a/simgear/scene/material/Technique.hxx b/simgear/scene/material/Technique.hxx new file mode 100644 index 00000000..8b18aeac --- /dev/null +++ b/simgear/scene/material/Technique.hxx @@ -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 + +#include +#include +#include + +#include +#include +#include +#include +#include + +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 > 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 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 valid; + }; + typedef osg::buffered_object ContextMap; + mutable ContextMap _contextMap; + osg::ref_ptr _shadowingStateSet; + float _glVersion; +}; +} +#endif diff --git a/simgear/structure/SGAtomic.hxx b/simgear/structure/SGAtomic.hxx index 1ff9a44d..a6202a86 100644 --- a/simgear/structure/SGAtomic.hxx +++ b/simgear/structure/SGAtomic.hxx @@ -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(mValue); +#else + SGGuard 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(&mValue), + (long)newVal, + (long)oldVal); + return previous == (long)oldVal; +#else + SGGuard 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 +class Swappable : private SGSwappable +{ +public: + Swappable(const T& value) : SGSwappable(static_cast(value)) + { + } + T operator() () const + { + return static_cast(SGSwappable::operator unsigned long ()); + } + bool compareAndSwap(const T& oldVal, const T& newVal) + { + return SGSwappable::compareAndSwap(static_cast(oldVal), + static_cast(newVal)); + } +}; +} #endif diff --git a/simgear/xml/XMLStaticParser.hxx b/simgear/xml/XMLStaticParser.hxx new file mode 100644 index 00000000..8cecac68 --- /dev/null +++ b/simgear/xml/XMLStaticParser.hxx @@ -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 +#include +#include +#include + +#include +#include + +#include "easyxml.hxx" + +namespace simgear +{ + +template class XMLStaticParser; + +// Parser object. Instantiated for each new element encountered. + +template +struct ElementBuilder : public osg::Referenced +{ + ElementBuilder(XMLStaticParser* 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 +struct BuilderFactory : public osg::Referenced +{ + typedef ElementBuilder builder_type; + typedef std::map > + 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 +class XMLStaticParser : public XMLVisitor +{ +public: + + + static osg::ref_ptr 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 > 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 +static osg::ref_ptr > builderFactory; +} +#endif