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