+
+#ifdef HAVE_CONFIG_H
+# include <simgear_config.h>
+#endif
+
#include "Technique.hxx"
#include "Pass.hxx"
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
+#include <iterator>
+#include <vector>
#include <string>
#include <osg/GLExtensions>
#include <osgDB/Input>
#include <osgDB/ParameterOutput>
+#include <simgear/props/props.hxx>
#include <simgear/structure/OSGUtils.hxx>
namespace simgear
}
Technique::Technique(bool alwaysValid)
- : _alwaysValid(alwaysValid), _glVersion(1.1f)
+ : _alwaysValid(alwaysValid), _contextIdLocation(-1)
{
}
Technique::Technique(const Technique& rhs, const osg::CopyOp& copyop) :
_contextMap(rhs._contextMap), _alwaysValid(rhs._alwaysValid),
- _shadowingStateSet(rhs._shadowingStateSet), _glVersion(rhs._glVersion)
+ _shadowingStateSet(rhs._shadowingStateSet),
+ _validExpression(rhs._validExpression),
+ _contextIdLocation(rhs._contextIdLocation)
{
using namespace std;
using namespace boost;
transform(rhs.passes.begin(), rhs.passes.end(),
- backRefInsertIterator(passes),
+ back_inserter(passes),
bind(simgear::clone_ref<Pass>, _1, copyop));
}
return contextInfo.valid();
}
ref_ptr<ValidateOperation> validOp = new ValidateOperation(this);
- renderInfo->getState()->getGraphicsContext()->getGraphicsThread()
- ->add(validOp.get());
+ GraphicsContext* context = renderInfo->getState()->getGraphicsContext();
+ GraphicsThread* thread = context->getGraphicsThread();
+ if (thread)
+ thread->add(validOp.get());
+ else
+ context->add(validOp.get());
return newStatus;
}
void Technique::validateInContext(GraphicsContext* gc)
{
- ContextInfo& contextInfo = _contextMap[gc->getState()->getContextID()];
+ unsigned int contextId = gc->getState()->getContextID();
+ ContextInfo& contextInfo = _contextMap[contextId];
Status oldVal = contextInfo.valid();
Status newVal = INVALID;
- if (getGLVersionNumber() >= _glVersion)
+ expression::FixedLengthBinding<1> binding;
+ binding.getBindings()[_contextIdLocation].val.intVal = contextId;
+ if (_validExpression->getValue(&binding))
newVal = VALID;
contextInfo.valid.compareAndSwap(oldVal, newVal);
}
EffectGeode::DrawablesIterator drawablesEnd = itr;
BOOST_FOREACH(ref_ptr<Pass>& pass, passes)
{
- cv->pushStateSet(pass->getStateSet());
+ cv->pushStateSet(pass.get());
int i = 0;
for (itr = begin; itr != drawablesEnd; ++itr, ++i) {
if (depth[i] != FLT_MAX)
pass->releaseGLObjects(state);
}
if (state == 0) {
- for (int i = 0; i < _contextMap.size(); ++i) {
+ for (int i = 0; i < (int)_contextMap.size(); ++i) {
ContextInfo& info = _contextMap[i];
Status oldVal = info.valid();
info.valid.compareAndSwap(oldVal, UNKNOWN);
}
}
+void Technique::setValidExpression(SGExpressionb* exp,
+ const simgear::expression
+ ::BindingLayout& layout)
+{
+ using namespace simgear::expression;
+ _validExpression = exp;
+ VariableBinding binding;
+ if (layout.findBinding("__contextId", binding))
+ _contextIdLocation = binding.location;
+}
+
+class GLVersionExpression : public SGExpression<float>
+{
+public:
+ void eval(float& value, const expression::Binding*) const
+ {
+#ifdef TECHNIQUE_TEST_EXTENSIONS
+ value = 1.1;
+#else
+ value = getGLVersionNumber();
+#endif
+ }
+};
+
+Expression* glVersionParser(const SGPropertyNode* exp,
+ expression::Parser* parser)
+{
+ return new GLVersionExpression();
+}
+
+expression::ExpParserRegistrar glVersionRegistrar("glversion", glVersionParser);
+
+class ExtensionSupportedExpression
+ : public GeneralNaryExpression<bool, int>
+{
+public:
+ ExtensionSupportedExpression() {}
+ ExtensionSupportedExpression(const string& extString)
+ : _extString(extString)
+ {
+ }
+ const string& getExtensionString() { return _extString; }
+ void setExtensionString(const string& extString) { _extString = extString; }
+ void eval(bool&value, const expression::Binding* b) const
+ {
+ int contextId = getOperand(0)->getValue(b);
+ value = isGLExtensionSupported((unsigned)contextId, _extString.c_str());
+ }
+protected:
+ string _extString;
+};
+
+Expression* extensionSupportedParser(const SGPropertyNode* exp,
+ expression::Parser* parser)
+{
+ if (exp->getType() == props::STRING
+ || exp->getType() == props::UNSPECIFIED) {
+ ExtensionSupportedExpression* esp
+ = new ExtensionSupportedExpression(exp->getStringValue());
+ int location = parser->getBindingLayout().addBinding("__contextId",
+ expression::INT);
+ VariableExpression<int>* contextExp
+ = new VariableExpression<int>(location);
+ esp->addOperand(contextExp);
+ return esp;
+ }
+ throw expression::ParseError("extension-supported expression has wrong type");
+}
+
+expression::ExpParserRegistrar
+extensionSupportedRegistrar("extension-supported", extensionSupportedParser);
+
+void Technique::setGLExtensionsPred(float glVersion,
+ const std::vector<std::string>& extensions)
+{
+ using namespace std;
+ using namespace expression;
+ BindingLayout layout;
+ int contextLoc = layout.addBinding("__contextId", INT);
+ VariableExpression<int>* contextExp
+ = new VariableExpression<int>(contextLoc);
+ SGExpression<bool>* versionTest
+ = makePredicate<std::less_equal>(new SGConstExpression<float>(glVersion),
+ new GLVersionExpression);
+ AndExpression* extensionsExp = 0;
+ for (vector<string>::const_iterator itr = extensions.begin(),
+ e = extensions.end();
+ itr != e;
+ ++itr) {
+ if (!extensionsExp)
+ extensionsExp = new AndExpression;
+ ExtensionSupportedExpression* supported
+ = new ExtensionSupportedExpression(*itr);
+ supported->addOperand(contextExp);
+ extensionsExp->addOperand(supported);
+ }
+ SGExpressionb* predicate = 0;
+ if (extensionsExp) {
+ OrExpression* orExp = new OrExpression;
+ orExp->addOperand(versionTest);
+ orExp->addOperand(extensionsExp);
+ predicate = orExp;
+ } else {
+ predicate = versionTest;
+ }
+ setValidExpression(predicate, layout);
+}
+
+void Technique::refreshValidity()
+{
+ for (int i = 0; i < (int)_contextMap.size(); ++i) {
+ ContextInfo& info = _contextMap[i];
+ Status oldVal = info.valid();
+ // What happens if we lose the race here?
+ info.valid.compareAndSwap(oldVal, UNKNOWN);
+ }
+}
+
bool Technique_writeLocalData(const Object& obj, osgDB::Output& fw)
{
const Technique& tniq = static_cast<const Technique&>(obj);
fw.indent() << "alwaysValid "
<< (tniq.getAlwaysValid() ? "TRUE\n" : "FALSE\n");
+#if 0
fw.indent() << "glVersion " << tniq.getGLVersion() << "\n";
+#endif
if (tniq.getShadowingStateSet()) {
fw.indent() << "shadowingStateSet\n";
fw.writeObject(*tniq.getShadowingStateSet());
}
- fw.indent() << "passes\n";
+ fw.indent() << "num_passes " << tniq.passes.size() << "\n";
BOOST_FOREACH(const ref_ptr<Pass>& pass, tniq.passes) {
fw.writeObject(*pass);
}