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