f5f20e4ac1
up to common parents.
275 lines
8.4 KiB
Plaintext
275 lines
8.4 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.
|
|
|
|
// 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<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
|
|
|