Browse Source

don't recompute character vertices if animation is unchanged

David Rose 24 years ago
parent
commit
2fc11e2a9f

+ 24 - 8
panda/src/chan/movingPartBase.cxx

@@ -87,11 +87,19 @@ write_with_value(ostream &out, int indent_level) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: MovingPartBase::do_update
 //       Access: Public, Virtual
-//  Description:
+//  Description: Recursively update this particular part and all of
+//               its descendents for the current frame.  This is not
+//               really public and is not intended to be called
+//               directly; it is called from the top of the tree by
+//               PartBundle::update().
+//
+//               The return value is true if any part has changed,
+//               false otherwise.
 ////////////////////////////////////////////////////////////////////
-void MovingPartBase::
+bool MovingPartBase::
 do_update(PartBundle *root, PartGroup *parent,
           bool parent_changed, bool anim_changed) {
+  bool any_changed = false;
   bool needs_update = anim_changed;
 
   // See if any of the channel values have changed since last time.
@@ -102,9 +110,9 @@ do_update(PartBundle *root, PartGroup *parent,
        ++bci) {
     AnimControl *control = (*bci);
     int channel_index = control->get_channel_index();
-    nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
+    nassertr(channel_index >= 0 && channel_index < (int)_channels.size(), false);
     AnimChannelBase *channel = _channels[channel_index];
-    nassertv(channel != (AnimChannelBase*)0L);
+    nassertr(channel != (AnimChannelBase*)0L, false);
 
     needs_update = control->channel_has_changed(channel);
   }
@@ -115,15 +123,19 @@ do_update(PartBundle *root, PartGroup *parent,
   }
 
   if (parent_changed || needs_update) {
-    update_internals(parent, needs_update, parent_changed);
+    any_changed = update_internals(parent, needs_update, parent_changed);
   }
 
   // Now recurse.
   Children::iterator ci;
   for (ci = _children.begin(); ci != _children.end(); ++ci) {
-    (*ci)->do_update(root, this, parent_changed || needs_update,
-                     anim_changed);
+    if ((*ci)->do_update(root, this, parent_changed || needs_update,
+                         anim_changed)) {
+      any_changed = true;
+    }
   }
+
+  return any_changed;
 }
 
 
