2 // Copyright (C) 2008 - 2009 Mathias Froehlich - Mathias.Froehlich@web.de
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Library General Public
6 // License as published by the Free Software Foundation; either
7 // version 2 of the License, or (at your option) any later version.
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Library General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 #ifndef SimGear_BoundingVolumeBuildVisitor_hxx
20 #define SimGear_BoundingVolumeBuildVisitor_hxx
23 #include <osg/Drawable>
26 #include <osg/PagedLOD>
27 #include <osg/Transform>
28 #include <osg/TriangleFunctor>
30 #include <simgear/scene/material/mat.hxx>
31 #include <simgear/scene/material/matlib.hxx>
32 #include <simgear/scene/util/OsgMath.hxx>
33 #include <simgear/scene/util/SGNodeMasks.hxx>
34 #include <simgear/scene/util/SGSceneUserData.hxx>
35 #include <simgear/math/SGGeometry.hxx>
37 #include <simgear/bvh/BVHStaticGeometryBuilder.hxx>
39 #include "PrimitiveCollector.hxx"
43 class BoundingVolumeBuildVisitor : public osg::NodeVisitor {
45 class _PrimitiveCollector : public PrimitiveCollector {
47 _PrimitiveCollector() :
48 _geometryBuilder(new BVHStaticGeometryBuilder)
50 virtual ~_PrimitiveCollector()
53 virtual void addPoint(const osg::Vec3d& v1)
55 virtual void addLine(const osg::Vec3d& v1, const osg::Vec3d& v2)
57 virtual void addTriangle(const osg::Vec3d& v1, const osg::Vec3d& v2, const osg::Vec3d& v3)
59 _geometryBuilder->addTriangle(toVec3f(toSG(v1)), toVec3f(toSG(v2)), toVec3f(toSG(v3)));
62 BVHNode* buildTreeAndClear()
64 BVHNode* bvNode = _geometryBuilder->buildTree();
65 _geometryBuilder = new BVHStaticGeometryBuilder;
69 void swap(_PrimitiveCollector& primitiveCollector)
71 PrimitiveCollector::swap(primitiveCollector);
72 std::swap(_geometryBuilder, primitiveCollector._geometryBuilder);
75 void setCurrentMaterial(const BVHMaterial* material)
77 _geometryBuilder->setCurrentMaterial(material);
79 const BVHMaterial* getCurrentMaterial() const
81 return _geometryBuilder->getCurrentMaterial();
84 SGSharedPtr<BVHStaticGeometryBuilder> _geometryBuilder;
87 BoundingVolumeBuildVisitor(bool dumpIntoLeafs) :
88 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
89 _dumpIntoLeafs(dumpIntoLeafs)
91 setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
93 ~BoundingVolumeBuildVisitor()
97 const BVHMaterial* pushMaterial(osg::Geode* geode)
99 const BVHMaterial* oldMaterial = _primitiveCollector.getCurrentMaterial();
100 const BVHMaterial* material = SGMaterialLib::findMaterial(geode);
102 _primitiveCollector.setCurrentMaterial(material);
106 void fillWith(osg::Drawable* drawable)
108 drawable->accept(_primitiveCollector);
111 virtual void apply(osg::Geode& geode)
113 if (hasBoundingVolumeTree(geode))
116 const BVHMaterial* oldMaterial = pushMaterial(&geode);
118 bool flushHere = getNodePath().size() <= 1 || _dumpIntoLeafs;
120 // push the current active primitive list
121 _PrimitiveCollector previousPrimitives;
122 _primitiveCollector.swap(previousPrimitives);
124 const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
125 _primitiveCollector.setCurrentMaterial(mat);
128 for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
129 fillWith(geode.getDrawable(i));
131 // Flush the bounding volume tree if we reached the topmost group
132 addBoundingVolumeTreeToNode(geode);
134 // pop the current active primitive list
135 _primitiveCollector.swap(previousPrimitives);
137 for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
138 fillWith(geode.getDrawable(i));
141 _primitiveCollector.setCurrentMaterial(oldMaterial);
144 virtual void apply(osg::Group& group)
145 { traverseAndCollect(group); }
147 virtual void apply(osg::Transform& transform)
148 { traverseAndDump(transform); }
150 virtual void apply(osg::PagedLOD&)
152 // Do nothing. In this case we get called by the loading process anyway
155 virtual void apply(osg::Camera& camera)
157 if (camera.getRenderOrder() != osg::Camera::NESTED_RENDER)
159 traverseAndDump(camera);
162 void traverseAndDump(osg::Node& node)
164 if (hasBoundingVolumeTree(node))
167 // push the current active primitive list
168 _PrimitiveCollector previousPrimitives;
169 _primitiveCollector.swap(previousPrimitives);
171 const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
172 _primitiveCollector.setCurrentMaterial(mat);
177 // We know whenever we see a transform, we need to flush the
178 // collected bounding volume tree since these transforms are not
179 // handled by the plain leafs.
180 addBoundingVolumeTreeToNode(node);
182 // pop the current active primitive list
183 _primitiveCollector.swap(previousPrimitives);
186 void traverseAndCollect(osg::Node& node)
188 // Already been here??
189 if (hasBoundingVolumeTree(node))
192 // Force a flush of the bvtree if we are in the topmost node.
193 if (getNodePath().size() <= 1) {
194 traverseAndDump(node);
198 // Note that we do not need to push the already collected list of
199 // primitives, since we are now in the topmost node ...
205 void addBoundingVolumeTreeToNode(osg::Node& node)
207 // Build the flat tree.
208 BVHNode* bvNode = _primitiveCollector.buildTreeAndClear();
214 SGSceneUserData* userData;
215 userData = SGSceneUserData::getOrCreateSceneUserData(&node);
216 userData->setBVHNode(bvNode);
219 bool hasBoundingVolumeTree(osg::Node& node)
221 SGSceneUserData* userData;
222 userData = SGSceneUserData::getSceneUserData(&node);
225 if (!userData->getBVHNode())
231 _PrimitiveCollector _primitiveCollector;