]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/BoundingVolumeBuildVisitor.hxx
warning fix: initializing members in the order they are declared keeps gcc happy
[simgear.git] / simgear / scene / model / BoundingVolumeBuildVisitor.hxx
1
2 // Copyright (C) 2008 - 2009  Mathias Froehlich - Mathias.Froehlich@web.de
3 //
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Library General Public
6 // License as published by the Free Software Foundation; either
7 // version 2 of the License, or (at your option) any later version.
8 //
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // Library General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 //
18
19 #ifndef SimGear_BoundingVolumeBuildVisitor_hxx
20 #define SimGear_BoundingVolumeBuildVisitor_hxx
21
22 #include <osg/Camera>
23 #include <osg/Drawable>
24 #include <osg/Geode>
25 #include <osg/Group>
26 #include <osg/PagedLOD>
27 #include <osg/Transform>
28 #include <osg/TriangleFunctor>
29
30 #include <simgear/scene/material/Effect.hxx>
31 #include <simgear/scene/material/EffectGeode.hxx>
32 #include <simgear/scene/material/mat.hxx>
33 #include <simgear/scene/material/matlib.hxx>
34 #include <simgear/scene/util/SGNodeMasks.hxx>
35 #include <simgear/scene/util/SGSceneUserData.hxx>
36 #include <simgear/math/SGGeometry.hxx>
37
38 #include <simgear/scene/bvh/BVHStaticGeometryBuilder.hxx>
39
40 namespace simgear {
41
42 class BoundingVolumeBuildVisitor : public osg::NodeVisitor {
43 public:
44     class PFunctor : public osg::PrimitiveFunctor {
45     public:
46         PFunctor() :
47             _modeCache(0)
48         {
49             _geometryBuilder = new BVHStaticGeometryBuilder;
50         }
51         virtual ~PFunctor()
52         { }
53
54         virtual void setVertexArray(unsigned int count, const osg::Vec2* vertices)
55         {
56             _vertices.resize(count);
57             for (unsigned i = 0; i < count; ++i)
58                 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
59         }
60
61         virtual void setVertexArray(unsigned int count, const osg::Vec3* vertices)
62         {
63             _vertices.resize(count);
64             for (unsigned i = 0; i < count; ++i)
65                 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], vertices[i][2]);
66         }
67
68         virtual void setVertexArray(unsigned int count, const osg::Vec4* vertices)
69         {
70             _vertices.resize(count);
71             for (unsigned i = 0; i < count; ++i)
72                 _vertices[i] = SGVec3f(vertices[i][0]/vertices[i][3],
73                                        vertices[i][1]/vertices[i][3],
74                                        vertices[i][2]/vertices[i][3]);
75         }
76
77         virtual void setVertexArray(unsigned int count, const osg::Vec2d* vertices)
78         {
79             _vertices.resize(count);
80             for (unsigned i = 0; i < count; ++i)
81                 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
82         }
83
84         virtual void setVertexArray(unsigned int count, const osg::Vec3d* vertices)
85         {
86             _vertices.resize(count);
87             for (unsigned i = 0; i < count; ++i)
88                 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], vertices[i][2]);
89         }
90
91         virtual void setVertexArray(unsigned int count, const osg::Vec4d* vertices) 
92         {
93             _vertices.resize(count);
94             for (unsigned i = 0; i < count; ++i)
95                 _vertices[i] = SGVec3f(vertices[i][0]/vertices[i][3],
96                                        vertices[i][1]/vertices[i][3],
97                                        vertices[i][2]/vertices[i][3]);
98         }
99
100         virtual void drawArrays(GLenum mode, GLint first, GLsizei count)
101         {
102             if (_vertices.empty() || count <= 0)
103                 return;
104
105             GLsizei end = first + count;
106             switch(mode) {
107             case (GL_TRIANGLES):
108                 for (GLsizei i = first; i < end - 2; i += 3) {
109                     addTriangle(i, i + 1, i + 2);
110                 }
111                 break;
112
113             case (GL_TRIANGLE_STRIP):
114                 for (GLsizei i = first; i < end - 2; ++i) {
115                     addTriangle(i, i + 1, i + 2);
116                 }
117                 break;
118
119             case (GL_QUADS):
120                 for (GLsizei i = first; i < end - 3; i += 4) {
121                     addQuad(i, i + 1, i + 2, i + 3);
122                 }
123                 break;
124
125             case (GL_QUAD_STRIP):
126                 for (GLsizei i = first; i < end - 3; i += 2) {
127                     addQuad(i, i + 1, i + 2, i + 3);
128                 }
129                 break;
130
131             case (GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN
132             case (GL_TRIANGLE_FAN):
133                 for (GLsizei i = first; i < end - 2; ++i) {
134                     addTriangle(first, i + 1, i + 2);
135                 }
136                 break;
137
138             case (GL_POINTS):
139                 for (GLsizei i = first; i < end; ++i) {
140                     addPoint(i);
141                 }
142                 break;
143
144             case (GL_LINES):
145                 for (GLsizei i = first; i < end - 1; i += 2) {
146                     addLine(i, i + 1);
147                 }
148                 break;
149
150             case (GL_LINE_STRIP):
151                 for (GLsizei i = first; i < end - 1; ++i) {
152                     addLine(i, i + 1);
153                 }
154                 break;
155
156             case (GL_LINE_LOOP):
157                 for (GLsizei i = first; i < end - 1; ++i) {
158                     addLine(i, i + 1);
159                 }
160                 addLine(end - 1, first);
161                 break;
162
163             default:
164                 break;
165             }
166         }
167   
168         virtual void drawElements(GLenum mode, GLsizei count, const GLubyte* indices)
169         {
170             drawElementsTemplate(mode, count, indices);
171         }
172
173         virtual void drawElements(GLenum mode, GLsizei count, const GLushort* indices)
174         {
175             drawElementsTemplate(mode, count, indices);
176         }
177
178         virtual void drawElements(GLenum mode, GLsizei count, const GLuint* indices)
179         {
180             drawElementsTemplate(mode, count, indices);
181         }
182
183         virtual void begin(GLenum mode)
184         {
185             _modeCache = mode;
186             _vertices.resize(0);
187         }
188
189         virtual void vertex(const osg::Vec2& v)
190         {
191             _vertices.push_back(SGVec3f(v[0], v[1], 0));
192         }
193         virtual void vertex(const osg::Vec3& v)
194         {
195             _vertices.push_back(SGVec3f(v[0], v[1], v[2]));
196         }
197         virtual void vertex(const osg::Vec4& v)
198         {
199             _vertices.push_back(SGVec3f(v[0]/v[3], v[1]/v[3], v[2]/v[3]));
200         }
201         virtual void vertex(float x, float y)
202         {
203             _vertices.push_back(SGVec3f(x, y, 0));
204         }
205         virtual void vertex(float x, float y, float z)
206         {
207             _vertices.push_back(SGVec3f(x, y, z));
208         }
209         virtual void vertex(float x, float y, float z, float w)
210         {
211             _vertices.push_back(SGVec3f(x/w, y/w, z/w));
212         }
213         virtual void end()
214         {
215             if (_vertices.empty())
216                 return;
217
218             drawArrays(_modeCache, 0, _vertices.size());
219         }
220
221         template<typename index_type>
222         void drawElementsTemplate(GLenum mode, GLsizei count,
223                                   const index_type* indices)
224         {
225             if (_vertices.empty() || indices == 0 || count <= 0)
226                 return;
227     
228             switch(mode) {
229             case (GL_TRIANGLES):
230                 for (GLsizei i = 0; i < count - 2; i += 3) {
231                     addTriangle(indices[i], indices[i + 1], indices[i + 2]);
232                 }
233                 break;
234
235             case (GL_TRIANGLE_STRIP):
236                 for (GLsizei i = 0; i < count - 2; ++i) {
237                     addTriangle(indices[i], indices[i + 1], indices[i + 2]);
238                 }
239                 break;
240
241             case (GL_QUADS):
242                 for (GLsizei i = 0; i < count - 3; i += 4) {
243                     addQuad(indices[i], indices[i + 1], indices[i + 2], indices[i + 3]);
244                 }
245                 break;
246
247             case (GL_QUAD_STRIP):
248                 for (GLsizei i = 0; i < count - 3; i += 2) {
249                     addQuad(indices[i], indices[i + 1], indices[i + 2], indices[i + 3]);
250                 }
251                 break;
252
253             case (GL_POLYGON):
254             case (GL_TRIANGLE_FAN):
255                 for (GLsizei i = 0; i < count - 2; ++i) {
256                     addTriangle(indices[0], indices[i + 1], indices[i + 2]);
257                 }
258                 break;
259
260             case (GL_POINTS):
261                 for(GLsizei i = 0; i < count; ++i) {
262                     addPoint(indices[i]);
263                 }
264                 break;
265
266             case (GL_LINES):
267                 for (GLsizei i = 0; i < count - 1; i += 2) {
268                     addLine(indices[i], indices[i + 1]);
269                 }
270                 break;
271
272             case (GL_LINE_STRIP):
273                 for (GLsizei i = 0; i < count - 1; ++i) {
274                     addLine(indices[i], indices[i + 1]);
275                 }
276                 break;
277
278             case (GL_LINE_LOOP):
279                 for (GLsizei i = 0; i < count - 1; ++i) {
280                     addLine(indices[i], indices[i + 1]);
281                 }
282                 addLine(indices[count - 1], indices[0]);
283                 break;
284
285             default:
286                 break;
287             }
288         }    
289
290         void addPoint(unsigned i1)
291         {
292             addPoint(_vertices[i1]);
293         }
294         void addLine(unsigned i1, unsigned i2)
295         {
296             addLine(_vertices[i1], _vertices[i2]);
297         }
298         void addTriangle(unsigned i1, unsigned i2, unsigned i3)
299         {
300             addTriangle(_vertices[i1], _vertices[i2], _vertices[i3]);
301         }
302         void addQuad(unsigned i1, unsigned i2, unsigned i3, unsigned i4)
303         {
304             addQuad(_vertices[i1], _vertices[i2], _vertices[i3], _vertices[i4]);
305         }
306
307         void addPoint(const SGVec3f& v1)
308         {
309         }
310         void addLine(const SGVec3f& v1, const SGVec3f& v2)
311         {
312         }
313         void addTriangle(const SGVec3f& v1, const SGVec3f& v2, const SGVec3f& v3)
314         {
315             _geometryBuilder->addTriangle(v1, v2, v3);
316         }
317         void addQuad(const SGVec3f& v1, const SGVec3f& v2,
318                      const SGVec3f& v3, const SGVec3f& v4)
319         {
320             _geometryBuilder->addTriangle(v1, v2, v3);
321             _geometryBuilder->addTriangle(v1, v3, v4);
322         }
323
324         BVHNode* buildTreeAndClear()
325         {
326             BVHNode* bvNode = _geometryBuilder->buildTree();
327             _geometryBuilder = new BVHStaticGeometryBuilder;
328             _vertices.clear();
329             return bvNode;
330         }
331
332         void swap(PFunctor& primitiveFunctor)
333         {
334             _vertices.swap(primitiveFunctor._vertices);
335             std::swap(_modeCache, primitiveFunctor._modeCache);
336             std::swap(_geometryBuilder, primitiveFunctor._geometryBuilder);
337         }
338
339         void setCurrentMaterial(const SGMaterial* material)
340         {
341             _geometryBuilder->setCurrentMaterial(material);
342         }
343         const SGMaterial* getCurrentMaterial() const
344         {
345             return _geometryBuilder->getCurrentMaterial();
346         }
347
348         std::vector<SGVec3f> _vertices;
349         GLenum _modeCache;
350
351         SGSharedPtr<BVHStaticGeometryBuilder> _geometryBuilder;
352     };
353
354
355     // class PrimitiveIndexFunctor
356     // {
357     // public:
358
359     //     virtual ~PrimitiveIndexFunctor() {}
360
361     //     virtual void setVertexArray(unsigned int count,const Vec2* vertices) = 0;
362     //     virtual void setVertexArray(unsigned int count,const Vec3* vertices) = 0;
363     //     virtual void setVertexArray(unsigned int count,const Vec4* vertices) = 0;
364
365     //     virtual void setVertexArray(unsigned int count,const Vec2d* vertices) = 0;
366     //     virtual void setVertexArray(unsigned int count,const Vec3d* vertices) = 0;
367     //     virtual void setVertexArray(unsigned int count,const Vec4d* vertices) = 0;
368
369     //     virtual void drawArrays(GLenum mode,GLint first,GLsizei count) = 0;
370     //     virtual void drawElements(GLenum mode,GLsizei count,const GLubyte* indices) = 0;
371     //     virtual void drawElements(GLenum mode,GLsizei count,const GLushort* indices) = 0;
372     //     virtual void drawElements(GLenum mode,GLsizei count,const GLuint* indices) = 0;
373
374     //     virtual void begin(GLenum mode) = 0;
375     //     virtual void vertex(unsigned int pos) = 0;
376     //     virtual void end() = 0;
377     // };
378
379     BoundingVolumeBuildVisitor(bool dumpIntoLeafs) :
380         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
381         _dumpIntoLeafs(dumpIntoLeafs)
382     {
383         setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
384     }
385     ~BoundingVolumeBuildVisitor()
386     {
387     }
388
389     const SGMaterial* pushMaterial(Effect* effect)
390     {
391         const SGMaterial* oldMaterial = _primitiveFunctor.getCurrentMaterial();
392         const SGMaterial* material = SGMaterialLib::findMaterial(effect);
393         if (material)
394             _primitiveFunctor.setCurrentMaterial(material);
395         return oldMaterial;
396     }
397
398     void fillWith(osg::Drawable* drawable)
399     {
400         drawable->accept(_primitiveFunctor);
401     }
402
403     virtual void apply(osg::Geode& geode)
404     {
405         if (hasBoundingVolumeTree(geode))
406             return;
407
408         const SGMaterial* oldMaterial = 0;
409
410         EffectGeode *eg = dynamic_cast<EffectGeode*>(&geode);
411         if (eg)
412             oldMaterial = pushMaterial(eg->getEffect());
413
414         bool flushHere = getNodePath().size() <= 1 || _dumpIntoLeafs;
415         if (flushHere) {
416             // push the current active primitive list
417             PFunctor previousPrimitives;
418             _primitiveFunctor.swap(previousPrimitives);
419
420             // walk the children
421             for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
422                 fillWith(geode.getDrawable(i));
423
424             // Flush the bounding volume tree if we reached the topmost group
425             addBoundingVolumeTreeToNode(geode);
426
427             // pop the current active primitive list
428             _primitiveFunctor.swap(previousPrimitives);
429         } else {
430             for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
431                 fillWith(geode.getDrawable(i));
432         }
433         if (eg)
434             _primitiveFunctor.setCurrentMaterial(oldMaterial);
435     }
436
437     virtual void apply(osg::Group& group)
438     { traverseAndCollect(group); }
439
440     virtual void apply(osg::Transform& transform)
441     { traverseAndDump(transform); }
442
443     virtual void apply(osg::PagedLOD&)
444     {
445         // Do nothing. In this case we get called by the loading process anyway
446     }
447
448     virtual void apply(osg::Camera& camera)
449     {
450         if (camera.getRenderOrder() != osg::Camera::NESTED_RENDER)
451             return;
452         traverseAndDump(camera);
453     }
454
455     void traverseAndDump(osg::Node& node)
456     {
457         if (hasBoundingVolumeTree(node))
458             return;
459
460         // push the current active primitive list
461         PFunctor previousPrimitives;
462         _primitiveFunctor.swap(previousPrimitives);
463
464         // walk the children
465         traverse(node);
466
467         // We know whenever we see a transform, we need to flush the
468         // collected bounding volume tree since these transforms are not
469         // handled by the plain leafs.
470         addBoundingVolumeTreeToNode(node);
471
472         // pop the current active primitive list
473         _primitiveFunctor.swap(previousPrimitives);
474     }
475
476     void traverseAndCollect(osg::Node& node)
477     {
478         // Already been here??
479         if (hasBoundingVolumeTree(node))
480             return;
481
482         // Force a flush of the bvtree if we are in the topmost node.
483         if (getNodePath().size() <= 1) {
484             traverseAndDump(node);
485             return;
486         }
487
488         // Note that we do not need to push the already collected list of
489         // primitives, since we are now in the topmost node ...
490
491         // walk the children
492         traverse(node);
493     }
494
495     void addBoundingVolumeTreeToNode(osg::Node& node)
496     {
497         // Build the flat tree.
498         BVHNode* bvNode = _primitiveFunctor.buildTreeAndClear();
499
500         // Nothing in there?
501         if (!bvNode)
502             return;
503
504         SGSceneUserData* userData;
505         userData = SGSceneUserData::getOrCreateSceneUserData(&node);
506         userData->setBVHNode(bvNode);
507     }
508
509     bool hasBoundingVolumeTree(osg::Node& node)
510     {
511         SGSceneUserData* userData;
512         userData = SGSceneUserData::getSceneUserData(&node);
513         if (!userData)
514             return false;
515         if (!userData->getBVHNode())
516             return false;
517         return true;
518     }
519
520 private:
521     PFunctor _primitiveFunctor;
522     bool _dumpIntoLeafs;
523 };
524
525 }
526
527 #endif