David Rose пре 20 година
родитељ
комит
aa837381d3

+ 8 - 1
panda/src/chan/Sources.pp

@@ -14,6 +14,7 @@
     animChannel.I animChannel.h animChannelBase.I  \
     animChannel.I animChannel.h animChannelBase.I  \
     animChannelBase.h \
     animChannelBase.h \
     animChannelMatrixDynamic.I animChannelMatrixDynamic.h \
     animChannelMatrixDynamic.I animChannelMatrixDynamic.h \
+    animChannelMatrixFixed.I animChannelMatrixFixed.h \
     animChannelMatrixXfmTable.I animChannelMatrixXfmTable.h \
     animChannelMatrixXfmTable.I animChannelMatrixXfmTable.h \
     animChannelScalarDynamic.I animChannelScalarDynamic.h \
     animChannelScalarDynamic.I animChannelScalarDynamic.h \
     animChannelScalarTable.I animChannelScalarTable.h \
     animChannelScalarTable.I animChannelScalarTable.h \
@@ -25,6 +26,7 @@
     movingPartScalar.h partBundle.I partBundle.N partBundle.h  \
     movingPartScalar.h partBundle.I partBundle.N partBundle.h  \
     partBundleNode.I partBundleNode.h \
     partBundleNode.I partBundleNode.h \
     partGroup.I partGroup.h  \
     partGroup.I partGroup.h  \
+    partSubset.I partSubset.h \
     vector_PartGroupStar.h 
     vector_PartGroupStar.h 
 
 
   #define INCLUDED_SOURCES  \
   #define INCLUDED_SOURCES  \
@@ -33,6 +35,7 @@
     animChannel.cxx  \
     animChannel.cxx  \
     animChannelBase.cxx \
     animChannelBase.cxx \
     animChannelMatrixDynamic.cxx  \
     animChannelMatrixDynamic.cxx  \
+    animChannelMatrixFixed.cxx  \
     animChannelMatrixXfmTable.cxx  \
     animChannelMatrixXfmTable.cxx  \
     animChannelScalarDynamic.cxx \
     animChannelScalarDynamic.cxx \
     animChannelScalarTable.cxx \
     animChannelScalarTable.cxx \
@@ -41,7 +44,9 @@
     config_chan.cxx movingPartBase.cxx movingPartMatrix.cxx  \
     config_chan.cxx movingPartBase.cxx movingPartMatrix.cxx  \
     movingPartScalar.cxx partBundle.cxx \
     movingPartScalar.cxx partBundle.cxx \
     partBundleNode.cxx \
     partBundleNode.cxx \
-    partGroup.cxx vector_PartGroupStar.cxx 
+    partGroup.cxx \
+    partSubset.cxx \
+    vector_PartGroupStar.cxx 
 
 
   #define INSTALL_HEADERS \
   #define INSTALL_HEADERS \
     animBundle.I animBundle.h \
     animBundle.I animBundle.h \
@@ -49,6 +54,7 @@
     animChannel.I animChannel.h animChannelBase.I animChannelBase.h \
     animChannel.I animChannel.h animChannelBase.I animChannelBase.h \
     animChannelFixed.I animChannelFixed.h \
     animChannelFixed.I animChannelFixed.h \
     animChannelMatrixDynamic.I animChannelMatrixDynamic.h \
     animChannelMatrixDynamic.I animChannelMatrixDynamic.h \
+    animChannelMatrixFixed.I animChannelMatrixFixed.h \
     animChannelMatrixXfmTable.I animChannelMatrixXfmTable.h \
     animChannelMatrixXfmTable.I animChannelMatrixXfmTable.h \
     animChannelScalarDynamic.I animChannelScalarDynamic.h \
     animChannelScalarDynamic.I animChannelScalarDynamic.h \
     animChannelScalarTable.I animChannelScalarTable.h \
     animChannelScalarTable.I animChannelScalarTable.h \
@@ -60,6 +66,7 @@
     movingPartScalar.I movingPartScalar.h partBundle.I partBundle.h \
     movingPartScalar.I movingPartScalar.h partBundle.I partBundle.h \
     partBundleNode.I partBundleNode.h \
     partBundleNode.I partBundleNode.h \
     partGroup.I partGroup.h \
     partGroup.I partGroup.h \
+    partSubset.I partSubset.h \
     vector_PartGroupStar.h
     vector_PartGroupStar.h
     
     
   #define IGATESCAN all
   #define IGATESCAN all

+ 1 - 2
panda/src/chan/animChannelMatrixDynamic.cxx

@@ -26,7 +26,6 @@
 #include "datagramIterator.h"
 #include "datagramIterator.h"
 #include "bamReader.h"
 #include "bamReader.h"
 #include "bamWriter.h"
 #include "bamWriter.h"
-#include "fftCompressor.h"
 
 
 TypeHandle AnimChannelMatrixDynamic::_type_handle;
 TypeHandle AnimChannelMatrixDynamic::_type_handle;
 
 
