unify PandaNode::CData again; create PandaNodePipelineReader

This commit is contained in:
David Rose 2006-04-30 20:24:36 +00:00
parent f410cff0cd
commit f1038ea8ef
9 changed files with 1005 additions and 695 deletions

View File

@ -115,7 +115,7 @@ traverse(const NodePath &root, bool python_cull_control) {
CullTraverserData data(root, TransformState::make_identity(),
_initial_state, _view_frustum,
_guard_band);
_guard_band, _current_thread);
traverse(data);
@ -133,7 +133,7 @@ traverse(const NodePath &root, bool python_cull_control) {
} else {
CullTraverserData data(root, TransformState::make_identity(),
_initial_state, _view_frustum,
_guard_band);
_guard_band, _current_thread);
traverse(data);
}
@ -153,16 +153,17 @@ traverse(CullTraverserData &data) {
// optimization, we should tag nodes with these properties as
// being "fancy", and skip this processing for non-fancy nodes.
if (data.is_in_view(_camera_mask, _current_thread)) {
if (data.is_in_view(_camera_mask)) {
if (pgraph_cat.is_spam()) {
pgraph_cat.spam()
<< "\n" << data._node_path
<< " " << data._draw_mask << "\n";
}
PandaNodePipelineReader *node_reader = data.node_reader();
PandaNode *node = data.node();
const RenderEffects *node_effects = node->get_effects(_current_thread);
const RenderEffects *node_effects = node_reader->get_effects();
if (node_effects->has_show_bounds()) {
// If we should show the bounding volume for this node, make it
// up now.
@ -171,7 +172,7 @@ traverse(CullTraverserData &data) {
data.apply_transform_and_state(this);
const FogAttrib *fog = node->get_state(_current_thread)->get_fog();
const FogAttrib *fog = node_reader->get_state()->get_fog();
if (fog != (const FogAttrib *)NULL && fog->get_fog() != (Fog *)NULL) {
// If we just introduced a FogAttrib here, call adjust_to_camera()
// now. This maybe isn't the perfect time to call it, but it's
@ -200,11 +201,12 @@ traverse(CullTraverserData &data) {
void CullTraverser::
traverse_below(CullTraverserData &data) {
_nodes_pcollector.add_level(1);
PandaNodePipelineReader *node_reader = data.node_reader();
PandaNode *node = data.node();
bool this_node_hidden = data.is_this_node_hidden(this);
const RenderEffects *node_effects = node->get_effects(_current_thread);
const RenderEffects *node_effects = node_reader->get_effects();
bool has_decal = !this_node_hidden && node_effects->has_decal();
if (has_decal && !_depth_offset_decals) {
// Start the three-pass decal rendering if we're not using
@ -252,7 +254,8 @@ traverse_below(CullTraverserData &data) {
}
// Now visit all the node's children.
PandaNode::Children children = node->get_children(_current_thread);
PandaNode::Children children = node_reader->get_children();
node_reader->release();
int num_children = children.get_num_children();
if (node->has_selective_visibility()) {
int i = node->get_first_visible_child();
@ -523,6 +526,8 @@ start_decal(const CullTraverserData &data) {
return;
}
const PandaNodePipelineReader *node_reader = data.node_reader();
// Build a chain of CullableObjects. The head of the chain will be
// all of the base Geoms in order, followed by an empty
// CullableObject node, followed by all of the decal Geoms, in
@ -531,7 +536,7 @@ start_decal(const CullTraverserData &data) {
// Since the CullableObject is a linked list which gets built in
// LIFO order, we start with the decals.
CullableObject *decals = (CullableObject *)NULL;
PandaNode::Children cr = node->get_children(_current_thread);
PandaNode::Children cr = node_reader->get_children();
int num_children = cr.get_num_children();
if (node->has_selective_visibility()) {
int i = node->get_first_visible_child();
@ -592,10 +597,11 @@ start_decal(const CullTraverserData &data) {
////////////////////////////////////////////////////////////////////
CullableObject *CullTraverser::
r_get_decals(CullTraverserData &data, CullableObject *decals) {
if (data.is_in_view(_camera_mask, _current_thread)) {
if (data.is_in_view(_camera_mask)) {
PandaNodePipelineReader *node_reader = data.node_reader();
PandaNode *node = data.node();
const RenderEffects *node_effects = node->get_effects();
const RenderEffects *node_effects = node_reader->get_effects();
if (node_effects->has_show_bounds()) {
// If we should show the bounding volume for this node, make it
// up now.
@ -605,18 +611,18 @@ r_get_decals(CullTraverserData &data, CullableObject *decals) {
data.apply_transform_and_state(this);
// First, visit all of the node's children.
int num_children = node->get_num_children();
int num_children = node_reader->get_num_children();
if (node->has_selective_visibility()) {
int i = node->get_first_visible_child();
while (i < num_children) {
CullTraverserData next_data(data, node->get_child(i));
CullTraverserData next_data(data, node_reader->get_child(i));
decals = r_get_decals(next_data, decals);
i = node->get_next_visible_child(i);
}
} else {
for (int i = num_children - 1; i >= 0; i--) {
CullTraverserData next_data(data, node->get_child(i));
CullTraverserData next_data(data, node_reader->get_child(i));
decals = r_get_decals(next_data, decals);
}
}

View File

@ -26,8 +26,10 @@ CullTraverserData(const NodePath &start,
const TransformState *net_transform,
const RenderState *state,
GeometricBoundingVolume *view_frustum,
GeometricBoundingVolume *guard_band) :
GeometricBoundingVolume *guard_band,
Thread *current_thread) :
_node_path(start),
_node_reader(start.node(), current_thread),
_net_transform(net_transform),
_state(state),
_view_frustum(view_frustum),
@ -35,6 +37,7 @@ CullTraverserData(const NodePath &start,
_cull_planes(CullPlanes::make_empty()),
_draw_mask(DrawMask::all_on())
{
_node_reader.check_bounds();
}
////////////////////////////////////////////////////////////////////
@ -45,6 +48,7 @@ CullTraverserData(const NodePath &start,
INLINE CullTraverserData::
CullTraverserData(const CullTraverserData &copy) :
_node_path(copy._node_path),
_node_reader(copy._node_reader),
_net_transform(copy._net_transform),
_state(copy._state),
_view_frustum(copy._view_frustum),
@ -62,6 +66,7 @@ CullTraverserData(const CullTraverserData &copy) :
INLINE void CullTraverserData::
operator = (const CullTraverserData &copy) {
_node_path = copy._node_path;
_node_reader = copy._node_reader;
_net_transform = copy._net_transform;
_state = copy._state;
_view_frustum = copy._view_frustum;
@ -79,6 +84,7 @@ operator = (const CullTraverserData &copy) {
INLINE CullTraverserData::
CullTraverserData(const CullTraverserData &parent, PandaNode *child) :
_node_path(parent._node_path, child),
_node_reader(child, parent._node_reader.get_current_thread()),
_net_transform(parent._net_transform),
_state(parent._state),
_view_frustum(parent._view_frustum),
@ -86,6 +92,7 @@ CullTraverserData(const CullTraverserData &parent, PandaNode *child) :
_cull_planes(parent._cull_planes),
_draw_mask(parent._draw_mask)
{
_node_reader.check_bounds();
}
////////////////////////////////////////////////////////////////////
@ -107,6 +114,28 @@ node() const {
return _node_path.node();
}
////////////////////////////////////////////////////////////////////
// Function: CullTraverserData::node_reader
// Access: Public
// Description: Returns the PipelineReader for the node traversed to
// so far.
////////////////////////////////////////////////////////////////////
INLINE PandaNodePipelineReader *CullTraverserData::
node_reader() {
return &_node_reader;
}
////////////////////////////////////////////////////////////////////
// Function: CullTraverserData::node_reader
// Access: Public
// Description: Returns the PipelineReader for the node traversed to
// so far.
////////////////////////////////////////////////////////////////////
INLINE const PandaNodePipelineReader *CullTraverserData::
node_reader() const {
return &_node_reader;
}
////////////////////////////////////////////////////////////////////
// Function: CullTraverserData::get_net_transform
// Access: Public
@ -128,13 +157,13 @@ get_net_transform(const CullTraverser *) const {
// work for future nodes.
////////////////////////////////////////////////////////////////////
INLINE bool CullTraverserData::
is_in_view(const DrawMask &camera_mask, Thread *current_thread) {
if (node()->get_transform(current_thread)->is_invalid()) {
is_in_view(const DrawMask &camera_mask) {
if (_node_reader.get_transform()->is_invalid()) {
// If the transform is invalid, forget it.
return false;
}
if (!node()->compare_draw_mask(_draw_mask, camera_mask, current_thread)) {
if (!_node_reader.compare_draw_mask(_draw_mask, camera_mask)) {
// If there are no draw bits in common with the camera, the node
// is out.
return false;
@ -148,7 +177,7 @@ is_in_view(const DrawMask &camera_mask, Thread *current_thread) {
}
// Otherwise, compare the bounding volume to the frustum.
return is_in_view_impl(current_thread);
return is_in_view_impl();
}
////////////////////////////////////////////////////////////////////

View File

@ -51,24 +51,22 @@ get_modelview_transform(const CullTraverser *trav) const {
////////////////////////////////////////////////////////////////////
void CullTraverserData::
apply_transform_and_state(CullTraverser *trav) {
Thread *current_thread = trav->get_current_thread();
PandaNode *node = _node_path.node();
CPT(RenderState) node_state = node->get_state(current_thread);
CPT(RenderState) node_state = _node_reader.get_state();
if (trav->has_tag_state_key() &&
node->has_tag(trav->get_tag_state_key(), current_thread)) {
_node_reader.has_tag(trav->get_tag_state_key())) {
// Here's a node that has been tagged with the special key for our
// current camera. This indicates some special state transition
// for this node, which is unique to this camera.
const Camera *camera = trav->get_scene()->get_camera_node();
string tag_state = node->get_tag(trav->get_tag_state_key(), current_thread);
string tag_state = _node_reader.get_tag(trav->get_tag_state_key());
node_state = node_state->compose(camera->get_tag_state(tag_state));
}
node->compose_draw_mask(_draw_mask, current_thread);
_node_reader.compose_draw_mask(_draw_mask);
apply_transform_and_state(trav, node->get_transform(current_thread),
node_state, node->get_effects(current_thread),
node->get_off_clip_planes(current_thread));
apply_transform_and_state(trav, _node_reader.get_transform(),
node_state, _node_reader.get_effects(),
_node_reader.get_off_clip_planes());
}
////////////////////////////////////////////////////////////////////
@ -137,8 +135,8 @@ apply_transform_and_state(CullTraverser *trav,
// Description: The private implementation of is_in_view().
////////////////////////////////////////////////////////////////////
bool CullTraverserData::
is_in_view_impl(Thread *current_thread) {
CPT(BoundingVolume) node_volume = node()->get_bounds(current_thread);
is_in_view_impl() {
CPT(BoundingVolume) node_volume = _node_reader.get_bounds();
nassertr(node_volume->is_of_type(GeometricBoundingVolume::get_class_type()), false);
const GeometricBoundingVolume *node_gbv =
DCAST(GeometricBoundingVolume, node_volume);
@ -173,7 +171,7 @@ is_in_view_impl(Thread *current_thread) {
} else {
// The node is partially, but not completely, within the viewing
// frustum.
if (node()->is_final(current_thread)) {
if (_node_reader.is_final()) {
// Normally we'd keep testing child bounding volumes as we
// continue down. But this node has the "final" flag, so the
// user is claiming that there is some important reason we
@ -207,7 +205,7 @@ is_in_view_impl(Thread *current_thread) {
} else {
// The node is partially within one or more clip planes.
if (node()->is_final(current_thread)) {
if (_node_reader.is_final()) {
// Even though the node is only partially within the clip
// planes, stop culling against them.
_cull_planes = CullPlanes::make_empty();
@ -230,7 +228,7 @@ test_within_clip_planes_impl(const CullTraverser *trav,
int result = BoundingVolume::IF_all | BoundingVolume::IF_possible | BoundingVolume::IF_some;
const BoundingVolume *node_volume = node()->get_bounds();
const BoundingVolume *node_volume = _node_reader.get_bounds();
nassertr(node_volume->is_of_type(GeometricBoundingVolume::get_class_type()), result);
const GeometricBoundingVolume *node_gbv =
DCAST(GeometricBoundingVolume, node_volume);

View File

@ -51,7 +51,8 @@ public:
const TransformState *net_transform,
const RenderState *state,
GeometricBoundingVolume *view_frustum,
GeometricBoundingVolume *guard_band);
GeometricBoundingVolume *guard_band,
Thread *current_thread);
INLINE CullTraverserData(const CullTraverserData &copy);
INLINE void operator = (const CullTraverserData &copy);
INLINE CullTraverserData(const CullTraverserData &parent,
@ -59,11 +60,13 @@ public:
INLINE ~CullTraverserData();
INLINE PandaNode *node() const;
INLINE PandaNodePipelineReader *node_reader();
INLINE const PandaNodePipelineReader *node_reader() const;
CPT(TransformState) get_modelview_transform(const CullTraverser *trav) const;
INLINE const TransformState *get_net_transform(const CullTraverser *trav) const;
INLINE bool is_in_view(const DrawMask &camera_mask, Thread *current_thread);
INLINE bool is_in_view(const DrawMask &camera_mask);
INLINE bool is_this_node_hidden(const CullTraverser *trav) const;
void apply_transform_and_state(CullTraverser *trav);
@ -74,6 +77,7 @@ public:
const RenderAttrib *off_clip_planes);
WorkingNodePath _node_path;
PandaNodePipelineReader _node_reader;
CPT(TransformState) _net_transform;
CPT(RenderState) _state;
PT(GeometricBoundingVolume) _view_frustum;
@ -82,7 +86,7 @@ public:
DrawMask _draw_mask;
private:
bool is_in_view_impl(Thread *current_thread);
bool is_in_view_impl();
int test_within_clip_planes_impl(const CullTraverser *trav,
const ClipPlaneAttrib *cpa) const;

View File

@ -56,13 +56,13 @@ munge_geom(GraphicsStateGuardianBase *gsg,
GeomPipelineReader geom_reader(_geom, current_thread);
_munged_data = geom_reader.get_vertex_data();
#ifndef NDEBUG
#ifdef _DEBUG
{
GeomVertexDataPipelineReader data_reader(_munged_data, current_thread);
data_reader.check_array_readers();
nassertv(geom_reader.check_valid(&data_reader));
}
#endif // NDEBUG
#endif // _DEBUG
int geom_rendering = geom_reader.get_geom_rendering();
geom_rendering = _state->get_geom_rendering(geom_rendering);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -110,12 +110,6 @@ public:
virtual int get_visible_child() const;
virtual bool is_renderable() const;
INLINE void compose_draw_mask(DrawMask &running_draw_mask,
Thread *current_thread) const;
INLINE bool compare_draw_mask(DrawMask running_draw_mask,
DrawMask camera_mask,
Thread *current_thread) const;
PUBLISHED:
PT(PandaNode) copy_subgraph(Thread *current_thread = Thread::get_current_thread()) const;
@ -280,14 +274,11 @@ protected:
Thread *current_thread);
private:
class CDataLight;
class CDataHeavy;
class CDataBounds;
class CDataLinks;
class CData;
INLINE int do_find_parent(PandaNode *node, const CDataLinks *cdata) const;
int do_find_child(PandaNode *node, const CDataLinks *cdata) const;
int do_find_stashed(PandaNode *node, const CDataLinks *cdata) const;
INLINE int do_find_parent(PandaNode *node, const CData *cdata) const;
int do_find_child(PandaNode *node, const CData *cdata) const;
int do_find_stashed(PandaNode *node, const CData *cdata) const;
bool stage_remove_child(PandaNode *child_node, int pipeline_stage,
Thread *current_thread);
bool stage_replace_child(PandaNode *orig_child, PandaNode *new_child,
@ -387,21 +378,14 @@ private:
#endif // HAVE_PYTHON
// This is the data that must be cycled between pipeline stages. We
// store it in several different CData objects, in an attempt to
// minimize overhead caused by cycling data unnecessarily. The
// things that are likely to change often (and at the same time) are
// grouped into the same CData object; things that change less often
// are grouped into a different one.
// This is the data that must be cycled between pipeline stages.
// The CDataLight object stores the lightweight parts of the node
// that are likely to change fairly often: transform and state.
class EXPCL_PANDA CDataLight : public CycleData {
class EXPCL_PANDA CData : public CycleData {
public:
INLINE CDataLight();
CDataLight(const CDataLight &copy);
virtual ~CDataLight();
ALLOC_DELETED_CHAIN(CDataLight);
CData();
CData(const CData &copy);
virtual ~CData();
ALLOC_DELETED_CHAIN(CData);
virtual CycleData *make_copy() const;
virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
@ -411,34 +395,18 @@ private:
return PandaNode::get_class_type();
}
public:
// This section contains the lightweight parts of the node that
// are likely to change fairly often: transform and state.
NCPT(RenderState) _state;
NCPT(TransformState) _transform;
NCPT(TransformState) _prev_transform;
};
PipelineCycler<CDataLight> _cycler_light;
typedef CycleDataReader<CDataLight> CDLightReader;
typedef CycleDataWriter<CDataLight> CDLightWriter;
typedef CycleDataStageReader<CDataLight> CDLightStageReader;
typedef CycleDataStageWriter<CDataLight> CDLightStageWriter;
// The CDataHeavy object stores the heavierweight parts of the node
// that are less likely to change as often: tags, collide mask.
class EXPCL_PANDA CDataHeavy : public CycleData {
public:
INLINE CDataHeavy();
CDataHeavy(const CDataHeavy &copy);
virtual ~CDataHeavy();
ALLOC_DELETED_CHAIN(CDataHeavy);
virtual CycleData *make_copy() const;
virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
virtual void fillin(DatagramIterator &scan, BamReader *manager);
virtual TypeHandle get_parent_type() const {
return PandaNode::get_class_type();
}
// This section contains the heavierweight parts of the node that
// are less likely to change as often: tags, collide mask.
#ifdef HAVE_PYTHON
void inc_py_refs();
void dec_py_refs();
@ -475,29 +443,12 @@ private:
// This is true if the external bounds of this node should be
// deemed "final". See set_final().
bool _final_bounds;
};
PipelineCycler<CDataHeavy> _cycler_heavy;
typedef CycleDataReader<CDataHeavy> CDHeavyReader;
typedef CycleDataWriter<CDataHeavy> CDHeavyWriter;
typedef CycleDataStageReader<CDataHeavy> CDHeavyStageReader;
typedef CycleDataStageWriter<CDataHeavy> CDHeavyStageWriter;
// The CDataBounds object stores the data that is accumulated upward
// from the node's children: that is, the external bounding volume,
// and conceptually similar things like the net_collide_mask, etc.
// None of the data in this object is preserved in a bam file.
class EXPCL_PANDA CDataBounds : public CycleData {
public:
INLINE CDataBounds();
CDataBounds(const CDataBounds &copy);
virtual ~CDataBounds();
ALLOC_DELETED_CHAIN(CDataBounds);
virtual CycleData *make_copy() const;
virtual TypeHandle get_parent_type() const {
return PandaNode::get_class_type();
}
// This section contains the data that is accumulated upward from
// the node's children: that is, the external bounding volume, and
// conceptually similar things like the net_collide_mask, etc.
// None of the data in this object is preserved in a bam file.
// This is the union of all into_collide_mask bits for any nodes
// at and below this level.
@ -518,30 +469,10 @@ private:
// When _last_update != _next_update, this cache is stale.
UpdateSeq _last_update, _next_update;
};
PipelineCycler<CDataBounds> _cycler_bounds;
typedef CycleDataReader<CDataBounds> CDBoundsReader;
typedef CycleDataWriter<CDataBounds> CDBoundsWriter;
typedef CycleDataStageReader<CDataBounds> CDBoundsStageReader;
typedef CycleDataStageWriter<CDataBounds> CDBoundsStageWriter;
// The CDataLinks object stores the links to other nodes above and
// below this node in the graph.
class EXPCL_PANDA CDataLinks : public CycleData {
public:
INLINE CDataLinks();
CDataLinks(const CDataLinks &copy);
virtual ~CDataLinks();
ALLOC_DELETED_CHAIN(CDataLinks);
virtual CycleData *make_copy() const;
virtual void write_datagram(BamWriter *manager, Datagram &dg) const;
virtual int complete_pointers(TypedWritable **plist, BamReader *manager);
virtual void fillin(DatagramIterator &scan, BamReader *manager);
virtual TypeHandle get_parent_type() const {
return PandaNode::get_class_type();
}
// This section stores the links to other nodes above and below
// this node in the graph.
void write_up_list(const Up &up_list,
BamWriter *manager, Datagram &dg) const;
@ -571,14 +502,13 @@ private:
PT(Up) _up;
};
PipelineCycler<CDataLinks> _cycler_links;
typedef CycleDataReader<CDataLinks> CDLinksReader;
typedef CycleDataWriter<CDataLinks> CDLinksWriter;
typedef CycleDataStageReader<CDataLinks> CDLinksStageReader;
typedef CycleDataStageWriter<CDataLinks> CDLinksStageWriter;
PipelineCycler<CData> _cycler;
typedef CycleDataReader<CData> CDReader;
typedef CycleDataWriter<CData> CDWriter;
typedef CycleDataStageReader<CData> CDStageReader;
typedef CycleDataStageWriter<CData> CDStageWriter;
CDBoundsStageWriter update_bounds(int pipeline_stage,
CDBoundsStageReader &cdata);
CDStageWriter update_bounds(int pipeline_stage, CDStageReader &cdata);
static DrawMask _overall_bit;
@ -595,7 +525,7 @@ public:
class EXPCL_PANDA Children {
public:
INLINE Children();
INLINE Children(const CDataLinks *cdata);
INLINE Children(const CData *cdata);
INLINE Children(const Children &copy);
INLINE void operator = (const Children &copy);
@ -611,7 +541,7 @@ public:
class EXPCL_PANDA Stashed {
public:
INLINE Stashed();
INLINE Stashed(const CDataLinks *cdata);
INLINE Stashed(const CData *cdata);
INLINE Stashed(const Stashed &copy);
INLINE void operator = (const Stashed &copy);
@ -627,7 +557,7 @@ public:
class EXPCL_PANDA Parents {
public:
INLINE Parents();
INLINE Parents(const CDataLinks *cdata);
INLINE Parents(const CData *cdata);
INLINE Parents(const Parents &copy);
INLINE void operator = (const Parents &copy);
@ -678,6 +608,70 @@ private:
friend class NodePath;
friend class NodePathComponent;
friend class WorkingNodePath;
friend class PandaNodePipelineReader;
};
////////////////////////////////////////////////////////////////////
// Class : PandaNodePipelineReader
// Description : Encapsulates the data from a PandaNode,
// pre-fetched for one stage of the pipeline.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA PandaNodePipelineReader {
public:
INLINE PandaNodePipelineReader(const PandaNode *object, Thread *current_thread);
INLINE PandaNodePipelineReader(const PandaNodePipelineReader &copy);
INLINE void operator = (const PandaNodePipelineReader &copy);
public:
INLINE ~PandaNodePipelineReader();
ALLOC_DELETED_CHAIN(PandaNodePipelineReader);
INLINE const PandaNode *get_object() const;
INLINE Thread *get_current_thread() const;
INLINE void release();
INLINE void check_bounds() const;
INLINE void compose_draw_mask(DrawMask &running_draw_mask) const;
INLINE bool compare_draw_mask(DrawMask running_draw_mask,
DrawMask camera_mask) const;
INLINE int get_num_parents() const;
INLINE PandaNode *get_parent(int n) const;
INLINE int find_parent(PandaNode *node) const;
INLINE int get_num_children() const;
INLINE PandaNode *get_child(int n) const;
INLINE int get_child_sort(int n) const;
INLINE int find_child(PandaNode *node) const;
INLINE int get_num_stashed() const;
INLINE PandaNode *get_stashed(int n) const;
INLINE int get_stashed_sort(int n) const;
INLINE int find_stashed(PandaNode *node) const;
INLINE const RenderState *get_state() const;
INLINE const RenderEffects *get_effects() const;
INLINE const TransformState *get_transform() const;
INLINE const TransformState *get_prev_transform() const;
INLINE string get_tag(const string &key) const;
INLINE bool has_tag(const string &key) const;
INLINE CollideMask get_net_collide_mask() const;
INLINE CPT(RenderAttrib) get_off_clip_planes() const;
INLINE CPT(BoundingVolume) get_bounds() const;
INLINE bool is_final() const;
INLINE PandaNode::Children get_children() const;
INLINE PandaNode::Stashed get_stashed() const;
INLINE PandaNode::Parents get_parents() const;
private:
const PandaNode *_object;
Thread *_current_thread;
const PandaNode::CData *_cdata;
};
INLINE ostream &operator << (ostream &out, const PandaNode &node) {

View File

@ -253,6 +253,8 @@ has_cull_callback() const {
////////////////////////////////////////////////////////////////////
bool PortalNode::
cull_callback(CullTraverser *trav, CullTraverserData &data) {
Thread *current_thread = trav->get_current_thread();
PortalClipper *portal_viewer = trav->get_portal_clipper();
set_visible(false);
if (is_open() && !_cell_out.is_empty() && portal_viewer) {
@ -312,7 +314,8 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
CullTraverserData next_data(_cell_out,
cell_transform,
next_state, new_bh, NULL);
next_state, new_bh, NULL,
current_thread);
// data._state, new_bh, NULL);
// Make this cell show with the reduced frustum