]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/Technique.cxx
aeab9cf365b9b3057c70701b82e6d9165fd02397
[simgear.git] / simgear / scene / material / Technique.cxx
1
2 #ifdef HAVE_CONFIG_H
3 #  include <simgear_config.h>
4 #endif
5
6 #include "Technique.hxx"
7 #include "Pass.hxx"
8
9 #include <boost/foreach.hpp>
10
11 #include <iterator>
12 #include <vector>
13 #include <string>
14
15 #include <osg/GLExtensions>
16 #include <osg/GL2Extensions>
17 #include <osg/Math>
18 #include <osgUtil/CullVisitor>
19
20 #include <osgDB/Registry>
21 #include <osgDB/Input>
22 #include <osgDB/ParameterOutput>
23
24 #include <simgear/props/props.hxx>
25 #include <simgear/structure/OSGUtils.hxx>
26
27 namespace simgear
28 {
29 using namespace osg;
30 using namespace osgUtil;
31
32 namespace
33 {
34
35 struct ValidateOperation : GraphicsOperation
36 {
37     ValidateOperation(Technique* technique_)
38         : GraphicsOperation(opName, false), technique(technique_)
39     {
40     }
41     virtual void operator() (GraphicsContext* gc);
42     osg::ref_ptr<Technique> technique;
43     static const std::string opName;
44 };
45
46 const std::string ValidateOperation::opName("ValidateOperation");
47
48
49 void ValidateOperation::operator() (GraphicsContext* gc)
50 {
51     technique->validateInContext(gc);
52 }
53 }
54
55 Technique::Technique(bool alwaysValid)
56     : _alwaysValid(alwaysValid), _contextIdLocation(-1)
57 {
58 }
59
60 Technique::Technique(const Technique& rhs, const osg::CopyOp& copyop) :
61     _contextMap(rhs._contextMap), _alwaysValid(rhs._alwaysValid),
62     _shadowingStateSet(copyop(rhs._shadowingStateSet.get())),
63     _validExpression(rhs._validExpression),
64     _contextIdLocation(rhs._contextIdLocation)
65 {
66     for (std::vector<ref_ptr<Pass> >::const_iterator itr = rhs.passes.begin(),
67              end = rhs.passes.end();
68          itr != end;
69          ++itr)
70         passes.push_back(static_cast<Pass*>(copyop(itr->get())));
71 }
72
73 Technique::~Technique()
74 {
75 }
76
77 Technique::Status Technique::valid(osg::RenderInfo* renderInfo)
78 {
79     if (_alwaysValid)
80         return VALID;
81     unsigned contextID = renderInfo->getContextID();
82     ContextInfo& contextInfo = _contextMap[contextID];
83     Status status = contextInfo.valid();
84     if (status != UNKNOWN)
85         return status;
86     Status newStatus = QUERY_IN_PROGRESS;
87     // lock and spawn validity check.
88     if (!contextInfo.valid.compareAndSwap(status, newStatus)) {
89         // Lost the race with another thread spawning a request
90         return contextInfo.valid();
91     }
92     ref_ptr<ValidateOperation> validOp = new ValidateOperation(this);
93     GraphicsContext* context = renderInfo->getState()->getGraphicsContext();
94     GraphicsThread* thread = context->getGraphicsThread();
95     if (thread)
96         thread->add(validOp.get());
97     else
98         context->add(validOp.get());
99     return newStatus;
100 }
101
102 Technique::Status Technique::getValidStatus(const RenderInfo* renderInfo) const
103 {
104     if (_alwaysValid)
105         return VALID;
106     ContextInfo& contextInfo = _contextMap[renderInfo->getContextID()];
107     return contextInfo.valid();
108 }
109
110 void Technique::validateInContext(GraphicsContext* gc)
111 {
112     unsigned int contextId = gc->getState()->getContextID();
113     ContextInfo& contextInfo = _contextMap[contextId];
114     Status oldVal = contextInfo.valid();
115     Status newVal = INVALID;
116     expression::FixedLengthBinding<1> binding;
117     binding.getBindings()[_contextIdLocation].val.intVal = contextId;
118     if (_validExpression->getValue(&binding))
119         newVal = VALID;
120     contextInfo.valid.compareAndSwap(oldVal, newVal);
121 }
122
123 namespace
124 {
125 enum NumDrawables {NUM_DRAWABLES = 128};
126 }
127
128 EffectGeode::DrawablesIterator
129 Technique::processDrawables(const EffectGeode::DrawablesIterator& begin,
130                             const EffectGeode::DrawablesIterator& end,
131                             CullVisitor* cv,
132                             bool isCullingActive)
133 {
134     RefMatrix& matrix = *cv->getModelViewMatrix();
135     float depth[NUM_DRAWABLES];
136     EffectGeode::DrawablesIterator itr = begin;
137     bool computeNearFar
138         = cv->getComputeNearFarMode() != CullVisitor::DO_NOT_COMPUTE_NEAR_FAR;
139     for (int i = 0; i < NUM_DRAWABLES && itr != end; ++itr, ++i) {
140         Drawable* drawable = itr->get();
141         const BoundingBox& bb = drawable->getBound();
142         if ((drawable->getCullCallback()
143              && drawable->getCullCallback()->cull(cv, drawable,
144                                                   &cv->getRenderInfo()))
145             || (isCullingActive && cv->isCulled(bb))) {
146             depth[i] = FLT_MAX;
147             continue;
148         }
149         if (computeNearFar && bb.valid()) {
150             if (!cv->updateCalculatedNearFar(matrix, *drawable, false)) {
151                 depth[i] = FLT_MAX;
152                 continue;
153             }
154         }
155         depth[i] = (bb.valid()
156                     ? cv->getDistanceFromEyePoint(bb.center(), false)
157                     : 0.0f);
158         if (isNaN(depth[i]))
159             depth[i] = FLT_MAX;
160     }
161     EffectGeode::DrawablesIterator drawablesEnd = itr;
162     BOOST_FOREACH(ref_ptr<Pass>& pass, passes)
163     {
164         cv->pushStateSet(pass.get());
165         int i = 0;
166         for (itr = begin; itr != drawablesEnd; ++itr, ++i) {
167             if (depth[i] != FLT_MAX)
168                 cv->addDrawableAndDepth(itr->get(), &matrix, depth[i]);
169         }
170         cv->popStateSet();
171     }
172     return drawablesEnd;
173 }
174
175 void Technique::resizeGLObjectBuffers(unsigned int maxSize)
176 {
177     if (_shadowingStateSet.valid())
178         _shadowingStateSet->resizeGLObjectBuffers(maxSize);
179     BOOST_FOREACH(ref_ptr<Pass>& pass, passes) {
180         pass->resizeGLObjectBuffers(maxSize);
181     }
182     _contextMap.resize(maxSize);
183 }
184
185 void Technique::releaseGLObjects(osg::State* state) const
186 {
187     if (_shadowingStateSet.valid())
188         _shadowingStateSet->releaseGLObjects(state);
189     BOOST_FOREACH(const ref_ptr<Pass>& pass, passes)
190     {
191         pass->releaseGLObjects(state);
192     }
193     if (state == 0) {
194         for (int i = 0; i < (int)_contextMap.size(); ++i) {
195             ContextInfo& info = _contextMap[i];
196             Status oldVal = info.valid();
197             info.valid.compareAndSwap(oldVal, UNKNOWN);
198         }
199     } else {
200         ContextInfo& info = _contextMap[state->getContextID()];
201         Status oldVal = info.valid();
202         info.valid.compareAndSwap(oldVal, UNKNOWN);
203     }
204 }
205
206 void Technique::setValidExpression(SGExpressionb* exp,
207                                    const simgear::expression
208                                    ::BindingLayout& layout)
209 {
210     using namespace simgear::expression;
211     _validExpression = exp;
212     VariableBinding binding;
213     if (layout.findBinding("__contextId", binding))
214         _contextIdLocation = binding.location;
215 }
216
217 class GLVersionExpression : public SGExpression<float>
218 {
219 public:
220     void eval(float& value, const expression::Binding*) const
221     {
222 #ifdef TECHNIQUE_TEST_EXTENSIONS
223         value = 1.1;
224 #else
225         value = getGLVersionNumber();
226 #endif
227     }
228 };
229
230 Expression* glVersionParser(const SGPropertyNode* exp,
231                             expression::Parser* parser)
232 {
233     return new GLVersionExpression();
234 }
235
236 expression::ExpParserRegistrar glVersionRegistrar("glversion", glVersionParser);
237
238 class ExtensionSupportedExpression
239     : public GeneralNaryExpression<bool, int>
240 {
241 public:
242     ExtensionSupportedExpression() {}
243     ExtensionSupportedExpression(const string& extString)
244         : _extString(extString)
245     {
246     }
247     const string& getExtensionString() { return _extString; }
248     void setExtensionString(const string& extString) { _extString = extString; }
249     void eval(bool&value, const expression::Binding* b) const
250     {
251         int contextId = getOperand(0)->getValue(b);
252         value = isGLExtensionSupported((unsigned)contextId, _extString.c_str());
253     }
254 protected:
255     string _extString;
256 };
257
258 Expression* extensionSupportedParser(const SGPropertyNode* exp,
259                                      expression::Parser* parser)
260 {
261     if (exp->getType() == props::STRING
262         || exp->getType() == props::UNSPECIFIED) {
263         ExtensionSupportedExpression* esp
264             = new ExtensionSupportedExpression(exp->getStringValue());
265         int location = parser->getBindingLayout().addBinding("__contextId",
266                                                              expression::INT);
267         VariableExpression<int>* contextExp
268             = new VariableExpression<int>(location);
269         esp->addOperand(contextExp);
270         return esp;
271     }
272     throw expression::ParseError("extension-supported expression has wrong type");
273 }
274
275 expression::ExpParserRegistrar
276 extensionSupportedRegistrar("extension-supported", extensionSupportedParser);
277
278 class GLShaderLanguageExpression : public GeneralNaryExpression<float, int>
279 {
280 public:
281     void eval(float& value, const expression::Binding* b) const
282     {
283         value = 0.0f;
284         int contextId = getOperand(0)->getValue(b);
285         GL2Extensions* extensions
286             = GL2Extensions::Get(static_cast<unsigned>(contextId), true);
287         if (!extensions)
288             return;
289         if (!extensions->isGlslSupported())
290             return;
291         value = extensions->getLanguageVersion();
292     }
293 };
294
295 Expression* shaderLanguageParser(const SGPropertyNode* exp,
296                                  expression::Parser* parser)
297 {
298     GLShaderLanguageExpression* slexp = new GLShaderLanguageExpression;
299     int location = parser->getBindingLayout().addBinding("__contextId",
300                                                          expression::INT);
301     VariableExpression<int>* contextExp = new VariableExpression<int>(location);
302     slexp->addOperand(contextExp);
303     return slexp;
304 }
305
306 expression::ExpParserRegistrar shaderLanguageRegistrar("shader-language",
307                                                        glVersionParser);
308
309     
310 void Technique::setGLExtensionsPred(float glVersion,
311                                     const std::vector<std::string>& extensions)
312 {
313     using namespace std;
314     using namespace expression;
315     BindingLayout layout;
316     int contextLoc = layout.addBinding("__contextId", INT);
317     VariableExpression<int>* contextExp
318         = new VariableExpression<int>(contextLoc);
319     SGExpression<bool>* versionTest
320         = makePredicate<std::less_equal>(new SGConstExpression<float>(glVersion),
321                         new GLVersionExpression);
322     AndExpression* extensionsExp = 0;
323     for (vector<string>::const_iterator itr = extensions.begin(),
324              e = extensions.end();
325          itr != e;
326          ++itr) {
327         if (!extensionsExp)
328             extensionsExp = new AndExpression;
329         ExtensionSupportedExpression* supported
330             = new ExtensionSupportedExpression(*itr);
331         supported->addOperand(contextExp);
332         extensionsExp->addOperand(supported);
333     }
334     SGExpressionb* predicate = 0;
335     if (extensionsExp) {
336         OrExpression* orExp = new OrExpression;
337         orExp->addOperand(versionTest);
338         orExp->addOperand(extensionsExp);
339         predicate = orExp;
340     } else {
341         predicate = versionTest;
342     }
343     setValidExpression(predicate, layout);
344 }
345
346 void Technique::refreshValidity()
347 {
348     for (int i = 0; i < (int)_contextMap.size(); ++i) {
349         ContextInfo& info = _contextMap[i];
350         Status oldVal = info.valid();
351         // What happens if we lose the race here?
352         info.valid.compareAndSwap(oldVal, UNKNOWN);
353     }
354 }
355
356 bool Technique_writeLocalData(const Object& obj, osgDB::Output& fw)
357 {
358     const Technique& tniq = static_cast<const Technique&>(obj);
359     fw.indent() << "alwaysValid "
360                 << (tniq.getAlwaysValid() ? "TRUE\n" : "FALSE\n");
361 #if 0
362     fw.indent() << "glVersion " << tniq.getGLVersion() << "\n";
363 #endif
364     if (tniq.getShadowingStateSet()) {
365         fw.indent() << "shadowingStateSet\n";
366         fw.writeObject(*tniq.getShadowingStateSet());
367     }
368     fw.indent() << "num_passes " << tniq.passes.size() << "\n";
369     BOOST_FOREACH(const ref_ptr<Pass>& pass, tniq.passes) {
370         fw.writeObject(*pass);
371     }
372     return true;
373 }
374
375 namespace
376 {
377 osgDB::RegisterDotOsgWrapperProxy TechniqueProxy
378 (
379     new Technique,
380     "simgear::Technique",
381     "Object simgear::Technique",
382     0,
383     &Technique_writeLocalData
384     );
385 }
386 }