@@ -101,7 +100,7 @@ get_value_no_scale_shear(int frame, LMatrix4f &mat) {
 //  Description: Gets the scale value at the indicated frame.
 //  Description: Gets the scale value at the indicated frame.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void AnimChannelMatrixDynamic::
 void AnimChannelMatrixDynamic::
-get_scale(int frame, LVecBase3f &scale) {
+get_scale(int, LVecBase3f &scale) {
   scale = _value->get_scale();
   scale = _value->get_scale();
 }
 }
 
 

+ 18 - 0
panda/src/chan/animChannelMatrixFixed.I

@@ -0,0 +1,18 @@
+// Filename: animChannelMatrixFixed.I
+// Created by:  drose (19Jan06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+

+ 110 - 0
panda/src/chan/animChannelMatrixFixed.cxx

@@ -0,0 +1,110 @@
+// Filename: animChannelMatrixFixed.cxx
+// Created by:  drose (19Jan06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "animChannelMatrixFixed.h"
+#include "compose_matrix.h"
+
+TypeHandle AnimChannelMatrixFixed::_type_handle;
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimChannelMatrixFixed::Constructor
+//       Access: Public
+//  Description: This flavor creates an AnimChannelMatrixFixed that is not
+//               in a hierarchy.
+////////////////////////////////////////////////////////////////////
+AnimChannelMatrixFixed::
+AnimChannelMatrixFixed(const string &name, const LMatrix4f &value)
+  : AnimChannelFixed<ACMatrixSwitchType>(name, value)
+{
+  // Decompose the matrix into components in case we will be blending.
+  decompose_matrix(_value, _scale, _shear, _hpr, _pos);
+  compose_matrix(_value_no_scale_shear, LVecBase3f(1.0f, 1.0f, 1.0f),
+                 _hpr, _pos);
+
+  _quat.set_hpr(_hpr);
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimChannelMatrixFixed::get_value_no_scale_shear
+//       Access: Public, Virtual
+//  Description: Gets the value of the channel at the indicated frame,
+//               without any scale or shear information.
+////////////////////////////////////////////////////////////////////
+void AnimChannelMatrixFixed::
+get_value_no_scale_shear(int frame, LMatrix4f &mat) {
+  mat = _value_no_scale_shear;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimChannelMatrixFixed::get_scale
+//       Access: Public, Virtual
+//  Description: Gets the scale value at the indicated frame.
+////////////////////////////////////////////////////////////////////
+void AnimChannelMatrixFixed::
+get_scale(int, LVecBase3f &scale) {
+  scale = _scale;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimChannelMatrixFixed::get_hpr
+//       Access: Public, Virtual
+//  Description: Returns the h, p, and r components associated
+//               with the current frame.  As above, this only makes
+//               sense for a matrix-type channel.
+////////////////////////////////////////////////////////////////////
+void AnimChannelMatrixFixed::
+get_hpr(int, LVecBase3f &hpr) {
+  hpr = _hpr;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimChannelMatrixFixed::get_quat
+//       Access: Public, Virtual
+//  Description: Returns the rotation component associated with the
+//               current frame, expressed as a quaternion.  As above,
+//               this only makes sense for a matrix-type channel.
+////////////////////////////////////////////////////////////////////
+void AnimChannelMatrixFixed::
+get_quat(int, LQuaternionf &quat) {
+  quat = _quat;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimChannelMatrixFixed::get_pos
+//       Access: Public, Virtual
+//  Description: Returns the x, y, and z translation components
+//               associated with the current frame.  As above, this
+//               only makes sense for a matrix-type channel.
+////////////////////////////////////////////////////////////////////
+void AnimChannelMatrixFixed::
+get_pos(int, LVecBase3f &pos) {
+  pos = _pos;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimChannelMatrixFixed::get_shear
+//       Access: Public, Virtual
+//  Description: Returns the a, b, and c shear components associated
+//               with the current frame.  As above, this only makes
+//               sense for a matrix-type channel.
+////////////////////////////////////////////////////////////////////
+void AnimChannelMatrixFixed::
+get_shear(int, LVecBase3f &shear) {
+  shear = _shear;
+}

+ 77 - 0
panda/src/chan/animChannelMatrixFixed.h

@@ -0,0 +1,77 @@
+// Filename: animChannelMatrixFixed.h
+// Created by:  drose (19Jan06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef ANIMCHANNELMATRIXFIXED_H
+#define ANIMCHANNELMATRIXFIXED_H
+
+#include "pandabase.h"
+
+#include "animChannelFixed.h"
+#include "luse.h"
+
+EXPORT_TEMPLATE_CLASS(EXPCL_PANDA, EXPTP_PANDA, AnimChannelFixed<ACMatrixSwitchType>);
+
+////////////////////////////////////////////////////////////////////
+//       Class : AnimChannelMatrixFixed
+// Description : A specialization on AnimChannelFixed to add all the
+//               special matrix component operations.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA AnimChannelMatrixFixed : public AnimChannelFixed<ACMatrixSwitchType> {
+public:
+  AnimChannelMatrixFixed(const string &name, const LMatrix4f &value);
+
+
+  virtual void get_value_no_scale_shear(int frame, LMatrix4f &value);
+  virtual void get_scale(int frame, LVecBase3f &scale);
+  virtual void get_hpr(int frame, LVecBase3f &hpr);
+  virtual void get_quat(int frame, LQuaternionf &quat);
+  virtual void get_pos(int frame, LVecBase3f &pos);
+  virtual void get_shear(int frame, LVecBase3f &shear);
+
+private:
+  LMatrix4f _value_no_scale_shear;
+  LVecBase3f _scale;
+  LVecBase3f _hpr;
+  LQuaternionf _quat;
+  LVecBase3f _pos;
+  LVecBase3f _shear;
+
+public:
+  virtual TypeHandle get_type() const {
+    return get_class_type();
+  }
+  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
+  static TypeHandle get_class_type() {
+    return _type_handle;
+  }
+  static void init_type() {
+    AnimChannelFixed<ACMatrixSwitchType>::init_type();
+    register_type(_type_handle, "AnimChannelMatrixFixed",
+                  AnimChannelFixed<ACMatrixSwitchType>::get_class_type());
+  }
+
+private:
+  static TypeHandle _type_handle;
+};
+
+#include "animChannelMatrixFixed.I"
+
+#endif
+
+
+

+ 12 - 9
panda/src/chan/chan_composite1.cxx

@@ -1,11 +1,14 @@
-
 #include "auto_bind.cxx"
 #include "auto_bind.cxx"
-#include "config_chan.cxx"
-#include "movingPartBase.cxx"
-#include "movingPartMatrix.cxx"
-#include "movingPartScalar.cxx"
-#include "partBundle.cxx"
-#include "partBundleNode.cxx"
-#include "partGroup.cxx"
-#include "vector_PartGroupStar.cxx"
+#include "animBundle.cxx"
+#include "animBundleNode.cxx"
+#include "animChannel.cxx"
+#include "animChannelBase.cxx"
+#include "animChannelMatrixDynamic.cxx"
+#include "animChannelMatrixFixed.cxx"
+#include "animChannelMatrixXfmTable.cxx"
+#include "animChannelScalarDynamic.cxx"
+#include "animChannelScalarTable.cxx"
+#include "animControl.cxx"
+#include "animControlCollection.cxx"
+#include "animGroup.cxx"
 
 

+ 9 - 13
panda/src/chan/chan_composite2.cxx

@@ -1,13 +1,9 @@
-
-#include "animBundle.cxx"
-#include "animBundleNode.cxx"
-#include "animChannel.cxx"
-#include "animChannelBase.cxx"
-#include "animChannelMatrixDynamic.cxx"
-#include "animChannelMatrixXfmTable.cxx"
-#include "animChannelScalarDynamic.cxx"
-#include "animChannelScalarTable.cxx"
-#include "animControl.cxx"
-#include "animControlCollection.cxx"
-#include "animGroup.cxx"
-
+#include "config_chan.cxx"
+#include "movingPartBase.cxx"
+#include "movingPartMatrix.cxx"
+#include "movingPartScalar.cxx"
+#include "partBundle.cxx"
+#include "partBundleNode.cxx"
+#include "partGroup.cxx"
+#include "partSubset.cxx"
+#include "vector_PartGroupStar.cxx"

+ 2 - 0
panda/src/chan/config_chan.cxx

@@ -23,6 +23,7 @@
 #include "animChannelBase.h"
 #include "animChannelBase.h"
 #include "animChannelMatrixXfmTable.h"
 #include "animChannelMatrixXfmTable.h"
 #include "animChannelMatrixDynamic.h"
 #include "animChannelMatrixDynamic.h"
+#include "animChannelMatrixFixed.h"
 #include "animChannelScalarTable.h"
 #include "animChannelScalarTable.h"
 #include "animChannelScalarDynamic.h"
 #include "animChannelScalarDynamic.h"
 #include "animControl.h"
 #include "animControl.h"
@@ -89,6 +90,7 @@ ConfigureFn(config_chan) {
   AnimChannelBase::init_type();
   AnimChannelBase::init_type();
   AnimChannelMatrixXfmTable::init_type();
   AnimChannelMatrixXfmTable::init_type();
   AnimChannelMatrixDynamic::init_type();
   AnimChannelMatrixDynamic::init_type();
+  AnimChannelMatrixFixed::init_type();
   AnimChannelScalarTable::init_type();
   AnimChannelScalarTable::init_type();
   AnimChannelScalarDynamic::init_type();
   AnimChannelScalarDynamic::init_type();
   AnimControl::init_type();
   AnimControl::init_type();

+ 22 - 18
panda/src/chan/movingPartBase.cxx

@@ -47,7 +47,7 @@ MovingPartBase(){
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MovingPartBase::write
 //     Function: MovingPartBase::write
-//       Access: Public, Virtual
+//       Access: Published, Virtual
 //  Description: Writes a brief description of the channel and all of
 //  Description: Writes a brief description of the channel and all of
 //               its descendants.
 //               its descendants.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -65,7 +65,7 @@ write(ostream &out, int indent_level) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MovingPartBase::write_with_value
 //     Function: MovingPartBase::write_with_value
-//       Access: Public, Virtual
+//       Access: Published, Virtual
 //  Description: Writes a brief description of the channel and all of
 //  Description: Writes a brief description of the channel and all of
 //               its descendants, along with their values.
 //               its descendants, along with their values.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -112,9 +112,9 @@ do_update(PartBundle *root, PartGroup *parent,
     int channel_index = control->get_channel_index();
     int channel_index = control->get_channel_index();
     nassertr(channel_index >= 0 && channel_index < (int)_channels.size(), false);
     nassertr(channel_index >= 0 && channel_index < (int)_channels.size(), false);
     AnimChannelBase *channel = _channels[channel_index];
     AnimChannelBase *channel = _channels[channel_index];
-    nassertr(channel != (AnimChannelBase*)0L, false);
-
-    needs_update = control->channel_has_changed(channel);
+    if (channel != (AnimChannelBase*)NULL) {
+      needs_update = control->channel_has_changed(channel);
+    }
   }
   }
 
 
   if (needs_update) {
   if (needs_update) {
@@ -187,7 +187,7 @@ pick_channel_index(plist<int> &holes, int &next) const {
   if (next < (int)_channels.size()) {
   if (next < (int)_channels.size()) {
     int i;
     int i;
     for (i = next; i < (int)_channels.size(); i++) {
     for (i = next; i < (int)_channels.size(); i++) {
-      if (_channels[i] == (AnimChannelBase*)0L) {
+      if (_channels[i] == (AnimChannelBase*)NULL) {
         // Here's a hole we do have.
         // Here's a hole we do have.
         holes.push_back(i);
         holes.push_back(i);
       }
       }
@@ -207,25 +207,29 @@ 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) {
+bind_hierarchy(AnimGroup *anim, int channel_index, bool is_included,
+               const PartSubset &subset) {
   if (chan_cat.is_debug()) {
   if (chan_cat.is_debug()) {
     chan_cat.debug()
     chan_cat.debug()
-      << "binding " << *this << " to " << *anim << "\n";
+      << "binding " << *this << " to " << *anim << ", is_included = "
+      << is_included << "\n";
   }
   }
   while ((int)_channels.size() <= channel_index) {
   while ((int)_channels.size() <= channel_index) {
-    _channels.push_back((AnimChannelBase*)0L);
+    _channels.push_back((AnimChannelBase*)NULL);
   }
   }
 
 
-  nassertv(_channels[channel_index] == (AnimChannelBase*)0L);
+  nassertv(_channels[channel_index] == (AnimChannelBase*)NULL);
 
 
-  if (anim == (AnimGroup*)0L) {
-    // If we're binding to the NULL anim, it means actually to create
-    // a default AnimChannel that just returns the part's initial
-    // value.
-    _channels[channel_index] = make_initial_channel();
-  } else {
-    _channels[channel_index] = DCAST(AnimChannelBase, anim);
+  if (is_included) {
+    if (anim == (AnimGroup*)NULL) {
+      // If we're binding to the NULL anim, it means actually to create
+      // a default AnimChannel that just returns the part's initial
+      // value.
+      _channels[channel_index] = make_initial_channel();
+    } else {
+      _channels[channel_index] = DCAST(AnimChannelBase, anim);
+    }
   }
   }
 
 
-  PartGroup::bind_hierarchy(anim, channel_index);
+  PartGroup::bind_hierarchy(anim, channel_index, is_included, subset);
 }
 }

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

@@ -49,10 +49,13 @@ PUBLISHED:
 public:
 public:
   virtual TypeHandle get_value_type() const=0;
   virtual TypeHandle get_value_type() const=0;
   virtual AnimChannelBase *make_initial_channel() const=0;
   virtual AnimChannelBase *make_initial_channel() const=0;
+
+PUBLISHED:
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
   virtual void write_with_value(ostream &out, int indent_level) const;
   virtual void write_with_value(ostream &out, int indent_level) const;
   virtual void output_value(ostream &out) const=0;
   virtual void output_value(ostream &out) const=0;
 
 
+public:
   virtual bool do_update(PartBundle *root, PartGroup *parent,
   virtual bool do_update(PartBundle *root, PartGroup *parent,
                          bool parent_changed, bool anim_changed);
                          bool parent_changed, bool anim_changed);
 
 
@@ -64,7 +67,8 @@ protected:
   MovingPartBase();
   MovingPartBase();
 
 
   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);
 
 
   typedef pvector< PT(AnimChannelBase) > Channels;
   typedef pvector< PT(AnimChannelBase) > Channels;
   Channels _channels;
   Channels _channels;

+ 109 - 77
panda/src/chan/movingPartMatrix.cxx

@@ -41,6 +41,19 @@ MovingPartMatrix::
 ~MovingPartMatrix() {
 ~MovingPartMatrix() {
 }
 }
 
 
+
+////////////////////////////////////////////////////////////////////
+//     Function: MovingPartMatrix::make_initial_channel
+//       Access: Public, Virtual
+//  Description: Creates and returns a new AnimChannel that is not
+//               part of any hierarchy, but that returns the default
+//               value associated with this part.
+////////////////////////////////////////////////////////////////////
+AnimChannelBase *MovingPartMatrix::
+make_initial_channel() const {
+  return new AnimChannelMatrixFixed(get_name(), _initial_value);
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: MovingPartMatrix::get_blend_value
 //     Function: MovingPartMatrix::get_blend_value
 //       Access: Public
 //       Access: Public
@@ -63,9 +76,13 @@ get_blend_value(const PartBundle *root) {
     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());
     ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
     ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
-    nassertv(channel != NULL);
+    if (channel == (ChannelType *)NULL) {
+      // Nothing is actually bound here.
+      _value = _initial_value;
 
 
-    channel->get_value(control->get_frame(), _value);
+    } else {
+      channel->get_value(control->get_frame(), _value);
+    }
 
 
   } else {
   } else {
     // A blend of two or more values.
     // A blend of two or more values.
@@ -90,17 +107,20 @@ get_blend_value(const PartBundle *root) {
           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());
           ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
           ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
-          nassertv(channel != NULL);
-          
-          ValueType v;
-          channel->get_value(control->get_frame(), v);
-          
-          _value += v * effect;
-          net += effect;
+          if (channel != (ChannelType *)NULL) {
+            ValueType v;
+            channel->get_value(control->get_frame(), v);
+            
+            _value += v * effect;
+            net += effect;
+          }
         }
         }
         
         
-        nassertv(net != 0.0f);
-        _value /= net;
+        if (net == 0.0f) {
+          _value = _initial_value;
+        } else {
+          _value /= net;
+        }
       }
       }
       break;
       break;
 
 
@@ -126,30 +146,34 @@ get_blend_value(const PartBundle *root) {
           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());
           ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
           ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
-          nassertv(channel != NULL);
+          if (channel != (ChannelType *)NULL) {
+            ValueType v;
+            channel->get_value_no_scale_shear(control->get_frame(), v);
+            LVecBase3f iscale, ishear;
+            channel->get_scale(control->get_frame(), iscale);
+            channel->get_shear(control->get_frame(), ishear);
+            
+            _value += v * effect;
+            scale += iscale * effect;
+            shear += ishear * effect;
+            net += effect;
+          }
+        }
+        
+        if (net == 0.0f) {
+          _value = _initial_value;
+
+        } else {
+          _value /= net;
+          scale /= net;
+          shear /= net;
           
           
-          ValueType v;
-          channel->get_value_no_scale_shear(control->get_frame(), v);
-          LVecBase3f iscale, ishear;
-          channel->get_scale(control->get_frame(), iscale);
-          channel->get_shear(control->get_frame(), ishear);
+          // Now rebuild the matrix with the correct scale values.
           
           
-          _value += v * effect;
-          scale += iscale * effect;
-          shear += ishear * effect;
-          net += effect;
+          LVector3f false_scale, false_shear, hpr, translate;
+          decompose_matrix(_value, false_scale, false_shear, hpr, translate);
+          compose_matrix(_value, scale, shear, hpr, translate);
         }
         }
-        
-        nassertv(net != 0.0f);
-        _value /= net;
-        scale /= net;
-        shear /= net;
-        
-        // Now rebuild the matrix with the correct scale values.
-        
-        LVector3f false_scale, false_shear, hpr, translate;
-        decompose_matrix(_value, false_scale, false_shear, hpr, translate);
-        compose_matrix(_value, scale, shear, hpr, translate);
       }
       }
       break;
       break;
 
 
@@ -171,28 +195,32 @@ get_blend_value(const PartBundle *root) {
           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());
           ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
           ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
-          nassertv(channel != NULL);
-          
-          LVecBase3f iscale, ihpr, ipos, ishear;
-          channel->get_scale(control->get_frame(), iscale);
-          channel->get_hpr(control->get_frame(), ihpr);
-          channel->get_pos(control->get_frame(), ipos);
-          channel->get_shear(control->get_frame(), ishear);
-          
-          scale += iscale * effect;
-          hpr += ihpr * effect;
-          pos += ipos * effect;
-          shear += ishear * effect;
-          net += effect;
+          if (channel != (ChannelType *)NULL) {
+            LVecBase3f iscale, ihpr, ipos, ishear;
+            channel->get_scale(control->get_frame(), iscale);
+            channel->get_hpr(control->get_frame(), ihpr);
+            channel->get_pos(control->get_frame(), ipos);
+            channel->get_shear(control->get_frame(), ishear);
+            
+            scale += iscale * effect;
+            hpr += ihpr * effect;
+            pos += ipos * effect;
+            shear += ishear * effect;
+            net += effect;
+          }
         }
         }
         
         
-        nassertv(net != 0.0f);
-        scale /= net;
-        hpr /= net;
-        pos /= net;
-        shear /= net;
-        
-        compose_matrix(_value, scale, shear, hpr, pos);
+        if (net == 0.0f) {
+          _value = _initial_value;
+
+        } else {
+          scale /= net;
+          hpr /= net;
+          pos /= net;
+          shear /= net;
+          
+          compose_matrix(_value, scale, shear, hpr, pos);
+        }
       }
       }
       break;
       break;
 
 
