diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 1f898f13cf..9b392574e8 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -281,8 +281,7 @@ do_cull(CullHandler *cull_handler, const qpNodePath &camera, } } - - trav.traverse(scene.node()); + trav.traverse(scene); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/graph/boundedObject.cxx b/panda/src/graph/boundedObject.cxx index b068b9d107..b95bf5f0d0 100644 --- a/panda/src/graph/boundedObject.cxx +++ b/panda/src/graph/boundedObject.cxx @@ -104,6 +104,10 @@ BoundingVolume *BoundedObject:: recompute_bound() { CDWriter cdata(_cycler); switch (cdata->_bound_type) { + case BVT_static: + // Don't change it if it's a static volume. + break; + case BVT_dynamic_sphere: cdata->_bound = new BoundingSphere; break; diff --git a/panda/src/loader/bamFile.h b/panda/src/loader/bamFile.h index 5b2a8e2873..090227f8af 100644 --- a/panda/src/loader/bamFile.h +++ b/panda/src/loader/bamFile.h @@ -45,7 +45,7 @@ class Filename; // common scene graph files. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA BamFile { -public: +PUBLISHED: BamFile(); ~BamFile(); diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index cff358c82c..57ea817845 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -41,7 +41,7 @@ materialAttrib.I materialAttrib.h \ qpmodelNode.I qpmodelNode.h \ qpmodelRoot.I qpmodelRoot.h \ - qpnodePath.I qpnodePath.h \ + qpnodePath.I qpnodePath.h qpnodePath.cxx \ qpnodePathCollection.I qpnodePathCollection.h \ qpnodePathComponent.I qpnodePathComponent.h \ qpnodePathLerps.h \ diff --git a/panda/src/pgraph/cullTraverserData.I b/panda/src/pgraph/cullTraverserData.I index 807546c916..bd62b6d45b 100644 --- a/panda/src/pgraph/cullTraverserData.I +++ b/panda/src/pgraph/cullTraverserData.I @@ -23,11 +23,13 @@ // Description: //////////////////////////////////////////////////////////////////// INLINE CullTraverserData:: -CullTraverserData(const TransformState *render_transform, +CullTraverserData(const qpNodePath &start, + const TransformState *render_transform, const TransformState *net_transform, const RenderState *state, GeometricBoundingVolume *view_frustum, GeometricBoundingVolume *guard_band) : + _node_path(start), _render_transform(render_transform), _net_transform(net_transform), _state(state), @@ -37,32 +39,42 @@ CullTraverserData(const TransformState *render_transform, } //////////////////////////////////////////////////////////////////// -// Function: CullTraverserData::Copy Constructor +// Function: CullTraverserData::Constructor // Access: Public -// Description: +// Description: This constructor creates a CullTraverserData object +// that reflects the next node down in the traversal. //////////////////////////////////////////////////////////////////// INLINE CullTraverserData:: -CullTraverserData(const CullTraverserData ©) : - _render_transform(copy._render_transform), - _net_transform(copy._net_transform), - _state(copy._state), - _view_frustum(copy._view_frustum), - _guard_band(copy._guard_band) +CullTraverserData(const CullTraverserData &parent, PandaNode *child) : + _node_path(parent._node_path, child), + _render_transform(parent._render_transform), + _net_transform(parent._net_transform), + _state(parent._state), + _view_frustum(parent._view_frustum), + _guard_band(parent._guard_band) { } +//////////////////////////////////////////////////////////////////// +// Function: CullTraverserData::Copy Constructor +// Access: Private +// Description: Do not copy CullTraverserData objects. +//////////////////////////////////////////////////////////////////// +INLINE CullTraverserData:: +CullTraverserData(const CullTraverserData ©) : + _node_path(qpNodePath()) +{ + nassertv(false); +} + //////////////////////////////////////////////////////////////////// // Function: CullTraverserData::Copy Assignment Operator -// Access: Public -// Description: +// Access: Private +// Description: Do not copy CullTraverserData objects. //////////////////////////////////////////////////////////////////// INLINE void CullTraverserData:: operator = (const CullTraverserData ©) { - _render_transform = copy._render_transform; - _net_transform = copy._net_transform; - _state = copy._state; - _view_frustum = copy._view_frustum; - _guard_band = copy._guard_band; + nassertv(false); } //////////////////////////////////////////////////////////////////// @@ -74,18 +86,33 @@ INLINE CullTraverserData:: ~CullTraverserData() { } +//////////////////////////////////////////////////////////////////// +// Function: CullTraverserData::node +// Access: Public +// Description: Returns the node traversed to so far. +//////////////////////////////////////////////////////////////////// +INLINE PandaNode *CullTraverserData:: +node() const { + return _node_path.node(); +} + //////////////////////////////////////////////////////////////////// // Function: CullTraverserData::is_in_view // Access: Public -// Description: Returns true if the node is within the view frustum, -// false otherwise. If the node's bounding volume falls -// completely within the view frustum, this will also -// reset the view frustum pointer, saving some work for -// future nodes. +// Description: Returns true if the current node is within the view +// frustum, false otherwise. If the node's bounding +// volume falls completely within the view frustum, this +// will also reset the view frustum pointer, saving some +// work for future nodes. //////////////////////////////////////////////////////////////////// INLINE bool CullTraverserData:: -is_in_view(PandaNode *node, const DrawMask &camera_mask) { - if ((node->get_draw_mask() & camera_mask).is_zero()) { +is_in_view(const DrawMask &camera_mask) { + if (node()->get_transform()->is_invalid()) { + // If the transform is invalid, forget it. + return false; + } + + if ((node()->get_draw_mask() & camera_mask).is_zero()) { // If there are no draw bits in common with the camera, the node // is out. return false; @@ -98,5 +125,5 @@ is_in_view(PandaNode *node, const DrawMask &camera_mask) { } // Otherwise, compare the bounding volume to the frustum. - return is_in_view_impl(node); + return is_in_view_impl(); } diff --git a/panda/src/pgraph/cullTraverserData.cxx b/panda/src/pgraph/cullTraverserData.cxx index d158629e3e..1e2ffb4882 100644 --- a/panda/src/pgraph/cullTraverserData.cxx +++ b/panda/src/pgraph/cullTraverserData.cxx @@ -28,13 +28,13 @@ //////////////////////////////////////////////////////////////////// // Function: CullTraverserData::apply_transform_and_state // Access: Public -// Description: Applies the transform and state from the indicated +// Description: Applies the transform and state from the current // node onto the current data. This also evaluates // billboards, etc. //////////////////////////////////////////////////////////////////// void CullTraverserData:: -apply_transform_and_state(qpCullTraverser *trav, PandaNode *node) { - const TransformState *node_transform = node->get_transform(); +apply_transform_and_state(qpCullTraverser *trav) { + const TransformState *node_transform = node()->get_transform(); if (!node_transform->is_identity()) { _render_transform = _render_transform->compose(node_transform); _net_transform = _net_transform->compose(node_transform); @@ -69,9 +69,9 @@ apply_transform_and_state(qpCullTraverser *trav, PandaNode *node) { } } - _state = _state->compose(node->get_state()); + _state = _state->compose(node()->get_state()); - const RenderEffects *node_effects = node->get_effects(); + const RenderEffects *node_effects = node()->get_effects(); const BillboardEffect *billboard = node_effects->get_billboard(); if (billboard != (const BillboardEffect *)NULL) { // Got to apply a billboard transform here. @@ -94,11 +94,11 @@ apply_transform_and_state(qpCullTraverser *trav, PandaNode *node) { // Description: The private implementation of is_in_view(). //////////////////////////////////////////////////////////////////// bool CullTraverserData:: -is_in_view_impl(PandaNode *node) { +is_in_view_impl() { // By the time we get here, we know we have a viewing frustum. nassertr(_view_frustum != (GeometricBoundingVolume *)NULL, true); - const BoundingVolume &node_volume = node->get_bound(); + const BoundingVolume &node_volume = node()->get_bound(); nassertr(node_volume.is_of_type(GeometricBoundingVolume::get_class_type()), false); const GeometricBoundingVolume *node_gbv = DCAST(GeometricBoundingVolume, &node_volume); @@ -123,7 +123,7 @@ is_in_view_impl(PandaNode *node) { _view_frustum = (GeometricBoundingVolume *)NULL; } else { - if (node->is_final()) { + if (node()->is_final()) { // The bounding volume is partially, but not completely, // within the viewing frustum. Normally we'd keep testing // child bounding volumes as we continue down. But this node diff --git a/panda/src/pgraph/cullTraverserData.h b/panda/src/pgraph/cullTraverserData.h index 144cc08151..c89fa55986 100644 --- a/panda/src/pgraph/cullTraverserData.h +++ b/panda/src/pgraph/cullTraverserData.h @@ -21,6 +21,7 @@ #include "pandabase.h" +#include "workingNodePath.h" #include "renderState.h" #include "transformState.h" #include "geometricBoundingVolume.h" @@ -46,18 +47,28 @@ class qpCullTraverser; //////////////////////////////////////////////////////////////////// class EXPCL_PANDA CullTraverserData { public: - INLINE CullTraverserData(const TransformState *render_transform, + INLINE CullTraverserData(const qpNodePath &start, + const TransformState *render_transform, const TransformState *net_transform, const RenderState *state, GeometricBoundingVolume *view_frustum, GeometricBoundingVolume *guard_band); + INLINE CullTraverserData(const CullTraverserData &parent, + PandaNode *child); + +private: INLINE CullTraverserData(const CullTraverserData ©); - INLINE void operator = (const CullTraverserData ©); + INLINE void operator = (const CullTraverserData ©); + +public: INLINE ~CullTraverserData(); - INLINE bool is_in_view(PandaNode *node, const DrawMask &camera_mask); - void apply_transform_and_state(qpCullTraverser *trav, PandaNode *node); + INLINE PandaNode *node() const; + INLINE bool is_in_view(const DrawMask &camera_mask); + void apply_transform_and_state(qpCullTraverser *trav); + + WorkingNodePath _node_path; CPT(TransformState) _render_transform; CPT(TransformState) _net_transform; CPT(RenderState) _state; @@ -65,7 +76,7 @@ public: PT(GeometricBoundingVolume) _guard_band; private: - bool is_in_view_impl(PandaNode *node); + bool is_in_view_impl(); static CPT(RenderState) get_fake_view_frustum_cull_effect(); }; diff --git a/panda/src/pgraph/pandaNode.I b/panda/src/pgraph/pandaNode.I index b8d2b58d43..ebbe9a57ac 100644 --- a/panda/src/pgraph/pandaNode.I +++ b/panda/src/pgraph/pandaNode.I @@ -739,7 +739,7 @@ get_bound() const { //////////////////////////////////////////////////////////////////// INLINE const BoundingVolume &PandaNode:: get_internal_bound() const { - if (_internal_bound.is_bound_stale()) { + if (is_bound_stale() || _internal_bound.is_bound_stale()) { ((PandaNode *)this)->recompute_internal_bound(); } return _internal_bound.get_bound(); diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index 7781b39864..bdbc598f33 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -1157,17 +1157,21 @@ propagate_stale_bound() { //////////////////////////////////////////////////////////////////// BoundingVolume *PandaNode:: recompute_bound() { - // First, get ourselves a fresh, empty bounding volume. + // Get the internal bound before we do anything else, since the + // is_bound_stale() flag may also apply to this. + const BoundingVolume *internal_bound = &get_internal_bound(); + + // Now, get ourselves a fresh, empty bounding volume. This will + // reset the is_bound_stale() flag if it was set. BoundingVolume *bound = BoundedObject::recompute_bound(); nassertr(bound != (BoundingVolume*)NULL, bound); // Now actually compute the bounding volume by putting it around all // of our child bounding volumes. - pvector child_volumes; // It goes around this node's internal bounding volume . . . - child_volumes.push_back(&get_internal_bound()); + child_volumes.push_back(internal_bound); CDReader cdata(_cycler); Down::const_iterator di; diff --git a/panda/src/pgraph/pgraph_composite2.cxx b/panda/src/pgraph/pgraph_composite2.cxx index a941fc14c4..2f35a97c0d 100644 --- a/panda/src/pgraph/pgraph_composite2.cxx +++ b/panda/src/pgraph/pgraph_composite2.cxx @@ -10,7 +10,6 @@ #include "materialAttrib.cxx" #include "qpmodelNode.cxx" #include "qpmodelRoot.cxx" -#include "qpnodePath.cxx" #include "qpnodePathCollection.cxx" #include "qpnodePathComponent.cxx" #include "qpnodePathLerps.cxx" diff --git a/panda/src/pgraph/qpcullTraverser.cxx b/panda/src/pgraph/qpcullTraverser.cxx index 9aa511cca4..e1c694be5f 100644 --- a/panda/src/pgraph/qpcullTraverser.cxx +++ b/panda/src/pgraph/qpcullTraverser.cxx @@ -65,44 +65,39 @@ qpCullTraverser(const qpCullTraverser ©) : // Description: Begins the traversal from the indicated node. //////////////////////////////////////////////////////////////////// void qpCullTraverser:: -traverse(PandaNode *root) { +traverse(qpNodePath &root) { nassertv(_cull_handler != (CullHandler *)NULL); - CullTraverserData data(_render_transform, TransformState::make_identity(), + CullTraverserData data(root, + _render_transform, TransformState::make_identity(), _initial_state, _view_frustum, _guard_band); - traverse(root, data); + traverse(data); } //////////////////////////////////////////////////////////////////// // Function: qpCullTraverser::traverse // Access: Public -// Description: Traverses from the indicated node with the given -// data, which has not yet been converted into the -// node's space. +// Description: Traverses from the next node with the given +// data, which has been constructed with the node but +// has not yet been converted into the node's space. //////////////////////////////////////////////////////////////////// void qpCullTraverser:: -traverse(PandaNode *node, const CullTraverserData &data) { +traverse(CullTraverserData &data) { // Most nodes will have no transform or state, and will not // contain decals or require a special cull callback. As an // optimization, we should tag nodes with these properties as // being "fancy", and skip this processing for non-fancy nodes. + if (data.is_in_view(_camera_mask)) { + data.apply_transform_and_state(this); - if (node->get_transform()->is_invalid()) { - // If the transform is invalid, forget it. - return; - } - - CullTraverserData next_data(data); - if (next_data.is_in_view(node, _camera_mask)) { - next_data.apply_transform_and_state(this, node); - + PandaNode *node = data.node(); if (node->has_cull_callback()) { - if (!node->cull_callback(this, next_data)) { + if (!node->cull_callback(this, data)) { return; } } - traverse_below(node, next_data); + traverse_below(data); } } @@ -114,10 +109,11 @@ traverse(PandaNode *node, const CullTraverserData &data) { // node's space. //////////////////////////////////////////////////////////////////// void qpCullTraverser:: -traverse_below(PandaNode *node, const CullTraverserData &data) { +traverse_below(const CullTraverserData &data) { + PandaNode *node = data.node(); const RenderEffects *node_effects = node->get_effects(); if (node_effects->has_decal()) { - start_decal(node, data); + start_decal(data); } else { if (node->is_geom_node()) { @@ -139,13 +135,15 @@ traverse_below(PandaNode *node, const CullTraverserData &data) { if (node->has_selective_visibility()) { int i = node->get_first_visible_child(); while (i < num_children) { - traverse(node->get_child(i), data); + CullTraverserData next_data(data, node->get_child(i)); + traverse(next_data); i = node->get_next_visible_child(i); } } else { for (int i = 0; i < num_children; i++) { - traverse(node->get_child(i), data); + CullTraverserData next_data(data, node->get_child(i)); + traverse(next_data); } } } @@ -159,7 +157,8 @@ traverse_below(PandaNode *node, const CullTraverserData &data) { // to find all the decal geoms. //////////////////////////////////////////////////////////////////// void qpCullTraverser:: -start_decal(PandaNode *node, const CullTraverserData &data) { +start_decal(const CullTraverserData &data) { + PandaNode *node = data.node(); if (!node->is_geom_node()) { pgraph_cat.error() << "DecalEffect applied to " << *node << ", not a GeomNode.\n"; @@ -179,13 +178,15 @@ start_decal(PandaNode *node, const CullTraverserData &data) { if (node->has_selective_visibility()) { int i = node->get_first_visible_child(); while (i < num_children) { - decals = r_get_decals(cr.get_child(i), data, decals); + CullTraverserData next_data(data, cr.get_child(i)); + decals = r_get_decals(next_data, decals); i = node->get_next_visible_child(i); } } else { for (int i = num_children - 1; i >= 0; i--) { - decals = r_get_decals(cr.get_child(i), data, decals); + CullTraverserData next_data(data, cr.get_child(i)); + decals = r_get_decals(next_data, decals); } } @@ -219,30 +220,26 @@ start_decal(PandaNode *node, const CullTraverserData &data) { // they were encountered in the scene graph). //////////////////////////////////////////////////////////////////// CullableObject *qpCullTraverser:: -r_get_decals(PandaNode *node, const CullTraverserData &data, - CullableObject *decals) { - if (node->get_transform()->is_invalid()) { - // If the transform is invalid, forget it. - return decals; - } +r_get_decals(CullTraverserData &data, CullableObject *decals) { + if (data.is_in_view(_camera_mask)) { + data.apply_transform_and_state(this); - CullTraverserData next_data(data); - if (next_data.is_in_view(node, _camera_mask)) { - next_data.apply_transform_and_state(this, node); + PandaNode *node = data.node(); // First, visit all of the node's children. - PandaNode::Children cr = node->get_children(); - int num_children = cr.get_num_children(); + int num_children = node->get_num_children(); if (node->has_selective_visibility()) { int i = node->get_first_visible_child(); while (i < num_children) { - decals = r_get_decals(cr.get_child(i), next_data, decals); + CullTraverserData next_data(data, node->get_child(i)); + decals = r_get_decals(next_data, decals); i = node->get_next_visible_child(i); } } else { for (int i = num_children - 1; i >= 0; i--) { - decals = r_get_decals(cr.get_child(i), next_data, decals); + CullTraverserData next_data(data, node->get_child(i)); + decals = r_get_decals(next_data, decals); } } @@ -252,7 +249,7 @@ r_get_decals(PandaNode *node, const CullTraverserData &data, int num_geoms = geom_node->get_num_geoms(); for (int i = num_geoms - 1; i >= 0; i--) { - decals = new CullableObject(next_data, geom_node, i, decals); + decals = new CullableObject(data, geom_node, i, decals); } } } diff --git a/panda/src/pgraph/qpcullTraverser.h b/panda/src/pgraph/qpcullTraverser.h index 76693d1d6e..38c6681ce1 100644 --- a/panda/src/pgraph/qpcullTraverser.h +++ b/panda/src/pgraph/qpcullTraverser.h @@ -32,6 +32,7 @@ class PandaNode; class CullHandler; class CullTraverserData; class CullableObject; +class qpNodePath; //////////////////////////////////////////////////////////////////// // Class : CullTraverser @@ -67,14 +68,13 @@ public: INLINE void set_cull_handler(CullHandler *cull_handler); INLINE CullHandler *get_cull_handler() const; - void traverse(PandaNode *root); - void traverse(PandaNode *node, const CullTraverserData &data); - void traverse_below(PandaNode *node, const CullTraverserData &data); + void traverse(qpNodePath &root); + void traverse(CullTraverserData &data); + void traverse_below(const CullTraverserData &data); private: - void start_decal(PandaNode *node, const CullTraverserData &data); - CullableObject *r_get_decals(PandaNode *node, - const CullTraverserData &data, + void start_decal(const CullTraverserData &data); + CullableObject *r_get_decals(CullTraverserData &data, CullableObject *decals); CPT(RenderState) _initial_state; diff --git a/panda/src/pgraph/qpgeomNode.cxx b/panda/src/pgraph/qpgeomNode.cxx index 4f6616f7d7..7258fe920a 100644 --- a/panda/src/pgraph/qpgeomNode.cxx +++ b/panda/src/pgraph/qpgeomNode.cxx @@ -235,7 +235,7 @@ write_geoms(ostream &out, int indent_level) const { for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) { const GeomEntry &entry = (*gi); indent(out, indent_level + 2) - << *entry._geom << " (" << *entry._state << ")\n"; + << *entry._geom << " " << *entry._state << "\n"; } } @@ -253,7 +253,7 @@ write_verbose(ostream &out, int indent_level) const { for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) { const GeomEntry &entry = (*gi); indent(out, indent_level + 2) - << *entry._geom << " (" << *entry._state << ")\n"; + << *entry._geom << " " << *entry._state << "\n"; entry._geom->write_verbose(out, indent_level + 4); } } diff --git a/panda/src/pgraph/qpgeomTransformer.I b/panda/src/pgraph/qpgeomTransformer.I index feb21c69ed..e1b5bb7988 100644 --- a/panda/src/pgraph/qpgeomTransformer.I +++ b/panda/src/pgraph/qpgeomTransformer.I @@ -63,5 +63,8 @@ operator < (const qpGeomTransformer::SourceTexCoords &other) const { //////////////////////////////////////////////////////////////////// INLINE bool qpGeomTransformer::SourceColors:: operator < (const qpGeomTransformer::SourceColors &other) const { + if (_colors != other._colors) { + return _colors < other._colors; + } return (_scale.compare_to(other._scale) < 0); } diff --git a/panda/src/pgraph/qpgeomTransformer.cxx b/panda/src/pgraph/qpgeomTransformer.cxx index aa1aa0b915..d767170b88 100644 --- a/panda/src/pgraph/qpgeomTransformer.cxx +++ b/panda/src/pgraph/qpgeomTransformer.cxx @@ -296,6 +296,7 @@ transform_colors(Geom *geom, const LVecBase4f &scale) { // transformed this array? SourceColors sc; sc._scale = scale; + sc._colors = colors; PTA_Colorf &new_colors = _tcolors[sc]; diff --git a/panda/src/pgraph/qplodNode.cxx b/panda/src/pgraph/qplodNode.cxx index 261c2aff45..41eb435492 100644 --- a/panda/src/pgraph/qplodNode.cxx +++ b/panda/src/pgraph/qplodNode.cxx @@ -68,6 +68,21 @@ make_copy() const { return new qpLODNode(*this); } +//////////////////////////////////////////////////////////////////// +// Function: qpLODNode::safe_to_combine +// Access: Public, Virtual +// Description: Returns true if it is generally safe to combine this +// particular kind of PandaNode with other kinds of +// PandaNodes, adding children or whatever. For +// instance, an LODNode should not be combined with any +// other PandaNode, because its set of children is +// meaningful. +//////////////////////////////////////////////////////////////////// +bool qpLODNode:: +safe_to_combine() const { + return false; +} + //////////////////////////////////////////////////////////////////// // Function: qpLODNode::xform // Access: Public, Virtual diff --git a/panda/src/pgraph/qplodNode.h b/panda/src/pgraph/qplodNode.h index c31285caac..11adde9562 100644 --- a/panda/src/pgraph/qplodNode.h +++ b/panda/src/pgraph/qplodNode.h @@ -40,6 +40,7 @@ protected: INLINE qpLODNode(const qpLODNode ©); public: virtual PandaNode *make_copy() const; + virtual bool safe_to_combine() const; virtual void xform(const LMatrix4f &mat); virtual bool has_cull_callback() const; virtual bool cull_callback(qpCullTraverser *trav, CullTraverserData &data); diff --git a/panda/src/pgraph/qpmodelNode.cxx b/panda/src/pgraph/qpmodelNode.cxx index 2a15840563..0c4014315f 100644 --- a/panda/src/pgraph/qpmodelNode.cxx +++ b/panda/src/pgraph/qpmodelNode.cxx @@ -65,6 +65,21 @@ safe_to_transform() const { return !_preserve_transform; } +//////////////////////////////////////////////////////////////////// +// Function: qpModelNode::safe_to_combine +// Access: Public, Virtual +// Description: Returns true if it is generally safe to combine this +// particular kind of PandaNode with other kinds of +// PandaNodes, adding children or whatever. For +// instance, an LODNode should not be combined with any +// other PandaNode, because its set of children is +// meaningful. +//////////////////////////////////////////////////////////////////// +bool qpModelNode:: +safe_to_combine() const { + return false; +} + //////////////////////////////////////////////////////////////////// // Function: qpModelNode::preserve_name // Access: Public, Virtual diff --git a/panda/src/pgraph/qpmodelNode.h b/panda/src/pgraph/qpmodelNode.h index c6aeb9a0ef..de54428102 100644 --- a/panda/src/pgraph/qpmodelNode.h +++ b/panda/src/pgraph/qpmodelNode.h @@ -47,6 +47,7 @@ public: virtual bool safe_to_flatten() const; virtual bool safe_to_transform() const; + virtual bool safe_to_combine() const; virtual bool preserve_name() const; PUBLISHED: diff --git a/panda/src/pgraph/qpnodePath.I b/panda/src/pgraph/qpnodePath.I index e90a14cfce..1c877176e1 100644 --- a/panda/src/pgraph/qpnodePath.I +++ b/panda/src/pgraph/qpnodePath.I @@ -597,34 +597,6 @@ get_mat() const { return node()->get_transform()->get_mat(); } -//////////////////////////////////////////////////////////////////// -// Function: qpNodePath::has_color_scale -// Access: Published -// Description: Returns true if a color scale has been applied -// to the referenced node, false otherwise. It is still -// possible that color at this node might have been -// scaled by an ancestor node. -//////////////////////////////////////////////////////////////////// -INLINE bool qpNodePath:: -has_color_scale() const { - nassertr(false, false); - return false; -} - -//////////////////////////////////////////////////////////////////// -// Function: qpNodePath::clear_color_scale -// Access: Published -// Description: Completely removes any color scale from the -// referenced node. This is preferable to simply -// setting the color scale to identity, as it also -// removes the overhead associated with having a color -// scale at all. -//////////////////////////////////////////////////////////////////// -INLINE void qpNodePath:: -clear_color_scale() { - nassertv(false); -} - //////////////////////////////////////////////////////////////////// // Function: qpNodePath::set_color_scale // Access: Published diff --git a/panda/src/pgraph/qpnodePath.cxx b/panda/src/pgraph/qpnodePath.cxx index 89d22f5014..b2ca33976d 100644 --- a/panda/src/pgraph/qpnodePath.cxx +++ b/panda/src/pgraph/qpnodePath.cxx @@ -721,6 +721,35 @@ set_mat(const LMatrix4f &mat) { set_transform(TransformState::make_mat(mat)); } +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::has_color_scale +// Access: Published +// Description: Returns true if a color scale has been applied +// to the referenced node, false otherwise. It is still +// possible that color at this node might have been +// scaled by an ancestor node. +//////////////////////////////////////////////////////////////////// +bool qpNodePath:: +has_color_scale() const { + nassertr_always(!is_empty(), false); + return node()->has_attrib(ColorScaleAttrib::get_class_type()); +} + +//////////////////////////////////////////////////////////////////// +// Function: qpNodePath::clear_color_scale +// Access: Published +// Description: Completely removes any color scale from the +// referenced node. This is preferable to simply +// setting the color scale to identity, as it also +// removes the overhead associated with having a color +// scale at all. +//////////////////////////////////////////////////////////////////// +void qpNodePath:: +clear_color_scale() { + nassertv_always(!is_empty()); + node()->clear_attrib(ColorScaleAttrib::get_class_type()); +} + //////////////////////////////////////////////////////////////////// // Function: qpNodePath::set_color_scale // Access: Published diff --git a/panda/src/pgraph/qpnodePath.h b/panda/src/pgraph/qpnodePath.h index 79084c16e4..53df39798a 100644 --- a/panda/src/pgraph/qpnodePath.h +++ b/panda/src/pgraph/qpnodePath.h @@ -284,9 +284,8 @@ PUBLISHED: INLINE bool has_mat() const; INLINE const LMatrix4f &get_mat() const; - INLINE bool has_color_scale() const; - INLINE void clear_color_scale(); - + bool has_color_scale() const; + void clear_color_scale(); void set_color_scale(const LVecBase4f &scale); INLINE void set_color_scale(float sx, float sy, float sz, float sa); INLINE void set_sr(float sr); diff --git a/panda/src/pgraph/qpsceneGraphReducer.cxx b/panda/src/pgraph/qpsceneGraphReducer.cxx index dd941c04e6..c8ce5bb612 100644 --- a/panda/src/pgraph/qpsceneGraphReducer.cxx +++ b/panda/src/pgraph/qpsceneGraphReducer.cxx @@ -23,8 +23,10 @@ #include "colorScaleAttrib.h" #include "qpgeomNode.h" +#include "pointerTo.h" #include "geom.h" #include "indent.h" +#include "plist.h" //////////////////////////////////////////////////////////////////// // Function: qpSceneGraphReducer::AccumulatedAttribs::write @@ -487,7 +489,9 @@ r_flatten(PandaNode *grandparent_node, PandaNode *parent_node, // saved above is no longer accurate, so hereafter we must ask the // node for its real child list. if (combine_siblings && parent_node->get_num_children() >= 2) { - num_nodes += flatten_siblings(parent_node); + if (parent_node->safe_to_combine()) { + num_nodes += flatten_siblings(parent_node); + } } if (parent_node->get_num_children() == 1) { @@ -646,7 +650,7 @@ consider_child(PandaNode *grandparent_node, PandaNode *parent_node, } //////////////////////////////////////////////////////////////////// -// Function: qpSceneGraphReducer::consider_siblings +// Function: qpSceneGraphReducer:c:onsider_siblings // Access: Protected, Virtual // Description: Decides whether or not the indicated sibling nodes // should be collapsed into a single node or not. diff --git a/panda/src/pgraph/qpsequenceNode.cxx b/panda/src/pgraph/qpsequenceNode.cxx index f31ee8089a..0dd6416392 100644 --- a/panda/src/pgraph/qpsequenceNode.cxx +++ b/panda/src/pgraph/qpsequenceNode.cxx @@ -32,6 +32,21 @@ make_copy() const { return new CData(*this); } +//////////////////////////////////////////////////////////////////// +// Function: qpSequenceNode::safe_to_combine +// Access: Public, Virtual +// Description: Returns true if it is generally safe to combine this +// particular kind of PandaNode with other kinds of +// PandaNodes, adding children or whatever. For +// instance, an LODNode should not be combined with any +// other PandaNode, because its set of children is +// meaningful. +//////////////////////////////////////////////////////////////////// +bool qpSequenceNode:: +safe_to_combine() const { + return false; +} + //////////////////////////////////////////////////////////////////// // Function: qpSequenceNode::CData::write_datagram // Access: Public, Virtual diff --git a/panda/src/pgraph/qpsequenceNode.h b/panda/src/pgraph/qpsequenceNode.h index 67ff1db6c2..b4730c4836 100644 --- a/panda/src/pgraph/qpsequenceNode.h +++ b/panda/src/pgraph/qpsequenceNode.h @@ -37,6 +37,7 @@ public: qpSequenceNode(const qpSequenceNode ©); virtual PandaNode *make_copy() const; + virtual bool safe_to_combine() const; virtual bool has_cull_callback() const; virtual bool cull_callback(qpCullTraverser *trav, CullTraverserData &data); diff --git a/panda/src/pgraph/workingNodePath.I b/panda/src/pgraph/workingNodePath.I index acdfc2f328..b6cb71fd69 100644 --- a/panda/src/pgraph/workingNodePath.I +++ b/panda/src/pgraph/workingNodePath.I @@ -70,3 +70,13 @@ get_node_path() const { nassertr(result._head != (qpNodePathComponent *)NULL, qpNodePath::fail()); return result; } + +//////////////////////////////////////////////////////////////////// +// Function: WorkingNodePath::node +// Access: Public +// Description: Returns the node traversed to so far. +//////////////////////////////////////////////////////////////////// +INLINE PandaNode *WorkingNodePath:: +node() const { + return _node; +} diff --git a/panda/src/pgraph/workingNodePath.h b/panda/src/pgraph/workingNodePath.h index a92b3b1312..8b69ee8670 100644 --- a/panda/src/pgraph/workingNodePath.h +++ b/panda/src/pgraph/workingNodePath.h @@ -53,6 +53,7 @@ public: INLINE ~WorkingNodePath(); INLINE qpNodePath get_node_path() const; + INLINE PandaNode *node() const; private: PT(qpNodePathComponent) r_get_node_path() const; diff --git a/panda/src/pgui/pgFrameStyle.cxx b/panda/src/pgui/pgFrameStyle.cxx index 9e21384b2c..f3efa2c236 100644 --- a/panda/src/pgui/pgFrameStyle.cxx +++ b/panda/src/pgui/pgFrameStyle.cxx @@ -23,6 +23,7 @@ #include "pandaNode.h" #include "transparencyAttrib.h" #include "pointerTo.h" +#include "qpnodePath.h" #include "geomNode.h" #include "transparencyProperty.h" @@ -168,16 +169,16 @@ generate_into(Node *node, const LVecBase4f &frame) { // indicated size, and parents it to the indicated node, // with a scene graph sort order of -1. // -// The return value is the generated node, if any, or -// NULL if nothing is generated. +// The return value is the generated NodePath, if any, +// or an empty NodePath if nothing is generated. //////////////////////////////////////////////////////////////////// -PandaNode *PGFrameStyle:: -generate_into(PandaNode *node, const LVecBase4f &frame) { +qpNodePath PGFrameStyle:: +generate_into(const qpNodePath &parent, const LVecBase4f &frame) { PT(PandaNode) new_node; switch (_type) { case T_none: - return (PandaNode *)NULL; + return qpNodePath(); case T_flat: new_node = qpgenerate_flat_geom(frame); @@ -209,8 +210,7 @@ generate_into(PandaNode *node, const LVecBase4f &frame) { } // Adding the node to the parent keeps the reference count. - node->add_child(new_node); - return new_node; + return parent.attach_new_node(new_node); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgui/pgFrameStyle.h b/panda/src/pgui/pgFrameStyle.h index 7049f8f0f2..d6930a8945 100644 --- a/panda/src/pgui/pgFrameStyle.h +++ b/panda/src/pgui/pgFrameStyle.h @@ -27,6 +27,7 @@ class NodeRelation; class Node; class PandaNode; +class qpNodePath; //////////////////////////////////////////////////////////////////// // Class : PGFrameStyle @@ -65,7 +66,7 @@ PUBLISHED: public: bool xform(const LMatrix4f &mat); NodeRelation *generate_into(Node *node, const LVecBase4f &frame); - PandaNode *generate_into(PandaNode *node, const LVecBase4f &frame); + qpNodePath generate_into(const qpNodePath &parent, const LVecBase4f &frame); private: PT_Node generate_flat_geom(const LVecBase4f &frame); diff --git a/panda/src/pgui/qppgButton.cxx b/panda/src/pgui/qppgButton.cxx index 5daae15190..0b981d8ca5 100644 --- a/panda/src/pgui/qppgButton.cxx +++ b/panda/src/pgui/qppgButton.cxx @@ -186,10 +186,10 @@ setup(const string &label) { PT(PandaNode) rollover = new PandaNode("rollover"); PT(PandaNode) inactive = new PandaNode("inactive"); - get_state_def(S_ready)->add_child(ready); - get_state_def(S_depressed)->add_child(depressed); - get_state_def(S_rollover)->add_child(rollover); - get_state_def(S_inactive)->add_child(inactive); + get_state_def(S_ready).attach_new_node(ready); + get_state_def(S_depressed).attach_new_node(depressed); + get_state_def(S_rollover).attach_new_node(rollover); + get_state_def(S_inactive).attach_new_node(inactive); ready->add_child(geom); depressed->add_child(geom); diff --git a/panda/src/pgui/qppgEntry.I b/panda/src/pgui/qppgEntry.I index d1af9980b7..67ddfabf15 100644 --- a/panda/src/pgui/qppgEntry.I +++ b/panda/src/pgui/qppgEntry.I @@ -191,7 +191,7 @@ get_blink_rate() const { // the cursor. You can attach suitable cursor geometry // to this node. //////////////////////////////////////////////////////////////////// -INLINE PandaNode *qpPGEntry:: +INLINE const qpNodePath &qpPGEntry:: get_cursor_def() { return _cursor_def; } @@ -204,7 +204,8 @@ get_cursor_def() { //////////////////////////////////////////////////////////////////// INLINE void qpPGEntry:: clear_cursor_def() { - get_cursor_def()->remove_all_children(); + _cursor_def.remove_node(); + _cursor_def = _text_render_root.attach_new_node("cursor"); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgui/qppgEntry.cxx b/panda/src/pgui/qppgEntry.cxx index 5ebc41b211..72e27c17ac 100644 --- a/panda/src/pgui/qppgEntry.cxx +++ b/panda/src/pgui/qppgEntry.cxx @@ -20,6 +20,7 @@ #include "pgMouseWatcherParameter.h" #include "qpcullTraverser.h" +#include "cullTraverserData.h" #include "throw_event.h" #include "transformState.h" #include "mouseWatcherParameter.h" @@ -50,10 +51,8 @@ qpPGEntry(const string &name) : _blink_start = 0.0f; _blink_rate = 1.0f; - _text_render_root = new PandaNode("text_root"); - _current_text_node = (PandaNode *)NULL; - _cursor_def = new PandaNode("cursor"); - _text_render_root->add_child(_cursor_def); + _text_render_root = qpNodePath("text_root"); + _cursor_def = _text_render_root.attach_new_node("cursor"); _cursor_visible = true; _cursor_keys_active = true; @@ -149,8 +148,8 @@ cull_callback(qpCullTraverser *trav, CullTraverserData &data) { update_cursor(); // Now render the text. - nassertr(_text_render_root != (PandaNode *)NULL, true); - trav->traverse(_text_render_root, data); + CullTraverserData next_data(data, _text_render_root.node()); + trav->traverse(next_data); // Now continue to render everything else below this node. return true; @@ -596,12 +595,12 @@ setup(float width, int num_lines) { ls.set_color(0.0f, 0.0f, 0.0f, 1.0f); ls.move_to(0.0f, 0.0f, -0.15f * line_height); ls.draw_to(0.0f, 0.0f, 0.85f * line_height); - get_cursor_def()->add_child(ls.create()); + get_cursor_def().attach_new_node(ls.create()); /* // An underscore cursor would work too. text_node->set_text("_"); - get_cursor_def()->add_child(text_node->generate()); + get_cursor_def().attach_new_node(text_node->generate()); */ } @@ -782,11 +781,11 @@ update_text() { line._left = _last_text_def->get_left(); } - if (_current_text_node != (PandaNode *)NULL) { - _text_render_root->remove_child(_current_text_node); + if (!_current_text.is_empty()) { + _current_text.remove_node(); } - _current_text_node = _last_text_def->generate(); - _text_render_root->add_child(_current_text_node); + _current_text = + _text_render_root.attach_new_node(_last_text_def->generate()); _text_geom_stale = false; _cursor_stale = true; } @@ -824,7 +823,7 @@ update_cursor() { float line_height = _last_text_def->get_line_height(); LVecBase3f trans(_ww_lines[row]._left + width, 0.0f, -line_height * row); - _cursor_def->set_transform(TransformState::make_pos(trans)); + _cursor_def.set_pos(trans); _cursor_stale = false; } @@ -851,11 +850,9 @@ void qpPGEntry:: show_hide_cursor(bool visible) { if (visible != _cursor_visible) { if (visible) { - // Reveal the cursor. - _cursor_def->set_draw_mask(DrawMask::all_on()); + _cursor_def.show(); } else { - // Hide the cursor. - _cursor_def->set_draw_mask(DrawMask::all_off()); + _cursor_def.hide(); } _cursor_visible = visible; } diff --git a/panda/src/pgui/qppgEntry.h b/panda/src/pgui/qppgEntry.h index 13d5ca9ccc..f282f1211f 100644 --- a/panda/src/pgui/qppgEntry.h +++ b/panda/src/pgui/qppgEntry.h @@ -88,7 +88,7 @@ PUBLISHED: INLINE void set_blink_rate(float blink_rate); INLINE float get_blink_rate() const; - INLINE PandaNode *get_cursor_def(); + INLINE const qpNodePath &get_cursor_def(); INLINE void clear_cursor_def(); INLINE void set_cursor_keys_active(bool flag); @@ -139,13 +139,12 @@ private: typedef pvector< PT(qpTextNode) > TextDefs; TextDefs _text_defs; - // This node is the root of the subgraph that renders both the text - // and the cursor. - PT(PandaNode) _text_render_root; + // This is the subgraph that renders both the text and the cursor. + qpNodePath _text_render_root; // This is the node for rendering the actual text that is parented // to the above node when the text is generated. - PT(PandaNode) _current_text_node; + qpNodePath _current_text; qpTextNode *_last_text_def; bool _text_geom_stale; @@ -163,7 +162,7 @@ private: // This is the node that represents the cursor geometry. It is also // attached to the above node, and is transformed around and/or // hidden according to the cursor's position and blink state. - PandaNode *_cursor_def; + qpNodePath _cursor_def; double _blink_start; double _blink_rate; diff --git a/panda/src/pgui/qppgItem.cxx b/panda/src/pgui/qppgItem.cxx index 377276ad50..9325d775df 100644 --- a/panda/src/pgui/qppgItem.cxx +++ b/panda/src/pgui/qppgItem.cxx @@ -28,6 +28,7 @@ #include "string_utils.h" #include "qpnodePath.h" #include "qpcullTraverser.h" +#include "cullTraverserData.h" #ifdef HAVE_AUDIO #include "audioSound.h" @@ -118,15 +119,13 @@ xform(const LMatrix4f &mat) { // Transform the individual states and their frame styles. StateDefs::iterator di; for (di = _state_defs.begin(); di != _state_defs.end(); ++di) { - PandaNode *node = (*di)._node; - if (node != (PandaNode *)NULL) { - // Apply the matrix to the previous transform. - node->set_transform(node->get_transform()->compose(TransformState::make_mat(mat))); + qpNodePath &root = (*di)._root; + // Apply the matrix to the previous transform. + root.set_transform(root.get_transform()->compose(TransformState::make_mat(mat))); - // Now flatten the transform into the subgraph. - qpSceneGraphReducer gr; - gr.apply_attribs(node); - } + // Now flatten the transform into the subgraph. + qpSceneGraphReducer gr; + gr.apply_attribs(root.node()); // Transform the frame style too. if ((*di)._frame_style.xform(mat)) { @@ -193,8 +192,9 @@ cull_callback(qpCullTraverser *trav, CullTraverserData &data) { if (has_state_def(get_state())) { // This item has a current state definition that we should use // to render the item. - PandaNode *def = get_state_def(get_state()); - trav->traverse(def, data); + qpNodePath &root = get_state_def(get_state()); + CullTraverserData next_data(data, root.node()); + trav->traverse(next_data); } // Now continue to render everything else below this node. @@ -223,9 +223,9 @@ recompute_internal_bound() { // get_state_def() on each one, to ensure that the frames are // updated correctly before we measure their bounding volumes. for (int i = 0; i < (int)_state_defs.size(); i++) { - PandaNode *node = get_state_def(i); - if (node != (PandaNode *)NULL) { - child_volumes.push_back(&node->get_bound()); + qpNodePath &root = get_state_def(i); + if (!root.is_empty()) { + child_volumes.push_back(&root.node()->get_bound()); } } @@ -582,7 +582,7 @@ has_state_def(int state) const { if (state < 0 || state >= (int)_state_defs.size()) { return false; } - return (_state_defs[state]._node != (PandaNode *)NULL); + return (!_state_defs[state]._root.is_empty()); } //////////////////////////////////////////////////////////////////// @@ -598,12 +598,8 @@ clear_state_def(int state) { return; } - PandaNode *node = _state_defs[state]._node; - if (node != (PandaNode *)NULL) { - node->remove_all_children(); - } - - _state_defs[state]._frame_node = (PandaNode *)NULL; + _state_defs[state]._root = qpNodePath(); + _state_defs[state]._frame = qpNodePath(); _state_defs[state]._frame_stale = true; mark_bound_stale(); @@ -617,14 +613,14 @@ clear_state_def(int state) { // indicated state. The first time this is called for a // particular state index, it may create the Node. //////////////////////////////////////////////////////////////////// -PandaNode *qpPGItem:: +qpNodePath &qpPGItem:: get_state_def(int state) { - nassertr(state >= 0 && state < 1000, (PandaNode *)NULL); // Sanity check. + nassertr(state >= 0 && state < 1000, get_state_def(0)); // Sanity check. slot_state_def(state); - if (_state_defs[state]._node == (PandaNode *)NULL) { + if (_state_defs[state]._root.is_empty()) { // Create a new node. - _state_defs[state]._node = new PandaNode("state_" + format_string(state)); + _state_defs[state]._root = qpNodePath("state_" + format_string(state)); _state_defs[state]._frame_stale = true; } @@ -632,7 +628,7 @@ get_state_def(int state) { update_frame(state); } - return _state_defs[state]._node; + return _state_defs[state]._root; } //////////////////////////////////////////////////////////////////// @@ -641,16 +637,16 @@ get_state_def(int state) { // Description: Parents an instance of the bottom node of the // indicated NodePath to the indicated state index. //////////////////////////////////////////////////////////////////// -void qpPGItem:: +qpNodePath qpPGItem:: instance_to_state_def(int state, const qpNodePath &path) { if (path.is_empty()) { - // If the path is empty, quietly do nothing. - return; + // If the source is empty, quietly do nothing. + return qpNodePath(); } - get_state_def(state)->add_child(path.node()); - mark_bound_stale(); + + return path.instance_to(get_state_def(state)); } //////////////////////////////////////////////////////////////////// @@ -677,8 +673,8 @@ void qpPGItem:: set_frame_style(int state, const PGFrameStyle &style) { // Get the state def node, mainly to ensure that this state is // slotted and listed as having been defined. - PandaNode *def = get_state_def(state); - nassertv(def != (PandaNode *)NULL); + qpNodePath &root = get_state_def(state); + nassertv(!root.is_empty()); _state_defs[state]._frame_style = style; _state_defs[state]._frame_stale = true; @@ -799,13 +795,7 @@ void qpPGItem:: update_frame(int state) { // First, remove the old frame geometry, if any. if (state >= 0 && state < (int)_state_defs.size()) { - PandaNode *old_frame = _state_defs[state]._frame_node; - if (old_frame != (PandaNode *)NULL) { - PandaNode *node = _state_defs[state]._node; - nassertv(node != (PandaNode *)NULL); - node->remove_child(old_frame); - _state_defs[state]._frame_node = (PandaNode *)NULL; - } + _state_defs[state]._frame.remove_node(); } // We must turn off the stale flag first, before we call @@ -815,10 +805,9 @@ update_frame(int state) { // Now create new frame geometry. if (has_frame()) { - PandaNode *node = get_state_def(state); - nassertv(node != (PandaNode *)NULL); - _state_defs[state]._frame_node = - _state_defs[state]._frame_style.generate_into(node, _frame); + qpNodePath &root = get_state_def(state); + _state_defs[state]._frame = + _state_defs[state]._frame_style.generate_into(root, _frame); } } @@ -834,14 +823,7 @@ mark_frames_stale() { StateDefs::iterator di; for (di = _state_defs.begin(); di != _state_defs.end(); ++di) { // Remove the old frame, if any. - PandaNode *old_frame = (*di)._frame_node; - if (old_frame != (PandaNode *)NULL) { - PandaNode *node = (*di)._node; - nassertv(node != (PandaNode *)NULL); - node->remove_child(old_frame); - (*di)._frame_node = (PandaNode *)NULL; - } - + (*di)._frame.remove_node(); (*di)._frame_stale = true; } mark_bound_stale(); diff --git a/panda/src/pgui/qppgItem.h b/panda/src/pgui/qppgItem.h index aec8d49384..fbb084c87d 100644 --- a/panda/src/pgui/qppgItem.h +++ b/panda/src/pgui/qppgItem.h @@ -25,6 +25,7 @@ #include "pgFrameStyle.h" #include "pandaNode.h" +#include "qpnodePath.h" #include "luse.h" #include "pointerTo.h" #include "qptextNode.h" @@ -34,7 +35,6 @@ class PGTop; class MouseWatcherParameter; class AudioSound; -class qpNodePath; //////////////////////////////////////////////////////////////////// // Class : qpPGItem @@ -108,8 +108,8 @@ PUBLISHED: int get_num_state_defs() const; void clear_state_def(int state); bool has_state_def(int state) const; - PandaNode *get_state_def(int state); - void instance_to_state_def(int state, const qpNodePath &chain); + qpNodePath &get_state_def(int state); + qpNodePath instance_to_state_def(int state, const qpNodePath &path); PGFrameStyle get_frame_style(int state); void set_frame_style(int state, const PGFrameStyle &style); @@ -171,9 +171,9 @@ private: class StateDef { public: - PT(PandaNode) _node; + qpNodePath _root; PGFrameStyle _frame_style; - PT(PandaNode) _frame_node; + qpNodePath _frame; bool _frame_stale; }; typedef pvector StateDefs; diff --git a/panda/src/pgui/qppgTop.cxx b/panda/src/pgui/qppgTop.cxx index 7444df7161..153f188172 100644 --- a/panda/src/pgui/qppgTop.cxx +++ b/panda/src/pgui/qppgTop.cxx @@ -118,7 +118,7 @@ cull_callback(qpCullTraverser *trav, CullTraverserData &data) { // PGTop node, for the convenience of PGItems to register themselves // as they are drawn. PGCullTraverser pg_trav(this, trav); - pg_trav.traverse_below(this, data); + pg_trav.traverse_below(data); // We've taken care of the traversal, thank you. return false; diff --git a/panda/src/pgui/qppgWaitBar.cxx b/panda/src/pgui/qppgWaitBar.cxx index 4d792ffb88..d9b197f37f 100644 --- a/panda/src/pgui/qppgWaitBar.cxx +++ b/panda/src/pgui/qppgWaitBar.cxx @@ -34,7 +34,6 @@ qpPGWaitBar(const string &name) : qpPGItem(name) _range = 100.0; _value = 0.0; _bar_state = -1; - _bar_node = (PandaNode *)NULL; } //////////////////////////////////////////////////////////////////// @@ -58,7 +57,6 @@ qpPGWaitBar(const qpPGWaitBar ©) : _value(copy._value) { _bar_state = -1; - _bar_node = (PandaNode *)NULL; } //////////////////////////////////////////////////////////////////// @@ -155,16 +153,12 @@ update() { } // Remove the old bar geometry, if any. - if (_bar_node != (PandaNode *)NULL) { - PandaNode *parent_node = _bar_node->get_parent(0); - parent_node->remove_child(_bar_node); - _bar_node = (PandaNode *)NULL; - } + _bar.remove_node(); // Now create new bar geometry. if (_value != 0.0 && _range != 0.0) { - PandaNode *node = get_state_def(state); - nassertv(node != (PandaNode *)NULL); + qpNodePath &root = get_state_def(state); + nassertv(!root.is_empty()); PGFrameStyle style = get_frame_style(state); const LVecBase4f &frame = get_frame(); @@ -181,7 +175,7 @@ update() { frac = max(min(frac, 1.0f), 0.0f); bar_frame[1] = bar_frame[0] + frac * (bar_frame[1] - bar_frame[0]); - _bar_node = _bar_style.generate_into(node, bar_frame); + _bar = _bar_style.generate_into(root, bar_frame); } // Indicate that the bar is current for this state. diff --git a/panda/src/pgui/qppgWaitBar.h b/panda/src/pgui/qppgWaitBar.h index 55bb9cb6e4..32fcca60e4 100644 --- a/panda/src/pgui/qppgWaitBar.h +++ b/panda/src/pgui/qppgWaitBar.h @@ -63,7 +63,7 @@ private: float _range, _value; int _bar_state; PGFrameStyle _bar_style; - PT(PandaNode) _bar_node; + qpNodePath _bar; public: static TypeHandle get_class_type() {