]> git.mxchange.org Git - simgear.git/commitdiff
Effects framework
authortimoore <timoore>
Wed, 15 Jul 2009 23:09:19 +0000 (23:09 +0000)
committerTim Moore <timoore@redhat.com>
Thu, 16 Jul 2009 10:09:43 +0000 (12:09 +0200)
17 files changed:
simgear/scene/material/Effect.cxx [new file with mode: 0644]
simgear/scene/material/Effect.hxx [new file with mode: 0644]
simgear/scene/material/EffectData.cxx [new file with mode: 0644]
simgear/scene/material/EffectData.hxx [new file with mode: 0644]
simgear/scene/material/EffectElement.hxx [new file with mode: 0644]
simgear/scene/material/EffectElementBuilder.hxx [new file with mode: 0644]
simgear/scene/material/EffectGeode.cxx [new file with mode: 0644]
simgear/scene/material/EffectGeode.hxx [new file with mode: 0644]
simgear/scene/material/ElementBuilder.cxx [new file with mode: 0644]
simgear/scene/material/ElementBuilder.hxx [new file with mode: 0644]
simgear/scene/material/Makefile.am
simgear/scene/material/Pass.cxx [new file with mode: 0644]
simgear/scene/material/Pass.hxx [new file with mode: 0644]
simgear/scene/material/Technique.cxx [new file with mode: 0644]
simgear/scene/material/Technique.hxx [new file with mode: 0644]
simgear/structure/SGAtomic.hxx
simgear/xml/XMLStaticParser.hxx [new file with mode: 0644]

diff --git a/simgear/scene/material/Effect.cxx b/simgear/scene/material/Effect.cxx
new file mode 100644 (file)
index 0000000..646a009
--- /dev/null
@@ -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);
+    }
+}
+}
diff --git a/simgear/scene/material/Effect.hxx b/simgear/scene/material/Effect.hxx
new file mode 100644 (file)
index 0000000..c675234
--- /dev/null
@@ -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
diff --git a/simgear/scene/material/EffectData.cxx b/simgear/scene/material/EffectData.cxx
new file mode 100644 (file)
index 0000000..3483f8d
--- /dev/null
@@ -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 (file)
index 0000000..c548283
--- /dev/null
@@ -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
diff --git a/simgear/scene/material/EffectElement.hxx b/simgear/scene/material/EffectElement.hxx
new file mode 100644 (file)
index 0000000..3a7fdd4
--- /dev/null
@@ -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 (file)
index 0000000..41c8240
--- /dev/null
@@ -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
diff --git a/simgear/scene/material/EffectGeode.cxx b/simgear/scene/material/EffectGeode.cxx
new file mode 100644 (file)
index 0000000..62a56d3
--- /dev/null
@@ -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);
+}
+
+}
diff --git a/simgear/scene/material/EffectGeode.hxx b/simgear/scene/material/EffectGeode.hxx
new file mode 100644 (file)
index 0000000..209a4a1
--- /dev/null
@@ -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
diff --git a/simgear/scene/material/ElementBuilder.cxx b/simgear/scene/material/ElementBuilder.cxx
new file mode 100644 (file)
index 0000000..4398478
--- /dev/null
@@ -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 (file)
index 0000000..e875206
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef SIMGEAR_ELEMENT_BUILDER_HXX
+#define SIMGEAR_ELEMENT_BUILDER_HXX 1
+
+#include <simgear/xml/XMLStaticParser.hxx>
+
+namespace simgear
+{
+}
+#endif
index fc0059c313871d214c765f9a8175522ea5833746..c81bdbcc1e7cc35a31c9a867601ed2931273c106 100644 (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
diff --git a/simgear/scene/material/Pass.cxx b/simgear/scene/material/Pass.cxx
new file mode 100644 (file)
index 0000000..dc882d4
--- /dev/null
@@ -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);
+}
+
+}
diff --git a/simgear/scene/material/Pass.hxx b/simgear/scene/material/Pass.hxx
new file mode 100644 (file)
index 0000000..e6b3dc9
--- /dev/null
@@ -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
diff --git a/simgear/scene/material/Technique.cxx b/simgear/scene/material/Technique.cxx
new file mode 100644 (file)
index 0000000..38b463b
--- /dev/null
@@ -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);
+    }
+}
+}
diff --git a/simgear/scene/material/Technique.hxx b/simgear/scene/material/Technique.hxx
new file mode 100644 (file)
index 0000000..8b18aea
--- /dev/null
@@ -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
index 1ff9a44d05213f08c4cfd3ab7337c99e86d6ee7a..a6202a869132c4372be5bf50dd0d658eb90e7362 100644 (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
diff --git a/simgear/xml/XMLStaticParser.hxx b/simgear/xml/XMLStaticParser.hxx
new file mode 100644 (file)
index 0000000..8cecac6
--- /dev/null
@@ -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