//C++ header - Open Scene Graph - Copyright (C) 1998-2002 Robert Osfield //Distributed under the terms of the GNU Library General Public License (LGPL) //as published by the Free Software Foundation. #ifndef OSGUTIL_RENDERGRAPH #define OSGUTIL_RENDERGRAPH 1 #include #include #include #include #include #include #include #include #include namespace osgUtil { struct LeafDepthSortFunctor { bool operator() (const osg::ref_ptr& lhs,const osg::ref_ptr& rhs) { return (lhs->_depth>rhs->_depth); } }; class OSGUTIL_EXPORT RenderGraph : public osg::Referenced { public: typedef std::map< const osg::StateSet*, osg::ref_ptr > ChildList; typedef std::vector< osg::ref_ptr > LeafList; RenderGraph* _parent; osg::ref_ptr _stateset; int _depth; ChildList _children; LeafList _leaves; mutable float _averageDistance; mutable float _minimumDistance; osg::ref_ptr _userData; RenderGraph(): _parent(NULL), _stateset(NULL), _depth(0), _averageDistance(0), _minimumDistance(0), _userData(NULL) { } RenderGraph(RenderGraph* parent,const osg::StateSet* stateset): _parent(parent), _stateset(stateset), _depth(0), _averageDistance(0), _minimumDistance(0), _userData(NULL) { if (_parent) _depth = _parent->_depth + 1; } ~RenderGraph() {} RenderGraph* cloneType() const { return osgNew RenderGraph; } void setUserData(osg::Referenced* obj) { _userData = obj; } osg::Referenced* getUserData() { return _userData.get(); } const osg::Referenced* getUserData() const { return _userData.get(); } /** return true if all of drawables, lights and children are empty.*/ inline bool empty() const { return _leaves.empty() && _children.empty(); } inline bool leaves_empty() const { return _leaves.empty(); } inline float getAverageDistance() const { if (_averageDistance==FLT_MAX && !_leaves.empty()) { _averageDistance = 0.0f; for(LeafList::const_iterator itr=_leaves.begin(); itr!=_leaves.end(); ++itr) { _averageDistance += (*itr)->_depth; } _averageDistance /= (float)_leaves.size(); } return _averageDistance; } inline float getMinimumDistance() const { if (_minimumDistance==FLT_MAX && !_leaves.empty()) { LeafList::const_iterator itr=_leaves.begin(); _minimumDistance = (*itr)->_depth; ++itr; for(; itr!=_leaves.end(); ++itr) { if ((*itr)->_depth<_minimumDistance) _minimumDistance=(*itr)->_depth; } } return _minimumDistance; } inline void sortFrontToBack() { std::sort(_leaves.begin(),_leaves.end(),LeafDepthSortFunctor()); } /** reset the internal contents of a RenderGraph, including deleting all children.*/ void reset(); /** recursively clean the RenderGraph of all its drawables, lights and depths. * Leaves children intact, and ready to be populated again.*/ void clean(); /** recursively prune the RenderGraph of empty children.*/ void prune(); inline RenderGraph* find_or_insert(const osg::StateSet* stateset) { // search for the appropriate state group, return it if found. ChildList::iterator itr = _children.find(stateset); if (itr!=_children.end()) return itr->second.get(); // create a state group and insert it into the children list // then return the state group. RenderGraph* sg = osgNew RenderGraph(this,stateset); _children[stateset] = sg; return sg; } /** add a render leaf.*/ inline void addLeaf(RenderLeaf* leaf) { if (leaf) { _averageDistance = FLT_MAX; // signify dirty. _minimumDistance = FLT_MAX; // signify dirty. _leaves.push_back(leaf); leaf->_parent = this; } } static inline void moveRenderGraph(osg::State& state,RenderGraph* sg_curr,RenderGraph* sg_new) { if (sg_new==sg_curr || sg_new==NULL) return; if (sg_curr==NULL) { // use return path to trace back steps to sg_new. std::vector return_path; // need to pop back root render graph. do { return_path.push_back(sg_new); sg_new = sg_new->_parent; } while (sg_new); for(std::vector::reverse_iterator itr=return_path.rbegin(); itr!=return_path.rend(); ++itr) { RenderGraph* rg = (*itr); if (rg->_stateset.valid()) state.pushStateSet(rg->_stateset.get()); } return; } // first handle the typical case which is two state groups // are neighbours. if (sg_curr->_parent==sg_new->_parent) { // state has changed so need to pop old state. if (sg_curr->_stateset.valid()) state.popStateSet(); // and push new state. if (sg_new->_stateset.valid()) state.pushStateSet(sg_new->_stateset.get()); return; } // need to pop back up to the same depth as the new state group. while (sg_curr->_depth>sg_new->_depth) { if (sg_curr->_stateset.valid()) state.popStateSet(); sg_curr = sg_curr->_parent; } // use return path to trace back steps to sg_new. std::vector return_path; // need to pop back up to the same depth as the curr state group. while (sg_new->_depth>sg_curr->_depth) { return_path.push_back(sg_new); sg_new = sg_new->_parent; } // now pop back up both parent paths until they agree. // DRT - 10/22/02 // should be this to conform with above case where two RenderGraph // nodes have the same parent while (sg_curr != sg_new) { if (sg_curr->_stateset.valid()) state.popStateSet(); sg_curr = sg_curr->_parent; return_path.push_back(sg_new); sg_new = sg_new->_parent; } for(std::vector::reverse_iterator itr=return_path.rbegin(); itr!=return_path.rend(); ++itr) { RenderGraph* rg = (*itr); if (rg->_stateset.valid()) state.pushStateSet(rg->_stateset.get()); } } inline static void moveToRootRenderGraph(osg::State& state,RenderGraph* sg_curr) { // need to pop back all statesets and matrices. while (sg_curr) { if (sg_curr->_stateset.valid()) state.popStateSet(); sg_curr = sg_curr->_parent; } } private: /// disallow copy construction. RenderGraph(const RenderGraph&):osg::Referenced() {} /// disallow copy operator. RenderGraph& operator = (const RenderGraph&) { return *this; } }; } #endif