2 // Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de
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.
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.
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.
19 #ifndef SimGear_BoundingVolumeBuildVisitor_hxx
20 #define SimGear_BoundingVolumeBuildVisitor_hxx
23 #include <osg/Drawable>
26 #include <osg/MatrixTransform>
27 #include <osg/PagedLOD>
28 #include <osg/Transform>
29 #include <osg/TriangleFunctor>
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>
37 #include <simgear/scene/bvh/BVHStaticGeometryBuilder.hxx>
41 class BoundingVolumeBuildVisitor : public osg::NodeVisitor {
43 class PFunctor : public osg::PrimitiveFunctor {
48 _geometryBuilder = new BVHStaticGeometryBuilder;
53 virtual void setVertexArray(unsigned int count, const osg::Vec2* vertices)
55 _vertices.resize(count);
56 for (unsigned i = 0; i < count; ++i)
57 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
60 virtual void setVertexArray(unsigned int count, const osg::Vec3* vertices)
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]);
67 virtual void setVertexArray(unsigned int count, const osg::Vec4* vertices)
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]);
76 virtual void setVertexArray(unsigned int count, const osg::Vec2d* vertices)
78 _vertices.resize(count);
79 for (unsigned i = 0; i < count; ++i)
80 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
83 virtual void setVertexArray(unsigned int count, const osg::Vec3d* vertices)
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]);
90 virtual void setVertexArray(unsigned int count, const osg::Vec4d* vertices)
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]);
99 virtual void drawArrays(GLenum mode, GLint first, GLsizei count)
101 if (_vertices.empty() || count==0)
106 for (GLsizei i = first; i < first + count; i += 3) {
107 addTriangle(i, i + 1, i + 2);
111 case (GL_TRIANGLE_STRIP):
112 for (GLsizei i = 0; i < count; i += 3) {
114 addTriangle(first + i, first + i + 2, first + i + 1);
116 addTriangle(first + i, first + i + 1, first + i + 2);
121 for (GLsizei i = first; i < first + count; i += 4) {
122 addQuad(i, i + 1, i + 2, i + 3);
126 case (GL_QUAD_STRIP):
127 for (GLsizei i = 0; i < count - 2; i += 2) {
129 addQuad(first + i + 1, first + i, i + 3, first + i + 2);
131 addQuad(first + i, first + i + 1, first + i + 2, first + i + 3);
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);
143 for (GLsizei i = 0; i < count; ++i) {
149 for (GLsizei i = first; i < first + count; i += 2) {
154 case (GL_LINE_STRIP):
155 for (GLsizei i = first; i < first + count; ++i) {
161 for (GLsizei i = first; i < first + count; ++i) {
164 addLine(first + count - 1, first);
172 virtual void drawElements(GLenum mode, GLsizei count, const GLubyte* indices)
174 drawElementsTemplate(mode, count, indices);
177 virtual void drawElements(GLenum mode, GLsizei count, const GLushort* indices)
179 drawElementsTemplate(mode, count, indices);
182 virtual void drawElements(GLenum mode, GLsizei count, const GLuint* indices)
184 drawElementsTemplate(mode, count, indices);
187 virtual void begin(GLenum mode)
193 virtual void vertex(const osg::Vec2& v)
195 _vertices.push_back(SGVec3f(v[0], v[1], 0));
197 virtual void vertex(const osg::Vec3& v)
199 _vertices.push_back(SGVec3f(v[0], v[1], v[2]));
201 virtual void vertex(const osg::Vec4& v)
203 _vertices.push_back(SGVec3f(v[0]/v[3], v[1]/v[3], v[2]/v[3]));
205 virtual void vertex(float x, float y)
207 _vertices.push_back(SGVec3f(x, y, 0));
209 virtual void vertex(float x, float y, float z)
211 _vertices.push_back(SGVec3f(x, y, z));
213 virtual void vertex(float x, float y, float z, float w)
215 _vertices.push_back(SGVec3f(x/w, y/w, z/w));
219 if (_vertices.empty())
222 drawArrays(_modeCache, 0, _vertices.size());
225 template<typename index_type>
226 void drawElementsTemplate(GLenum mode, GLsizei count,
227 const index_type* indices)
229 if (_vertices.empty() || indices == 0 || count == 0)
234 for (GLsizei i = 0; i < count; i += 3) {
235 addTriangle(indices[i], indices[i + 1], indices[i + 2]);
239 case (GL_TRIANGLE_STRIP):
240 for (GLsizei i = 2; i < count; ++i) {
242 addTriangle(indices[i - 2], indices[i], indices[i - 1]);
244 addTriangle(indices[i - 2], indices[i - 1], indices[i]);
249 for (GLsizei i = 0; i < count; i += 4) {
250 addQuad(indices[i], indices[i + 1], indices[i + 2], indices[i + 3]);
254 case (GL_QUAD_STRIP):
255 for (GLsizei i = 3; i < count; i += 2) {
257 addQuad(indices[i - 2], indices[i - 3], indices[i], indices[i - 1]);
259 addQuad(indices[i - 3], indices[i - 2], indices[i - 1], indices[i]);
264 case (GL_TRIANGLE_FAN):
265 for (GLsizei i = 2; i < count; ++i) {
266 addTriangle(indices[0], indices[i - 1], indices[i]);
271 for(GLsizei i = 0; i < count; ++i) {
272 addPoint(indices[i]);
277 for (GLsizei i = 0; i < count; i += 2) {
278 addLine(indices[i], indices[i + 1]);
282 case (GL_LINE_STRIP):
283 for (GLsizei i = 0; i < count; ++i) {
284 addLine(indices[i], indices[i + 1]);
289 for (GLsizei i = 0; i < count; ++i) {
290 addLine(indices[i], indices[i + 1]);
292 addLine(indices[count - 1], indices[0]);
300 void addPoint(unsigned i1)
302 addPoint(_vertices[i1]);
304 void addLine(unsigned i1, unsigned i2)
306 addLine(_vertices[i1], _vertices[i2]);
308 void addTriangle(unsigned i1, unsigned i2, unsigned i3)
310 addTriangle(_vertices[i1], _vertices[i2], _vertices[i3]);
312 void addQuad(unsigned i1, unsigned i2, unsigned i3, unsigned i4)
314 addQuad(_vertices[i1], _vertices[i2], _vertices[i3], _vertices[i4]);
317 void addPoint(const SGVec3f& v1)
320 void addLine(const SGVec3f& v1, const SGVec3f& v2)
323 void addTriangle(const SGVec3f& v1, const SGVec3f& v2, const SGVec3f& v3)
325 _geometryBuilder->addTriangle(v1, v2, v3);
327 void addQuad(const SGVec3f& v1, const SGVec3f& v2,
328 const SGVec3f& v3, const SGVec3f& v4)
330 _geometryBuilder->addTriangle(v1, v2, v3);
331 _geometryBuilder->addTriangle(v1, v3, v4);
334 BVHNode* buildTreeAndClear()
336 BVHNode* bvNode = _geometryBuilder->buildTree();
337 _geometryBuilder = new BVHStaticGeometryBuilder;
342 void swap(PFunctor& primitiveFunctor)
344 _vertices.swap(primitiveFunctor._vertices);
345 std::swap(_modeCache, primitiveFunctor._modeCache);
346 std::swap(_geometryBuilder, primitiveFunctor._geometryBuilder);
349 void setCurrentMaterial(const SGMaterial* material)
351 _geometryBuilder->setCurrentMaterial(material);
353 const SGMaterial* getCurrentMaterial() const
355 return _geometryBuilder->getCurrentMaterial();
358 std::vector<SGVec3f> _vertices;
361 SGSharedPtr<BVHStaticGeometryBuilder> _geometryBuilder;
365 // class PrimitiveIndexFunctor
369 // virtual ~PrimitiveIndexFunctor() {}
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;
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;
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;
384 // virtual void begin(GLenum mode) = 0;
385 // virtual void vertex(unsigned int pos) = 0;
386 // virtual void end() = 0;
389 BoundingVolumeBuildVisitor() :
390 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN)
392 setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
394 ~BoundingVolumeBuildVisitor()
398 const SGMaterial* pushMaterial(osg::StateSet* stateSet)
400 const SGMaterial* oldMaterial = _primitiveFunctor.getCurrentMaterial();
401 const SGMaterial* material = SGMaterialLib::findMaterial(stateSet);
403 _primitiveFunctor.setCurrentMaterial(material);
407 void fillWith(osg::Drawable* drawable)
409 const SGMaterial* oldMaterial = pushMaterial(drawable->getStateSet());
410 drawable->accept(_primitiveFunctor);
411 _primitiveFunctor.setCurrentMaterial(oldMaterial);
414 virtual void apply(osg::Geode& geode)
416 const SGMaterial* oldMaterial = pushMaterial(geode.getStateSet());
418 if (!hasBoundingVolumeTree(geode))
419 for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
420 fillWith(geode.getDrawable(i));
422 // Flush the bounding volume tree if we reached the topmost group
423 if (getNodePath().size() <= 1)
424 addBoundingVolumeTreeToNode(geode);
425 _primitiveFunctor.setCurrentMaterial(oldMaterial);
428 virtual void apply(osg::Group& group)
430 // Note that we do not need to push the already collected list of
431 // primitives, since we are now in the topmost node ...
433 const SGMaterial* oldMaterial = pushMaterial(group.getStateSet());
435 if (!hasBoundingVolumeTree(group))
438 // Flush the bounding volume tree if we reached the topmost group
439 if (getNodePath().size() <= 1)
440 addBoundingVolumeTreeToNode(group);
442 _primitiveFunctor.setCurrentMaterial(oldMaterial);
445 virtual void apply(osg::Transform& transform)
447 // push the current active primitive list
448 PFunctor previousPrimitives;
449 _primitiveFunctor.swap(previousPrimitives);
451 const SGMaterial* oldMaterial = pushMaterial(transform.getStateSet());
454 if (!hasBoundingVolumeTree(transform))
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);
462 _primitiveFunctor.setCurrentMaterial(oldMaterial);
464 // pop the current active primitive list
465 _primitiveFunctor.swap(previousPrimitives);
468 virtual void apply(osg::PagedLOD&)
470 // Do nothing. In this case we get called by the loading process anyway
473 virtual void apply(osg::Camera& camera)
475 if (camera.getRenderOrder() != osg::Camera::NESTED_RENDER)
477 apply(static_cast<osg::Transform&>(camera));
480 void addBoundingVolumeTreeToNode(osg::Node& node)
482 // Build the flat tree.
483 BVHNode* bvNode = _primitiveFunctor.buildTreeAndClear();
489 SGSceneUserData* userData;
490 userData = SGSceneUserData::getOrCreateSceneUserData(&node);
491 userData->setBVHNode(bvNode);
494 bool hasBoundingVolumeTree(osg::Node& node)
496 SGSceneUserData* userData;
497 userData = SGSceneUserData::getSceneUserData(&node);
500 if (!userData->getBVHNode())
506 PFunctor _primitiveFunctor;