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 <osgDB/ReadFile>
36 #include <simgear/scene/material/mat.hxx>
37 #include <simgear/scene/material/matlib.hxx>
38 #include <simgear/scene/util/SGNodeMasks.hxx>
39 #include <simgear/scene/util/OsgMath.hxx>
40 #include <simgear/scene/util/SGSceneUserData.hxx>
41 #include <simgear/math/SGGeometry.hxx>
43 #include <simgear/bvh/BVHStaticGeometryBuilder.hxx>
45 #include "PrimitiveCollector.hxx"
49 class BVHPageNodeOSG::_NodeVisitor : public osg::NodeVisitor {
51 class _PrimitiveCollector : public PrimitiveCollector {
53 _PrimitiveCollector() :
54 _geometryBuilder(new BVHStaticGeometryBuilder)
56 virtual ~_PrimitiveCollector()
59 virtual void addPoint(const osg::Vec3d& v1)
61 virtual void addLine(const osg::Vec3d& v1, const osg::Vec3d& v2)
63 virtual void addTriangle(const osg::Vec3d& v1, const osg::Vec3d& v2, const osg::Vec3d& v3)
65 _geometryBuilder->addTriangle(toVec3f(toSG(v1)), toVec3f(toSG(v2)), toVec3f(toSG(v3)));
68 BVHNode* buildTreeAndClear()
70 BVHNode* bvNode = _geometryBuilder->buildTree();
71 _geometryBuilder = new BVHStaticGeometryBuilder;
75 void swap(_PrimitiveCollector& primitiveCollector)
77 PrimitiveCollector::swap(primitiveCollector);
78 std::swap(_geometryBuilder, primitiveCollector._geometryBuilder);
81 void setCurrentMaterial(const BVHMaterial* material)
83 _geometryBuilder->setCurrentMaterial(material);
85 const BVHMaterial* getCurrentMaterial() const
87 return _geometryBuilder->getCurrentMaterial();
90 SGSharedPtr<BVHStaticGeometryBuilder> _geometryBuilder;
94 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN)
96 setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
98 virtual ~_NodeVisitor()
102 const BVHMaterial* pushMaterial(osg::Geode* geode)
104 const BVHMaterial* oldMaterial = _primitiveCollector.getCurrentMaterial();
105 const BVHMaterial* material = SGMaterialLib::findMaterial(geode);
107 _primitiveCollector.setCurrentMaterial(material);
111 virtual void apply(osg::Geode& geode)
113 const BVHMaterial* oldMaterial = pushMaterial(&geode);
115 for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
116 geode.getDrawable(i)->accept(_primitiveCollector);
118 _primitiveCollector.setCurrentMaterial(oldMaterial);
121 virtual void apply(osg::Group& group)
123 // FIXME optimize this to collapse more leafs
125 // push the current active primitive list
126 _PrimitiveCollector previousPrimitives;
127 _primitiveCollector.swap(previousPrimitives);
129 const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
130 _primitiveCollector.setCurrentMaterial(mat);
132 NodeVector nodeVector;
133 _nodeVector.swap(nodeVector);
138 // We know whenever we see a transform, we need to flush the
139 // collected bounding volume tree since these transforms are not
140 // handled by the plain leafs.
141 addBoundingVolumeTreeToNode();
143 _nodeVector.swap(nodeVector);
145 if (!nodeVector.empty()) {
146 if (nodeVector.size() == 1) {
147 _nodeVector.push_back(nodeVector.front());
149 SGSharedPtr<BVHGroup> group = new BVHGroup;
150 for (NodeVector::iterator i = nodeVector.begin();
151 i != nodeVector.end(); ++i)
152 group->addChild(i->get());
153 _nodeVector.push_back(group);
157 // pop the current active primitive list
158 _primitiveCollector.swap(previousPrimitives);
161 virtual void apply(osg::Transform& transform)
163 if (transform.getReferenceFrame() != osg::Transform::RELATIVE_RF)
167 if (!transform.computeLocalToWorldMatrix(matrix, this))
170 // push the current active primitive list
171 _PrimitiveCollector previousPrimitives;
172 _primitiveCollector.swap(previousPrimitives);
174 const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
175 _primitiveCollector.setCurrentMaterial(mat);
177 NodeVector nodeVector;
178 _nodeVector.swap(nodeVector);
183 // We know whenever we see a transform, we need to flush the
184 // collected bounding volume tree since these transforms are not
185 // handled by the plain leafs.
186 addBoundingVolumeTreeToNode();
188 _nodeVector.swap(nodeVector);
190 // pop the current active primitive list
191 _primitiveCollector.swap(previousPrimitives);
193 if (!nodeVector.empty()) {
194 SGSharedPtr<BVHTransform> bvhTransform = new BVHTransform;
195 bvhTransform->setToWorldTransform(SGMatrixd(matrix.ptr()));
197 for (NodeVector::iterator i = nodeVector.begin();
198 i != nodeVector.end(); ++i)
199 bvhTransform->addChild(i->get());
201 _nodeVector.push_back(bvhTransform);
205 virtual void apply(osg::Camera& camera)
207 if (camera.getRenderOrder() != osg::Camera::NESTED_RENDER)
209 apply(static_cast<osg::Transform&>(camera));
212 void addBoundingVolumeTreeToNode()
214 // Build the flat tree.
215 BVHNode* bvNode = _primitiveCollector.buildTreeAndClear();
220 if (bvNode->getBoundingSphere().empty())
223 _nodeVector.push_back(bvNode);
226 virtual void apply(osg::PagedLOD& pagedLOD)
228 float range = std::numeric_limits<float>::max();
229 unsigned numFileNames = pagedLOD.getNumFileNames();
230 for (unsigned i = 0; i < numFileNames; ++i) {
231 if (range < pagedLOD.getMaxRange(i))
233 range = pagedLOD.getMaxRange(i);
236 std::vector<std::string> nameList;
237 for (unsigned i = pagedLOD.getNumChildren(); i < pagedLOD.getNumFileNames(); ++i) {
238 if (pagedLOD.getMaxRange(i) <= range) {
239 nameList.push_back(pagedLOD.getFileName(i));
243 if (!nameList.empty()) {
244 SGSphered boundingSphere(toVec3d(toSG(pagedLOD.getCenter())), pagedLOD.getRadius());
245 _nodeVector.push_back(new BVHPageNodeOSG(nameList, boundingSphere, pagedLOD.getDatabaseOptions()));
248 // For the rest that might be already there, traverse this as lod
249 apply(static_cast<osg::LOD&>(pagedLOD));
252 virtual void apply(osg::ProxyNode& proxyNode)
254 unsigned numFileNames = proxyNode.getNumFileNames();
255 for (unsigned i = 0; i < numFileNames; ++i) {
256 if (i < proxyNode.getNumChildren() && proxyNode.getChild(i))
258 // FIXME evaluate proxyNode.getDatabasePath()
259 osg::ref_ptr<osg::Node> node;
260 node = osgDB::readNodeFile(proxyNode.getFileName(i),
261 dynamic_cast<const osgDB::Options*>(proxyNode.getDatabaseOptions()));
263 node = new osg::Group;
264 if (i < proxyNode.getNumChildren())
265 proxyNode.setChild(i, node);
267 proxyNode.addChild(node);
270 apply(static_cast<osg::Group&>(proxyNode));
273 SGSharedPtr<BVHNode> getBVHNode()
275 addBoundingVolumeTreeToNode();
277 if (_nodeVector.empty())
278 return SGSharedPtr<BVHNode>();
279 if (_nodeVector.size() == 1)
280 return _nodeVector.front();
281 SGSharedPtr<BVHGroup> group = new BVHGroup;
282 for (NodeVector::iterator i = _nodeVector.begin();
283 i != _nodeVector.end(); ++i)
284 group->addChild(i->get());
289 _PrimitiveCollector _primitiveCollector;
290 typedef std::vector<SGSharedPtr<BVHNode> > NodeVector;
291 NodeVector _nodeVector;
294 class BVHPageNodeOSG::_Request : public BVHPageRequest {
296 _Request(BVHPageNodeOSG* pageNode) :
305 if (!_pageNode.valid())
307 for (std::vector<std::string>::const_iterator i = _pageNode->_modelList.begin();
308 i != _pageNode->_modelList.end(); ++i) {
309 SGSharedPtr<BVHNode> node = BVHPageNodeOSG::load(*i, _pageNode->_options);
312 _nodeVector.push_back(node);
315 virtual void insert()
317 if (!_pageNode.valid())
319 for (unsigned i = 0; i < _nodeVector.size(); ++i)
320 _pageNode->addChild(_nodeVector[i].get());
322 virtual BVHPageNode* getPageNode()
324 return _pageNode.get();
328 SGSharedPtr<BVHPageNodeOSG> _pageNode;
329 std::vector<SGSharedPtr<BVHNode> > _nodeVector;
333 BVHPageNodeOSG::load(const std::string& name, const osg::ref_ptr<osg::Referenced>& options)
335 osg::ref_ptr<osg::Node> node;
336 node = osgDB::readNodeFile(name, dynamic_cast<const osgDB::Options*>(options.get()));
338 return SGSharedPtr<BVHNode>();
340 _NodeVisitor nodeVisitor;
341 node->accept(nodeVisitor);
342 return nodeVisitor.getBVHNode();
345 BVHPageNodeOSG::BVHPageNodeOSG(const std::string& name,
346 const SGSphered& boundingSphere,
347 const osg::ref_ptr<osg::Referenced>& options) :
348 _boundingSphere(boundingSphere),
351 _modelList.push_back(name);
354 BVHPageNodeOSG::BVHPageNodeOSG(const std::vector<std::string>& nameList,
355 const SGSphered& boundingSphere,
356 const osg::ref_ptr<osg::Referenced>& options) :
357 _modelList(nameList),
358 _boundingSphere(boundingSphere),
363 BVHPageNodeOSG::~BVHPageNodeOSG()
368 BVHPageNodeOSG::newRequest()
370 return new _Request(this);
374 BVHPageNodeOSG::setBoundingSphere(const SGSphered& sphere)
376 _boundingSphere = sphere;
377 invalidateParentBound();
381 BVHPageNodeOSG::computeBoundingSphere() const
383 return _boundingSphere;
387 BVHPageNodeOSG::invalidateBound()
389 // Don't propagate invalidate bound to its parent
390 // Just do this once we get a bounding sphere set