00001
00002 #ifdef HAVE_CONFIG_H
00003 # include <simgear_config.h>
00004 #endif
00005
00006 #include "Technique.hxx"
00007 #include "Pass.hxx"
00008
00009 #include <boost/foreach.hpp>
00010
00011 #include <iterator>
00012 #include <vector>
00013 #include <string>
00014
00015 #include <osg/GLExtensions>
00016 #include <osg/GL2Extensions>
00017 #include <osg/Math>
00018 #include <osgUtil/CullVisitor>
00019
00020 #include <osgDB/Registry>
00021 #include <osgDB/Input>
00022 #include <osgDB/ParameterOutput>
00023
00024 #include <simgear/props/props.hxx>
00025 #include <simgear/structure/OSGUtils.hxx>
00026
00027 namespace simgear
00028 {
00029 using namespace osg;
00030 using namespace osgUtil;
00031
00032 namespace
00033 {
00034
00035 struct ValidateOperation : GraphicsOperation
00036 {
00037 ValidateOperation(Technique* technique_)
00038 : GraphicsOperation(opName, false), technique(technique_)
00039 {
00040 }
00041 virtual void operator() (GraphicsContext* gc);
00042 osg::ref_ptr<Technique> technique;
00043 static const std::string opName;
00044 };
00045
00046 const std::string ValidateOperation::opName("ValidateOperation");
00047
00048
00049 void ValidateOperation::operator() (GraphicsContext* gc)
00050 {
00051 technique->validateInContext(gc);
00052 }
00053 }
00054
00055 Technique::Technique(bool alwaysValid)
00056 : _alwaysValid(alwaysValid), _contextIdLocation(-1)
00057 {
00058 }
00059
00060 Technique::Technique(const Technique& rhs, const osg::CopyOp& copyop) :
00061 _contextMap(rhs._contextMap), _alwaysValid(rhs._alwaysValid),
00062 _shadowingStateSet(copyop(rhs._shadowingStateSet)),
00063 _validExpression(rhs._validExpression),
00064 _contextIdLocation(rhs._contextIdLocation)
00065 {
00066 for (std::vector<ref_ptr<Pass> >::const_iterator itr = rhs.passes.begin(),
00067 end = rhs.passes.end();
00068 itr != end;
00069 ++itr)
00070 passes.push_back(static_cast<Pass*>(copyop(itr->get())));
00071 }
00072
00073 Technique::~Technique()
00074 {
00075 }
00076
00077 Technique::Status Technique::valid(osg::RenderInfo* renderInfo)
00078 {
00079 if (_alwaysValid)
00080 return VALID;
00081 unsigned contextID = renderInfo->getContextID();
00082 ContextInfo& contextInfo = _contextMap[contextID];
00083 Status status = contextInfo.valid();
00084 if (status != UNKNOWN)
00085 return status;
00086 Status newStatus = QUERY_IN_PROGRESS;
00087
00088 if (!contextInfo.valid.compareAndSwap(status, newStatus)) {
00089
00090 return contextInfo.valid();
00091 }
00092 ref_ptr<ValidateOperation> validOp = new ValidateOperation(this);
00093 GraphicsContext* context = renderInfo->getState()->getGraphicsContext();
00094 GraphicsThread* thread = context->getGraphicsThread();
00095 if (thread)
00096 thread->add(validOp.get());
00097 else
00098 context->add(validOp.get());
00099 return newStatus;
00100 }
00101
00102 Technique::Status Technique::getValidStatus(const RenderInfo* renderInfo) const
00103 {
00104 if (_alwaysValid)
00105 return VALID;
00106 ContextInfo& contextInfo = _contextMap[renderInfo->getContextID()];
00107 return contextInfo.valid();
00108 }
00109
00110 void Technique::validateInContext(GraphicsContext* gc)
00111 {
00112 unsigned int contextId = gc->getState()->getContextID();
00113 ContextInfo& contextInfo = _contextMap[contextId];
00114 Status oldVal = contextInfo.valid();
00115 Status newVal = INVALID;
00116 expression::FixedLengthBinding<1> binding;
00117 binding.getBindings()[_contextIdLocation].val.intVal = contextId;
00118 if (_validExpression->getValue(&binding))
00119 newVal = VALID;
00120 contextInfo.valid.compareAndSwap(oldVal, newVal);
00121 }
00122
00123 namespace
00124 {
00125 enum NumDrawables {NUM_DRAWABLES = 128};
00126 }
00127
00128 EffectGeode::DrawablesIterator
00129 Technique::processDrawables(const EffectGeode::DrawablesIterator& begin,
00130 const EffectGeode::DrawablesIterator& end,
00131 CullVisitor* cv,
00132 bool isCullingActive)
00133 {
00134 RefMatrix& matrix = *cv->getModelViewMatrix();
00135 float depth[NUM_DRAWABLES];
00136 EffectGeode::DrawablesIterator itr = begin;
00137 bool computeNearFar
00138 = cv->getComputeNearFarMode() != CullVisitor::DO_NOT_COMPUTE_NEAR_FAR;
00139 for (int i = 0; i < NUM_DRAWABLES && itr != end; ++itr, ++i) {
00140 Drawable* drawable = itr->get();
00141 const BoundingBox& bb = drawable->getBound();
00142 if ((drawable->getCullCallback()
00143 && drawable->getCullCallback()->cull(cv, drawable,
00144 &cv->getRenderInfo()))
00145 || (isCullingActive && cv->isCulled(bb))) {
00146 depth[i] = FLT_MAX;
00147 continue;
00148 }
00149 if (computeNearFar && bb.valid()) {
00150 if (!cv->updateCalculatedNearFar(matrix, *drawable, false)) {
00151 depth[i] = FLT_MAX;
00152 continue;
00153 }
00154 }
00155 depth[i] = (bb.valid()
00156 ? cv->getDistanceFromEyePoint(bb.center(), false)
00157 : 0.0f);
00158 if (isNaN(depth[i]))
00159 depth[i] = FLT_MAX;
00160 }
00161 EffectGeode::DrawablesIterator drawablesEnd = itr;
00162 BOOST_FOREACH(ref_ptr<Pass>& pass, passes)
00163 {
00164 cv->pushStateSet(pass.get());
00165 int i = 0;
00166 for (itr = begin; itr != drawablesEnd; ++itr, ++i) {
00167 if (depth[i] != FLT_MAX)
00168 cv->addDrawableAndDepth(itr->get(), &matrix, depth[i]);
00169 }
00170 cv->popStateSet();
00171 }
00172 return drawablesEnd;
00173 }
00174
00175 void Technique::resizeGLObjectBuffers(unsigned int maxSize)
00176 {
00177 if (_shadowingStateSet.valid())
00178 _shadowingStateSet->resizeGLObjectBuffers(maxSize);
00179 BOOST_FOREACH(ref_ptr<Pass>& pass, passes) {
00180 pass->resizeGLObjectBuffers(maxSize);
00181 }
00182 _contextMap.resize(maxSize);
00183 }
00184
00185 void Technique::releaseGLObjects(osg::State* state) const
00186 {
00187 if (_shadowingStateSet.valid())
00188 _shadowingStateSet->releaseGLObjects(state);
00189 BOOST_FOREACH(const ref_ptr<Pass>& pass, passes)
00190 {
00191 pass->releaseGLObjects(state);
00192 }
00193 if (state == 0) {
00194 for (int i = 0; i < (int)_contextMap.size(); ++i) {
00195 ContextInfo& info = _contextMap[i];
00196 Status oldVal = info.valid();
00197 info.valid.compareAndSwap(oldVal, UNKNOWN);
00198 }
00199 } else {
00200 ContextInfo& info = _contextMap[state->getContextID()];
00201 Status oldVal = info.valid();
00202 info.valid.compareAndSwap(oldVal, UNKNOWN);
00203 }
00204 }
00205
00206 void Technique::setValidExpression(SGExpressionb* exp,
00207 const simgear::expression
00208 ::BindingLayout& layout)
00209 {
00210 using namespace simgear::expression;
00211 _validExpression = exp;
00212 VariableBinding binding;
00213 if (layout.findBinding("__contextId", binding))
00214 _contextIdLocation = binding.location;
00215 }
00216
00217 class GLVersionExpression : public SGExpression<float>
00218 {
00219 public:
00220 void eval(float& value, const expression::Binding*) const
00221 {
00222 #ifdef TECHNIQUE_TEST_EXTENSIONS
00223 value = 1.1;
00224 #else
00225 value = getGLVersionNumber();
00226 #endif
00227 }
00228 };
00229
00230 Expression* glVersionParser(const SGPropertyNode* exp,
00231 expression::Parser* parser)
00232 {
00233 return new GLVersionExpression();
00234 }
00235
00236 expression::ExpParserRegistrar glVersionRegistrar("glversion", glVersionParser);
00237
00238 class ExtensionSupportedExpression
00239 : public GeneralNaryExpression<bool, int>
00240 {
00241 public:
00242 ExtensionSupportedExpression() {}
00243 ExtensionSupportedExpression(const string& extString)
00244 : _extString(extString)
00245 {
00246 }
00247 const string& getExtensionString() { return _extString; }
00248 void setExtensionString(const string& extString) { _extString = extString; }
00249 void eval(bool&value, const expression::Binding* b) const
00250 {
00251 int contextId = getOperand(0)->getValue(b);
00252 value = isGLExtensionSupported((unsigned)contextId, _extString.c_str());
00253 }
00254 protected:
00255 string _extString;
00256 };
00257
00258 Expression* extensionSupportedParser(const SGPropertyNode* exp,
00259 expression::Parser* parser)
00260 {
00261 if (exp->getType() == props::STRING
00262 || exp->getType() == props::UNSPECIFIED) {
00263 ExtensionSupportedExpression* esp
00264 = new ExtensionSupportedExpression(exp->getStringValue());
00265 int location = parser->getBindingLayout().addBinding("__contextId",
00266 expression::INT);
00267 VariableExpression<int>* contextExp
00268 = new VariableExpression<int>(location);
00269 esp->addOperand(contextExp);
00270 return esp;
00271 }
00272 throw expression::ParseError("extension-supported expression has wrong type");
00273 }
00274
00275 expression::ExpParserRegistrar
00276 extensionSupportedRegistrar("extension-supported", extensionSupportedParser);
00277
00278 class GLShaderLanguageExpression : public GeneralNaryExpression<float, int>
00279 {
00280 public:
00281 void eval(float& value, const expression::Binding* b) const
00282 {
00283 value = 0.0f;
00284 int contextId = getOperand(0)->getValue(b);
00285 GL2Extensions* extensions
00286 = GL2Extensions::Get(static_cast<unsigned>(contextId), true);
00287 if (!extensions)
00288 return;
00289 if (!extensions->isGlslSupported())
00290 return;
00291 value = extensions->getLanguageVersion();
00292 }
00293 };
00294
00295 Expression* shaderLanguageParser(const SGPropertyNode* exp,
00296 expression::Parser* parser)
00297 {
00298 GLShaderLanguageExpression* slexp = new GLShaderLanguageExpression;
00299 int location = parser->getBindingLayout().addBinding("__contextId",
00300 expression::INT);
00301 VariableExpression<int>* contextExp = new VariableExpression<int>(location);
00302 slexp->addOperand(contextExp);
00303 return slexp;
00304 }
00305
00306 expression::ExpParserRegistrar shaderLanguageRegistrar("shader-language",
00307 glVersionParser);
00308
00309
00310 void Technique::setGLExtensionsPred(float glVersion,
00311 const std::vector<std::string>& extensions)
00312 {
00313 using namespace std;
00314 using namespace expression;
00315 BindingLayout layout;
00316 int contextLoc = layout.addBinding("__contextId", INT);
00317 VariableExpression<int>* contextExp
00318 = new VariableExpression<int>(contextLoc);
00319 SGExpression<bool>* versionTest
00320 = makePredicate<std::less_equal>(new SGConstExpression<float>(glVersion),
00321 new GLVersionExpression);
00322 AndExpression* extensionsExp = 0;
00323 for (vector<string>::const_iterator itr = extensions.begin(),
00324 e = extensions.end();
00325 itr != e;
00326 ++itr) {
00327 if (!extensionsExp)
00328 extensionsExp = new AndExpression;
00329 ExtensionSupportedExpression* supported
00330 = new ExtensionSupportedExpression(*itr);
00331 supported->addOperand(contextExp);
00332 extensionsExp->addOperand(supported);
00333 }
00334 SGExpressionb* predicate = 0;
00335 if (extensionsExp) {
00336 OrExpression* orExp = new OrExpression;
00337 orExp->addOperand(versionTest);
00338 orExp->addOperand(extensionsExp);
00339 predicate = orExp;
00340 } else {
00341 predicate = versionTest;
00342 }
00343 setValidExpression(predicate, layout);
00344 }
00345
00346 void Technique::refreshValidity()
00347 {
00348 for (int i = 0; i < (int)_contextMap.size(); ++i) {
00349 ContextInfo& info = _contextMap[i];
00350 Status oldVal = info.valid();
00351
00352 info.valid.compareAndSwap(oldVal, UNKNOWN);
00353 }
00354 }
00355
00356 bool Technique_writeLocalData(const Object& obj, osgDB::Output& fw)
00357 {
00358 const Technique& tniq = static_cast<const Technique&>(obj);
00359 fw.indent() << "alwaysValid "
00360 << (tniq.getAlwaysValid() ? "TRUE\n" : "FALSE\n");
00361 #if 0
00362 fw.indent() << "glVersion " << tniq.getGLVersion() << "\n";
00363 #endif
00364 if (tniq.getShadowingStateSet()) {
00365 fw.indent() << "shadowingStateSet\n";
00366 fw.writeObject(*tniq.getShadowingStateSet());
00367 }
00368 fw.indent() << "num_passes " << tniq.passes.size() << "\n";
00369 BOOST_FOREACH(const ref_ptr<Pass>& pass, tniq.passes) {
00370 fw.writeObject(*pass);
00371 }
00372 return true;
00373 }
00374
00375 namespace
00376 {
00377 osgDB::RegisterDotOsgWrapperProxy TechniqueProxy
00378 (
00379 new Technique,
00380 "simgear::Technique",
00381 "Object simgear::Technique",
00382 0,
00383 &Technique_writeLocalData
00384 );
00385 }
00386 }