+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);
+
+class GLShaderLanguageExpression : public GeneralNaryExpression<float, int>
+{
+public:
+ void eval(float& value, const expression::Binding* b) const
+ {
+ value = 0.0f;
+ int contextId = getOperand(0)->getValue(b);
+ GL2Extensions* extensions
+ = GL2Extensions::Get(static_cast<unsigned>(contextId), true);
+ if (!extensions)
+ return;
+ if (!extensions->isGlslSupported())
+ return;
+ value = extensions->getLanguageVersion();
+ }
+};
+
+Expression* shaderLanguageParser(const SGPropertyNode* exp,
+ expression::Parser* parser)
+{
+ GLShaderLanguageExpression* slexp = new GLShaderLanguageExpression;
+ int location = parser->getBindingLayout().addBinding("__contextId",
+ expression::INT);
+ VariableExpression<int>* contextExp = new VariableExpression<int>(location);
+ slexp->addOperand(contextExp);
+ return slexp;
+}
+
+expression::ExpParserRegistrar shaderLanguageRegistrar("shader-language",
+ glVersionParser);
+
+
+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);
+ }
+}
+