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.
18 #include "BVHPageNodeOSG.hxx"
20 #include "../../bvh/BVHPageRequest.hxx"
21 #include "../../bvh/BVHPager.hxx"
24 #include <osg/Drawable>
27 #include <osg/PagedLOD>
28 #include <osg/ProxyNode>
29 #include <osg/Transform>
30 #include <osg/TriangleFunctor>
31 #include <osgDB/ReadFile>
33 #include <simgear/scene/material/mat.hxx>
34 #include <simgear/scene/material/matlib.hxx>
35 #include <simgear/scene/util/SGNodeMasks.hxx>
36 #include <simgear/scene/util/OsgMath.hxx>
37 #include <simgear/scene/util/SGSceneUserData.hxx>
38 #include <simgear/math/SGGeometry.hxx>
40 #include <simgear/bvh/BVHStaticGeometryBuilder.hxx>
44 class BVHPageNodeOSG::_NodeVisitor : public osg::NodeVisitor {
46 class PFunctor : public osg::PrimitiveFunctor {
51 _geometryBuilder = new BVHStaticGeometryBuilder;
56 virtual void setVertexArray(unsigned int count, const osg::Vec2* vertices)
58 _vertices.resize(count);
59 for (unsigned i = 0; i < count; ++i)
60 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
63 virtual void setVertexArray(unsigned int count, const osg::Vec3* vertices)
65 _vertices.resize(count);
66 for (unsigned i = 0; i < count; ++i)
67 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], vertices[i][2]);
70 virtual void setVertexArray(unsigned int count, const osg::Vec4* vertices)
72 _vertices.resize(count);
73 for (unsigned i = 0; i < count; ++i)
74 _vertices[i] = SGVec3f(vertices[i][0]/vertices[i][3],
75 vertices[i][1]/vertices[i][3],
76 vertices[i][2]/vertices[i][3]);
79 virtual void setVertexArray(unsigned int count, const osg::Vec2d* vertices)
81 _vertices.resize(count);
82 for (unsigned i = 0; i < count; ++i)
83 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
86 virtual void setVertexArray(unsigned int count, const osg::Vec3d* vertices)
88 _vertices.resize(count);
89 for (unsigned i = 0; i < count; ++i)
90 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], vertices[i][2]);
93 virtual void setVertexArray(unsigned int count, const osg::Vec4d* vertices)
95 _vertices.resize(count);
96 for (unsigned i = 0; i < count; ++i)
97 _vertices[i] = SGVec3f(vertices[i][0]/vertices[i][3],
98 vertices[i][1]/vertices[i][3],
99 vertices[i][2]/vertices[i][3]);
102 virtual void drawArrays(GLenum mode, GLint first, GLsizei count)
104 if (_vertices.empty() || count <= 0)
107 GLsizei end = first + count;
110 for (GLsizei i = first; i < end - 2; i += 3) {
111 addTriangle(i, i + 1, i + 2);
115 case (GL_TRIANGLE_STRIP):
116 for (GLsizei i = first; i < end - 2; ++i) {
117 addTriangle(i, i + 1, i + 2);
122 for (GLsizei i = first; i < end - 3; i += 4) {
123 addQuad(i, i + 1, i + 2, i + 3);
127 case (GL_QUAD_STRIP):
128 for (GLsizei i = first; i < end - 3; i += 2) {
129 addQuad(i, i + 1, i + 2, i + 3);
133 case (GL_POLYGON): // treat polygons as GL_TRIANGLE_FAN
134 case (GL_TRIANGLE_FAN):
135 for (GLsizei i = first; i < end - 2; ++i) {
136 addTriangle(first, i + 1, i + 2);
141 for (GLsizei i = first; i < end; ++i) {
147 for (GLsizei i = first; i < end - 1; i += 2) {
152 case (GL_LINE_STRIP):
153 for (GLsizei i = first; i < end - 1; ++i) {
159 for (GLsizei i = first; i < end - 1; ++i) {
162 addLine(end - 1, first);
170 virtual void drawElements(GLenum mode, GLsizei count, const GLubyte* indices)
172 drawElementsTemplate(mode, count, indices);
175 virtual void drawElements(GLenum mode, GLsizei count, const GLushort* indices)
177 drawElementsTemplate(mode, count, indices);
180 virtual void drawElements(GLenum mode, GLsizei count, const GLuint* indices)
182 drawElementsTemplate(mode, count, indices);
185 virtual void begin(GLenum mode)
191 virtual void vertex(const osg::Vec2& v)
193 _vertices.push_back(SGVec3f(v[0], v[1], 0));
195 virtual void vertex(const osg::Vec3& v)
197 _vertices.push_back(SGVec3f(v[0], v[1], v[2]));
199 virtual void vertex(const osg::Vec4& v)
201 _vertices.push_back(SGVec3f(v[0]/v[3], v[1]/v[3], v[2]/v[3]));
203 virtual void vertex(float x, float y)
205 _vertices.push_back(SGVec3f(x, y, 0));
207 virtual void vertex(float x, float y, float z)
209 _vertices.push_back(SGVec3f(x, y, z));
211 virtual void vertex(float x, float y, float z, float w)
213 _vertices.push_back(SGVec3f(x/w, y/w, z/w));
217 if (_vertices.empty())
220 drawArrays(_modeCache, 0, _vertices.size());
223 template<typename index_type>
224 void drawElementsTemplate(GLenum mode, GLsizei count,
225 const index_type* indices)
227 if (_vertices.empty() || indices == 0 || count <= 0)
232 for (GLsizei i = 0; i < count - 2; i += 3) {
233 addTriangle(indices[i], indices[i + 1], indices[i + 2]);
237 case (GL_TRIANGLE_STRIP):
238 for (GLsizei i = 0; i < count - 2; ++i) {
239 addTriangle(indices[i], indices[i + 1], indices[i + 2]);
244 for (GLsizei i = 0; i < count - 3; i += 4) {
245 addQuad(indices[i], indices[i + 1], indices[i + 2], indices[i + 3]);
249 case (GL_QUAD_STRIP):
250 for (GLsizei i = 0; i < count - 3; i += 2) {
251 addQuad(indices[i], indices[i + 1], indices[i + 2], indices[i + 3]);
256 case (GL_TRIANGLE_FAN):
257 for (GLsizei i = 0; i < count - 2; ++i) {
258 addTriangle(indices[0], indices[i + 1], indices[i + 2]);
263 for(GLsizei i = 0; i < count; ++i) {
264 addPoint(indices[i]);
269 for (GLsizei i = 0; i < count - 1; i += 2) {
270 addLine(indices[i], indices[i + 1]);
274 case (GL_LINE_STRIP):
275 for (GLsizei i = 0; i < count - 1; ++i) {
276 addLine(indices[i], indices[i + 1]);
281 for (GLsizei i = 0; i < count - 1; ++i) {
282 addLine(indices[i], indices[i + 1]);
284 addLine(indices[count - 1], indices[0]);
292 void addPoint(unsigned i1)
294 addPoint(_vertices[i1]);
296 void addLine(unsigned i1, unsigned i2)
298 addLine(_vertices[i1], _vertices[i2]);
300 void addTriangle(unsigned i1, unsigned i2, unsigned i3)
302 addTriangle(_vertices[i1], _vertices[i2], _vertices[i3]);
304 void addQuad(unsigned i1, unsigned i2, unsigned i3, unsigned i4)
306 addQuad(_vertices[i1], _vertices[i2], _vertices[i3], _vertices[i4]);
309 void addPoint(const SGVec3f& v1)
312 void addLine(const SGVec3f& v1, const SGVec3f& v2)
315 void addTriangle(const SGVec3f& v1, const SGVec3f& v2, const SGVec3f& v3)
317 _geometryBuilder->addTriangle(v1, v2, v3);
319 void addQuad(const SGVec3f& v1, const SGVec3f& v2,
320 const SGVec3f& v3, const SGVec3f& v4)
322 _geometryBuilder->addTriangle(v1, v2, v3);
323 _geometryBuilder->addTriangle(v1, v3, v4);
326 BVHNode* buildTreeAndClear()
328 BVHNode* bvNode = _geometryBuilder->buildTree();
329 _geometryBuilder = new BVHStaticGeometryBuilder;
334 void swap(PFunctor& primitiveFunctor)
336 _vertices.swap(primitiveFunctor._vertices);
337 std::swap(_modeCache, primitiveFunctor._modeCache);
338 std::swap(_geometryBuilder, primitiveFunctor._geometryBuilder);
341 void setCurrentMaterial(const BVHMaterial* material)
343 _geometryBuilder->setCurrentMaterial(material);
345 const BVHMaterial* getCurrentMaterial() const
347 return _geometryBuilder->getCurrentMaterial();
350 std::vector<SGVec3f> _vertices;
353 SGSharedPtr<BVHStaticGeometryBuilder> _geometryBuilder;
357 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN)
359 setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
361 virtual ~_NodeVisitor()
365 const BVHMaterial* pushMaterial(osg::Geode* geode)
367 const BVHMaterial* oldMaterial = _primitiveFunctor.getCurrentMaterial();
368 const BVHMaterial* material = SGMaterialLib::findMaterial(geode);
370 _primitiveFunctor.setCurrentMaterial(material);
374 virtual void apply(osg::Geode& geode)
376 const BVHMaterial* oldMaterial = pushMaterial(&geode);
378 for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
379 geode.getDrawable(i)->accept(_primitiveFunctor);
381 _primitiveFunctor.setCurrentMaterial(oldMaterial);
384 virtual void apply(osg::Group& group)
386 // FIXME optimize this to collapse more leafs
388 // push the current active primitive list
389 PFunctor previousPrimitives;
390 _primitiveFunctor.swap(previousPrimitives);
392 const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
393 _primitiveFunctor.setCurrentMaterial(mat);
395 NodeVector nodeVector;
396 _nodeVector.swap(nodeVector);
401 // We know whenever we see a transform, we need to flush the
402 // collected bounding volume tree since these transforms are not
403 // handled by the plain leafs.
404 addBoundingVolumeTreeToNode();
406 _nodeVector.swap(nodeVector);
408 if (!nodeVector.empty()) {
409 if (nodeVector.size() == 1) {
410 _nodeVector.push_back(nodeVector.front());
412 SGSharedPtr<BVHGroup> group = new BVHGroup;
413 for (NodeVector::iterator i = nodeVector.begin();
414 i != nodeVector.end(); ++i)
415 group->addChild(i->get());
416 _nodeVector.push_back(group);
420 // pop the current active primitive list
421 _primitiveFunctor.swap(previousPrimitives);
424 virtual void apply(osg::Transform& transform)
426 if (transform.getReferenceFrame() != osg::Transform::RELATIVE_RF)
430 if (!transform.computeLocalToWorldMatrix(matrix, this))
433 // push the current active primitive list
434 PFunctor previousPrimitives;
435 _primitiveFunctor.swap(previousPrimitives);
437 const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
438 _primitiveFunctor.setCurrentMaterial(mat);
440 NodeVector nodeVector;
441 _nodeVector.swap(nodeVector);
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();
451 _nodeVector.swap(nodeVector);
453 // pop the current active primitive list
454 _primitiveFunctor.swap(previousPrimitives);
456 if (!nodeVector.empty()) {
457 SGSharedPtr<BVHTransform> bvhTransform = new BVHTransform;
458 bvhTransform->setToWorldTransform(SGMatrixd(matrix.ptr()));
460 for (NodeVector::iterator i = nodeVector.begin();
461 i != nodeVector.end(); ++i)
462 bvhTransform->addChild(i->get());
464 _nodeVector.push_back(bvhTransform);
468 virtual void apply(osg::Camera& camera)
470 if (camera.getRenderOrder() != osg::Camera::NESTED_RENDER)
472 apply(static_cast<osg::Transform&>(camera));
475 void addBoundingVolumeTreeToNode()
477 // Build the flat tree.
478 BVHNode* bvNode = _primitiveFunctor.buildTreeAndClear();
483 if (bvNode->getBoundingSphere().empty())
486 _nodeVector.push_back(bvNode);
489 virtual void apply(osg::PagedLOD& pagedLOD)
491 float range = std::numeric_limits<float>::max();
492 unsigned numFileNames = pagedLOD.getNumFileNames();
493 for (unsigned i = 0; i < numFileNames; ++i) {
494 if (range < pagedLOD.getMaxRange(i))
496 range = pagedLOD.getMaxRange(i);
499 std::vector<std::string> nameList;
500 for (unsigned i = pagedLOD.getNumChildren(); i < pagedLOD.getNumFileNames(); ++i) {
501 if (pagedLOD.getMaxRange(i) <= range) {
502 nameList.push_back(pagedLOD.getFileName(i));
506 if (!nameList.empty()) {
507 SGSphered boundingSphere(toVec3d(toSG(pagedLOD.getCenter())), pagedLOD.getRadius());
508 _nodeVector.push_back(new BVHPageNodeOSG(nameList, boundingSphere, pagedLOD.getDatabaseOptions()));
511 // For the rest that might be already there, traverse this as lod
512 apply(static_cast<osg::LOD&>(pagedLOD));
515 virtual void apply(osg::ProxyNode& proxyNode)
517 unsigned numFileNames = proxyNode.getNumFileNames();
518 for (unsigned i = 0; i < numFileNames; ++i) {
519 if (i < proxyNode.getNumChildren() && proxyNode.getChild(i))
521 // FIXME evaluate proxyNode.getDatabasePath()
522 osg::ref_ptr<osg::Node> node;
523 node = osgDB::readNodeFile(proxyNode.getFileName(i),
524 dynamic_cast<const osgDB::Options*>(proxyNode.getDatabaseOptions()));
526 node = new osg::Group;
527 if (i < proxyNode.getNumChildren())
528 proxyNode.setChild(i, node);
530 proxyNode.addChild(node);
533 apply(static_cast<osg::Group&>(proxyNode));
536 SGSharedPtr<BVHNode> getBVHNode()
538 addBoundingVolumeTreeToNode();
540 if (_nodeVector.empty())
541 return SGSharedPtr<BVHNode>();
542 if (_nodeVector.size() == 1)
543 return _nodeVector.front();
544 SGSharedPtr<BVHGroup> group = new BVHGroup;
545 for (NodeVector::iterator i = _nodeVector.begin();
546 i != _nodeVector.end(); ++i)
547 group->addChild(i->get());
552 PFunctor _primitiveFunctor;
553 typedef std::vector<SGSharedPtr<BVHNode> > NodeVector;
554 NodeVector _nodeVector;
557 class BVHPageNodeOSG::_Request : public BVHPageRequest {
559 _Request(BVHPageNodeOSG* pageNode) :
568 if (!_pageNode.valid())
570 for (std::vector<std::string>::const_iterator i = _pageNode->_modelList.begin();
571 i != _pageNode->_modelList.end(); ++i) {
572 SGSharedPtr<BVHNode> node = BVHPageNodeOSG::load(*i, _pageNode->_options);
575 _nodeVector.push_back(node);
578 virtual void insert()
580 if (!_pageNode.valid())
582 for (unsigned i = 0; i < _nodeVector.size(); ++i)
583 _pageNode->addChild(_nodeVector[i].get());
585 virtual BVHPageNode* getPageNode()
587 return _pageNode.get();
590 SGSharedPtr<BVHPageNodeOSG> _pageNode;
591 std::vector<SGSharedPtr<BVHNode> > _nodeVector;
595 BVHPageNodeOSG::load(const std::string& name, const osg::ref_ptr<osg::Referenced>& options)
597 osg::ref_ptr<osg::Node> node;
598 node = osgDB::readNodeFile(name, dynamic_cast<const osgDB::Options*>(options.get()));
600 return SGSharedPtr<BVHNode>();
602 _NodeVisitor nodeVisitor;
603 node->accept(nodeVisitor);
604 return nodeVisitor.getBVHNode();
607 BVHPageNodeOSG::BVHPageNodeOSG(const std::string& name,
608 const SGSphered& boundingSphere,
609 const osg::ref_ptr<osg::Referenced>& options) :
610 _boundingSphere(boundingSphere),
613 _modelList.push_back(name);
616 BVHPageNodeOSG::BVHPageNodeOSG(const std::vector<std::string>& nameList,
617 const SGSphered& boundingSphere,
618 const osg::ref_ptr<osg::Referenced>& options) :
619 _modelList(nameList),
620 _boundingSphere(boundingSphere),
625 BVHPageNodeOSG::~BVHPageNodeOSG()
630 BVHPageNodeOSG::newRequest()
632 return new _Request(this);
636 BVHPageNodeOSG::setBoundingSphere(const SGSphered& sphere)
638 _boundingSphere = sphere;
639 invalidateParentBound();
643 BVHPageNodeOSG::computeBoundingSphere() const
645 return _boundingSphere;
649 BVHPageNodeOSG::invalidateBound()
651 // Don't propagate invalidate bound to its parent
652 // Just do this once we get a bounding sphere set