]> git.mxchange.org Git - simgear.git/blob - simgear/scene/model/BoundingVolumeBuildVisitor.hxx
Work around apparent OSG 3.2.0 normal binding bug.
[simgear.git] / simgear / scene / model / BoundingVolumeBuildVisitor.hxx
1
2 // Copyright (C) 2008 - 2009  Mathias Froehlich - Mathias.Froehlich@web.de
3 //
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.
8 //
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.
13 //
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.
17 //
18
19 #ifndef SimGear_BoundingVolumeBuildVisitor_hxx
20 #define SimGear_BoundingVolumeBuildVisitor_hxx
21
22 #include <osg/Camera>
23 #include <osg/Drawable>
24 #include <osg/Geode>
25 #include <osg/Group>
26 #include <osg/PagedLOD>
27 #include <osg/Transform>
28 #include <osg/TriangleFunctor>
29
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>
36
37 #include <simgear/bvh/BVHStaticGeometryBuilder.hxx>
38
39 #include "PrimitiveCollector.hxx"
40
41 namespace simgear {
42
43 class BoundingVolumeBuildVisitor : public osg::NodeVisitor {
44 public:
45     class _PrimitiveCollector : public PrimitiveCollector {
46     public:
47         _PrimitiveCollector() :
48             _geometryBuilder(new BVHStaticGeometryBuilder)
49         { }
50         virtual ~_PrimitiveCollector()
51         { }
52
53         virtual void addPoint(const osg::Vec3d& v1)
54         { }
55         virtual void addLine(const osg::Vec3d& v1, const osg::Vec3d& v2)
56         { }
57         virtual void addTriangle(const osg::Vec3d& v1, const osg::Vec3d& v2, const osg::Vec3d& v3)
58         {
59             _geometryBuilder->addTriangle(toVec3f(toSG(v1)), toVec3f(toSG(v2)), toVec3f(toSG(v3)));
60         }
61
62         BVHNode* buildTreeAndClear()
63         {
64             BVHNode* bvNode = _geometryBuilder->buildTree();
65             _geometryBuilder = new BVHStaticGeometryBuilder;
66             return bvNode;
67         }
68
69         void swap(_PrimitiveCollector& primitiveCollector)
70         {
71             PrimitiveCollector::swap(primitiveCollector);
72             std::swap(_geometryBuilder, primitiveCollector._geometryBuilder);
73         }
74
75         void setCurrentMaterial(const BVHMaterial* material)
76         {
77             _geometryBuilder->setCurrentMaterial(material);
78         }
79         const BVHMaterial* getCurrentMaterial() const
80         {
81             return _geometryBuilder->getCurrentMaterial();
82         }
83
84         SGSharedPtr<BVHStaticGeometryBuilder> _geometryBuilder;
85     };
86
87     BoundingVolumeBuildVisitor(bool dumpIntoLeafs) :
88         osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN),
89         _dumpIntoLeafs(dumpIntoLeafs)
90     {
91         setTraversalMask(SG_NODEMASK_TERRAIN_BIT);
92     }
93     ~BoundingVolumeBuildVisitor()
94     {
95     }
96
97     const BVHMaterial* pushMaterial(osg::Geode* geode)
98     {
99         const BVHMaterial* oldMaterial = _primitiveCollector.getCurrentMaterial();
100         const BVHMaterial* material = SGMaterialLib::findMaterial(geode);
101         if (material)
102             _primitiveCollector.setCurrentMaterial(material);
103         return oldMaterial;
104     }
105
106     void fillWith(osg::Drawable* drawable)
107     {
108         drawable->accept(_primitiveCollector);
109     }
110
111     virtual void apply(osg::Geode& geode)
112     {
113         if (hasBoundingVolumeTree(geode))
114             return;
115
116         const BVHMaterial* oldMaterial = pushMaterial(&geode);
117
118         bool flushHere = getNodePath().size() <= 1 || _dumpIntoLeafs;
119         if (flushHere) {
120             // push the current active primitive list
121             _PrimitiveCollector previousPrimitives;
122             _primitiveCollector.swap(previousPrimitives);
123
124             const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
125             _primitiveCollector.setCurrentMaterial(mat);
126
127             // walk the children
128             for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
129                 fillWith(geode.getDrawable(i));
130
131             // Flush the bounding volume tree if we reached the topmost group
132             addBoundingVolumeTreeToNode(geode);
133
134             // pop the current active primitive list
135             _primitiveCollector.swap(previousPrimitives);
136         } else {
137             for(unsigned i = 0; i < geode.getNumDrawables(); ++i)
138                 fillWith(geode.getDrawable(i));
139         }
140
141         _primitiveCollector.setCurrentMaterial(oldMaterial);
142     }
143
144     virtual void apply(osg::Group& group)
145     { traverseAndCollect(group); }
146
147     virtual void apply(osg::Transform& transform)
148     { traverseAndDump(transform); }
149
150     virtual void apply(osg::PagedLOD&)
151     {
152         // Do nothing. In this case we get called by the loading process anyway
153     }
154
155     virtual void apply(osg::Camera& camera)
156     {
157         if (camera.getRenderOrder() != osg::Camera::NESTED_RENDER)
158             return;
159         traverseAndDump(camera);
160     }
161
162     void traverseAndDump(osg::Node& node)
163     {
164         if (hasBoundingVolumeTree(node))
165             return;
166
167         // push the current active primitive list
168         _PrimitiveCollector previousPrimitives;
169         _primitiveCollector.swap(previousPrimitives);
170
171         const BVHMaterial* mat = previousPrimitives.getCurrentMaterial();
172         _primitiveCollector.setCurrentMaterial(mat);
173
174         // walk the children
175         traverse(node);
176
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);
181
182         // pop the current active primitive list
183         _primitiveCollector.swap(previousPrimitives);
184     }
185
186     void traverseAndCollect(osg::Node& node)
187     {
188         // Already been here??
189         if (hasBoundingVolumeTree(node))
190             return;
191
192         // Force a flush of the bvtree if we are in the topmost node.
193         if (getNodePath().size() <= 1) {
194             traverseAndDump(node);
195             return;
196         }
197
198         // Note that we do not need to push the already collected list of
199         // primitives, since we are now in the topmost node ...
200
201         // walk the children
202         traverse(node);
203     }
204
205     void addBoundingVolumeTreeToNode(osg::Node& node)
206     {
207         // Build the flat tree.
208         BVHNode* bvNode = _primitiveCollector.buildTreeAndClear();
209
210         // Nothing in there?
211         if (!bvNode)
212             return;
213
214         SGSceneUserData* userData;
215         userData = SGSceneUserData::getOrCreateSceneUserData(&node);
216         userData->setBVHNode(bvNode);
217     }
218
219     bool hasBoundingVolumeTree(osg::Node& node)
220     {
221         SGSceneUserData* userData;
222         userData = SGSceneUserData::getSceneUserData(&node);
223         if (!userData)
224             return false;
225         if (!userData->getBVHNode())
226             return false;
227         return true;
228     }
229
230 private:
231     _PrimitiveCollector _primitiveCollector;
232     bool _dumpIntoLeafs;
233 };
234
235 }
236
237 #endif