Browse Source

don't auto-stop disjoint animations

David Rose 20 years ago
parent
commit
ca8455d5ef

+ 16 - 0
panda/src/chan/animControl.I

@@ -44,3 +44,19 @@ INLINE int AnimControl::
 get_channel_index() const {
 get_channel_index() const {
   return _channel_index;
   return _channel_index;
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimControl::get_bound_joints
+//       Access: Published
+//  Description: Returns the subset of joints controlled by this
+//               AnimControl.  Most of the time, this will be
+//               BitArray::all_on(), for a normal full-body animation.
+//               For a subset animation, however, this will be just a
+//               subset of those bits, corresponding to the set of
+//               joints and sliders actually bound (as enumerated by
+//               bind_hierarchy() in depth-first LIFO order).
+////////////////////////////////////////////////////////////////////
+INLINE const BitArray &AnimControl::
+get_bound_joints() const {
+  return _bound_joints;
+}

+ 3 - 1
panda/src/chan/animControl.cxx

@@ -29,7 +29,8 @@ TypeHandle AnimControl::_type_handle;
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 AnimControl::
 AnimControl::
-AnimControl(PartBundle *part, AnimBundle *anim, int channel_index) {
+AnimControl(PartBundle *part, AnimBundle *anim, int channel_index,
+            const BitArray &bound_joints) {
 #ifdef DO_MEMORY_USAGE
 #ifdef DO_MEMORY_USAGE
   MemoryUsage::update_type(this, get_class_type());
   MemoryUsage::update_type(this, get_class_type());
 #endif
 #endif
@@ -37,6 +38,7 @@ AnimControl(PartBundle *part, AnimBundle *anim, int channel_index) {
   _part = part;
   _part = part;
   _anim = anim;
   _anim = anim;
   _channel_index = channel_index;
   _channel_index = channel_index;
+  _bound_joints = bound_joints;
   set_frame_rate(_anim->get_base_frame_rate());
   set_frame_rate(_anim->get_base_frame_rate());
   set_num_frames(_anim->get_num_frames());
   set_num_frames(_anim->get_num_frames());
 
 

+ 9 - 1
panda/src/chan/animControl.h

@@ -24,6 +24,7 @@
 #include "animInterface.h"
 #include "animInterface.h"
 #include "animBundle.h"
 #include "animBundle.h"
 #include "partGroup.h"
 #include "partGroup.h"
+#include "bitArray.h"
 
 
 #include "referenceCount.h"
 #include "referenceCount.h"
 
 
@@ -40,7 +41,8 @@ class AnimChannelBase;
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 class EXPCL_PANDA AnimControl : public ReferenceCount, public AnimInterface {
 class EXPCL_PANDA AnimControl : public ReferenceCount, public AnimInterface {
 public:
 public:
-  AnimControl(PartBundle *part, AnimBundle *anim, int channel_index);
+  AnimControl(PartBundle *part, AnimBundle *anim, int channel_index,
+              const BitArray &bound_joints);
 
 
 PUBLISHED:
 PUBLISHED:
   virtual ~AnimControl();
   virtual ~AnimControl();
@@ -48,6 +50,7 @@ PUBLISHED:
   PartBundle *get_part() const;
   PartBundle *get_part() const;
   INLINE AnimBundle *get_anim() const;
   INLINE AnimBundle *get_anim() const;
   INLINE int get_channel_index() const;
   INLINE int get_channel_index() const;
+  INLINE const BitArray &get_bound_joints() const;
 
 
   virtual void output(ostream &out) const;
   virtual void output(ostream &out) const;
 
 
@@ -73,6 +76,11 @@ private:
   // This is the frame number as of the last call to mark_channels().
   // This is the frame number as of the last call to mark_channels().
   int _marked_frame;
   int _marked_frame;
 
 
+  // This is the bitmask of joints and/or sliders from the animation
+  // that we have actually bound into this AnimControl.  See
+  // get_bound_joints().
+  BitArray _bound_joints;
+
 public:
 public:
   static TypeHandle get_class_type() {
   static TypeHandle get_class_type() {
     return _type_handle;
     return _type_handle;

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

@@ -16,10 +16,10 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
-
 #include "movingPartBase.h"
 #include "movingPartBase.h"
 #include "animControl.h"
 #include "animControl.h"
 #include "animChannelBase.h"
 #include "animChannelBase.h"
+#include "bitArray.h"
 
 
 #include "indent.h"
 #include "indent.h"
 
 
@@ -207,7 +207,8 @@ pick_channel_index(plist<int> &holes, int &next) const {
 //               hierarchy, at the given channel index number.
 //               hierarchy, at the given channel index number.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void MovingPartBase::
 void MovingPartBase::
-bind_hierarchy(AnimGroup *anim, int channel_index, bool is_included,
+bind_hierarchy(AnimGroup *anim, int channel_index, int &joint_index, 
+               bool is_included, BitArray &bound_joints,
                const PartSubset &subset) {
                const PartSubset &subset) {
   if (chan_cat.is_debug()) {
   if (chan_cat.is_debug()) {
     chan_cat.debug()
     chan_cat.debug()
@@ -229,7 +230,16 @@ bind_hierarchy(AnimGroup *anim, int channel_index, bool is_included,
     } else {
     } else {
       _channels[channel_index] = DCAST(AnimChannelBase, anim);
       _channels[channel_index] = DCAST(AnimChannelBase, anim);
     }
     }
+
+    // Record that we have bound this joint in the bound_joints
+    // BitArray.
+    bound_joints.set_bit(joint_index);
+  } else {
+    // Record that we have *not* bound this particular joint.
+    bound_joints.clear_bit(joint_index);
   }
   }
+  ++joint_index;
 
 
-  PartGroup::bind_hierarchy(anim, channel_index, is_included, subset);
+  PartGroup::bind_hierarchy(anim, channel_index, joint_index, 
+                            is_included, bound_joints, subset);
 }
 }

+ 3 - 1
panda/src/chan/movingPartBase.h

@@ -68,7 +68,9 @@ protected:
 
 
   virtual void pick_channel_index(plist<int> &holes, int &next) const;
   virtual void pick_channel_index(plist<int> &holes, int &next) const;
   virtual void bind_hierarchy(AnimGroup *anim, int channel_index,
   virtual void bind_hierarchy(AnimGroup *anim, int channel_index,
-                              bool is_included, const PartSubset &subset);
+                              int &joint_index, bool is_included, 
+                              BitArray &bound_joints,
+                              const PartSubset &subset);
 
 
   typedef pvector< PT(AnimChannelBase) > Channels;
   typedef pvector< PT(AnimChannelBase) > Channels;
   Channels _channels;
   Channels _channels;

+ 0 - 3
panda/src/chan/movingPartMatrix.cxx

@@ -89,9 +89,6 @@ get_blend_value(const PartBundle *root) {
 
 
     switch (root->get_blend_type()) {
     switch (root->get_blend_type()) {
     case PartBundle::BT_single:
     case PartBundle::BT_single:
-      // This one shouldn't be possible.
-      nassertv(false);
-      
     case PartBundle::BT_linear:
     case PartBundle::BT_linear:
       {
       {
         // An ordinary, linear blend.
         // An ordinary, linear blend.

+ 22 - 12
panda/src/chan/partBundle.cxx

@@ -21,6 +21,7 @@
 #include "animBundle.h"
 #include "animBundle.h"
 #include "animControl.h"
 #include "animControl.h"
 #include "config_chan.h"
 #include "config_chan.h"
+#include "bitArray.h"
 
 
 #include "indent.h"
 #include "indent.h"
 #include "datagram.h"
 #include "datagram.h"
@@ -107,7 +108,7 @@ set_blend_type(BlendType bt) {
       // most-recently-added one.
       // most-recently-added one.
 
 
       nassertv(_last_control_set != NULL);
       nassertv(_last_control_set != NULL);
-      clear_and_stop_except(_last_control_set);
+      clear_and_stop_intersecting(_last_control_set);
     }
     }
 
 
     _anim_changed = true;
     _anim_changed = true;
@@ -173,7 +174,7 @@ set_control_effect(AnimControl *control, float effect) {
     // If we currently have BT_single, we only allow one AnimControl
     // If we currently have BT_single, we only allow one AnimControl
     // at a time.  Stop all of the other AnimControls.
     // at a time.  Stop all of the other AnimControls.
     if (get_blend_type() == BT_single) {
     if (get_blend_type() == BT_single) {
-      clear_and_stop_except(control);
+      clear_and_stop_intersecting(control);
     }
     }
 
 
     if (get_control_effect(control) != effect) {
     if (get_control_effect(control) != effect) {
@@ -285,8 +286,14 @@ bind_anim(AnimBundle *anim, int hierarchy_match_flags,
     channel_index = holes.front();
     channel_index = holes.front();
   }
   }
 
 
-  bind_hierarchy(anim, channel_index, subset.is_empty(), subset);
-  return new AnimControl(this, anim, channel_index);
+  int joint_index = 0;
+  BitArray bound_joints;
+  if (subset.is_include_empty()) {
+    bound_joints = BitArray::all_on();
+  }
+  bind_hierarchy(anim, channel_index, joint_index, subset.is_include_empty(), 
+                 bound_joints, subset);
+  return new AnimControl(this, anim, channel_index, bound_joints);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -416,16 +423,17 @@ register_with_read_factory()
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: PartBundle::clear_and_stop_except
+//     Function: PartBundle::clear_and_stop_intersecting
 //       Access: Protected
 //       Access: Protected
 //  Description: Removes and stops all the currently activated
 //  Description: Removes and stops all the currently activated
-//               AnimControls, except for the indicated one.  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.
+//               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::
 void PartBundle::
-clear_and_stop_except(AnimControl *control) {
+clear_and_stop_intersecting(AnimControl *control) {
   double new_net_blend = 0.0f;
   double new_net_blend = 0.0f;
   ChannelBlend new_blend;
   ChannelBlend new_blend;
   bool any_changed = false;
   bool any_changed = false;
@@ -433,8 +441,10 @@ clear_and_stop_except(AnimControl *control) {
   ChannelBlend::iterator cbi;
   ChannelBlend::iterator cbi;
   for (cbi = _blend.begin(); cbi != _blend.end(); ++cbi) {
   for (cbi = _blend.begin(); cbi != _blend.end(); ++cbi) {
     AnimControl *ac = (*cbi).first;
     AnimControl *ac = (*cbi).first;
-    if (ac == control) {
-      // Save this control, but only this one.
+    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_blend.insert(new_blend.end(), (*cbi));
       new_net_blend += (*cbi).second;
       new_net_blend += (*cbi).second;
     } else {
     } else {

+ 1 - 1
panda/src/chan/partBundle.h

@@ -135,7 +135,7 @@ public:
 
 
 protected:
 protected:
   void recompute_net_blend();
   void recompute_net_blend();
-  void clear_and_stop_except(AnimControl *control);
+  void clear_and_stop_intersecting(AnimControl *control);
 
 
   BlendType _blend_type;
   BlendType _blend_type;
   PartBundleNode *_node;
   PartBundleNode *_node;

+ 12 - 4
panda/src/chan/partGroup.cxx

@@ -432,7 +432,8 @@ pick_channel_index(plist<int> &holes, int &next) const {
 //               hierarchy, at the given channel index number.
 //               hierarchy, at the given channel index number.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PartGroup::
 void PartGroup::
-bind_hierarchy(AnimGroup *anim, int channel_index, bool is_included,
+bind_hierarchy(AnimGroup *anim, int channel_index, int &joint_index, 
+               bool is_included, BitArray &bound_joints,
                const PartSubset &subset) {
                const PartSubset &subset) {
   if (subset.matches_include(get_name())) {
   if (subset.matches_include(get_name())) {
     is_included = true;
     is_included = true;
@@ -451,12 +452,18 @@ bind_hierarchy(AnimGroup *anim, int channel_index, bool is_included,
     if (pc->get_name() < ac->get_name()) {
     if (pc->get_name() < ac->get_name()) {
       // Here's a part, not in the anim.  Bind it to the special NULL
       // Here's a part, not in the anim.  Bind it to the special NULL
       // anim.
       // anim.
-      pc->bind_hierarchy(NULL, channel_index, is_included, subset);
+      pc->bind_hierarchy(NULL, channel_index, joint_index, is_included, 
+                         bound_joints, subset);
       i++;
       i++;
+
     } else if (ac->get_name() < pc->get_name()) {
     } else if (ac->get_name() < pc->get_name()) {
+      // Here's an anim, not in the part.  Ignore it.
       j++;
       j++;
+
     } else {
     } else {
-      pc->bind_hierarchy(ac, channel_index, is_included, subset);
+      // Here's a matched part and anim pair.
+      pc->bind_hierarchy(ac, channel_index, joint_index, is_included, 
+                         bound_joints, subset);
       i++;
       i++;
       j++;
       j++;
     }
     }
@@ -465,7 +472,8 @@ bind_hierarchy(AnimGroup *anim, int channel_index, bool is_included,
   // Now pick up any more parts, not in the anim.
   // Now pick up any more parts, not in the anim.
   while (i < part_num_children) {
   while (i < part_num_children) {
     PartGroup *pc = get_child(i);
     PartGroup *pc = get_child(i);
-    pc->bind_hierarchy(NULL, channel_index, is_included, subset);
+    pc->bind_hierarchy(NULL, channel_index, joint_index, is_included, 
+                       bound_joints, subset);
     i++;
     i++;
   }
   }
 }
 }

+ 4 - 1
panda/src/chan/partGroup.h

@@ -34,6 +34,7 @@ class PartBundle;
 class PartSubset;
 class PartSubset;
 class BamReader;
 class BamReader;
 class FactoryParams;
 class FactoryParams;
+class BitArray;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //       Class : PartGroup
 //       Class : PartGroup
@@ -93,7 +94,9 @@ protected:
 
 
   virtual void pick_channel_index(plist<int> &holes, int &next) const;
   virtual void pick_channel_index(plist<int> &holes, int &next) const;
   virtual void bind_hierarchy(AnimGroup *anim, int channel_index,
   virtual void bind_hierarchy(AnimGroup *anim, int channel_index,
-                              bool is_included, const PartSubset &subset);
+                              int &joint_index, bool is_included, 
+                              BitArray &bound_joints,
+                              const PartSubset &subset);
 
 
   typedef pvector< PT(PartGroup) > Children;
   typedef pvector< PT(PartGroup) > Children;
   Children _children;
   Children _children;

+ 4 - 4
panda/src/chan/partSubset.cxx

@@ -129,15 +129,15 @@ output(ostream &out) const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: PartSubset::is_empty
+//     Function: PartSubset::is_include_empty
 //       Access: Published
 //       Access: Published
-//  Description: Returns true if the PartSubset is completely empty,
+//  Description: Returns true if the include list is completely empty,
 //               false otherwise.  If it is empty, it is the same
 //               false otherwise.  If it is empty, it is the same
 //               thing as including all joints.
 //               thing as including all joints.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 bool PartSubset::
 bool PartSubset::
-is_empty() const {
-  return _include_joints.empty() && _exclude_joints.empty();
+is_include_empty() const {
+  return _include_joints.empty();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/chan/partSubset.h

@@ -42,7 +42,7 @@ PUBLISHED:
 
 
   void output(ostream &out) const;
   void output(ostream &out) const;
 
 
-  bool is_empty() const;
+  bool is_include_empty() const;
   bool matches_include(const string &joint_name) const;
   bool matches_include(const string &joint_name) const;
   bool matches_exclude(const string &joint_name) const;
   bool matches_exclude(const string &joint_name) const;