From 725e82e6f465d0cabc7ec1a3f70f77817f1e2f1e Mon Sep 17 00:00:00 2001 From: David Rose Date: Mon, 20 Mar 2006 20:48:26 +0000 Subject: [PATCH] show_through() --- panda/src/collide/collisionNode.cxx | 17 +- panda/src/collide/collisionNode.h | 1 + panda/src/egg2pg/config_egg2pg.cxx | 3 - panda/src/egg2pg/config_egg2pg.h | 1 - panda/src/egg2pg/eggLoader.cxx | 4 - panda/src/pgraph/camera.I | 3 + panda/src/pgraph/camera.cxx | 2 +- panda/src/pgraph/cullTraverser.cxx | 18 +- panda/src/pgraph/cullTraverserData.I | 38 +-- panda/src/pgraph/cullTraverserData.cxx | 1 + panda/src/pgraph/cullTraverserData.h | 2 +- panda/src/pgraph/findApproxLevelEntry.cxx | 3 +- panda/src/pgraph/geomNode.cxx | 15 ++ panda/src/pgraph/geomNode.h | 1 + panda/src/pgraph/nodePath.I | 62 ++++- panda/src/pgraph/nodePath.cxx | 3 +- panda/src/pgraph/nodePath.h | 6 +- panda/src/pgraph/pandaNode.I | 134 +++++++++- panda/src/pgraph/pandaNode.cxx | 305 ++++++++++++++++++++-- panda/src/pgraph/pandaNode.h | 37 ++- panda/src/pgraph/planeNode.cxx | 17 +- panda/src/pgraph/planeNode.h | 1 + panda/src/pgraph/portalNode.cxx | 15 ++ panda/src/pgraph/portalNode.h | 1 + panda/src/pgraph/sceneGraphReducer.cxx | 10 +- panda/src/pgui/pgItem.cxx | 17 +- panda/src/pgui/pgItem.h | 1 + panda/src/pgui/pgScrollFrame.cxx | 14 +- panda/src/putil/bam.h | 3 +- panda/src/putil/bitArray.I | 3 +- panda/src/putil/bitArray.h | 2 +- panda/src/putil/bitMask.I | 3 +- panda/src/putil/bitMask.h | 2 +- panda/src/text/textNode.cxx | 31 +-- panda/src/text/textNode.h | 1 + panda/src/tform/mouseWatcher.cxx | 4 +- pandatool/src/bam/bamToEgg.cxx | 2 +- 37 files changed, 656 insertions(+), 127 deletions(-) diff --git a/panda/src/collide/collisionNode.cxx b/panda/src/collide/collisionNode.cxx index 388ba39723..625f70a5b5 100644 --- a/panda/src/collide/collisionNode.cxx +++ b/panda/src/collide/collisionNode.cxx @@ -47,7 +47,7 @@ CollisionNode(const string &name) : _collide_geom(false) { // 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. set_into_collide_mask(get_default_collide_mask()); @@ -262,6 +262,21 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { 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 diff --git a/panda/src/collide/collisionNode.h b/panda/src/collide/collisionNode.h index c8ce6e5ba8..1937fedf86 100644 --- a/panda/src/collide/collisionNode.h +++ b/panda/src/collide/collisionNode.h @@ -51,6 +51,7 @@ public: virtual bool has_cull_callback() const; virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); + virtual bool is_renderable() const; virtual void output(ostream &out) const; diff --git a/panda/src/egg2pg/config_egg2pg.cxx b/panda/src/egg2pg/config_egg2pg.cxx index 051a6aba96..d1d7084e51 100644 --- a/panda/src/egg2pg/config_egg2pg.cxx +++ b/panda/src/egg2pg/config_egg2pg.cxx @@ -82,9 +82,6 @@ ConfigVariableBool egg_rigid_geometry "geometry has to be vertex-animated, but there will tend to be " "more separate pieces.")); -ConfigVariableBool egg_show_collision_solids -("egg-show-collision-solids", false); - ConfigVariableBool egg_load_old_curves ("egg-load-old-curves", true, PRC_DESC("When this is true, a entry appearing in an egg file " diff --git a/panda/src/egg2pg/config_egg2pg.h b/panda/src/egg2pg/config_egg2pg.h index 311348613d..b628f145f7 100644 --- a/panda/src/egg2pg/config_egg2pg.h +++ b/panda/src/egg2pg/config_egg2pg.h @@ -45,7 +45,6 @@ extern EXPCL_PANDAEGG ConfigVariableBool egg_unify; extern EXPCL_PANDAEGG ConfigVariableDouble egg_flatten_radius; extern EXPCL_PANDAEGG ConfigVariableBool egg_combine_geoms; 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_classic_nurbs_curves; extern EXPCL_PANDAEGG ConfigVariableBool egg_accept_errors; diff --git a/panda/src/egg2pg/eggLoader.cxx b/panda/src/egg2pg/eggLoader.cxx index fa91cba260..7591c0af0d 100644 --- a/panda/src/egg2pg/eggLoader.cxx +++ b/panda/src/egg2pg/eggLoader.cxx @@ -1596,10 +1596,6 @@ make_node(EggGroup *egg_group, PandaNode *parent) { } node = create_group_arc(egg_group, parent, node); - - if (!egg_show_collision_solids) { - node->set_draw_mask(DrawMask::all_off()); - } return node; } else if (egg_group->get_portal_flag()) { diff --git a/panda/src/pgraph/camera.I b/panda/src/pgraph/camera.I index 1a131b7dd6..11ffb96086 100644 --- a/panda/src/pgraph/camera.I +++ b/panda/src/pgraph/camera.I @@ -107,6 +107,9 @@ get_display_region(int n) const { //////////////////////////////////////////////////////////////////// INLINE void Camera:: 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; } diff --git a/panda/src/pgraph/camera.cxx b/panda/src/pgraph/camera.cxx index 56a168cc71..4fb23d478e 100644 --- a/panda/src/pgraph/camera.cxx +++ b/panda/src/pgraph/camera.cxx @@ -32,7 +32,7 @@ Camera:: Camera(const string &name) : LensNode(name), _active(true), - _camera_mask(DrawMask::all_on()), + _camera_mask(~PandaNode::get_overall_bit()), _initial_state(RenderState::make_empty()) { } diff --git a/panda/src/pgraph/cullTraverser.cxx b/panda/src/pgraph/cullTraverser.cxx index c542a093d3..3da3ce5c3a 100644 --- a/panda/src/pgraph/cullTraverser.cxx +++ b/panda/src/pgraph/cullTraverser.cxx @@ -152,7 +152,9 @@ traverse(CullTraverserData &data) { if (data.is_in_view(_camera_mask)) { 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(); @@ -189,29 +191,33 @@ traverse(CullTraverserData &data) { // Function: CullTraverser::traverse_below // Access: Public // Description: Traverses all the children of the indicated node, -// with the given data, which been converted into the -// node's space. +// with the given data, which has been converted into +// the node's space. //////////////////////////////////////////////////////////////////// void CullTraverser:: traverse_below(CullTraverserData &data) { _nodes_pcollector.add_level(1); 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(); - bool has_decal = node_effects->has_decal(); + bool has_decal = visible && node_effects->has_decal(); if (has_decal && !_depth_offset_decals) { // Start the three-pass decal rendering if we're not using // DepthOffsetAttribs to implement decals. start_decal(data); } else { - if (node->is_geom_node()) { + if (visible && node->is_geom_node()) { _geom_nodes_pcollector.add_level(1); GeomNode *geom_node = DCAST(GeomNode, node); if (pgraph_cat.is_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. diff --git a/panda/src/pgraph/cullTraverserData.I b/panda/src/pgraph/cullTraverserData.I index 2111d455f7..c112e212a1 100644 --- a/panda/src/pgraph/cullTraverserData.I +++ b/panda/src/pgraph/cullTraverserData.I @@ -32,7 +32,8 @@ CullTraverserData(const NodePath &start, _state(state), _view_frustum(view_frustum), _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 ©) : _state(copy._state), _view_frustum(copy._view_frustum), _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 ©) { _view_frustum = copy._view_frustum; _guard_band = copy._guard_band; _cull_planes = copy._cull_planes; + _draw_mask = copy._draw_mask; } //////////////////////////////////////////////////////////////////// @@ -80,7 +83,8 @@ CullTraverserData(const CullTraverserData &parent, PandaNode *child) : _state(parent._state), _view_frustum(parent._view_frustum), _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; } - 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 // is out. return false; @@ -146,29 +150,3 @@ is_in_view(const DrawMask &camera_mask) { // Otherwise, compare the bounding volume to the frustum. 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; -} diff --git a/panda/src/pgraph/cullTraverserData.cxx b/panda/src/pgraph/cullTraverserData.cxx index af0bd416ec..d02a0b3b76 100644 --- a/panda/src/pgraph/cullTraverserData.cxx +++ b/panda/src/pgraph/cullTraverserData.cxx @@ -62,6 +62,7 @@ apply_transform_and_state(CullTraverser *trav) { string tag_state = node->get_tag(trav->get_tag_state_key()); 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(), node_state, node->get_effects(), diff --git a/panda/src/pgraph/cullTraverserData.h b/panda/src/pgraph/cullTraverserData.h index 85fc92c97c..c210678f05 100644 --- a/panda/src/pgraph/cullTraverserData.h +++ b/panda/src/pgraph/cullTraverserData.h @@ -64,7 +64,6 @@ public: CPT(TransformState) get_net_transform(const CullTraverser *trav) const; 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, @@ -79,6 +78,7 @@ public: PT(GeometricBoundingVolume) _view_frustum; PT(GeometricBoundingVolume) _guard_band; CPT(CullPlanes) _cull_planes; + DrawMask _draw_mask; private: bool is_in_view_impl(); diff --git a/panda/src/pgraph/findApproxLevelEntry.cxx b/panda/src/pgraph/findApproxLevelEntry.cxx index adbfc2fbda..ac49608040 100644 --- a/panda/src/pgraph/findApproxLevelEntry.cxx +++ b/panda/src/pgraph/findApproxLevelEntry.cxx @@ -149,8 +149,7 @@ consider_node(NodePathCollection &result, FindApproxLevelEntry *&next_level, void FindApproxLevelEntry:: consider_next_step(PandaNode *child_node, FindApproxLevelEntry *&next_level, int increment) const { - if (!_approx_path.return_hidden() && - child_node->get_draw_mask().is_zero()) { + if (!_approx_path.return_hidden() && child_node->is_overall_hidden()) { // If the approx path does not allow us to return hidden nodes, // and this node has indeed been completely hidden, then stop // here. diff --git a/panda/src/pgraph/geomNode.cxx b/panda/src/pgraph/geomNode.cxx index 44663ea3cc..5aa272cbf1 100644 --- a/panda/src/pgraph/geomNode.cxx +++ b/panda/src/pgraph/geomNode.cxx @@ -363,6 +363,21 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any, 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 // Access: Published, Virtual diff --git a/panda/src/pgraph/geomNode.h b/panda/src/pgraph/geomNode.h index 5cc1ec4c6b..04281ddcb3 100644 --- a/panda/src/pgraph/geomNode.h +++ b/panda/src/pgraph/geomNode.h @@ -53,6 +53,7 @@ public: calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any, const TransformState *transform) const; + virtual bool is_renderable() const; virtual CollideMask get_legal_collide_mask() const; PUBLISHED: diff --git a/panda/src/pgraph/nodePath.I b/panda/src/pgraph/nodePath.I index 97d8a16d84..e16408079a 100644 --- a/panda/src/pgraph/nodePath.I +++ b/panda/src/pgraph/nodePath.I @@ -1884,11 +1884,14 @@ adjust_all_priorities(int adjustment) { // Description: Undoes the effect of a previous hide() on this node: // makes the referenced node (and the entire subgraph // below this node) visible to all cameras. +// +// This will not reveal the node if a parent node has +// been hidden. //////////////////////////////////////////////////////////////////// INLINE void NodePath:: show() { 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 // Description: Makes the referenced node visible just to the // 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:: show(DrawMask camera_mask) { 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:: hide() { 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 // Description: Makes the referenced node invisible just to the // 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:: hide(DrawMask camera_mask) { 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()); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index 61147f777e..5c9dd2c2ee 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -5154,7 +5154,8 @@ get_hidden_ancestor(DrawMask camera_mask) const { comp != (NodePathComponent *)NULL; comp = comp->get_next(pipeline_stage)) { 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; result._head = comp; return result; diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index 359172c857..734310730e 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -738,10 +738,12 @@ PUBLISHED: // Variants on show and hide INLINE void show(); INLINE void show(DrawMask camera_mask); + INLINE void show_through(); + INLINE void show_through(DrawMask camera_mask); INLINE void hide(); INLINE void hide(DrawMask camera_mask); - INLINE bool is_hidden(DrawMask camera_mask = DrawMask::all_on()) const; - NodePath get_hidden_ancestor(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 = PandaNode::get_overall_bit()) const; void stash(int sort = 0); void unstash(int sort = 0); diff --git a/panda/src/pgraph/pandaNode.I b/panda/src/pgraph/pandaNode.I index bebe6339c7..e8e5b7ae87 100644 --- a/panda/src/pgraph/pandaNode.I +++ b/panda/src/pgraph/pandaNode.I @@ -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 // Access: Published @@ -431,15 +488,75 @@ ls(ostream &out, int indent_level) const { } //////////////////////////////////////////////////////////////////// -// Function: PandaNode::get_draw_mask -// Access: Published -// Description: Returns the hide/show bits of this particular node. -// See set_draw_mask(). +// Function: PandaNode::get_overall_bit +// Access: Published, Static +// Description: Returns the special bit that, when specifically +// cleared in the node's DrawMask, indicates that the +// node is hidden to all cameras, regardless of the +// remaining DrawMask bits. //////////////////////////////////////////////////////////////////// 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); - 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:: CDataHeavy() { _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(); _user_bounds = NULL; _internal_bounds = NULL; @@ -807,6 +925,8 @@ CDataHeavy() { INLINE PandaNode::CDataBounds:: CDataBounds() { _net_collide_mask = CollideMask::all_off(); + _net_draw_control_mask = DrawMask::all_off(); + _net_draw_show_mask = DrawMask::all_off(); ++_next_update; } diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index ec746cd1cd..08e99ccc6a 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -28,6 +28,11 @@ #include "clipPlaneAttrib.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; // @@ -132,7 +137,8 @@ PandaNode(const PandaNode ©) : CDHeavyWriter cdata(_cycler_heavy); cdata->_effects = copy_cdata->_effects; 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->_user_bounds = copy_cdata->_user_bounds; cdata->_internal_bounds = NULL; @@ -507,6 +513,21 @@ get_visible_child() const { 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 // 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 -// 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 -// none of its draw mask bits intersect with the -// camera's draw mask bits. These masks can be used to -// selectively hide and show different parts of the -// scene graph from different cameras that are otherwise -// viewing the same scene. See -// Camera::set_camera_mask(). +// These three parameters can be used to adjust the +// _draw_control_mask and _draw_show_mask independently, +// which work together to provide per-camera visibility +// for the node and its descendents. +// +// _draw_control_mask indicates the bits in +// _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:: -set_draw_mask(DrawMask mask) { +adjust_draw_mask(DrawMask show_mask, DrawMask hide_mask, DrawMask clear_mask) { bool any_changed = false; OPEN_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy) { 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; } } CLOSE_ITERATE_CURRENT_AND_UPSTREAM(_cycler_heavy); if (any_changed) { + mark_bounds_stale(); 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 // Access: Published @@ -1536,6 +1645,26 @@ write(ostream &out, int indent_level) const { if (!effects->is_empty()) { 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"; } @@ -2633,6 +2762,10 @@ PandaNode::CDBoundsStageWriter PandaNode:: update_bounds(int pipeline_stage, PandaNode::CDBoundsStageReader &cdata) { // We might need to try this a couple of times, in case someone else // steps on our result. + if (drawmask_cat.is_debug()) { + drawmask_cat.debug(false) + << *this << "::update_bounds() {\n"; + } do { // Grab the last_update counter, then release the lock. 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 // node itself. 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); 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; { @@ -2683,6 +2839,37 @@ update_bounds(int pipeline_stage, PandaNode::CDBoundsStageReader &cdata) { CDBoundsStageWriter child_cdataw = child->update_bounds(pipeline_stage, child_cdata); 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); child_volumes_ref.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 { // Child is good. 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); child_volumes_ref.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. 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 // the cache. Safe to store the computed values and return. 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; // 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->_last_update = next_update; + + if (drawmask_cat.is_debug()) { + drawmask_cat.debug(false) + << "} " << *this << "::update_bounds();\n"; + } return cdataw; } @@ -2946,7 +3190,8 @@ PandaNode::CDataHeavy:: CDataHeavy(const PandaNode::CDataHeavy ©) : _effects(copy._effects), _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), _user_bounds(copy._user_bounds), _internal_bounds(copy._internal_bounds), @@ -2998,7 +3243,8 @@ void PandaNode::CDataHeavy:: write_datagram(BamWriter *manager, Datagram &dg) const { 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(_tag_data.size()); @@ -3048,7 +3294,32 @@ fillin(DatagramIterator &scan, BamReader *manager) { // Read the effects pointer. 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()); // Read in the tag list. @@ -3106,6 +3377,8 @@ dec_py_refs() { PandaNode::CDataBounds:: CDataBounds(const PandaNode::CDataBounds ©) : _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), _external_bounds(copy._external_bounds), _last_update(copy._last_update), diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index 7d149cdd7e..887fdfac1e 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -103,6 +103,11 @@ public: virtual int get_next_visible_child(int n) const; virtual bool has_single_child_visibility() 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: PT(PandaNode) copy_subgraph() const; @@ -180,8 +185,18 @@ PUBLISHED: void copy_tags(PandaNode *other); void list_tags(ostream &out, const string &separator = "\n") const; - void set_draw_mask(DrawMask mask); - INLINE DrawMask get_draw_mask() const; + INLINE static DrawMask get_overall_bit(); + 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); INLINE CollideMask get_into_collide_mask() const; @@ -406,8 +421,9 @@ private: PythonTagData _python_tag_data; #endif // HAVE_PYTHON - // This is the draw_mask of this particular node. - DrawMask _draw_mask; + // These two together determine the per-camera visibility of this + // node. See adjust_draw_mask() for details. + DrawMask _draw_control_mask, _draw_show_mask; // This is the mask that indicates which CollisionNodes may detect // 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 - // at and below this level. It's updated automatically whenever - // _stale_bounds is true. + // at and below this level. 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 - // planes that have been turned *off* at and below this level. We - // piggyback this automatic update on _stale_bounds. TODO: - // fix the circular reference counts involved here. + // planes that have been turned *off* at and below this level. + // TODO: fix the circular reference counts involved here. CPT(RenderAttrib) _off_clip_planes; // This is the bounding volume around the _user_bounds, the @@ -521,6 +538,8 @@ private: CDBoundsStageWriter update_bounds(int pipeline_stage, CDBoundsStageReader &cdata); + static DrawMask _overall_bit; + public: // This class is returned from get_children_copy(). Use it to walk // through the list of children, particularly with a self-modifying diff --git a/panda/src/pgraph/planeNode.cxx b/panda/src/pgraph/planeNode.cxx index 38b662030f..f8bd10bda5 100644 --- a/panda/src/pgraph/planeNode.cxx +++ b/panda/src/pgraph/planeNode.cxx @@ -78,7 +78,7 @@ PlaneNode(const string &name, const Planef &plane) : _priority(0) { // PlaneNodes are hidden by default. - set_draw_mask(DrawMask::all_off()); + set_overall_hidden(true); set_plane(plane); } @@ -183,6 +183,21 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { 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 // Access: Protected, Virtual diff --git a/panda/src/pgraph/planeNode.h b/panda/src/pgraph/planeNode.h index f62e6776f1..b6661d83cf 100644 --- a/panda/src/pgraph/planeNode.h +++ b/panda/src/pgraph/planeNode.h @@ -53,6 +53,7 @@ public: virtual bool has_cull_callback() const; virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); + virtual bool is_renderable() const; PUBLISHED: INLINE void set_plane(const Planef &plane); diff --git a/panda/src/pgraph/portalNode.cxx b/panda/src/pgraph/portalNode.cxx index b78457d9c3..93073e827a 100755 --- a/panda/src/pgraph/portalNode.cxx +++ b/panda/src/pgraph/portalNode.cxx @@ -334,6 +334,21 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { 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 diff --git a/panda/src/pgraph/portalNode.h b/panda/src/pgraph/portalNode.h index 4a1b965b4a..f23e048d48 100755 --- a/panda/src/pgraph/portalNode.h +++ b/panda/src/pgraph/portalNode.h @@ -60,6 +60,7 @@ public: virtual bool has_cull_callback() const; virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); + virtual bool is_renderable() const; virtual void output(ostream &out) const; diff --git a/panda/src/pgraph/sceneGraphReducer.cxx b/panda/src/pgraph/sceneGraphReducer.cxx index e2836b3fa7..ea180fab7c 100644 --- a/panda/src/pgraph/sceneGraphReducer.cxx +++ b/panda/src/pgraph/sceneGraphReducer.cxx @@ -343,8 +343,11 @@ operator () (const PandaNode *node1, const PandaNode *node2) const { if (node1->get_effects() != node2->get_effects()) { return node1->get_effects() < node2->get_effects(); } - if (node1->get_draw_mask() != node2->get_draw_mask()) { - return node1->get_draw_mask() < node2->get_draw_mask(); + if (node1->get_draw_control_mask() != node2->get_draw_control_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; @@ -452,7 +455,8 @@ consider_child(PandaNode *grandparent_node, PandaNode *parent_node, if (parent_node->get_transform() != child_node->get_transform() || parent_node->get_state() != child_node->get_state() || 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. return false; } diff --git a/panda/src/pgui/pgItem.cxx b/panda/src/pgui/pgItem.cxx index f0e08f6a28..1b6466712b 100644 --- a/panda/src/pgui/pgItem.cxx +++ b/panda/src/pgui/pgItem.cxx @@ -252,6 +252,21 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { 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 // Access: Protected, Virtual @@ -1025,7 +1040,7 @@ play_sound(const string &event) { //////////////////////////////////////////////////////////////////// void PGItem:: 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); // Determine the four rectangular regions on the four sides of the diff --git a/panda/src/pgui/pgItem.h b/panda/src/pgui/pgItem.h index 887dfb76db..2a753ebf79 100644 --- a/panda/src/pgui/pgItem.h +++ b/panda/src/pgui/pgItem.h @@ -67,6 +67,7 @@ protected: virtual bool has_cull_callback() const; virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); + virtual bool is_renderable() const; virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const; diff --git a/panda/src/pgui/pgScrollFrame.cxx b/panda/src/pgui/pgScrollFrame.cxx index bb35aacae0..d414ef93c3 100644 --- a/panda/src/pgui/pgScrollFrame.cxx +++ b/panda/src/pgui/pgScrollFrame.cxx @@ -267,18 +267,18 @@ remanage() { // Now show or hide the sliders appropriately. if (_horizontal_slider != (PGSliderBar *)NULL) { if (got_horizontal) { - _horizontal_slider->set_draw_mask(DrawMask::all_on()); + _horizontal_slider->set_overall_hidden(false); } else { - _horizontal_slider->set_draw_mask(DrawMask::all_off()); + _horizontal_slider->set_overall_hidden(true); _horizontal_slider->set_ratio(0.0f); horizontal_width = 0.0f; } } if (_vertical_slider != (PGSliderBar *)NULL) { if (got_vertical) { - _vertical_slider->set_draw_mask(DrawMask::all_on()); + _vertical_slider->set_overall_hidden(false); } else { - _vertical_slider->set_draw_mask(DrawMask::all_off()); + _vertical_slider->set_overall_hidden(true); _vertical_slider->set_ratio(0.0f); vertical_width = 0.0f; } @@ -288,14 +288,14 @@ remanage() { // flag again indirectly; we clear it again to avoid a feedback // loop. _needs_remanage = false; - } +} // 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; 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; vertical_width = 0.0f; } diff --git a/panda/src/putil/bam.h b/panda/src/putil/bam.h index 16e7ef7daf..7484def3b5 100644 --- a/panda/src/putil/bam.h +++ b/panda/src/putil/bam.h @@ -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 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 2 on 3/17/06 to add PandaNode::_draw_control_mask. #endif diff --git a/panda/src/putil/bitArray.I b/panda/src/putil/bitArray.I index e11e820a64..de63efcb6f 100755 --- a/panda/src/putil/bitArray.I +++ b/panda/src/putil/bitArray.I @@ -57,10 +57,11 @@ BitArray(const BitArray ©) : // Access: Published // Description: //////////////////////////////////////////////////////////////////// -INLINE void BitArray:: +INLINE BitArray &BitArray:: operator = (const BitArray ©) { _array = copy._array; _highest_bits = copy._highest_bits; + return *this; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/putil/bitArray.h b/panda/src/putil/bitArray.h index 0a6bde1d55..0e11afc1b3 100755 --- a/panda/src/putil/bitArray.h +++ b/panda/src/putil/bitArray.h @@ -47,7 +47,7 @@ PUBLISHED: INLINE BitArray(); INLINE BitArray(WordType init_value); INLINE BitArray(const BitArray ©); - INLINE void operator = (const BitArray ©); + INLINE BitArray &operator = (const BitArray ©); INLINE static BitArray all_on(); INLINE static BitArray all_off(); diff --git a/panda/src/putil/bitMask.I b/panda/src/putil/bitMask.I index a5a05da493..419d7419f4 100644 --- a/panda/src/putil/bitMask.I +++ b/panda/src/putil/bitMask.I @@ -61,9 +61,10 @@ BitMask(const BitMask ©) : // Description: //////////////////////////////////////////////////////////////////// template -INLINE void BitMask:: +INLINE BitMask &BitMask:: operator = (const BitMask ©) { _word = copy._word; + return *this; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/putil/bitMask.h b/panda/src/putil/bitMask.h index b171aabdb6..411115edce 100644 --- a/panda/src/putil/bitMask.h +++ b/panda/src/putil/bitMask.h @@ -44,7 +44,7 @@ PUBLISHED: INLINE BitMask(); INLINE BitMask(WordType init_value); INLINE BitMask(const BitMask ©); - INLINE void operator = (const BitMask ©); + INLINE BitMask &operator = (const BitMask ©); INLINE static BitMask all_on(); INLINE static BitMask all_off(); diff --git a/panda/src/text/textNode.cxx b/panda/src/text/textNode.cxx index b9aa3435ce..7c8cf56bd4 100644 --- a/panda/src/text/textNode.cxx +++ b/panda/src/text/textNode.cxx @@ -194,24 +194,10 @@ write(ostream &out, int indent_level) const { indent(out, indent_level) << "TextNode " << get_name() << "\n"; 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) - << "transform is:\n" - << " scale: " << scale << "\n" - << " shear: " << shear << "\n" - << " hpr: " << hpr << "\n" - << " trans: " << hpr << "\n"; - } else { - indent(out, indent_level + 2) - << "transform is:\n" << _transform; - } + << "transform is: " << *TransformState::make_mat(_transform) << "\n"; indent(out, indent_level + 2) << "in coordinate system " << _coordinate_system << "\n"; - - out << "\n"; indent(out, indent_level + 2) << "text is " << get_text() << "\n"; } @@ -569,6 +555,21 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { 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 // Access: Protected, Virtual diff --git a/panda/src/text/textNode.h b/panda/src/text/textNode.h index e74b526b27..e4022cf001 100644 --- a/panda/src/text/textNode.h +++ b/panda/src/text/textNode.h @@ -236,6 +236,7 @@ public: virtual bool has_cull_callback() const; virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); + virtual bool is_renderable() const; virtual PT(BoundingVolume) compute_internal_bounds(int pipeline_stage) const; diff --git a/panda/src/tform/mouseWatcher.cxx b/panda/src/tform/mouseWatcher.cxx index e6e510c98b..ed270e0c5c 100644 --- a/panda/src/tform/mouseWatcher.cxx +++ b/panda/src/tform/mouseWatcher.cxx @@ -1029,7 +1029,7 @@ set_no_mouse() { if (_has_mouse) { // Hide the mouse pointer. 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]))); if (!_has_mouse) { // Show the mouse pointer. - _geometry->set_draw_mask(DrawMask::all_on()); + _geometry->set_overall_hidden(false); } } diff --git a/pandatool/src/bam/bamToEgg.cxx b/pandatool/src/bam/bamToEgg.cxx index 6f95ec4f4c..3dcc812b97 100644 --- a/pandatool/src/bam/bamToEgg.cxx +++ b/pandatool/src/bam/bamToEgg.cxx @@ -396,7 +396,7 @@ bool BamToEgg:: apply_node_properties(EggGroup *egg_group, PandaNode *node) { 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 // put in the "backstage" flag to mean it's not real geometry. egg_group->add_object_type("backstage");