From 2fc11e2a9f551ad521b3654f66335e59613f7ace Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 19 Feb 2002 18:50:32 +0000 Subject: [PATCH] don't recompute character vertices if animation is unchanged --- panda/src/chan/movingPartBase.cxx | 32 +++++++++++++++++------ panda/src/chan/movingPartBase.h | 4 +-- panda/src/chan/partBundle.cxx | 13 +++++++--- panda/src/chan/partBundle.h | 2 +- panda/src/chan/partGroup.cxx | 19 +++++++++++--- panda/src/chan/partGroup.h | 2 +- panda/src/char/character.cxx | 33 +++++++++++++----------- panda/src/char/character.h | 14 +++++------ panda/src/char/characterJoint.cxx | 42 +++++++++++++++++++++++-------- panda/src/char/characterJoint.h | 2 +- panda/src/char/config_char.cxx | 35 ++++++++++++++++++++++++++ panda/src/char/config_char.h | 5 ++++ 12 files changed, 151 insertions(+), 52 deletions(-) diff --git a/panda/src/chan/movingPartBase.cxx b/panda/src/chan/movingPartBase.cxx index 1ed2cc5b69..8cc7781320 100644 --- a/panda/src/chan/movingPartBase.cxx +++ b/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; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/chan/movingPartBase.h b/panda/src/chan/movingPartBase.h index 6dd04dbca3..a0a1ac6f66 100644 --- a/panda/src/chan/movingPartBase.h +++ b/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: diff --git a/panda/src/chan/partBundle.cxx b/panda/src/chan/partBundle.cxx index d35e72e838..6390db7e55 100644 --- a/panda/src/chan/partBundle.cxx +++ b/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; } diff --git a/panda/src/chan/partBundle.h b/panda/src/chan/partBundle.h index 0c1ddd3291..5aa7e16f64 100644 --- a/panda/src/chan/partBundle.h +++ b/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: diff --git a/panda/src/chan/partGroup.cxx b/panda/src/chan/partGroup.cxx index 36c91ba76f..dde6f335a4 100644 --- a/panda/src/chan/partGroup.cxx +++ b/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; } diff --git a/panda/src/chan/partGroup.h b/panda/src/chan/partGroup.h index 0f11acfdee..0dd40b49dc 100644 --- a/panda/src/chan/partGroup.h +++ b/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: diff --git a/panda/src/char/character.cxx b/panda/src/char/character.cxx index 167e77f4ed..387436ac61 100644 --- a/panda/src/char/character.cxx +++ b/panda/src/char/character.cxx @@ -21,16 +21,16 @@ #include "computedVertices.h" #include "config_char.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include +#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(); } diff --git a/panda/src/char/character.h b/panda/src/char/character.h index f929338ac5..373e470096 100644 --- a/panda/src/char/character.h +++ b/panda/src/char/character.h @@ -19,16 +19,16 @@ #ifndef CHARACTER_H #define CHARACTER_H -#include +#include "pandabase.h" #include "computedVertices.h" -#include -#include -#include -#include -#include -#include +#include "partBundleNode.h" +#include "namedNode.h" +#include "vector_PartGroupStar.h" +#include "pointerTo.h" +#include "geom.h" +#include "pStatCollector.h" class CharacterJointBundle; class ComputedVertices; diff --git a/panda/src/char/characterJoint.cxx b/panda/src/char/characterJoint.cxx index ac0f12b637..fbe246c003 100644 --- a/panda/src/char/characterJoint.cxx +++ b/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); + // 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; + } - _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; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/char/characterJoint.h b/panda/src/char/characterJoint.h index 4e4e46f24b..c4d9cf3e9d 100644 --- a/panda/src/char/characterJoint.h +++ b/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: diff --git a/panda/src/char/config_char.cxx b/panda/src/char/config_char.cxx index ff21ef0495..6d6af7d0f9 100644 --- a/panda/src/char/config_char.cxx +++ b/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(); diff --git a/panda/src/char/config_char.h b/panda/src/char/config_char.h index 4a5cd355a6..37b297afc5 100644 --- a/panda/src/char/config_char.h +++ b/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