Optimizer 35 KB

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