]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/BVHPageNodeOSG.cxx
bvh: Implement paging for osg derived bvh trees.
[simgear.git] / simgear / scene / model / BVHPageNodeOSG.cxx
1 // Copyright (C) 2008 - 2012  Mathias Froehlich - Mathias.Froehlich@web.de
2 //
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.
7 //
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.
12 //
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.
16 //
17
18 #include "BVHPageNodeOSG.hxx"
19
20 #include "../../bvh/BVHPageRequest.hxx"
21 #include "../../bvh/BVHPager.hxx"
22
23 #include <osg/Camera>
24 #include <osg/Drawable>
25 #include <osg/Geode>
26 #include <osg/Group>
27 #include <osg/PagedLOD>
28 #include <osg/ProxyNode>
29 #include <osg/Transform>
30 #include <osg/TriangleFunctor>
31 #include <osgDB/ReadFile>
32
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>
39
40 #include <simgear/bvh/BVHStaticGeometryBuilder.hxx>
41
42 namespace simgear {
43
44 class BVHPageNodeOSG::_NodeVisitor : public osg::NodeVisitor {
45 public:
46     class PFunctor : public osg::PrimitiveFunctor {
47     public:
48         PFunctor() :
49             _modeCache(0)
50         {
51             _geometryBuilder = new BVHStaticGeometryBuilder;
52         }
53         virtual ~PFunctor()
54         { }
55
56         virtual void setVertexArray(unsigned int count, const osg::Vec2* vertices)
57         {
58             _vertices.resize(count);
59             for (unsigned i = 0; i < count; ++i)
60                 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
61         }
62
63         virtual void setVertexArray(unsigned int count, const osg::Vec3* vertices)
64         {
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]);
68         }
69
70         virtual void setVertexArray(unsigned int count, const osg::Vec4* vertices)
71         {
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]);
77         }
78
79         virtual void setVertexArray(unsigned int count, const osg::Vec2d* vertices)
80         {
81             _vertices.resize(count);
82             for (unsigned i = 0; i < count; ++i)
83                 _vertices[i] = SGVec3f(vertices[i][0], vertices[i][1], 0);
84         }
85
86         virtual void setVertexArray(unsigned int count, const osg::Vec3d* vertices)
87         {
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]);
91         }
92
93         virtual void setVertexArray(unsigned int count, const osg::Vec4d* vertices) 
94         {
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]);
100         }
101
102         virtual void drawArrays(GLenum mode, GLint first, GLsizei count)
103         {
104             if (_vertices.empty() || count <= 0)
105                 return;
106
107             GLsizei end = first + count;
108             switch(mode) {
109             case (GL_TRIANGLES):
110                 for (GLsizei i = first; i < end - 2; i += 3) {
111                     addTriangle(i, i + 1, i + 2);
112                 }
113                 break;
114
115             case (GL_TRIANGLE_STRIP):
116                 for (GLsizei i = first; i < end - 2; ++i) {
117                     addTriangle(i, i + 1, i + 2);
118                 }
119                 break;
120
121             case (GL_QUADS):
122                 for (GLsizei i = first; i < end - 3; i += 4) {
123                     addQuad(i, i + 1, i + 2, i + 3);
124                 }
125                 break;
126
127             case (GL_QUAD_STRIP):
128                 for (GLsizei i = first; i < end - 3; i += 2) {
129                     addQuad(i, i + 1, i + 2, i + 3);
130                 }
131                 break;
132
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);
137                 }
138                 break;
139
140             case (GL_POINTS):
141                 for (GLsizei i = first; i < end; ++i) {
142                     addPoint(i);
143                 }
144                 break;
145
146             case (GL_LINES):
147                 for (GLsizei i = first; i < end - 1; i += 2) {
148                     addLine(i, i + 1);
149                 }
150                 break;
151
152             case (GL_LINE_STRIP):
153                 for (GLsizei i = first; i < end - 1; ++i) {
154                     addLine(i, i + 1);
155                 }
156                 break;
157
158             case (GL_LINE_LOOP):
159                 for (GLsizei i = first; i < end - 1; ++i) {
160                     addLine(i, i + 1);
161                 }
162                 addLine(end - 1, first);
163                 break;
164
165             default:
166                 break;
167             }
168         }
169   
170         virtual void drawElements(GLenum mode, GLsizei count, const GLubyte* indices)
171         {
172             drawElementsTemplate(mode, count, indices);
173         }
174
175         virtual void drawElements(GLenum mode, GLsizei count, const GLushort* indices)
176         {
177             drawElementsTemplate(mode, count, indices);
178         }
179
180         virtual void drawElements(GLenum mode, GLsizei count, const GLuint* indices)
181         {
182             drawElementsTemplate(mode, count, indices);
183         }
184
185         virtual void begin(GLenum mode)
186         {
187             _modeCache = mode;
188             _vertices.resize(0);
189         }
190
191         virtual void vertex(const osg::Vec2& v)
192         {
193             _vertices.push_back(SGVec3f(v[0], v[1], 0));
194         }
195         virtual void vertex(const osg::Vec3& v)
196         {
197             _vertices.push_back(SGVec3f(v[0], v[1], v[2]));
198         }
199         virtual void vertex(const osg::Vec4& v)
200         {
201             _vertices.push_back(SGVec3f(v[0]/v[3], v[1]/v[3], v[2]/v[3]));
202         }
203         virtual void vertex(float x, float y)
204         {
205             _vertices.push_back(SGVec3f(x, y, 0));
206         }
207         virtual void vertex(float x, float y, float z)
208         {
209             _vertices.push_back(SGVec3f(x, y, z));
210         }
211         virtual void vertex(float x, float y, float z, float w)
212         {
213             _vertices.push_back(SGVec3f(x/w, y/w, z/w));
214         }
215         virtual void end()
216         {
217             if (_vertices.empty())
218                 return;
219
220             drawArrays(_modeCache, 0, _vertices.size());
221         }
222
223         template<typename index_type>
224         void drawElementsTemplate(GLenum mode, GLsizei count,
225                                   const index_type* indices)
226         {
227             if (_vertices.empty() || indices == 0 || count <= 0)
228                 return;
229     
230             switch(mode) {
231             case (GL_TRIANGLES):
232                 for (GLsizei i = 0; i < count - 2; i += 3) {
233                     addTriangle(indices[i], indices[i + 1], indices[i + 2]);
234                 }
235                 break;
236
237             case (GL_TRIANGLE_STRIP):
238                 for (GLsizei i = 0; i < count - 2; ++i) {
239                     addTriangle(indices[i], indices[i + 1], indices[i + 2]);
240                 }
241                 break;
242
243             case (GL_QUADS):
244                 for (GLsizei i = 0; i < count - 3; i += 4) {
245                     addQuad(indices[i], indices[i + 1], indices[i + 2], indices[i + 3]);
246                 }
247                 break;
248
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]);
252                 }
253                 break;
254
255             case (GL_POLYGON):
256             case (GL_TRIANGLE_FAN):
257                 for (GLsizei i = 0; i < count - 2; ++i) {
258                     addTriangle(indices[0], indices[i + 1], indices[i + 2]);
259                 }
260                 break;
261
262             case (GL_POINTS):
263                 for(GLsizei i = 0; i < count; ++i) {
264                     addPoint(indices[i]);
265                 }
266                 break;
267
268             case (GL_LINES):
269                 for (GLsizei i = 0; i < count - 1; i += 2) {
270                     addLine(indices[i], indices[i + 1]);
271                 }
272                 break;
273
274             case (GL_LINE_STRIP):
275                 for (GLsizei i = 0; i < count - 1; ++i) {
276                     addLine(indices[i], indices[i + 1]);
277                 }
278                 break;
279
280             case (GL_LINE_LOOP):
281                 for (GLsizei i = 0; i < count - 1; ++i) {
282                     addLine(indices[i], indices[i + 1]);
283                 }
284                 addLine(indices[count - 1], indices[0]);
285                 break;
286
287             default:
288                 break;
289             }
290         }    
291
292         void addPoint(unsigned i1)
293         {
294             addPoint(_vertices[i1]);
295         }
296         void addLine(unsigned i1, unsigned i2)
297         {
298             addLine(_vertices[i1], _vertices[i2]);
299         }
300         void addTriangle(unsigned i1, unsigned i2, unsigned i3)
301         {
302             addTriangle(_vertices[i1], _vertices[i2], _vertices[i3]);
303         }
304         void addQuad(unsigned i1, unsigned i2, unsigned i3, unsigned i4)
305         {
306             addQuad(_vertices[i1], _vertices[i2], _vertices[i3], _vertices[i4]);
307         }
308
309         void addPoint(const SGVec3f& v1)
310         {
311         }
312         void addLine(const SGVec3f& v1, const SGVec3f& v2)
313         {
314         }
315         void addTriangle(const SGVec3f& v1, const SGVec3f& v2, const SGVec3f& v3)
316         {
317             _geometryBuilder->addTriangle(v1, v2, v3);
318         }
319         void addQuad(const SGVec3f& v1, const SGVec3f& v2,
320                      const SGVec3f& v3, const SGVec3f& v4)
321         {
322             _geometryBuilder->addTriangle(v1, v2, v3);
323             _geometryBuilder->addTriangle(v1, v3, v4);
324         }
325
326         BVHNode* buildTreeAndClear()
327         {
328             BVHNode* bvNode = _geometryBuilder->buildTree();
329             _geometryBuilder = new BVHStaticGeometryBuilder;
330             _vertices.clear();
331             return bvNode;
332         }
333
334         void swap(PFunctor& primitiveFunctor)
335         {
336             _vertices.swap(primitiveFunctor._vertices);
337             std::swap(_modeCache, primitiveFunctor._modeCache);
338             std::swap(_geometryBuilder, primitiveFunctor._geometryBuilder);
339         }
340
341         void setCurrentMaterial(const BVHMaterial* material)
342         {
343             _geometryBuilder->setCurrentMaterial(material);
344         }
345         const BVHMaterial* getCurrentMaterial() const
346         {
347             return _geometryBuilder->getCurrentMaterial();
348         }
349
350         std::vector<SGVec3f> _vertices;
351         GLenum _modeCache;
352
353         SGSharedPtr<BVHStaticGeometryBuilder> _geometryBuilder;
354     };
355
356     _NodeVisitor() :
357         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN)
358     {
359         setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
360     }
361     virtual ~_NodeVisitor()
362     {
363     }
364
365     const BVHMaterial* pushMaterial(osg::Geode* geode)
366     {
367         const BVHMaterial* oldMaterial = _primitiveFunctor.getCurrentMaterial();
368         const BVHMaterial* material = SGMaterialLib::findMaterial(geode);
369         if (material)
370             _primitiveFunctor.setCurrentMaterial(material);
371         return oldMaterial;
372     }
373
374     virtual void apply(osg::Geode& geode)
375     {
376         const BVHMaterial* oldMaterial = pushMaterial(&geode);
377
378         for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
379             geode.getDrawable(i)->accept(_primitiveFunctor);
380
381         _primitiveFunctor.setCurrentMaterial(oldMaterial);
382     }
383
384     virtual void apply(osg::Group& group)
385     {
386         // FIXME optimize this to collapse more leafs
387
388         // push the current active primitive list
389         PFunctor previousPrimitives;
390         _primitiveFunctor.swap(previousPrimitives);
391
392         const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
393         _primitiveFunctor.setCurrentMaterial(mat);
394
395         NodeVector nodeVector;
396         _nodeVector.swap(nodeVector);
397
398         // walk the children
399         traverse(group);
400
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();
405
406         _nodeVector.swap(nodeVector);
407
408         if (!nodeVector.empty()) {
409             if (nodeVector.size() == 1) {
410                 _nodeVector.push_back(nodeVector.front());
411             } else {
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);
417             }
418         }
419
420         // pop the current active primitive list
421         _primitiveFunctor.swap(previousPrimitives);
422     }
423
424     virtual void apply(osg::Transform& transform)
425     {
426         if (transform.getReferenceFrame() != osg::Transform::RELATIVE_RF)
427             return;
428
429         osg::Matrix matrix;
430         if (!transform.computeLocalToWorldMatrix(matrix, this))
431             return;
432
433         // push the current active primitive list
434         PFunctor previousPrimitives;
435         _primitiveFunctor.swap(previousPrimitives);
436
437         const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
438         _primitiveFunctor.setCurrentMaterial(mat);
439
440         NodeVector nodeVector;
441         _nodeVector.swap(nodeVector);
442
443         // walk the children
444         traverse(transform);
445
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();
450
451         _nodeVector.swap(nodeVector);
452
453         // pop the current active primitive list
454         _primitiveFunctor.swap(previousPrimitives);
455
456         if (!nodeVector.empty()) {
457             SGSharedPtr<BVHTransform> bvhTransform = new BVHTransform;
458             bvhTransform->setToWorldTransform(SGMatrixd(matrix.ptr()));
459
460             for (NodeVector::iterator i = nodeVector.begin();
461                  i != nodeVector.end(); ++i)
462                 bvhTransform->addChild(i->get());
463
464             _nodeVector.push_back(bvhTransform);
465         }
466     }
467
468     virtual void apply(osg::Camera& camera)
469     {
470         if (camera.getRenderOrder() != osg::Camera::NESTED_RENDER)
471             return;
472         apply(static_cast<osg::Transform&>(camera));
473     }
474
475     void addBoundingVolumeTreeToNode()
476     {
477         // Build the flat tree.
478         BVHNode* bvNode = _primitiveFunctor.buildTreeAndClear();
479
480         // Nothing in there?
481         if (!bvNode)
482             return;
483         if (bvNode->getBoundingSphere().empty())
484             return;
485
486         _nodeVector.push_back(bvNode);
487     }
488
489     virtual void apply(osg::PagedLOD& pagedLOD)
490     {
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))
495                 continue;
496             range = pagedLOD.getMaxRange(i);
497         }
498
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));
503             }
504         }
505
506         if (!nameList.empty()) {
507             SGSphered boundingSphere(toVec3d(toSG(pagedLOD.getCenter())), pagedLOD.getRadius());
508             _nodeVector.push_back(new BVHPageNodeOSG(nameList, boundingSphere, pagedLOD.getDatabaseOptions()));
509         }
510
511         // For the rest that might be already there, traverse this as lod
512         apply(static_cast<osg::LOD&>(pagedLOD));
513     }
514
515     virtual void apply(osg::ProxyNode& proxyNode)
516     {
517         unsigned numFileNames = proxyNode.getNumFileNames();
518         for (unsigned i = 0; i < numFileNames; ++i) {
519             if (i < proxyNode.getNumChildren() && proxyNode.getChild(i))
520                 continue;
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()));
525             if (!node.valid())
526                 node = new osg::Group;
527             if (i < proxyNode.getNumChildren())
528                 proxyNode.setChild(i, node);
529             else
530                 proxyNode.addChild(node);
531         }
532
533         apply(static_cast<osg::Group&>(proxyNode));
534     }
535
536     SGSharedPtr<BVHNode> getBVHNode()
537     {
538         addBoundingVolumeTreeToNode();
539
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());
548         return group;
549     }
550
551 private:
552     PFunctor _primitiveFunctor;
553     typedef std::vector<SGSharedPtr<BVHNode> > NodeVector;
554     NodeVector _nodeVector;
555 };
556
557 class BVHPageNodeOSG::_Request : public BVHPageRequest {
558 public:
559     _Request(BVHPageNodeOSG* pageNode) :
560         _pageNode(pageNode)
561     {
562     }
563     virtual ~_Request()
564     {
565     }
566     virtual void load()
567     {
568         if (!_pageNode.valid())
569             return;
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);
573             if (!node.valid())
574                 continue;
575             _nodeVector.push_back(node);
576         }
577     }
578     virtual void insert()
579     {
580         if (!_pageNode.valid())
581             return;
582         for (unsigned i = 0; i < _nodeVector.size(); ++i)
583             _pageNode->addChild(_nodeVector[i].get());
584     }
585     virtual BVHPageNode* getPageNode()
586     {
587         return _pageNode.get();
588     }
589
590     SGSharedPtr<BVHPageNodeOSG> _pageNode;
591     std::vector<SGSharedPtr<BVHNode> > _nodeVector;
592 };
593
594 SGSharedPtr<BVHNode>
595 BVHPageNodeOSG::load(const std::string& name, const osg::ref_ptr<osg::Referenced>& options)
596 {
597     osg::ref_ptr<osg::Node> node;
598     node = osgDB::readNodeFile(name, dynamic_cast<const osgDB::Options*>(options.get()));
599     if (!node.valid())
600         return SGSharedPtr<BVHNode>();
601
602     _NodeVisitor nodeVisitor;
603     node->accept(nodeVisitor);
604     return nodeVisitor.getBVHNode();
605 }
606
607 BVHPageNodeOSG::BVHPageNodeOSG(const std::string& name,
608                                const SGSphered& boundingSphere,
609                                const osg::ref_ptr<osg::Referenced>& options) :
610     _boundingSphere(boundingSphere),
611     _options(options)
612 {
613     _modelList.push_back(name);
614 }
615
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),
621     _options(options)
622 {
623 }
624
625 BVHPageNodeOSG::~BVHPageNodeOSG()
626 {
627 }
628     
629 BVHPageRequest*
630 BVHPageNodeOSG::newRequest()
631 {
632     return new _Request(this);
633 }
634
635 void
636 BVHPageNodeOSG::setBoundingSphere(const SGSphered& sphere)
637 {
638     _boundingSphere = sphere;
639     invalidateParentBound();
640 }
641
642 SGSphered
643 BVHPageNodeOSG::computeBoundingSphere() const
644 {
645     return _boundingSphere;
646 }
647
648 void
649 BVHPageNodeOSG::invalidateBound()
650 {
651     // Don't propagate invalidate bound to its parent
652     // Just do this once we get a bounding sphere set
653 }
654
655 }