enable intra-frame animation interpolation

This commit is contained in:
David Rose 2006-10-14 23:58:48 +00:00
parent a7afebd785
commit 731ab7b576
13 changed files with 454 additions and 121 deletions

View File

@ -1149,6 +1149,67 @@ class Actor(DirectObject, NodePath):
for control in self.getAnimControls(animName, partName, lodName):
control.pose(frame)
def setBlend(self, animBlend = None, frameBlend = None,
blendType = None, partName = None):
"""
Changes the way the Actor handles blending of multiple
different animations, and/or interpolation between consecutive
frames.
The animBlend and frameBlend parameters are boolean flags.
You may set either or both to True or False. If you do not
specify them, they do not change from the previous value.
When animBlend is True, multiple different animations may
simultaneously be playing on the Actor. This means you may
call play(), loop(), or pose() on multiple animations and have
all of them contribute to the final pose each frame.
In this mode (that is, when animBlend is True), starting a
particular animation with play(), loop(), or pose() does not
implicitly make the animation visible; you must also call
setControlEffect() for each animation you wish to use to
indicate how much each animation contributes to the final
pose.
The frameBlend flag is unrelated to playing multiple
animations. It controls whether the Actor smoothly
interpolates between consecutive frames of its animation (when
the flag is True) or holds each frame until the next one is
ready (when the flag is False). The default value of
frameBlend is controlled by the interpolate-frames Config.prc
variable.
In either case, you may also specify blendType, which controls
the precise algorithm used to blend two or more different
matrix values into a final result. Different skeleton
hierarchies may benefit from different algorithms. The
default blendType is controlled by the anim-blend-type
Config.prc variable.
"""
bundles = []
for lodName, bundleDict in self.__partBundleDict.items():
if partName == None:
for partBundle in bundleDict.values():
bundles.append(partBundle.node().getBundle())
else:
truePartName = self.__subpartDict.get(partName, [partName])[0]
partBundle = bundleDict.get(truePartName)
if partBundle != None:
bundles.append(partBundle.node().getBundle())
else:
Actor.notify.warning("Couldn't find part: %s" % (partName))
for bundle in bundles:
if blendType != None:
bundle.setBlendType(blendType)
if animBlend != None:
bundle.setAnimBlendFlag(animBlend)
if frameBlend != None:
bundle.setFrameBlendFlag(frameBlend)
def enableBlend(self, blendType = PartBundle.BTNormalizedLinear, partName = None):
"""
Enables blending of multiple animations simultaneously.
@ -1161,25 +1222,19 @@ class Actor(DirectObject, NodePath):
animation visible; you must also call setControlEffect() for
each animation you wish to use to indicate how much each
animation contributes to the final pose.
This method is deprecated. You should use setBlend() instead.
"""
for lodName, bundleDict in self.__partBundleDict.items():
if partName == None:
for partBundle in bundleDict.values():
partBundle.node().getBundle().setBlendType(blendType)
else:
truePartName = self.__subpartDict.get(partName, [partName])[0]
partBundle = bundleDict.get(truePartName)
if partBundle != None:
partBundle.node().getBundle().setBlendType(blendType)
else:
Actor.notify.warning("Couldn't find part: %s" % (partName))
self.setBlend(animBlend = True, blendType = blendType, partName = partName)
def disableBlend(self, partName = None):
"""
Restores normal one-animation-at-a-time operation after a
previous call to enableBlend().
This method is deprecated. You should use setBlend() instead.
"""
self.enableBlend(PartBundle.BTSingle, partName)
self.setBlend(animBlend = False, partName = partName)
def setControlEffect(self, animName, effect,
partName = None, lodName = None):
@ -1187,7 +1242,7 @@ class Actor(DirectObject, NodePath):
Sets the amount by which the named animation contributes to
the overall pose. This controls blending of multiple
animations; it only makes sense to call this after a previous
call to enableBlend().
call to setBlend(animBlend = True).
"""
for control in self.getAnimControls(animName, partName, lodName):
control.getPart().setControlEffect(control, effect)

View File

@ -83,6 +83,13 @@ PRC_DESC("Set this false to disable reading of compressed animation channels, "
"might want to do this would be to speed load time when you don't "
"care about what the animation looks like."));
ConfigVariableBool interpolate_frames
("interpolate-frames", false,
PRC_DESC("Set this true to interpolate character animations between frames, "
"or false to hold each frame until the next one is ready. This can "
"also be changed on a per-character basis with "
"PartBundle::set_frame_blend_flag()."));
ConfigureFn(config_chan) {
AnimBundle::init_type();

View File

@ -30,5 +30,6 @@ NotifyCategoryDecl(chan, EXPCL_PANDA, EXPTP_PANDA);
EXPCL_PANDA extern ConfigVariableBool compress_channels;
EXPCL_PANDA extern ConfigVariableInt compress_chan_quality;
EXPCL_PANDA extern ConfigVariableBool read_compressed_channels;
EXPCL_PANDA extern ConfigVariableBool interpolate_frames;
#endif

View File

@ -69,7 +69,7 @@ get_blend_value(const PartBundle *root) {
// No channel is bound; supply the default value.
_value = _initial_value;
} else if (cdata->_blend.size() == 1) {
} else if (cdata->_blend.size() == 1 && !cdata->_frame_blend_flag) {
// A single value, the normal case.
AnimControl *control = (*cdata->_blend.begin()).first;
@ -85,10 +85,11 @@ get_blend_value(const PartBundle *root) {
}
} else {
// A blend of two or more values.
// 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_single:
case PartBundle::BT_linear:
{
// An ordinary, linear blend.
@ -107,8 +108,18 @@ get_blend_value(const PartBundle *root) {
if (channel != (ChannelType *)NULL) {
ValueType v;
channel->get_value(control->get_frame(), v);
_value += v * effect;
if (!cdata->_frame_blend_flag) {
// Hold the current frame until the next one is ready.
_value += v * effect;
} else {
// Blend between successive frames.
float frac = (float)control->get_frac();
_value += v * (effect * (1.0f - frac));
channel->get_value(control->get_next_frame(), v);
_value += v * (effect * frac);
}
net += effect;
}
}
@ -144,15 +155,35 @@ get_blend_value(const PartBundle *root) {
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
if (channel != (ChannelType *)NULL) {
int frame = control->get_frame();
ValueType v;
channel->get_value_no_scale_shear(control->get_frame(), v);
LVecBase3f iscale, ishear;
channel->get_scale(control->get_frame(), iscale);
channel->get_shear(control->get_frame(), ishear);
channel->get_value_no_scale_shear(frame, v);
channel->get_scale(frame, iscale);
channel->get_shear(frame, ishear);
_value += v * effect;
scale += iscale * effect;
shear += ishear * effect;
if (!cdata->_frame_blend_flag) {
// Hold the current frame until the next one is ready.
_value += v * effect;
scale += iscale * effect;
shear += ishear * effect;
} else {
// Blend between successive frames.
float frac = (float)control->get_frac();
float e0 = effect * (1.0f - frac);
_value += v * e0;
scale += iscale * e0;
shear += ishear * e0;
int next_frame = control->get_next_frame();
channel->get_value_no_scale_shear(next_frame, v);
channel->get_scale(next_frame, iscale);
channel->get_shear(next_frame, ishear);
float e1 = effect * frac;
_value += v * e1;
scale += iscale * e1;
shear += ishear * e1;
}
net += effect;
}
}
@ -193,16 +224,41 @@ get_blend_value(const PartBundle *root) {
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
if (channel != (ChannelType *)NULL) {
int frame = control->get_frame();
LVecBase3f iscale, ihpr, ipos, ishear;
channel->get_scale(control->get_frame(), iscale);
channel->get_hpr(control->get_frame(), ihpr);
channel->get_pos(control->get_frame(), ipos);
channel->get_shear(control->get_frame(), ishear);
channel->get_scale(frame, iscale);
channel->get_hpr(frame, ihpr);
channel->get_pos(frame, ipos);
channel->get_shear(frame, ishear);
scale += iscale * effect;
hpr += ihpr * effect;
pos += ipos * effect;
shear += ishear * effect;
if (!cdata->_frame_blend_flag) {
// Hold the current frame until the next one is ready.
scale += iscale * effect;
hpr += ihpr * effect;
pos += ipos * effect;
shear += ishear * effect;
} else {
// Blend between successive frames.
float frac = (float)control->get_frac();
float e0 = effect * (1.0f - frac);
scale += iscale * e0;
hpr += ihpr * e0;
pos += ipos * e0;
shear += ishear * e0;
int next_frame = control->get_next_frame();
channel->get_scale(next_frame, iscale);
channel->get_hpr(next_frame, ihpr);
channel->get_pos(next_frame, ipos);
channel->get_shear(next_frame, ishear);
float e1 = effect * frac;
scale += iscale * e1;
hpr += ihpr * e1;
pos += ipos * e1;
shear += ishear * e1;
}
net += effect;
}
}
@ -241,17 +297,43 @@ get_blend_value(const PartBundle *root) {
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
if (channel != (ChannelType *)NULL) {
int frame = control->get_frame();
LVecBase3f iscale, ipos, ishear;
LQuaternionf iquat;
channel->get_scale(control->get_frame(), iscale);
channel->get_quat(control->get_frame(), iquat);
channel->get_pos(control->get_frame(), ipos);
channel->get_shear(control->get_frame(), ishear);
channel->get_scale(frame, iscale);
channel->get_quat(frame, iquat);
channel->get_pos(frame, ipos);
channel->get_shear(frame, ishear);
scale += iscale * effect;
quat += iquat * effect;
pos += ipos * effect;
shear += ishear * effect;
if (!cdata->_frame_blend_flag) {
// Hold the current frame until the next one is ready.
scale += iscale * effect;
quat += iquat * effect;
pos += ipos * effect;
shear += ishear * effect;
} else {
// Blend between successive frames.
float frac = (float)control->get_frac();
float e0 = effect * (1.0f - frac);
scale += iscale * e0;
quat += iquat * e0;
pos += ipos * e0;
shear += ishear * e0;
int next_frame = control->get_next_frame();
channel->get_scale(next_frame, iscale);
channel->get_quat(next_frame, iquat);
channel->get_pos(next_frame, ipos);
channel->get_shear(next_frame, ishear);
float e1 = effect * frac;
scale += iscale * e1;
quat += iquat * e1;
pos += ipos * e1;
shear += ishear * e1;
}
net += effect;
}
}

View File

@ -54,7 +54,7 @@ get_blend_value(const PartBundle *root) {
// No channel is bound; supply the default value.
_value = _initial_value;
} else if (cdata->_blend.size() == 1) {
} else if (cdata->_blend.size() == 1 && !cdata->_frame_blend_flag) {
// A single value, the normal case.
AnimControl *control = (*cdata->_blend.begin()).first;
@ -87,7 +87,17 @@ get_blend_value(const PartBundle *root) {
ValueType v;
channel->get_value(control->get_frame(), v);
_value += v * effect;
if (!cdata->_frame_blend_flag) {
// Hold the current frame until the next one is ready.
_value += v * effect;
} else {
// Blend between successive frames.
float frac = (float)control->get_frac();
_value += v * (effect * (1.0f - frac));
channel->get_value(control->get_next_frame(), v);
_value += v * (effect * frac);
}
net += effect;
}
}

View File

@ -17,11 +17,31 @@
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: PartBundle::set_blend_type
// Access: Published
// Description: Defines the algorithm that is used when blending
// multiple frames or multiple animations together, when
// either anim_blend_flag or frame_blend_flag is set
// to true.
//
// See partBundle.h for a description of the meaning of
// each of the BlendType values.
////////////////////////////////////////////////////////////////////
INLINE void PartBundle::
set_blend_type(PartBundle::BlendType bt) {
nassertv(Thread::get_current_pipeline_stage() == 0);
CDWriter cdata(_cycler);
cdata->_blend_type = bt;
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::get_blend_type
// Access: Published
// Description: Returns the way the character responds to multiple
// animations being bound simultaneously.
// Description: Returns the algorithm that is used when blending
// multiple frames or multiple animations together, when
// either anim_blend_flag or frame_blend_flag is set
// to true.
////////////////////////////////////////////////////////////////////
INLINE PartBundle::BlendType PartBundle::
get_blend_type() const {
@ -29,6 +49,62 @@ get_blend_type() const {
return cdata->_blend_type;
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::get_anim_blend_flag
// Access: Published
// Description: Returns whether the character allows multiple
// different animations to be bound simultaneously. See
// set_anim_blend_flag().
////////////////////////////////////////////////////////////////////
INLINE bool PartBundle::
get_anim_blend_flag() const {
CDReader cdata(_cycler);
return cdata->_anim_blend_flag;
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::set_frame_blend_flag
// Access: Published
// Description: Specifies whether the character interpolates (blends)
// between two sequential frames of an active animation,
// showing a smooth intra-frame motion, or whether it
// holds each frame until the next frame is ready,
// showing precisely the specified animation.
//
// When this value is false, the character holds each
// frame until the next is ready. When this is true,
// the character will interpolate between two
// consecutive frames of animation for each frame the
// animation is onscreen, according to the amount of
// time elapsed between the frames.
//
// The default value of this flag is determined by the
// interpolate-frames Config.prc variable.
//
// Use set_blend_type() to change the algorithm that the
// character uses to interpolate matrix positions.
////////////////////////////////////////////////////////////////////
INLINE void PartBundle::
set_frame_blend_flag(bool frame_blend_flag) {
nassertv(Thread::get_current_pipeline_stage() == 0);
CDWriter cdata(_cycler);
cdata->_frame_blend_flag = frame_blend_flag;
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::get_frame_blend_flag
// Access: Published
// Description: Returns whether the character interpolates (blends)
// between two sequential animation frames, or whether
// it holds the current frame until the next one is
// ready. See set_frame_blend_flag().
////////////////////////////////////////////////////////////////////
INLINE bool PartBundle::
get_frame_blend_flag() const {
CDReader cdata(_cycler);
return cdata->_frame_blend_flag;
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::get_node
// Access: Published
@ -50,11 +126,11 @@ get_node() const {
// Zero indicates the animation does not affect the
// character, and one means it does.
//
// If the blend_type is not BT_single (see
// set_blend_type()), it is possible to have multiple
// AnimControls in effect simultaneously. In this case,
// the effect is a weight that indicates the relative
// importance of each AnimControl to the final
// If the _anim_blend_flag is not false (see
// set_anim_blend_flag()), it is possible to have
// multiple AnimControls in effect simultaneously. In
// this case, the effect is a weight that indicates the
// relative importance of each AnimControl to the final
// animation.
////////////////////////////////////////////////////////////////////
void PartBundle::

View File

@ -22,16 +22,24 @@
#include "animControl.h"
#include "config_chan.h"
#include "bitArray.h"
#include "string_utils.h"
#include "indent.h"
#include "datagram.h"
#include "datagramIterator.h"
#include "bamReader.h"
#include "bamWriter.h"
#include "configVariableEnum.h"
TypeHandle PartBundle::_type_handle;
static ConfigVariableEnum<PartBundle::BlendType> anim_blend_type
("anim-blend-type", PartBundle::BT_normalized_linear,
PRC_DESC("The default blend type to use for blending animations between "
"frames, or between multiple animations. See interpolate-frames, "
"and also PartBundle::set_anim_blend_flag() and "
"PartBundle::set_frame_blend_flag()."));
////////////////////////////////////////////////////////////////////
// Function: PartBundle::Copy Constructor
@ -71,37 +79,33 @@ make_copy() const {
////////////////////////////////////////////////////////////////////
// Function: PartBundle::set_blend_type
// Function: PartBundle::set_anim_blend_flag
// Access: Published
// Description: Defines the way the character responds to multiple
// set_control_effect()). By default, the blend_type is
// BT_single, which disallows multiple animations. In
// BT_single mode, it is not necessary to explicitly set
// the control_effect when starting an animation;
// starting the animation will implicitly remove the
// control_effect from the previous animation and set it
// on the current one.
// calls to set_control_effect()). By default, this
// flag is set false, which disallows multiple
// animations. When this flag is false, it is not
// necessary to explicitly set the control_effect when
// starting an animation; starting the animation will
// implicitly remove the control_effect from the
// previous animation and set it on the current one.
//
// However, if the blend_type is set to any other value,
// the control_effect must be explicitly set via
// set_control_effect() whenever an animation is to
// affect the character.
//
// See partBundle.h for a description of the meaning of
// each of the BlendType values.
// However, if this flag is set true, the control_effect
// must be explicitly set via set_control_effect()
// whenever an animation is to affect the character.
////////////////////////////////////////////////////////////////////
void PartBundle::
set_blend_type(BlendType bt) {
set_anim_blend_flag(bool anim_blend_flag) {
nassertv(Thread::get_current_pipeline_stage() == 0);
CDLockedReader cdata(_cycler);
if (cdata->_blend_type != bt) {
if (cdata->_anim_blend_flag != anim_blend_flag) {
CDWriter cdataw(_cycler, cdata);
cdataw->_blend_type = bt;
cdataw->_anim_blend_flag = anim_blend_flag;
if (cdataw->_blend_type == BT_single && cdataw->_blend.size() > 1) {
// If we just changed to a single blend type, i.e. no blending,
// we should eliminate all the AnimControls other than the
if (!anim_blend_flag && cdataw->_blend.size() > 1) {
// If we just changed to disallow animation blending, we should
// eliminate all the AnimControls other than the
// most-recently-added one.
nassertv(cdataw->_last_control_set != NULL);
@ -245,6 +249,12 @@ update() {
{
CDReader cdata(_cycler, current_thread);
anim_changed = cdata->_anim_changed;
if (cdata->_frame_blend_flag) {
// If the intra-frame blend flag is on, we will just assume the
// animation changes every time we call update().
anim_changed = true;
}
}
bool any_changed = do_update(this, NULL, false, anim_changed, current_thread);
@ -300,9 +310,10 @@ control_activated(AnimControl *control) {
nassertv(control->get_part() == this);
CDLockedReader cdata(_cycler);
// If (and only if) our blend type is BT_single, which means no
// blending, then starting an animation implicitly enables it.
if (cdata->_blend_type == BT_single) {
// If (and only if) our anim_blend_flag is false, then starting an
// animation implicitly enables it.
if (!cdata->_anim_blend_flag) {
CDWriter cdataw(_cycler, cdata);
do_set_control_effect(control, 1.0f, cdataw);
}
@ -330,9 +341,9 @@ do_set_control_effect(AnimControl *control, float effect, CData *cdata) {
} else {
// Otherwise we define it.
// If we currently have BT_single, we only allow one AnimControl
// at a time. Stop all of the other AnimControls.
if (cdata->_blend_type == BT_single) {
// If anim_blend_flag is false, we only allow one AnimControl at a
// time. Stop all of the other AnimControls.
if (!cdata->_anim_blend_flag) {
clear_and_stop_intersecting(control, cdata);
}
@ -388,9 +399,9 @@ recompute_net_blend(CData *cdata) {
// Description: Removes and stops all the currently activated
// 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.
// internal function that's only called when
// _anim_blend_flag is false, to automatically stop all
// the other currently-executing animations.
////////////////////////////////////////////////////////////////////
void PartBundle::
clear_and_stop_intersecting(AnimControl *control, CData *cdata) {
@ -470,7 +481,9 @@ register_with_read_factory()
////////////////////////////////////////////////////////////////////
PartBundle::CData::
CData() {
_blend_type = BT_single;
_blend_type = anim_blend_type;
_anim_blend_flag = false;
_frame_blend_flag = interpolate_frames;
_last_control_set = NULL;
_net_blend = 0.0f;
_anim_changed = false;
@ -503,3 +516,58 @@ CycleData *PartBundle::CData::
make_copy() const {
return new CData(*this);
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::BlendType output operator
// Description:
////////////////////////////////////////////////////////////////////
ostream &
operator << (ostream &out, PartBundle::BlendType blend_type) {
switch (blend_type) {
case PartBundle::BT_linear:
return out << "linear";
case PartBundle::BT_normalized_linear:
return out << "normalized_linear";
case PartBundle::BT_componentwise:
return out << "componentwise";
case PartBundle::BT_componentwise_quat:
return out << "componentwise_quat";
}
chan_cat->error()
<< "Invalid BlendType value: " << (int)blend_type << "\n";
nassertr(false, out);
return out;
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::BlendType input operator
// Description:
////////////////////////////////////////////////////////////////////
istream &
operator >> (istream &in, PartBundle::BlendType &blend_type) {
string word;
in >> word;
if (cmp_nocase_uh(word, "linear") == 0) {
blend_type = PartBundle::BT_linear;
} else if (cmp_nocase_uh(word, "normalized_linear") == 0) {
blend_type = PartBundle::BT_normalized_linear;
} else if (cmp_nocase_uh(word, "componentwise") == 0) {
blend_type = PartBundle::BT_componentwise;
} else if (cmp_nocase_uh(word, "componentwise_quat") == 0) {
blend_type = PartBundle::BT_componentwise_quat;
} else {
chan_cat->error()
<< "Invalid BlendType string: " << word << "\n";
blend_type = PartBundle::BT_linear;
}
return in;
}

View File

@ -60,18 +60,9 @@ PUBLISHED:
// This is the parameter to set_blend_type() and specifies the kind
// of blending operation to be performed when multiple controls are
// in effect simultaneously (see set_control_effect()).
// in effect simultaneously (see set_control_effect()) or between
// sequential frames of the animation.
enum BlendType {
// BT_single means no blending is performed. Only one AnimControl
// is allowed to be set at a time in set_control_effect(). In
// this mode, and this mode only, activating a particular
// AnimControl (via play(), loop(), or pose()) will implicitly set
// the bundle's control_effect to 100% of that particular
// AnimControl, removing any AnimControls previously set. In
// other modes, the control_effect must be set manually.
BT_single,
// BT_linear does a componentwise average of all blended matrices,
// which is a linear blend. The result of this is that if a
// particular vertex would have been at point P in one animation
@ -100,9 +91,15 @@ PUBLISHED:
BT_componentwise_quat,
};
void set_blend_type(BlendType bt);
INLINE void set_blend_type(BlendType bt);
INLINE BlendType get_blend_type() const;
void set_anim_blend_flag(bool anim_blend_flag);
INLINE bool get_anim_blend_flag() const;
INLINE void set_frame_blend_flag(bool frame_blend_flag);
INLINE bool get_frame_blend_flag() const;
INLINE PartBundleNode *get_node() const;
void clear_control_effects();
@ -147,6 +144,8 @@ private:
}
BlendType _blend_type;
bool _anim_blend_flag;
bool _frame_blend_flag;
AnimControl *_last_control_set;
ChannelBlend _blend;
float _net_blend;
@ -193,6 +192,9 @@ inline ostream &operator <<(ostream &out, const PartBundle &bundle) {
return out;
}
ostream &operator <<(ostream &out, PartBundle::BlendType blend_type);
istream &operator >>(istream &in, PartBundle::BlendType &blend_type);
#include "partBundle.I"
#endif

View File

@ -54,6 +54,8 @@ Character(const Character &copy) :
// update our _parts list.
copy_joints(get_bundle(), copy.get_bundle());
_last_auto_update = -1.0;
}
////////////////////////////////////////////////////////////////////
@ -154,15 +156,18 @@ cull_callback(CullTraverser *, CullTraverserData &) {
// optimization later, to handle characters that might animate
// themselves in front of the view frustum.
PStatTimer timer(_joints_pcollector);
double now = ClockObject::get_global_clock()->get_frame_time();
if (now != _last_auto_update) {
_last_auto_update = now;
if (char_cat.is_spam()) {
double now = ClockObject::get_global_clock()->get_frame_time();
char_cat.spam() << "Animating " << *this << " at time " << now << "\n";
PStatTimer timer(_joints_pcollector);
if (char_cat.is_spam()) {
char_cat.spam() << "Animating " << *this << " at time " << now << "\n";
}
do_update();
}
do_update();
return true;
}

View File

@ -119,6 +119,8 @@ private:
typedef vector_PartGroupStar Parts;
Parts _parts;
double _last_auto_update;
// Statistics
PStatCollector _joints_pcollector;
PStatCollector _skinning_pcollector;

View File

@ -119,7 +119,7 @@ pingpong(bool restart, double from, double to) {
////////////////////////////////////////////////////////////////////
INLINE void AnimInterface::
stop() {
pose(get_frame());
pose(get_full_fframe());
}
////////////////////////////////////////////////////////////////////
@ -129,7 +129,7 @@ stop() {
// it there.
////////////////////////////////////////////////////////////////////
INLINE void AnimInterface::
pose(int frame) {
pose(double frame) {
{
CDWriter cdata(_cycler);
cdata->pose(frame);
@ -192,7 +192,30 @@ get_frame() const {
if (num_frames <= 0) {
return 0;
}
return cmod(get_full_frame(), num_frames);
CDReader cdata(_cycler);
return cmod(cdata->get_full_frame(0), num_frames);
}
////////////////////////////////////////////////////////////////////
// Function: AnimInterface::get_next_frame
// Access: Published
// Description: Returns the current integer frame number + 1,
// constrained to the range 0 <= f < get_num_frames().
//
// If the play mode is PM_play, this will clamp to the
// same value as get_frame() at the end of the
// animation. If the play mode is any other value, this
// will wrap around to frame 0 at the end of the
// animation.
////////////////////////////////////////////////////////////////////
INLINE int AnimInterface::
get_next_frame() const {
int num_frames = get_num_frames();
if (num_frames <= 0) {
return 0;
}
CDReader cdata(_cycler);
return cmod(cdata->get_full_frame(1), num_frames);
}
////////////////////////////////////////////////////////////////////
@ -229,7 +252,7 @@ get_frac() const {
INLINE int AnimInterface::
get_full_frame() const {
CDReader cdata(_cycler);
return cdata->get_full_frame();
return cdata->get_full_frame(0);
}
////////////////////////////////////////////////////////////////////
@ -308,7 +331,7 @@ set_num_frames(int num_frames) {
////////////////////////////////////////////////////////////////////
INLINE double AnimInterface::CData::
get_frac() const {
return get_full_fframe() - (double)get_full_frame();
return get_full_fframe() - (double)get_full_frame(0);
}
INLINE ostream &

View File

@ -229,7 +229,7 @@ fillin(DatagramIterator &scan, BamReader *) {
void AnimInterface::CData::
play(double from, double to) {
if (from >= to) {
pose((int)from);
pose(from);
return;
}
@ -259,7 +259,7 @@ play(double from, double to) {
void AnimInterface::CData::
loop(bool restart, double from, double to) {
if (from >= to) {
pose((int)from);
pose(from);
return;
}
@ -292,7 +292,7 @@ loop(bool restart, double from, double to) {
void AnimInterface::CData::
pingpong(bool restart, double from, double to) {
if (from >= to) {
pose((int)from);
pose(from);
return;
}
@ -322,20 +322,21 @@ pingpong(bool restart, double from, double to) {
// it there.
////////////////////////////////////////////////////////////////////
void AnimInterface::CData::
pose(int frame) {
pose(double frame) {
_play_mode = PM_pose;
_start_time = ClockObject::get_global_clock()->get_frame_time();
_start_frame = (double)frame;
_start_frame = frame;
_play_frames = 0.0;
_from_frame = frame;
_to_frame = frame;
_from_frame = (int)floor(frame);
_to_frame = (int)floor(frame);
_paused_f = 0.0;
}
////////////////////////////////////////////////////////////////////
// Function: AnimInterface::CData::get_full_frame
// Access: Public
// Description: Returns the current integer frame number.
// Description: Returns the current integer frame number, plus the
// indicated increment.
//
// Unlike the value returned by get_frame(), this frame
// number may extend beyond the range of
@ -347,8 +348,8 @@ pose(int frame) {
// to_frame in the play() method.
////////////////////////////////////////////////////////////////////
int AnimInterface::CData::
get_full_frame() const {
int frame = (int)floor(get_full_fframe());
get_full_frame(int increment) const {
int frame = (int)floor(get_full_fframe()) + increment;
if (_play_mode == PM_play) {
// In play mode, we never let the return value exceed
// (_from_frame, _to_frame).
@ -435,19 +436,19 @@ void AnimInterface::CData::
output(ostream &out) const {
switch (_play_mode) {
case PM_pose:
out << "pose, frame " << get_full_frame();
out << "pose, frame " << get_full_fframe();
return;
case PM_play:
out << "play, frame " << get_full_frame();
out << "play, frame " << get_full_fframe();
return;
case PM_loop:
out << "loop, frame " << get_full_frame();
out << "loop, frame " << get_full_fframe();
return;
case PM_pingpong:
out << "pingpong, frame " << get_full_frame();
out << "pingpong, frame " << get_full_fframe();
return;
}
}

View File

@ -54,7 +54,7 @@ PUBLISHED:
INLINE void pingpong(bool restart);
INLINE void pingpong(bool restart, double from, double to);
INLINE void stop();
INLINE void pose(int frame);
INLINE void pose(double frame);
INLINE void set_play_rate(double play_rate);
INLINE double get_play_rate() const;
@ -62,6 +62,7 @@ PUBLISHED:
virtual int get_num_frames() const;
INLINE int get_frame() const;
INLINE int get_next_frame() const;
INLINE double get_frac() const;
INLINE int get_full_frame() const;
INLINE double get_full_fframe() const;
@ -102,10 +103,10 @@ private:
void play(double from, double to);
void loop(bool restart, double from, double to);
void pingpong(bool restart, double from, double to);
void pose(int frame);
void pose(double frame);
INLINE double get_frac() const;
int get_full_frame() const;
int get_full_frame(int increment) const;
double get_full_fframe() const;
bool is_playing() const;