show_through()

This commit is contained in:
David Rose 2006-03-20 20:48:26 +00:00
parent 21727aca0c
commit 725e82e6f4
37 changed files with 656 additions and 127 deletions

View File

@ -47,7 +47,7 @@ CollisionNode(const string &name) :
_collide_geom(false) _collide_geom(false)
{ {
// CollisionNodes are hidden by default. // CollisionNodes are hidden by default.
set_draw_mask(DrawMask::all_off()); set_overall_hidden(true);
// CollisionNodes have a certain set of bits on by default. // CollisionNodes have a certain set of bits on by default.
set_into_collide_mask(get_default_collide_mask()); set_into_collide_mask(get_default_collide_mask());
@ -262,6 +262,21 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
return true; return true;
} }
////////////////////////////////////////////////////////////////////
// Function: CollisionNode::is_renderable
// Access: Public, Virtual
// Description: Returns true if there is some value to visiting this
// particular node during the cull traversal for any
// camera, false otherwise. This will be used to
// optimize the result of get_net_draw_show_mask(), so
// that any subtrees that contain only nodes for which
// is_renderable() is false need not be visited.
////////////////////////////////////////////////////////////////////
bool CollisionNode::
is_renderable() const {
return true;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: CollisionNode::output // Function: CollisionNode::output

View File

@ -51,6 +51,7 @@ public:
virtual bool has_cull_callback() const; virtual bool has_cull_callback() const;
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
virtual bool is_renderable() const;
virtual void output(ostream &out) const; virtual void output(ostream &out) const;

View File

@ -82,9 +82,6 @@ ConfigVariableBool egg_rigid_geometry
"geometry has to be vertex-animated, but there will tend to be " "geometry has to be vertex-animated, but there will tend to be "
"more separate pieces.")); "more separate pieces."));
ConfigVariableBool egg_show_collision_solids
("egg-show-collision-solids", false);
ConfigVariableBool egg_load_old_curves ConfigVariableBool egg_load_old_curves
("egg-load-old-curves", true, ("egg-load-old-curves", true,
PRC_DESC("When this is true, a <NurbsCurve> entry appearing in an egg file " PRC_DESC("When this is true, a <NurbsCurve> entry appearing in an egg file "

View File

@ -45,7 +45,6 @@ extern EXPCL_PANDAEGG ConfigVariableBool egg_unify;
extern EXPCL_PANDAEGG ConfigVariableDouble egg_flatten_radius; extern EXPCL_PANDAEGG ConfigVariableDouble egg_flatten_radius;
extern EXPCL_PANDAEGG ConfigVariableBool egg_combine_geoms; extern EXPCL_PANDAEGG ConfigVariableBool egg_combine_geoms;
extern EXPCL_PANDAEGG ConfigVariableBool egg_rigid_geometry; extern EXPCL_PANDAEGG ConfigVariableBool egg_rigid_geometry;
extern EXPCL_PANDAEGG ConfigVariableBool egg_show_collision_solids;
extern EXPCL_PANDAEGG ConfigVariableBool egg_load_old_curves; extern EXPCL_PANDAEGG ConfigVariableBool egg_load_old_curves;
extern EXPCL_PANDAEGG ConfigVariableBool egg_load_classic_nurbs_curves; extern EXPCL_PANDAEGG ConfigVariableBool egg_load_classic_nurbs_curves;
extern EXPCL_PANDAEGG ConfigVariableBool egg_accept_errors; extern EXPCL_PANDAEGG ConfigVariableBool egg_accept_errors;

View File

@ -1596,10 +1596,6 @@ make_node(EggGroup *egg_group, PandaNode *parent) {
} }
node = create_group_arc(egg_group, parent, node); node = create_group_arc(egg_group, parent, node);
if (!egg_show_collision_solids) {
node->set_draw_mask(DrawMask::all_off());
}
return node; return node;
} else if (egg_group->get_portal_flag()) { } else if (egg_group->get_portal_flag()) {

View File

@ -107,6 +107,9 @@ get_display_region(int n) const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE void Camera:: INLINE void Camera::
set_camera_mask(DrawMask mask) { set_camera_mask(DrawMask mask) {
// You shouldn't attempt to use Panda's reserved "overall" bit as a
// camera mask.
nassertv((mask & PandaNode::get_overall_bit()).is_zero());
_camera_mask = mask; _camera_mask = mask;
} }

View File

@ -32,7 +32,7 @@ Camera::
Camera(const string &name) : Camera(const string &name) :
LensNode(name), LensNode(name),
_active(true), _active(true),
_camera_mask(DrawMask::all_on()), _camera_mask(~PandaNode::get_overall_bit()),
_initial_state(RenderState::make_empty()) _initial_state(RenderState::make_empty())
{ {
} }

View File

@ -152,7 +152,9 @@ traverse(CullTraverserData &data) {
if (data.is_in_view(_camera_mask)) { if (data.is_in_view(_camera_mask)) {
if (pgraph_cat.is_spam()) { if (pgraph_cat.is_spam()) {
pgraph_cat.spam() << "\n" << data._node_path << "\n"; pgraph_cat.spam()
<< "\n" << data._node_path
<< " " << data._draw_mask << "\n";
} }
PandaNode *node = data.node(); PandaNode *node = data.node();
@ -189,29 +191,33 @@ traverse(CullTraverserData &data) {
// Function: CullTraverser::traverse_below // Function: CullTraverser::traverse_below
// Access: Public // Access: Public
// Description: Traverses all the children of the indicated node, // Description: Traverses all the children of the indicated node,
// with the given data, which been converted into the // with the given data, which has been converted into
// node's space. // the node's space.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void CullTraverser:: void CullTraverser::
traverse_below(CullTraverserData &data) { traverse_below(CullTraverserData &data) {
_nodes_pcollector.add_level(1); _nodes_pcollector.add_level(1);
PandaNode *node = data.node(); PandaNode *node = data.node();
bool visible = !(data._draw_mask & PandaNode::get_overall_bit()).is_zero() &&
!(data._draw_mask & _camera_mask).is_zero();
const RenderEffects *node_effects = node->get_effects(); const RenderEffects *node_effects = node->get_effects();
bool has_decal = node_effects->has_decal(); bool has_decal = visible && node_effects->has_decal();
if (has_decal && !_depth_offset_decals) { if (has_decal && !_depth_offset_decals) {
// Start the three-pass decal rendering if we're not using // Start the three-pass decal rendering if we're not using
// DepthOffsetAttribs to implement decals. // DepthOffsetAttribs to implement decals.
start_decal(data); start_decal(data);
} else { } else {
if (node->is_geom_node()) { if (visible && node->is_geom_node()) {
_geom_nodes_pcollector.add_level(1); _geom_nodes_pcollector.add_level(1);
GeomNode *geom_node = DCAST(GeomNode, node); GeomNode *geom_node = DCAST(GeomNode, node);
if (pgraph_cat.is_spam()) { if (pgraph_cat.is_spam()) {
pgraph_cat.spam() pgraph_cat.spam()
<< "Found " << *geom_node << " in state " << *data._state << "\n"; << "Found " << *geom_node << " in state " << *data._state
<< " draw_mask = " << data._draw_mask << "\n";
} }
// Get all the Geoms, with no decalling. // Get all the Geoms, with no decalling.

View File

@ -32,7 +32,8 @@ CullTraverserData(const NodePath &start,
_state(state), _state(state),
_view_frustum(view_frustum), _view_frustum(view_frustum),
_guard_band(guard_band), _guard_band(guard_band),
_cull_planes(CullPlanes::make_empty()) _cull_planes(CullPlanes::make_empty()),
_draw_mask(DrawMask::all_on())
{ {
} }
@ -48,7 +49,8 @@ CullTraverserData(const CullTraverserData &copy) :
_state(copy._state), _state(copy._state),
_view_frustum(copy._view_frustum), _view_frustum(copy._view_frustum),
_guard_band(copy._guard_band), _guard_band(copy._guard_band),
_cull_planes(copy._cull_planes) _cull_planes(copy._cull_planes),
_draw_mask(copy._draw_mask)
{ {
} }
@ -65,6 +67,7 @@ operator = (const CullTraverserData &copy) {
_view_frustum = copy._view_frustum; _view_frustum = copy._view_frustum;
_guard_band = copy._guard_band; _guard_band = copy._guard_band;
_cull_planes = copy._cull_planes; _cull_planes = copy._cull_planes;
_draw_mask = copy._draw_mask;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -80,7 +83,8 @@ CullTraverserData(const CullTraverserData &parent, PandaNode *child) :
_state(parent._state), _state(parent._state),
_view_frustum(parent._view_frustum), _view_frustum(parent._view_frustum),
_guard_band(parent._guard_band), _guard_band(parent._guard_band),
_cull_planes(parent._cull_planes) _cull_planes(parent._cull_planes),
_draw_mask(parent._draw_mask)
{ {
} }
@ -130,7 +134,7 @@ is_in_view(const DrawMask &camera_mask) {
return false; return false;
} }
if ((node()->get_draw_mask() & camera_mask).is_zero()) { if (!node()->compare_draw_mask(_draw_mask, camera_mask)) {
// If there are no draw bits in common with the camera, the node // If there are no draw bits in common with the camera, the node
// is out. // is out.
return false; return false;
@ -146,29 +150,3 @@ is_in_view(const DrawMask &camera_mask) {
// Otherwise, compare the bounding volume to the frustum. // Otherwise, compare the bounding volume to the frustum.
return is_in_view_impl(); return is_in_view_impl();
} }
////////////////////////////////////////////////////////////////////
// Function: CullTraverserData::test_within_clip_planes
// Access: Public
// Description: Returns the BoundingVolume intersection bits
// appropriate for the intersection of the current clip
// planes with the current node.
//
// That is, if the current node is within all clip
// planes (and will not be clipped at all), returns
// BoundingVolume::IF_all. If it is completely behind
// at least one clip plane, returns
// BoundingVolume::IF_intersection. If it is partially
// behind one or more clip planes, returns
// BoundingVolume::IF_some.
////////////////////////////////////////////////////////////////////
INLINE int CullTraverserData::
test_within_clip_planes(const CullTraverser *trav) const {
const ClipPlaneAttrib *cpa = _state->get_clip_plane();
if (cpa != (ClipPlaneAttrib *)NULL) {
return test_within_clip_planes_impl(trav, cpa);
}
// No clip plane attrib; therefore, the node is not clipped at
// all.
return BoundingVolume::IF_all | BoundingVolume::IF_possible | BoundingVolume::IF_some;
}

View File

@ -62,6 +62,7 @@ apply_transform_and_state(CullTraverser *trav) {
string tag_state = node->get_tag(trav->get_tag_state_key()); string tag_state = node->get_tag(trav->get_tag_state_key());
node_state = node_state->compose(camera->get_tag_state(tag_state)); node_state = node_state->compose(camera->get_tag_state(tag_state));
} }
node->compose_draw_mask(_draw_mask);
apply_transform_and_state(trav, node->get_transform(), apply_transform_and_state(trav, node->get_transform(),
node_state, node->get_effects(), node_state, node->get_effects(),

View File

@ -64,7 +64,6 @@ public:
CPT(TransformState) get_net_transform(const CullTraverser *trav) const; CPT(TransformState) get_net_transform(const CullTraverser *trav) const;
INLINE bool is_in_view(const DrawMask &camera_mask); INLINE bool is_in_view(const DrawMask &camera_mask);
INLINE int test_within_clip_planes(const CullTraverser *trav) const;
void apply_transform_and_state(CullTraverser *trav); void apply_transform_and_state(CullTraverser *trav);
void apply_transform_and_state(CullTraverser *trav, void apply_transform_and_state(CullTraverser *trav,
@ -79,6 +78,7 @@ public:
PT(GeometricBoundingVolume) _view_frustum; PT(GeometricBoundingVolume) _view_frustum;
PT(GeometricBoundingVolume) _guard_band; PT(GeometricBoundingVolume) _guard_band;
CPT(CullPlanes) _cull_planes; CPT(CullPlanes) _cull_planes;
DrawMask _draw_mask;
private: private:
bool is_in_view_impl(); bool is_in_view_impl();

View File

@ -149,8 +149,7 @@ consider_node(NodePathCollection &result, FindApproxLevelEntry *&next_level,
void FindApproxLevelEntry:: void FindApproxLevelEntry::
consider_next_step(PandaNode *child_node, FindApproxLevelEntry *&next_level, consider_next_step(PandaNode *child_node, FindApproxLevelEntry *&next_level,
int increment) const { int increment) const {
if (!_approx_path.return_hidden() && if (!_approx_path.return_hidden() && child_node->is_overall_hidden()) {
child_node->get_draw_mask().is_zero()) {
// If the approx path does not allow us to return hidden nodes, // If the approx path does not allow us to return hidden nodes,
// and this node has indeed been completely hidden, then stop // and this node has indeed been completely hidden, then stop
// here. // here.

View File

@ -363,6 +363,21 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any,
return next_transform; return next_transform;
} }
////////////////////////////////////////////////////////////////////
// Function: GeomNode::is_renderable
// Access: Public, Virtual
// Description: Returns true if there is some value to visiting this
// particular node during the cull traversal for any
// camera, false otherwise. This will be used to
// optimize the result of get_net_draw_show_mask(), so
// that any subtrees that contain only nodes for which
// is_renderable() is false need not be visited.
////////////////////////////////////////////////////////////////////
bool GeomNode::
is_renderable() const {
return true;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: GeomNode::get_legal_collide_mask // Function: GeomNode::get_legal_collide_mask
// Access: Published, Virtual // Access: Published, Virtual

View File

@ -53,6 +53,7 @@ public:
calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point,
bool &found_any, bool &found_any,
const TransformState *transform) const; const TransformState *transform) const;
virtual bool is_renderable() const;
virtual CollideMask get_legal_collide_mask() const; virtual CollideMask get_legal_collide_mask() const;
PUBLISHED: PUBLISHED:

View File

@ -1884,11 +1884,14 @@ adjust_all_priorities(int adjustment) {
// Description: Undoes the effect of a previous hide() on this node: // Description: Undoes the effect of a previous hide() on this node:
// makes the referenced node (and the entire subgraph // makes the referenced node (and the entire subgraph
// below this node) visible to all cameras. // below this node) visible to all cameras.
//
// This will not reveal the node if a parent node has
// been hidden.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE void NodePath:: INLINE void NodePath::
show() { show() {
nassertv_always(!is_empty()); nassertv_always(!is_empty());
node()->set_draw_mask(DrawMask::all_on()); node()->adjust_draw_mask(DrawMask::all_off(), DrawMask::all_off(), PandaNode::get_overall_bit());
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1896,13 +1899,52 @@ show() {
// Access: Published // Access: Published
// Description: Makes the referenced node visible just to the // Description: Makes the referenced node visible just to the
// cameras whose camera_mask shares the indicated bits. // cameras whose camera_mask shares the indicated bits.
// That is, this sets the indicated bits in the //
// node's draw mask. // This undoes the effect of a previous hide() call. It
// will not reveal the node if a parent node has been
// hidden. However, see show_through().
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE void NodePath:: INLINE void NodePath::
show(DrawMask camera_mask) { show(DrawMask camera_mask) {
nassertv_always(!is_empty()); nassertv_always(!is_empty());
node()->set_draw_mask(node()->get_draw_mask() | camera_mask); camera_mask &= ~PandaNode::get_overall_bit();
node()->adjust_draw_mask(DrawMask::all_off(), DrawMask::all_off(), camera_mask);
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::show_through
// Access: Published
// Description: Makes the referenced node visible just to the
// cameras whose camera_mask shares the indicated bits.
//
// Unlike show(), this will reveal the node even if a
// parent node has been hidden, thus "showing through" a
// parent's hide().
////////////////////////////////////////////////////////////////////
INLINE void NodePath::
show_through() {
nassertv_always(!is_empty());
node()->adjust_draw_mask(PandaNode::get_overall_bit(), DrawMask::all_off(), DrawMask::all_off());
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::show_through
// Access: Published
// Description: Makes the referenced node visible just to the
// cameras whose camera_mask shares the indicated bits.
//
// Unlike show(), this will reveal the node even if a
// parent node has been hidden via the one-parameter
// hide() method, thus "showing through" a parent's
// hide(). (However, it will not show through a
// parent's hide() call if the no-parameter form of
// hide() was used.)
////////////////////////////////////////////////////////////////////
INLINE void NodePath::
show_through(DrawMask camera_mask) {
nassertv_always(!is_empty());
camera_mask &= ~PandaNode::get_overall_bit();
node()->adjust_draw_mask(camera_mask, DrawMask::all_off(), DrawMask::all_off());
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1917,7 +1959,7 @@ show(DrawMask camera_mask) {
INLINE void NodePath:: INLINE void NodePath::
hide() { hide() {
nassertv_always(!is_empty()); nassertv_always(!is_empty());
node()->set_draw_mask(DrawMask::all_off()); node()->adjust_draw_mask(DrawMask::all_off(), PandaNode::get_overall_bit(), DrawMask::all_off());
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1925,13 +1967,17 @@ hide() {
// Access: Published // Access: Published
// Description: Makes the referenced node invisible just to the // Description: Makes the referenced node invisible just to the
// cameras whose camera_mask shares the indicated bits. // cameras whose camera_mask shares the indicated bits.
// That is, this clears the indicated bits from the //
// node's draw mask. // This will also hide any nodes below this node in the
// scene graph, including those nodes for which show()
// has been called, but it will not hide descendent
// nodes for which show_through() has been called.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE void NodePath:: INLINE void NodePath::
hide(DrawMask camera_mask) { hide(DrawMask camera_mask) {
nassertv_always(!is_empty()); nassertv_always(!is_empty());
node()->set_draw_mask(node()->get_draw_mask() & ~camera_mask); camera_mask &= ~PandaNode::get_overall_bit();
node()->adjust_draw_mask(DrawMask::all_off(), camera_mask, DrawMask::all_off());
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -5154,7 +5154,8 @@ get_hidden_ancestor(DrawMask camera_mask) const {
comp != (NodePathComponent *)NULL; comp != (NodePathComponent *)NULL;
comp = comp->get_next(pipeline_stage)) { comp = comp->get_next(pipeline_stage)) {
PandaNode *node = comp->get_node(); PandaNode *node = comp->get_node();
if ((node->get_draw_mask() & camera_mask).is_zero()) { if (node->is_overall_hidden() ||
((node->get_draw_show_mask() | ~node->get_draw_control_mask()) & camera_mask).is_zero()) {
NodePath result; NodePath result;
result._head = comp; result._head = comp;
return result; return result;

View File

@ -738,10 +738,12 @@ PUBLISHED:
// Variants on show and hide // Variants on show and hide
INLINE void show(); INLINE void show();
INLINE void show(DrawMask camera_mask); INLINE void show(DrawMask camera_mask);
INLINE void show_through();
INLINE void show_through(DrawMask camera_mask);
INLINE void hide(); INLINE void hide();
INLINE void hide(DrawMask camera_mask); INLINE void hide(DrawMask camera_mask);
INLINE bool is_hidden(DrawMask camera_mask = DrawMask::all_on()) const; INLINE bool is_hidden(DrawMask camera_mask = PandaNode::get_overall_bit()) const;
NodePath get_hidden_ancestor(DrawMask camera_mask = DrawMask::all_on()) const; NodePath get_hidden_ancestor(DrawMask camera_mask = PandaNode::get_overall_bit()) const;
void stash(int sort = 0); void stash(int sort = 0);
void unstash(int sort = 0); void unstash(int sort = 0);

View File

@ -17,6 +17,63 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: PandaNode::compose_draw_mask
// Access: Public
// Description: Computes the result of applying this node's draw
// masks to a running draw mask, as during a traversal.
////////////////////////////////////////////////////////////////////
INLINE void PandaNode::
compose_draw_mask(DrawMask &running_draw_mask) const {
CDHeavyReader cdata(_cycler_heavy);
running_draw_mask = (running_draw_mask & ~cdata->_draw_control_mask) |
(cdata->_draw_show_mask & cdata->_draw_control_mask);
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::compare_draw_mask
// Access: Public
// Description: Compares the running draw mask computed during a
// traversal with this node's net draw masks. Returns
// true if the node should be traversed into, or false
// if there is nothing at this level or below that will
// be visible to the indicated camera_mask.
////////////////////////////////////////////////////////////////////
INLINE bool PandaNode::
compare_draw_mask(DrawMask running_draw_mask, DrawMask camera_mask) const {
DrawMask net_draw_control_mask, net_draw_show_mask;
int pipeline_stage = Thread::get_current_pipeline_stage();
CDBoundsStageReader cdata(_cycler_bounds, pipeline_stage);
if (cdata->_last_update != cdata->_next_update) {
// The cache is stale; it needs to be rebuilt.
CDBoundsStageWriter cdataw =
((PandaNode *)this)->update_bounds(pipeline_stage, cdata);
net_draw_control_mask = cdataw->_net_draw_control_mask;
net_draw_show_mask = cdataw->_net_draw_show_mask;
} else {
net_draw_control_mask = cdata->_net_draw_control_mask;
net_draw_show_mask = cdata->_net_draw_show_mask;
}
// Now the bits that are not in net_draw_control_mask--that is,
// those bits that are not changed by any of the nodes at this level
// and below--are taken from running_draw_mask, which is inherited
// from above. On the other hand, the bits that *are* in
// net_draw_control_mask--those bits that are changed by any of the
// nodes at this level and below--are taken from net_draw_show_mask,
// which is propagated upwards from below.
// This way, we will traverse into this node if it has any children
// which want to be visited by the traversal, but we will avoid
// traversing into it if all of its children are hidden to this
// camera.
DrawMask compare_mask = (running_draw_mask & ~net_draw_control_mask) | (net_draw_show_mask & net_draw_control_mask);
return !((compare_mask & _overall_bit).is_zero()) && !((compare_mask & camera_mask).is_zero());
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PandaNode::get_num_parents // Function: PandaNode::get_num_parents
// Access: Published // Access: Published
@ -431,15 +488,75 @@ ls(ostream &out, int indent_level) const {
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PandaNode::get_draw_mask // Function: PandaNode::get_overall_bit
// Access: Published // Access: Published, Static
// Description: Returns the hide/show bits of this particular node. // Description: Returns the special bit that, when specifically
// See set_draw_mask(). // cleared in the node's DrawMask, indicates that the
// node is hidden to all cameras, regardless of the
// remaining DrawMask bits.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE DrawMask PandaNode:: INLINE DrawMask PandaNode::
get_draw_mask() const { get_overall_bit() {
return _overall_bit;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::is_overall_hidden
// Access: Published, Static
// Description: Returns true if the node has been hidden to all
// cameras by clearing its overall bit.
////////////////////////////////////////////////////////////////////
INLINE bool PandaNode::
is_overall_hidden() const {
CDHeavyReader cdata(_cycler_heavy); CDHeavyReader cdata(_cycler_heavy);
return cdata->_draw_mask; return ((cdata->_draw_show_mask | ~cdata->_draw_control_mask) & _overall_bit).is_zero();
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::set_overall_hidden
// Access: Published
// Description: Sets or clears the hidden flag. When the hidden flag
// is true, the node and all of its children are
// invisible to all cameras, regardless of the setting
// of any draw masks. Setting the hidden flag to false
// restores the previous visibility as established by
// the draw masks.
//
// This actually works by twiddling the reserved
// _overall_bit in the node's draw mask, which has
// special meaning.
////////////////////////////////////////////////////////////////////
INLINE void PandaNode::
set_overall_hidden(bool hidden) {
if (hidden) {
adjust_draw_mask(DrawMask::all_off(), _overall_bit, DrawMask::all_off());
} else {
adjust_draw_mask(DrawMask::all_off(), DrawMask::all_off(), _overall_bit);
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::get_draw_control_mask
// Access: Published
// Description: Returns the set of bits in draw_show_mask that are
// considered meaningful. See adjust_draw_mask().
////////////////////////////////////////////////////////////////////
INLINE DrawMask PandaNode::
get_draw_control_mask() const {
CDHeavyReader cdata(_cycler_heavy);
return cdata->_draw_control_mask;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::get_draw_show_mask
// Access: Published
// Description: Returns the hide/show bits of this particular node.
// See adjust_draw_mask().
////////////////////////////////////////////////////////////////////
INLINE DrawMask PandaNode::
get_draw_show_mask() const {
CDHeavyReader cdata(_cycler_heavy);
return cdata->_draw_show_mask;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -791,7 +908,8 @@ CDataLight() {
INLINE PandaNode::CDataHeavy:: INLINE PandaNode::CDataHeavy::
CDataHeavy() { CDataHeavy() {
_effects = RenderEffects::make_empty(); _effects = RenderEffects::make_empty();
_draw_mask = DrawMask::all_on(); _draw_control_mask = DrawMask::all_off();
_draw_show_mask = DrawMask::all_on();
_into_collide_mask = CollideMask::all_off(); _into_collide_mask = CollideMask::all_off();
_user_bounds = NULL; _user_bounds = NULL;
_internal_bounds = NULL; _internal_bounds = NULL;
@ -807,6 +925,8 @@ CDataHeavy() {
INLINE PandaNode::CDataBounds:: INLINE PandaNode::CDataBounds::
CDataBounds() { CDataBounds() {
_net_collide_mask = CollideMask::all_off(); _net_collide_mask = CollideMask::all_off();
_net_draw_control_mask = DrawMask::all_off();
_net_draw_show_mask = DrawMask::all_off();
++_next_update; ++_next_update;
} }

View File

@ -28,6 +28,11 @@
#include "clipPlaneAttrib.h" #include "clipPlaneAttrib.h"
#include "boundingSphere.h" #include "boundingSphere.h"
// This category is just temporary for debugging convenience.
NotifyCategoryDecl(drawmask, EXPCL_PANDA, EXPTP_PANDA);
NotifyCategoryDef(drawmask, "");
DrawMask PandaNode::_overall_bit = DrawMask::bit(31);
TypeHandle PandaNode::_type_handle; TypeHandle PandaNode::_type_handle;
// //
@ -132,7 +137,8 @@ PandaNode(const PandaNode &copy) :
CDHeavyWriter cdata(_cycler_heavy); CDHeavyWriter cdata(_cycler_heavy);
cdata->_effects = copy_cdata->_effects; cdata->_effects = copy_cdata->_effects;
cdata->_tag_data = copy_cdata->_tag_data; cdata->_tag_data = copy_cdata->_tag_data;
cdata->_draw_mask = copy_cdata->_draw_mask; cdata->_draw_control_mask = copy_cdata->_draw_control_mask;
cdata->_draw_show_mask = copy_cdata->_draw_show_mask;
cdata->_into_collide_mask = copy_cdata->_into_collide_mask; cdata->_into_collide_mask = copy_cdata->_into_collide_mask;
cdata->_user_bounds = copy_cdata->_user_bounds; cdata->_user_bounds = copy_cdata->_user_bounds;
cdata->_internal_bounds = NULL; cdata->_internal_bounds = NULL;
@ -507,6 +513,21 @@ get_visible_child() const {
return 0; return 0;
} }
////////////////////////////////////////////////////////////////////
// Function: PandaNode::is_renderable
// Access: Public, Virtual
// Description: Returns true if there is some value to visiting this
// particular node during the cull traversal for any
// camera, false otherwise. This will be used to
// optimize the result of get_net_draw_show_mask(), so
// that any subtrees that contain only nodes for which
// is_renderable() is false need not be visited.
////////////////////////////////////////////////////////////////////
bool PandaNode::
is_renderable() const {
return false;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PandaNode::copy_subgraph // Function: PandaNode::copy_subgraph
// Access: Published // Access: Published
@ -1380,36 +1401,124 @@ list_tags(ostream &out, const string &separator) const {
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PandaNode::set_draw_mask // Function: PandaNode::adjust_draw_mask
// Access: Published // Access: Published
// Description: Sets the hide/show bits of this particular node. // Description: Adjusts the hide/show bits of this particular node.
// //
// During the cull traversal, a node is not visited if // These three parameters can be used to adjust the
// none of its draw mask bits intersect with the // _draw_control_mask and _draw_show_mask independently,
// camera's draw mask bits. These masks can be used to // which work together to provide per-camera visibility
// selectively hide and show different parts of the // for the node and its descendents.
// scene graph from different cameras that are otherwise //
// viewing the same scene. See // _draw_control_mask indicates the bits in
// Camera::set_camera_mask(). // _draw_show_mask that are significant. Each different
// bit corresponds to a different camera (and these bits
// are assigned via Camera::set_camera_mask()).
//
// Where _draw_control_mask has a 1 bit, a 1 bit in
// _draw_show_mask indicates the node is visible to that
// camera, and a 0 bit indicates the node is hidden to
// that camera. Where _draw_control_mask is 0, the node
// is hidden only if a parent node is hidden.
//
// The meaning of the three parameters is as follows:
//
// * Wherever show_mask is 1, _draw_show_mask and
// _draw_control_mask will be set 1. Thus, show_mask
// indicates the set of cameras to which the node should
// be shown.
//
// * Wherever hide_mask is 1, _draw_show_mask will be
// set 0 and _draw_control_mask will be set 1. Thus,
// hide_mask indicates the set of cameras from which the
// node should be hidden.
//
// * Wherever clear_mask is 1, _draw_control_mask will
// be set 0. Thus, clear_mask indicates the set of
// cameras from which the hidden state should be
// inherited from a parent.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void PandaNode:: void PandaNode::
set_draw_mask(DrawMask mask) { adjust_draw_mask(DrawMask show_mask, DrawMask hide_mask, DrawMask clear_mask) {
bool any_changed = false; bool any_changed = false;
OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy) { OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy) {
CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage); CDHeavyStageWriter cdata(_cycler_heavy, pipeline_stage);
if (cdata->_draw_mask != mask) {
cdata->_draw_mask = mask; DrawMask draw_control_mask = (cdata->_draw_control_mask | show_mask | hide_mask) & ~clear_mask;
DrawMask draw_show_mask = (cdata->_draw_show_mask | show_mask) & ~hide_mask;
// The uncontrolled bits are implicitly on.
draw_show_mask |= ~draw_control_mask;
if (cdata->_draw_control_mask != draw_control_mask ||
cdata->_draw_show_mask != draw_show_mask) {
cdata->_draw_control_mask = draw_control_mask;
cdata->_draw_show_mask = draw_show_mask;
any_changed = true; any_changed = true;
} }
} }
CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy); CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy);
if (any_changed) { if (any_changed) {
mark_bounds_stale();
draw_mask_changed(); draw_mask_changed();
} }
} }
////////////////////////////////////////////////////////////////////
// Function: PandaNode::get_net_draw_control_mask
// Access: Published
// Description: Returns the set of bits in get_net_draw_show_mask()
// that have been explicitly set via adjust_draw_mask(),
// rather than implicitly inherited.
//
// A 1 bit in any position of this mask indicates that
// (a) this node has renderable children, and (b) some
// child of this node has made an explicit hide() or
// show_through() call for the corresponding bit.
////////////////////////////////////////////////////////////////////
DrawMask PandaNode::
get_net_draw_control_mask() const {
int pipeline_stage = Thread::get_current_pipeline_stage();
CDBoundsStageReader cdata(_cycler_bounds, pipeline_stage);
if (cdata->_last_update != cdata->_next_update) {
// The cache is stale; it needs to be rebuilt.
CDBoundsStageWriter cdataw =
((PandaNode *)this)->update_bounds(pipeline_stage, cdata);
return cdataw->_net_draw_control_mask;
}
return cdata->_net_draw_control_mask;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::get_net_draw_show_mask
// Access: Published
// Description: Returns the union of all draw_show_mask values--of
// renderable nodes only--at this level and below. If
// any bit in this mask is 0, there is no reason to
// traverse below this node for a camera with the
// corresponding camera_mask.
//
// The bits in this mask that do not correspond to a 1
// bit in the net_draw_control_mask are meaningless (and
// will be set to 1). For bits that *do* correspond to
// a 1 bit in the net_draw_control_mask, a 1 bit
// indicates that at least one child should be visible,
// while a 0 bit indicates that all children are hidden.
////////////////////////////////////////////////////////////////////
DrawMask PandaNode::
get_net_draw_show_mask() const {
int pipeline_stage = Thread::get_current_pipeline_stage();
CDBoundsStageReader cdata(_cycler_bounds, pipeline_stage);
if (cdata->_last_update != cdata->_next_update) {
// The cache is stale; it needs to be rebuilt.
CDBoundsStageWriter cdataw =
((PandaNode *)this)->update_bounds(pipeline_stage, cdata);
return cdataw->_net_draw_show_mask;
}
return cdata->_net_draw_show_mask;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PandaNode::set_into_collide_mask // Function: PandaNode::set_into_collide_mask
// Access: Published // Access: Published
@ -1536,6 +1645,26 @@ write(ostream &out, int indent_level) const {
if (!effects->is_empty()) { if (!effects->is_empty()) {
out << " " << *effects; out << " " << *effects;
} }
DrawMask draw_control_mask = get_draw_control_mask();
if (!draw_control_mask.is_zero()) {
DrawMask draw_show_mask = get_draw_show_mask();
if (!(draw_control_mask & _overall_bit).is_zero()) {
if (!(draw_show_mask & _overall_bit).is_zero()) {
out << " (show_through)";
} else {
out << " (hidden)";
}
}
if (!(draw_control_mask & ~_overall_bit).is_zero()) {
draw_control_mask &= ~_overall_bit;
if (!(draw_show_mask & draw_control_mask).is_zero()) {
out << " (per-camera show_through)";
}
if (!(~draw_show_mask & draw_control_mask).is_zero()) {
out << " (per-camera hidden)";
}
}
}
out << "\n"; out << "\n";
} }
@ -2633,6 +2762,10 @@ PandaNode::CDBoundsStageWriter PandaNode::
update_bounds(int pipeline_stage, PandaNode::CDBoundsStageReader &cdata) { update_bounds(int pipeline_stage, PandaNode::CDBoundsStageReader &cdata) {
// We might need to try this a couple of times, in case someone else // We might need to try this a couple of times, in case someone else
// steps on our result. // steps on our result.
if (drawmask_cat.is_debug()) {
drawmask_cat.debug(false)
<< *this << "::update_bounds() {\n";
}
do { do {
// Grab the last_update counter, then release the lock. // Grab the last_update counter, then release the lock.
UpdateSeq last_update = cdata->_last_update; UpdateSeq last_update = cdata->_last_update;
@ -2643,9 +2776,32 @@ update_bounds(int pipeline_stage, PandaNode::CDBoundsStageReader &cdata) {
// Start with a clean slate, or at least with the contents of the // Start with a clean slate, or at least with the contents of the
// node itself. // node itself.
CollideMask net_collide_mask; CollideMask net_collide_mask;
DrawMask net_draw_control_mask, net_draw_show_mask;
DrawMask draw_control_mask, draw_show_mask;
bool renderable = is_renderable();
{ {
CDHeavyStageReader cdata(_cycler_heavy, pipeline_stage); CDHeavyStageReader cdata(_cycler_heavy, pipeline_stage);
net_collide_mask = cdata->_into_collide_mask; net_collide_mask = cdata->_into_collide_mask;
draw_control_mask = net_draw_control_mask = cdata->_draw_control_mask;
draw_show_mask = net_draw_show_mask = cdata->_draw_show_mask;
}
if (!renderable) {
// This is not a "renderable" node. This means that this node
// does not itself contribute any bits to net_draw_show_mask or
// net_draw_control_mask, but it may contribute some bits to any
// renderable nodes from below.
net_draw_show_mask = DrawMask::all_off();
net_draw_control_mask = DrawMask::all_off();
}
draw_show_mask |= ~draw_control_mask;
if (drawmask_cat.is_debug()) {
drawmask_cat.debug(false)
<< "net_draw_control_mask = " << net_draw_control_mask
<< "\nnet_draw_show_mask = " << net_draw_show_mask
<< "\ndraw_control_mask = " << draw_control_mask
<< "\ndraw_show_mask = " << draw_show_mask
<< "\n";
} }
CPT(RenderAttrib) off_clip_planes; CPT(RenderAttrib) off_clip_planes;
{ {
@ -2683,6 +2839,37 @@ update_bounds(int pipeline_stage, PandaNode::CDBoundsStageReader &cdata) {
CDBoundsStageWriter child_cdataw = child->update_bounds(pipeline_stage, child_cdata); CDBoundsStageWriter child_cdataw = child->update_bounds(pipeline_stage, child_cdata);
net_collide_mask |= child_cdataw->_net_collide_mask; net_collide_mask |= child_cdataw->_net_collide_mask;
DrawMask child_control_mask = child_cdataw->_net_draw_control_mask;
DrawMask child_show_mask = child_cdataw->_net_draw_show_mask;
if (child_control_mask != DrawMask::all_off() ||
child_show_mask != DrawMask::all_off()) {
// This child includes a renderable node or subtree. Thus,
// we should propagate its draw masks.
renderable = true;
// Compute the set of control bits that are defined on this
// node, but not on the child node.
DrawMask new_control_mask = draw_control_mask & ~child_control_mask;
// Anywhere we have a control bit that our child does not,
// the child inherits our show bit.
DrawMask new_child_show_mask = (child_show_mask & ~new_control_mask) | (draw_show_mask & new_control_mask);
DrawMask new_child_control_mask = child_control_mask | new_control_mask;
// Now merge that result with our accumulated draw masks.
net_draw_control_mask |= new_child_control_mask;
net_draw_show_mask |= new_child_show_mask;
}
if (drawmask_cat.is_debug()) {
drawmask_cat.debug(false)
<< "\nchild update " << *child << ":\n"
<< "child_control_mask = " << child_control_mask
<< "\nchild_show_mask = " << child_show_mask
<< "\nnet_draw_control_mask = " << net_draw_control_mask
<< "\nnet_draw_show_mask = " << net_draw_show_mask
<< "\n";
}
off_clip_planes = orig_cp->compose_off(child_cdataw->_off_clip_planes); off_clip_planes = orig_cp->compose_off(child_cdataw->_off_clip_planes);
child_volumes_ref.push_back(child_cdataw->_external_bounds); child_volumes_ref.push_back(child_cdataw->_external_bounds);
child_volumes.push_back(child_cdataw->_external_bounds); child_volumes.push_back(child_cdataw->_external_bounds);
@ -2690,12 +2877,43 @@ update_bounds(int pipeline_stage, PandaNode::CDBoundsStageReader &cdata) {
} else { } else {
// Child is good. // Child is good.
net_collide_mask |= child_cdata->_net_collide_mask; net_collide_mask |= child_cdata->_net_collide_mask;
// See comments in similar block above.
DrawMask child_control_mask = child_cdata->_net_draw_control_mask;
DrawMask child_show_mask = child_cdata->_net_draw_show_mask;
if (child_control_mask != DrawMask::all_off() ||
child_show_mask != DrawMask::all_off()) {
renderable = true;
DrawMask new_control_mask = draw_control_mask & ~child_control_mask;
DrawMask new_child_show_mask = (child_show_mask & ~new_control_mask) | (draw_show_mask & new_control_mask);
DrawMask new_child_control_mask = child_control_mask | new_control_mask;
net_draw_control_mask |= new_child_control_mask;
net_draw_show_mask |= new_child_show_mask;
}
if (drawmask_cat.is_debug()) {
drawmask_cat.debug(false)
<< "\nchild fresh " << *child << ":\n"
<< "child_control_mask = " << child_control_mask
<< "\nchild_show_mask = " << child_show_mask
<< "\nnet_draw_control_mask = " << net_draw_control_mask
<< "\nnet_draw_show_mask = " << net_draw_show_mask
<< "\n";
}
off_clip_planes = orig_cp->compose_off(child_cdata->_off_clip_planes); off_clip_planes = orig_cp->compose_off(child_cdata->_off_clip_planes);
child_volumes_ref.push_back(child_cdata->_external_bounds); child_volumes_ref.push_back(child_cdata->_external_bounds);
child_volumes.push_back(child_cdata->_external_bounds); child_volumes.push_back(child_cdata->_external_bounds);
} }
} }
if (renderable) {
// This is a "renderable" node. That means all draw_show_mask
// bits, not specifically set on or off, should be assumed to be
// on.
net_draw_show_mask |= ~net_draw_control_mask;
}
{ {
// Now grab the write lock on this node. // Now grab the write lock on this node.
CDBoundsStageWriter cdataw(_cycler_bounds, pipeline_stage); CDBoundsStageWriter cdataw(_cycler_bounds, pipeline_stage);
@ -2704,6 +2922,27 @@ update_bounds(int pipeline_stage, PandaNode::CDBoundsStageReader &cdata) {
// Great, no one has monkeyed with these while we were computing // Great, no one has monkeyed with these while we were computing
// the cache. Safe to store the computed values and return. // the cache. Safe to store the computed values and return.
cdataw->_net_collide_mask = net_collide_mask; cdataw->_net_collide_mask = net_collide_mask;
if (renderable) {
// There are renderable nodes below, so the implicit draw
// bits are all on.
cdataw->_net_draw_control_mask = net_draw_control_mask;
cdataw->_net_draw_show_mask = net_draw_show_mask | ~net_draw_control_mask;
if (drawmask_cat.is_debug()) {
drawmask_cat.debug(false)
<< "renderable, set mask " << cdataw->_net_draw_show_mask << "\n";
}
} else {
// There are no renderable nodes below, so the implicit draw
// bits are all off.
cdataw->_net_draw_control_mask = net_draw_control_mask;
cdataw->_net_draw_show_mask = net_draw_show_mask;
if (drawmask_cat.is_debug()) {
drawmask_cat.debug(false)
<< "not renderable, set mask " << cdataw->_net_draw_show_mask << "\n";
}
}
cdataw->_off_clip_planes = off_clip_planes; cdataw->_off_clip_planes = off_clip_planes;
// Compute the bounding sphere around all of our child // Compute the bounding sphere around all of our child
@ -2722,6 +2961,11 @@ update_bounds(int pipeline_stage, PandaNode::CDBoundsStageReader &cdata) {
cdataw->_external_bounds = gbv; cdataw->_external_bounds = gbv;
cdataw->_last_update = next_update; cdataw->_last_update = next_update;
if (drawmask_cat.is_debug()) {
drawmask_cat.debug(false)
<< "} " << *this << "::update_bounds();\n";
}
return cdataw; return cdataw;
} }
@ -2946,7 +3190,8 @@ PandaNode::CDataHeavy::
CDataHeavy(const PandaNode::CDataHeavy &copy) : CDataHeavy(const PandaNode::CDataHeavy &copy) :
_effects(copy._effects), _effects(copy._effects),
_tag_data(copy._tag_data), _tag_data(copy._tag_data),
_draw_mask(copy._draw_mask), _draw_control_mask(copy._draw_control_mask),
_draw_show_mask(copy._draw_show_mask),
_into_collide_mask(copy._into_collide_mask), _into_collide_mask(copy._into_collide_mask),
_user_bounds(copy._user_bounds), _user_bounds(copy._user_bounds),
_internal_bounds(copy._internal_bounds), _internal_bounds(copy._internal_bounds),
@ -2998,7 +3243,8 @@ void PandaNode::CDataHeavy::
write_datagram(BamWriter *manager, Datagram &dg) const { write_datagram(BamWriter *manager, Datagram &dg) const {
manager->write_pointer(dg, _effects); manager->write_pointer(dg, _effects);
dg.add_uint32(_draw_mask.get_word()); dg.add_uint32(_draw_control_mask.get_word());
dg.add_uint32(_draw_show_mask.get_word());
dg.add_uint32(_into_collide_mask.get_word()); dg.add_uint32(_into_collide_mask.get_word());
dg.add_uint32(_tag_data.size()); dg.add_uint32(_tag_data.size());
@ -3048,7 +3294,32 @@ fillin(DatagramIterator &scan, BamReader *manager) {
// Read the effects pointer. // Read the effects pointer.
manager->read_pointer(scan); manager->read_pointer(scan);
_draw_mask.set_word(scan.get_uint32()); if (manager->get_file_minor_ver() < 2) {
DrawMask draw_mask;
draw_mask.set_word(scan.get_uint32());
if (draw_mask == DrawMask::all_off()) {
// Hidden.
_draw_control_mask = _overall_bit;
_draw_show_mask = ~_overall_bit;
} else if (draw_mask == DrawMask::all_on()) {
// Normally visible.
_draw_control_mask = DrawMask::all_off();
_draw_show_mask = DrawMask::all_on();
} else {
// Some per-camera combination.
draw_mask &= ~_overall_bit;
_draw_control_mask = ~draw_mask;
_draw_show_mask = draw_mask;
}
} else {
_draw_control_mask.set_word(scan.get_uint32());
_draw_show_mask.set_word(scan.get_uint32());
}
_into_collide_mask.set_word(scan.get_uint32()); _into_collide_mask.set_word(scan.get_uint32());
// Read in the tag list. // Read in the tag list.
@ -3106,6 +3377,8 @@ dec_py_refs() {
PandaNode::CDataBounds:: PandaNode::CDataBounds::
CDataBounds(const PandaNode::CDataBounds &copy) : CDataBounds(const PandaNode::CDataBounds &copy) :
_net_collide_mask(copy._net_collide_mask), _net_collide_mask(copy._net_collide_mask),
_net_draw_control_mask(copy._net_draw_control_mask),
_net_draw_show_mask(copy._net_draw_show_mask),
_off_clip_planes(copy._off_clip_planes), _off_clip_planes(copy._off_clip_planes),
_external_bounds(copy._external_bounds), _external_bounds(copy._external_bounds),
_last_update(copy._last_update), _last_update(copy._last_update),

View File

@ -103,6 +103,11 @@ public:
virtual int get_next_visible_child(int n) const; virtual int get_next_visible_child(int n) const;
virtual bool has_single_child_visibility() const; virtual bool has_single_child_visibility() const;
virtual int get_visible_child() const; virtual int get_visible_child() const;
virtual bool is_renderable() const;
INLINE void compose_draw_mask(DrawMask &running_draw_mask) const;
INLINE bool compare_draw_mask(DrawMask running_draw_mask,
DrawMask camera_mask) const;
PUBLISHED: PUBLISHED:
PT(PandaNode) copy_subgraph() const; PT(PandaNode) copy_subgraph() const;
@ -180,8 +185,18 @@ PUBLISHED:
void copy_tags(PandaNode *other); void copy_tags(PandaNode *other);
void list_tags(ostream &out, const string &separator = "\n") const; void list_tags(ostream &out, const string &separator = "\n") const;
void set_draw_mask(DrawMask mask); INLINE static DrawMask get_overall_bit();
INLINE DrawMask get_draw_mask() const; INLINE bool is_overall_hidden() const;
INLINE void set_overall_hidden(bool overall_hidden);
void adjust_draw_mask(DrawMask show_mask,
DrawMask hide_mask,
DrawMask clear_mask);
INLINE DrawMask get_draw_control_mask() const;
INLINE DrawMask get_draw_show_mask() const;
CollideMask get_net_draw_control_mask() const;
CollideMask get_net_draw_show_mask() const;
void set_into_collide_mask(CollideMask mask); void set_into_collide_mask(CollideMask mask);
INLINE CollideMask get_into_collide_mask() const; INLINE CollideMask get_into_collide_mask() const;
@ -406,8 +421,9 @@ private:
PythonTagData _python_tag_data; PythonTagData _python_tag_data;
#endif // HAVE_PYTHON #endif // HAVE_PYTHON
// This is the draw_mask of this particular node. // These two together determine the per-camera visibility of this
DrawMask _draw_mask; // node. See adjust_draw_mask() for details.
DrawMask _draw_control_mask, _draw_show_mask;
// This is the mask that indicates which CollisionNodes may detect // This is the mask that indicates which CollisionNodes may detect
// a collision with this particular node. By default it is zero // a collision with this particular node. By default it is zero
@ -453,14 +469,15 @@ private:
} }
// This is the union of all into_collide_mask bits for any nodes // This is the union of all into_collide_mask bits for any nodes
// at and below this level. It's updated automatically whenever // at and below this level.
// _stale_bounds is true.
CollideMask _net_collide_mask; CollideMask _net_collide_mask;
// These are similar, for the draw mask.
DrawMask _net_draw_control_mask, _net_draw_show_mask;
// This is a ClipPlaneAttrib that represents the union of all clip // This is a ClipPlaneAttrib that represents the union of all clip
// planes that have been turned *off* at and below this level. We // planes that have been turned *off* at and below this level.
// piggyback this automatic update on _stale_bounds. TODO: // TODO: fix the circular reference counts involved here.
// fix the circular reference counts involved here.
CPT(RenderAttrib) _off_clip_planes; CPT(RenderAttrib) _off_clip_planes;
// This is the bounding volume around the _user_bounds, the // This is the bounding volume around the _user_bounds, the
@ -521,6 +538,8 @@ private:
CDBoundsStageWriter update_bounds(int pipeline_stage, CDBoundsStageWriter update_bounds(int pipeline_stage,
CDBoundsStageReader &cdata); CDBoundsStageReader &cdata);
static DrawMask _overall_bit;
public: public:
// This class is returned from get_children_copy(). Use it to walk // This class is returned from get_children_copy(). Use it to walk
// through the list of children, particularly with a self-modifying // through the list of children, particularly with a self-modifying

View File

@ -78,7 +78,7 @@ PlaneNode(const string &name, const Planef &plane) :
_priority(0) _priority(0)
{ {
// PlaneNodes are hidden by default. // PlaneNodes are hidden by default.
set_draw_mask(DrawMask::all_off()); set_overall_hidden(true);
set_plane(plane); set_plane(plane);
} }
@ -183,6 +183,21 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
return true; return true;
} }
////////////////////////////////////////////////////////////////////
// Function: PlaneNode::is_renderable
// Access: Public, Virtual
// Description: Returns true if there is some value to visiting this
// particular node during the cull traversal for any
// camera, false otherwise. This will be used to
// optimize the result of get_net_draw_show_mask(), so
// that any subtrees that contain only nodes for which
// is_renderable() is false need not be visited.
////////////////////////////////////////////////////////////////////
bool PlaneNode::
is_renderable() const {
return true;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PlaneNode::compute_internal_bounds // Function: PlaneNode::compute_internal_bounds
// Access: Protected, Virtual // Access: Protected, Virtual

View File

@ -53,6 +53,7 @@ public:
virtual bool has_cull_callback() const; virtual bool has_cull_callback() const;
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
virtual bool is_renderable() const;
PUBLISHED: PUBLISHED:
INLINE void set_plane(const Planef &plane); INLINE void set_plane(const Planef &plane);

View File

@ -334,6 +334,21 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
return true; return true;
} }
////////////////////////////////////////////////////////////////////
// Function: PortalNode::is_renderable
// Access: Public, Virtual
// Description: Returns true if there is some value to visiting this
// particular node during the cull traversal for any
// camera, false otherwise. This will be used to
// optimize the result of get_net_draw_show_mask(), so
// that any subtrees that contain only nodes for which
// is_renderable() is false need not be visited.
////////////////////////////////////////////////////////////////////
bool PortalNode::
is_renderable() const {
return true;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PortalNode::output // Function: PortalNode::output

View File

@ -60,6 +60,7 @@ public:
virtual bool has_cull_callback() const; virtual bool has_cull_callback() const;
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
virtual bool is_renderable() const;
virtual void output(ostream &out) const; virtual void output(ostream &out) const;

View File

@ -343,8 +343,11 @@ operator () (const PandaNode *node1, const PandaNode *node2) const {
if (node1->get_effects() != node2->get_effects()) { if (node1->get_effects() != node2->get_effects()) {
return node1->get_effects() < node2->get_effects(); return node1->get_effects() < node2->get_effects();
} }
if (node1->get_draw_mask() != node2->get_draw_mask()) { if (node1->get_draw_control_mask() != node2->get_draw_control_mask()) {
return node1->get_draw_mask() < node2->get_draw_mask(); return node1->get_draw_control_mask() < node2->get_draw_control_mask();
}
if (node1->get_draw_show_mask() != node2->get_draw_show_mask()) {
return node1->get_draw_show_mask() < node2->get_draw_show_mask();
} }
return 0; return 0;
@ -452,7 +455,8 @@ consider_child(PandaNode *grandparent_node, PandaNode *parent_node,
if (parent_node->get_transform() != child_node->get_transform() || if (parent_node->get_transform() != child_node->get_transform() ||
parent_node->get_state() != child_node->get_state() || parent_node->get_state() != child_node->get_state() ||
parent_node->get_effects() != child_node->get_effects() || parent_node->get_effects() != child_node->get_effects() ||
parent_node->get_draw_mask() != child_node->get_draw_mask()) { parent_node->get_draw_control_mask() != child_node->get_draw_control_mask() ||
parent_node->get_draw_show_mask() != child_node->get_draw_show_mask()) {
// The two nodes have a different state; too bad. // The two nodes have a different state; too bad.
return false; return false;
} }

View File

@ -252,6 +252,21 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
return true; return true;
} }
////////////////////////////////////////////////////////////////////
// Function: PGItem::is_renderable
// Access: Public, Virtual
// Description: Returns true if there is some value to visiting this
// particular node during the cull traversal for any
// camera, false otherwise. This will be used to
// optimize the result of get_net_draw_show_mask(), so
// that any subtrees that contain only nodes for which
// is_renderable() is false need not be visited.
////////////////////////////////////////////////////////////////////
bool PGItem::
is_renderable() const {
return true;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: PGItem::compute_internal_bounds // Function: PGItem::compute_internal_bounds
// Access: Protected, Virtual // Access: Protected, Virtual
@ -1025,7 +1040,7 @@ play_sound(const string &event) {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
void PGItem:: void PGItem::
reduce_region(LVecBase4f &frame, PGItem *obscurer) const { reduce_region(LVecBase4f &frame, PGItem *obscurer) const {
if (obscurer != (PGItem *)NULL && !obscurer->get_draw_mask().is_zero()) { if (obscurer != (PGItem *)NULL && !obscurer->is_overall_hidden()) {
LVecBase4f oframe = get_relative_frame(obscurer); LVecBase4f oframe = get_relative_frame(obscurer);
// Determine the four rectangular regions on the four sides of the // Determine the four rectangular regions on the four sides of the

View File

@ -67,6 +67,7 @@ protected:
virtual bool has_cull_callback() const; virtual bool has_cull_callback() const;
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
virtual bool is_renderable() const;
virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const; virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const;

View File

@ -267,18 +267,18 @@ remanage() {
// Now show or hide the sliders appropriately. // Now show or hide the sliders appropriately.
if (_horizontal_slider != (PGSliderBar *)NULL) { if (_horizontal_slider != (PGSliderBar *)NULL) {
if (got_horizontal) { if (got_horizontal) {
_horizontal_slider->set_draw_mask(DrawMask::all_on()); _horizontal_slider->set_overall_hidden(false);
} else { } else {
_horizontal_slider->set_draw_mask(DrawMask::all_off()); _horizontal_slider->set_overall_hidden(true);
_horizontal_slider->set_ratio(0.0f); _horizontal_slider->set_ratio(0.0f);
horizontal_width = 0.0f; horizontal_width = 0.0f;
} }
} }
if (_vertical_slider != (PGSliderBar *)NULL) { if (_vertical_slider != (PGSliderBar *)NULL) {
if (got_vertical) { if (got_vertical) {
_vertical_slider->set_draw_mask(DrawMask::all_on()); _vertical_slider->set_overall_hidden(false);
} else { } else {
_vertical_slider->set_draw_mask(DrawMask::all_off()); _vertical_slider->set_overall_hidden(true);
_vertical_slider->set_ratio(0.0f); _vertical_slider->set_ratio(0.0f);
vertical_width = 0.0f; vertical_width = 0.0f;
} }
@ -288,14 +288,14 @@ remanage() {
// flag again indirectly; we clear it again to avoid a feedback // flag again indirectly; we clear it again to avoid a feedback
// loop. // loop.
_needs_remanage = false; _needs_remanage = false;
} }
// Are either or both of the scroll bars hidden? // Are either or both of the scroll bars hidden?
if (got_horizontal && _horizontal_slider->get_draw_mask().is_zero()) { if (got_horizontal && _horizontal_slider->is_overall_hidden()) {
got_horizontal = false; got_horizontal = false;
horizontal_width = 0.0f; horizontal_width = 0.0f;
} }
if (got_vertical && _vertical_slider->get_draw_mask().is_zero()) { if (got_vertical && _vertical_slider->is_overall_hidden()) {
got_vertical = false; got_vertical = false;
vertical_width = 0.0f; vertical_width = 0.0f;
} }

View File

@ -36,8 +36,9 @@ static const unsigned short _bam_major_ver = 6;
// Bumped to major version 5 on 5/6/05 for new Geom implementation. // Bumped to major version 5 on 5/6/05 for new Geom implementation.
// Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData. // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
static const unsigned short _bam_minor_ver = 1; static const unsigned short _bam_minor_ver = 2;
// Bumped to minor version 1 on 3/12/06 to add Texture::_compression. // Bumped to minor version 1 on 3/12/06 to add Texture::_compression.
// Bumped to minor version 2 on 3/17/06 to add PandaNode::_draw_control_mask.
#endif #endif

View File

@ -57,10 +57,11 @@ BitArray(const BitArray &copy) :
// Access: Published // Access: Published
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE void BitArray:: INLINE BitArray &BitArray::
operator = (const BitArray &copy) { operator = (const BitArray &copy) {
_array = copy._array; _array = copy._array;
_highest_bits = copy._highest_bits; _highest_bits = copy._highest_bits;
return *this;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -47,7 +47,7 @@ PUBLISHED:
INLINE BitArray(); INLINE BitArray();
INLINE BitArray(WordType init_value); INLINE BitArray(WordType init_value);
INLINE BitArray(const BitArray &copy); INLINE BitArray(const BitArray &copy);
INLINE void operator = (const BitArray &copy); INLINE BitArray &operator = (const BitArray &copy);
INLINE static BitArray all_on(); INLINE static BitArray all_on();
INLINE static BitArray all_off(); INLINE static BitArray all_off();

View File

@ -61,9 +61,10 @@ BitMask(const BitMask<WType, nbits> &copy) :
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
template<class WType, int nbits> template<class WType, int nbits>
INLINE void BitMask<WType, nbits>:: INLINE BitMask<WType, nbits> &BitMask<WType, nbits>::
operator = (const BitMask<WType, nbits> &copy) { operator = (const BitMask<WType, nbits> &copy) {
_word = copy._word; _word = copy._word;
return *this;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////

View File

@ -44,7 +44,7 @@ PUBLISHED:
INLINE BitMask(); INLINE BitMask();
INLINE BitMask(WordType init_value); INLINE BitMask(WordType init_value);
INLINE BitMask(const BitMask<WType, nbits> &copy); INLINE BitMask(const BitMask<WType, nbits> &copy);
INLINE void operator = (const BitMask<WType, nbits> &copy); INLINE BitMask<WType, nbits> &operator = (const BitMask<WType, nbits> &copy);
INLINE static BitMask<WType, nbits> all_on(); INLINE static BitMask<WType, nbits> all_on();
INLINE static BitMask<WType, nbits> all_off(); INLINE static BitMask<WType, nbits> all_off();

View File

@ -194,24 +194,10 @@ write(ostream &out, int indent_level) const {
indent(out, indent_level) indent(out, indent_level)
<< "TextNode " << get_name() << "\n"; << "TextNode " << get_name() << "\n";
TextProperties::write(out, indent_level + 2); TextProperties::write(out, indent_level + 2);
out << "\n";
LVecBase3f scale, shear, hpr, trans;
if (decompose_matrix(_transform, scale, shear, hpr, trans, _coordinate_system)) {
indent(out, indent_level + 2) indent(out, indent_level + 2)
<< "transform is:\n" << "transform is: " << *TransformState::make_mat(_transform) << "\n";
<< " scale: " << scale << "\n"
<< " shear: " << shear << "\n"
<< " hpr: " << hpr << "\n"
<< " trans: " << hpr << "\n";
} else {
indent(out, indent_level + 2)
<< "transform is:\n" << _transform;
}
indent(out, indent_level + 2) indent(out, indent_level + 2)
<< "in coordinate system " << _coordinate_system << "\n"; << "in coordinate system " << _coordinate_system << "\n";
out << "\n";
indent(out, indent_level + 2) indent(out, indent_level + 2)
<< "text is " << get_text() << "\n"; << "text is " << get_text() << "\n";
} }
@ -569,6 +555,21 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) {
return true; return true;
} }
////////////////////////////////////////////////////////////////////
// Function: TextNode::is_renderable
// Access: Public, Virtual
// Description: Returns true if there is some value to visiting this
// particular node during the cull traversal for any
// camera, false otherwise. This will be used to
// optimize the result of get_net_draw_show_mask(), so
// that any subtrees that contain only nodes for which
// is_renderable() is false need not be visited.
////////////////////////////////////////////////////////////////////
bool TextNode::
is_renderable() const {
return true;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::compute_internal_bound // Function: TextNode::compute_internal_bound
// Access: Protected, Virtual // Access: Protected, Virtual

View File

@ -236,6 +236,7 @@ public:
virtual bool has_cull_callback() const; virtual bool has_cull_callback() const;
virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data);
virtual bool is_renderable() const;
virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const; virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const;

View File

@ -1029,7 +1029,7 @@ set_no_mouse() {
if (_has_mouse) { if (_has_mouse) {
// Hide the mouse pointer. // Hide the mouse pointer.
if (!_geometry.is_null()) { if (!_geometry.is_null()) {
_geometry->set_draw_mask(DrawMask::all_off()); _geometry->set_overall_hidden(true);
} }
} }
@ -1053,7 +1053,7 @@ set_mouse(const LVecBase2f &xy, const LVecBase2f &pixel_xy) {
_geometry->set_transform(TransformState::make_pos(LVecBase3f(xy[0], 0, xy[1]))); _geometry->set_transform(TransformState::make_pos(LVecBase3f(xy[0], 0, xy[1])));
if (!_has_mouse) { if (!_has_mouse) {
// Show the mouse pointer. // Show the mouse pointer.
_geometry->set_draw_mask(DrawMask::all_on()); _geometry->set_overall_hidden(false);
} }
} }

View File

@ -396,7 +396,7 @@ bool BamToEgg::
apply_node_properties(EggGroup *egg_group, PandaNode *node) { apply_node_properties(EggGroup *egg_group, PandaNode *node) {
bool any_applied = false; bool any_applied = false;
if (node->get_draw_mask().is_zero()) { if (node->is_overall_hidden()) {
// This node is hidden. We'll go ahead and convert it, but we'll // This node is hidden. We'll go ahead and convert it, but we'll
// put in the "backstage" flag to mean it's not real geometry. // put in the "backstage" flag to mean it's not real geometry.
egg_group->add_object_type("backstage"); egg_group->add_object_type("backstage");