]> git.mxchange.org Git - simgear.git/blob - simgear/scene/material/Technique.cxx
Effects framework
[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 <string>
8
9 #include <osg/GLExtensions>
10 #include <osg/Math>
11 #include <osgUtil/CullVisitor>
12
13 #include <simgear/structure/OSGUtils.hxx>
14
15 namespace simgear
16 {
17 using namespace osg;
18 using namespace osgUtil;
19
20 namespace
21 {
22
23 struct ValidateOperation : GraphicsOperation
24 {
25     ValidateOperation(Technique* technique_)
26         : GraphicsOperation(opName, false), technique(technique_)
27     {
28     }
29     virtual void operator() (GraphicsContext* gc);
30     osg::ref_ptr<Technique> technique;
31     static const std::string opName;
32 };
33
34 const std::string ValidateOperation::opName("ValidateOperation");
35
36
37 void ValidateOperation::operator() (GraphicsContext* gc)
38 {
39     technique->validateInContext(gc);
40 }
41 }
42
43 Technique::Technique() : _glVersion(1.1f)
44 {
45 }
46
47 Technique::Technique(const Technique& rhs, const osg::CopyOp& copyop) :
48     _contextMap(rhs._contextMap), _shadowingStateSet(rhs._shadowingStateSet),
49     _glVersion(rhs._glVersion)
50 {
51     using namespace std;
52     using namespace boost;
53     transform(rhs.passes.begin(), rhs.passes.end(),
54               backRefInsertIterator(passes),
55               bind(simgear::clone_ref<Pass>, _1, copyop));
56
57 }
58
59 Technique::~Technique()
60 {
61 }
62
63 Technique::Status Technique::valid(osg::RenderInfo* renderInfo)
64 {
65     unsigned contextID = renderInfo->getContextID();
66     ContextInfo& contextInfo = _contextMap[contextID];
67     Status status = contextInfo.valid();
68     if (status != UNKNOWN)
69         return status;
70     Status newStatus = QUERY_IN_PROGRESS;
71     // lock and spawn validity check.
72     if (!contextInfo.valid.compareAndSwap(status, newStatus)) {
73         // Lost the race with another thread spawning a request
74         return contextInfo.valid();
75     }
76     ref_ptr<ValidateOperation> validOp = new ValidateOperation(this);
77     renderInfo->getState()->getGraphicsContext()->getGraphicsThread()
78         ->add(validOp.get());
79     return newStatus;
80 }
81
82 Technique::Status Technique::getValidStatus(const RenderInfo* renderInfo) const
83 {
84     ContextInfo& contextInfo = _contextMap[renderInfo->getContextID()];
85     return contextInfo.valid();
86 }
87
88 void Technique::validateInContext(GraphicsContext* gc)
89 {
90     ContextInfo& contextInfo = _contextMap[gc->getState()->getContextID()];
91     Status oldVal = contextInfo.valid();
92     Status newVal = INVALID;
93     if (getGLVersionNumber() >= _glVersion)
94         newVal = VALID;
95     contextInfo.valid.compareAndSwap(oldVal, newVal);
96 }
97
98 namespace
99 {
100 enum NumDrawables {NUM_DRAWABLES = 128};
101 }
102
103 EffectGeode::DrawablesIterator
104 Technique::processDrawables(const EffectGeode::DrawablesIterator& begin,
105                             const EffectGeode::DrawablesIterator& end,
106                             CullVisitor* cv,
107                             bool isCullingActive)
108 {
109     RefMatrix& matrix = *cv->getModelViewMatrix();
110     float depth[NUM_DRAWABLES];
111     EffectGeode::DrawablesIterator itr = begin;
112     bool computeNearFar
113         = cv->getComputeNearFarMode() != CullVisitor::DO_NOT_COMPUTE_NEAR_FAR;
114     for (int i = 0; i < NUM_DRAWABLES && itr != end; ++itr, ++i) {
115         Drawable* drawable = itr->get();
116         const BoundingBox& bb = drawable->getBound();
117         if ((drawable->getCullCallback()
118              && drawable->getCullCallback()->cull(cv, drawable,
119                                                   &cv->getRenderInfo()))
120             || (isCullingActive && cv->isCulled(bb))) {
121             depth[i] = FLT_MAX;
122             continue;
123         }
124         if (computeNearFar && bb.valid()) {
125             if (!cv->updateCalculatedNearFar(matrix, *drawable, false)) {
126                 depth[i] = FLT_MAX;
127                 continue;
128             }
129         }
130         depth[i] = (bb.valid()
131                     ? cv->getDistanceFromEyePoint(bb.center(), false)
132                     : 0.0f);
133         if (isNaN(depth[i]))
134             depth[i] = FLT_MAX;
135     }
136     EffectGeode::DrawablesIterator drawablesEnd = itr;
137     BOOST_FOREACH(ref_ptr<Pass>& pass, passes)
138     {
139         cv->pushStateSet(pass->getStateSet());
140         int i = 0;
141         for (itr = begin; itr != drawablesEnd; ++itr, ++i) {
142             if (depth[i] != FLT_MAX)
143                 cv->addDrawableAndDepth(itr->get(), &matrix, depth[i]);
144         }
145         cv->popStateSet();
146     }
147     return drawablesEnd;
148 }
149
150 void Technique::resizeGLObjectBuffers(unsigned int maxSize)
151 {
152     if (_shadowingStateSet.valid())
153         _shadowingStateSet->resizeGLObjectBuffers(maxSize);
154     BOOST_FOREACH(ref_ptr<Pass>& pass, passes) {
155         pass->resizeGLObjectBuffers(maxSize);
156     }
157     _contextMap.resize(maxSize);
158 }
159
160 void Technique::releaseGLObjects(osg::State* state) const
161 {
162     if (_shadowingStateSet.valid())
163         _shadowingStateSet->releaseGLObjects(state);
164     BOOST_FOREACH(const ref_ptr<Pass>& pass, passes)
165     {
166         pass->releaseGLObjects(state);
167     }
168     if (state == 0) {
169         for (int i = 0; i < _contextMap.size(); ++i) {
170             ContextInfo& info = _contextMap[i];
171             Status oldVal = info.valid();
172             info.valid.compareAndSwap(oldVal, UNKNOWN);
173         }
174     } else {
175         ContextInfo& info = _contextMap[state->getContextID()];
176         Status oldVal = info.valid();
177         info.valid.compareAndSwap(oldVal, UNKNOWN);
178     }
179 }
180 }