#ifndef _gpuCacheDrawTraversal_h_
#define _gpuCacheDrawTraversal_h_
#include "gpuCacheGeometry.h"
#include "gpuCacheFrustum.h"
#include "gpuCacheVBOProxy.h"
#include <boost/foreach.hpp>
namespace GPUCache {
class DrawTraversalState
{
public:
enum TransparentPruneType {
kPruneNone,
kPruneOpaque,
kPruneTransparent
};
DrawTraversalState(
const Frustum& frustrum,
const double seconds,
const TransparentPruneType transparentPrune)
: fFrustum(frustrum),
fSeconds(seconds),
fTransparentPrune(transparentPrune)
{}
virtual ~DrawTraversalState() {}
const Frustum& frustum() const { return fFrustum; }
double seconds() const { return fSeconds; }
TransparentPruneType transparentPrune() const { return fTransparentPrune; }
VBOProxy& vboProxy() { return fVBOProxy; }
private:
DrawTraversalState(const DrawTraversalState&);
const DrawTraversalState& operator=(const DrawTraversalState&);
private:
const Frustum fFrustum;
const double fSeconds;
const TransparentPruneType fTransparentPrune;
VBOProxy fVBOProxy;
};
template <class Derived, class State>
class DrawTraversal : public SubNodeVisitor
{
public:
State& state() const { return fState; }
const MMatrix& xform()
const {
return fXform; }
protected:
DrawTraversal(
State& state,
bool isReflection,
Frustum::ClippingResult parentClippingResult
)
: fState(state),
fXform(xform),
fIsReflection(isReflection),
fParentClippingResult(parentClippingResult)
{}
bool isReflection() const { return fIsReflection; }
const SubNode& subNode() const { return *fSubNode; }
private:
virtual void visit(const XformData& xform,
const SubNode& subNode)
{
if (state().transparentPrune() == State::kPruneOpaque &&
subNode.transparentType() == SubNode::kOpaque) {
return;
}
else if (state().transparentPrune() == State::kPruneTransparent &&
subNode.transparentType() == SubNode::kTransparent) {
return;
}
const boost::shared_ptr<const XformSample>& sample =
xform.getSample(fState.seconds());
if (!sample) return;
if (!sample->visibility()) return;
Frustum::ClippingResult clippingResult = Frustum::kInside;
if (fParentClippingResult != Frustum::kInside) {
clippingResult = state().frustum().test(
sample->boundingBox(), fParentClippingResult);
if (clippingResult == Frustum::kOutside) {
return;
}
}
Derived traversal(fState, sample->xform() * fXform,
bool(fIsReflection ^ sample->isReflection()),
clippingResult);
BOOST_FOREACH(const SubNode::Ptr& child,
subNode.getChildren() ) {
child->accept(traversal);
}
}
virtual void visit(const ShapeData& shape,
const SubNode& subNode)
{
const boost::shared_ptr<const ShapeSample>& sample =
shape.getSample(fState.seconds());
if (!sample) return;
fSubNode = &subNode;
static_cast<Derived*>(this)->draw(sample);
}
private:
DrawTraversal(const DrawTraversal&);
const DrawTraversal& operator=(const DrawTraversal&);
private:
State& fState;
const SubNode* fSubNode;
const bool fIsReflection;
const Frustum::ClippingResult fParentClippingResult;
};
}
#endif