shave a few more microseconds off animation time

This commit is contained in:
David Rose 2008-11-20 18:44:30 +00:00
parent 2a5851d614
commit a666ef78fe
11 changed files with 140 additions and 67 deletions

View File

@ -22,7 +22,9 @@
INLINE MovingPartBase::
MovingPartBase(const MovingPartBase &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,
// though this is just a pointerwise copy.

View File

@ -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);
}

View File

@ -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:

View File

@ -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:
{

View File

@ -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.

View File

@ -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);
}
////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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;

View File

@ -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;
}
}

View File

@ -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<JointVertexTransform *> VertexTransforms;
typedef ov_set<JointVertexTransform *> VertexTransforms;
VertexTransforms _vertex_transforms;
public:

View File

@ -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<TransformTable *> Palettes;
typedef ov_set<TransformTable *> Palettes;
Palettes _tables;
// This is the data that must be cycled between pipeline stages.