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