@@ -215,34 +243,38 @@ get_blend_value(const PartBundle *root) {
           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());
           ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
           ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
-          nassertv(channel != NULL);
-          
-          LVecBase3f iscale, ipos, ishear;
-          LQuaternionf iquat;
-          channel->get_scale(control->get_frame(), iscale);
-          channel->get_quat(control->get_frame(), iquat);
-          channel->get_pos(control->get_frame(), ipos);
-          channel->get_shear(control->get_frame(), ishear);
-          
-          scale += iscale * effect;
-          quat += iquat * effect;
-          pos += ipos * effect;
-          shear += ishear * effect;
-          net += effect;
+          if (channel != (ChannelType *)NULL) {
+            LVecBase3f iscale, ipos, ishear;
+            LQuaternionf iquat;
+            channel->get_scale(control->get_frame(), iscale);
+            channel->get_quat(control->get_frame(), iquat);
+            channel->get_pos(control->get_frame(), ipos);
+            channel->get_shear(control->get_frame(), ishear);
+            
+            scale += iscale * effect;
+            quat += iquat * effect;
+            pos += ipos * effect;
+            shear += ishear * effect;
+            net += effect;
+          }
         }
         }
         
         
-        nassertv(net != 0.0f);
-        scale /= net;
-        quat /= net;
-        pos /= net;
-        shear /= net;
-
-        // There should be no need to normalize the quaternion,
-        // assuming all of the input quaternions were already
-        // normalized.
+        if (net == 0.0f) {
+          _value = _initial_value;
 
 
-        _value = LMatrix4f::scale_shear_mat(scale, shear) * quat;
-        _value.set_row(3, pos);
+        } else {
+          scale /= net;
+          quat /= net;
+          pos /= net;
+          shear /= net;
+          
+          // There should be no need to normalize the quaternion,
+          // assuming all of the input quaternions were already
+          // normalized.
+          
+          _value = LMatrix4f::scale_shear_mat(scale, shear) * quat;
+          _value.set_row(3, pos);
+        }
       }
       }
       break;
       break;
     }
     }

