1 /* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version. The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
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
11 * OpenSceneGraph Public License for more details.
12 */
13
14 /* Modified for OpenMW */
15
16 #ifndef OPENMW_OSGUTIL_OPTIMIZER
17 #define OPENMW_OSGUTIL_OPTIMIZER
18
19 #include <osg/NodeVisitor>
20 #include <osg/Matrix>
21 #include <osg/Geometry>
22 #include <osg/Transform>
23 #include <osg/Texture2D>
24
25 //#include <osgUtil/Export>
26
27 #include <set>
28
29 //namespace osgUtil {
30 namespace SceneUtil {
31
32 // forward declare
33 class Optimizer;
34
35 /** Helper base class for implementing Optimizer techniques.*/
36 class BaseOptimizerVisitor : public osg::NodeVisitor
37 {
38 public:
39
BaseOptimizerVisitor(Optimizer * optimizer,unsigned int operation)40 BaseOptimizerVisitor(Optimizer* optimizer, unsigned int operation):
41 osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
42 _optimizer(optimizer),
43 _operationType(operation)
44 {
45 setNodeMaskOverride(0xffffffff);
46 }
47
48 inline bool isOperationPermissibleForObject(const osg::StateSet* object) const;
49 inline bool isOperationPermissibleForObject(const osg::StateAttribute* object) const;
50 inline bool isOperationPermissibleForObject(const osg::Drawable* object) const;
51 inline bool isOperationPermissibleForObject(const osg::Node* object) const;
52
53 protected:
54
55 Optimizer* _optimizer;
56 unsigned int _operationType;
57 };
58
59 /** Traverses scene graph to improve efficiency. See OptimizationOptions.
60 * For example of usage see examples/osgimpostor or osgviewer.
61 */
62
63 class Optimizer
64 {
65
66 public:
67
Optimizer()68 Optimizer() : _mergeAlphaBlending(false) {}
~Optimizer()69 virtual ~Optimizer() {}
70
71 enum OptimizationOptions
72 {
73 FLATTEN_STATIC_TRANSFORMS = (1 << 0),
74 REMOVE_REDUNDANT_NODES = (1 << 1),
75 REMOVE_LOADED_PROXY_NODES = (1 << 2),
76 COMBINE_ADJACENT_LODS = (1 << 3),
77 SHARE_DUPLICATE_STATE = (1 << 4),
78 MERGE_GEOMETRY = (1 << 5),
79 CHECK_GEOMETRY = (1 << 6), // deprecated, currently no-op
80 MAKE_FAST_GEOMETRY = (1 << 7),
81 SPATIALIZE_GROUPS = (1 << 8),
82 COPY_SHARED_NODES = (1 << 9),
83 TRISTRIP_GEOMETRY = (1 << 10),
84 TESSELLATE_GEOMETRY = (1 << 11),
85 OPTIMIZE_TEXTURE_SETTINGS = (1 << 12),
86 MERGE_GEODES = (1 << 13),
87 FLATTEN_BILLBOARDS = (1 << 14),
88 TEXTURE_ATLAS_BUILDER = (1 << 15),
89 STATIC_OBJECT_DETECTION = (1 << 16),
90 FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS = (1 << 17),
91 INDEX_MESH = (1 << 18),
92 VERTEX_POSTTRANSFORM = (1 << 19),
93 VERTEX_PRETRANSFORM = (1 << 20),
94 DEFAULT_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS |
95 REMOVE_REDUNDANT_NODES |
96 REMOVE_LOADED_PROXY_NODES |
97 COMBINE_ADJACENT_LODS |
98 SHARE_DUPLICATE_STATE |
99 MERGE_GEOMETRY |
100 MAKE_FAST_GEOMETRY |
101 CHECK_GEOMETRY |
102 OPTIMIZE_TEXTURE_SETTINGS |
103 STATIC_OBJECT_DETECTION,
104 ALL_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS |
105 REMOVE_REDUNDANT_NODES |
106 REMOVE_LOADED_PROXY_NODES |
107 COMBINE_ADJACENT_LODS |
108 SHARE_DUPLICATE_STATE |
109 MERGE_GEODES |
110 MERGE_GEOMETRY |
111 MAKE_FAST_GEOMETRY |
112 CHECK_GEOMETRY |
113 SPATIALIZE_GROUPS |
114 COPY_SHARED_NODES |
115 TRISTRIP_GEOMETRY |
116 OPTIMIZE_TEXTURE_SETTINGS |
117 TEXTURE_ATLAS_BUILDER |
118 STATIC_OBJECT_DETECTION
119 };
120
setMergeAlphaBlending(bool merge)121 void setMergeAlphaBlending(bool merge) { _mergeAlphaBlending = merge; }
setViewPoint(const osg::Vec3f & viewPoint)122 void setViewPoint(const osg::Vec3f& viewPoint) { _viewPoint = viewPoint; }
123
124 /** Reset internal data to initial state - the getPermissibleOptionsMap is cleared.*/
125 void reset();
126
127 /** Traverse the node and its subgraph with a series of optimization
128 * visitors, specified by the OptimizationOptions.*/
129 virtual void optimize(osg::Node* node, unsigned int options);
130
131
132 /** Callback for customizing what operations are permitted on objects in the scene graph.*/
133 struct IsOperationPermissibleForObjectCallback : public osg::Referenced
134 {
isOperationPermissibleForObjectImplementationSceneUtil::Optimizer::IsOperationPermissibleForObjectCallback135 virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::StateSet* stateset,unsigned int option) const
136 {
137 return optimizer->isOperationPermissibleForObjectImplementation(stateset,option);
138 }
139
isOperationPermissibleForObjectImplementationSceneUtil::Optimizer::IsOperationPermissibleForObjectCallback140 virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::StateAttribute* attribute,unsigned int option) const
141 {
142 return optimizer->isOperationPermissibleForObjectImplementation(attribute,option);
143 }
144
isOperationPermissibleForObjectImplementationSceneUtil::Optimizer::IsOperationPermissibleForObjectCallback145 virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::Drawable* drawable,unsigned int option) const
146 {
147 return optimizer->isOperationPermissibleForObjectImplementation(drawable,option);
148 }
149
isOperationPermissibleForObjectImplementationSceneUtil::Optimizer::IsOperationPermissibleForObjectCallback150 virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::Node* node,unsigned int option) const
151 {
152 return optimizer->isOperationPermissibleForObjectImplementation(node,option);
153 }
154
155 };
156
157 /** Set the callback for customizing what operations are permitted on objects in the scene graph.*/
setIsOperationPermissibleForObjectCallback(IsOperationPermissibleForObjectCallback * callback)158 void setIsOperationPermissibleForObjectCallback(IsOperationPermissibleForObjectCallback* callback) { _isOperationPermissibleForObjectCallback=callback; }
159
160 /** Get the callback for customizing what operations are permitted on objects in the scene graph.*/
getIsOperationPermissibleForObjectCallback()161 IsOperationPermissibleForObjectCallback* getIsOperationPermissibleForObjectCallback() { return _isOperationPermissibleForObjectCallback.get(); }
162
163 /** Get the callback for customizing what operations are permitted on objects in the scene graph.*/
getIsOperationPermissibleForObjectCallback() const164 const IsOperationPermissibleForObjectCallback* getIsOperationPermissibleForObjectCallback() const { return _isOperationPermissibleForObjectCallback.get(); }
165
166
setPermissibleOptimizationsForObject(const osg::Object * object,unsigned int options)167 inline void setPermissibleOptimizationsForObject(const osg::Object* object, unsigned int options)
168 {
169 _permissibleOptimizationsMap[object] = options;
170 }
171
getPermissibleOptimizationsForObject(const osg::Object * object) const172 inline unsigned int getPermissibleOptimizationsForObject(const osg::Object* object) const
173 {
174 PermissibleOptimizationsMap::const_iterator itr = _permissibleOptimizationsMap.find(object);
175 if (itr!=_permissibleOptimizationsMap.end()) return itr->second;
176 else return 0xffffffff;
177 }
178
179
isOperationPermissibleForObject(const osg::StateSet * object,unsigned int option) const180 inline bool isOperationPermissibleForObject(const osg::StateSet* object, unsigned int option) const
181 {
182 if (_isOperationPermissibleForObjectCallback.valid())
183 return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
184 else
185 return isOperationPermissibleForObjectImplementation(object,option);
186 }
187
isOperationPermissibleForObject(const osg::StateAttribute * object,unsigned int option) const188 inline bool isOperationPermissibleForObject(const osg::StateAttribute* object, unsigned int option) const
189 {
190 if (_isOperationPermissibleForObjectCallback.valid())
191 return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
192 else
193 return isOperationPermissibleForObjectImplementation(object,option);
194 }
195
isOperationPermissibleForObject(const osg::Drawable * object,unsigned int option) const196 inline bool isOperationPermissibleForObject(const osg::Drawable* object, unsigned int option) const
197 {
198 if (_isOperationPermissibleForObjectCallback.valid())
199 return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
200 else
201 return isOperationPermissibleForObjectImplementation(object,option);
202 }
203
isOperationPermissibleForObject(const osg::Node * object,unsigned int option) const204 inline bool isOperationPermissibleForObject(const osg::Node* object, unsigned int option) const
205 {
206 if (_isOperationPermissibleForObjectCallback.valid())
207 return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
208 else
209 return isOperationPermissibleForObjectImplementation(object,option);
210 }
211
isOperationPermissibleForObjectImplementation(const osg::StateSet * stateset,unsigned int option) const212 bool isOperationPermissibleForObjectImplementation(const osg::StateSet* stateset, unsigned int option) const
213 {
214 return (option & getPermissibleOptimizationsForObject(stateset))!=0;
215 }
216
isOperationPermissibleForObjectImplementation(const osg::StateAttribute * attribute,unsigned int option) const217 bool isOperationPermissibleForObjectImplementation(const osg::StateAttribute* attribute, unsigned int option) const
218 {
219 return (option & getPermissibleOptimizationsForObject(attribute))!=0;
220 }
221
isOperationPermissibleForObjectImplementation(const osg::Drawable * drawable,unsigned int option) const222 bool isOperationPermissibleForObjectImplementation(const osg::Drawable* drawable, unsigned int option) const
223 {
224 if (option & (REMOVE_REDUNDANT_NODES|MERGE_GEOMETRY))
225 {
226 if (drawable->getUserData()) return false;
227 if (drawable->getUpdateCallback()) return false;
228 if (drawable->getEventCallback()) return false;
229 if (drawable->getCullCallback()) return false;
230 }
231 return (option & getPermissibleOptimizationsForObject(drawable))!=0;
232 }
233
isOperationPermissibleForObjectImplementation(const osg::Node * node,unsigned int option) const234 bool isOperationPermissibleForObjectImplementation(const osg::Node* node, unsigned int option) const
235 {
236 if (option & (REMOVE_REDUNDANT_NODES|COMBINE_ADJACENT_LODS|FLATTEN_STATIC_TRANSFORMS))
237 {
238 if (node->getUserData()) return false;
239 if (node->getUpdateCallback()) return false;
240 if (node->getEventCallback()) return false;
241 if (node->getCullCallback()) return false;
242 if (node->getNumDescriptions()>0) return false;
243 if (node->getStateSet()) return false;
244 if (node->getNodeMask()!=0xffffffff) return false;
245 // if (!node->getName().empty()) return false;
246 }
247
248 return (option & getPermissibleOptimizationsForObject(node))!=0;
249 }
250
251 protected:
252
253 osg::ref_ptr<IsOperationPermissibleForObjectCallback> _isOperationPermissibleForObjectCallback;
254
255 typedef std::map<const osg::Object*,unsigned int> PermissibleOptimizationsMap;
256 PermissibleOptimizationsMap _permissibleOptimizationsMap;
257
258 osg::Vec3f _viewPoint;
259 bool _mergeAlphaBlending;
260
261 public:
262
263 /** Flatten Static Transform nodes by applying their transform to the
264 * geometry on the leaves of the scene graph, then removing the
265 * now redundant transforms. Static transformed subgraphs that have multiple
266 * parental paths above them are not flattened, if you require this then
267 * the subgraphs have to be duplicated - for this use the
268 * FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor. */
269 class FlattenStaticTransformsVisitor : public BaseOptimizerVisitor
270 {
271 public:
272
FlattenStaticTransformsVisitor(Optimizer * optimizer=0)273 FlattenStaticTransformsVisitor(Optimizer* optimizer=0):
274 BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS) {}
275
276 void apply(osg::Node& geode) override;
277 void apply(osg::Drawable& drawable) override;
278 void apply(osg::Billboard& geode) override;
279 void apply(osg::Transform& transform) override;
280
281 bool removeTransforms(osg::Node* nodeWeCannotRemove);
282
283 protected:
284
285 typedef std::vector<osg::Transform*> TransformStack;
286 typedef std::set<osg::Drawable*> DrawableSet;
287 typedef std::set<osg::Billboard*> BillboardSet;
288 typedef std::set<osg::Node* > NodeSet;
289 typedef std::set<osg::Transform*> TransformSet;
290
291 TransformStack _transformStack;
292 NodeSet _excludedNodeSet;
293 DrawableSet _drawableSet;
294 BillboardSet _billboardSet;
295 TransformSet _transformSet;
296 };
297
298
299 /** Combine Static Transform nodes that sit above one another.*/
300 class CombineStaticTransformsVisitor : public BaseOptimizerVisitor
301 {
302 public:
303
CombineStaticTransformsVisitor(Optimizer * optimizer=0)304 CombineStaticTransformsVisitor(Optimizer* optimizer=0):
305 BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS) {}
306
307 void apply(osg::MatrixTransform& transform) override;
308
309 bool removeTransforms(osg::Node* nodeWeCannotRemove);
310
311 protected:
312
313 typedef std::set<osg::MatrixTransform*> TransformSet;
314 TransformSet _transformSet;
315 };
316
317 /** Remove rendundant nodes, such as groups with one single child.*/
318 class RemoveEmptyNodesVisitor : public BaseOptimizerVisitor
319 {
320 public:
321
322
323 typedef std::set<osg::Node*> NodeList;
324 NodeList _redundantNodeList;
325
RemoveEmptyNodesVisitor(Optimizer * optimizer=0)326 RemoveEmptyNodesVisitor(Optimizer* optimizer=0):
327 BaseOptimizerVisitor(optimizer, REMOVE_REDUNDANT_NODES) {}
328
329 void apply(osg::Group& group) override;
330
331 void removeEmptyNodes();
332
333 };
334
335 /** Remove redundant nodes, such as groups with one single child.*/
336 class RemoveRedundantNodesVisitor : public BaseOptimizerVisitor
337 {
338 public:
339
340 typedef std::set<osg::Node*> NodeList;
341 NodeList _redundantNodeList;
342
RemoveRedundantNodesVisitor(Optimizer * optimizer=0)343 RemoveRedundantNodesVisitor(Optimizer* optimizer=0):
344 BaseOptimizerVisitor(optimizer, REMOVE_REDUNDANT_NODES) {}
345
346 void apply(osg::Group& group) override;
347 void apply(osg::Transform& transform) override;
348 void apply(osg::LOD& lod) override;
349 void apply(osg::Switch& switchNode) override;
350
351 bool isOperationPermissible(osg::Node& node);
352
353 void removeRedundantNodes();
354
355 };
356
357 /** Merge adjacent Groups that have the same StateSet. */
358 class MergeGroupsVisitor : public SceneUtil::BaseOptimizerVisitor
359 {
360 public:
MergeGroupsVisitor(SceneUtil::Optimizer * optimizer)361 MergeGroupsVisitor(SceneUtil::Optimizer* optimizer)
362 : BaseOptimizerVisitor(optimizer, REMOVE_REDUNDANT_NODES)
363 {
364 }
365
366 bool isOperationPermissible(osg::Group& node);
367
368 void apply(osg::Group& group) override;
369 void apply(osg::LOD& lod) override;
370 void apply(osg::Switch& switchNode) override;
371 };
372
373 class MergeGeometryVisitor : public BaseOptimizerVisitor
374 {
375 public:
376
377 /// default to traversing all children.
MergeGeometryVisitor(Optimizer * optimizer=0)378 MergeGeometryVisitor(Optimizer* optimizer=0) :
379 BaseOptimizerVisitor(optimizer, MERGE_GEOMETRY),
380 _targetMaximumNumberOfVertices(10000), _alphaBlendingActive(false), _mergeAlphaBlending(false) {}
381
setMergeAlphaBlending(bool merge)382 void setMergeAlphaBlending(bool merge)
383 {
384 _mergeAlphaBlending = merge;
385 }
setViewPoint(const osg::Vec3f & viewPoint)386 void setViewPoint(const osg::Vec3f& viewPoint)
387 {
388 _viewPoint = viewPoint;
389 }
390
setTargetMaximumNumberOfVertices(unsigned int num)391 void setTargetMaximumNumberOfVertices(unsigned int num)
392 {
393 _targetMaximumNumberOfVertices = num;
394 }
395
getTargetMaximumNumberOfVertices() const396 unsigned int getTargetMaximumNumberOfVertices() const
397 {
398 return _targetMaximumNumberOfVertices;
399 }
400
401 void pushStateSet(osg::StateSet* stateSet);
402 void popStateSet();
403 void checkAlphaBlendingActive();
404
405 void apply(osg::Group& group) override;
apply(osg::Billboard &)406 void apply(osg::Billboard&) override { /* don't do anything*/ }
407
408 bool mergeGroup(osg::Group& group);
409
410 static bool mergeGeometry(osg::Geometry& lhs,osg::Geometry& rhs);
411
412 static bool mergePrimitive(osg::DrawArrays& lhs,osg::DrawArrays& rhs);
413 static bool mergePrimitive(osg::DrawArrayLengths& lhs,osg::DrawArrayLengths& rhs);
414 static bool mergePrimitive(osg::DrawElementsUByte& lhs,osg::DrawElementsUByte& rhs);
415 static bool mergePrimitive(osg::DrawElementsUShort& lhs,osg::DrawElementsUShort& rhs);
416 static bool mergePrimitive(osg::DrawElementsUInt& lhs,osg::DrawElementsUInt& rhs);
417
418 protected:
419
420 unsigned int _targetMaximumNumberOfVertices;
421 std::vector<osg::StateSet*> _stateSetStack;
422 bool _alphaBlendingActive;
423 bool _mergeAlphaBlending;
424 osg::Vec3f _viewPoint;
425 };
426
427 };
428
isOperationPermissibleForObject(const osg::StateSet * object) const429 inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::StateSet* object) const
430 {
431 return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) : true;
432 }
433
isOperationPermissibleForObject(const osg::StateAttribute * object) const434 inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::StateAttribute* object) const
435 {
436 return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) : true;
437 }
438
isOperationPermissibleForObject(const osg::Drawable * object) const439 inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::Drawable* object) const
440 {
441 return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) : true;
442 }
443
isOperationPermissibleForObject(const osg::Node * object) const444 inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::Node* object) const
445 {
446 return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) : true;
447 }
448
449 }
450
451 #endif
452