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