OpenSceneGraph/include/osgUtil/RenderGraph
Robert Osfield f11410928f Simplified the depth calculation code in CullVisitor so that it always computes
the depth of all drawables, so that it is always safe for RenderBin sort routines can use
these values directly.

Add an example of a RenderBin::SortCallback to sgv.cpp.
2002-09-18 14:57:01 +00:00

271 lines
8.3 KiB
Plaintext

//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 <osg/Matrix>
#include <osg/Drawable>
#include <osg/StateSet>
#include <osg/State>
#include <osg/Light>
#include <osgUtil/RenderLeaf>
#include <set>
#include <vector>
#include <algorithm>
namespace osgUtil {
struct LeafDepthSortFunctor
{
bool operator() (const osg::ref_ptr<RenderLeaf>& lhs,const osg::ref_ptr<RenderLeaf>& rhs)
{
return (lhs->_depth>rhs->_depth);
}
};
class OSGUTIL_EXPORT RenderGraph : public osg::Referenced
{
public:
typedef std::map< const osg::StateSet*, osg::ref_ptr<RenderGraph> > ChildList;
typedef std::vector< osg::ref_ptr<RenderLeaf> > LeafList;
RenderGraph* _parent;
osg::ref_ptr<const osg::StateSet> _stateset;
int _depth;
ChildList _children;
LeafList _leaves;
mutable float _averageDistance;
mutable float _minimumDistance;
osg::ref_ptr<osg::Referenced> _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<RenderGraph*> 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<RenderGraph*>::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<RenderGraph*> 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.
while (sg_curr->_parent!=sg_new->_parent)
{
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<RenderGraph*>::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