[c] Ported additive blending, including attachment and draw order timeline fixes. See #1029, #1060

This commit is contained in:
badlogic 2018-01-18 14:59:26 +01:00
parent 162f5a4270
commit c94bec6e4e
6 changed files with 381 additions and 229 deletions

View File

@ -60,10 +60,11 @@ typedef struct spAnimation {
} spAnimation; } spAnimation;
typedef enum { typedef enum {
SP_MIX_POSE_SETUP, SP_MIX_BLEND_SETUP,
SP_MIX_POSE_CURRENT, SP_MIX_BLEND_FIRST,
SP_MIX_POSE_CURRENT_LAYERED SP_MIX_BLEND_REPLACE,
} spMixPose; SP_MIX_BLEND_ADD
} spMixBlend;
typedef enum { typedef enum {
SP_MIX_DIRECTION_IN, SP_MIX_DIRECTION_IN,
@ -77,7 +78,7 @@ SP_API void spAnimation_dispose (spAnimation* self);
* @param lastTime The last time the animation was applied. * @param lastTime The last time the animation was applied.
* @param events Any triggered events are added. May be null.*/ * @param events Any triggered events are added. May be null.*/
SP_API void spAnimation_apply (const spAnimation* self, struct spSkeleton* skeleton, float lastTime, float time, int loop, SP_API void spAnimation_apply (const spAnimation* self, struct spSkeleton* skeleton, float lastTime, float time, int loop,
spEvent** events, int* eventsCount, float alpha, spMixPose pose, spMixDirection direction); spEvent** events, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction);
#ifdef SPINE_SHORT_NAMES #ifdef SPINE_SHORT_NAMES
typedef spAnimation Animation; typedef spAnimation Animation;
@ -120,7 +121,7 @@ struct spTimeline {
SP_API void spTimeline_dispose (spTimeline* self); SP_API void spTimeline_dispose (spTimeline* self);
SP_API void spTimeline_apply (const spTimeline* self, struct spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, SP_API void spTimeline_apply (const spTimeline* self, struct spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixPose pose, spMixDirection direction); int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction);
SP_API int spTimeline_getPropertyId (const spTimeline* self); SP_API int spTimeline_getPropertyId (const spTimeline* self);
#ifdef SPINE_SHORT_NAMES #ifdef SPINE_SHORT_NAMES

View File

@ -63,6 +63,7 @@ struct spTrackEntry {
float animationStart, animationEnd, animationLast, nextAnimationLast; float animationStart, animationEnd, animationLast, nextAnimationLast;
float delay, trackTime, trackLast, nextTrackLast, trackEnd, timeScale; float delay, trackTime, trackLast, nextTrackLast, trackEnd, timeScale;
float alpha, mixTime, mixDuration, interruptAlpha, totalAlpha; float alpha, mixTime, mixDuration, interruptAlpha, totalAlpha;
spMixBlend mixBlend;
spIntArray* timelineData; spIntArray* timelineData;
spTrackEntryArray* timelineDipMix; spTrackEntryArray* timelineDipMix;
float* timelinesRotation; float* timelinesRotation;
@ -81,6 +82,7 @@ struct spTrackEntry {
animationStart(0), animationEnd(0), animationLast(0), nextAnimationLast(0), animationStart(0), animationEnd(0), animationLast(0), nextAnimationLast(0),
delay(0), trackTime(0), trackLast(0), nextTrackLast(0), trackEnd(0), timeScale(0), delay(0), trackTime(0), trackLast(0), nextTrackLast(0), trackEnd(0), timeScale(0),
alpha(0), mixTime(0), mixDuration(0), interruptAlpha(0), totalAlpha(0), alpha(0), mixTime(0), mixDuration(0), interruptAlpha(0), totalAlpha(0),
mixBlend(SP_MIX_BLEND_REPLACE),
timelineData(0), timelineData(0),
timelineDipMix(0), timelineDipMix(0),
timelinesRotation(0), timelinesRotation(0),

View File

@ -287,7 +287,7 @@ void _spVertexAttachment_deinit (spVertexAttachment* self);
void _spTimeline_init (spTimeline* self, spTimelineType type, void _spTimeline_init (spTimeline* self, spTimelineType type,
void (*dispose) (spTimeline* self), void (*dispose) (spTimeline* self),
void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixPose pose, spMixDirection direction), int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction),
int (*getPropertyId) (const spTimeline* self)); int (*getPropertyId) (const spTimeline* self));
void _spTimeline_deinit (spTimeline* self); void _spTimeline_deinit (spTimeline* self);
@ -300,7 +300,7 @@ void _spTimeline_deinit (spTimeline* self);
void _spCurveTimeline_init (spCurveTimeline* self, spTimelineType type, int framesCount, void _spCurveTimeline_init (spCurveTimeline* self, spTimelineType type, int framesCount,
void (*dispose) (spTimeline* self), void (*dispose) (spTimeline* self),
void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, int* eventsCount, float alpha, spMixPose pose, spMixDirection direction), void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction),
int (*getPropertyId) (const spTimeline* self)); int (*getPropertyId) (const spTimeline* self));
void _spCurveTimeline_deinit (spCurveTimeline* self); void _spCurveTimeline_deinit (spCurveTimeline* self);
int _spCurveTimeline_binarySearch (float *values, int valuesLength, float target, int step); int _spCurveTimeline_binarySearch (float *values, int valuesLength, float target, int step);

View File

@ -51,7 +51,7 @@ void spAnimation_dispose (spAnimation* self) {
} }
void spAnimation_apply (const spAnimation* self, spSkeleton* skeleton, float lastTime, float time, int loop, spEvent** events, void spAnimation_apply (const spAnimation* self, spSkeleton* skeleton, float lastTime, float time, int loop, spEvent** events,
int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
int i, n = self->timelinesCount; int i, n = self->timelinesCount;
if (loop && self->duration) { if (loop && self->duration) {
@ -60,21 +60,21 @@ void spAnimation_apply (const spAnimation* self, spSkeleton* skeleton, float las
} }
for (i = 0; i < n; ++i) for (i = 0; i < n; ++i)
spTimeline_apply(self->timelines[i], skeleton, lastTime, time, events, eventsCount, alpha, pose, direction); spTimeline_apply(self->timelines[i], skeleton, lastTime, time, events, eventsCount, alpha, blend, direction);
} }
/**/ /**/
typedef struct _spTimelineVtable { typedef struct _spTimelineVtable {
void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixPose pose, spMixDirection direction); int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction);
int (*getPropertyId) (const spTimeline* self); int (*getPropertyId) (const spTimeline* self);
void (*dispose) (spTimeline* self); void (*dispose) (spTimeline* self);
} _spTimelineVtable; } _spTimelineVtable;
void _spTimeline_init (spTimeline* self, spTimelineType type, /**/ void _spTimeline_init (spTimeline* self, spTimelineType type, /**/
void (*dispose) (spTimeline* self), /**/ void (*dispose) (spTimeline* self), /**/
void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, int* eventsCount, float alpha, spMixPose pose, spMixDirection direction), void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction),
int (*getPropertyId) (const spTimeline* self)) { int (*getPropertyId) (const spTimeline* self)) {
CONST_CAST(spTimelineType, self->type) = type; CONST_CAST(spTimelineType, self->type) = type;
CONST_CAST(_spTimelineVtable*, self->vtable) = NEW(_spTimelineVtable); CONST_CAST(_spTimelineVtable*, self->vtable) = NEW(_spTimelineVtable);
@ -92,8 +92,8 @@ void spTimeline_dispose (spTimeline* self) {
} }
void spTimeline_apply (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, void spTimeline_apply (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
VTABLE(spTimeline, self)->apply(self, skeleton, lastTime, time, firedEvents, eventsCount, alpha, pose, direction); VTABLE(spTimeline, self)->apply(self, skeleton, lastTime, time, firedEvents, eventsCount, alpha, blend, direction);
} }
int spTimeline_getPropertyId (const spTimeline* self) { int spTimeline_getPropertyId (const spTimeline* self) {
@ -107,7 +107,7 @@ static const int BEZIER_SIZE = 10 * 2 - 1;
void _spCurveTimeline_init (spCurveTimeline* self, spTimelineType type, int framesCount, /**/ void _spCurveTimeline_init (spCurveTimeline* self, spTimelineType type, int framesCount, /**/
void (*dispose) (spTimeline* self), /**/ void (*dispose) (spTimeline* self), /**/
void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, int* eventsCount, float alpha, spMixPose pose, spMixDirection direction), void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction),
int (*getPropertyId)(const spTimeline* self)) { int (*getPropertyId)(const spTimeline* self)) {
_spTimeline_init(SUPER(self), type, dispose, apply, getPropertyId); _spTimeline_init(SUPER(self), type, dispose, apply, getPropertyId);
self->curves = CALLOC(float, (framesCount - 1) * BEZIER_SIZE); self->curves = CALLOC(float, (framesCount - 1) * BEZIER_SIZE);
@ -225,7 +225,7 @@ void _spBaseTimeline_dispose (spTimeline* timeline) {
/* Many timelines have structure identical to struct spBaseTimeline and extend spCurveTimeline. **/ /* Many timelines have structure identical to struct spBaseTimeline and extend spCurveTimeline. **/
struct spBaseTimeline* _spBaseTimeline_create (int framesCount, spTimelineType type, int frameSize, /**/ struct spBaseTimeline* _spBaseTimeline_create (int framesCount, spTimelineType type, int frameSize, /**/
void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixPose pose, spMixDirection direction), int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction),
int (*getPropertyId) (const spTimeline* self)) { int (*getPropertyId) (const spTimeline* self)) {
struct spBaseTimeline* self = NEW(struct spBaseTimeline); struct spBaseTimeline* self = NEW(struct spBaseTimeline);
_spCurveTimeline_init(SUPER(self), type, framesCount, _spBaseTimeline_dispose, apply, getPropertyId); _spCurveTimeline_init(SUPER(self), type, framesCount, _spBaseTimeline_dispose, apply, getPropertyId);
@ -239,7 +239,7 @@ struct spBaseTimeline* _spBaseTimeline_create (int framesCount, spTimelineType t
/**/ /**/
void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
spBone *bone; spBone *bone;
int frame; int frame;
float prevRotation, frameTime, percent, r; float prevRotation, frameTime, percent, r;
@ -248,26 +248,33 @@ void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
bone = skeleton->bones[self->boneIndex]; bone = skeleton->bones[self->boneIndex];
if (time < self->frames[0]) { if (time < self->frames[0]) {
switch (pose) { switch (blend) {
case SP_MIX_POSE_SETUP: case SP_MIX_BLEND_SETUP:
bone->rotation = bone->data->rotation; bone->rotation = bone->data->rotation;
return; return;
case SP_MIX_POSE_CURRENT: case SP_MIX_BLEND_FIRST:
r = bone->data->rotation - bone->rotation; r = bone->data->rotation - bone->rotation;
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360; r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
bone->rotation += r * alpha; bone->rotation += r * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */ case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
; /* to appease compiler */
} }
return; return;
} }
if (time >= self->frames[self->framesCount - ROTATE_ENTRIES]) { /* Time is after last frame. */ if (time >= self->frames[self->framesCount - ROTATE_ENTRIES]) { /* Time is after last frame. */
if (pose == SP_MIX_POSE_SETUP) r = self->frames[self->framesCount + ROTATE_PREV_ROTATION];
bone->rotation = bone->data->rotation + self->frames[self->framesCount + ROTATE_PREV_ROTATION] * alpha; switch (blend) {
else { case SP_MIX_BLEND_SETUP:
r = bone->data->rotation + self->frames[self->framesCount + ROTATE_PREV_ROTATION] - bone->rotation; bone->rotation = bone->data->rotation + r * alpha;
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360; /* Wrap within -180 and 180. */ break;
bone->rotation += r * alpha; case SP_MIX_BLEND_FIRST:
case SP_MIX_BLEND_REPLACE:
r += bone->data->rotation - bone->rotation;
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360; /* Wrap within -180 and 180. */
case SP_MIX_BLEND_ADD:
bone->rotation += r * alpha;
} }
return; return;
} }
@ -279,15 +286,16 @@ void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
percent = spCurveTimeline_getCurvePercent(SUPER(self), (frame >> 1) - 1, 1 - (time - frameTime) / (self->frames[frame + ROTATE_PREV_TIME] - frameTime)); percent = spCurveTimeline_getCurvePercent(SUPER(self), (frame >> 1) - 1, 1 - (time - frameTime) / (self->frames[frame + ROTATE_PREV_TIME] - frameTime));
r = self->frames[frame + ROTATE_ROTATION] - prevRotation; r = self->frames[frame + ROTATE_ROTATION] - prevRotation;
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360; r = prevRotation + (r - (16384 - (int)(16384.499999999996 - r / 360)) * 360) * percent;
r = prevRotation + r * percent; switch (blend) {
if (pose == SP_MIX_POSE_SETUP) { case SP_MIX_BLEND_SETUP:
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360; bone->rotation = bone->data->rotation + (r - (16384 - (int)(16384.499999999996 - r / 360)) * 360) * alpha;
bone->rotation = bone->data->rotation + r * alpha; break;
} else { case SP_MIX_BLEND_FIRST:
r = bone->data->rotation + r - bone->rotation; case SP_MIX_BLEND_REPLACE:
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360; r += bone->data->rotation - bone->rotation;
bone->rotation += r * alpha; case SP_MIX_BLEND_ADD:
bone->rotation += (r - (16384 - (int)(16384.499999999996 - r / 360)) * 360) * alpha;
} }
UNUSED(lastTime); UNUSED(lastTime);
@ -315,7 +323,7 @@ static const int TRANSLATE_PREV_TIME = -3, TRANSLATE_PREV_X = -2, TRANSLATE_PREV
static const int TRANSLATE_X = 1, TRANSLATE_Y = 2; static const int TRANSLATE_X = 1, TRANSLATE_Y = 2;
void _spTranslateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, void _spTranslateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
spEvent** firedEvents, int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
spBone *bone; spBone *bone;
int frame; int frame;
float frameTime, percent; float frameTime, percent;
@ -327,15 +335,17 @@ void _spTranslateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleto
bone = skeleton->bones[self->boneIndex]; bone = skeleton->bones[self->boneIndex];
if (time < self->frames[0]) { if (time < self->frames[0]) {
switch (pose) { switch (blend) {
case SP_MIX_POSE_SETUP: case SP_MIX_BLEND_SETUP:
bone->x = bone->data->x; bone->x = bone->data->x;
bone->y = bone->data->y; bone->y = bone->data->y;
return; return;
case SP_MIX_POSE_CURRENT: case SP_MIX_BLEND_FIRST:
bone->x += (bone->data->x - bone->x) * alpha; bone->x += (bone->data->x - bone->x) * alpha;
bone->y += (bone->data->y - bone->y) * alpha; bone->y += (bone->data->y - bone->y) * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */ case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
; /* to appease compiler */
} }
return; return;
} }
@ -357,12 +367,19 @@ void _spTranslateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleto
x += (frames[frame + TRANSLATE_X] - x) * percent; x += (frames[frame + TRANSLATE_X] - x) * percent;
y += (frames[frame + TRANSLATE_Y] - y) * percent; y += (frames[frame + TRANSLATE_Y] - y) * percent;
} }
if (pose == SP_MIX_POSE_SETUP) { switch (blend) {
bone->x = bone->data->x + x * alpha; case SP_MIX_BLEND_SETUP:
bone->y = bone->data->y + y * alpha; bone->x = bone->data->x + x * alpha;
} else { bone->y = bone->data->y + y * alpha;
bone->x += (bone->data->x + x - bone->x) * alpha; break;
bone->y += (bone->data->y + y - bone->y) * alpha; case SP_MIX_BLEND_FIRST:
case SP_MIX_BLEND_REPLACE:
bone->x += (bone->data->x + x - bone->x) * alpha;
bone->y += (bone->data->y + y - bone->y) * alpha;
break;
case SP_MIX_BLEND_ADD:
bone->x += x * alpha;
bone->y += y * alpha;
} }
UNUSED(lastTime); UNUSED(lastTime);
@ -388,7 +405,7 @@ void spTranslateTimeline_setFrame (spTranslateTimeline* self, int frameIndex, fl
/**/ /**/
void _spScaleTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, void _spScaleTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
spBone *bone; spBone *bone;
int frame; int frame;
float frameTime, percent, x, y; float frameTime, percent, x, y;
@ -399,15 +416,17 @@ void _spScaleTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
bone = skeleton->bones[self->boneIndex]; bone = skeleton->bones[self->boneIndex];
if (time < self->frames[0]) { if (time < self->frames[0]) {
switch (pose) { switch (blend) {
case SP_MIX_POSE_SETUP: case SP_MIX_BLEND_SETUP:
bone->scaleX = bone->data->scaleX; bone->scaleX = bone->data->scaleX;
bone->scaleY = bone->data->scaleY; bone->scaleY = bone->data->scaleY;
return; return;
case SP_MIX_POSE_CURRENT: case SP_MIX_BLEND_FIRST:
bone->scaleX += (bone->data->scaleX - bone->scaleX) * alpha; bone->scaleX += (bone->data->scaleX - bone->scaleX) * alpha;
bone->scaleY += (bone->data->scaleY - bone->scaleY) * alpha; bone->scaleY += (bone->data->scaleY - bone->scaleY) * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */ case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
; /* to appease compiler */
} }
return; return;
} }
@ -430,27 +449,56 @@ void _spScaleTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
y = (y + (frames[frame + TRANSLATE_Y] - y) * percent) * bone->data->scaleY; y = (y + (frames[frame + TRANSLATE_Y] - y) * percent) * bone->data->scaleY;
} }
if (alpha == 1) { if (alpha == 1) {
bone->scaleX = x; if (blend == SP_MIX_BLEND_ADD) {
bone->scaleY = y; bone->scaleX += x - bone->data->scaleX;
bone->scaleY += y - bone->data->scaleY;
} else {
bone->scaleX = x;
bone->scaleY = y;
}
} else { } else {
float bx, by; float bx, by;
if (pose == SP_MIX_POSE_SETUP) {
bx = bone->data->scaleX;
by = bone->data->scaleY;
} else {
bx = bone->scaleX;
by = bone->scaleY;
}
/* Mixing out uses sign of setup or current pose, else use sign of key. */
if (direction == SP_MIX_DIRECTION_OUT) { if (direction == SP_MIX_DIRECTION_OUT) {
x = ABS(x) * SIGNUM(bx); switch (blend) {
y = ABS(y) * SIGNUM(by); case SP_MIX_BLEND_SETUP:
bx = bone->data->scaleX;
by = bone->data->scaleY;
bone->scaleX = bx + (ABS(x) * SIGNUM(bx) - bx) * alpha;
bone->scaleY = by + (ABS(y) * SIGNUM(by) - by) * alpha;
break;
case SP_MIX_BLEND_FIRST:
case SP_MIX_BLEND_REPLACE:
bx = bone->scaleX;
by = bone->scaleY;
bone->scaleX = bx + (ABS(x) * SIGNUM(bx) - bx) * alpha;
bone->scaleY = by + (ABS(y) * SIGNUM(by) - by) * alpha;
break;
case SP_MIX_BLEND_ADD:
bx = bone->scaleX;
by = bone->scaleY;
bone->scaleX = bx + (ABS(x) * SIGNUM(bx) - bone->data->scaleX) * alpha;
bone->scaleY = by + (ABS(y) * SIGNUM(by) - bone->data->scaleY) * alpha;
}
} else { } else {
bx = ABS(bx) * SIGNUM(x); switch (blend) {
by = ABS(by) * SIGNUM(y); case SP_MIX_BLEND_SETUP:
bx = ABS(bone->data->scaleX) * SIGNUM(x);
by = ABS(bone->data->scaleY) * SIGNUM(y);
bone->scaleX = bx + (x - bx) * alpha;
bone->scaleY = by + (y - by) * alpha;
break;
case SP_MIX_BLEND_FIRST:
case SP_MIX_BLEND_REPLACE:
bone->scaleX += (x - bone->scaleX * SIGNUM(x)) * alpha;
bone->scaleY += (y - bone->scaleY * SIGNUM(y)) * alpha;
break;
case SP_MIX_BLEND_ADD:
bx = SIGNUM(x);
by = SIGNUM(y);
bone->scaleX = ABS(bone->scaleX) * bx + (x - ABS(bone->data->scaleX) * bx) * alpha;
bone->scaleY = ABS(bone->scaleY) * by + (y - ABS(bone->data->scaleY) * by) * alpha;
}
} }
bone->scaleX = bx + (x - bx) * alpha;
bone->scaleY = by + (y - by) * alpha;
} }
UNUSED(lastTime); UNUSED(lastTime);
@ -473,7 +521,7 @@ void spScaleTimeline_setFrame (spScaleTimeline* self, int frameIndex, float time
/**/ /**/
void _spShearTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, void _spShearTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
spBone *bone; spBone *bone;
int frame; int frame;
float frameTime, percent, x, y; float frameTime, percent, x, y;
@ -486,15 +534,17 @@ void _spShearTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
frames = self->frames; frames = self->frames;
framesCount = self->framesCount; framesCount = self->framesCount;
if (time < self->frames[0]) { if (time < self->frames[0]) {
switch (pose) { switch (blend) {
case SP_MIX_POSE_SETUP: case SP_MIX_BLEND_SETUP:
bone->shearX = bone->data->shearX; bone->shearX = bone->data->shearX;
bone->shearY = bone->data->shearY; bone->shearY = bone->data->shearY;
return; return;
case SP_MIX_POSE_CURRENT: case SP_MIX_BLEND_FIRST:
bone->shearX += (bone->data->shearX - bone->shearX) * alpha; bone->shearX += (bone->data->shearX - bone->shearX) * alpha;
bone->shearY += (bone->data->shearY - bone->shearY) * alpha; bone->shearY += (bone->data->shearY - bone->shearY) * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */ case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
; /* to appease compiler */
} }
return; return;
} }
@ -514,12 +564,19 @@ void _spShearTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
x = x + (frames[frame + TRANSLATE_X] - x) * percent; x = x + (frames[frame + TRANSLATE_X] - x) * percent;
y = y + (frames[frame + TRANSLATE_Y] - y) * percent; y = y + (frames[frame + TRANSLATE_Y] - y) * percent;
} }
if (pose == SP_MIX_POSE_SETUP) { switch (blend) {
bone->shearX = bone->data->shearX + x * alpha; case SP_MIX_BLEND_SETUP:
bone->shearY = bone->data->shearY + y * alpha; bone->shearX = bone->data->shearX + x * alpha;
} else { bone->shearY = bone->data->shearY + y * alpha;
bone->shearX += (bone->data->shearX + x - bone->shearX) * alpha; break;
bone->shearY += (bone->data->shearY + y - bone->shearY) * alpha; case SP_MIX_BLEND_FIRST:
case SP_MIX_BLEND_REPLACE:
bone->shearX += (bone->data->shearX + x - bone->shearX) * alpha;
bone->shearY += (bone->data->shearY + y - bone->shearY) * alpha;
break;
case SP_MIX_BLEND_ADD:
bone->shearX += x * alpha;
bone->shearY += y * alpha;
} }
UNUSED(lastTime); UNUSED(lastTime);
@ -545,7 +602,7 @@ static const int COLOR_PREV_TIME = -5, COLOR_PREV_R = -4, COLOR_PREV_G = -3, COL
static const int COLOR_R = 1, COLOR_G = 2, COLOR_B = 3, COLOR_A = 4; static const int COLOR_R = 1, COLOR_G = 2, COLOR_B = 3, COLOR_A = 4;
void _spColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, void _spColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
spSlot *slot; spSlot *slot;
int frame; int frame;
float percent, frameTime; float percent, frameTime;
@ -556,16 +613,18 @@ void _spColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
slot = skeleton->slots[self->slotIndex]; slot = skeleton->slots[self->slotIndex];
if (time < self->frames[0]) { if (time < self->frames[0]) {
switch (pose) { switch (blend) {
case SP_MIX_POSE_SETUP: case SP_MIX_BLEND_SETUP:
spColor_setFromColor(&slot->color, &slot->data->color); spColor_setFromColor(&slot->color, &slot->data->color);
return; return;
case SP_MIX_POSE_CURRENT: case SP_MIX_BLEND_FIRST:
color = &slot->color; color = &slot->color;
setup = &slot->data->color; setup = &slot->data->color;
spColor_addFloats(color, (setup->r - color->r) * alpha, (setup->g - color->g) * alpha, (setup->b - color->b) * alpha, spColor_addFloats(color, (setup->r - color->r) * alpha, (setup->g - color->g) * alpha, (setup->b - color->b) * alpha,
(setup->a - color->a) * alpha); (setup->a - color->a) * alpha);
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */ case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
; /* to appease compiler */
} }
return; return;
} }
@ -597,7 +656,7 @@ void _spColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
if (alpha == 1) { if (alpha == 1) {
spColor_setFromFloats(&slot->color, r, g, b, a); spColor_setFromFloats(&slot->color, r, g, b, a);
} else { } else {
if (pose == SP_MIX_POSE_SETUP) { if (blend == SP_MIX_BLEND_SETUP) {
spColor_setFromColor(&slot->color, &slot->data->color); spColor_setFromColor(&slot->color, &slot->data->color);
} }
spColor_addFloats(&slot->color, (r - slot->color.r) * alpha, (g - slot->color.g) * alpha, (b - slot->color.b) * alpha, (a - slot->color.a) * alpha); spColor_addFloats(&slot->color, (r - slot->color.r) * alpha, (g - slot->color.g) * alpha, (b - slot->color.b) * alpha, (a - slot->color.a) * alpha);
@ -632,7 +691,7 @@ static const int TWOCOLOR_PREV_R2 = -3, TWOCOLOR_PREV_G2 = -2, TWOCOLOR_PREV_B2
static const int TWOCOLOR_R = 1, TWOCOLOR_G = 2, TWOCOLOR_B = 3, TWOCOLOR_A = 4, TWOCOLOR_R2 = 5, TWOCOLOR_G2 = 6, TWOCOLOR_B2 = 7; static const int TWOCOLOR_R = 1, TWOCOLOR_G = 2, TWOCOLOR_B = 3, TWOCOLOR_A = 4, TWOCOLOR_R2 = 5, TWOCOLOR_G2 = 6, TWOCOLOR_B2 = 7;
void _spTwoColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, void _spTwoColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
spSlot *slot; spSlot *slot;
int frame; int frame;
float percent, frameTime; float percent, frameTime;
@ -645,12 +704,12 @@ void _spTwoColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton
slot = skeleton->slots[self->slotIndex]; slot = skeleton->slots[self->slotIndex];
if (time < self->frames[0]) { if (time < self->frames[0]) {
switch (pose) { switch (blend) {
case SP_MIX_POSE_SETUP: case SP_MIX_BLEND_SETUP:
spColor_setFromColor(&slot->color, &slot->data->color); spColor_setFromColor(&slot->color, &slot->data->color);
spColor_setFromColor(slot->darkColor, slot->data->darkColor); spColor_setFromColor(slot->darkColor, slot->data->darkColor);
return; return;
case SP_MIX_POSE_CURRENT: case SP_MIX_BLEND_FIRST:
light = &slot->color; light = &slot->color;
dark = slot->darkColor; dark = slot->darkColor;
setupLight = &slot->data->color; setupLight = &slot->data->color;
@ -658,7 +717,9 @@ void _spTwoColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton
spColor_addFloats(light, (setupLight->r - light->r) * alpha, (setupLight->g - light->g) * alpha, (setupLight->b - light->b) * alpha, spColor_addFloats(light, (setupLight->r - light->r) * alpha, (setupLight->g - light->g) * alpha, (setupLight->b - light->b) * alpha,
(setupLight->a - light->a) * alpha); (setupLight->a - light->a) * alpha);
spColor_addFloats(dark, (setupDark->r - dark->r) * alpha, (setupDark->g - dark->g) * alpha, (setupDark->b - dark->b) * alpha, 0); spColor_addFloats(dark, (setupDark->r - dark->r) * alpha, (setupDark->g - dark->g) * alpha, (setupDark->b - dark->b) * alpha, 0);
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */ case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
; /* to appease compiler */
} }
return; return;
} }
@ -702,7 +763,7 @@ void _spTwoColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton
} else { } else {
light = &slot->color; light = &slot->color;
dark = slot->darkColor; dark = slot->darkColor;
if (pose == SP_MIX_POSE_SETUP) { if (blend == SP_MIX_BLEND_SETUP) {
spColor_setFromColor(light, &slot->data->color); spColor_setFromColor(light, &slot->data->color);
spColor_setFromColor(dark, slot->data->darkColor); spColor_setFromColor(dark, slot->data->darkColor);
} }
@ -738,20 +799,20 @@ void spTwoColorTimeline_setFrame (spTwoColorTimeline* self, int frameIndex, floa
/**/ /**/
void _spAttachmentTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, void _spAttachmentTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
spEvent** firedEvents, int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
const char* attachmentName; const char* attachmentName;
spAttachmentTimeline* self = (spAttachmentTimeline*)timeline; spAttachmentTimeline* self = (spAttachmentTimeline*)timeline;
int frameIndex; int frameIndex;
spSlot* slot = skeleton->slots[self->slotIndex]; spSlot* slot = skeleton->slots[self->slotIndex];
if (direction == SP_MIX_DIRECTION_OUT && pose == SP_MIX_POSE_SETUP) { if (direction == SP_MIX_DIRECTION_OUT && blend == SP_MIX_BLEND_SETUP) {
const char* attachmentName = slot->data->attachmentName; const char* attachmentName = slot->data->attachmentName;
spSlot_setAttachment(slot, attachmentName ? spSkeleton_getAttachmentForSlotIndex(skeleton, self->slotIndex, attachmentName) : 0); spSlot_setAttachment(slot, attachmentName ? spSkeleton_getAttachmentForSlotIndex(skeleton, self->slotIndex, attachmentName) : 0);
return; return;
} }
if (time < self->frames[0]) { if (time < self->frames[0]) {
if (pose == SP_MIX_POSE_SETUP) { if (blend == SP_MIX_BLEND_SETUP || blend == SP_MIX_BLEND_FIRST) {
attachmentName = slot->data->attachmentName; attachmentName = slot->data->attachmentName;
spSlot_setAttachment(skeleton->slots[self->slotIndex], spSlot_setAttachment(skeleton->slots[self->slotIndex],
attachmentName ? spSkeleton_getAttachmentForSlotIndex(skeleton, self->slotIndex, attachmentName) : 0); attachmentName ? spSkeleton_getAttachmentForSlotIndex(skeleton, self->slotIndex, attachmentName) : 0);
@ -815,7 +876,7 @@ void spAttachmentTimeline_setFrame (spAttachmentTimeline* self, int frameIndex,
/**/ /**/
void _spDeformTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, void _spDeformTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
int frame, i, vertexCount; int frame, i, vertexCount;
float percent, frameTime; float percent, frameTime;
const float* prevVertices; const float* prevVertices;
@ -851,18 +912,18 @@ void _spDeformTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
slot->attachmentVerticesCapacity = vertexCount; slot->attachmentVerticesCapacity = vertexCount;
} }
} }
if (slot->attachmentVerticesCount == 0) alpha = 1; if (slot->attachmentVerticesCount == 0) blend = SP_MIX_BLEND_SETUP;
frameVertices = self->frameVertices; frameVertices = self->frameVertices;
vertices = slot->attachmentVertices; vertices = slot->attachmentVertices;
if (time < frames[0]) { /* Time is before first frame. */ if (time < frames[0]) { /* Time is before first frame. */
spVertexAttachment* vertexAttachment = SUB_CAST(spVertexAttachment, slot->attachment); spVertexAttachment* vertexAttachment = SUB_CAST(spVertexAttachment, slot->attachment);
switch (pose) { switch (blend) {
case SP_MIX_POSE_SETUP: case SP_MIX_BLEND_SETUP:
slot->attachmentVerticesCount = 0; slot->attachmentVerticesCount = 0;
return; return;
case SP_MIX_POSE_CURRENT: case SP_MIX_BLEND_FIRST:
if (alpha == 1) { if (alpha == 1) {
slot->attachmentVerticesCount = 0; slot->attachmentVerticesCount = 0;
return; return;
@ -879,7 +940,9 @@ void _spDeformTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
vertices[i] *= alpha; vertices[i] *= alpha;
} }
} }
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */ case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
; /* to appease compiler */
} }
return; return;
} }
@ -888,26 +951,59 @@ void _spDeformTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
if (time >= frames[framesCount - 1]) { /* Time is after last frame. */ if (time >= frames[framesCount - 1]) { /* Time is after last frame. */
const float* lastVertices = self->frameVertices[framesCount - 1]; const float* lastVertices = self->frameVertices[framesCount - 1];
if (alpha == 1) { if (alpha == 1) {
/* Vertex positions or deform offsets, no alpha. */ if (blend == SP_MIX_BLEND_ADD) {
memcpy(vertices, lastVertices, vertexCount * sizeof(float)); spVertexAttachment* vertexAttachment = SUB_CAST(spVertexAttachment, slot->attachment);
} else if (pose == SP_MIX_POSE_SETUP) { if (!vertexAttachment->bones) {
spVertexAttachment* vertexAttachment = SUB_CAST(spVertexAttachment, slot->attachment); /* Unweighted vertex positions, with alpha. */
if (!vertexAttachment->bones) { float* setupVertices = vertexAttachment->vertices;
/* Unweighted vertex positions, with alpha. */ for (i = 0; i < vertexCount; i++) {
float* setupVertices = vertexAttachment->vertices; vertices[i] += lastVertices[i] - setupVertices[i];
for (i = 0; i < vertexCount; i++) { }
float setup = setupVertices[i]; } else {
vertices[i] = setup + (lastVertices[i] - setup) * alpha; /* Weighted deform offsets, with alpha. */
for (i = 0; i < vertexCount; i++)
vertices[i] += lastVertices[i];
} }
} else { } else {
/* Weighted deform offsets, with alpha. */ /* Vertex positions or deform offsets, no alpha. */
for (i = 0; i < vertexCount; i++) memcpy(vertices, lastVertices, vertexCount * sizeof(float));
vertices[i] = lastVertices[i] * alpha;
} }
} else { } else {
/* Vertex positions or deform offsets, with alpha. */ spVertexAttachment* vertexAttachment;
for (i = 0; i < vertexCount; i++) switch (blend) {
vertices[i] += (lastVertices[i] - vertices[i]) * alpha; case SP_MIX_BLEND_SETUP:
vertexAttachment = SUB_CAST(spVertexAttachment, slot->attachment);
if (!vertexAttachment->bones) {
/* Unweighted vertex positions, with alpha. */
float* setupVertices = vertexAttachment->vertices;
for (i = 0; i < vertexCount; i++) {
float setup = setupVertices[i];
vertices[i] = setup + (lastVertices[i] - setup) * alpha;
}
} else {
/* Weighted deform offsets, with alpha. */
for (i = 0; i < vertexCount; i++)
vertices[i] = lastVertices[i] * alpha;
}
break;
case SP_MIX_BLEND_FIRST:
case SP_MIX_BLEND_REPLACE:
/* Vertex positions or deform offsets, with alpha. */
for (i = 0; i < vertexCount; i++)
vertices[i] += (lastVertices[i] - vertices[i]) * alpha;
case SP_MIX_BLEND_ADD:
vertexAttachment = SUB_CAST(spVertexAttachment, slot->attachment);
if (!vertexAttachment->bones) {
/* Unweighted vertex positions, with alpha. */
float* setupVertices = vertexAttachment->vertices;
for (i = 0; i < vertexCount; i++) {
vertices[i] += (lastVertices[i] - setupVertices[i]) * alpha;
}
} else {
for (i = 0; i < vertexCount; i++)
vertices[i] += lastVertices[i] * alpha;
}
}
} }
return; return;
} }
@ -920,32 +1016,65 @@ void _spDeformTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
percent = spCurveTimeline_getCurvePercent(SUPER(self), frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime)); percent = spCurveTimeline_getCurvePercent(SUPER(self), frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime));
if (alpha == 1) { if (alpha == 1) {
/* Vertex positions or deform offsets, no alpha. */ if (blend == SP_MIX_BLEND_ADD) {
for (i = 0; i < vertexCount; i++) { spVertexAttachment* vertexAttachment = SUB_CAST(spVertexAttachment, slot->attachment);
float prev = prevVertices[i]; if (!vertexAttachment->bones) {
vertices[i] = prev + (nextVertices[i] - prev) * percent; float* setupVertices = vertexAttachment->vertices;
} for (i = 0; i < vertexCount; i++) {
} else if (pose == SP_MIX_POSE_SETUP) { float prev = prevVertices[i];
spVertexAttachment* vertexAttachment = SUB_CAST(spVertexAttachment, slot->attachment); vertices[i] += prev + (nextVertices[i] - prev) * percent - setupVertices[i];
if (!vertexAttachment->bones) { }
/* Unweighted vertex positions, with alpha. */ } else {
float* setupVertices = vertexAttachment->vertices; for (i = 0; i < vertexCount; i++) {
for (i = 0; i < vertexCount; i++) { float prev = prevVertices[i];
float prev = prevVertices[i], setup = setupVertices[i]; vertices[i] += prev + (nextVertices[i] - prev) * percent;
vertices[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha; }
} }
} else { } else {
/* Weighted deform offsets, with alpha. */
for (i = 0; i < vertexCount; i++) { for (i = 0; i < vertexCount; i++) {
float prev = prevVertices[i]; float prev = prevVertices[i];
vertices[i] = (prev + (nextVertices[i] - prev) * percent) * alpha; vertices[i] = prev + (nextVertices[i] - prev) * percent;
} }
} }
} else { } else {
/* Vertex positions or deform offsets, with alpha. */ spVertexAttachment* vertexAttachment;
for (i = 0; i < vertexCount; i++) { switch (blend) {
float prev = prevVertices[i]; case SP_MIX_BLEND_SETUP:
vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha; vertexAttachment = SUB_CAST(spVertexAttachment, slot->attachment);
if (!vertexAttachment->bones) {
float *setupVertices = vertexAttachment->vertices;
for (i = 0; i < vertexCount; i++) {
float prev = prevVertices[i], setup = setupVertices[i];
vertices[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha;
}
} else {
for (i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
vertices[i] = (prev + (nextVertices[i] - prev) * percent) * alpha;
}
}
break;
case SP_MIX_BLEND_FIRST:
case SP_MIX_BLEND_REPLACE:
for (i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha;
}
break;
case SP_MIX_BLEND_ADD:
vertexAttachment = SUB_CAST(spVertexAttachment, slot->attachment);
if (!vertexAttachment->bones) {
float *setupVertices = vertexAttachment->vertices;
for (i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
vertices[i] += (prev + (nextVertices[i] - prev) * percent - setupVertices[i]) * alpha;
}
} else {
for (i = 0; i < vertexCount; i++) {
float prev = prevVertices[i];
vertices[i] += (prev + (nextVertices[i] - prev) * percent) * alpha;
}
}
} }
} }
@ -998,13 +1127,13 @@ void spDeformTimeline_setFrame (spDeformTimeline* self, int frameIndex, float ti
/** Fires events for frames > lastTime and <= time. */ /** Fires events for frames > lastTime and <= time. */
void _spEventTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, void _spEventTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
spEventTimeline* self = (spEventTimeline*)timeline; spEventTimeline* self = (spEventTimeline*)timeline;
int frame; int frame;
if (!firedEvents) return; if (!firedEvents) return;
if (lastTime > time) { /* Fire events after last time for looped animations. */ if (lastTime > time) { /* Fire events after last time for looped animations. */
_spEventTimeline_apply(timeline, skeleton, lastTime, (float)INT_MAX, firedEvents, eventsCount, alpha, pose, direction); _spEventTimeline_apply(timeline, skeleton, lastTime, (float)INT_MAX, firedEvents, eventsCount, alpha, blend, direction);
lastTime = -1; lastTime = -1;
} else if (lastTime >= self->frames[self->framesCount - 1]) /* Last time is after last frame. */ } else if (lastTime >= self->frames[self->framesCount - 1]) /* Last time is after last frame. */
return; return;
@ -1065,19 +1194,19 @@ void spEventTimeline_setFrame (spEventTimeline* self, int frameIndex, spEvent* e
/**/ /**/
void _spDrawOrderTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, void _spDrawOrderTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
spEvent** firedEvents, int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
int i; int i;
int frame; int frame;
const int* drawOrderToSetupIndex; const int* drawOrderToSetupIndex;
spDrawOrderTimeline* self = (spDrawOrderTimeline*)timeline; spDrawOrderTimeline* self = (spDrawOrderTimeline*)timeline;
if (direction == SP_MIX_DIRECTION_OUT && pose == SP_MIX_POSE_SETUP) { if (direction == SP_MIX_DIRECTION_OUT && blend == SP_MIX_BLEND_SETUP) {
memcpy(skeleton->drawOrder, skeleton->slots, self->slotsCount * sizeof(spSlot*)); memcpy(skeleton->drawOrder, skeleton->slots, self->slotsCount * sizeof(spSlot*));
return; return;
} }
if (time < self->frames[0]) { if (time < self->frames[0]) {
if (pose == SP_MIX_POSE_SETUP) memcpy(skeleton->drawOrder, skeleton->slots, self->slotsCount * sizeof(spSlot*)); if (blend == SP_MIX_BLEND_SETUP || blend == SP_MIX_BLEND_FIRST) memcpy(skeleton->drawOrder, skeleton->slots, self->slotsCount * sizeof(spSlot*));
return; return;
} }
@ -1147,7 +1276,7 @@ static const int IKCONSTRAINT_PREV_TIME = -3, IKCONSTRAINT_PREV_MIX = -2, IKCONS
static const int IKCONSTRAINT_MIX = 1, IKCONSTRAINT_BEND_DIRECTION = 2; static const int IKCONSTRAINT_MIX = 1, IKCONSTRAINT_BEND_DIRECTION = 2;
void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
spEvent** firedEvents, int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
int frame; int frame;
float frameTime, percent, mix; float frameTime, percent, mix;
float *frames; float *frames;
@ -1158,15 +1287,17 @@ void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skel
constraint = skeleton->ikConstraints[self->ikConstraintIndex]; constraint = skeleton->ikConstraints[self->ikConstraintIndex];
if (time < self->frames[0]) { if (time < self->frames[0]) {
switch (pose) { switch (blend) {
case SP_MIX_POSE_SETUP: case SP_MIX_BLEND_SETUP:
constraint->mix = constraint->data->mix; constraint->mix = constraint->data->mix;
constraint->bendDirection = constraint->data->bendDirection; constraint->bendDirection = constraint->data->bendDirection;
return; return;
case SP_MIX_POSE_CURRENT: case SP_MIX_BLEND_FIRST:
constraint->mix += (constraint->data->mix - constraint->mix) * alpha; constraint->mix += (constraint->data->mix - constraint->mix) * alpha;
constraint->bendDirection = constraint->data->bendDirection; constraint->bendDirection = constraint->data->bendDirection;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */ case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
; /* to appease compiler */
} }
return; return;
} }
@ -1174,7 +1305,7 @@ void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skel
frames = self->frames; frames = self->frames;
framesCount = self->framesCount; framesCount = self->framesCount;
if (time >= frames[framesCount - IKCONSTRAINT_ENTRIES]) { /* Time is after last frame. */ if (time >= frames[framesCount - IKCONSTRAINT_ENTRIES]) { /* Time is after last frame. */
if (pose == SP_MIX_POSE_SETUP) { if (blend == SP_MIX_BLEND_SETUP) {
constraint->mix = constraint->data->mix + (frames[framesCount + IKCONSTRAINT_PREV_MIX] - constraint->data->mix) * alpha; constraint->mix = constraint->data->mix + (frames[framesCount + IKCONSTRAINT_PREV_MIX] - constraint->data->mix) * alpha;
constraint->bendDirection = direction == SP_MIX_DIRECTION_OUT ? constraint->data->bendDirection constraint->bendDirection = direction == SP_MIX_DIRECTION_OUT ? constraint->data->bendDirection
: (int)frames[framesCount + IKCONSTRAINT_PREV_BEND_DIRECTION]; : (int)frames[framesCount + IKCONSTRAINT_PREV_BEND_DIRECTION];
@ -1191,7 +1322,7 @@ void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skel
frameTime = self->frames[frame]; frameTime = self->frames[frame];
percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / IKCONSTRAINT_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + IKCONSTRAINT_PREV_TIME] - frameTime)); percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / IKCONSTRAINT_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + IKCONSTRAINT_PREV_TIME] - frameTime));
if (pose == SP_MIX_POSE_SETUP) { if (blend == SP_MIX_BLEND_SETUP) {
constraint->mix = constraint->data->mix + (mix + (frames[frame + IKCONSTRAINT_MIX] - mix) * percent - constraint->data->mix) * alpha; constraint->mix = constraint->data->mix + (mix + (frames[frame + IKCONSTRAINT_MIX] - mix) * percent - constraint->data->mix) * alpha;
constraint->bendDirection = direction == SP_MIX_DIRECTION_OUT ? constraint->data->bendDirection : (int)frames[frame + IKCONSTRAINT_PREV_BEND_DIRECTION]; constraint->bendDirection = direction == SP_MIX_DIRECTION_OUT ? constraint->data->bendDirection : (int)frames[frame + IKCONSTRAINT_PREV_BEND_DIRECTION];
} else { } else {
@ -1231,7 +1362,7 @@ static const int TRANSFORMCONSTRAINT_SCALE = 3;
static const int TRANSFORMCONSTRAINT_SHEAR = 4; static const int TRANSFORMCONSTRAINT_SHEAR = 4;
void _spTransformConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, void _spTransformConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
spEvent** firedEvents, int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
int frame; int frame;
float frameTime, percent, rotate, translate, scale, shear; float frameTime, percent, rotate, translate, scale, shear;
spTransformConstraint* constraint; spTransformConstraint* constraint;
@ -1242,19 +1373,21 @@ void _spTransformConstraintTimeline_apply (const spTimeline* timeline, spSkeleto
constraint = skeleton->transformConstraints[self->transformConstraintIndex]; constraint = skeleton->transformConstraints[self->transformConstraintIndex];
if (time < self->frames[0]) { if (time < self->frames[0]) {
spTransformConstraintData* data = constraint->data; spTransformConstraintData* data = constraint->data;
switch (pose) { switch (blend) {
case SP_MIX_POSE_SETUP: case SP_MIX_BLEND_SETUP:
constraint->rotateMix = data->rotateMix; constraint->rotateMix = data->rotateMix;
constraint->translateMix = data->translateMix; constraint->translateMix = data->translateMix;
constraint->scaleMix = data->scaleMix; constraint->scaleMix = data->scaleMix;
constraint->shearMix = data->shearMix; constraint->shearMix = data->shearMix;
return; return;
case SP_MIX_POSE_CURRENT: case SP_MIX_BLEND_FIRST:
constraint->rotateMix += (data->rotateMix - constraint->rotateMix) * alpha; constraint->rotateMix += (data->rotateMix - constraint->rotateMix) * alpha;
constraint->translateMix += (data->translateMix - constraint->translateMix) * alpha; constraint->translateMix += (data->translateMix - constraint->translateMix) * alpha;
constraint->scaleMix += (data->scaleMix - constraint->scaleMix) * alpha; constraint->scaleMix += (data->scaleMix - constraint->scaleMix) * alpha;
constraint->shearMix += (data->shearMix - constraint->shearMix) * alpha; constraint->shearMix += (data->shearMix - constraint->shearMix) * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */ case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
; /* to appease compiler */
} }
return; return;
return; return;
@ -1284,7 +1417,7 @@ void _spTransformConstraintTimeline_apply (const spTimeline* timeline, spSkeleto
scale += (frames[frame + TRANSFORMCONSTRAINT_SCALE] - scale) * percent; scale += (frames[frame + TRANSFORMCONSTRAINT_SCALE] - scale) * percent;
shear += (frames[frame + TRANSFORMCONSTRAINT_SHEAR] - shear) * percent; shear += (frames[frame + TRANSFORMCONSTRAINT_SHEAR] - shear) * percent;
} }
if (pose == SP_MIX_POSE_SETUP) { if (blend == SP_MIX_BLEND_SETUP) {
spTransformConstraintData* data = constraint->data; spTransformConstraintData* data = constraint->data;
constraint->rotateMix = data->rotateMix + (rotate - data->rotateMix) * alpha; constraint->rotateMix = data->rotateMix + (rotate - data->rotateMix) * alpha;
constraint->translateMix = data->translateMix + (translate - data->translateMix) * alpha; constraint->translateMix = data->translateMix + (translate - data->translateMix) * alpha;
@ -1326,7 +1459,7 @@ static const int PATHCONSTRAINTPOSITION_PREV_VALUE = -1;
static const int PATHCONSTRAINTPOSITION_VALUE = 1; static const int PATHCONSTRAINTPOSITION_VALUE = 1;
void _spPathConstraintPositionTimeline_apply(const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, void _spPathConstraintPositionTimeline_apply(const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
spEvent** firedEvents, int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
int frame; int frame;
float frameTime, percent, position; float frameTime, percent, position;
spPathConstraint* constraint; spPathConstraint* constraint;
@ -1336,13 +1469,15 @@ void _spPathConstraintPositionTimeline_apply(const spTimeline* timeline, spSkele
constraint = skeleton->pathConstraints[self->pathConstraintIndex]; constraint = skeleton->pathConstraints[self->pathConstraintIndex];
if (time < self->frames[0]) { if (time < self->frames[0]) {
switch (pose) { switch (blend) {
case SP_MIX_POSE_SETUP: case SP_MIX_BLEND_SETUP:
constraint->position = constraint->data->position; constraint->position = constraint->data->position;
return; return;
case SP_MIX_POSE_CURRENT: case SP_MIX_BLEND_FIRST:
constraint->position += (constraint->data->position - constraint->position) * alpha; constraint->position += (constraint->data->position - constraint->position) * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */ case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
; /* to appease compiler */
} }
return; return;
} }
@ -1361,7 +1496,7 @@ void _spPathConstraintPositionTimeline_apply(const spTimeline* timeline, spSkele
position += (frames[frame + PATHCONSTRAINTPOSITION_VALUE] - position) * percent; position += (frames[frame + PATHCONSTRAINTPOSITION_VALUE] - position) * percent;
} }
if (pose == SP_MIX_POSE_SETUP) if (blend == SP_MIX_BLEND_SETUP)
constraint->position = constraint->data->position + (position - constraint->data->position) * alpha; constraint->position = constraint->data->position + (position - constraint->data->position) * alpha;
else else
constraint->position += (position - constraint->position) * alpha; constraint->position += (position - constraint->position) * alpha;
@ -1391,7 +1526,7 @@ static const int PATHCONSTRAINTSPACING_PREV_VALUE = -1;
static const int PATHCONSTRAINTSPACING_VALUE = 1; static const int PATHCONSTRAINTSPACING_VALUE = 1;
void _spPathConstraintSpacingTimeline_apply(const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, void _spPathConstraintSpacingTimeline_apply(const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
spEvent** firedEvents, int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
int frame; int frame;
float frameTime, percent, spacing; float frameTime, percent, spacing;
spPathConstraint* constraint; spPathConstraint* constraint;
@ -1401,13 +1536,15 @@ void _spPathConstraintSpacingTimeline_apply(const spTimeline* timeline, spSkelet
constraint = skeleton->pathConstraints[self->pathConstraintIndex]; constraint = skeleton->pathConstraints[self->pathConstraintIndex];
if (time < self->frames[0]) { if (time < self->frames[0]) {
switch (pose) { switch (blend) {
case SP_MIX_POSE_SETUP: case SP_MIX_BLEND_SETUP:
constraint->spacing = constraint->data->spacing; constraint->spacing = constraint->data->spacing;
return; return;
case SP_MIX_POSE_CURRENT: case SP_MIX_BLEND_FIRST:
constraint->spacing += (constraint->data->spacing - constraint->spacing) * alpha; constraint->spacing += (constraint->data->spacing - constraint->spacing) * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */ case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
; /* to appease compiler */
} }
return; return;
} }
@ -1427,7 +1564,7 @@ void _spPathConstraintSpacingTimeline_apply(const spTimeline* timeline, spSkelet
spacing += (frames[frame + PATHCONSTRAINTSPACING_VALUE] - spacing) * percent; spacing += (frames[frame + PATHCONSTRAINTSPACING_VALUE] - spacing) * percent;
} }
if (pose == SP_MIX_POSE_SETUP) if (blend == SP_MIX_BLEND_SETUP)
constraint->spacing = constraint->data->spacing + (spacing - constraint->data->spacing) * alpha; constraint->spacing = constraint->data->spacing + (spacing - constraint->data->spacing) * alpha;
else else
constraint->spacing += (spacing - constraint->spacing) * alpha; constraint->spacing += (spacing - constraint->spacing) * alpha;
@ -1460,7 +1597,7 @@ static const int PATHCONSTRAINTMIX_ROTATE = 1;
static const int PATHCONSTRAINTMIX_TRANSLATE = 2; static const int PATHCONSTRAINTMIX_TRANSLATE = 2;
void _spPathConstraintMixTimeline_apply(const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, void _spPathConstraintMixTimeline_apply(const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
spEvent** firedEvents, int* eventsCount, float alpha, spMixPose pose, spMixDirection direction) { spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
int frame; int frame;
float frameTime, percent, rotate, translate; float frameTime, percent, rotate, translate;
spPathConstraint* constraint; spPathConstraint* constraint;
@ -1470,15 +1607,17 @@ void _spPathConstraintMixTimeline_apply(const spTimeline* timeline, spSkeleton*
constraint = skeleton->pathConstraints[self->pathConstraintIndex]; constraint = skeleton->pathConstraints[self->pathConstraintIndex];
if (time < self->frames[0]) { if (time < self->frames[0]) {
switch (pose) { switch (blend) {
case SP_MIX_POSE_SETUP: case SP_MIX_BLEND_SETUP:
constraint->rotateMix = constraint->data->rotateMix; constraint->rotateMix = constraint->data->rotateMix;
constraint->translateMix = constraint->data->translateMix; constraint->translateMix = constraint->data->translateMix;
return; return;
case SP_MIX_POSE_CURRENT: case SP_MIX_BLEND_FIRST:
constraint->rotateMix += (constraint->data->rotateMix - constraint->rotateMix) * alpha; constraint->rotateMix += (constraint->data->rotateMix - constraint->rotateMix) * alpha;
constraint->translateMix += (constraint->data->translateMix - constraint->translateMix) * alpha; constraint->translateMix += (constraint->data->translateMix - constraint->translateMix) * alpha;
case SP_MIX_POSE_CURRENT_LAYERED:; /* to appease compiler */ case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
; /* to appease compiler */
} }
return; return;
} }
@ -1501,7 +1640,7 @@ void _spPathConstraintMixTimeline_apply(const spTimeline* timeline, spSkeleton*
translate += (frames[frame + PATHCONSTRAINTMIX_TRANSLATE] - translate) * percent; translate += (frames[frame + PATHCONSTRAINTMIX_TRANSLATE] - translate) * percent;
} }
if (pose == SP_MIX_POSE_SETUP) { if (blend == SP_MIX_BLEND_SETUP) {
constraint->rotateMix = constraint->data->rotateMix + (rotate - constraint->data->rotateMix) * alpha; constraint->rotateMix = constraint->data->rotateMix + (rotate - constraint->data->rotateMix) * alpha;
constraint->translateMix = constraint->data->translateMix + (translate - constraint->data->translateMix) * alpha; constraint->translateMix = constraint->data->translateMix + (translate - constraint->data->translateMix) * alpha;
} else { } else {

View File

@ -50,8 +50,8 @@ void spAnimationState_disposeStatics () {
void _spAnimationState_disposeTrackEntry (spTrackEntry* entry); void _spAnimationState_disposeTrackEntry (spTrackEntry* entry);
void _spAnimationState_disposeTrackEntries (spAnimationState* state, spTrackEntry* entry); void _spAnimationState_disposeTrackEntries (spAnimationState* state, spTrackEntry* entry);
int /*boolean*/ _spAnimationState_updateMixingFrom (spAnimationState* self, spTrackEntry* entry, float delta); int /*boolean*/ _spAnimationState_updateMixingFrom (spAnimationState* self, spTrackEntry* entry, float delta);
float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* entry, spSkeleton* skeleton, spMixPose currentPose); float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* entry, spSkeleton* skeleton, spMixBlend currentBlend);
void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline* timeline, spSkeleton* skeleton, float time, float alpha, spMixPose pose, float* timelinesRotation, int i, int /*boolean*/ firstFrame); void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline* timeline, spSkeleton* skeleton, float time, float alpha, spMixBlend blend, float* timelinesRotation, int i, int /*boolean*/ firstFrame);
void _spAnimationState_queueEvents (spAnimationState* self, spTrackEntry* entry, float animationTime); void _spAnimationState_queueEvents (spAnimationState* self, spTrackEntry* entry, float animationTime);
void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEntry* current, int /*boolean*/ interrupt); void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEntry* current, int /*boolean*/ interrupt);
spTrackEntry* _spAnimationState_expandToIndex (spAnimationState* self, int index); spTrackEntry* _spAnimationState_expandToIndex (spAnimationState* self, int index);
@ -354,8 +354,8 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
float* timelinesRotation; float* timelinesRotation;
spTimeline* timeline; spTimeline* timeline;
int applied = 0; int applied = 0;
spMixPose currentPose; spMixBlend blend;
spMixPose pose; spMixBlend timelineBlend;
if (internal->animationsChanged) _spAnimationState_animationsChanged(self); if (internal->animationsChanged) _spAnimationState_animationsChanged(self);
@ -364,12 +364,12 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
current = self->tracks[i]; current = self->tracks[i];
if (!current || current->delay > 0) continue; if (!current || current->delay > 0) continue;
applied = -1; applied = -1;
currentPose = i == 0 ? SP_MIX_POSE_CURRENT : SP_MIX_POSE_CURRENT_LAYERED; blend = i == 0 ? SP_MIX_BLEND_FIRST : current->mixBlend;
/* Apply mixing from entries first. */ /* Apply mixing from entries first. */
mix = current->alpha; mix = current->alpha;
if (current->mixingFrom) if (current->mixingFrom)
mix *= _spAnimationState_applyMixingFrom(self, current, skeleton, currentPose); mix *= _spAnimationState_applyMixingFrom(self, current, skeleton, blend);
else if (current->trackTime >= current->trackEnd && current->next == 0) else if (current->trackTime >= current->trackEnd && current->next == 0)
mix = 0; mix = 0;
@ -377,9 +377,9 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
animationLast = current->animationLast; animationTime = spTrackEntry_getAnimationTime(current); animationLast = current->animationLast; animationTime = spTrackEntry_getAnimationTime(current);
timelineCount = current->animation->timelinesCount; timelineCount = current->animation->timelinesCount;
timelines = current->animation->timelines; timelines = current->animation->timelines;
if (mix == 1) { if (mix == 1 || blend == SP_MIX_BLEND_ADD) {
for (ii = 0; ii < timelineCount; ii++) for (ii = 0; ii < timelineCount; ii++)
spTimeline_apply(timelines[ii], skeleton, animationLast, animationTime, internal->events, &internal->eventsCount, 1, SP_MIX_POSE_SETUP, SP_MIX_DIRECTION_IN); spTimeline_apply(timelines[ii], skeleton, animationLast, animationTime, internal->events, &internal->eventsCount, mix, blend, SP_MIX_DIRECTION_IN);
} else { } else {
spIntArray* timelineData = current->timelineData; spIntArray* timelineData = current->timelineData;
@ -389,11 +389,11 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
for (ii = 0; ii < timelineCount; ii++) { for (ii = 0; ii < timelineCount; ii++) {
timeline = timelines[ii]; timeline = timelines[ii];
pose = timelineData->items[ii] >= FIRST ? SP_MIX_POSE_SETUP : currentPose; timelineBlend = timelineData->items[ii] == SUBSEQUENT ? blend : SP_MIX_BLEND_SETUP;
if (timeline->type == SP_TIMELINE_ROTATE) if (timeline->type == SP_TIMELINE_ROTATE)
_spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, mix, pose, timelinesRotation, ii << 1, firstFrame); _spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
else else
spTimeline_apply(timeline, skeleton, animationLast, animationTime, internal->events, &internal->eventsCount, mix, pose, SP_MIX_DIRECTION_IN); spTimeline_apply(timeline, skeleton, animationLast, animationTime, internal->events, &internal->eventsCount, mix, timelineBlend, SP_MIX_DIRECTION_IN);
} }
} }
_spAnimationState_queueEvents(self, current, animationTime); _spAnimationState_queueEvents(self, current, animationTime);
@ -406,7 +406,7 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
return applied; return applied;
} }
float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* to, spSkeleton* skeleton, spMixPose currentPose) { float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* to, spSkeleton* skeleton, spMixBlend blend) {
_spAnimationState* internal = SUB_CAST(_spAnimationState, self); _spAnimationState* internal = SUB_CAST(_spAnimationState, self);
float mix; float mix;
spEvent** events; spEvent** events;
@ -418,24 +418,25 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* t
spTimeline** timelines; spTimeline** timelines;
spIntArray* timelineData; spIntArray* timelineData;
spTrackEntryArray* timelineDipMix; spTrackEntryArray* timelineDipMix;
spMixBlend timelineBlend;
float alphaDip; float alphaDip;
float alphaMix; float alphaMix;
float alpha; float alpha;
int /*boolean*/ firstFrame; int /*boolean*/ firstFrame;
float* timelinesRotation; float* timelinesRotation;
spMixPose pose;
int i; int i;
spTrackEntry* dipMix; spTrackEntry* dipMix;
spTrackEntry* from = to->mixingFrom; spTrackEntry* from = to->mixingFrom;
if (from->mixingFrom) _spAnimationState_applyMixingFrom(self, from, skeleton, currentPose); if (from->mixingFrom) _spAnimationState_applyMixingFrom(self, from, skeleton, blend);
if (to->mixDuration == 0) { /* Single frame mix to undo mixingFrom changes. */ if (to->mixDuration == 0) { /* Single frame mix to undo mixingFrom changes. */
mix = 1; mix = 1;
currentPose = SP_MIX_POSE_SETUP; if (blend == SP_MIX_BLEND_FIRST) blend = SP_MIX_BLEND_SETUP;
} else { } else {
mix = to->mixTime / to->mixDuration; mix = to->mixTime / to->mixDuration;
if (mix > 1) mix = 1; if (mix > 1) mix = 1;
if (blend != SP_MIX_BLEND_FIRST) blend = from->mixBlend;
} }
events = mix < from->eventThreshold ? internal->events : 0; events = mix < from->eventThreshold ? internal->events : 0;
@ -445,44 +446,52 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* t
animationTime = spTrackEntry_getAnimationTime(from); animationTime = spTrackEntry_getAnimationTime(from);
timelineCount = from->animation->timelinesCount; timelineCount = from->animation->timelinesCount;
timelines = from->animation->timelines; timelines = from->animation->timelines;
timelineData = from->timelineData;
timelineDipMix = from->timelineDipMix;
firstFrame = from->timelinesRotationCount == 0;
if (firstFrame) _spAnimationState_resizeTimelinesRotation(from, timelineCount << 1);
timelinesRotation = from->timelinesRotation;
alphaDip = from->alpha * to->interruptAlpha; alphaMix = alphaDip * (1 - mix); alphaDip = from->alpha * to->interruptAlpha; alphaMix = alphaDip * (1 - mix);
from->totalAlpha = 0; if (blend == SP_MIX_BLEND_ADD) {
for (i = 0; i < timelineCount; i++) { for (i = 0; i < timelineCount; i++) {
spTimeline* timeline = timelines[i]; spTimeline *timeline = timelines[i];
switch (timelineData->items[i]) { spTimeline_apply(timeline, skeleton, animationLast, animationTime, events, &internal->eventsCount, alphaMix, blend, SP_MIX_DIRECTION_OUT);
case SUBSEQUENT:
if (!attachments && timeline->type == SP_TIMELINE_ATTACHMENT) continue;
if (!drawOrder && timeline->type == SP_TIMELINE_DRAWORDER) continue;
pose = currentPose;
alpha = alphaMix;
break;
case FIRST:
pose = SP_MIX_POSE_SETUP;
alpha = alphaMix;
break;
case DIP:
pose = SP_MIX_POSE_SETUP;
alpha = alphaDip;
break;
default:
pose = SP_MIX_POSE_SETUP;
alpha = alphaDip;
dipMix = timelineDipMix->items[i];
alpha *= MAX(0, 1 - dipMix->mixTime / dipMix->mixDuration);
break;
} }
from->totalAlpha += alpha; } else {
if (timeline->type == SP_TIMELINE_ROTATE) timelineData = from->timelineData;
_spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, alpha, pose, timelinesRotation, i << 1, firstFrame); timelineDipMix = from->timelineDipMix;
else {
spTimeline_apply(timeline, skeleton, animationLast, animationTime, events, &internal->eventsCount, alpha, pose, SP_MIX_DIRECTION_OUT); firstFrame = from->timelinesRotationCount == 0;
if (firstFrame) _spAnimationState_resizeTimelinesRotation(from, timelineCount << 1);
timelinesRotation = from->timelinesRotation;
from->totalAlpha = 0;
for (i = 0; i < timelineCount; i++) {
spTimeline *timeline = timelines[i];
switch (timelineData->items[i]) {
case SUBSEQUENT:
if (!attachments && timeline->type == SP_TIMELINE_ATTACHMENT) continue;
if (!drawOrder && timeline->type == SP_TIMELINE_DRAWORDER) continue;
timelineBlend = blend;
alpha = alphaMix;
break;
case FIRST:
timelineBlend = SP_MIX_BLEND_SETUP;
alpha = alphaMix;
break;
case DIP:
timelineBlend = SP_MIX_BLEND_SETUP;
alpha = alphaDip;
break;
default:
timelineBlend = SP_MIX_BLEND_SETUP;
dipMix = timelineDipMix->items[i];
alpha = alphaDip * MAX(0, 1 - dipMix->mixTime / dipMix->mixDuration);
break;
}
from->totalAlpha += alpha;
if (timeline->type == SP_TIMELINE_ROTATE)
_spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, alpha, timelineBlend,
timelinesRotation, i << 1, firstFrame);
else {
spTimeline_apply(timeline, skeleton, animationLast, animationTime, events, &internal->eventsCount,
alpha, timelineBlend, SP_MIX_DIRECTION_OUT);
}
} }
} }
@ -495,7 +504,7 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* t
return mix; return mix;
} }
void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline* timeline, spSkeleton* skeleton, float time, float alpha, spMixPose pose, float* timelinesRotation, int i, int /*boolean*/ firstFrame) { void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline* timeline, spSkeleton* skeleton, float time, float alpha, spMixBlend blend, float* timelinesRotation, int i, int /*boolean*/ firstFrame) {
spRotateTimeline *rotateTimeline; spRotateTimeline *rotateTimeline;
float *frames; float *frames;
spBone* bone; spBone* bone;
@ -510,7 +519,7 @@ void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline*
if (firstFrame) timelinesRotation[i] = 0; if (firstFrame) timelinesRotation[i] = 0;
if (alpha == 1) { if (alpha == 1) {
spTimeline_apply(timeline, skeleton, 0, time, 0, 0, 1, pose, SP_MIX_DIRECTION_IN); spTimeline_apply(timeline, skeleton, 0, time, 0, 0, 1, blend, SP_MIX_DIRECTION_IN);
return; return;
} }
@ -518,7 +527,7 @@ void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline*
frames = rotateTimeline->frames; frames = rotateTimeline->frames;
bone = skeleton->bones[rotateTimeline->boneIndex]; bone = skeleton->bones[rotateTimeline->boneIndex];
if (time < frames[0]) { if (time < frames[0]) {
if (pose == SP_MIX_POSE_SETUP) { if (blend == SP_MIX_BLEND_SETUP) {
bone->rotation = bone->data->rotation; bone->rotation = bone->data->rotation;
} }
return; /* Time is before first frame. */ return; /* Time is before first frame. */
@ -541,7 +550,7 @@ void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline*
} }
/* Mix between rotations using the direction of the shortest route on the first frame while detecting crosses. */ /* Mix between rotations using the direction of the shortest route on the first frame while detecting crosses. */
r1 = pose == SP_MIX_POSE_SETUP ? bone->data->rotation : bone->rotation; r1 = blend == SP_MIX_BLEND_SETUP ? bone->data->rotation : bone->rotation;
diff = r2 - r1; diff = r2 - r1;
if (diff == 0) { if (diff == 0) {
total = timelinesRotation[i]; total = timelinesRotation[i];
@ -803,6 +812,7 @@ spTrackEntry* _spAnimationState_trackEntry (spAnimationState* self, int trackInd
entry->interruptAlpha = 1; entry->interruptAlpha = 1;
entry->mixTime = 0; entry->mixTime = 0;
entry->mixDuration = !last ? 0 : spAnimationStateData_getMix(self->data, last->animation, animation); entry->mixDuration = !last ? 0 : spAnimationStateData_getMix(self->data, last->animation, animation);
entry->mixBlend = SP_MIX_BLEND_REPLACE;
entry->timelineData = spIntArray_create(16); entry->timelineData = spIntArray_create(16);
entry->timelineDipMix = spTrackEntryArray_create(16); entry->timelineDipMix = spTrackEntryArray_create(16);
@ -833,7 +843,7 @@ void _spAnimationState_animationsChanged (spAnimationState* self) {
for (;i < n; i++) { for (;i < n; i++) {
entry = self->tracks[i]; entry = self->tracks[i];
if (entry != 0) _spTrackEntry_setTimelineData(entry, 0, mixingTo, self); if (entry != 0 && entry->mixBlend != SP_MIX_BLEND_ADD) _spTrackEntry_setTimelineData(entry, 0, mixingTo, self);
} }
} }

View File

@ -619,7 +619,7 @@ module spine {
slot.color.setFromColor(slot.data.color); slot.color.setFromColor(slot.data.color);
slot.darkColor.setFromColor(slot.data.darkColor); slot.darkColor.setFromColor(slot.data.darkColor);
return; return;
case MixBlend.setup: case MixBlend.first:
let light = slot.color, dark = slot.darkColor, setupLight = slot.data.color, setupDark = slot.data.darkColor; let light = slot.color, dark = slot.darkColor, setupLight = slot.data.color, setupDark = slot.data.darkColor;
light.add((setupLight.r - light.r) * alpha, (setupLight.g - light.g) * alpha, (setupLight.b - light.b) * alpha, light.add((setupLight.r - light.r) * alpha, (setupLight.g - light.g) * alpha, (setupLight.b - light.b) * alpha,
(setupLight.a - light.a) * alpha); (setupLight.a - light.a) * alpha);
@ -1146,7 +1146,7 @@ module spine {
constraint.scaleMix = data.scaleMix; constraint.scaleMix = data.scaleMix;
constraint.shearMix = data.shearMix; constraint.shearMix = data.shearMix;
return; return;
case MixBlend.setup: case MixBlend.first:
constraint.rotateMix += (data.rotateMix - constraint.rotateMix) * alpha; constraint.rotateMix += (data.rotateMix - constraint.rotateMix) * alpha;
constraint.translateMix += (data.translateMix - constraint.translateMix) * alpha; constraint.translateMix += (data.translateMix - constraint.translateMix) * alpha;
constraint.scaleMix += (data.scaleMix - constraint.scaleMix) * alpha; constraint.scaleMix += (data.scaleMix - constraint.scaleMix) * alpha;