+ 1 - 0
panda/src/chan/movingPartMatrix.h

@@ -43,6 +43,7 @@ public:
                           LMatrix4f::ident_mat());
                           LMatrix4f::ident_mat());
   virtual ~MovingPartMatrix();
   virtual ~MovingPartMatrix();
 
 
+  virtual AnimChannelBase *make_initial_channel() const;
   virtual void get_blend_value(const PartBundle *root);
   virtual void get_blend_value(const PartBundle *root);
 
 
 protected:
 protected:

+ 18 - 10
panda/src/chan/movingPartScalar.cxx

@@ -61,9 +61,13 @@ get_blend_value(const PartBundle *root) {
     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());
     ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
     ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
-    nassertv(channel != NULL);
+    if (channel == NULL) {
+      // Nothing is actually bound here.
+      _value = _initial_value;
 
 
-    channel->get_value(control->get_frame(), _value);
+    } else {
+      channel->get_value(control->get_frame(), _value);
+    }
 
 
   } else {
   } else {
     // A blend of two or more values.
     // A blend of two or more values.
@@ -79,17 +83,21 @@ get_blend_value(const PartBundle *root) {
       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());
       ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
       ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
-      nassertv(channel != NULL);
+      if (channel != NULL) {
+        ValueType v;
+        channel->get_value(control->get_frame(), v);
+        
+        _value += v * effect;
+        net += effect;
+      }
+    }
 
 
-      ValueType v;
-      channel->get_value(control->get_frame(), v);
+    if (net == 0.0f) {
+      _value = _initial_value;
 
 
-      _value += v * effect;
-      net += effect;
+    } else {
+      _value /= net;
     }
     }
