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