Browse Source

control effect, etc., needs to be cycled

David Rose 20 years ago
parent
commit
069fb87e7b

+ 13 - 10
panda/src/chan/movingPartBase.cxx

@@ -104,16 +104,19 @@ do_update(PartBundle *root, PartGroup *parent,
 
 
   // See if any of the channel values have changed since last time.
   // See if any of the channel values have changed since last time.
 
 
-  PartBundle::control_iterator bci;
-  for (bci = root->control_begin();
-       !needs_update && bci != root->control_end();
-       ++bci) {
-    AnimControl *control = (*bci);
-    int channel_index = control->get_channel_index();
-    nassertr(channel_index >= 0 && channel_index < (int)_channels.size(), false);
-    AnimChannelBase *channel = _channels[channel_index];
-    if (channel != (AnimChannelBase*)NULL) {
-      needs_update = control->channel_has_changed(channel);
+  {
+    PartBundle::CDReader cdata(root->_cycler);
+    PartBundle::ChannelBlend::const_iterator bci;
+    for (bci = cdata->_blend.begin();
+         !needs_update && bci != cdata->_blend.end();
+         ++bci) {
+      AnimControl *control = (*bci).first;
+      int channel_index = control->get_channel_index();
+      nassertr(channel_index >= 0 && channel_index < (int)_channels.size(), false);
+      AnimChannelBase *channel = _channels[channel_index];
+      if (channel != (AnimChannelBase*)NULL) {
+        needs_update = control->channel_has_changed(channel);
+      }
     }
     }
   }
   }
 
 

+ 9 - 9
panda/src/chan/movingPartMatrix.cxx

@@ -63,15 +63,15 @@ make_initial_channel() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MovingPartMatrix::
 void MovingPartMatrix::
 get_blend_value(const PartBundle *root) {
 get_blend_value(const PartBundle *root) {
-  const PartBundle::ChannelBlend &blend = root->get_blend_map();
+  PartBundle::CDReader cdata(root->_cycler);
 
 
-  if (blend.empty()) {
+  if (cdata->_blend.empty()) {
     // No channel is bound; supply the default value.
     // No channel is bound; supply the default value.
     _value = _initial_value;
     _value = _initial_value;
 
 
-  } else if (blend.size() == 1) {
+  } else if (cdata->_blend.size() == 1) {
     // A single value, the normal case.
     // A single value, the normal case.
-    AnimControl *control = (*blend.begin()).first;
+    AnimControl *control = (*cdata->_blend.begin()).first;
 
 
     int channel_index = control->get_channel_index();
     int channel_index = control->get_channel_index();
     nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
     nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
@@ -87,7 +87,7 @@ get_blend_value(const PartBundle *root) {
   } else {
   } else {
     // A blend of two or more values.
     // A blend of two or more values.
 
 
-    switch (root->get_blend_type()) {
+    switch (cdata->_blend_type) {
     case PartBundle::BT_single:
     case PartBundle::BT_single:
     case PartBundle::BT_linear:
     case PartBundle::BT_linear:
       {
       {
@@ -96,7 +96,7 @@ get_blend_value(const PartBundle *root) {
         float net = 0.0f;
         float net = 0.0f;
         
         
         PartBundle::ChannelBlend::const_iterator cbi;
         PartBundle::ChannelBlend::const_iterator cbi;
-        for (cbi = blend.begin(); cbi != blend.end(); ++cbi) {
+        for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
           AnimControl *control = (*cbi).first;
           AnimControl *control = (*cbi).first;
           float effect = (*cbi).second;
           float effect = (*cbi).second;
           nassertv(effect != 0.0f);
           nassertv(effect != 0.0f);
@@ -135,7 +135,7 @@ get_blend_value(const PartBundle *root) {
         float net = 0.0f;
         float net = 0.0f;
         
         
         PartBundle::ChannelBlend::const_iterator cbi;
         PartBundle::ChannelBlend::const_iterator cbi;
-        for (cbi = blend.begin(); cbi != blend.end(); ++cbi) {
+        for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
           AnimControl *control = (*cbi).first;
           AnimControl *control = (*cbi).first;
           float effect = (*cbi).second;
           float effect = (*cbi).second;
           nassertv(effect != 0.0f);
           nassertv(effect != 0.0f);
@@ -184,7 +184,7 @@ get_blend_value(const PartBundle *root) {
         float net = 0.0f;
         float net = 0.0f;
         
         
         PartBundle::ChannelBlend::const_iterator cbi;
         PartBundle::ChannelBlend::const_iterator cbi;
-        for (cbi = blend.begin(); cbi != blend.end(); ++cbi) {
+        for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
           AnimControl *control = (*cbi).first;
           AnimControl *control = (*cbi).first;
           float effect = (*cbi).second;
           float effect = (*cbi).second;
           nassertv(effect != 0.0f);
           nassertv(effect != 0.0f);
@@ -232,7 +232,7 @@ get_blend_value(const PartBundle *root) {
         float net = 0.0f;
         float net = 0.0f;
         
         
         PartBundle::ChannelBlend::const_iterator cbi;
         PartBundle::ChannelBlend::const_iterator cbi;
-        for (cbi = blend.begin(); cbi != blend.end(); ++cbi) {
+        for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
           AnimControl *control = (*cbi).first;
           AnimControl *control = (*cbi).first;
           float effect = (*cbi).second;
           float effect = (*cbi).second;
           nassertv(effect != 0.0f);
           nassertv(effect != 0.0f);

+ 5 - 5
panda/src/chan/movingPartScalar.cxx

@@ -48,15 +48,15 @@ MovingPartScalar::
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MovingPartScalar::
 void MovingPartScalar::
 get_blend_value(const PartBundle *root) {
 get_blend_value(const PartBundle *root) {
-  const PartBundle::ChannelBlend &blend = root->get_blend_map();
+  PartBundle::CDReader cdata(root->_cycler);
 
 
-  if (blend.empty()) {
+  if (cdata->_blend.empty()) {
     // No channel is bound; supply the default value.
     // No channel is bound; supply the default value.
     _value = _initial_value;
     _value = _initial_value;
 
 
-  } else if (blend.size() == 1) {
+  } else if (cdata->_blend.size() == 1) {
     // A single value, the normal case.
     // A single value, the normal case.
-    AnimControl *control = (*blend.begin()).first;
+    AnimControl *control = (*cdata->_blend.begin()).first;
 
 
     int channel_index = control->get_channel_index();
     int channel_index = control->get_channel_index();
     nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
     nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
@@ -75,7 +75,7 @@ get_blend_value(const PartBundle *root) {
     float net = 0.0f;
     float net = 0.0f;
 
 
     PartBundle::ChannelBlend::const_iterator cbi;
     PartBundle::ChannelBlend::const_iterator cbi;
-    for (cbi = blend.begin(); cbi != blend.end(); ++cbi) {
+    for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
       AnimControl *control = (*cbi).first;
       AnimControl *control = (*cbi).first;
       float effect = (*cbi).second;
       float effect = (*cbi).second;
       nassertv(effect != 0.0f);
       nassertv(effect != 0.0f);

+ 31 - 39
panda/src/chan/partBundle.I

@@ -25,7 +25,8 @@
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PartBundle::BlendType PartBundle::
 INLINE PartBundle::BlendType PartBundle::
 get_blend_type() const {
 get_blend_type() const {
-  return _blend_type;
+  CDReader cdata(_cycler);
+  return cdata->_blend_type;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -39,50 +40,41 @@ get_node() const {
   return _node;
   return _node;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: PartBundle::control_begin
-//       Access: Public
-//  Description: Returns an iterator that can be used to traverse the
-//               entire set of AnimControls currently in effect.
-////////////////////////////////////////////////////////////////////
-INLINE PartBundle::control_iterator PartBundle::
-control_begin() const {
-  return _blend.begin();
-}
-
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: PartBundle::control_end
-//       Access: Public
-//  Description: Returns an iterator that can be used to traverse the
-//               entire set of AnimControls currently in effect.
+//     Function: PartBundle::set_control_effect
+//       Access: Published
+//  Description: Sets the amount by which the character is affected by
+//               the indicated AnimControl (and its associated
+//               animation).  Normally, this will only be zero or one.
+//               Zero indicates the animation does not affect the
+//               character, and one means it does.
+//
+//               If the blend_type is not BT_single (see
+//               set_blend_type()), it is possible to have multiple
+//               AnimControls in effect simultaneously.  In this case,
+//               the effect is a weight that indicates the relative
+//               importance of each AnimControl to the final
+//               animation.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE PartBundle::control_iterator PartBundle::
-control_end() const {
-  return _blend.end();
-}
+void PartBundle::
+set_control_effect(AnimControl *control, float effect) {
+  nassertv(Thread::get_current_pipeline_stage() == 0);
 
 
-
-////////////////////////////////////////////////////////////////////
-//     Function: PartBundle::control_size
-//       Access: Public
-//  Description: Returns the number of entries between control_begin()
-//               and control_end(): the number of AnimControls
-//               currently in effect.
-////////////////////////////////////////////////////////////////////
-INLINE PartBundle::control_size_type PartBundle::
-control_size() const {
-  return _blend.size();
+  CDWriter cdata(_cycler);
+  do_set_control_effect(control, effect, cdata);
 }
 }
 
 
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: PartBundle::get_blend_map
-//       Access: Public
-//  Description: Returns the entire mapping of AnimControls to blend
-//               effect.
+//     Function: PartBundle::get_control_effect
+//       Access: Published
+//  Description: Returns the amount by which the character is affected
+//               by the indicated AnimControl and its associated
+//               animation.  See set_control_effect().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-INLINE const PartBundle::ChannelBlend &PartBundle::
-get_blend_map() const {
-  return _blend;
+INLINE float PartBundle::
+get_control_effect(AnimControl *control) const {
+  CDReader cdata(_cycler);
+  return do_get_control_effect(control, cdata);
 }
 }
+

+ 176 - 136
panda/src/chan/partBundle.cxx

@@ -41,12 +41,10 @@ TypeHandle PartBundle::_type_handle;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PartBundle::
 PartBundle::
 PartBundle(const PartBundle &copy) :
 PartBundle(const PartBundle &copy) :
-  PartGroup(copy),
-  _blend_type(copy._blend_type)
+  PartGroup(copy)
 {
 {
-  _last_control_set = NULL;
-  _net_blend = 0.0f;
-  _anim_changed = false;
+  CDWriter cdata(_cycler, true);
+  cdata->_blend_type = copy.get_blend_type();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -58,11 +56,6 @@ PartBundle(const PartBundle &copy) :
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 PartBundle::
 PartBundle::
 PartBundle(const string &name) : PartGroup(name) {
 PartBundle(const string &name) : PartGroup(name) {
-  _blend_type = BT_single;
-
-  _last_control_set = NULL;
-  _net_blend = 0.0f;
-  _anim_changed = false;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -99,19 +92,23 @@ make_copy() const {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PartBundle::
 void PartBundle::
 set_blend_type(BlendType bt) {
 set_blend_type(BlendType bt) {
-  if (_blend_type != bt) {
-    _blend_type = bt;
+  nassertv(Thread::get_current_pipeline_stage() == 0);
+
+  CDReader cdata(_cycler);
+  if (cdata->_blend_type != bt) {
+    CDWriter cdataw(_cycler, cdata);
+    cdataw->_blend_type = bt;
 
 
-    if (_blend_type == BT_single && control_size() > 1) {
+    if (cdataw->_blend_type == BT_single && cdataw->_blend.size() > 1) {
       // If we just changed to a single blend type, i.e. no blending,
       // If we just changed to a single blend type, i.e. no blending,
       // we should eliminate all the AnimControls other than the
       // we should eliminate all the AnimControls other than the
       // most-recently-added one.
       // most-recently-added one.
 
 
-      nassertv(_last_control_set != NULL);
-      clear_and_stop_intersecting(_last_control_set);
+      nassertv(cdataw->_last_control_set != NULL);
+      clear_and_stop_intersecting(cdataw->_last_control_set, cdataw);
     }
     }
 
 
-    _anim_changed = true;
+    cdataw->_anim_changed = true;
   }
   }
 }
 }
 
 
@@ -132,84 +129,17 @@ set_blend_type(BlendType bt) {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PartBundle::
 void PartBundle::
 clear_control_effects() {
 clear_control_effects() {
-  if (!_blend.empty()) {
-    _blend.clear();
-    _net_blend = 0.0f;
-    _anim_changed = true;
-  }
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: PartBundle::set_control_effect
-//       Access: Published
-//  Description: Sets the amount by which the character is affected by
-//               the indicated AnimControl (and its associated
-//               animation).  Normally, this will only be zero or one.
-//               Zero indicates the animation does not affect the
-//               character, and one means it does.
-//
-//               If the blend_type is not BT_single (see
-//               set_blend_type()), it is possible to have multiple
-//               AnimControls in effect simultaneously.  In this case,
-//               the effect is a weight that indicates the relative
-//               importance of each AnimControl to the final
-//               animation.
-////////////////////////////////////////////////////////////////////
-void PartBundle::
-set_control_effect(AnimControl *control, float effect) {
-  nassertv(control->get_part() == this);
-
-  if (effect == 0.0f) {
-    // An effect of zero means to eliminate the control.
-    ChannelBlend::iterator cbi = _blend.find(control);
-    if (cbi != _blend.end()) {
-      _blend.erase(cbi);
-      _anim_changed = true;
-    }
-
-  } else {
-    // Otherwise we define it.
-
-    // If we currently have BT_single, we only allow one AnimControl
-    // at a time.  Stop all of the other AnimControls.
-    if (get_blend_type() == BT_single) {
-      clear_and_stop_intersecting(control);
-    }
-
-    if (get_control_effect(control) != effect) {
-      _blend[control] = effect;
-      _anim_changed = true;
-    }
-    _last_control_set = control;
-  }
-
-  recompute_net_blend();
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: PartBundle::get_control_effect
-//       Access: Published
-//  Description: Returns the amount by which the character is affected
-//               by the indicated AnimControl and its associated
-//               animation.  See set_control_effect().
-////////////////////////////////////////////////////////////////////
-float PartBundle::
-get_control_effect(AnimControl *control) {
-  nassertr(control->get_part() == this, 0.0f);
-
-  ChannelBlend::iterator cbi = _blend.find(control);
-  if (cbi == _blend.end()) {
-    // The control is not in effect.
-    return 0.0f;
-  } else {
-    return (*cbi).second;
+  nassertv(Thread::get_current_pipeline_stage() == 0);
+
+  CDReader cdata(_cycler);
+  if (!cdata->_blend.empty()) {
+    CDWriter cdataw(_cycler, cdata);
+    cdataw->_blend.clear();
+    cdataw->_net_blend = 0.0f;
+    cdataw->_anim_changed = true;
   }
   }
 }
 }
 
 
-
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PartBundle::output
 //     Function: PartBundle::output
 //       Access: Published, Virtual
 //       Access: Published, Virtual
@@ -261,6 +191,8 @@ write(ostream &out, int indent_level) const {
 PT(AnimControl) PartBundle::
 PT(AnimControl) PartBundle::
 bind_anim(AnimBundle *anim, int hierarchy_match_flags,
 bind_anim(AnimBundle *anim, int hierarchy_match_flags,
           const PartSubset &subset) {
           const PartSubset &subset) {
+  nassertr(Thread::get_current_pipeline_stage() == 0, NULL);
+
   if ((hierarchy_match_flags & HMF_ok_wrong_root_name) == 0) {
   if ((hierarchy_match_flags & HMF_ok_wrong_root_name) == 0) {
     // Make sure the root names match.
     // Make sure the root names match.
     if (get_name() != anim->get_name()) {
     if (get_name() != anim->get_name()) {
@@ -308,15 +240,22 @@ bind_anim(AnimBundle *anim, int hierarchy_match_flags,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PartBundle::
 bool PartBundle::
 update() {
 update() {
-  bool any_changed = do_update(this, NULL, false, _anim_changed);
+  bool anim_changed;
+  {
+    CDReader cdata(_cycler);
+    anim_changed = cdata->_anim_changed;
+  }
+  bool any_changed = do_update(this, NULL, false, anim_changed);
 
 
   // Now update all the controls for next time.
   // Now update all the controls for next time.
+  CDWriter cdata(_cycler, false);
   ChannelBlend::const_iterator cbi;
   ChannelBlend::const_iterator cbi;
-  for (cbi = _blend.begin(); cbi != _blend.end(); ++cbi) {
+  for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
     AnimControl *control = (*cbi).first;
     AnimControl *control = (*cbi).first;
     control->mark_channels();
     control->mark_channels();
   }
   }
-  _anim_changed = false;
+  
+  cdata->_anim_changed = false;
 
 
   return any_changed;
   return any_changed;
 }
 }
@@ -333,12 +272,14 @@ force_update() {
   bool any_changed = do_update(this, NULL, true, true);
   bool any_changed = do_update(this, NULL, true, true);
 
 
   // Now update all the controls for next time.
   // Now update all the controls for next time.
+  CDWriter cdata(_cycler, false);
   ChannelBlend::const_iterator cbi;
   ChannelBlend::const_iterator cbi;
-  for (cbi = _blend.begin(); cbi != _blend.end(); ++cbi) {
+  for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
     AnimControl *control = (*cbi).first;
     AnimControl *control = (*cbi).first;
     control->mark_channels();
     control->mark_channels();
   }
   }
-  _anim_changed = false;
+  
+  cdata->_anim_changed = false;
 
 
   return any_changed;
   return any_changed;
 }
 }
@@ -353,31 +294,128 @@ force_update() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PartBundle::
 void PartBundle::
 control_activated(AnimControl *control) {
 control_activated(AnimControl *control) {
+  nassertv(Thread::get_current_pipeline_stage() == 0);
   nassertv(control->get_part() == this);
   nassertv(control->get_part() == this);
 
 
+  CDReader cdata(_cycler);
   // If (and only if) our blend type is BT_single, which means no
   // If (and only if) our blend type is BT_single, which means no
   // blending, then starting an animation implicitly enables it.
   // blending, then starting an animation implicitly enables it.
-  if (get_blend_type() == BT_single) {
-    set_control_effect(control, 1.0f);
+  if (cdata->_blend_type == BT_single) {
+    CDWriter cdataw(_cycler, cdata);
+    do_set_control_effect(control, 1.0f, cdataw);
   }
   }
 }
 }
 
 
 
 
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PartBundle::do_set_control_effect
+//       Access: Private
+//  Description: The private implementation of set_control_effect().
+////////////////////////////////////////////////////////////////////
+void PartBundle::
+do_set_control_effect(AnimControl *control, float effect, CData *cdata) {
+  nassertv(control->get_part() == this);
+
+  if (effect == 0.0f) {
+    // An effect of zero means to eliminate the control.
+    ChannelBlend::iterator cbi = cdata->_blend.find(control);
+    if (cbi != cdata->_blend.end()) {
+      cdata->_blend.erase(cbi);
+      cdata->_anim_changed = true;
+    }
+
+  } else {
+    // Otherwise we define it.
+
+    // If we currently have BT_single, we only allow one AnimControl
+    // at a time.  Stop all of the other AnimControls.
+    if (cdata->_blend_type == BT_single) {
+      clear_and_stop_intersecting(control, cdata);
+    }
+
+    if (do_get_control_effect(control, cdata) != effect) {
+      cdata->_blend[control] = effect;
+      cdata->_anim_changed = true;
+    }
+    cdata->_last_control_set = control;
+  }
+
+  recompute_net_blend(cdata);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartBundle::do_get_control_effect
+//       Access: Private
+//  Description: The private implementation of get_control_effect().
+////////////////////////////////////////////////////////////////////
+float PartBundle::
+do_get_control_effect(AnimControl *control, const CData *cdata) const {
+  nassertr(control->get_part() == this, 0.0f);
+
+  ChannelBlend::const_iterator cbi = cdata->_blend.find(control);
+  if (cbi == cdata->_blend.end()) {
+    // The control is not in effect.
+    return 0.0f;
+  } else {
+    return (*cbi).second;
+  }
+}
+
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PartBundle::recompute_net_blend
 //     Function: PartBundle::recompute_net_blend
-//       Access: Protected
+//       Access: Private
 //  Description: Recomputes the total blending amount after a control
 //  Description: Recomputes the total blending amount after a control
 //               effect has been adjusted.  This value must be kept
 //               effect has been adjusted.  This value must be kept
 //               up-to-date so we can normalize the blending amounts.
 //               up-to-date so we can normalize the blending amounts.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PartBundle::
 void PartBundle::
-recompute_net_blend() {
-  _net_blend = 0.0f;
+recompute_net_blend(CData *cdata) {
+  cdata->_net_blend = 0.0f;
 
 
   ChannelBlend::const_iterator bti;
   ChannelBlend::const_iterator bti;
-  for (bti = _blend.begin(); bti != _blend.end(); ++bti) {
-    _net_blend += (*bti).second;
+  for (bti = cdata->_blend.begin(); bti != cdata->_blend.end(); ++bti) {
+    cdata->_net_blend += (*bti).second;
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartBundle::clear_and_stop_intersecting
+//       Access: Private
+//  Description: Removes and stops all the currently activated
+//               AnimControls that animate some joints also animated
+//               by the indicated AnimControl.  This is a special
+//               internal function that's only called when _blend_type
+//               is BT_single, to automatically stop all the other
+//               currently-executing animations.
+////////////////////////////////////////////////////////////////////
+void PartBundle::
+clear_and_stop_intersecting(AnimControl *control, CData *cdata) {
+  double new_net_blend = 0.0f;
+  ChannelBlend new_blend;
+  bool any_changed = false;
+
+  ChannelBlend::iterator cbi;
+  for (cbi = cdata->_blend.begin(); cbi != cdata->_blend.end(); ++cbi) {
+    AnimControl *ac = (*cbi).first;
+    if (ac == control ||
+        !ac->get_bound_joints().has_bits_in_common(control->get_bound_joints())) {
+      // Save this control--it's either the target control, or it has
+      // no joints in common with the target control.
+      new_blend.insert(new_blend.end(), (*cbi));
+      new_net_blend += (*cbi).second;
+    } else {
+      // Remove and stop this control.
+      ac->stop();
+      any_changed = true;
+    }
+  }
+
+  if (any_changed) {
+    cdata->_net_blend = new_net_blend;
+    cdata->_blend.swap(new_blend);
+    cdata->_anim_changed = true;
   }
   }
 }
 }
 
 
@@ -423,40 +461,42 @@ register_with_read_factory()
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: PartBundle::clear_and_stop_intersecting
-//       Access: Protected
-//  Description: Removes and stops all the currently activated
-//               AnimControls that animate some joints also animated
-//               by the indicated AnimControl.  This is a special
-//               internal function that's only called when _blend_type
-//               is BT_single, to automatically stop all the other
-//               currently-executing animations.
+//     Function: PartBundle::CData::Constructor
+//       Access: Public
+//  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void PartBundle::
-clear_and_stop_intersecting(AnimControl *control) {
-  double new_net_blend = 0.0f;
-  ChannelBlend new_blend;
-  bool any_changed = false;
+PartBundle::CData::
+CData() {
+  _blend_type = BT_single;
+  _last_control_set = NULL;
+  _net_blend = 0.0f;
+  _anim_changed = false;
+}
 
 
-  ChannelBlend::iterator cbi;
-  for (cbi = _blend.begin(); cbi != _blend.end(); ++cbi) {
-    AnimControl *ac = (*cbi).first;
-    if (ac == control ||
-        !ac->get_bound_joints().has_bits_in_common(control->get_bound_joints())) {
-      // Save this control--it's either the target control, or it has
-      // no joints in common with the target control.
-      new_blend.insert(new_blend.end(), (*cbi));
-      new_net_blend += (*cbi).second;
-    } else {
-      // Remove and stop this control.
-      ac->stop();
-      any_changed = true;
-    }
-  }
+////////////////////////////////////////////////////////////////////
+//     Function: PartBundle::CData::Copy Constructor
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+PartBundle::CData::
+CData(const PartBundle::CData &copy) :
+  _blend_type(copy._blend_type),
+  _last_control_set(copy._last_control_set),
+  _blend(copy._blend),
+  _net_blend(copy._net_blend),
+  _anim_changed(copy._anim_changed)
+{
+  // Note that this copy constructor is not used by the PartBundle
+  // copy constructor!  Any elements that must be copied between
+  // PartBundles should also be explicitly copied there.
+}
 
 
-  if (any_changed) {
-    _net_blend = new_net_blend;
-    _blend.swap(new_blend);
-    _anim_changed = true;
-  }
+////////////////////////////////////////////////////////////////////
+//     Function: PartBundle::CData::make_copy
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+CycleData *PartBundle::CData::
+make_copy() const {
+  return new CData(*this);
 }
 }

+ 33 - 23
panda/src/chan/partBundle.h

@@ -25,7 +25,6 @@
 #include "animControl.h"
 #include "animControl.h"
 #include "partSubset.h"
 #include "partSubset.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
-#include "iterator_types.h"
 
 
 class AnimBundle;
 class AnimBundle;
 class PartBundleNode;
 class PartBundleNode;
@@ -44,9 +43,6 @@ public:
   // do_update() call to specify the channels that are in effect.
   // do_update() call to specify the channels that are in effect.
   typedef pmap<AnimControl *, float> ChannelBlend;
   typedef pmap<AnimControl *, float> ChannelBlend;
 
 
-  typedef first_of_pair_iterator<ChannelBlend::const_iterator> control_iterator;
-  typedef ChannelBlend::size_type control_size_type;
-
 protected:
 protected:
   // The copy constructor is protected; use make_copy() or copy_subgraph().
   // The copy constructor is protected; use make_copy() or copy_subgraph().
   PartBundle(const PartBundle &copy);
   PartBundle(const PartBundle &copy);
@@ -105,8 +101,8 @@ PUBLISHED:
   INLINE PartBundleNode *get_node() const;
   INLINE PartBundleNode *get_node() const;
 
 
   void clear_control_effects();
   void clear_control_effects();
-  void set_control_effect(AnimControl *control, float effect);
-  float get_control_effect(AnimControl *control);
+  INLINE void set_control_effect(AnimControl *control, float effect);
+  INLINE float get_control_effect(AnimControl *control) const;
 
 
   virtual void output(ostream &out) const;
   virtual void output(ostream &out) const;
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
@@ -116,15 +112,6 @@ PUBLISHED:
                             const PartSubset &subset = PartSubset());
                             const PartSubset &subset = PartSubset());
 
 
 public:
 public:
-  // The following functions may be used to traverse the set of
-  // controls applied to the PartBundle.  Beware!  These are not safe
-  // to use outside of PANDA.DLL.
-  INLINE control_iterator control_begin() const;
-  INLINE control_iterator control_end() const;
-  INLINE control_size_type control_size() const;
-
-  INLINE const ChannelBlend &get_blend_map() const;
-
   // The following functions aren't really part of the public
   // The following functions aren't really part of the public
   // interface; they're just public so we don't have to declare a
   // interface; they're just public so we don't have to declare a
   // bunch of friends.
   // bunch of friends.
@@ -133,17 +120,37 @@ public:
   bool force_update();
   bool force_update();
   virtual void control_activated(AnimControl *control);
   virtual void control_activated(AnimControl *control);
 
 
-protected:
-  void recompute_net_blend();
-  void clear_and_stop_intersecting(AnimControl *control);
+private:
+  class CData;
+
+  void do_set_control_effect(AnimControl *control, float effect, CData *cdata);
+  float do_get_control_effect(AnimControl *control, const CData *cdata) const;
+  void recompute_net_blend(CData *cdata);
+  void clear_and_stop_intersecting(AnimControl *control, CData *cdata);
 
 
-  BlendType _blend_type;
   PartBundleNode *_node;
   PartBundleNode *_node;
 
 
-  AnimControl *_last_control_set;
-  ChannelBlend _blend;
-  float _net_blend;
-  bool _anim_changed;
+  // This is the data that must be cycled between pipeline stages.
+  class CData : public CycleData {
+  public:
+    CData();
+    CData(const CData &copy);
+
+    virtual CycleData *make_copy() const;
+    virtual TypeHandle get_parent_type() const {
+      return PartBundle::get_class_type();
+    }
+
+    BlendType _blend_type;
+    AnimControl *_last_control_set;
+    ChannelBlend _blend;
+    float _net_blend;
+    bool _anim_changed;
+  };
+
+  PipelineCycler<CData> _cycler;
+  typedef CycleDataReader<CData> CDReader;
+  typedef CycleDataWriter<CData> CDWriter;
 
 
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();
@@ -170,6 +177,9 @@ private:
   static TypeHandle _type_handle;
   static TypeHandle _type_handle;
 
 
   friend class PartBundleNode;
   friend class PartBundleNode;
+  friend class MovingPartBase;
+  friend class MovingPartMatrix;
+  friend class MovingPartScalar;
 };
 };
 
 
 inline ostream &operator <<(ostream &out, const PartBundle &bundle) {
 inline ostream &operator <<(ostream &out, const PartBundle &bundle) {