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