root/OpenSceneGraph/trunk/include/osgUtil/Optimizer @ 9886

Revision 9886, 34.3 kB (checked in by robert, 6 years ago)

From Roland Smeenk, "While working on the Collada plugin I noticed that all geometry created by the dae reader result in slow path geometry.
Because there already exists the option to convert slow path geometry to the fast path by computing an internal fast path alternative, I added a new optimizer option that automatically does this. To check the results I also made some changes to the statistics gathering and rendering.

Somewhat unrelated, but also part of the optimizer I disabled removal of CameraView? nodes during RemoveRedundantNodes? optimization.
As discussed on the ML, CameraViews? were removed from the scenegraph. This solves that issue.

Summary:
-Geometry::areFastPathsUsed now also looks at internalOptimizedGeometry
-Added Optimize option to make all slow path geometry compute their internal fast path alternative
-Added fast geometry counter to the statistics
-Disabled removel of CameraViews? in optimizer
"

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
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#ifndef OSGUTIL_OPTIMIZER
15#define OSGUTIL_OPTIMIZER
16
17#include <osg/NodeVisitor>
18#include <osg/Matrix>
19#include <osg/Geometry>
20#include <osg/Transform>
21#include <osg/Texture2D>
22
23#include <osgUtil/Export>
24
25#include <set>
26
27namespace osgUtil {
28
29// forward declare
30class Optimizer;
31
32/** Helper base class for implementing Optimizer techniques.*/
33class OSGUTIL_EXPORT BaseOptimizerVisitor : public osg::NodeVisitor
34{
35    public:
36
37        BaseOptimizerVisitor(Optimizer* optimizer, unsigned int operation):
38            osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
39            _optimizer(optimizer),
40            _operationType(operation)
41        {
42            setNodeMaskOverride(0xffffffff);
43        }
44
45        inline bool isOperationPermissibleForObject(const osg::StateSet* object) const;
46        inline bool isOperationPermissibleForObject(const osg::StateAttribute* object) const;
47        inline bool isOperationPermissibleForObject(const osg::Drawable* object) const;       
48        inline bool isOperationPermissibleForObject(const osg::Node* object) const;
49
50    protected:
51
52        Optimizer*      _optimizer;
53        unsigned int _operationType;
54};
55
56/** Traverses scene graph to improve efficiency. See OptimizationOptions.
57  * For example of usage see examples/osgimpostor or osgviewer.
58  */
59 
60class OSGUTIL_EXPORT Optimizer
61{
62
63    public:
64
65        Optimizer() {}
66        virtual ~Optimizer() {}
67
68        enum OptimizationOptions
69        {
70            FLATTEN_STATIC_TRANSFORMS = (1 << 0),
71            REMOVE_REDUNDANT_NODES =    (1 << 1),
72            REMOVE_LOADED_PROXY_NODES = (1 << 2),
73            COMBINE_ADJACENT_LODS =     (1 << 3),
74            SHARE_DUPLICATE_STATE =     (1 << 4),
75            MERGE_GEOMETRY =            (1 << 5),
76            CHECK_GEOMETRY =            (1 << 6),
77            MAKE_FAST_GEOMETRY =        (1 << 7),
78            SPATIALIZE_GROUPS =         (1 << 8),
79            COPY_SHARED_NODES =         (1 << 9),
80            TRISTRIP_GEOMETRY =         (1 << 10),
81            TESSELLATE_GEOMETRY =       (1 << 11),
82            OPTIMIZE_TEXTURE_SETTINGS = (1 << 12),
83            MERGE_GEODES =              (1 << 13),
84            FLATTEN_BILLBOARDS =        (1 << 14),
85            TEXTURE_ATLAS_BUILDER =     (1 << 15),
86            STATIC_OBJECT_DETECTION =   (1 << 16),
87            FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS = (1 << 17),
88            DEFAULT_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS |
89                                REMOVE_REDUNDANT_NODES |
90                                REMOVE_LOADED_PROXY_NODES |
91                                COMBINE_ADJACENT_LODS |
92                                SHARE_DUPLICATE_STATE |
93                                MERGE_GEOMETRY |
94                                MAKE_FAST_GEOMETRY |
95                                CHECK_GEOMETRY |
96                                OPTIMIZE_TEXTURE_SETTINGS |
97                                STATIC_OBJECT_DETECTION,
98            ALL_OPTIMIZATIONS = FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS |
99                                REMOVE_REDUNDANT_NODES |
100                                REMOVE_LOADED_PROXY_NODES |
101                                COMBINE_ADJACENT_LODS |
102                                SHARE_DUPLICATE_STATE |
103                                MERGE_GEODES |
104                                MERGE_GEOMETRY |
105                                MAKE_FAST_GEOMETRY |
106                                CHECK_GEOMETRY |
107                                SPATIALIZE_GROUPS |
108                                COPY_SHARED_NODES |
109                                TRISTRIP_GEOMETRY |
110                                OPTIMIZE_TEXTURE_SETTINGS |
111                                TEXTURE_ATLAS_BUILDER |
112                                STATIC_OBJECT_DETECTION
113        };
114
115        /** Reset internal data to initial state - the getPermissibleOptionsMap is cleared.*/
116        void reset();
117       
118        /** Traverse the node and its subgraph with a series of optimization
119          * visitors, specified by the OptimizationOptions.*/
120        void optimize(osg::Node* node);
121
122        /** Traverse the node and its subgraph with a series of optimization
123          * visitors, specified by the OptimizationOptions.*/
124        virtual void optimize(osg::Node* node, unsigned int options);
125
126
127        /** Callback for customizing what operations are permitted on objects in the scene graph.*/       
128        struct IsOperationPermissibleForObjectCallback : public osg::Referenced
129        {
130            virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::StateSet* stateset,unsigned int option) const
131            {
132                return optimizer->isOperationPermissibleForObjectImplementation(stateset,option);
133            }
134           
135            virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::StateAttribute* attribute,unsigned int option) const
136            {
137                return optimizer->isOperationPermissibleForObjectImplementation(attribute,option);
138            }
139           
140            virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::Drawable* drawable,unsigned int option) const
141            {
142                return optimizer->isOperationPermissibleForObjectImplementation(drawable,option);
143            }
144           
145            virtual bool isOperationPermissibleForObjectImplementation(const Optimizer* optimizer, const osg::Node* node,unsigned int option) const
146            {
147                return optimizer->isOperationPermissibleForObjectImplementation(node,option);
148            }
149           
150        };
151       
152        /** Set the callback for customizing what operations are permitted on objects in the scene graph.*/       
153        void setIsOperationPermissibleForObjectCallback(IsOperationPermissibleForObjectCallback* callback) { _isOperationPermissibleForObjectCallback=callback; }
154
155        /** Get the callback for customizing what operations are permitted on objects in the scene graph.*/       
156        IsOperationPermissibleForObjectCallback* getIsOperationPermissibleForObjectCallback() { return _isOperationPermissibleForObjectCallback.get(); }
157
158        /** Get the callback for customizing what operations are permitted on objects in the scene graph.*/       
159        const IsOperationPermissibleForObjectCallback* getIsOperationPermissibleForObjectCallback() const { return _isOperationPermissibleForObjectCallback.get(); }
160
161
162        inline void setPermissibleOptimizationsForObject(const osg::Object* object, unsigned int options)
163        {
164            _permissibleOptimizationsMap[object] = options;
165        }
166       
167        inline unsigned int getPermissibleOptimizationsForObject(const osg::Object* object) const
168        {
169            PermissibleOptimizationsMap::const_iterator itr = _permissibleOptimizationsMap.find(object);
170            if (itr!=_permissibleOptimizationsMap.end()) return itr->second;
171            else return 0xffffffff;
172        }
173
174
175        inline bool isOperationPermissibleForObject(const osg::StateSet* object, unsigned int option) const
176        {
177            if (_isOperationPermissibleForObjectCallback.valid())
178                return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
179            else
180                return isOperationPermissibleForObjectImplementation(object,option);
181        }
182
183        inline bool isOperationPermissibleForObject(const osg::StateAttribute* object, unsigned int option) const
184        {
185            if (_isOperationPermissibleForObjectCallback.valid())
186                return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
187            else
188                return isOperationPermissibleForObjectImplementation(object,option);
189        }
190
191        inline bool isOperationPermissibleForObject(const osg::Drawable* object, unsigned int option) const
192        {
193            if (_isOperationPermissibleForObjectCallback.valid())
194                return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
195            else
196                return isOperationPermissibleForObjectImplementation(object,option);
197        }
198
199        inline bool isOperationPermissibleForObject(const osg::Node* object, unsigned int option) const
200        {
201            if (_isOperationPermissibleForObjectCallback.valid())
202                return _isOperationPermissibleForObjectCallback->isOperationPermissibleForObjectImplementation(this,object,option);
203            else
204                return isOperationPermissibleForObjectImplementation(object,option);
205        }
206
207        bool isOperationPermissibleForObjectImplementation(const osg::StateSet* stateset, unsigned int option) const
208        {
209            return (option & getPermissibleOptimizationsForObject(stateset))!=0;
210        }
211       
212        bool isOperationPermissibleForObjectImplementation(const osg::StateAttribute* attribute, unsigned int option) const
213        {
214            return (option & getPermissibleOptimizationsForObject(attribute))!=0;
215        }
216
217        bool isOperationPermissibleForObjectImplementation(const osg::Drawable* drawable, unsigned int option) const
218        {
219            if (option & (REMOVE_REDUNDANT_NODES|MERGE_GEOMETRY))
220            {
221                if (drawable->getUserData()) return false;
222                if (drawable->getUpdateCallback()) return false;
223                if (drawable->getEventCallback()) return false;
224                if (drawable->getCullCallback()) return false;
225            }
226            return (option & getPermissibleOptimizationsForObject(drawable))!=0;
227        }
228
229        bool isOperationPermissibleForObjectImplementation(const osg::Node* node, unsigned int option) const
230        {
231            if (option & (REMOVE_REDUNDANT_NODES|COMBINE_ADJACENT_LODS|FLATTEN_STATIC_TRANSFORMS))
232            {
233                if (node->getUserData()) return false;
234                if (node->getUpdateCallback()) return false;
235                if (node->getEventCallback()) return false;
236                if (node->getCullCallback()) return false;
237                if (node->getNumDescriptions()>0) return false;
238                if (node->getStateSet()) return false;
239                if (node->getNodeMask()!=0xffffffff) return false;
240                // if (!node->getName().empty()) return false;
241            }
242
243            return (option & getPermissibleOptimizationsForObject(node))!=0;
244        }
245       
246    protected:
247
248        osg::ref_ptr<IsOperationPermissibleForObjectCallback> _isOperationPermissibleForObjectCallback;
249
250        typedef std::map<const osg::Object*,unsigned int> PermissibleOptimizationsMap;
251        PermissibleOptimizationsMap _permissibleOptimizationsMap;   
252   
253    public:
254
255        /** Flatten Static Transform nodes by applying their transform to the
256          * geometry on the leaves of the scene graph, then removing the
257          * now redundant transforms.  Static transformed Subgraphs that have multiple
258          * parental paths above them are not flattened, if you require this then
259          * the subgraphs have to be duplicated - for this use the
260          * FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor. */
261        class OSGUTIL_EXPORT FlattenStaticTransformsVisitor : public BaseOptimizerVisitor
262        {
263            public:
264
265                FlattenStaticTransformsVisitor(Optimizer* optimizer=0):
266                    BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS) {}
267
268                virtual void apply(osg::Node& geode);
269                virtual void apply(osg::Geode& geode);
270                virtual void apply(osg::Billboard& geode);
271                virtual void apply(osg::ProxyNode& node);
272                virtual void apply(osg::PagedLOD& node);
273                virtual void apply(osg::Transform& transform);
274
275                bool removeTransforms(osg::Node* nodeWeCannotRemove);
276
277            protected:
278
279                typedef std::vector<osg::Transform*>                TransformStack;
280                typedef std::set<osg::Drawable*>                    DrawableSet;
281                typedef std::set<osg::Billboard*>                   BillboardSet;
282                typedef std::set<osg::Node* >                       NodeSet;
283                typedef std::set<osg::Transform*>                   TransformSet;
284               
285                TransformStack  _transformStack;
286                NodeSet         _excludedNodeSet;
287                DrawableSet     _drawableSet;
288                BillboardSet    _billboardSet;
289                TransformSet    _transformSet;
290        };
291
292        /** FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor is similar to
293          * to FlattenStaticTransformsVisitor in that is desgined to remove static transforms
294          * from the scene graph, pushing down the transforms to the geometry leaves of the scene graph,
295          * but with the difference that any subgraphs that are shared between different transforms
296          * of duplicated and flatten individually.  This results in more static transforms
297          * being removed, but also means that more data is generated, and as a result may
298          * not always be the most appropriate flatten visitor to use.*/ 
299        class OSGUTIL_EXPORT FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor : public BaseOptimizerVisitor
300        {
301            public:
302
303                FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor(Optimizer* optimizer=0):
304                    BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS) {}
305
306                virtual void reset();
307
308                virtual void apply(osg::Group& group);
309                virtual void apply(osg::Transform& transform);
310                virtual void apply(osg::LOD& lod);
311                virtual void apply(osg::Geode& geode);
312                virtual void apply(osg::Billboard& billboard);
313
314            protected:
315
316                void transformGeode(osg::Geode& geode);
317                void transformDrawable(osg::Drawable& drawable);
318                void transformBillboard(osg::Billboard& billboard);
319
320                std::vector<osg::Matrix> _matrixStack;
321
322        };
323
324        /** Combine Static Transform nodes that sit above one another.*/       
325        class OSGUTIL_EXPORT CombineStaticTransformsVisitor : public BaseOptimizerVisitor
326        {
327            public:
328
329                CombineStaticTransformsVisitor(Optimizer* optimizer=0):
330                    BaseOptimizerVisitor(optimizer, FLATTEN_STATIC_TRANSFORMS) {}
331
332                virtual void apply(osg::MatrixTransform& transform);
333
334                bool removeTransforms(osg::Node* nodeWeCannotRemove);
335
336            protected:
337
338                typedef std::set<osg::MatrixTransform*> TransformSet;
339                TransformSet  _transformSet;
340        };
341
342        /** Remove rendundant nodes, such as groups with one single child.*/
343        class OSGUTIL_EXPORT RemoveEmptyNodesVisitor : public BaseOptimizerVisitor
344        {
345            public:
346
347
348                typedef std::set<osg::Node*> NodeList;
349                NodeList                     _redundantNodeList;
350
351                RemoveEmptyNodesVisitor(Optimizer* optimizer=0):
352                    BaseOptimizerVisitor(optimizer, REMOVE_REDUNDANT_NODES) {}
353
354                virtual void apply(osg::Geode& geode);
355                virtual void apply(osg::Group& group);
356               
357                void removeEmptyNodes();
358
359        };
360
361        /** Remove redundant nodes, such as groups with one single child.*/
362        class OSGUTIL_EXPORT RemoveRedundantNodesVisitor : public BaseOptimizerVisitor
363        {
364            public:
365
366                typedef std::set<osg::Node*> NodeList;
367                NodeList                     _redundantNodeList;
368
369                RemoveRedundantNodesVisitor(Optimizer* optimizer=0):
370                    BaseOptimizerVisitor(optimizer, REMOVE_REDUNDANT_NODES) {}
371               
372                virtual void apply(osg::Group& group);
373                virtual void apply(osg::Transform& transform);
374               
375                bool isOperationPermissible(osg::Node& node);
376               
377                void removeRedundantNodes();
378
379        };
380
381        /** Remove loaded proxy nodes.*/
382        class OSGUTIL_EXPORT RemoveLoadedProxyNodesVisitor : public BaseOptimizerVisitor
383        {
384            public:
385
386                typedef std::set<osg::Node*> NodeList;
387                NodeList                     _redundantNodeList;
388
389                RemoveLoadedProxyNodesVisitor(Optimizer* optimizer=0):
390                    BaseOptimizerVisitor(optimizer, REMOVE_LOADED_PROXY_NODES) {}
391               
392                virtual void apply(osg::ProxyNode& group);
393               
394                void removeRedundantNodes();
395
396        };
397
398        /** Tessellate all geodes, to remove POLYGONS.*/
399        class OSGUTIL_EXPORT TessellateVisitor : public BaseOptimizerVisitor
400        {
401            public:
402
403                typedef std::set<osg::Group*>  GroupList;
404                GroupList                      _groupList;
405
406                TessellateVisitor(Optimizer* optimizer=0):
407                    BaseOptimizerVisitor(optimizer, TESSELLATE_GEOMETRY) {}
408
409                virtual void apply(osg::Geode& geode);
410
411        };
412
413        /** Optimize the LOD groups, by combining adjacent LOD's which have
414          * complementary ranges.*/
415        class OSGUTIL_EXPORT CombineLODsVisitor : public BaseOptimizerVisitor
416        {
417            public:
418
419                typedef std::set<osg::Group*>  GroupList;
420                GroupList                      _groupList;
421
422                CombineLODsVisitor(Optimizer* optimizer=0):
423                    BaseOptimizerVisitor(optimizer, COMBINE_ADJACENT_LODS) {}
424
425                virtual void apply(osg::LOD& lod);
426
427                void combineLODs();
428
429        };
430 
431        /** Optimize State in the scene graph by removing duplicate state,
432          * replacing it with shared instances, both for StateAttributes,
433          * and whole StateSets.*/
434        class OSGUTIL_EXPORT StateVisitor : public BaseOptimizerVisitor
435        {
436            public:
437
438                /// default to traversing all children.
439                StateVisitor(bool combineDynamicState,
440                             bool combineStaticState,
441                             bool combineUnspecifiedState,
442                             Optimizer* optimizer=0):
443                    BaseOptimizerVisitor(optimizer, SHARE_DUPLICATE_STATE)
444                {
445                    _optimize[osg::Object::DYNAMIC] = combineDynamicState;
446                    _optimize[osg::Object::STATIC] = combineStaticState;
447                    _optimize[osg::Object::UNSPECIFIED] = combineUnspecifiedState;
448                }
449
450                /** empty visitor, make it ready for next traversal.*/       
451                virtual void reset();
452
453                virtual void apply(osg::Node& node);
454
455                virtual void apply(osg::Geode& geode);
456
457                void optimize();
458
459            protected:
460
461                void addStateSet(osg::StateSet* stateset,osg::Object* obj);
462               
463                inline bool optimize(osg::Object::DataVariance variance)
464                {
465                    return _optimize[variance];
466                }
467
468                typedef std::set<osg::Object*>              ObjectSet;
469                typedef std::map<osg::StateSet*,ObjectSet>  StateSetMap;
470
471                // note, one element for DYNAMIC, STATIC and UNSPECIFIED
472                bool _optimize[3];
473               
474                StateSetMap _statesets;
475
476        };
477
478        /** Combine geodes
479          */
480        class OSGUTIL_EXPORT MergeGeodesVisitor : public BaseOptimizerVisitor
481        {
482            public:
483
484                /// default to traversing all children.
485                MergeGeodesVisitor(Optimizer* optimizer=0):
486                    BaseOptimizerVisitor(optimizer, MERGE_GEODES) {}
487
488                virtual void apply(osg::Group& group);
489
490                bool mergeGeodes(osg::Group& group);
491
492            protected:
493
494                bool mergeGeode(osg::Geode& lhs, osg::Geode& rhs);
495
496        };
497
498        class OSGUTIL_EXPORT CheckGeometryVisitor : public BaseOptimizerVisitor
499        {
500            public:
501
502                /// default to traversing all children.
503                CheckGeometryVisitor(Optimizer* optimizer=0):
504                    BaseOptimizerVisitor(optimizer, CHECK_GEOMETRY) {}
505
506                virtual void apply(osg::Geode& geode) { checkGeode(geode); }
507
508                void checkGeode(osg::Geode& geode);
509               
510        };
511       
512        class OSGUTIL_EXPORT MakeFastGeometryVisitor : public BaseOptimizerVisitor
513        {
514            public:
515
516                /// default to traversing all children.
517                MakeFastGeometryVisitor(Optimizer* optimizer=0):
518                    BaseOptimizerVisitor(optimizer, MAKE_FAST_GEOMETRY) {}
519
520                virtual void apply(osg::Geode& geode) { checkGeode(geode); }
521
522                void checkGeode(osg::Geode& geode);
523               
524        };       
525       
526        class OSGUTIL_EXPORT MergeGeometryVisitor : public BaseOptimizerVisitor
527        {
528            public:
529
530                /// default to traversing all children.
531                MergeGeometryVisitor(Optimizer* optimizer=0) :
532                    BaseOptimizerVisitor(optimizer, MERGE_GEOMETRY),
533                    _targetMaximumNumberOfVertices(10000) {}
534
535                void setTargetMaximumNumberOfVertices(unsigned int num)
536                {
537                    _targetMaximumNumberOfVertices = num;
538                }
539               
540                unsigned int getTargetMaximumNumberOfVertices() const
541                {
542                    return _targetMaximumNumberOfVertices;
543                }
544
545                virtual void apply(osg::Geode& geode) { mergeGeode(geode); }
546                virtual void apply(osg::Billboard&) { /* don't do anything*/ }
547
548                bool mergeGeode(osg::Geode& geode);
549
550                static bool geometryContainsSharedArrays(osg::Geometry& geom);
551
552                static bool mergeGeometry(osg::Geometry& lhs,osg::Geometry& rhs);
553
554                static bool mergePrimitive(osg::DrawArrays& lhs,osg::DrawArrays& rhs);
555                static bool mergePrimitive(osg::DrawArrayLengths& lhs,osg::DrawArrayLengths& rhs);
556                static bool mergePrimitive(osg::DrawElementsUByte& lhs,osg::DrawElementsUByte& rhs);
557                static bool mergePrimitive(osg::DrawElementsUShort& lhs,osg::DrawElementsUShort& rhs);
558                static bool mergePrimitive(osg::DrawElementsUInt& lhs,osg::DrawElementsUInt& rhs);
559
560            protected:
561
562                unsigned int _targetMaximumNumberOfVertices;
563
564        };
565
566        /** Spatialize scene into a balanced quad/oct tree.*/
567        class OSGUTIL_EXPORT SpatializeGroupsVisitor : public BaseOptimizerVisitor
568        {
569            public:
570
571                SpatializeGroupsVisitor(Optimizer* optimizer=0):
572                    BaseOptimizerVisitor(optimizer, SPATIALIZE_GROUPS) {}
573               
574                virtual void apply(osg::Group& group);
575                virtual void apply(osg::Geode& geode);
576               
577                bool divide(unsigned int maxNumTreesPerCell=8);
578               
579                bool divide(osg::Group* group, unsigned int maxNumTreesPerCell);
580                bool divide(osg::Geode* geode, unsigned int maxNumTreesPerCell);
581               
582                typedef std::set<osg::Group*> GroupsToDivideList;
583                GroupsToDivideList _groupsToDivideList;
584
585                typedef std::set<osg::Geode*> GeodesToDivideList;
586                GeodesToDivideList _geodesToDivideList;
587        };
588
589        /** Copy any shared subgraphs, enabling flattening of static transforms.*/
590        class OSGUTIL_EXPORT CopySharedSubgraphsVisitor : public BaseOptimizerVisitor
591        {
592            public:
593
594                CopySharedSubgraphsVisitor(Optimizer* optimizer=0):
595                    BaseOptimizerVisitor(optimizer, COPY_SHARED_NODES) {}
596               
597                virtual void apply(osg::Node& node);
598
599                void copySharedNodes();
600               
601                typedef std::set<osg::Node*> SharedNodeList;
602                SharedNodeList _sharedNodeList;
603               
604        };
605
606
607        /** For all textures apply settings.*/
608        class OSGUTIL_EXPORT TextureVisitor : public BaseOptimizerVisitor
609        {
610            public:
611
612                TextureVisitor(bool changeAutoUnRef, bool valueAutoUnRef,
613                               bool changeClientImageStorage, bool valueClientImageStorage,
614                               bool changeAnisotropy, float valueAnisotropy,
615                               Optimizer* optimizer=0):
616                        BaseOptimizerVisitor(optimizer, OPTIMIZE_TEXTURE_SETTINGS),
617                        _changeAutoUnRef(changeAutoUnRef), _valueAutoUnRef(valueAutoUnRef),
618                        _changeClientImageStorage(changeClientImageStorage), _valueClientImageStorage(valueClientImageStorage),
619                        _changeAnisotropy(changeAnisotropy), _valueAnisotropy(valueAnisotropy) {}
620               
621                virtual void apply(osg::Geode& node);
622                virtual void apply(osg::Node& node);
623
624                void apply(osg::StateSet& stateset);
625                void apply(osg::Texture& texture);
626
627                bool            _changeAutoUnRef, _valueAutoUnRef;
628                bool            _changeClientImageStorage, _valueClientImageStorage;
629                bool            _changeAnisotropy;
630                float           _valueAnisotropy;
631
632        };
633       
634        /** Flatten MatrixTransform/Billboard pairs.*/
635        class OSGUTIL_EXPORT FlattenBillboardVisitor : public BaseOptimizerVisitor
636        {
637            public:
638                FlattenBillboardVisitor(Optimizer* optimizer=0):
639                        BaseOptimizerVisitor(optimizer, FLATTEN_BILLBOARDS) {}
640
641                typedef std::vector<osg::NodePath> NodePathList;
642                typedef std::map<osg::Billboard*, NodePathList > BillboardNodePathMap;
643
644                virtual void reset();
645
646                virtual void apply(osg::Billboard& billboard);
647
648                void process();   
649
650                BillboardNodePathMap _billboards;
651
652        };
653       
654        /** Texture Atlas Builder creates a set of textures/images which each contain multiple images.
655          * Texture Atlas' are used to make it possible to use much wider batching of data. */
656        class OSGUTIL_EXPORT TextureAtlasBuilder
657        {
658        public:
659            TextureAtlasBuilder();
660           
661            void reset();
662           
663            void setMaximumAtlasSize(unsigned int width, unsigned int height);
664
665            unsigned int getMaximumAtlasWidth() const { return _maximumAtlasWidth; }
666            unsigned int getMaximumAtlasHeight() const { return _maximumAtlasHeight; }
667           
668            void setMargin(unsigned int margin);
669            unsigned int getMargin() const { return _margin; }
670
671            void addSource(const osg::Image* image);
672            void addSource(const osg::Texture2D* texture);
673           
674            unsigned int getNumSources() const { return _sourceList.size(); }
675            const osg::Image* getSourceImage(unsigned int i) { return _sourceList[i]->_image.get(); }
676            const osg::Texture2D* getSourceTexture(unsigned int i) { return _sourceList[i]->_texture.get(); }
677           
678            void buildAtlas();
679           
680            osg::Image* getImageAtlas(unsigned int i);
681            osg::Texture2D* getTextureAtlas(unsigned int i);
682            osg::Matrix getTextureMatrix(unsigned int i);
683           
684            osg::Image* getImageAtlas(const osg::Image* image);
685            osg::Texture2D* getTextureAtlas(const osg::Image* image);
686            osg::Matrix getTextureMatrix(const osg::Image* image);
687           
688            osg::Image* getImageAtlas(const osg::Texture2D* textue);
689            osg::Texture2D* getTextureAtlas(const osg::Texture2D* texture);
690            osg::Matrix getTextureMatrix(const osg::Texture2D* texture);
691           
692        protected:
693       
694            unsigned int _maximumAtlasWidth;
695            unsigned int _maximumAtlasHeight;
696            unsigned int _margin;
697           
698
699            // forward declare
700            class Atlas;
701           
702            class Source : public osg::Referenced
703            {
704            public:
705                Source():
706                    _x(0),_y(0),_atlas(0) {}
707
708                Source(const osg::Image* image):
709                    _x(0),_y(0),_atlas(0),_image(image) {}
710
711                Source(const osg::Texture2D* texture):
712                    _x(0),_y(0),_atlas(0),_texture(texture) { if (texture) _image = texture->getImage(); }
713           
714                unsigned int _x;
715                unsigned int _y;
716                Atlas* _atlas;
717
718                osg::ref_ptr<const osg::Image> _image;
719                osg::ref_ptr<const osg::Texture2D> _texture;
720               
721                bool suitableForAtlas(unsigned int maximumAtlasWidth, unsigned int maximumAtlasHeight, unsigned int margin);
722                osg::Matrix computeTextureMatrix() const;
723               
724               
725            protected:
726           
727                virtual ~Source() {}
728            };
729           
730            typedef std::vector< osg::ref_ptr<Source> > SourceList;
731
732            class Atlas : public osg::Referenced
733            {
734            public:
735                Atlas(unsigned int width, unsigned height, unsigned margin):
736                    _maximumAtlasWidth(width),
737                    _maximumAtlasHeight(height),
738                    _margin(margin),
739                    _x(0),
740                    _y(0),
741                    _width(0),
742                    _height(0){}
743       
744                unsigned int _maximumAtlasWidth;
745                unsigned int _maximumAtlasHeight;
746                unsigned int _margin;
747
748                osg::ref_ptr<osg::Texture2D> _texture;
749                osg::ref_ptr<osg::Image> _image;
750           
751                SourceList _sourceList;
752               
753                unsigned int _x;
754                unsigned int _y;
755                unsigned int _width;
756                unsigned int _height;
757               
758                bool doesSourceFit(Source* source);
759                bool addSource(Source* source);
760                void clampToNearestPowerOfTwoSize();
761                void copySources();
762               
763            protected:
764           
765                virtual ~Atlas() {}
766            };
767           
768            typedef std::vector< osg::ref_ptr<Atlas> > AtlasList;
769           
770            Source* getSource(const osg::Image* image);
771            Source* getSource(const osg::Texture2D* texture);
772
773            SourceList _sourceList;
774            AtlasList _atlasList;   
775        };
776
777 
778        /** Optimize texture usage in the scene graph by combining textures into texture atlas
779          * Use of texture atlas cuts down on the number of seperate states in the scene, reducing
780          * state changes and improving the chances of use larger batches of geomertry.*/
781        class OSGUTIL_EXPORT TextureAtlasVisitor : public BaseOptimizerVisitor
782        {
783            public:
784
785                /// default to traversing all children.
786                TextureAtlasVisitor(Optimizer* optimizer=0):
787                    BaseOptimizerVisitor(optimizer, TEXTURE_ATLAS_BUILDER) {}
788
789
790                TextureAtlasBuilder& getTextureAtlasBuilder() { return _builder; }
791
792                /** empty visitor, make it ready for next traversal.*/       
793                virtual void reset();
794
795                virtual void apply(osg::Node& node);
796
797                virtual void apply(osg::Geode& geode);
798
799                void optimize();
800
801            protected:
802
803                bool pushStateSet(osg::StateSet* stateset);
804                void popStateSet();
805
806                typedef std::set<osg::Drawable*>  Drawables;
807                typedef std::map<osg::StateSet*, Drawables>  StateSetMap;
808                typedef std::set<osg::Texture2D*>  Textures;
809                typedef std::vector<osg::StateSet*>  StateSetStack;
810
811                TextureAtlasBuilder _builder;
812
813                StateSetMap     _statesetMap;
814                StateSetStack   _statesetStack;
815                Textures        _textures;
816
817        };
818
819        /** Optimize the setting of StateSet and Geometry objects in scene so that they have a STATIC DataVariance
820          * when they don't have any callbacks associated with them. */
821        class OSGUTIL_EXPORT StaticObjectDetectionVisitor : public BaseOptimizerVisitor
822        {
823            public:
824
825                /// default to traversing all children.
826                StaticObjectDetectionVisitor(Optimizer* optimizer=0):
827                    BaseOptimizerVisitor(optimizer, STATIC_OBJECT_DETECTION) {}
828
829                virtual void apply(osg::Node& node);
830
831                virtual void apply(osg::Geode& geode);
832
833            protected:
834
835                void applyStateSet(osg::StateSet& stateset);
836               
837                void applyDrawable(osg::Drawable& drawable);
838
839        };
840};
841
842inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::StateSet* object) const
843{
844    return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) :  true;
845}
846
847inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::StateAttribute* object) const
848{
849    return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) :  true;
850}
851
852inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::Drawable* object) const
853{
854    return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) :  true;
855}
856
857inline bool BaseOptimizerVisitor::isOperationPermissibleForObject(const osg::Node* object) const
858{
859    return _optimizer ? _optimizer->isOperationPermissibleForObject(object,_operationType) :  true;
860}
861
862}
863
864#endif
Note: See TracBrowser for help on using the browser.