@@ -134,9 +146,13 @@ do_update(PartBundle *root, PartGroup *parent,
 //               some ancestor has changed values.  It is a hook for
 //               derived classes to update whatever cache they may
 //               have that depends on these.
+//
+//               The return value is true if the part has changed as a
+//               result of the update, or false otherwise.
 ////////////////////////////////////////////////////////////////////
-void MovingPartBase::
+bool MovingPartBase::
 update_internals(PartGroup *, bool, bool) {
+  return false;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 2 - 2
panda/src/chan/movingPartBase.h

@@ -48,11 +48,11 @@ public:
   virtual void write_with_value(ostream &out, int indent_level) const;
   virtual void output_value(ostream &out) const=0;
 
-  virtual void do_update(PartBundle *root, PartGroup *parent,
+  virtual bool do_update(PartBundle *root, PartGroup *parent,
                          bool parent_changed, bool anim_changed);
 
   virtual void get_blend_value(const PartBundle *root)=0;
-  virtual void update_internals(PartGroup *parent, bool self_changed,
+  virtual bool update_internals(PartGroup *parent, bool self_changed,
                                 bool parent_changed);
 
 protected:

+ 10 - 3
panda/src/chan/partBundle.cxx

@@ -344,11 +344,16 @@ advance_time(double time) {
 ////////////////////////////////////////////////////////////////////
 //     Function: PartBundle::update
 //       Access: Public
-//  Description:
+//  Description: Updates all the parts in the bundle to reflect the
+//               data for the current frame (as set in each of the
+//               AnimControls).
+//
+//               Returns true if any part has changed as a result of
+//               this, or false otherwise.
 ////////////////////////////////////////////////////////////////////
-void PartBundle::
+bool PartBundle::
 update() {
-  do_update(this, NULL, false, _anim_changed);
+  bool any_changed = do_update(this, NULL, false, _anim_changed);
 
   // Now update all the controls for next time.
   ChannelBlend::const_iterator cbi;
@@ -357,6 +362,8 @@ update() {
     control->mark_channels();
   }
   _anim_changed = false;
+
+  return any_changed;
 }
 
 

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

@@ -122,7 +122,7 @@ public:
   // bunch of friends.
 
   void advance_time(double time);
-  void update();
+  bool update();
   virtual void control_activated(AnimControl *control);
 
 protected:

+ 16 - 3
panda/src/chan/partGroup.cxx

@@ -350,15 +350,28 @@ write_with_value(ostream &out, int indent_level) const {
 ////////////////////////////////////////////////////////////////////
 //     Function: PartGroup::do_update
 //       Access: Public, Virtual
-//  Description:
+//  Description: Recursively update this particular part and all of
+//               its descendents for the current frame.  This is not
+//               really public and is not intended to be called
+//               directly; it is called from the top of the tree by
+//               PartBundle::update().
+//
+//               The return value is true if any part has changed,
+//               false otherwise.
 ////////////////////////////////////////////////////////////////////
-void PartGroup::
+bool PartGroup::
 do_update(PartBundle *root, PartGroup *,
           bool parent_changed, bool anim_changed) {
+  bool any_changed = false;
+
   Children::iterator ci;
   for (ci = _children.begin(); ci != _children.end(); ++ci) {
-    (*ci)->do_update(root, this, parent_changed, anim_changed);
+    if ((*ci)->do_update(root, this, parent_changed, anim_changed)) {
+      any_changed = true;
+    }
   }
+
+  return any_changed;
 }
 
 

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

@@ -82,7 +82,7 @@ public:
                        const PartGroup *parent,
                        int hierarchy_match_flags = 0) const;
 
-  virtual void do_update(PartBundle *root, PartGroup *parent,
+  virtual bool do_update(PartBundle *root, PartGroup *parent,
                          bool parent_changed, bool anim_changed);
 
 protected:

+ 18 - 15
panda/src/char/character.cxx

@@ -21,16 +21,16 @@
 #include "computedVertices.h"
 #include "config_char.h"
 
-#include <geomNode.h>
-#include <datagram.h>
-#include <datagramIterator.h>
-#include <bamReader.h>
-#include <bamWriter.h>
-#include <pStatTimer.h>
-#include <geomNode.h>
-#include <animControl.h>
-#include <clockObject.h>
-#include <pStatTimer.h>
+#include "geomNode.h"
+#include "datagram.h"
+#include "datagramIterator.h"
+#include "bamReader.h"
+#include "bamWriter.h"
+#include "pStatTimer.h"
+#include "geomNode.h"
+#include "animControl.h"
+#include "clockObject.h"
+#include "pStatTimer.h"
 
 TypeHandle Character::_type_handle;
 
@@ -140,11 +140,14 @@ update() {
   PStatTimer timer(_char_pcollector);
 
   // First, update all the joints and sliders.
-  get_bundle()->update();
+  bool any_changed = get_bundle()->update();
 
-  // Now update the vertices.
-  if (_computed_vertices != (ComputedVertices *)NULL) {
-    _computed_vertices->update(this);
+  // Now update the vertices, if we need to.  This is likely to be a
+  // slow operation.
+  if (any_changed || even_animation) {
+    if (_computed_vertices != (ComputedVertices *)NULL) {
+      _computed_vertices->update(this);
+    }
   }
 }
 
@@ -299,7 +302,7 @@ copy_geom(Geom *source, const Character *from) {
   PT(Geom) dest = source;
 
   source->get_coords(coords, index);
-  if ((coords != NULL) && (coords == (from->_cv._coords))) {
+  if ((coords != (void *)NULL) && (coords == (from->_cv._coords))) {
     if (dest == source) {
       dest = source->make_copy();
     }

+ 7 - 7
panda/src/char/character.h

@@ -19,16 +19,16 @@
 #ifndef CHARACTER_H
 #define CHARACTER_H
 
-#include <pandabase.h>
+#include "pandabase.h"
 
 #include "computedVertices.h"
 
-#include <partBundleNode.h>
-#include <namedNode.h>
-#include <vector_PartGroupStar.h>
-#include <pointerTo.h>
-#include <geom.h>
-#include <pStatCollector.h>
+#include "partBundleNode.h"
+#include "namedNode.h"
+#include "vector_PartGroupStar.h"
+#include "pointerTo.h"
+#include "geom.h"
+#include "pStatCollector.h"
 
 class CharacterJointBundle;
 class ComputedVertices;

+ 31 - 11
panda/src/char/characterJoint.cxx

@@ -84,22 +84,40 @@ make_copy() const {
 ////////////////////////////////////////////////////////////////////
 //     Function: CharacterJoint::update_internals
 //       Access: Public, Virtual
-//  Description:
+//  Description: This is called by do_update() whenever the part or
+//               some ancestor has changed values.  It is a hook for
+//               derived classes to update whatever cache they may
+//               have that depends on these.
+//
+//               The return value is true if the part has changed as a
+//               result of the update, or false otherwise.
+//
+//               In the case of a CharacterJoint, of course, it means
+//               to recompute the joint angles and associated
+//               transforms for this particular joint.
 ////////////////////////////////////////////////////////////////////
-void CharacterJoint::
-update_internals(PartGroup *parent, bool self_changed, bool) {
-  nassertv(parent != NULL);
+bool CharacterJoint::
+update_internals(PartGroup *parent, bool self_changed, bool parent_changed) {
+  nassertr(parent != (PartGroup *)NULL, false);
 
   bool net_changed = false;
   if (parent->is_of_type(CharacterJoint::get_class_type())) {
-    CharacterJoint *parent_joint = DCAST(CharacterJoint, parent);
-
-    _net_transform = _value * parent_joint->_net_transform;
-    net_changed = true;
+    // The joint is not a toplevel joint; its parent therefore affects
+    // its net transform.
+    if (parent_changed || self_changed) {
+      CharacterJoint *parent_joint = DCAST(CharacterJoint, parent);
+      
+      _net_transform = _value * parent_joint->_net_transform;
+      net_changed = true;
+    }
 
-  } else if (self_changed) {
-    _net_transform = _value;
-    net_changed = true;
+  } else {
+    // The joint *is* a toplevel joint, and the only thing that
+    // affects its net transform is the joint itself.
+    if (self_changed) {
+      _net_transform = _value;
+      net_changed = true;
+    }
   }
 
   if (net_changed && !_net_transform_arcs.empty()) {
@@ -141,6 +159,8 @@ update_internals(PartGroup *parent, bool self_changed, bool) {
       }
     }
   }
+
+  return self_changed || net_changed;
 }
 
 ////////////////////////////////////////////////////////////////////

+ 1 - 1
panda/src/char/characterJoint.h

@@ -43,7 +43,7 @@ public:
 
   virtual PartGroup *make_copy() const;
 
-  virtual void update_internals(PartGroup *parent, bool self_changed,
+  virtual bool update_internals(PartGroup *parent, bool self_changed,
                                 bool parent_changed);
 
 PUBLISHED:

+ 35 - 0
panda/src/char/config_char.cxx

@@ -31,6 +31,41 @@ Configure(config_char);
 NotifyCategoryDef(char, "");
 
 ConfigureFn(config_char) {
+  init_libchar();
+}
+
+// The animation system, by default, only recomputes the characters'
+// vertices on frames for which there is some change in the animation
+// cycle.  Since this doesn't happen every frame, and since the
+// recomputing of vertices can take significant time, this might
+// result in irregular patterns of slow frames and fast frames,
+// resulting in an unsteady frame rate.  Sometimes it is preferable to
+// achieve a more even frame rate, even if the average frame rate is
+// slower overall.
+
+// Set even-animation to true to achieve this.  When this is true,
+// characters' vertices will be recomputed every frame, whether they
+// need it or not.  This will tend to balance out the frame rate so
+// that it is more uniformly slow.
+const bool even_animation = config_char.GetBool("even-animation", false);
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: init_libchar
+//  Description: Initializes the library.  This must be called at
+//               least once before any of the functions or classes in
+//               this library can be used.  Normally it will be
+//               called by the static initializers and need not be
+//               called explicitly, but special cases exist.
+////////////////////////////////////////////////////////////////////
+void
+init_libchar() {
+  static bool initialized = false;
+  if (initialized) {
+    return;
+  }
+  initialized = true;
+
   Character::init_type();
   CharacterJoint::init_type();
   CharacterJointBundle::init_type();

+ 5 - 0
panda/src/char/config_char.h

@@ -27,4 +27,9 @@
 NotifyCategoryDecl(char, EXPCL_PANDA, EXPTP_PANDA);
 #endif
 
+// Configure variables for char package.
+extern const bool EXPCL_PANDA even_animation;
+
+extern EXPCL_PANDA void init_libchar();
+
 #endif