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/PagedLOD>
27 #include <osg/Transform>
28 #include <osg/TriangleFunctor>
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>
38 #include <simgear/scene/bvh/BVHStaticGeometryBuilder.hxx>
42 class BoundingVolumeBuildVisitor : public osg::NodeVisitor {
44 class PFunctor : public osg::PrimitiveFunctor {
49 _geometryBuilder = new BVHStaticGeometryBuilder;
54 virtual void setVertexArray(unsigned int count, const osg::Vec2* vertices)
56 _vertices.resize(count);
57 for (unsigned i = 0; i < count; ++i)
58 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
61 virtual void setVertexArray(unsigned int count, const osg::Vec3* vertices)
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]);
68 virtual void setVertexArray(unsigned int count, const osg::Vec4* vertices)
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]);
77 virtual void setVertexArray(unsigned int count, const osg::Vec2d* vertices)
79 _vertices.resize(count);
80 for (unsigned i = 0; i < count; ++i)
81 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
84 virtual void setVertexArray(unsigned int count, const osg::Vec3d* vertices)
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]);
91 virtual void setVertexArray(unsigned int count, const osg::Vec4d* vertices)
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]);
100 virtual void drawArrays(GLenum mode, GLint first, GLsizei count)
102 if (_vertices.empty() || count <= 0)
105 GLsizei end = first + count;
108 for (GLsizei i = first; i < end - 2; i += 3) {
109 addTriangle(i, i + 1, i + 2);
113 case (GL_TRIANGLE_STRIP):
114 for (GLsizei i = first; i < end - 2; ++i) {
115 addTriangle(i, i + 1, i + 2);
120 for (GLsizei i = first; i < end - 3; i += 4) {
121 addQuad(i, i + 1, i + 2, i + 3);
125 case (GL_QUAD_STRIP):
126 for (GLsizei i = first; i < end - 3; i += 2) {
127 addQuad(i, i + 1, i + 2, i + 3);
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);
139 for (GLsizei i = first; i < end; ++i) {
145 for (GLsizei i = first; i < end - 1; i += 2) {
150 case (GL_LINE_STRIP):
151 for (GLsizei i = first; i < end - 1; ++i) {
157 for (GLsizei i = first; i < end - 1; ++i) {
160 addLine(end - 1, first);
168 virtual void drawElements(GLenum mode, GLsizei count, const GLubyte* indices)
170 drawElementsTemplate(mode, count, indices);
173 virtual void drawElements(GLenum mode, GLsizei count, const GLushort* indices)
175 drawElementsTemplate(mode, count, indices);
178 virtual void drawElements(GLenum mode, GLsizei count, const GLuint* indices)
180 drawElementsTemplate(mode, count, indices);
183 virtual void begin(GLenum mode)
189 virtual void vertex(const osg::Vec2& v)
191 _vertices.push_back(SGVec3f(v[0], v[1], 0));
193 virtual void vertex(const osg::Vec3& v)
195 _vertices.push_back(SGVec3f(v[0], v[1], v[2]));
197 virtual void vertex(const osg::Vec4& v)
199 _vertices.push_back(SGVec3f(v[0]/v[3], v[1]/v[3], v[2]/v[3]));
201 virtual void vertex(float x, float y)
203 _vertices.push_back(SGVec3f(x, y, 0));
205 virtual void vertex(float x, float y, float z)
207 _vertices.push_back(SGVec3f(x, y, z));
209 virtual void vertex(float x, float y, float z, float w)
211 _vertices.push_back(SGVec3f(x/w, y/w, z/w));
215 if (_vertices.empty())
218 drawArrays(_modeCache, 0, _vertices.size());
221 template<typename index_type>
222 void drawElementsTemplate(GLenum mode, GLsizei count,
223 const index_type* indices)
225 if (_vertices.empty() || indices == 0 || count <= 0)
230 for (GLsizei i = 0; i < count - 2; i += 3) {
231 addTriangle(indices[i], indices[i + 1], indices[i + 2]);
235 case (GL_TRIANGLE_STRIP):
236 for (GLsizei i = 0; i < count - 2; ++i) {
237 addTriangle(indices[i], indices[i + 1], indices[i + 2]);
242 for (GLsizei i = 0; i < count - 3; i += 4) {
243 addQuad(indices[i], indices[i + 1], indices[i + 2], indices[i + 3]);
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]);
254 case (GL_TRIANGLE_FAN):
255 for (GLsizei i = 0; i < count - 2; ++i) {
256 addTriangle(indices[0], indices[i + 1], indices[i + 2]);
261 for(GLsizei i = 0; i < count; ++i) {
262 addPoint(indices[i]);
267 for (GLsizei i = 0; i < count - 1; i += 2) {
268 addLine(indices[i], indices[i + 1]);
272 case (GL_LINE_STRIP):
273 for (GLsizei i = 0; i < count - 1; ++i) {
274 addLine(indices[i], indices[i + 1]);
279 for (GLsizei i = 0; i < count - 1; ++i) {
280 addLine(indices[i], indices[i + 1]);
282 addLine(indices[count - 1], indices[0]);
290 void addPoint(unsigned i1)
292 addPoint(_vertices[i1]);
294 void addLine(unsigned i1, unsigned i2)
296 addLine(_vertices[i1], _vertices[i2]);
298 void addTriangle(unsigned i1, unsigned i2, unsigned i3)
300 addTriangle(_vertices[i1], _vertices[i2], _vertices[i3]);
302 void addQuad(unsigned i1, unsigned i2, unsigned i3, unsigned i4)
304 addQuad(_vertices[i1], _vertices[i2], _vertices[i3], _vertices[i4]);
307 void addPoint(const SGVec3f& v1)
310 void addLine(const SGVec3f& v1, const SGVec3f& v2)
313 void addTriangle(const SGVec3f& v1, const SGVec3f& v2, const SGVec3f& v3)
315 _geometryBuilder->addTriangle(v1, v2, v3);
317 void addQuad(const SGVec3f& v1, const SGVec3f& v2,
318 const SGVec3f& v3, const SGVec3f& v4)
320 _geometryBuilder->addTriangle(v1, v2, v3);
321 _geometryBuilder->addTriangle(v1, v3, v4);
324 BVHNode* buildTreeAndClear()
326 BVHNode* bvNode = _geometryBuilder->buildTree();
327 _geometryBuilder = new BVHStaticGeometryBuilder;
332 void swap(PFunctor& primitiveFunctor)
334 _vertices.swap(primitiveFunctor._vertices);
335 std::swap(_modeCache, primitiveFunctor._modeCache);
336 std::swap(_geometryBuilder, primitiveFunctor._geometryBuilder);
339 void setCurrentMaterial(const SGMaterial* material)
341 _geometryBuilder->setCurrentMaterial(material);
343 const SGMaterial* getCurrentMaterial() const
345 return _geometryBuilder->getCurrentMaterial();
348 std::vector<SGVec3f> _vertices;
351 SGSharedPtr<BVHStaticGeometryBuilder> _geometryBuilder;
355 // class PrimitiveIndexFunctor
359 // virtual ~PrimitiveIndexFunctor() {}
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;
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;
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;
374 // virtual void begin(GLenum mode) = 0;
375 // virtual void vertex(unsigned int pos) = 0;
376 // virtual void end() = 0;
379 BoundingVolumeBuildVisitor(bool dumpIntoLeafs) :
380 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
381 _dumpIntoLeafs(dumpIntoLeafs)
383 setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
385 ~BoundingVolumeBuildVisitor()
389 const SGMaterial* pushMaterial(Effect* effect)
391 const SGMaterial* oldMaterial = _primitiveFunctor.getCurrentMaterial();
392 const SGMaterial* material = SGMaterialLib::findMaterial(effect);
394 _primitiveFunctor.setCurrentMaterial(material);
398 void fillWith(osg::Drawable* drawable)
400 drawable->accept(_primitiveFunctor);
403 virtual void apply(osg::Geode& geode)
405 if (hasBoundingVolumeTree(geode))
408 const SGMaterial* oldMaterial = 0;
410 EffectGeode *eg = dynamic_cast<EffectGeode*>(&geode);
412 oldMaterial = pushMaterial(eg->getEffect());
414 bool flushHere = getNodePath().size() <= 1 || _dumpIntoLeafs;
416 // push the current active primitive list
417 PFunctor previousPrimitives;
418 _primitiveFunctor.swap(previousPrimitives);
421 for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
422 fillWith(geode.getDrawable(i));
424 // Flush the bounding volume tree if we reached the topmost group
425 addBoundingVolumeTreeToNode(geode);
427 // pop the current active primitive list
428 _primitiveFunctor.swap(previousPrimitives);
430 for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
431 fillWith(geode.getDrawable(i));
434 _primitiveFunctor.setCurrentMaterial(oldMaterial);
437 virtual void apply(osg::Group& group)
438 { traverseAndCollect(group); }
440 virtual void apply(osg::Transform& transform)
441 { traverseAndDump(transform); }
443 virtual void apply(osg::PagedLOD&)
445 // Do nothing. In this case we get called by the loading process anyway
448 virtual void apply(osg::Camera& camera)
450 if (camera.getRenderOrder() != osg::Camera::NESTED_RENDER)
452 traverseAndDump(camera);
455 void traverseAndDump(osg::Node& node)
457 if (hasBoundingVolumeTree(node))
460 // push the current active primitive list
461 PFunctor previousPrimitives;
462 _primitiveFunctor.swap(previousPrimitives);
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);
472 // pop the current active primitive list
473 _primitiveFunctor.swap(previousPrimitives);
476 void traverseAndCollect(osg::Node& node)
478 // Already been here??
479 if (hasBoundingVolumeTree(node))
482 // Force a flush of the bvtree if we are in the topmost node.
483 if (getNodePath().size() <= 1) {
484 traverseAndDump(node);
488 // Note that we do not need to push the already collected list of
489 // primitives, since we are now in the topmost node ...
495 void addBoundingVolumeTreeToNode(osg::Node& node)
497 // Build the flat tree.
498 BVHNode* bvNode = _primitiveFunctor.buildTreeAndClear();
504 SGSceneUserData* userData;
505 userData = SGSceneUserData::getOrCreateSceneUserData(&node);
506 userData->setBVHNode(bvNode);
509 bool hasBoundingVolumeTree(osg::Node& node)
511 SGSceneUserData* userData;
512 userData = SGSceneUserData::getSceneUserData(&node);
515 if (!userData->getBVHNode())
521 PFunctor _primitiveFunctor;