Browse Source

shave a few more microseconds off animation time

David Rose 17 years ago
parent
commit
a666ef78fe

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

@@ -22,7 +22,9 @@
 INLINE MovingPartBase::
 INLINE MovingPartBase::
 MovingPartBase(const MovingPartBase &copy) :
 MovingPartBase(const MovingPartBase &copy) :
   PartGroup(copy),
   PartGroup(copy),
-  _forced_channel(copy._forced_channel)
+  _forced_channel(copy._forced_channel),
+  _num_effective_channels(0),
+  _effective_control(NULL)
 {
 {
   // We don't copy the bound channels.  We do copy the forced_channel,
   // We don't copy the bound channels.  We do copy the forced_channel,
   // though this is just a pointerwise copy.
   // though this is just a pointerwise copy.

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

@@ -29,8 +29,11 @@ TypeHandle MovingPartBase::_type_handle;
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 MovingPartBase::
 MovingPartBase::
-MovingPartBase(PartGroup *parent, const string &name)
-  : PartGroup(parent, name) {
+MovingPartBase(PartGroup *parent, const string &name) :
+  PartGroup(parent, name),
+  _num_effective_channels(0),
+  _effective_control(NULL)
+{
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -39,7 +42,10 @@ MovingPartBase(PartGroup *parent, const string &name)
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 MovingPartBase::
 MovingPartBase::
-MovingPartBase() {
+MovingPartBase() :
+  _num_effective_channels(0),
+  _effective_control(NULL)
+{
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -136,6 +142,10 @@ do_update(PartBundle *root, const CycleData *root_cdata, PartGroup *parent,
       needs_update = _forced_channel->has_changed(0, 0.0, 0, 0.0);
       needs_update = _forced_channel->has_changed(0, 0.0, 0, 0.0);
     }
     }
 
 
+  } else if (_effective_control != (AnimControl *)NULL) {
+    const PartBundle::CData *cdata = (const PartBundle::CData *)root_cdata;
+    needs_update = _effective_control->channel_has_changed(_effective_channel, cdata->_frame_blend_flag);
+
   } else {
   } else {
     const PartBundle::CData *cdata = (const PartBundle::CData *)root_cdata;
     const PartBundle::CData *cdata = (const PartBundle::CData *)root_cdata;
     PartBundle::ChannelBlend::const_iterator bci;
     PartBundle::ChannelBlend::const_iterator bci;
@@ -315,3 +325,45 @@ find_bound_joints(int &joint_index, bool is_included, BitArray &bound_joints,
 
 
   PartGroup::find_bound_joints(joint_index, is_included, bound_joints, subset);
   PartGroup::find_bound_joints(joint_index, is_included, bound_joints, subset);
 }
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: MovingPartBase::determine_effective_channels
+//       Access: Protected, Virtual
+//  Description: Should be called whenever the ChannelBlend values
+//               have changed, this recursively updates the
+//               _effective_channel member in each part.
+////////////////////////////////////////////////////////////////////
+void MovingPartBase::
+determine_effective_channels(const CycleData *root_cdata) {
+  _effective_control = NULL;
+  _effective_channel = NULL;
+  _num_effective_channels = 0;
+
+  AnimControl *effective_control = NULL;
+  AnimChannelBase *effective_channel = NULL;
+  int num_effective_channels = 0;
+
+  const PartBundle::CData *cdata = (const PartBundle::CData *)root_cdata;
+  PartBundle::ChannelBlend::const_iterator cbi;
+  for (cbi = cdata->_blend.begin(); 
+       cbi != cdata->_blend.end(); 
+       ++cbi) {
+    AnimControl *control = (*cbi).first;
+    int channel_index = control->get_channel_index();
+    if (channel_index >= 0 && channel_index < (int)_channels.size()) {
+      if (_channels[channel_index] != (AnimChannelBase *)NULL) {
+        effective_control = control;
+        effective_channel = _channels[channel_index];
+        ++num_effective_channels;
+      }
+    }
+  }
+
+  _num_effective_channels = num_effective_channels;
+  if (num_effective_channels == 1) {
+    _effective_control = effective_control;
+    _effective_channel = effective_channel;
+  }
+
+  PartGroup::determine_effective_channels(root_cdata);
+}

+ 17 - 0
panda/src/chan/movingPartBase.h

@@ -75,9 +75,26 @@ protected:
   virtual void find_bound_joints(int &joint_index, bool is_included, 
   virtual void find_bound_joints(int &joint_index, bool is_included, 
                                  BitArray &bound_joints,
                                  BitArray &bound_joints,
                                  const PartSubset &subset);
                                  const PartSubset &subset);
+  virtual void determine_effective_channels(const CycleData *root_cdata);
 
 
+  // This is the vector of all channels bound to this part.
   typedef pvector< PT(AnimChannelBase) > Channels;
   typedef pvector< PT(AnimChannelBase) > Channels;
   Channels _channels;
   Channels _channels;
+
+  // This is the number of channels in the above _channels vector that
+  // actually have an effect on this part.
+  int _num_effective_channels;
+
+  // This is the single channel that has an effect on this part, as
+  // determined by determine_effective_channels().  It is only set if
+  // there is exactly one channel that affects this part
+  // (i.e. _num_effective_channels is 1).  If there are multiple
+  // channels, or no channels at all, it is NULL.
+  AnimControl *_effective_control;
+  PT(AnimChannelBase) _effective_channel;
+
+  // This is the particular channel that's been forced to this part,
+  // via set_forced_channel().  It overrides all of the above if set.
   PT(AnimChannelBase) _forced_channel;
   PT(AnimChannelBase) _forced_channel;
 
 
 public:
 public:

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

@@ -77,39 +77,16 @@ get_blend_value(const PartBundle *root) {
       _value = _initial_value;
       _value = _initial_value;
     }
     }
 
 
-  } else if ((cdata->_blend.size() == 1 || !cdata->_anim_blend_flag) && 
+  } else if (_effective_control != (AnimControl *)NULL && 
              !cdata->_frame_blend_flag) {
              !cdata->_frame_blend_flag) {
     // A single value, the normal case.
     // A single value, the normal case.
-    AnimControl *bound_control = NULL;
-    ChannelType *bound_channel = NULL;
-
-    PartBundle::ChannelBlend::const_iterator cbi;
-    for (cbi = cdata->_blend.begin(); 
-         cbi != cdata->_blend.end() && bound_channel == (ChannelType *)NULL; 
-         ++cbi) {
-      AnimControl *control = (*cbi).first;
-      int channel_index = control->get_channel_index();
-      if (channel_index >= 0 && channel_index < (int)_channels.size()) {
-        bound_control = control;
-        bound_channel = DCAST(ChannelType, _channels[channel_index]);
-      }
-    }
-
-    if (bound_channel == (ChannelType *)NULL) {
-      // Nothing is actually bound here.
-      if (restore_initial_pose) {
-        _value = _initial_value;
-      }
-
-    } else {
-      bound_channel->get_value(bound_control->get_frame(), _value);
-    }
+    ChannelType *channel = DCAST(ChannelType, _effective_channel);
+    channel->get_value(_effective_control->get_frame(), _value);
 
 
   } else {
   } else {
     // A blend of two or more values, either between multiple
     // A blend of two or more values, either between multiple
     // different animations, or between consecutive frames of the same
     // different animations, or between consecutive frames of the same
     // animation (or both).
     // animation (or both).
-
     switch (cdata->_blend_type) {
     switch (cdata->_blend_type) {
     case PartBundle::BT_linear:
     case PartBundle::BT_linear:
       {
       {

+ 3 - 25
panda/src/chan/movingPartScalar.cxx

@@ -62,33 +62,11 @@ get_blend_value(const PartBundle *root) {
       _value = _initial_value;
       _value = _initial_value;
     }
     }
 
 
-  } else if ((cdata->_blend.size() == 1 || !cdata->_anim_blend_flag) && 
+  } else if (_effective_control != (AnimControl *)NULL &&
              !cdata->_frame_blend_flag) {
              !cdata->_frame_blend_flag) {
     // A single value, the normal case.
     // A single value, the normal case.
-    AnimControl *bound_control = NULL;
-    ChannelType *bound_channel = NULL;
-
-    PartBundle::ChannelBlend::const_iterator cbi;
-    for (cbi = cdata->_blend.begin(); 
-         cbi != cdata->_blend.end() && bound_channel == (ChannelType *)NULL; 
-         ++cbi) {
-      AnimControl *control = (*cbi).first;
-      int channel_index = control->get_channel_index();
-      if (channel_index >= 0 && channel_index < (int)_channels.size()) {
-        bound_control = control;
-        bound_channel = DCAST(ChannelType, _channels[channel_index]);
-      }
-    }
-
-    if (bound_channel == NULL) {
-      // Nothing is actually bound here.
-      if (restore_initial_pose) {
-        _value = _initial_value;
-      }
-
-    } else {
-      bound_channel->get_value(bound_control->get_frame(), _value);
-    }
+    ChannelType *channel = DCAST(ChannelType, _effective_channel);
+    channel->get_value(_effective_control->get_frame(), _value);
 
 
   } else {
   } else {
     // A blend of two or more values.
     // A blend of two or more values.

+ 5 - 0
panda/src/chan/partBundle.cxx

@@ -603,6 +603,10 @@ do_bind_anim(AnimControl *control, AnimBundle *anim,
   bind_hierarchy(ptanim, channel_index, joint_index, 
   bind_hierarchy(ptanim, channel_index, joint_index, 
                  subset.is_include_empty(), bound_joints, subset);
                  subset.is_include_empty(), bound_joints, subset);
   control->setup_anim(this, anim, channel_index, bound_joints);
   control->setup_anim(this, anim, channel_index, bound_joints);
+
+  CDReader cdata(_cycler);
+  determine_effective_channels(cdata);
+
   return true;
   return true;
 }
 }
 
 
@@ -706,6 +710,7 @@ recompute_net_blend(CData *cdata) {
   for (bti = cdata->_blend.begin(); bti != cdata->_blend.end(); ++bti) {
   for (bti = cdata->_blend.begin(); bti != cdata->_blend.end(); ++bti) {
     cdata->_net_blend += (*bti).second;
     cdata->_net_blend += (*bti).second;
   }
   }
+  determine_effective_channels(cdata);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 27 - 0
panda/src/chan/partGroup.cxx

@@ -53,6 +53,18 @@ PartGroup::
 ~PartGroup() {
 ~PartGroup() {
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PartGroup::is_character_joint
+//       Access: Public, Virtual
+//  Description: Returns true if this part is a CharacterJoint, false
+//               otherwise.  This is a tiny optimization over
+//               is_of_type(CharacterType::get_class_type()).
+////////////////////////////////////////////////////////////////////
+bool PartGroup::
+is_character_joint() const {
+  return false;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PartGroup::make_copy
 //     Function: PartGroup::make_copy
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -450,6 +462,21 @@ do_xform(const LMatrix4f &mat, const LMatrix4f &inv_mat) {
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PartGroup::determine_effective_channels
+//       Access: Public, Virtual
+//  Description: Should be called whenever the ChannelBlend values
+//               have changed, this recursively updates the
+//               _effective_channel member in each part.
+////////////////////////////////////////////////////////////////////
+void PartGroup::
+determine_effective_channels(const CycleData *root_cdata) {
+  Children::iterator ci;
+  for (ci = _children.begin(); ci != _children.end(); ++ci) {
+    (*ci)->determine_effective_channels(root_cdata);
+  }
+}
+
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PartGroup::write_descendants
 //     Function: PartGroup::write_descendants

+ 2 - 0
panda/src/chan/partGroup.h

@@ -66,6 +66,7 @@ PUBLISHED:
   // This is the normal PartGroup constructor.
   // This is the normal PartGroup constructor.
   PartGroup(PartGroup *parent, const string &name);
   PartGroup(PartGroup *parent, const string &name);
   virtual ~PartGroup();
   virtual ~PartGroup();
+  virtual bool is_character_joint() const;
 
 
   virtual PartGroup *make_copy() const;
   virtual PartGroup *make_copy() const;
   PartGroup *copy_subgraph() const;
   PartGroup *copy_subgraph() const;
@@ -96,6 +97,7 @@ public:
                          PartGroup *parent, bool parent_changed, 
                          PartGroup *parent, bool parent_changed, 
                          bool anim_changed, Thread *current_thread);
                          bool anim_changed, Thread *current_thread);
   virtual void do_xform(const LMatrix4f &mat, const LMatrix4f &inv_mat);
   virtual void do_xform(const LMatrix4f &mat, const LMatrix4f &inv_mat);
+  virtual void determine_effective_channels(const CycleData *root_cdata);
 
 
 protected:
 protected:
   void write_descendants(ostream &out, int indent_level) const;
   void write_descendants(ostream &out, int indent_level) const;

+ 19 - 8
panda/src/char/characterJoint.cxx

@@ -83,6 +83,18 @@ CharacterJoint::
   nassertv(_character == (Character *)NULL);
   nassertv(_character == (Character *)NULL);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: CharacterJoint::is_character_joint
+//       Access: Public, Virtual
+//  Description: Returns true if this part is a CharacterJoint, false
+//               otherwise.  This is a tiny optimization over
+//               is_of_type(CharacterType::get_class_type()).
+////////////////////////////////////////////////////////////////////
+bool CharacterJoint::
+is_character_joint() const {
+  return true;
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: CharacterJoint::make_copy
 //     Function: CharacterJoint::make_copy
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -112,11 +124,10 @@ make_copy() const {
 bool CharacterJoint::
 bool CharacterJoint::
 update_internals(PartBundle *root, PartGroup *parent, bool self_changed, 
 update_internals(PartBundle *root, PartGroup *parent, bool self_changed, 
                  bool parent_changed, Thread *current_thread) {
                  bool parent_changed, Thread *current_thread) {
-
   nassertr(parent != (PartGroup *)NULL, false);
   nassertr(parent != (PartGroup *)NULL, false);
 
 
   bool net_changed = false;
   bool net_changed = false;
-  if (parent->is_of_type(CharacterJoint::get_class_type())) {
+  if (parent->is_character_joint()) {
     // The joint is not a toplevel joint; its parent therefore affects
     // The joint is not a toplevel joint; its parent therefore affects
     // its net transform.
     // its net transform.
     if (parent_changed || self_changed) {
     if (parent_changed || self_changed) {
@@ -140,11 +151,11 @@ update_internals(PartBundle *root, PartGroup *parent, bool self_changed,
       CPT(TransformState) t = TransformState::make_mat(_net_transform);
       CPT(TransformState) t = TransformState::make_mat(_net_transform);
       
       
       NodeList::iterator ai;
       NodeList::iterator ai;
-      ai = _net_transform_nodes.begin();
-      while (ai != _net_transform_nodes.end()) {
+      for (ai = _net_transform_nodes.begin();
+           ai != _net_transform_nodes.end();
+           ++ai) {
         PandaNode *node = *ai;
         PandaNode *node = *ai;
         node->set_transform(t, current_thread);
         node->set_transform(t, current_thread);
-        ++ai;
       }
       }
     }
     }
 
 
@@ -161,11 +172,11 @@ update_internals(PartBundle *root, PartGroup *parent, bool self_changed,
     CPT(TransformState) t = TransformState::make_mat(_value);
     CPT(TransformState) t = TransformState::make_mat(_value);
 
 
     NodeList::iterator ai;
     NodeList::iterator ai;
-    ai = _local_transform_nodes.begin();
-    while (ai != _local_transform_nodes.end()) {
+    for (ai = _local_transform_nodes.begin();
+         ai != _local_transform_nodes.end();
+         ++ai) {
       PandaNode *node = *ai;
       PandaNode *node = *ai;
       node->set_transform(t, current_thread);
       node->set_transform(t, current_thread);
-      ++ai;
     }
     }
   }
   }
 
 

+ 4 - 2
panda/src/char/characterJoint.h

@@ -20,6 +20,7 @@
 #include "movingPartMatrix.h"
 #include "movingPartMatrix.h"
 #include "pandaNode.h"
 #include "pandaNode.h"
 #include "nodePathCollection.h"
 #include "nodePathCollection.h"
+#include "ordered_vector.h"
 
 
 class JointVertexTransform;
 class JointVertexTransform;
 class Character;
 class Character;
@@ -41,6 +42,7 @@ PUBLISHED:
   virtual ~CharacterJoint();
   virtual ~CharacterJoint();
 
 
 public:
 public:
+  virtual bool is_character_joint() const;
   virtual PartGroup *make_copy() const;
   virtual PartGroup *make_copy() const;
 
 
   virtual bool update_internals(PartBundle *root, PartGroup *parent, 
   virtual bool update_internals(PartBundle *root, PartGroup *parent, 
@@ -73,11 +75,11 @@ private:
   // Not a reference-counted pointer.
   // Not a reference-counted pointer.
   Character *_character;
   Character *_character;
 
 
-  typedef pset< PT(PandaNode) > NodeList;
+  typedef ov_set< PT(PandaNode) > NodeList;
   NodeList _net_transform_nodes;
   NodeList _net_transform_nodes;
   NodeList _local_transform_nodes;
   NodeList _local_transform_nodes;
 
 
-  typedef pset<JointVertexTransform *> VertexTransforms;
+  typedef ov_set<JointVertexTransform *> VertexTransforms;
   VertexTransforms _vertex_transforms;
   VertexTransforms _vertex_transforms;
 
 
 public:
 public:

+ 2 - 2
panda/src/gobj/vertexTransform.h

@@ -19,7 +19,7 @@
 #include "typedWritableReferenceCount.h"
 #include "typedWritableReferenceCount.h"
 #include "updateSeq.h"
 #include "updateSeq.h"
 #include "luse.h"
 #include "luse.h"
-#include "pset.h"
+#include "ordered_vector.h"
 #include "cycleData.h"
 #include "cycleData.h"
 #include "cycleDataReader.h"
 #include "cycleDataReader.h"
 #include "cycleDataWriter.h"
 #include "cycleDataWriter.h"
@@ -57,7 +57,7 @@ protected:
   void mark_modified(Thread *current_thread);
   void mark_modified(Thread *current_thread);
 
 
 private:
 private:
-  typedef pset<TransformTable *> Palettes;
+  typedef ov_set<TransformTable *> Palettes;
   Palettes _tables;
   Palettes _tables;
 
 
   // This is the data that must be cycled between pipeline stages.
   // This is the data that must be cycled between pipeline stages.