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