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