1 // Copyright (C) 2008 - 2012 Mathias Froehlich - Mathias.Froehlich@web.de
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Library General Public
5 // License as published by the Free Software Foundation; either
6 // version 2 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Library General Public License for more details.
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 # include <simgear_config.h>
22 #include "BVHPageNodeOSG.hxx"
24 #include "../../bvh/BVHPageRequest.hxx"
25 #include "../../bvh/BVHPager.hxx"
28 #include <osg/Drawable>
31 #include <osg/PagedLOD>
32 #include <osg/ProxyNode>
33 #include <osg/Transform>
34 #include <osg/TriangleFunctor>
35 #include <osgDB/ReadFile>
37 #include <simgear/scene/material/mat.hxx>
38 #include <simgear/scene/material/matlib.hxx>
39 #include <simgear/scene/util/SGNodeMasks.hxx>
40 #include <simgear/scene/util/OsgMath.hxx>
41 #include <simgear/scene/util/SGSceneUserData.hxx>
42 #include <simgear/math/SGGeometry.hxx>
44 #include <simgear/bvh/BVHStaticGeometryBuilder.hxx>
48 class BVHPageNodeOSG::_NodeVisitor : public osg::NodeVisitor {
50 class PFunctor : public osg::PrimitiveFunctor {
55 _geometryBuilder = new BVHStaticGeometryBuilder;
60 virtual void setVertexArray(unsigned int count, const osg::Vec2* vertices)
62 _vertices.resize(count);
63 for (unsigned i = 0; i < count; ++i)
64 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
67 virtual void setVertexArray(unsigned int count, const osg::Vec3* vertices)
69 _vertices.resize(count);
70 for (unsigned i = 0; i < count; ++i)
71 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], vertices[i][2]);
74 virtual void setVertexArray(unsigned int count, const osg::Vec4* vertices)
76 _vertices.resize(count);
77 for (unsigned i = 0; i < count; ++i)
78 _vertices[i] = SGVec3f(vertices[i][0]/vertices[i][3],
79 vertices[i][1]/vertices[i][3],
80 vertices[i][2]/vertices[i][3]);
83 virtual void setVertexArray(unsigned int count, const osg::Vec2d* vertices)
85 _vertices.resize(count);
86 for (unsigned i = 0; i < count; ++i)
87 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
90 virtual void setVertexArray(unsigned int count, const osg::Vec3d* vertices)
92 _vertices.resize(count);
93 for (unsigned i = 0; i < count; ++i)
94 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], vertices[i][2]);
97 virtual void setVertexArray(unsigned int count, const osg::Vec4d* vertices)
99 _vertices.resize(count);
100 for (unsigned i = 0; i < count; ++i)
101 _vertices[i] = SGVec3f(vertices[i][0]/vertices[i][3],
102 vertices[i][1]/vertices[i][3],
103 vertices[i][2]/vertices[i][3]);
106 virtual void drawArrays(GLenum mode, GLint first, GLsizei count)
108 if (_vertices.empty() || count <= 0)
111 GLsizei end = first + count;
114 for (GLsizei i = first; i < end - 2; i += 3) {
115 addTriangle(i, i + 1, i + 2);
119 case (GL_TRIANGLE_STRIP):
120 for (GLsizei i = first; i < end - 2; ++i) {
121 addTriangle(i, i + 1, i + 2);
126 for (GLsizei i = first; i < end - 3; i += 4) {
127 addQuad(i, i + 1, i + 2, i + 3);
131 case (GL_QUAD_STRIP):
132 for (GLsizei i = first; i < end - 3; i += 2) {
133 addQuad(i, i + 1, i + 2, i + 3);
137 case (GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN
138 case (GL_TRIANGLE_FAN):
139 for (GLsizei i = first; i < end - 2; ++i) {
140 addTriangle(first, i + 1, i + 2);
145 for (GLsizei i = first; i < end; ++i) {
151 for (GLsizei i = first; i < end - 1; i += 2) {
156 case (GL_LINE_STRIP):
157 for (GLsizei i = first; i < end - 1; ++i) {
163 for (GLsizei i = first; i < end - 1; ++i) {
166 addLine(end - 1, first);
174 virtual void drawElements(GLenum mode, GLsizei count, const GLubyte* indices)
176 drawElementsTemplate(mode, count, indices);
179 virtual void drawElements(GLenum mode, GLsizei count, const GLushort* indices)
181 drawElementsTemplate(mode, count, indices);
184 virtual void drawElements(GLenum mode, GLsizei count, const GLuint* indices)
186 drawElementsTemplate(mode, count, indices);
189 virtual void begin(GLenum mode)
195 virtual void vertex(const osg::Vec2& v)
197 _vertices.push_back(SGVec3f(v[0], v[1], 0));
199 virtual void vertex(const osg::Vec3& v)
201 _vertices.push_back(SGVec3f(v[0], v[1], v[2]));
203 virtual void vertex(const osg::Vec4& v)
205 _vertices.push_back(SGVec3f(v[0]/v[3], v[1]/v[3], v[2]/v[3]));
207 virtual void vertex(float x, float y)
209 _vertices.push_back(SGVec3f(x, y, 0));
211 virtual void vertex(float x, float y, float z)
213 _vertices.push_back(SGVec3f(x, y, z));
215 virtual void vertex(float x, float y, float z, float w)
217 _vertices.push_back(SGVec3f(x/w, y/w, z/w));
221 if (_vertices.empty())
224 drawArrays(_modeCache, 0, _vertices.size());
227 template<typename index_type>
228 void drawElementsTemplate(GLenum mode, GLsizei count,
229 const index_type* indices)
231 if (_vertices.empty() || indices == 0 || count <= 0)
236 for (GLsizei i = 0; i < count - 2; i += 3) {
237 addTriangle(indices[i], indices[i + 1], indices[i + 2]);
241 case (GL_TRIANGLE_STRIP):
242 for (GLsizei i = 0; i < count - 2; ++i) {
243 addTriangle(indices[i], indices[i + 1], indices[i + 2]);
248 for (GLsizei i = 0; i < count - 3; i += 4) {
249 addQuad(indices[i], indices[i + 1], indices[i + 2], indices[i + 3]);
253 case (GL_QUAD_STRIP):
254 for (GLsizei i = 0; i < count - 3; i += 2) {
255 addQuad(indices[i], indices[i + 1], indices[i + 2], indices[i + 3]);
260 case (GL_TRIANGLE_FAN):
261 for (GLsizei i = 0; i < count - 2; ++i) {
262 addTriangle(indices[0], indices[i + 1], indices[i + 2]);
267 for(GLsizei i = 0; i < count; ++i) {
268 addPoint(indices[i]);
273 for (GLsizei i = 0; i < count - 1; i += 2) {
274 addLine(indices[i], indices[i + 1]);
278 case (GL_LINE_STRIP):
279 for (GLsizei i = 0; i < count - 1; ++i) {
280 addLine(indices[i], indices[i + 1]);
285 for (GLsizei i = 0; i < count - 1; ++i) {
286 addLine(indices[i], indices[i + 1]);
288 addLine(indices[count - 1], indices[0]);
296 void addPoint(unsigned i1)
298 addPoint(_vertices[i1]);
300 void addLine(unsigned i1, unsigned i2)
302 addLine(_vertices[i1], _vertices[i2]);
304 void addTriangle(unsigned i1, unsigned i2, unsigned i3)
306 addTriangle(_vertices[i1], _vertices[i2], _vertices[i3]);
308 void addQuad(unsigned i1, unsigned i2, unsigned i3, unsigned i4)
310 addQuad(_vertices[i1], _vertices[i2], _vertices[i3], _vertices[i4]);
313 void addPoint(const SGVec3f& v1)
316 void addLine(const SGVec3f& v1, const SGVec3f& v2)
319 void addTriangle(const SGVec3f& v1, const SGVec3f& v2, const SGVec3f& v3)
321 _geometryBuilder->addTriangle(v1, v2, v3);
323 void addQuad(const SGVec3f& v1, const SGVec3f& v2,
324 const SGVec3f& v3, const SGVec3f& v4)
326 _geometryBuilder->addTriangle(v1, v2, v3);
327 _geometryBuilder->addTriangle(v1, v3, v4);
330 BVHNode* buildTreeAndClear()
332 BVHNode* bvNode = _geometryBuilder->buildTree();
333 _geometryBuilder = new BVHStaticGeometryBuilder;
338 void swap(PFunctor& primitiveFunctor)
340 _vertices.swap(primitiveFunctor._vertices);
341 std::swap(_modeCache, primitiveFunctor._modeCache);
342 std::swap(_geometryBuilder, primitiveFunctor._geometryBuilder);
345 void setCurrentMaterial(const BVHMaterial* material)
347 _geometryBuilder->setCurrentMaterial(material);
349 const BVHMaterial* getCurrentMaterial() const
351 return _geometryBuilder->getCurrentMaterial();
354 std::vector<SGVec3f> _vertices;
357 SGSharedPtr<BVHStaticGeometryBuilder> _geometryBuilder;
361 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN)
363 setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
365 virtual ~_NodeVisitor()
369 const BVHMaterial* pushMaterial(osg::Geode* geode)
371 const BVHMaterial* oldMaterial = _primitiveFunctor.getCurrentMaterial();
372 const BVHMaterial* material = SGMaterialLib::findMaterial(geode);
374 _primitiveFunctor.setCurrentMaterial(material);
378 virtual void apply(osg::Geode& geode)
380 const BVHMaterial* oldMaterial = pushMaterial(&geode);
382 for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
383 geode.getDrawable(i)->accept(_primitiveFunctor);
385 _primitiveFunctor.setCurrentMaterial(oldMaterial);
388 virtual void apply(osg::Group& group)
390 // FIXME optimize this to collapse more leafs
392 // push the current active primitive list
393 PFunctor previousPrimitives;
394 _primitiveFunctor.swap(previousPrimitives);
396 const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
397 _primitiveFunctor.setCurrentMaterial(mat);
399 NodeVector nodeVector;
400 _nodeVector.swap(nodeVector);
405 // We know whenever we see a transform, we need to flush the
406 // collected bounding volume tree since these transforms are not
407 // handled by the plain leafs.
408 addBoundingVolumeTreeToNode();
410 _nodeVector.swap(nodeVector);
412 if (!nodeVector.empty()) {
413 if (nodeVector.size() == 1) {
414 _nodeVector.push_back(nodeVector.front());
416 SGSharedPtr<BVHGroup> group = new BVHGroup;
417 for (NodeVector::iterator i = nodeVector.begin();
418 i != nodeVector.end(); ++i)
419 group->addChild(i->get());
420 _nodeVector.push_back(group);
424 // pop the current active primitive list
425 _primitiveFunctor.swap(previousPrimitives);
428 virtual void apply(osg::Transform& transform)
430 if (transform.getReferenceFrame() != osg::Transform::RELATIVE_RF)
434 if (!transform.computeLocalToWorldMatrix(matrix, this))
437 // push the current active primitive list
438 PFunctor previousPrimitives;
439 _primitiveFunctor.swap(previousPrimitives);
441 const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
442 _primitiveFunctor.setCurrentMaterial(mat);
444 NodeVector nodeVector;
445 _nodeVector.swap(nodeVector);
450 // We know whenever we see a transform, we need to flush the
451 // collected bounding volume tree since these transforms are not
452 // handled by the plain leafs.
453 addBoundingVolumeTreeToNode();
455 _nodeVector.swap(nodeVector);
457 // pop the current active primitive list
458 _primitiveFunctor.swap(previousPrimitives);
460 if (!nodeVector.empty()) {
461 SGSharedPtr<BVHTransform> bvhTransform = new BVHTransform;
462 bvhTransform->setToWorldTransform(SGMatrixd(matrix.ptr()));
464 for (NodeVector::iterator i = nodeVector.begin();
465 i != nodeVector.end(); ++i)
466 bvhTransform->addChild(i->get());
468 _nodeVector.push_back(bvhTransform);
472 virtual void apply(osg::Camera& camera)
474 if (camera.getRenderOrder() != osg::Camera::NESTED_RENDER)
476 apply(static_cast<osg::Transform&>(camera));
479 void addBoundingVolumeTreeToNode()
481 // Build the flat tree.
482 BVHNode* bvNode = _primitiveFunctor.buildTreeAndClear();
487 if (bvNode->getBoundingSphere().empty())
490 _nodeVector.push_back(bvNode);
493 virtual void apply(osg::PagedLOD& pagedLOD)
495 float range = std::numeric_limits<float>::max();
496 unsigned numFileNames = pagedLOD.getNumFileNames();
497 for (unsigned i = 0; i < numFileNames; ++i) {
498 if (range < pagedLOD.getMaxRange(i))
500 range = pagedLOD.getMaxRange(i);
503 std::vector<std::string> nameList;
504 for (unsigned i = pagedLOD.getNumChildren(); i < pagedLOD.getNumFileNames(); ++i) {
505 if (pagedLOD.getMaxRange(i) <= range) {
506 nameList.push_back(pagedLOD.getFileName(i));
510 if (!nameList.empty()) {
511 SGSphered boundingSphere(toVec3d(toSG(pagedLOD.getCenter())), pagedLOD.getRadius());
512 _nodeVector.push_back(new BVHPageNodeOSG(nameList, boundingSphere, pagedLOD.getDatabaseOptions()));
515 // For the rest that might be already there, traverse this as lod
516 apply(static_cast<osg::LOD&>(pagedLOD));
519 virtual void apply(osg::ProxyNode& proxyNode)
521 unsigned numFileNames = proxyNode.getNumFileNames();
522 for (unsigned i = 0; i < numFileNames; ++i) {
523 if (i < proxyNode.getNumChildren() && proxyNode.getChild(i))
525 // FIXME evaluate proxyNode.getDatabasePath()
526 osg::ref_ptr<osg::Node> node;
527 node = osgDB::readNodeFile(proxyNode.getFileName(i),
528 dynamic_cast<const osgDB::Options*>(proxyNode.getDatabaseOptions()));
530 node = new osg::Group;
531 if (i < proxyNode.getNumChildren())
532 proxyNode.setChild(i, node);
534 proxyNode.addChild(node);
537 apply(static_cast<osg::Group&>(proxyNode));
540 SGSharedPtr<BVHNode> getBVHNode()
542 addBoundingVolumeTreeToNode();
544 if (_nodeVector.empty())
545 return SGSharedPtr<BVHNode>();
546 if (_nodeVector.size() == 1)
547 return _nodeVector.front();
548 SGSharedPtr<BVHGroup> group = new BVHGroup;
549 for (NodeVector::iterator i = _nodeVector.begin();
550 i != _nodeVector.end(); ++i)
551 group->addChild(i->get());
556 PFunctor _primitiveFunctor;
557 typedef std::vector<SGSharedPtr<BVHNode> > NodeVector;
558 NodeVector _nodeVector;
561 class BVHPageNodeOSG::_Request : public BVHPageRequest {
563 _Request(BVHPageNodeOSG* pageNode) :
572 if (!_pageNode.valid())
574 for (std::vector<std::string>::const_iterator i = _pageNode->_modelList.begin();
575 i != _pageNode->_modelList.end(); ++i) {
576 SGSharedPtr<BVHNode> node = BVHPageNodeOSG::load(*i, _pageNode->_options);
579 _nodeVector.push_back(node);
582 virtual void insert()
584 if (!_pageNode.valid())
586 for (unsigned i = 0; i < _nodeVector.size(); ++i)
587 _pageNode->addChild(_nodeVector[i].get());
589 virtual BVHPageNode* getPageNode()
591 return _pageNode.get();
594 SGSharedPtr<BVHPageNodeOSG> _pageNode;
595 std::vector<SGSharedPtr<BVHNode> > _nodeVector;
599 BVHPageNodeOSG::load(const std::string& name, const osg::ref_ptr<osg::Referenced>& options)
601 osg::ref_ptr<osg::Node> node;
602 node = osgDB::readNodeFile(name, dynamic_cast<const osgDB::Options*>(options.get()));
604 return SGSharedPtr<BVHNode>();
606 _NodeVisitor nodeVisitor;
607 node->accept(nodeVisitor);
608 return nodeVisitor.getBVHNode();
611 BVHPageNodeOSG::BVHPageNodeOSG(const std::string& name,
612 const SGSphered& boundingSphere,
613 const osg::ref_ptr<osg::Referenced>& options) :
614 _boundingSphere(boundingSphere),
617 _modelList.push_back(name);
620 BVHPageNodeOSG::BVHPageNodeOSG(const std::vector<std::string>& nameList,
621 const SGSphered& boundingSphere,
622 const osg::ref_ptr<osg::Referenced>& options) :
623 _modelList(nameList),
624 _boundingSphere(boundingSphere),
629 BVHPageNodeOSG::~BVHPageNodeOSG()
634 BVHPageNodeOSG::newRequest()
636 return new _Request(this);
640 BVHPageNodeOSG::setBoundingSphere(const SGSphered& sphere)
642 _boundingSphere = sphere;
643 invalidateParentBound();
647 BVHPageNodeOSG::computeBoundingSphere() const
649 return _boundingSphere;
653 BVHPageNodeOSG::invalidateBound()
655 // Don't propagate invalidate bound to its parent
656 // Just do this once we get a bounding sphere set