diff --git a/panda/src/chan/Sources.pp b/panda/src/chan/Sources.pp index 4af481ac68..1fc088b628 100644 --- a/panda/src/chan/Sources.pp +++ b/panda/src/chan/Sources.pp @@ -26,6 +26,7 @@ movingPartBase.I movingPartBase.h \ movingPartMatrix.I movingPartMatrix.h movingPartScalar.I \ movingPartScalar.h partBundle.I partBundle.N partBundle.h \ + partBundleHandle.I partBundleHandle.h \ partBundleNode.I partBundleNode.h \ partGroup.I partGroup.h \ partSubset.I partSubset.h \ @@ -45,6 +46,7 @@ animControlCollection.cxx animGroup.cxx auto_bind.cxx \ config_chan.cxx movingPartBase.cxx movingPartMatrix.cxx \ movingPartScalar.cxx partBundle.cxx \ + partBundleHandle.cxx \ partBundleNode.cxx \ partGroup.cxx \ partSubset.cxx \ @@ -66,6 +68,7 @@ movingPart.I movingPart.h movingPartBase.I \ movingPartBase.h movingPartMatrix.I movingPartMatrix.h \ movingPartScalar.I movingPartScalar.h partBundle.I partBundle.h \ + partBundleHandle.I partBundleHandle.h \ partBundleNode.I partBundleNode.h \ partGroup.I partGroup.h \ partSubset.I partSubset.h \ diff --git a/panda/src/chan/partBundle.cxx b/panda/src/chan/partBundle.cxx index f99b9b5775..e286cb53b7 100644 --- a/panda/src/chan/partBundle.cxx +++ b/panda/src/chan/partBundle.cxx @@ -124,6 +124,46 @@ set_anim_blend_flag(bool anim_blend_flag) { } } +//////////////////////////////////////////////////////////////////// +// Function: PartBundle::apply_transform +// Access: Published +// Description: Returns a PartBundle that is a duplicate of this one, +// but with the indicated transform applied. If this is +// called multiple times with the same TransformState +// pointer, it returns the same PartBundle each time. +//////////////////////////////////////////////////////////////////// +PT(PartBundle) PartBundle:: +apply_transform(const TransformState *transform) { + if (transform->is_identity()) { + // Trivial no-op. + return this; + } + + AppliedTransforms::iterator ati = _applied_transforms.find(transform); + if (ati != _applied_transforms.end()) { + if ((*ati).first.is_valid_pointer() && + (*ati).second.is_valid_pointer()) { + // Here's our cached result. + return (*ati).second.p(); + } + } + + PT(PartBundle) new_bundle = DCAST(PartBundle, copy_subgraph()); + new_bundle->xform(transform->get_mat()); + + if (ati != _applied_transforms.end()) { + // A stale pointer to a deleted result. Update it. + (*ati).first.refresh(); + (*ati).second = new_bundle; + } else { + // No such result yet. Store it. + bool inserted = _applied_transforms.insert(AppliedTransforms::value_type(transform, new_bundle)).second; + nassertr(inserted, new_bundle); + } + + return new_bundle; +} + //////////////////////////////////////////////////////////////////// // Function: PartBundle::clear_control_effects // Access: Published diff --git a/panda/src/chan/partBundle.h b/panda/src/chan/partBundle.h index b31ba915c9..2c9b9c1dfa 100644 --- a/panda/src/chan/partBundle.h +++ b/panda/src/chan/partBundle.h @@ -32,6 +32,8 @@ #include "cycleDataWriter.h" #include "luse.h" #include "pvector.h" +#include "transformState.h" +#include "weakPointerTo.h" class AnimBundle; class PartBundleNode; @@ -106,6 +108,7 @@ PUBLISHED: INLINE void set_root_xform(const LMatrix4f &root_xform); INLINE void xform(const LMatrix4f &mat); INLINE const LMatrix4f &get_root_xform() const; + PT(PartBundle) apply_transform(const TransformState *transform); INLINE int get_num_nodes() const; INLINE PartBundleNode *get_node(int n) const; @@ -149,6 +152,9 @@ private: typedef pvector Nodes; Nodes _nodes; + typedef pmap AppliedTransforms; + AppliedTransforms _applied_transforms; + // This is the data that must be cycled between pipeline stages. class CData : public CycleData { public: diff --git a/panda/src/chan/partBundleHandle.I b/panda/src/chan/partBundleHandle.I new file mode 100644 index 0000000000..f252b72ca9 --- /dev/null +++ b/panda/src/chan/partBundleHandle.I @@ -0,0 +1,60 @@ +// Filename: partBundleHandle.I +// Created by: drose (01Oct07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: PartBundleHandle::Constructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PartBundleHandle:: +PartBundleHandle(PartBundle *bundle) : + _bundle(bundle) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: PartBundleHandle::Destructor +// Access: Published +// Description: +//////////////////////////////////////////////////////////////////// +INLINE PartBundleHandle:: +~PartBundleHandle() { +} + +//////////////////////////////////////////////////////////////////// +// Function: PartBundleHandle::get_bundle +// Access: Published +// Description: Returns the actual PartBundle embedded within the +// handle. +//////////////////////////////////////////////////////////////////// +INLINE PartBundle *PartBundleHandle:: +get_bundle() { + return _bundle; +} + +//////////////////////////////////////////////////////////////////// +// Function: PartBundleHandle::set_bundle +// Access: Published +// Description: Changes the actual PartBundle embedded within the +// handle. +//////////////////////////////////////////////////////////////////// +INLINE void PartBundleHandle:: +set_bundle(PartBundle *bundle) { + _bundle = bundle; +} diff --git a/panda/src/chan/partBundleHandle.cxx b/panda/src/chan/partBundleHandle.cxx new file mode 100644 index 0000000000..fbf4647fa6 --- /dev/null +++ b/panda/src/chan/partBundleHandle.cxx @@ -0,0 +1,19 @@ +// Filename: partBundleHandle.cxx +// Created by: drose (01Oct07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "partBundleHandle.h" diff --git a/panda/src/chan/partBundleHandle.h b/panda/src/chan/partBundleHandle.h new file mode 100644 index 0000000000..255ce5d787 --- /dev/null +++ b/panda/src/chan/partBundleHandle.h @@ -0,0 +1,57 @@ +// Filename: partBundleHandle.h +// Created by: drose (01Oct07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef PARTBUNDLEHANDLE_H +#define PARTBUNDLEHANDLE_H + +#include "pandabase.h" + +#include "partBundle.h" +#include "pointerTo.h" + +//////////////////////////////////////////////////////////////////// +// Class : PartBundleHandle +// Description : This is a trivial class returned by +// PartBundleNode::get_bundle(). Its purpose is to hold +// the actual PartBundle pointer contained within the +// PartBundleNode, so that scene graph flatten +// operations can safely combine or duplicate +// PartBundles as necessary without affecting high-level +// bundle operations. +// +// The high-level Actor class defined in +// direct/src/actor, for instance, will store a list of +// PartBundleHandles instead of on actual PartBundles, +// so that it will be immune to changes from these +// flatten operations. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_CHAN PartBundleHandle : public ReferenceCount { +PUBLISHED: + INLINE PartBundleHandle(PartBundle *bundle); + INLINE ~PartBundleHandle(); + + INLINE PartBundle *get_bundle(); + INLINE void set_bundle(PartBundle *bundle); + +private: + PT(PartBundle) _bundle; +}; + +#include "partBundleHandle.I" + +#endif diff --git a/panda/src/chan/partBundleNode.I b/panda/src/chan/partBundleNode.I index 8d9b1ec625..ecd798f0ed 100644 --- a/panda/src/chan/partBundleNode.I +++ b/panda/src/chan/partBundleNode.I @@ -73,6 +73,20 @@ get_num_bundles() const { //////////////////////////////////////////////////////////////////// INLINE PartBundle *PartBundleNode:: get_bundle(int n) const { + nassertr(n >= 0 && n < (int)_bundles.size(), NULL); + return _bundles[n]->get_bundle(); +} + +//////////////////////////////////////////////////////////////////// +// Function: PartBundleNode::get_bundle_handle +// Access: Public +// Description: Returns the PartBundleHandle that wraps around the +// actual nth PartBundle. While the PartBundle pointer +// might later change due to a future flatten operation, +// the PartBundleHandle will not. +//////////////////////////////////////////////////////////////////// +INLINE PartBundleHandle *PartBundleNode:: +get_bundle_handle(int n) const { nassertr(n >= 0 && n < (int)_bundles.size(), NULL); return _bundles[n]; } diff --git a/panda/src/chan/partBundleNode.cxx b/panda/src/chan/partBundleNode.cxx index 16e419bf48..0857e33538 100644 --- a/panda/src/chan/partBundleNode.cxx +++ b/panda/src/chan/partBundleNode.cxx @@ -21,6 +21,7 @@ #include "datagramIterator.h" #include "bamReader.h" #include "bamWriter.h" +#include "sceneGraphReducer.h" TypeHandle PartBundleNode::_type_handle; @@ -33,29 +34,34 @@ PartBundleNode:: ~PartBundleNode() { Bundles::iterator bi; for (bi = _bundles.begin(); bi != _bundles.end(); ++bi) { - (*bi)->remove_node(this); + (*bi)->get_bundle()->remove_node(this); } } //////////////////////////////////////////////////////////////////// -// Function: PartBundleNode::safe_to_transform +// Function: PartBundleNode::apply_attribs_to_vertices // Access: Public, Virtual -// Description: Returns true if it is generally safe to transform -// this particular kind of PandaNode by calling the -// xform() method, false otherwise. +// Description: Applies whatever attributes are specified in the +// AccumulatedAttribs object (and by the attrib_types +// bitmask) to the vertices on this node, if +// appropriate. If this node uses geom arrays like a +// GeomNode, the supplied GeomTransformer may be used to +// unify shared arrays across multiple different nodes. +// +// This is a generalization of xform(). //////////////////////////////////////////////////////////////////// -bool PartBundleNode:: -safe_to_transform() const { - // If any of our bundles appear on multiple nodes, we can't - // transform any of them without transforming all of them at once. - Bundles::const_iterator bi; - for (bi = _bundles.begin(); bi != _bundles.end(); ++bi) { - if ((*bi)->get_num_nodes() > 1) { - return false; +void PartBundleNode:: +apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, + GeomTransformer &transformer) { + if ((attrib_types & SceneGraphReducer::TT_transform) != 0) { + Bundles::iterator bi; + for (bi = _bundles.begin(); bi != _bundles.end(); ++bi) { + PT(PartBundleHandle) handle = (*bi); + PartBundle *bundle = handle->get_bundle(); + PT(PartBundle) new_bundle = bundle->apply_transform(attribs._transform); + update_bundle(handle, new_bundle); } } - - return true; } //////////////////////////////////////////////////////////////////// @@ -67,6 +73,10 @@ safe_to_transform() const { //////////////////////////////////////////////////////////////////// void PartBundleNode:: xform(const LMatrix4f &mat) { + // With plain xform(), we can't attempt to share bundles across + // different nodes. Better to use apply_attribs_to_vertices(), + // instead. + if (mat.almost_equal(LMatrix4f::ident_mat())) { // Don't bother. return; @@ -74,7 +84,14 @@ xform(const LMatrix4f &mat) { Bundles::iterator bi; for (bi = _bundles.begin(); bi != _bundles.end(); ++bi) { - (*bi)->xform(mat); + PT(PartBundleHandle) handle = (*bi); + PartBundle *bundle = handle->get_bundle(); + if (bundle->get_num_nodes() > 1) { + PT(PartBundle) new_bundle = DCAST(PartBundle, bundle->copy_subgraph()); + update_bundle(handle, new_bundle); + bundle = new_bundle; + } + bundle->xform(mat); } } @@ -85,8 +102,25 @@ xform(const LMatrix4f &mat) { //////////////////////////////////////////////////////////////////// void PartBundleNode:: add_bundle(PartBundle *bundle) { - _bundles.push_back(bundle); - bundle->add_node(this); + PT(PartBundleHandle) handle = new PartBundleHandle(bundle); + add_bundle_handle(handle); +} + +//////////////////////////////////////////////////////////////////// +// Function: PartBundleNode::add_bundle_handle +// Access: Protected +// Description: +//////////////////////////////////////////////////////////////////// +void PartBundleNode:: +add_bundle_handle(PartBundleHandle *handle) { + Bundles::iterator bi = find(_bundles.begin(), _bundles.end(), handle); + if (bi != _bundles.end()) { + // This handle is already within the node. + return; + } + + _bundles.push_back(handle); + handle->get_bundle()->add_node(this); } //////////////////////////////////////////////////////////////////// @@ -97,16 +131,34 @@ add_bundle(PartBundle *bundle) { //////////////////////////////////////////////////////////////////// void PartBundleNode:: steal_bundles(PartBundleNode *other) { + if (other == this) { + return; + } + Bundles::iterator bi; for (bi = other->_bundles.begin(); bi != other->_bundles.end(); ++bi) { - PartBundle *bundle = (*bi); - _bundles.push_back(bundle); - bundle->remove_node(other); - bundle->add_node(this); + PartBundleHandle *handle = (*bi); + handle->get_bundle()->remove_node(other); + add_bundle_handle(handle); } other->_bundles.clear(); } +//////////////////////////////////////////////////////////////////// +// Function: PartBundleNode::update_bundle +// Access: Protected, Virtual +// Description: Replaces the contents of the indicated +// PartBundleHandle (presumably stored within this node) +// with new_bundle. +//////////////////////////////////////////////////////////////////// +void PartBundleNode:: +update_bundle(PartBundleHandle *old_bundle_handle, PartBundle *new_bundle) { + PartBundle *old_bundle = old_bundle_handle->get_bundle(); + old_bundle->remove_node(this); + old_bundle_handle->set_bundle(new_bundle); + new_bundle->add_node(this); +} + //////////////////////////////////////////////////////////////////// // Function: PartBundleNode::write_datagram // Access: Public, Virtual @@ -120,7 +172,7 @@ write_datagram(BamWriter *manager, Datagram &dg) { dg.add_uint16(_bundles.size()); Bundles::iterator bi; for (bi = _bundles.begin(); bi != _bundles.end(); ++bi) { - manager->write_pointer(dg, (*bi)); + manager->write_pointer(dg, (*bi)->get_bundle()); } } @@ -137,8 +189,9 @@ complete_pointers(TypedWritable **p_list, BamReader* manager) { Bundles::iterator bi; for (bi = _bundles.begin(); bi != _bundles.end(); ++bi) { - (*bi) = DCAST(PartBundle, p_list[pi++]); - (*bi)->add_node(this); + PT(PartBundle) bundle = DCAST(PartBundle, p_list[pi++]); + bundle->add_node(this); + (*bi) = new PartBundleHandle(bundle); } return pi; diff --git a/panda/src/chan/partBundleNode.h b/panda/src/chan/partBundleNode.h index 7429ad3d8c..ac2b8ab589 100644 --- a/panda/src/chan/partBundleNode.h +++ b/panda/src/chan/partBundleNode.h @@ -22,6 +22,7 @@ #include "pandabase.h" #include "partBundle.h" +#include "partBundleHandle.h" #include "pandaNode.h" #include "dcast.h" @@ -43,19 +44,25 @@ protected: public: virtual ~PartBundleNode(); - virtual bool safe_to_transform() const; + virtual void apply_attribs_to_vertices(const AccumulatedAttribs &attribs, + int attrib_types, + GeomTransformer &transformer); virtual void xform(const LMatrix4f &mat); PUBLISHED: INLINE int get_num_bundles() const; INLINE PartBundle *get_bundle(int n) const; + INLINE PartBundleHandle *get_bundle_handle(int n) const; protected: void add_bundle(PartBundle *bundle); + void add_bundle_handle(PartBundleHandle *handle); void steal_bundles(PartBundleNode *other); + virtual void update_bundle(PartBundleHandle *old_bundle_handle, + PartBundle *new_bundle); protected: - typedef pvector< PT(PartBundle) > Bundles; + typedef pvector< PT(PartBundleHandle) > Bundles; Bundles _bundles; public: diff --git a/panda/src/char/character.cxx b/panda/src/char/character.cxx index 8baadd3b75..4d6182fc00 100644 --- a/panda/src/char/character.cxx +++ b/panda/src/char/character.cxx @@ -230,6 +230,43 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any, // pointer, and all geometry within this node will be // updated to reference new_bundle. // +// This method is deprecated. Use the newer version of +// this method, below. +//////////////////////////////////////////////////////////////////// +void Character:: +merge_bundles(PartBundle *old_bundle, PartBundle *new_bundle) { + if (old_bundle == new_bundle) { + // Trivially return. + return; + } + + // Find the PartBundleHandle of old_bundle. + PT(PartBundleHandle) old_bundle_handle; + Bundles::const_iterator bi; + for (bi = _bundles.begin(); bi != _bundles.end(); ++bi) { + if ((*bi)->get_bundle() == old_bundle) { + old_bundle_handle = (*bi); + break; + } + } + nassertv(!old_bundle_handle.is_null()); + + PT(PartBundleHandle) new_bundle_handle = new PartBundleHandle(new_bundle); + merge_bundles(old_bundle_handle, new_bundle_handle); +} + +//////////////////////////////////////////////////////////////////// +// Function: Character::merge_bundles +// Access: Published +// Description: Merges old_bundle_handle->get_bundle() with +// new_bundle. old_bundle_handle must be one of the +// PartBundleHandle within this node. At the end of +// this call, the bundle pointer within the +// old_bundle_handle will be replaced with that within +// the new_bundle_handle pointer, and all geometry +// within this node will be updated to reference +// new_bundle. +// // Normally, this is called when the two bundles have // the same, or nearly the same, hierarchies. In this // case, new_bundle will simply be assigned over the @@ -246,34 +283,9 @@ calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any, // LOD's of the same model. //////////////////////////////////////////////////////////////////// void Character:: -merge_bundles(PartBundle *old_bundle, PartBundle *new_bundle) { - // Find the index number of old_bundle. - size_t index = 0; - while (index < _bundles.size()) { - if (_bundles[index] == old_bundle) { - break; - } - ++index; - } - nassertv_always(index < _bundles.size()); - - if (old_bundle == new_bundle) { - // Trivially return. - return; - } - - // First, merge the bundles themselves. - JointMap joint_map; - r_merge_bundles(joint_map, old_bundle, new_bundle); - old_bundle->remove_node(this); - _bundles[index] = new_bundle; - new_bundle->add_node(this); - - // Now convert the geometry to use the new bundle. - GeomVertexMap gvmap; - GeomJointMap gjmap; - GeomSliderMap gsmap; - r_update_geom(this, joint_map, gvmap, gjmap, gsmap); +merge_bundles(PartBundleHandle *old_bundle_handle, + PartBundleHandle *new_bundle_handle) { + update_bundle(old_bundle_handle, new_bundle_handle->get_bundle()); } //////////////////////////////////////////////////////////////////// @@ -405,28 +417,6 @@ force_update() { } } -//////////////////////////////////////////////////////////////////// -// Function: Character::do_update -// Access: Private -// Description: The actual implementation of update(). Assumes the -// appropriate PStatCollector has already been started. -//////////////////////////////////////////////////////////////////// -void Character:: -do_update() { - // Update all the joints and sliders. - if (even_animation) { - int num_bundles = get_num_bundles(); - for (int i = 0; i < num_bundles; ++i) { - get_bundle(i)->force_update(); - } - } else { - int num_bundles = get_num_bundles(); - for (int i = 0; i < num_bundles; ++i) { - get_bundle(i)->update(); - } - } -} - //////////////////////////////////////////////////////////////////// // Function: Character::r_copy_children // Access: Protected, Virtual @@ -475,6 +465,56 @@ r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map, } } +//////////////////////////////////////////////////////////////////// +// Function: Character::update_bundle +// Access: Protected, Virtual +// Description: Replaces the contents of the indicated +// PartBundleHandle (presumably stored within this node) +// with new_bundle. +//////////////////////////////////////////////////////////////////// +void Character:: +update_bundle(PartBundleHandle *old_bundle_handle, PartBundle *new_bundle) { + if (old_bundle_handle->get_bundle() == new_bundle) { + // Trivially return. + return; + } + + // First, merge the bundles, to ensure we have the same set of + // joints in the new bundle. + JointMap joint_map; + r_merge_bundles(joint_map, old_bundle_handle->get_bundle(), new_bundle); + + PartBundleNode::update_bundle(old_bundle_handle, new_bundle); + + // Now convert the geometry to use the new bundle. + GeomVertexMap gvmap; + GeomJointMap gjmap; + GeomSliderMap gsmap; + r_update_geom(this, joint_map, gvmap, gjmap, gsmap); +} + +//////////////////////////////////////////////////////////////////// +// Function: Character::do_update +// Access: Private +// Description: The actual implementation of update(). Assumes the +// appropriate PStatCollector has already been started. +//////////////////////////////////////////////////////////////////// +void Character:: +do_update() { + // Update all the joints and sliders. + if (even_animation) { + int num_bundles = get_num_bundles(); + for (int i = 0; i < num_bundles; ++i) { + get_bundle(i)->force_update(); + } + } else { + int num_bundles = get_num_bundles(); + for (int i = 0; i < num_bundles; ++i) { + get_bundle(i)->update(); + } + } +} + //////////////////////////////////////////////////////////////////// // Function: Character::fill_joint_map // Access: Private diff --git a/panda/src/char/character.h b/panda/src/char/character.h index 20747878e3..2e59d418be 100644 --- a/panda/src/char/character.h +++ b/panda/src/char/character.h @@ -65,6 +65,8 @@ public: PUBLISHED: INLINE CharacterJointBundle *get_bundle(int i) const; void merge_bundles(PartBundle *old_bundle, PartBundle *other_bundle); + void merge_bundles(PartBundleHandle *old_bundle_handle, + PartBundleHandle *other_bundle_handle); CharacterJoint *find_joint(const string &name) const; CharacterSlider *find_slider(const string &name) const; @@ -76,6 +78,12 @@ PUBLISHED: void update(); void force_update(); +protected: + virtual void r_copy_children(const PandaNode *from, InstanceMap &inst_map, + Thread *current_thread); + virtual void update_bundle(PartBundleHandle *old_bundle_handle, + PartBundle *new_bundle); + private: void do_update(); @@ -85,8 +93,6 @@ private: typedef pmap GeomJointMap; typedef pmap GeomSliderMap; - virtual void r_copy_children(const PandaNode *from, InstanceMap &inst_map, - Thread *current_thread); void fill_joint_map(JointMap &joint_map, PartGroup *copy, PartGroup *orig); void r_merge_bundles(Character::JointMap &joint_map, PartGroup *old_group, PartGroup *new_group); diff --git a/panda/src/express/weakPointerToBase.I b/panda/src/express/weakPointerToBase.I index e32c2d26f4..c0ec5b5dff 100644 --- a/panda/src/express/weakPointerToBase.I +++ b/panda/src/express/weakPointerToBase.I @@ -399,6 +399,24 @@ clear() { reassign((To *)NULL); } +//////////////////////////////////////////////////////////////////// +// Function: WeakPointerToBase::refresh +// Access: Published +// Description: Informs the WeakPointerTo object that its pointer is +// no longer deleted. This may be used after a +// WeakPointerTo has deleted a deleted pointer, and then +// a new pointer has been reallocated. It's equivalent +// to simply reassigning the pointer to its new +// (i.e. original) value, but has the advantage that it +// is const, so can be used for WeakPointers used as +// keys in STL maps and sets. +//////////////////////////////////////////////////////////////////// +template +INLINE void WeakPointerToBase:: +refresh() const { + ((WeakPointerToBase *)this)->reassign((To *)_void_ptr); +} + //////////////////////////////////////////////////////////////////// // Function: WeakPointerToBase::output // Access: Published diff --git a/panda/src/express/weakPointerToBase.h b/panda/src/express/weakPointerToBase.h index 4b3d38a2ed..0c8b427126 100644 --- a/panda/src/express/weakPointerToBase.h +++ b/panda/src/express/weakPointerToBase.h @@ -83,6 +83,7 @@ public: PUBLISHED: INLINE void clear(); + INLINE void refresh() const; void output(ostream &out) const; }; diff --git a/panda/src/pgraph/sceneGraphReducer.cxx b/panda/src/pgraph/sceneGraphReducer.cxx index ae68a72305..ca13facb3d 100644 --- a/panda/src/pgraph/sceneGraphReducer.cxx +++ b/panda/src/pgraph/sceneGraphReducer.cxx @@ -116,7 +116,9 @@ flatten(PandaNode *root, int combine_siblings_bits) { num_pass_nodes += r_flatten(root, child_node, combine_siblings_bits); } - if (combine_siblings_bits != 0 && root->get_num_children() >= 2) { + if (combine_siblings_bits != 0 && + root->get_num_children() >= 2 && + root->safe_to_combine_children()) { num_pass_nodes += flatten_siblings(root, combine_siblings_bits); } @@ -397,7 +399,7 @@ r_flatten(PandaNode *grandparent_node, PandaNode *parent_node, // Finally, if any of our remaining children are plain PandaNodes // with no children, just remove them. - { + if (parent_node->safe_to_combine_children()) { for (int i = parent_node->get_num_children() - 1; i >= 0; --i) { PandaNode *child_node = parent_node->get_child(i); if (child_node->is_exact_type(PandaNode::get_class_type()) &&