From a666ef78fe1449064a89e171d095be4e86563adc Mon Sep 17 00:00:00 2001 From: David Rose Date: Thu, 20 Nov 2008 18:44:30 +0000 Subject: [PATCH] shave a few more microseconds off animation time --- panda/src/chan/movingPartBase.I | 4 +- panda/src/chan/movingPartBase.cxx | 58 +++++++++++++++++++++++++++-- panda/src/chan/movingPartBase.h | 17 +++++++++ panda/src/chan/movingPartMatrix.cxx | 29 ++------------- panda/src/chan/movingPartScalar.cxx | 28 ++------------ panda/src/chan/partBundle.cxx | 5 +++ panda/src/chan/partGroup.cxx | 27 ++++++++++++++ panda/src/chan/partGroup.h | 2 + panda/src/char/characterJoint.cxx | 27 ++++++++++---- panda/src/char/characterJoint.h | 6 ++- panda/src/gobj/vertexTransform.h | 4 +- 11 files changed, 140 insertions(+), 67 deletions(-) diff --git a/panda/src/chan/movingPartBase.I b/panda/src/chan/movingPartBase.I index 7191828797..c90b1692be 100644 --- a/panda/src/chan/movingPartBase.I +++ b/panda/src/chan/movingPartBase.I @@ -22,7 +22,9 @@ INLINE MovingPartBase:: MovingPartBase(const MovingPartBase ©) : 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, // though this is just a pointerwise copy. diff --git a/panda/src/chan/movingPartBase.cxx b/panda/src/chan/movingPartBase.cxx index 978caf135a..1766d5b88c 100644 --- a/panda/src/chan/movingPartBase.cxx +++ b/panda/src/chan/movingPartBase.cxx @@ -29,8 +29,11 @@ TypeHandle MovingPartBase::_type_handle; // Description: //////////////////////////////////////////////////////////////////// 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: //////////////////////////////////////////////////////////////////// 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); } + } 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 { const PartBundle::CData *cdata = (const PartBundle::CData *)root_cdata; 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); } + +//////////////////////////////////////////////////////////////////// +// 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); +} diff --git a/panda/src/chan/movingPartBase.h b/panda/src/chan/movingPartBase.h index 12581a9c11..7de798bad1 100644 --- a/panda/src/chan/movingPartBase.h +++ b/panda/src/chan/movingPartBase.h @@ -75,9 +75,26 @@ protected: virtual void find_bound_joints(int &joint_index, bool is_included, BitArray &bound_joints, 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; 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; public: diff --git a/panda/src/chan/movingPartMatrix.cxx b/panda/src/chan/movingPartMatrix.cxx index b82c9dfcdd..74c0730811 100644 --- a/panda/src/chan/movingPartMatrix.cxx +++ b/panda/src/chan/movingPartMatrix.cxx @@ -77,39 +77,16 @@ get_blend_value(const PartBundle *root) { _value = _initial_value; } - } else if ((cdata->_blend.size() == 1 || !cdata->_anim_blend_flag) && + } else if (_effective_control != (AnimControl *)NULL && !cdata->_frame_blend_flag) { // 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 { // A blend of two or more values, either between multiple // different animations, or between consecutive frames of the same // animation (or both). - switch (cdata->_blend_type) { case PartBundle::BT_linear: { diff --git a/panda/src/chan/movingPartScalar.cxx b/panda/src/chan/movingPartScalar.cxx index c95bf0134c..65afd7e716 100644 --- a/panda/src/chan/movingPartScalar.cxx +++ b/panda/src/chan/movingPartScalar.cxx @@ -62,33 +62,11 @@ get_blend_value(const PartBundle *root) { _value = _initial_value; } - } else if ((cdata->_blend.size() == 1 || !cdata->_anim_blend_flag) && + } else if (_effective_control != (AnimControl *)NULL && !cdata->_frame_blend_flag) { // 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 { // A blend of two or more values. diff --git a/panda/src/chan/partBundle.cxx b/panda/src/chan/partBundle.cxx index 317b16b2f6..59a85c84c2 100644 --- a/panda/src/chan/partBundle.cxx +++ b/panda/src/chan/partBundle.cxx @@ -603,6 +603,10 @@ do_bind_anim(AnimControl *control, AnimBundle *anim, bind_hierarchy(ptanim, channel_index, joint_index, subset.is_include_empty(), bound_joints, subset); control->setup_anim(this, anim, channel_index, bound_joints); + + CDReader cdata(_cycler); + determine_effective_channels(cdata); + return true; } @@ -706,6 +710,7 @@ recompute_net_blend(CData *cdata) { for (bti = cdata->_blend.begin(); bti != cdata->_blend.end(); ++bti) { cdata->_net_blend += (*bti).second; } + determine_effective_channels(cdata); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/chan/partGroup.cxx b/panda/src/chan/partGroup.cxx index f04d026ab9..6b01d77bc3 100644 --- a/panda/src/chan/partGroup.cxx +++ b/panda/src/chan/partGroup.cxx @@ -53,6 +53,18 @@ 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 // 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 diff --git a/panda/src/chan/partGroup.h b/panda/src/chan/partGroup.h index 1f836010a9..9240c1ef07 100644 --- a/panda/src/chan/partGroup.h +++ b/panda/src/chan/partGroup.h @@ -66,6 +66,7 @@ PUBLISHED: // This is the normal PartGroup constructor. PartGroup(PartGroup *parent, const string &name); virtual ~PartGroup(); + virtual bool is_character_joint() const; virtual PartGroup *make_copy() const; PartGroup *copy_subgraph() const; @@ -96,6 +97,7 @@ public: PartGroup *parent, bool parent_changed, bool anim_changed, Thread *current_thread); virtual void do_xform(const LMatrix4f &mat, const LMatrix4f &inv_mat); + virtual void determine_effective_channels(const CycleData *root_cdata); protected: void write_descendants(ostream &out, int indent_level) const; diff --git a/panda/src/char/characterJoint.cxx b/panda/src/char/characterJoint.cxx index 491ee392e6..ef3f11508a 100644 --- a/panda/src/char/characterJoint.cxx +++ b/panda/src/char/characterJoint.cxx @@ -83,6 +83,18 @@ CharacterJoint:: 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 // Access: Public, Virtual @@ -112,11 +124,10 @@ make_copy() const { bool CharacterJoint:: update_internals(PartBundle *root, PartGroup *parent, bool self_changed, bool parent_changed, Thread *current_thread) { - nassertr(parent != (PartGroup *)NULL, 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 // its net transform. 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); 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; 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); 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; node->set_transform(t, current_thread); - ++ai; } } diff --git a/panda/src/char/characterJoint.h b/panda/src/char/characterJoint.h index cd241f876c..18c13ed5b2 100644 --- a/panda/src/char/characterJoint.h +++ b/panda/src/char/characterJoint.h @@ -20,6 +20,7 @@ #include "movingPartMatrix.h" #include "pandaNode.h" #include "nodePathCollection.h" +#include "ordered_vector.h" class JointVertexTransform; class Character; @@ -41,6 +42,7 @@ PUBLISHED: virtual ~CharacterJoint(); public: + virtual bool is_character_joint() const; virtual PartGroup *make_copy() const; virtual bool update_internals(PartBundle *root, PartGroup *parent, @@ -73,11 +75,11 @@ private: // Not a reference-counted pointer. Character *_character; - typedef pset< PT(PandaNode) > NodeList; + typedef ov_set< PT(PandaNode) > NodeList; NodeList _net_transform_nodes; NodeList _local_transform_nodes; - typedef pset VertexTransforms; + typedef ov_set VertexTransforms; VertexTransforms _vertex_transforms; public: diff --git a/panda/src/gobj/vertexTransform.h b/panda/src/gobj/vertexTransform.h index 2bb11df991..551a91c1db 100644 --- a/panda/src/gobj/vertexTransform.h +++ b/panda/src/gobj/vertexTransform.h @@ -19,7 +19,7 @@ #include "typedWritableReferenceCount.h" #include "updateSeq.h" #include "luse.h" -#include "pset.h" +#include "ordered_vector.h" #include "cycleData.h" #include "cycleDataReader.h" #include "cycleDataWriter.h" @@ -57,7 +57,7 @@ protected: void mark_modified(Thread *current_thread); private: - typedef pset Palettes; + typedef ov_set Palettes; Palettes _tables; // This is the data that must be cycled between pipeline stages.