-
-    nassertv(net != 0.0f);
-    _value /= net;
   }
   }
 }
 }
 
 

+ 11 - 48
panda/src/chan/partBundle.cxx

@@ -43,8 +43,6 @@ PartBundle(const PartBundle &copy) :
   PartGroup(copy),
   PartGroup(copy),
   _blend_type(copy._blend_type)
   _blend_type(copy._blend_type)
 {
 {
-  // We don't invoke the AnimControlCollection's copy, or any of the
-  // bound animations.
   _last_control_set = NULL;
   _last_control_set = NULL;
   _net_blend = 0.0f;
   _net_blend = 0.0f;
   _anim_changed = false;
   _anim_changed = false;
@@ -250,16 +248,18 @@ write(ostream &out, int indent_level) const {
 //               conditions that will be tolerated (but warnings will
 //               conditions that will be tolerated (but warnings will
 //               still be issued).
 //               still be issued).
 //
 //
-//               This flavor of bind_anim() does not associate a name
-//               with the channel, and the AnimControl is not stored
-//               within the PartBundle; it is the user's
-//               responsibility to maintain the pointer.  The
-//               animation will automatically unbind itself when the
-//               AnimControl destructs (i.e. its reference count goes
-//               to zero).
+//               If subset is specified, it restricts the binding only
+//               to the named subtree of joints.
+//
+//               The AnimControl is not stored within the PartBundle;
+//               it is the user's responsibility to maintain the
+//               pointer.  The animation will automatically unbind
+//               itself when the AnimControl destructs (i.e. its
+//               reference count goes to zero).
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 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) {
   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()) {
@@ -285,47 +285,10 @@ bind_anim(AnimBundle *anim, int hierarchy_match_flags) {
     channel_index = holes.front();
     channel_index = holes.front();
   }
   }
 
 
-  bind_hierarchy(anim, channel_index);
+  bind_hierarchy(anim, channel_index, subset.is_empty(), subset);
   return new AnimControl(this, anim, channel_index);
   return new AnimControl(this, anim, channel_index);
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: PartBundle::bind_anim
-//       Access: Published
-//  Description: Binds the animation to the bundle, if possible, and
-//               returns a new AnimControl that can be used to start
-//               and stop the animation.  If the anim hierarchy does
-//               not match the part hierarchy, returns NULL.
-//
-//               If hierarchy_match_flags is 0, only an exact match is
-//               accepted; otherwise, it may contain a union of
-//               PartGroup::HierarchyMatchFlags values indicating
-//               conditions that will be tolerated (but warnings will
-//               still be issued).
-//
-//               This flavor of bind_anim() automatically stores the
-//               bound AnimControl in the PartBundle with the
-//               indicated name, so that it may later be referenced by
-//               name.  This means that the animation will not be
-//               unbound until another animation with the same name is
-//               bound, or it is explicitly unbound with
-//               unbind_anim().
-//
-//               The return value is true if the animation was
-//               successfully bound, false if there was some error.
-////////////////////////////////////////////////////////////////////
-bool PartBundle::
-bind_anim(AnimBundle *anim, const string &name,
-          int hierarchy_match_flags) {
-  PT(AnimControl) control = bind_anim(anim, hierarchy_match_flags);
-  if (control == (AnimControl *)NULL) {
-    return false;
-  }
-
-  store_anim(control, name);
-  return true;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PartBundle::update
 //     Function: PartBundle::update
 //       Access: Public
 //       Access: Public

+ 4 - 7
panda/src/chan/partBundle.h

@@ -23,8 +23,7 @@
 
 
 #include "partGroup.h"
 #include "partGroup.h"
 #include "animControl.h"
 #include "animControl.h"
-#include "animControlCollection.h"
-
+#include "partSubset.h"
 #include "pointerTo.h"
 #include "pointerTo.h"
 #include "iterator_types.h"
 #include "iterator_types.h"
 
 
@@ -38,7 +37,7 @@ class PartBundleNode;
 //               defines the hierarchy of moving parts that make up an
 //               defines the hierarchy of moving parts that make up an
 //               animatable object.
 //               animatable object.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA PartBundle : public PartGroup, public AnimControlCollection {
+class EXPCL_PANDA PartBundle : public PartGroup {
 public:
 public:
 
 
   // This is passed down through the MovingParts during the
   // This is passed down through the MovingParts during the
@@ -113,10 +112,8 @@ PUBLISHED:
   virtual void write(ostream &out, int indent_level) const;
   virtual void write(ostream &out, int indent_level) const;
 
 
   PT(AnimControl) bind_anim(AnimBundle *anim,
   PT(AnimControl) bind_anim(AnimBundle *anim,
-                            int hierarchy_match_flags = 0);
-
-  bool bind_anim(AnimBundle *anim, const string &name,
-                 int hierarchy_match_flags = 0);
+                            int hierarchy_match_flags = 0, 
+                            const PartSubset &subset = PartSubset());
 
 
 public:
 public:
   // The following functions may be used to traverse the set of
   // The following functions may be used to traverse the set of

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

@@ -16,10 +16,10 @@
 //
 //
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 
 
-
 #include "partGroup.h"
 #include "partGroup.h"
 #include "animGroup.h"
 #include "animGroup.h"
 #include "config_chan.h"
 #include "config_chan.h"
+#include "partSubset.h"
 
 
 #include "indent.h"
 #include "indent.h"
 #include "datagram.h"
 #include "datagram.h"
@@ -432,7 +432,14 @@ 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) {
+bind_hierarchy(AnimGroup *anim, int channel_index, bool is_included,
+               const PartSubset &subset) {
+  if (subset.matches_include(get_name())) {
+    is_included = true;
+  } else if (subset.matches_exclude(get_name())) {
+    is_included = false;
+  }
+
   int i = 0, j = 0;
   int i = 0, j = 0;
   int part_num_children = get_num_children();
   int part_num_children = get_num_children();
   int anim_num_children = (anim == NULL) ? 0 : anim->get_num_children();
   int anim_num_children = (anim == NULL) ? 0 : anim->get_num_children();
@@ -444,12 +451,12 @@ bind_hierarchy(AnimGroup *anim, int channel_index) {
     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);
+      pc->bind_hierarchy(NULL, channel_index, is_included, subset);
       i++;
       i++;
     } else if (ac->get_name() < pc->get_name()) {
     } else if (ac->get_name() < pc->get_name()) {
       j++;
       j++;
     } else {
     } else {
-      pc->bind_hierarchy(ac, channel_index);
+      pc->bind_hierarchy(ac, channel_index, is_included, subset);
       i++;
       i++;
       j++;
       j++;
     }
     }
@@ -458,7 +465,7 @@ bind_hierarchy(AnimGroup *anim, int channel_index) {
   // 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);
+    pc->bind_hierarchy(NULL, channel_index, is_included, subset);
     i++;
     i++;
   }
   }
 }
 }

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

