diff --git a/panda/src/chan/animControl.I b/panda/src/chan/animControl.I index 4974c05910..ba264a3605 100644 --- a/panda/src/chan/animControl.I +++ b/panda/src/chan/animControl.I @@ -44,3 +44,19 @@ INLINE int AnimControl:: get_channel_index() const { return _channel_index; } + +//////////////////////////////////////////////////////////////////// +// Function: AnimControl::get_bound_joints +// Access: Published +// Description: Returns the subset of joints controlled by this +// AnimControl. Most of the time, this will be +// BitArray::all_on(), for a normal full-body animation. +// For a subset animation, however, this will be just a +// subset of those bits, corresponding to the set of +// joints and sliders actually bound (as enumerated by +// bind_hierarchy() in depth-first LIFO order). +//////////////////////////////////////////////////////////////////// +INLINE const BitArray &AnimControl:: +get_bound_joints() const { + return _bound_joints; +} diff --git a/panda/src/chan/animControl.cxx b/panda/src/chan/animControl.cxx index 312b3dd952..fc2e36e490 100644 --- a/panda/src/chan/animControl.cxx +++ b/panda/src/chan/animControl.cxx @@ -29,7 +29,8 @@ TypeHandle AnimControl::_type_handle; // Description: //////////////////////////////////////////////////////////////////// AnimControl:: -AnimControl(PartBundle *part, AnimBundle *anim, int channel_index) { +AnimControl(PartBundle *part, AnimBundle *anim, int channel_index, + const BitArray &bound_joints) { #ifdef DO_MEMORY_USAGE MemoryUsage::update_type(this, get_class_type()); #endif @@ -37,6 +38,7 @@ AnimControl(PartBundle *part, AnimBundle *anim, int channel_index) { _part = part; _anim = anim; _channel_index = channel_index; + _bound_joints = bound_joints; set_frame_rate(_anim->get_base_frame_rate()); set_num_frames(_anim->get_num_frames()); diff --git a/panda/src/chan/animControl.h b/panda/src/chan/animControl.h index 4a0947c4d4..ef745eb92d 100644 --- a/panda/src/chan/animControl.h +++ b/panda/src/chan/animControl.h @@ -24,6 +24,7 @@ #include "animInterface.h" #include "animBundle.h" #include "partGroup.h" +#include "bitArray.h" #include "referenceCount.h" @@ -40,7 +41,8 @@ class AnimChannelBase; //////////////////////////////////////////////////////////////////// class EXPCL_PANDA AnimControl : public ReferenceCount, public AnimInterface { public: - AnimControl(PartBundle *part, AnimBundle *anim, int channel_index); + AnimControl(PartBundle *part, AnimBundle *anim, int channel_index, + const BitArray &bound_joints); PUBLISHED: virtual ~AnimControl(); @@ -48,6 +50,7 @@ PUBLISHED: PartBundle *get_part() const; INLINE AnimBundle *get_anim() const; INLINE int get_channel_index() const; + INLINE const BitArray &get_bound_joints() const; virtual void output(ostream &out) const; @@ -73,6 +76,11 @@ private: // This is the frame number as of the last call to mark_channels(). int _marked_frame; + // This is the bitmask of joints and/or sliders from the animation + // that we have actually bound into this AnimControl. See + // get_bound_joints(). + BitArray _bound_joints; + public: static TypeHandle get_class_type() { return _type_handle; diff --git a/panda/src/chan/movingPartBase.cxx b/panda/src/chan/movingPartBase.cxx index f171b571aa..6900c9f7b6 100644 --- a/panda/src/chan/movingPartBase.cxx +++ b/panda/src/chan/movingPartBase.cxx @@ -16,10 +16,10 @@ // //////////////////////////////////////////////////////////////////// - #include "movingPartBase.h" #include "animControl.h" #include "animChannelBase.h" +#include "bitArray.h" #include "indent.h" @@ -207,7 +207,8 @@ pick_channel_index(plist &holes, int &next) const { // hierarchy, at the given channel index number. //////////////////////////////////////////////////////////////////// void MovingPartBase:: -bind_hierarchy(AnimGroup *anim, int channel_index, bool is_included, +bind_hierarchy(AnimGroup *anim, int channel_index, int &joint_index, + bool is_included, BitArray &bound_joints, const PartSubset &subset) { if (chan_cat.is_debug()) { chan_cat.debug() @@ -229,7 +230,16 @@ bind_hierarchy(AnimGroup *anim, int channel_index, bool is_included, } else { _channels[channel_index] = DCAST(AnimChannelBase, anim); } - } - PartGroup::bind_hierarchy(anim, channel_index, is_included, subset); + // Record that we have bound this joint in the bound_joints + // BitArray. + bound_joints.set_bit(joint_index); + } else { + // Record that we have *not* bound this particular joint. + bound_joints.clear_bit(joint_index); + } + ++joint_index; + + PartGroup::bind_hierarchy(anim, channel_index, joint_index, + is_included, bound_joints, subset); } diff --git a/panda/src/chan/movingPartBase.h b/panda/src/chan/movingPartBase.h index c8c76a5880..9fac7c82c2 100644 --- a/panda/src/chan/movingPartBase.h +++ b/panda/src/chan/movingPartBase.h @@ -68,7 +68,9 @@ protected: virtual void pick_channel_index(plist &holes, int &next) const; virtual void bind_hierarchy(AnimGroup *anim, int channel_index, - bool is_included, const PartSubset &subset); + int &joint_index, bool is_included, + BitArray &bound_joints, + const PartSubset &subset); typedef pvector< PT(AnimChannelBase) > Channels; Channels _channels; diff --git a/panda/src/chan/movingPartMatrix.cxx b/panda/src/chan/movingPartMatrix.cxx index bf6bfc161e..08db8eeb5d 100644 --- a/panda/src/chan/movingPartMatrix.cxx +++ b/panda/src/chan/movingPartMatrix.cxx @@ -89,9 +89,6 @@ get_blend_value(const PartBundle *root) { switch (root->get_blend_type()) { case PartBundle::BT_single: - // This one shouldn't be possible. - nassertv(false); - case PartBundle::BT_linear: { // An ordinary, linear blend. diff --git a/panda/src/chan/partBundle.cxx b/panda/src/chan/partBundle.cxx index bce962adf4..4be166dc66 100644 --- a/panda/src/chan/partBundle.cxx +++ b/panda/src/chan/partBundle.cxx @@ -21,6 +21,7 @@ #include "animBundle.h" #include "animControl.h" #include "config_chan.h" +#include "bitArray.h" #include "indent.h" #include "datagram.h" @@ -107,7 +108,7 @@ set_blend_type(BlendType bt) { // most-recently-added one. nassertv(_last_control_set != NULL); - clear_and_stop_except(_last_control_set); + clear_and_stop_intersecting(_last_control_set); } _anim_changed = true; @@ -173,7 +174,7 @@ set_control_effect(AnimControl *control, float effect) { // If we currently have BT_single, we only allow one AnimControl // at a time. Stop all of the other AnimControls. if (get_blend_type() == BT_single) { - clear_and_stop_except(control); + clear_and_stop_intersecting(control); } if (get_control_effect(control) != effect) { @@ -285,8 +286,14 @@ bind_anim(AnimBundle *anim, int hierarchy_match_flags, channel_index = holes.front(); } - bind_hierarchy(anim, channel_index, subset.is_empty(), subset); - return new AnimControl(this, anim, channel_index); + int joint_index = 0; + BitArray bound_joints; + if (subset.is_include_empty()) { + bound_joints = BitArray::all_on(); + } + bind_hierarchy(anim, channel_index, joint_index, subset.is_include_empty(), + bound_joints, subset); + return new AnimControl(this, anim, channel_index, bound_joints); } //////////////////////////////////////////////////////////////////// @@ -416,16 +423,17 @@ register_with_read_factory() } //////////////////////////////////////////////////////////////////// -// Function: PartBundle::clear_and_stop_except +// Function: PartBundle::clear_and_stop_intersecting // Access: Protected // Description: Removes and stops all the currently activated -// AnimControls, except for the indicated one. This is -// a special internal function that's only called when -// _blend_type is BT_single, to automatically stop all -// the other currently-executing animations. +// AnimControls that animate some joints also animated +// by the indicated AnimControl. This is a special +// internal function that's only called when _blend_type +// is BT_single, to automatically stop all the other +// currently-executing animations. //////////////////////////////////////////////////////////////////// void PartBundle:: -clear_and_stop_except(AnimControl *control) { +clear_and_stop_intersecting(AnimControl *control) { double new_net_blend = 0.0f; ChannelBlend new_blend; bool any_changed = false; @@ -433,8 +441,10 @@ clear_and_stop_except(AnimControl *control) { ChannelBlend::iterator cbi; for (cbi = _blend.begin(); cbi != _blend.end(); ++cbi) { AnimControl *ac = (*cbi).first; - if (ac == control) { - // Save this control, but only this one. + if (ac == control || + !ac->get_bound_joints().has_bits_in_common(control->get_bound_joints())) { + // Save this control--it's either the target control, or it has + // no joints in common with the target control. new_blend.insert(new_blend.end(), (*cbi)); new_net_blend += (*cbi).second; } else { diff --git a/panda/src/chan/partBundle.h b/panda/src/chan/partBundle.h index 1ef67878fc..f20761537c 100644 --- a/panda/src/chan/partBundle.h +++ b/panda/src/chan/partBundle.h @@ -135,7 +135,7 @@ public: protected: void recompute_net_blend(); - void clear_and_stop_except(AnimControl *control); + void clear_and_stop_intersecting(AnimControl *control); BlendType _blend_type; PartBundleNode *_node; diff --git a/panda/src/chan/partGroup.cxx b/panda/src/chan/partGroup.cxx index eb5e75933f..35d6556a4b 100644 --- a/panda/src/chan/partGroup.cxx +++ b/panda/src/chan/partGroup.cxx @@ -432,7 +432,8 @@ pick_channel_index(plist &holes, int &next) const { // hierarchy, at the given channel index number. //////////////////////////////////////////////////////////////////// void PartGroup:: -bind_hierarchy(AnimGroup *anim, int channel_index, bool is_included, +bind_hierarchy(AnimGroup *anim, int channel_index, int &joint_index, + bool is_included, BitArray &bound_joints, const PartSubset &subset) { if (subset.matches_include(get_name())) { is_included = true; @@ -451,12 +452,18 @@ bind_hierarchy(AnimGroup *anim, int channel_index, bool is_included, if (pc->get_name() < ac->get_name()) { // Here's a part, not in the anim. Bind it to the special NULL // anim. - pc->bind_hierarchy(NULL, channel_index, is_included, subset); + pc->bind_hierarchy(NULL, channel_index, joint_index, is_included, + bound_joints, subset); i++; + } else if (ac->get_name() < pc->get_name()) { + // Here's an anim, not in the part. Ignore it. j++; + } else { - pc->bind_hierarchy(ac, channel_index, is_included, subset); + // Here's a matched part and anim pair. + pc->bind_hierarchy(ac, channel_index, joint_index, is_included, + bound_joints, subset); i++; j++; } @@ -465,7 +472,8 @@ bind_hierarchy(AnimGroup *anim, int channel_index, bool is_included, // Now pick up any more parts, not in the anim. while (i < part_num_children) { PartGroup *pc = get_child(i); - pc->bind_hierarchy(NULL, channel_index, is_included, subset); + pc->bind_hierarchy(NULL, channel_index, joint_index, is_included, + bound_joints, subset); i++; } } diff --git a/panda/src/chan/partGroup.h b/panda/src/chan/partGroup.h index 3ed0fd3c76..b2e55b9a71 100644 --- a/panda/src/chan/partGroup.h +++ b/panda/src/chan/partGroup.h @@ -34,6 +34,7 @@ class PartBundle; class PartSubset; class BamReader; class FactoryParams; +class BitArray; //////////////////////////////////////////////////////////////////// // Class : PartGroup @@ -93,7 +94,9 @@ protected: virtual void pick_channel_index(plist &holes, int &next) const; virtual void bind_hierarchy(AnimGroup *anim, int channel_index, - bool is_included, const PartSubset &subset); + int &joint_index, bool is_included, + BitArray &bound_joints, + const PartSubset &subset); typedef pvector< PT(PartGroup) > Children; Children _children; diff --git a/panda/src/chan/partSubset.cxx b/panda/src/chan/partSubset.cxx index e020e1973b..59a1e1d734 100644 --- a/panda/src/chan/partSubset.cxx +++ b/panda/src/chan/partSubset.cxx @@ -129,15 +129,15 @@ output(ostream &out) const { } //////////////////////////////////////////////////////////////////// -// Function: PartSubset::is_empty +// Function: PartSubset::is_include_empty // Access: Published -// Description: Returns true if the PartSubset is completely empty, +// Description: Returns true if the include list is completely empty, // false otherwise. If it is empty, it is the same // thing as including all joints. //////////////////////////////////////////////////////////////////// bool PartSubset:: -is_empty() const { - return _include_joints.empty() && _exclude_joints.empty(); +is_include_empty() const { + return _include_joints.empty(); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/chan/partSubset.h b/panda/src/chan/partSubset.h index 3bf9767fc3..14b4d9c7fe 100644 --- a/panda/src/chan/partSubset.h +++ b/panda/src/chan/partSubset.h @@ -42,7 +42,7 @@ PUBLISHED: void output(ostream &out) const; - bool is_empty() const; + bool is_include_empty() const; bool matches_include(const string &joint_name) const; bool matches_exclude(const string &joint_name) const;