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