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