@@ -31,6 +31,7 @@
 class AnimControl;
 class AnimControl;
 class AnimGroup;
 class AnimGroup;
 class PartBundle;
 class PartBundle;
+class PartSubset;
 class BamReader;
 class BamReader;
 class FactoryParams;
 class FactoryParams;
 
 
@@ -91,7 +92,8 @@ protected:
   void write_descendants_with_value(ostream &out, int indent_level) const;
   void write_descendants_with_value(ostream &out, int indent_level) const;
 
 
   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);
 
 
   typedef pvector< PT(PartGroup) > Children;
   typedef pvector< PT(PartGroup) > Children;
   Children _children;
   Children _children;

+ 18 - 0
panda/src/chan/partSubset.I

@@ -0,0 +1,18 @@
+// Filename: partSubset.I
+// Created by:  drose (19Jan06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+

+ 178 - 0
panda/src/chan/partSubset.cxx

@@ -0,0 +1,178 @@
+// Filename: partSubset.cxx
+// Created by:  drose (19Jan06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "partSubset.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartSubset::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PartSubset::
+PartSubset() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartSubset::Copy Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+PartSubset::
+PartSubset(const PartSubset &copy) : 
+  _include_joints(copy._include_joints),
+  _exclude_joints(copy._exclude_joints)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartSubset::Copy Assignment Operator
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PartSubset::
+operator = (const PartSubset &copy) {
+  _include_joints = copy._include_joints;
+  _exclude_joints = copy._exclude_joints;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartSubset::add_include_joint
+//       Access: Published
+//  Description: Adds the named joint to the list of joints that will
+//               be explicitly included in the subset.  Any joint at
+//               or below a named node will be included in the subset
+//               (unless a lower node is also listed in the exclude
+//               list).
+//
+//               Since the name is a GlobPattern, it may of course
+//               include filename globbing characters like * and ?.
+////////////////////////////////////////////////////////////////////
+void PartSubset::
+add_include_joint(const GlobPattern &name) {
+  _include_joints.push_back(name);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartSubset::add_exclude_joint
+//       Access: Published
+//  Description: Adds the named joint to the list of joints that will
+//               be explicitly exlcluded from the subset.  Any joint at
+//               or below a named node will not be included in the
+//               subset (unless a lower node is also listed in the
+//               include list).
+//
+//               Since the name is a GlobPattern, it may of course
+//               include filename globbing characters like * and ?.
+////////////////////////////////////////////////////////////////////
+void PartSubset::
+add_exclude_joint(const GlobPattern &name) {
+  _exclude_joints.push_back(name);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartSubset::append
+//       Access: Published
+//  Description: Appends the include and exclude list from the other
+//               object onto this object's lists.
+////////////////////////////////////////////////////////////////////
+void PartSubset::
+append(const PartSubset &other) {
+  Joints::const_iterator ji;
+  for (ji = other._include_joints.begin(); 
+       ji != other._include_joints.end(); 
+       ++ji) {
+    _include_joints.push_back(*ji);
+  }
+  for (ji = other._exclude_joints.begin(); 
+       ji != other._exclude_joints.end(); 
+       ++ji) {
+    _exclude_joints.push_back(*ji);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartSubset::output
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+void PartSubset::
+output(ostream &out) const {
+  if (_include_joints.empty() && _exclude_joints.empty()) {
+    out << "PartSubset, empty";
+  } else {
+    out << "PartSubset, include: [";
+    Joints::const_iterator ji;
+    for (ji = _include_joints.begin(); ji != _include_joints.end(); ++ji) {
+      out << " " << (*ji);
+    }
+    out << " ], exclude: [";
+    for (ji = _exclude_joints.begin(); ji != _exclude_joints.end(); ++ji) {
+      out << " " << (*ji);
+    }
+    out << " ]";
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartSubset::is_empty
+//       Access: Published
+//  Description: Returns true if the PartSubset is completely empty,
+//               false otherwise.  If it is empty, it is the same
+//               thing as including all joints.
+////////////////////////////////////////////////////////////////////
+bool PartSubset::
+is_empty() const {
+  return _include_joints.empty() && _exclude_joints.empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartSubset::matches_include
+//       Access: Published
+//  Description: Returns true if the indicated name matches a name on
+//               the include list, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool PartSubset::
+matches_include(const string &joint_name) const {
+  Joints::const_iterator ji;
+  for (ji = _include_joints.begin(); ji != _include_joints.end(); ++ji) {
+    if ((*ji).matches(joint_name)) {
+      return true;
+    }
+  }
+
+  return false;
+}
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartSubset::matches_exclude
+//       Access: Published
+//  Description: Returns true if the indicated name matches a name on
+//               the exclude list, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool PartSubset::
+matches_exclude(const string &joint_name) const {
+  Joints::const_iterator ji;
+  for (ji = _exclude_joints.begin(); ji != _exclude_joints.end(); ++ji) {
+    if ((*ji).matches(joint_name)) {
+      return true;
+    }
+  }
+
+  return false;
+}

+ 63 - 0
panda/src/chan/partSubset.h

@@ -0,0 +1,63 @@
+// Filename: partSubset.h
+// Created by:  drose (19Jan06)
+//
+////////////////////////////////////////////////////////////////////
+//
+// 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
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef PARTSUBSET_H
+#define PARTSUBSET_H
+
+#include "pandabase.h"
+#include "globPattern.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : PartSubset
+// Description : This class is used to define a subset of part names
+//               to apply to the PartBundle::bind_anim() operation.
+//               Only those part names within the subset will be
+//               included in the bind.
+////////////////////////////////////////////////////////////////////
+class EXPCL_PANDA PartSubset {
+PUBLISHED:
+  PartSubset();
+  PartSubset(const PartSubset &copy);
+  void operator = (const PartSubset &copy);
+
+  void add_include_joint(const GlobPattern &name);
+  void add_exclude_joint(const GlobPattern &name);
+
+  void append(const PartSubset &other);
+
+  void output(ostream &out) const;
+
+  bool is_empty() const;
+  bool matches_include(const string &joint_name) const;
+  bool matches_exclude(const string &joint_name) const;
+
+private:
+  typedef pvector<GlobPattern> Joints;
+  Joints _include_joints;
+  Joints _exclude_joints;
+};
+
+INLINE ostream &operator << (ostream &out, const PartSubset &subset) {
+  subset.output(out);
+  return out;
+}
+
+#include "partSubset.I"
+
+#endif
+