Pārlūkot izejas kodu

rework controlJoint() and freezeJoint() to reduce memory footprint

David Rose 18 gadi atpakaļ
vecāks
revīzija
81ae62f553

+ 1 - 17
panda/src/chan/animChannelFixed.I

@@ -38,23 +38,7 @@ AnimChannelFixed(AnimGroup *parent, const AnimChannelFixed<SwitchType> &copy) :
 ////////////////////////////////////////////////////////////////////
 //     Function: AnimChannelFixed::Constructor
 //       Access: Public
-//  Description: This is the flavor of AnimChannelFixed that puts it
-//               in a hierarchy.
-////////////////////////////////////////////////////////////////////
-template<class SwitchType>
-INLINE AnimChannelFixed<SwitchType>::
-AnimChannelFixed(AnimGroup *parent, const string &name,
-                 const ValueType &value)
-  : AnimChannel<SwitchType>(parent, name),
-    _value(value) {
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimChannelFixed::Constructor
-//       Access: Public
-//  Description: This flavor creates an AnimChannelFixed that is not
-//               in a hierarchy.
+//  Description: 
 ////////////////////////////////////////////////////////////////////
 template<class SwitchType>
 INLINE AnimChannelFixed<SwitchType>::

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

@@ -42,7 +42,6 @@ protected:
   INLINE AnimChannelFixed(AnimGroup *parent, const AnimChannelFixed<SwitchType> &copy);
 
 public:
-  INLINE AnimChannelFixed(AnimGroup *parent, const string &name, const ValueType &value);
   INLINE AnimChannelFixed(const string &name, const ValueType &value);
 
   virtual bool has_changed(double last_frame, double this_frame);

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

@@ -61,8 +61,8 @@ AnimChannelMatrixDynamic(AnimGroup *parent, const AnimChannelMatrixDynamic &copy
 //  Description:
 ////////////////////////////////////////////////////////////////////
 AnimChannelMatrixDynamic::
-AnimChannelMatrixDynamic(AnimGroup *parent, const string &name)
-  : AnimChannelMatrix(parent, name) 
+AnimChannelMatrixDynamic(const string &name)
+  : AnimChannelMatrix(name) 
 {
   _value = TransformState::make_identity();
   _last_value = NULL;  // This is impossible; thus, has_changed() will

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

@@ -44,7 +44,7 @@ protected:
   AnimChannelMatrixDynamic(AnimGroup *parent, const AnimChannelMatrixDynamic &copy);
 
 public:
-  AnimChannelMatrixDynamic(AnimGroup *parent, const string &name);
+  AnimChannelMatrixDynamic(const string &name);
 
   virtual bool has_changed(double last_frame, double this_frame);
   virtual void get_value(int frame, LMatrix4f &mat);

+ 44 - 38
panda/src/chan/animChannelMatrixFixed.cxx

@@ -31,54 +31,44 @@ TypeHandle AnimChannelMatrixFixed::_type_handle;
 ////////////////////////////////////////////////////////////////////
 AnimChannelMatrixFixed::
 AnimChannelMatrixFixed(AnimGroup *parent, const AnimChannelMatrixFixed &copy) : 
-  AnimChannelFixed<ACMatrixSwitchType>(parent, copy),
-  _value_no_scale_shear(copy._value_no_scale_shear),
-  _scale(copy._scale),
-  _hpr(copy._hpr),
-  _quat(copy._quat),
-  _pos(copy._pos),
-  _shear(copy._shear)
+  AnimChannel<ACMatrixSwitchType>(parent, copy),
+  _transform(copy._transform)
 {
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: AnimChannelMatrixFixed::Constructor
 //       Access: Public
-//  Description: This flavor creates an AnimChannelMatrixFixed that
-//               *is* in a hierarchy.
+//  Description: 
 ////////////////////////////////////////////////////////////////////
 AnimChannelMatrixFixed::
-AnimChannelMatrixFixed(AnimGroup *parent, const string &name, 
-                       const LMatrix4f &value)
-  : AnimChannelFixed<ACMatrixSwitchType>(parent, name, value)
+AnimChannelMatrixFixed(const string &name, const TransformState *transform) :
+  AnimChannel<ACMatrixSwitchType>(name),
+  _transform(transform)
 {
-  // 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::Constructor
-//       Access: Public
-//  Description: This flavor creates an AnimChannelMatrixFixed that is not
-//               in a hierarchy.
+//     Function: AnimChannelFixed::has_changed
+//       Access: Public, Virtual
+//  Description:
 ////////////////////////////////////////////////////////////////////
-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);
+bool AnimChannelMatrixFixed::
+has_changed(double, double) {
+  return false;
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: AnimChannelFixed::get_value
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+void AnimChannelMatrixFixed::
+get_value(int, LMatrix4f &value) {
+  value = _transform->get_mat();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: AnimChannelMatrixFixed::get_value_no_scale_shear
 //       Access: Public, Virtual
@@ -87,7 +77,12 @@ AnimChannelMatrixFixed(const string &name, const LMatrix4f &value)
 ////////////////////////////////////////////////////////////////////
 void AnimChannelMatrixFixed::
 get_value_no_scale_shear(int frame, LMatrix4f &mat) {
-  mat = _value_no_scale_shear;
+  if (_transform->has_scale() || _transform->has_shear()) {
+    compose_matrix(mat, LVecBase3f(1.0f, 1.0f, 1.0f),
+                   _transform->get_hpr(), _transform->get_pos());
+  } else {
+    mat = _transform->get_mat();
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -97,7 +92,7 @@ get_value_no_scale_shear(int frame, LMatrix4f &mat) {
 ////////////////////////////////////////////////////////////////////
 void AnimChannelMatrixFixed::
 get_scale(int, LVecBase3f &scale) {
-  scale = _scale;
+  scale = _transform->get_scale();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -109,7 +104,7 @@ get_scale(int, LVecBase3f &scale) {
 ////////////////////////////////////////////////////////////////////
 void AnimChannelMatrixFixed::
 get_hpr(int, LVecBase3f &hpr) {
-  hpr = _hpr;
+  hpr = _transform->get_hpr();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -121,7 +116,7 @@ get_hpr(int, LVecBase3f &hpr) {
 ////////////////////////////////////////////////////////////////////
 void AnimChannelMatrixFixed::
 get_quat(int, LQuaternionf &quat) {
-  quat = _quat;
+  quat = _transform->get_quat();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -133,7 +128,7 @@ get_quat(int, LQuaternionf &quat) {
 ////////////////////////////////////////////////////////////////////
 void AnimChannelMatrixFixed::
 get_pos(int, LVecBase3f &pos) {
-  pos = _pos;
+  pos = _transform->get_pos();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -145,5 +140,16 @@ get_pos(int, LVecBase3f &pos) {
 ////////////////////////////////////////////////////////////////////
 void AnimChannelMatrixFixed::
 get_shear(int, LVecBase3f &shear) {
-  shear = _shear;
+  shear = _transform->get_shear();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: AnimChannelFixed::output
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+void AnimChannelMatrixFixed::
+output(ostream &out) const {
+  AnimChannel<ACMatrixSwitchType>::output(out);
+  out << " = " << *_transform;
 }

+ 12 - 15
panda/src/chan/animChannelMatrixFixed.h

@@ -21,25 +21,25 @@
 
 #include "pandabase.h"
 
-#include "animChannelFixed.h"
+#include "animChannel.h"
 #include "luse.h"
 
-EXPORT_TEMPLATE_CLASS(EXPCL_PANDA, EXPTP_PANDA, AnimChannelFixed<ACMatrixSwitchType>);
+EXPORT_TEMPLATE_CLASS(EXPCL_PANDA, EXPTP_PANDA, AnimChannel<ACMatrixSwitchType>);
 
 ////////////////////////////////////////////////////////////////////
 //       Class : AnimChannelMatrixFixed
-// Description : A specialization on AnimChannelFixed to add all the
+// Description : A specialization on AnimChannel to add all the
 //               special matrix component operations.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA AnimChannelMatrixFixed : public AnimChannelFixed<ACMatrixSwitchType> {
+class EXPCL_PANDA AnimChannelMatrixFixed : public AnimChannel<ACMatrixSwitchType> {
 protected:
   AnimChannelMatrixFixed(AnimGroup *parent, const AnimChannelMatrixFixed &copy);
 
 public:
-  AnimChannelMatrixFixed(AnimGroup *parent, const string &name, const LMatrix4f &value);
-  AnimChannelMatrixFixed(const string &name, const LMatrix4f &value);
-
+  AnimChannelMatrixFixed(const string &name, const TransformState *transform);
 
+  virtual bool has_changed(double last_frame, double this_frame);
+  virtual void get_value(int frame, 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);
@@ -47,13 +47,10 @@ public:
   virtual void get_pos(int frame, LVecBase3f &pos);
   virtual void get_shear(int frame, LVecBase3f &shear);
 
+  virtual void output(ostream &out) const;
+
 private:
-  LMatrix4f _value_no_scale_shear;
-  LVecBase3f _scale;
-  LVecBase3f _hpr;
-  LQuaternionf _quat;
-  LVecBase3f _pos;
-  LVecBase3f _shear;
+  CPT(TransformState) _transform;
 
 public:
   virtual TypeHandle get_type() const {
@@ -64,9 +61,9 @@ public:
     return _type_handle;
   }
   static void init_type() {
-    AnimChannelFixed<ACMatrixSwitchType>::init_type();
+    AnimChannel<ACMatrixSwitchType>::init_type();
     register_type(_type_handle, "AnimChannelMatrixFixed",
-                  AnimChannelFixed<ACMatrixSwitchType>::get_class_type());
+                  AnimChannel<ACMatrixSwitchType>::get_class_type());
   }
 
 private:

+ 2 - 2
panda/src/chan/animChannelScalarDynamic.cxx

@@ -63,8 +63,8 @@ AnimChannelScalarDynamic(AnimGroup *parent, const AnimChannelScalarDynamic &copy
 //  Description:
 ////////////////////////////////////////////////////////////////////
 AnimChannelScalarDynamic::
-AnimChannelScalarDynamic(AnimGroup *parent, const string &name)
-  : AnimChannelScalar(parent, name) 
+AnimChannelScalarDynamic(const string &name)
+  : AnimChannelScalar(name) 
 {
   _last_value = _value = TransformState::make_identity();
   _value_changed = true;

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

@@ -44,7 +44,7 @@ protected:
   AnimChannelScalarDynamic(AnimGroup *parent, const AnimChannelScalarDynamic &copy);
 
 public:
-  AnimChannelScalarDynamic(AnimGroup *parent, const string &name);
+  AnimChannelScalarDynamic(const string &name);
 
   virtual bool has_changed(double last_frame, double this_frame);
   virtual void get_value(int frame, float &value);

+ 0 - 112
panda/src/chan/animGroup.cxx

@@ -19,8 +19,6 @@
 
 #include "animGroup.h"
 #include "animBundle.h"
-#include "animChannelMatrixDynamic.h"
-#include "animChannelScalarDynamic.h"
 #include "config_chan.h"
 
 #include "indent.h"
@@ -145,116 +143,6 @@ find_child(const string &name) const {
   return (AnimGroup *)NULL;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: AnimGroup::make_child_dynamic
-//       Access: Public
-//  Description: Finds the indicated child and replaces it with an
-//               AnimChannelMatrixDynamic or AnimChannelScalarDynamic,
-//               as appropriate, and returns the new channel.
-//
-//               This may be called before binding the animation to a
-//               character to replace certain joints with
-//               dynamically-controlled ones.
-//
-//               Returns NULL if the named child cannot be found.
-////////////////////////////////////////////////////////////////////
-AnimGroup *AnimGroup::
-make_child_dynamic(const string &name) {
-  Children::iterator ci;
-  for (ci = _children.begin(); ci != _children.end(); ++ci) {
-    AnimGroup *child = (*ci);
-    if (child->get_name() == name) {
-      AnimGroup *new_child = NULL;
-
-      if (child->is_of_type(AnimChannelMatrix::get_class_type())) {
-        AnimChannelMatrix *mchild = DCAST(AnimChannelMatrix, child);
-        AnimChannelMatrixDynamic *new_mchild = 
-          new AnimChannelMatrixDynamic(this, name);
-        new_child = new_mchild;
-
-        // Copy in the original value from frame 0.
-        LMatrix4f orig_value;
-        mchild->get_value(0, orig_value);
-        new_mchild->set_value(orig_value);
-
-      } else if (child->is_of_type(AnimChannelScalar::get_class_type())) {
-        AnimChannelScalar *schild = DCAST(AnimChannelScalar, child);
-        AnimChannelScalarDynamic *new_schild = 
-          new AnimChannelScalarDynamic(this, name);
-        new_child = new_schild;
-
-        // Copy in the original value from frame 0.
-        float orig_value;
-        schild->get_value(0, orig_value);
-        new_schild->set_value(orig_value);
-      }
-
-      if (new_child != (AnimGroup *)NULL) {
-        new_child->_children.swap(child->_children);
-        nassertr(_children.back() == new_child, NULL);
-
-        // The new child was appended to the end of our children list
-        // by its constructor.  Reposition it to replace the original
-        // child.
-
-        // I would like to use these lines, but for some reason it
-        // crashes:
-        /*
-        {
-          (*ci) = new_child;
-          _children.pop_back();
-        }
-        */
-
-        // But this longer way of achieving the same result works
-        // instead:
-        {
-          Children::iterator nci;
-          Children new_children;
-          for (nci = _children.begin(); nci != _children.end(); ++nci) {
-            if ((*nci) == child) {
-              new_children.push_back(new_child);
-            } else if ((*nci) != new_child) {
-              new_children.push_back(*nci);
-            }
-          }
-          new_children.swap(_children);
-        }
-
-        return new_child;
-      }
-    }
-    AnimGroup *result = child->make_child_dynamic(name);
-    if (result != (AnimGroup *)NULL) {
-      return result;
-    }
-  }
-
-  return (AnimGroup *)NULL;
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: AnimGroup::fix_child
-//       Access: Public
-//  Description: replaces childs animation matrix with a fixed one
-////////////////////////////////////////////////////////////////////
-void AnimGroup::
-fix_child(unsigned int index, const LMatrix4f &mat) {
-  AnimGroup *child = get_child(index);
-  AnimGroup *new_child = NULL;
-  if (child->is_of_type(AnimChannelMatrix::get_class_type())) {
-    AnimChannelMatrix *mchild = DCAST(AnimChannelMatrix, child);
-    AnimChannelMatrixFixed *new_mchild =  new AnimChannelMatrixFixed(this, child->get_name(), mat);
-    new_child = new_mchild;
-  }
-  if(new_child != (AnimGroup*)NULL) {
-    new_child->_children.swap(child->_children);
-    nassertv(_children.back() == new_child);
-    _children[index] = new_child;
-  }
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: AnimGroup::get_value_type
 //       Access: Public, Virtual

+ 0 - 3
panda/src/chan/animGroup.h

@@ -52,7 +52,6 @@ PUBLISHED:
   AnimGroup *get_child(int n) const;
   AnimGroup *find_child(const string &name) const;
 
-  AnimGroup *make_child_dynamic(const string &name);
 public:
   virtual TypeHandle get_value_type() const;
 
@@ -81,8 +80,6 @@ public:
 
   static TypedWritable *make_AnimGroup(const FactoryParams &params);
 
-  void fix_child(unsigned int index, LMatrix4f const & mat);
-
 protected:
   void fillin(DatagramIterator& scan, BamReader* manager);
 

+ 34 - 2
panda/src/chan/movingPartBase.cxx

@@ -43,7 +43,36 @@ MovingPartBase(PartGroup *parent, const string &name)
 //  Description:
 ////////////////////////////////////////////////////////////////////
 MovingPartBase::
-MovingPartBase(){
+MovingPartBase() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MovingPartBase::clear_forced_channel
+//       Access: Published, Virtual
+//  Description: Undoes the effect of a previous call to
+//               apply_freeze() or apply_control().  Returns true if
+//               the joint was modified, false otherwise.
+////////////////////////////////////////////////////////////////////
+bool MovingPartBase::
+clear_forced_channel() {
+  if (_forced_channel != (AnimChannelBase *)NULL) {
+    _forced_channel.clear();
+    return true;
+  }
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MovingPartBase::get_forced_channel
+//       Access: Published, Virtual
+//  Description: Returns the AnimChannelBase that has been forced to
+//               this joint by a previous call to apply_freeze() or
+//               apply_control(), or NULL if no such channel has been
+//               applied.
+////////////////////////////////////////////////////////////////////
+AnimChannelBase *MovingPartBase::
+get_forced_channel() const {
+  return _forced_channel;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -106,7 +135,10 @@ do_update(PartBundle *root, const CycleData *root_cdata, PartGroup *parent,
 
   // See if any of the channel values have changed since last time.
 
-  {
+  if (_forced_channel != (AnimChannelBase *)NULL) {
+    needs_update = _forced_channel->has_changed(0.0, 0.0);
+
+  } else {
     const PartBundle::CData *cdata = (const PartBundle::CData *)root_cdata;
     PartBundle::ChannelBlend::const_iterator bci;
     for (bci = cdata->_blend.begin();

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

@@ -51,6 +51,9 @@ public:
   virtual AnimChannelBase *make_initial_channel() const=0;
 
 PUBLISHED:
+  virtual bool clear_forced_channel();
+  virtual AnimChannelBase *get_forced_channel() const;
+
   virtual void write(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;
@@ -76,9 +79,9 @@ protected:
 
   typedef pvector< PT(AnimChannelBase) > Channels;
   Channels _channels;
+  PT(AnimChannelBase) _forced_channel;
 
 public:
-
   virtual TypeHandle get_type() const {
     return get_class_type();
   }

+ 43 - 5
panda/src/chan/movingPartMatrix.cxx

@@ -18,6 +18,7 @@
 
 
 #include "movingPartMatrix.h"
+#include "animChannelMatrixDynamic.h"
 #include "animChannelMatrixFixed.h"
 #include "compose_matrix.h"
 #include "datagram.h"
@@ -51,7 +52,7 @@ MovingPartMatrix::
 ////////////////////////////////////////////////////////////////////
 AnimChannelBase *MovingPartMatrix::
 make_initial_channel() const {
-  return new AnimChannelMatrixFixed(get_name(), _initial_value);
+  return new AnimChannelMatrixFixed(get_name(), TransformState::make_mat(_initial_value));
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -63,6 +64,15 @@ make_initial_channel() const {
 ////////////////////////////////////////////////////////////////////
 void MovingPartMatrix::
 get_blend_value(const PartBundle *root) {
+  // If a forced channel is set on this particular joint, we always
+  // return that value instead of performing the blend.  Furthermore,
+  // the frame number is always 0 for the forced channel.
+  if (_forced_channel != (AnimChannelBase *)NULL) {
+    ChannelType *channel = DCAST(ChannelType, _forced_channel);
+    channel->get_value(0, _value);
+    return;
+  }
+
   PartBundle::CDReader cdata(root->_cycler);
 
   if (cdata->_blend.empty()) {
@@ -360,14 +370,43 @@ get_blend_value(const PartBundle *root) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: MovingPartMatrix::apply_freeze
+//       Access: Public, Virtual
+//  Description: Freezes this particular joint so that it will always
+//               hold the specified transform.  Returns true if this
+//               is a joint that can be so frozen, false otherwise.
+//               This is called internally by
+//               PartBundle::freeze_joint().
+////////////////////////////////////////////////////////////////////
+bool MovingPartMatrix::
+apply_freeze(const TransformState *transform) {
+  _forced_channel = new AnimChannelMatrixFixed(get_name(), transform);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MovingPartMatrix::apply_control
+//       Access: Public, Virtual
+//  Description: Specifies a node to influence this particular joint
+//               so that it will always hold the node's transform.
+//               Returns true if this is a joint that can be so
+//               controlled, false otherwise.  This is called
+//               internally by PartBundle::control_joint().
+////////////////////////////////////////////////////////////////////
+bool MovingPartMatrix::
+apply_control(PandaNode *node) {
+  AnimChannelMatrixDynamic *chan = new AnimChannelMatrixDynamic(get_name());
+  chan->set_value_node(node);
+  _forced_channel = chan;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: MovingPartMatrix::make_MovingPartMatrix
 //       Access: Protected
 //  Description: Factory method to generate a MovingPartMatrix object
 ////////////////////////////////////////////////////////////////////
 TypedWritable* MovingPartMatrix::
-make_MovingPartMatrix(const FactoryParams &params)
-{
+make_MovingPartMatrix(const FactoryParams &params) {
   MovingPartMatrix *me = new MovingPartMatrix;
   DatagramIterator scan;
   BamReader *manager;
@@ -383,7 +422,6 @@ make_MovingPartMatrix(const FactoryParams &params)
 //  Description: Factory method to generate a MovingPartMatrix object
 ////////////////////////////////////////////////////////////////////
 void MovingPartMatrix::
-register_with_read_factory()
-{
+register_with_read_factory() {
   BamReader::get_factory()->register_factory(get_class_type(), make_MovingPartMatrix);
 }

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

@@ -46,6 +46,9 @@ public:
   virtual AnimChannelBase *make_initial_channel() const;
   virtual void get_blend_value(const PartBundle *root);
 
+  virtual bool apply_freeze(const TransformState *transform);
+  virtual bool apply_control(PandaNode *node);
+
 protected:
   INLINE MovingPartMatrix();
 

+ 42 - 4
panda/src/chan/movingPartScalar.cxx

@@ -18,6 +18,7 @@
 
 
 #include "movingPartScalar.h"
+#include "animChannelScalarDynamic.h"
 #include "datagram.h"
 #include "datagramIterator.h"
 #include "bamReader.h"
@@ -48,6 +49,15 @@ MovingPartScalar::
 ////////////////////////////////////////////////////////////////////
 void MovingPartScalar::
 get_blend_value(const PartBundle *root) {
+  // If a forced channel is set on this particular scalar, we always
+  // return that value instead of performing the blend.  Furthermore,
+  // the frame number is always 0 for the forced channel.
+  if (_forced_channel != (AnimChannelBase *)NULL) {
+    ChannelType *channel = DCAST(ChannelType, _forced_channel);
+    channel->get_value(0, _value);
+    return;
+  }
+
   PartBundle::CDReader cdata(root->_cycler);
 
   if (cdata->_blend.empty()) {
@@ -111,14 +121,43 @@ get_blend_value(const PartBundle *root) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: MovingPartScalar::apply_freeze
+//       Access: Public, Virtual
+//  Description: Freezes this particular joint so that it will always
+//               hold the specified transform.  Returns true if this
+//               is a joint that can be so frozen, false otherwise.
+//               This is called internally by
+//               PartBundle::freeze_joint().
+////////////////////////////////////////////////////////////////////
+bool MovingPartScalar::
+apply_freeze(const TransformState *transform) {
+  _forced_channel = new AnimChannelFixed<ACScalarSwitchType>(get_name(), transform->get_pos()[0]);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: MovingPartScalar::apply_control
+//       Access: Public, Virtual
+//  Description: Specifies a node to influence this particular joint
+//               so that it will always hold the node's transform.
+//               Returns true if this is a joint that can be so
+//               controlled, false otherwise.  This is called
+//               internally by PartBundle::control_joint().
+////////////////////////////////////////////////////////////////////
+bool MovingPartScalar::
+apply_control(PandaNode *node) {
+  AnimChannelScalarDynamic *chan = new AnimChannelScalarDynamic(get_name());
+  chan->set_value_node(node);
+  _forced_channel = chan;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: MovingPartScalar::make_MovingPartScalar
 //       Access: Protected
 //  Description: Factory method to generate a MovingPartScalar object
 ////////////////////////////////////////////////////////////////////
 TypedWritable* MovingPartScalar::
-make_MovingPartScalar(const FactoryParams &params)
-{
+make_MovingPartScalar(const FactoryParams &params) {
   MovingPartScalar *me = new MovingPartScalar;
   DatagramIterator scan;
   BamReader *manager;
@@ -134,8 +173,7 @@ make_MovingPartScalar(const FactoryParams &params)
 //  Description: Factory method to generate a MovingPartScalar object
 ////////////////////////////////////////////////////////////////////
 void MovingPartScalar::
-register_with_read_factory()
-{
+register_with_read_factory() {
   BamReader::get_factory()->register_factory(get_class_type(), make_MovingPartScalar);
 }
 

+ 3 - 0
panda/src/chan/movingPartScalar.h

@@ -43,6 +43,9 @@ public:
 
   virtual void get_blend_value(const PartBundle *root);
 
+  virtual bool apply_freeze(const TransformState *transform);
+  virtual bool apply_control(PandaNode *node);
+
 protected:
   INLINE MovingPartScalar();
 

+ 0 - 36
panda/src/chan/partBundle.I

@@ -206,39 +206,3 @@ get_control_effect(AnimControl *control) const {
   CDReader cdata(_cycler);
   return do_get_control_effect(control, cdata);
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: PartBundle::get_modifies_anim_bundles
-//       Access: Published
-//  Description: getter for anim copying
-////////////////////////////////////////////////////////////////////
-INLINE bool PartBundle::
-get_modifies_anim_bundles(){
-  return _modifies_anim_bundles;
-}
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: PartBundle::set_modifies_anim_bundles
-//       Access: Published
-//  Description: setter for anim copying
-////////////////////////////////////////////////////////////////////
-INLINE void PartBundle::
-set_modifies_anim_bundles(bool value){
-  _modifies_anim_bundles = value;
-}
-
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: PartGroup::freeze
-//       Access: Published
-//  Description: stores a joint freeze for later binding
-////////////////////////////////////////////////////////////////////
-INLINE void PartBundle::
-freeze_joint(const string &joint_name, LMatrix4f const &transform)
-{
-  PT(PartGroup) pg = find_child(joint_name);
-  pg->freeze(transform);
-  _modifies_anim_bundles = true;
-}

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

@@ -51,8 +51,7 @@ static ConfigVariableEnum<PartBundle::BlendType> anim_blend_type
 ////////////////////////////////////////////////////////////////////
 PartBundle::
 PartBundle(const PartBundle &copy) :
-  PartGroup(copy),
-  _modifies_anim_bundles(copy._modifies_anim_bundles)
+  PartGroup(copy)
 {
   CDWriter cdata(_cycler, true);
   CDReader cdata_from(copy._cycler);
@@ -71,8 +70,7 @@ PartBundle(const PartBundle &copy) :
 ////////////////////////////////////////////////////////////////////
 PartBundle::
 PartBundle(const string &name) : 
-  PartGroup(name),
-  _modifies_anim_bundles(false)
+  PartGroup(name)
 {
 }
 
@@ -224,10 +222,6 @@ bind_anim(AnimBundle *anim, int hierarchy_match_flags,
     }
   }
 
-  if(_modifies_anim_bundles) {
-    ptanim = ptanim->copy_bundle();
-  }
-
   if (!check_hierarchy(anim, NULL, hierarchy_match_flags)) {
     return NULL;
   }
@@ -250,6 +244,74 @@ bind_anim(AnimBundle *anim, int hierarchy_match_flags,
   return new AnimControl(this, anim, channel_index, bound_joints);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PartBundle::freeze_joint
+//       Access: Published
+//  Description: Specifies that the joint with the indicated name
+//               should be frozen with the specified transform.  It
+//               will henceforth always hold this fixed transform,
+//               regardless of any animations that may subsequently be
+//               bound to the joint.
+//
+//               Returns true if the joint is successfully frozen, or
+//               false if the named child is not a joint (or slider)
+//               or does not exist.
+////////////////////////////////////////////////////////////////////
+bool PartBundle::
+freeze_joint(const string &joint_name, const TransformState *transform) {
+  PartGroup *child = find_child(joint_name);
+  if (child == (PartGroup *)NULL) {
+    return false;
+  }
+
+  return child->apply_freeze(transform);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartBundle::control_joint
+//       Access: Published
+//  Description: Specifies that the joint with the indicated name
+//               should be animated with the transform on the
+//               indicated node.  It will henceforth always follow the
+//               node's transform, regardless of any animations that
+//               may subsequently be bound to the joint.
+//
+//               Returns true if the joint is successfully controlled,
+//               or false if the named child is not a joint (or
+//               slider) or does not exist.
+////////////////////////////////////////////////////////////////////
+bool PartBundle::
+control_joint(const string &joint_name, PandaNode *node) {
+  PartGroup *child = find_child(joint_name);
+  if (child == (PartGroup *)NULL) {
+    return false;
+  }
+
+  return child->apply_control(node);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartBundle::release_joint
+//       Access: Published
+//  Description: Releases the named joint from the effects of a
+//               previous call to freeze_joint() or control_joint().
+//               It will henceforth once again follow whatever
+//               transforms are dictated by the animation.
+//
+//               Returns true if the joint is released, or false if
+//               the named child was not previously controlled or
+//               frozen, or it does not exist.
+////////////////////////////////////////////////////////////////////
+bool PartBundle::
+release_joint(const string &joint_name) {
+  PartGroup *child = find_child(joint_name);
+  if (child == (PartGroup *)NULL) {
+    return false;
+  }
+
+  return child->clear_forced_channel();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PartBundle::update
 //       Access: Published
@@ -498,7 +560,6 @@ void PartBundle::
 write_datagram(BamWriter *manager, Datagram &dg) {
   PartGroup::write_datagram(manager, dg);
   manager->write_cdata(dg, _cycler);
-  dg.add_bool(_modifies_anim_bundles);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -532,8 +593,9 @@ fillin(DatagramIterator &scan, BamReader *manager) {
   if (manager->get_file_minor_ver() >= 10) {
     manager->read_cdata(scan, _cycler);
   }
-  if (manager->get_file_minor_ver() >= 11) {  
-    _modifies_anim_bundles=scan.get_bool();
+  if (manager->get_file_minor_ver() == 11) {  
+    // No longer need the _modifies_anim_bundles flag
+    scan.get_bool();
   }
 }
 

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

@@ -36,6 +36,7 @@
 class AnimBundle;
 class PartBundleNode;
 class PartBundleNode;
+class TransformState;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : PartBundle
@@ -120,14 +121,13 @@ PUBLISHED:
                             int hierarchy_match_flags = 0, 
                             const PartSubset &subset = PartSubset());
 
-
-  INLINE void freeze_joint(const string &joint_name, LMatrix4f const &transform);
+  bool freeze_joint(const string &joint_name, const TransformState *transform);
+  bool control_joint(const string &joint_name, PandaNode *node);
+  bool release_joint(const string &joint_name);
 
   bool update();
   bool force_update();
   
-  INLINE bool get_modifies_anim_bundles();
-  INLINE void set_modifies_anim_bundles(bool value);
 public:
   // The following functions aren't really part of the public
   // interface; they're just public so we don't have to declare a
@@ -139,10 +139,6 @@ protected:
   virtual void remove_node(PartBundleNode *node);
 
 private:
-
-  //this is used to determine when to copy the anim bundle
-  bool _modifies_anim_bundles;
-
   class CData;
 
   void do_set_control_effect(AnimControl *control, float effect, CData *cdata);

+ 2 - 18
panda/src/chan/partGroup.I

@@ -27,8 +27,7 @@
 INLINE PartGroup::
 PartGroup(const string &name) :
   Namable(name),
-  _children(get_class_type()),
-  _frozen(0)
+  _children(get_class_type())
 {
 }
 
@@ -42,23 +41,8 @@ PartGroup(const string &name) :
 INLINE PartGroup::
 PartGroup(const PartGroup &copy) :
   Namable(copy),
-  _children(get_class_type()),
-  _frozen(copy._frozen),
-  _frozen_transform(copy._frozen_transform)
+  _children(get_class_type())
 {
   // We don't copy children in the copy constructor.  However,
   // copy_subgraph() will do this.
 }
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: PartGroup::freeze
-//       Access: Published
-//  Description: stores a joint freeze for later binding
-////////////////////////////////////////////////////////////////////
-INLINE void PartGroup::
-freeze(LMatrix4f const &transform) 
-{
-  _frozen = true;
-  _frozen_transform=LMatrix4f(transform);
-}

+ 86 - 47
panda/src/chan/partGroup.cxx

@@ -46,7 +46,6 @@ PartGroup(PartGroup *parent, const string &name) :
   nassertv(parent != NULL);
   
   parent->_children.push_back(this);
-  _frozen = false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -139,6 +138,68 @@ find_child(const string &name) const {
   return (PartGroup *)NULL;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: PartGroup::apply_freeze
+//       Access: Published, Virtual
+//  Description: Freezes this particular joint so that it will always
+//               hold the specified transform.  Returns true if this
+//               is a joint that can be so frozen, false otherwise.
+//
+//               This is normally only called internally by
+//               PartBundle::freeze_joint(), but you may also call it
+//               directly.
+////////////////////////////////////////////////////////////////////
+bool PartGroup::
+apply_freeze(const TransformState *transform) {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartGroup::apply_control
+//       Access: Published, Virtual
+//  Description: Specifies a node to influence this particular joint
+//               so that it will always hold the node's transform.
+//               Returns true if this is a joint that can be so
+//               controlled, false otherwise.
+//
+//               This is normally only called internally by
+//               PartBundle::control_joint(), but you may also call it
+//               directly.
+////////////////////////////////////////////////////////////////////
+bool PartGroup::
+apply_control(PandaNode *node) {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartGroup::clear_forced_channel
+//       Access: Published, Virtual
+//  Description: Undoes the effect of a previous call to
+//               apply_freeze() or apply_control().  Returns true if
+//               the joint was modified, false otherwise.
+//
+//               This is normally only called internally by
+//               PartBundle::release_joint(), but you may also call it
+//               directly.
+////////////////////////////////////////////////////////////////////
+bool PartGroup::
+clear_forced_channel() {
+  return false;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PartGroup::get_forced_channel
+//       Access: Published, Virtual
+//  Description: Returns the AnimChannelBase that has been forced to
+//               this joint by a previous call to apply_freeze() or
+//               apply_control(), or NULL if no such channel has been
+//               applied.
+////////////////////////////////////////////////////////////////////
+AnimChannelBase *PartGroup::
+get_forced_channel() const {
+  return NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: PartGroup::get_value_type
 //       Access: Public, Virtual
@@ -192,9 +253,6 @@ sort_descendants() {
 //               PartGroup::HierarchyMatchFlags values indicating
 //               conditions that will be tolerated (but warnings will
 //               still be issued).
-//
-//               If there is a discrepancy, it is reported to the
-//               indicated output stream, if it is non-null.
 ////////////////////////////////////////////////////////////////////
 bool PartGroup::
 check_hierarchy(const AnimGroup *anim, const PartGroup *,
@@ -426,9 +484,6 @@ write_descendants_with_value(ostream &out, int indent_level) const {
   }
 }
 
-
-
-
 ////////////////////////////////////////////////////////////////////
 //     Function: PartGroup::pick_channel_index
 //       Access: Protected, Virtual
@@ -468,10 +523,6 @@ bind_hierarchy(AnimGroup *anim, int channel_index, int &joint_index,
 
   while (i < part_num_children && j < anim_num_children) {
     PartGroup *pc = get_child(i);
-    if (pc->_frozen) {
-      anim->fix_child(j, pc->_frozen_transform);
-    }
-
     AnimGroup *ac = anim->get_child(j);
 
     if (pc->get_name() < ac->get_name()) {
@@ -510,15 +561,10 @@ bind_hierarchy(AnimGroup *anim, int channel_index, int &joint_index,
 //               the particular object to a Datagram
 ////////////////////////////////////////////////////////////////////
 void PartGroup::
-write_datagram(BamWriter *manager, Datagram &me)
-{
-  int i;
+write_datagram(BamWriter *manager, Datagram &me) {
   me.add_string(get_name());
-  me.add_bool(_frozen);
-  _frozen_transform.write_datagram(me);
   me.add_uint16(_children.size());
-  for(i = 0; i < (int)_children.size(); i++)
-  {
+  for (size_t i = 0; i < _children.size(); i++) {
     manager->write_pointer(me, _children[i]);
   }
 }
@@ -532,46 +578,41 @@ write_datagram(BamWriter *manager, Datagram &me)
 //               place
 ////////////////////////////////////////////////////////////////////
 void PartGroup::
-fillin(DatagramIterator& scan, BamReader* manager)
-{
-  int i;
+fillin(DatagramIterator &scan, BamReader *manager) {
   set_name(scan.get_string());
-  if (manager->get_file_minor_ver() >= 11) {
-    _frozen=scan.get_bool();
-    _frozen_transform.read_datagram(scan);
+
+  if (manager->get_file_minor_ver() == 11) {
+    // Skip over the old freeze-joint information, no longer stored here
+    scan.get_bool();
+    LMatrix4f mat;
+    mat.read_datagram(scan);
   }
-  _num_children = scan.get_uint16();
-  for(i = 0; i < _num_children; i++)
-  {
+
+  int num_children = scan.get_uint16();
+  _children.reserve(num_children);
+  for (int i = 0; i < num_children; i++) {
     manager->read_pointer(scan);
+    _children.push_back(NULL);
   }
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: PartGroup::complete_pointers
 //       Access: Public
-//  Description: Takes in a vector of pointes to TypedWritable
+//  Description: Takes in a vector of pointers to TypedWritable
 //               objects that correspond to all the requests for
 //               pointers that this object made to BamReader.
 ////////////////////////////////////////////////////////////////////
 int PartGroup::
-complete_pointers(TypedWritable **p_list, BamReader*)
-{
-  int i;
-  for(i = 0; i < _num_children; i++)
-  {
-    if (p_list[i] == TypedWritable::Null)
-    {
-      chan_cat->warning() << get_type().get_name()
-                          << " Ignoring null PartGroup" << endl;
-    }
-    else
-    {
-      _children.push_back(DCAST(PartGroup, p_list[i]));
-    }
+complete_pointers(TypedWritable **p_list, BamReader *manager) {
+  int pi = TypedWritableReferenceCount::complete_pointers(p_list, manager);
+  
+  Children::iterator ci;
+  for (ci = _children.begin(); ci != _children.end(); ++ci) {
+    (*ci) = DCAST(PartGroup, p_list[pi++]);
   }
 
-  return _num_children;
+  return pi;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -580,8 +621,7 @@ complete_pointers(TypedWritable **p_list, BamReader*)
 //  Description: Factory method to generate a PartGroup object
 ////////////////////////////////////////////////////////////////////
 TypedWritable* PartGroup::
-make_PartGroup(const FactoryParams &params)
-{
+make_PartGroup(const FactoryParams &params) {
   PartGroup *me = new PartGroup;
   DatagramIterator scan;
   BamReader *manager;
@@ -597,8 +637,7 @@ make_PartGroup(const FactoryParams &params)
 //  Description: Factory method to generate a PartGroup object
 ////////////////////////////////////////////////////////////////////
 void PartGroup::
-register_with_read_factory()
-{
+register_with_read_factory() {
   BamReader::get_factory()->register_factory(get_class_type(), make_PartGroup);
 }
 

+ 9 - 11
panda/src/chan/partGroup.h

@@ -37,6 +37,9 @@ class BamReader;
 class FactoryParams;
 class BitArray;
 class CycleData;
+class TransformState;
+class PandaNode;
+class AnimChannelBase;
 
 ////////////////////////////////////////////////////////////////////
 //       Class : PartGroup
@@ -76,11 +79,14 @@ PUBLISHED:
   PartGroup *get_child(int n) const;
   PartGroup *find_child(const string &name) const;
 
+  virtual bool apply_freeze(const TransformState *transform);
+  virtual bool apply_control(PandaNode *node);
+  virtual bool clear_forced_channel();
+  virtual AnimChannelBase *get_forced_channel() const;
+
   virtual void write(ostream &out, int indent_level) const;
   virtual void write_with_value(ostream &out, int indent_level) const;
 
-  INLINE void freeze(LMatrix4f const &transform);
-
 public:
   virtual TypeHandle get_value_type() const;
 
@@ -118,14 +124,7 @@ public:
 protected:
   void fillin(DatagramIterator& scan, BamReader* manager);
 
-private:
-  int _num_children;
-
-  bool _frozen;
-  LMatrix4f _frozen_transform;
-
 public:
-
   virtual TypeHandle get_type() const {
     return get_class_type();
   }
@@ -141,13 +140,12 @@ public:
                   TypedWritableReferenceCount::get_class_type());
   }
 
-
 private:
   static TypeHandle _type_handle;
 
   friend class Character;
   friend class CharacterJointBundle;
-
+  friend class PartBundle;
 };
 
 #include "partGroup.I"

+ 6 - 0
panda/src/char/characterJointBundle.cxx

@@ -89,6 +89,12 @@ remove_node(PartBundleNode *node) {
 ////////////////////////////////////////////////////////////////////
 void CharacterJointBundle::
 r_set_character(PartGroup *group, Character *character) {
+  if (group == (PartGroup *)NULL) {
+    // This might happen if we are in the middle of reading the
+    // Character's hierarchy from the bam file.
+    return;
+  }
+
   if (group->is_of_type(CharacterJoint::get_class_type())) {
     DCAST(CharacterJoint, group)->set_character(character);
   }

+ 2 - 1
panda/src/putil/bam.h

@@ -36,7 +36,7 @@ static const unsigned short _bam_major_ver = 6;
 // Bumped to major version 5 on 5/6/05 for new Geom implementation.
 // Bumped to major version 6 on 2/11/06 to factor out PandaNode::CData.
 
-static const unsigned short _bam_minor_ver = 11;
+static const unsigned short _bam_minor_ver = 12;
 // Bumped to minor version 1 on 3/12/06 to add Texture::_compression.
 // Bumped to minor version 2 on 3/17/06 to add PandaNode::_draw_control_mask.
 // Bumped to minor version 3 on 3/21/06 to add Texture::_ram_images.
@@ -48,6 +48,7 @@ static const unsigned short _bam_minor_ver = 11;
 // Bumped to minor version 9 on 5/15/07 to add PlaneNode::_clip_effect.
 // Bumped to minor version 10 on 6/19/07 to properly write PartBundles.
 // Bumped to minor version 11 on 6/20/07 to write frozen joints to PartGroups.
+// Bumped to minor version 12 on 7/3/07 to rework control/frozen joints more.
 
 
 #endif