diff --git a/spine-c/include/spine/Animation.h b/spine-c/include/spine/Animation.h index da1cf2252..203f5f5ed 100644 --- a/spine-c/include/spine/Animation.h +++ b/spine-c/include/spine/Animation.h @@ -65,35 +65,27 @@ void spAnimation_dispose (spAnimation* self); * @param lastTime The last time the animation was applied. * @param events Any triggered events are added. May be null.*/ void spAnimation_apply (const spAnimation* self, struct spSkeleton* skeleton, float lastTime, float time, int loop, - spEvent** events, int* eventsCount); - -/** Poses the skeleton at the specified time for this animation mixed with the current pose. - * @param lastTime The last time the animation was applied. - * @param events Any triggered events are added. May be null. - * @param alpha The amount of this animation that affects the current pose. */ -void spAnimation_mix (const spAnimation* self, struct spSkeleton* skeleton, float lastTime, float time, int loop, - spEvent** events, int* eventsCount, float alpha); + spEvent** events, int* eventsCount, float alpha, int /*boolean*/ setupPose, int /*boolean*/ mixingOut); #ifdef SPINE_SHORT_NAMES typedef spAnimation Animation; #define Animation_create(...) spAnimation_create(__VA_ARGS__) #define Animation_dispose(...) spAnimation_dispose(__VA_ARGS__) #define Animation_apply(...) spAnimation_apply(__VA_ARGS__) -#define Animation_mix(...) spAnimation_mix(__VA_ARGS__) #endif /**/ typedef enum { - SP_TIMELINE_SCALE, SP_TIMELINE_ROTATE, SP_TIMELINE_TRANSLATE, + SP_TIMELINE_SCALE, SP_TIMELINE_SHEAR, - SP_TIMELINE_COLOR, SP_TIMELINE_ATTACHMENT, + SP_TIMELINE_COLOR, + SP_TIMELINE_DEFORM, SP_TIMELINE_EVENT, SP_TIMELINE_DRAWORDER, - SP_TIMELINE_DEFORM, SP_TIMELINE_IKCONSTRAINT, SP_TIMELINE_TRANSFORMCONSTRAINT, SP_TIMELINE_PATHCONSTRAINTPOSITION, @@ -115,7 +107,8 @@ struct spTimeline { void spTimeline_dispose (spTimeline* self); void spTimeline_apply (const spTimeline* self, struct spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha); + int* eventsCount, float alpha, int /*boolean*/ setupPose, int /*boolean*/ mixingOut); +int spTimeline_getPropertyId (const spTimeline* self); #ifdef SPINE_SHORT_NAMES typedef spTimeline Timeline; diff --git a/spine-c/include/spine/extension.h b/spine-c/include/spine/extension.h index 60e4d047e..6b62f8525 100644 --- a/spine-c/include/spine/extension.h +++ b/spine-c/include/spine/extension.h @@ -93,6 +93,7 @@ #define RAD_DEG (180 / PI) #define ABS(A) ((A) < 0? -(A): (A)) +#define SIGNUM(A) ((A) < 0? -1: (A) > 0 ? 1 : 0) #ifdef __STDC_VERSION__ #define FMOD(A,B) fmodf(A, B) @@ -230,7 +231,8 @@ void _spVertexAttachment_deinit (spVertexAttachment* self); void _spTimeline_init (spTimeline* self, spTimelineType type, void (*dispose) (spTimeline* self), void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha)); + int* eventsCount, float alpha, int setupPose, int mixingOut), + int (*getPropertyId) (const spTimeline* self)); void _spTimeline_deinit (spTimeline* self); #ifdef SPINE_SHORT_NAMES @@ -242,8 +244,8 @@ void _spTimeline_deinit (spTimeline* self); void _spCurveTimeline_init (spCurveTimeline* self, spTimelineType type, int framesCount, void (*dispose) (spTimeline* self), - void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha)); + void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, int* eventsCount, float alpha, int setupPose, int mixingOut), + int (*getPropertyId) (const spTimeline* self)); void _spCurveTimeline_deinit (spCurveTimeline* self); #ifdef SPINE_SHORT_NAMES diff --git a/spine-c/src/spine/Animation.c b/spine-c/src/spine/Animation.c index 45d39b9c4..2eacd5653 100644 --- a/spine-c/src/spine/Animation.c +++ b/spine-c/src/spine/Animation.c @@ -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, - int* eventsCount) { + int* eventsCount, float alpha, int setupPose, int mixingOut) { int i, n = self->timelinesCount; if (loop && self->duration) { @@ -60,38 +60,27 @@ void spAnimation_apply (const spAnimation* self, spSkeleton* skeleton, float las } for (i = 0; i < n; ++i) - spTimeline_apply(self->timelines[i], skeleton, lastTime, time, events, eventsCount, 1); -} - -void spAnimation_mix (const spAnimation* self, spSkeleton* skeleton, float lastTime, float time, int loop, spEvent** events, - int* eventsCount, float alpha) { - int i, n = self->timelinesCount; - - if (loop && self->duration) { - time = FMOD(time, self->duration); - if (lastTime > 0) lastTime = FMOD(lastTime, self->duration); - } - - for (i = 0; i < n; ++i) - spTimeline_apply(self->timelines[i], skeleton, lastTime, time, events, eventsCount, alpha); + spTimeline_apply(self->timelines[i], skeleton, lastTime, time, events, eventsCount, alpha, setupPose, mixingOut); } /**/ typedef struct _spTimelineVtable { void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha); + int* eventsCount, float alpha, int setupPose, int mixingOut); + int (*getPropertyId) (const spTimeline* self); void (*dispose) (spTimeline* self); } _spTimelineVtable; void _spTimeline_init (spTimeline* self, spTimelineType type, /**/ -void (*dispose) (spTimeline* self), /**/ - void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha)) { + void (*dispose) (spTimeline* self), /**/ + void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, int* eventsCount, float alpha, int setupPose, int mixingOut), + int (*getPropertyId) (const spTimeline* self)) { CONST_CAST(spTimelineType, self->type) = type; CONST_CAST(_spTimelineVtable*, self->vtable) = NEW(_spTimelineVtable); VTABLE(spTimeline, self)->dispose = dispose; VTABLE(spTimeline, self)->apply = apply; + VTABLE(spTimeline, self)->getPropertyId = getPropertyId; } void _spTimeline_deinit (spTimeline* self) { @@ -103,8 +92,12 @@ void spTimeline_dispose (spTimeline* self) { } void spTimeline_apply (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha) { - VTABLE(spTimeline, self)->apply(self, skeleton, lastTime, time, firedEvents, eventsCount, alpha); + int* eventsCount, float alpha, int /*boolean*/ setupPose, int /*boolean*/ mixingOut) { + VTABLE(spTimeline, self)->apply(self, skeleton, lastTime, time, firedEvents, eventsCount, alpha, setupPose, mixingOut); +} + +int spTimeline_getPropertyId (const spTimeline* self) { + return VTABLE(spTimeline, self)->getPropertyId(self); } /**/ @@ -113,10 +106,10 @@ static const float CURVE_LINEAR = 0, CURVE_STEPPED = 1, CURVE_BEZIER = 2; static const int BEZIER_SIZE = 10 * 2 - 1; void _spCurveTimeline_init (spCurveTimeline* self, spTimelineType type, int framesCount, /**/ -void (*dispose) (spTimeline* self), /**/ - void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha)) { - _spTimeline_init(SUPER(self), type, dispose, apply); + void (*dispose) (spTimeline* self), /**/ + void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, int* eventsCount, float alpha, int setupPose, int mixingOut), + int (*getPropertyId)(const spTimeline* self)) { + _spTimeline_init(SUPER(self), type, dispose, apply, getPropertyId); self->curves = CALLOC(float, (framesCount - 1) * BEZIER_SIZE); } @@ -228,9 +221,10 @@ void _spBaseTimeline_dispose (spTimeline* timeline) { /* Many timelines have structure identical to struct spBaseTimeline and extend spCurveTimeline. **/ struct spBaseTimeline* _spBaseTimeline_create (int framesCount, spTimelineType type, int frameSize, /**/ void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha)) { + int* eventsCount, float alpha, int setupPose, int mixingOut), + int (*getPropertyId) (const spTimeline* self)) { struct spBaseTimeline* self = NEW(struct spBaseTimeline); - _spCurveTimeline_init(SUPER(self), type, framesCount, _spBaseTimeline_dispose, apply); + _spCurveTimeline_init(SUPER(self), type, framesCount, _spBaseTimeline_dispose, apply, getPropertyId); CONST_CAST(int, self->framesCount) = framesCount * frameSize; CONST_CAST(float*, self->frames) = CALLOC(float, self->framesCount); @@ -244,10 +238,10 @@ static const int ROTATE_PREV_TIME = -2, ROTATE_PREV_ROTATION = -1; static const int ROTATE_ROTATION = 1; void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha) { + int* eventsCount, float alpha, int setupPose, int mixingOut) { spBone *bone; int frame; - float prevRotation, frameTime, percent, amount; + float prevRotation, frameTime, percent, r; spRotateTimeline* self = SUB_CAST(spRotateTimeline, timeline); @@ -256,12 +250,13 @@ void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, bone = skeleton->bones[self->boneIndex]; if (time >= self->frames[self->framesCount - ROTATE_ENTRIES]) { /* Time is after last frame. */ - amount = bone->data->rotation + self->frames[self->framesCount + ROTATE_PREV_ROTATION] - bone->rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone->rotation += amount * alpha; + if (setupPose) + bone->rotation = bone->data->rotation + self->frames[self->framesCount + ROTATE_PREV_ROTATION] * alpha; + else { + r = bone->data->rotation + self->frames[self->framesCount + ROTATE_PREV_ROTATION] - bone->rotation; + r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360; /* Wrap within -180 and 180. */ + bone->rotation += r * alpha; + } return; } @@ -271,25 +266,29 @@ void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, frameTime = self->frames[frame]; percent = spCurveTimeline_getCurvePercent(SUPER(self), (frame >> 1) - 1, 1 - (time - frameTime) / (self->frames[frame + ROTATE_PREV_TIME] - frameTime)); - amount = self->frames[frame + ROTATE_ROTATION] - prevRotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - amount = bone->data->rotation + (prevRotation + amount * percent) - bone->rotation; - while (amount > 180) - amount -= 360; - while (amount < -180) - amount += 360; - bone->rotation += amount * alpha; + r = self->frames[frame + ROTATE_ROTATION] - prevRotation; + r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360; + r = prevRotation + r * percent; + if (setupPose) { + r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360; + bone->rotation = bone->data->rotation + r * alpha; + } else { + r = bone->data->rotation + r - bone->rotation; + r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360; + bone->rotation += r * alpha; + } UNUSED(lastTime); UNUSED(firedEvents); UNUSED(eventsCount); } +int _spRotateTimeline_getPropertyId (const spTimeline* timeline) { + return (SP_TIMELINE_ROTATE << 25) + SUB_CAST(spRotateTimeline, timeline)->boneIndex; +} + spRotateTimeline* spRotateTimeline_create (int framesCount) { - return _spBaseTimeline_create(framesCount, SP_TIMELINE_ROTATE, ROTATE_ENTRIES, _spRotateTimeline_apply); + return _spBaseTimeline_create(framesCount, SP_TIMELINE_ROTATE, ROTATE_ENTRIES, _spRotateTimeline_apply, _spRotateTimeline_getPropertyId); } void spRotateTimeline_setFrame (spRotateTimeline* self, int frameIndex, float time, float degrees) { @@ -304,10 +303,13 @@ static const int TRANSLATE_PREV_TIME = -3, TRANSLATE_PREV_X = -2, TRANSLATE_PREV static const int TRANSLATE_X = 1, TRANSLATE_Y = 2; void _spTranslateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { + spEvent** firedEvents, int* eventsCount, float alpha, int setupPose, int mixingOut) { spBone *bone; int frame; - float prevX, prevY, frameTime, percent; + float frameTime, percent; + float x, y; + float *frames; + int framesCount; spTranslateTimeline* self = SUB_CAST(spTranslateTimeline, timeline); @@ -315,29 +317,42 @@ void _spTranslateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleto bone = skeleton->bones[self->boneIndex]; - if (time >= self->frames[self->framesCount - TRANSLATE_ENTRIES]) { /* Time is after last frame. */ - bone->x += (bone->data->x + self->frames[self->framesCount + TRANSLATE_PREV_X] - bone->x) * alpha; - bone->y += (bone->data->y + self->frames[self->framesCount + TRANSLATE_PREV_Y] - bone->y) * alpha; - return; + frames = self->frames; + framesCount = self->framesCount; + if (time >= frames[framesCount - TRANSLATE_ENTRIES]) { /* Time is after last frame. */ + x = frames[framesCount + TRANSLATE_PREV_X]; + y = frames[framesCount + TRANSLATE_PREV_Y]; + } else { + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(frames, framesCount, time, TRANSLATE_ENTRIES); + x = frames[frame + TRANSLATE_PREV_X]; + y = frames[frame + TRANSLATE_PREV_Y]; + frameTime = frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSLATE_ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + TRANSLATE_PREV_TIME] - frameTime)); + + x += (frames[frame + TRANSLATE_X] - x) * percent; + y += (frames[frame + TRANSLATE_Y] - y) * percent; + } + if (setupPose) { + bone->x = bone->data->x + x * alpha; + bone->y = bone->data->y + y * alpha; + } else { + bone->x += (bone->data->x + x - bone->x) * alpha; + bone->y += (bone->data->y + y - bone->y) * alpha; } - - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, TRANSLATE_ENTRIES); - prevX = self->frames[frame + TRANSLATE_PREV_X]; - prevY = self->frames[frame + TRANSLATE_PREV_Y]; - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSLATE_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + TRANSLATE_PREV_TIME] - frameTime)); - - bone->x += (bone->data->x + prevX + (self->frames[frame + TRANSLATE_X] - prevX) * percent - bone->x) * alpha; - bone->y += (bone->data->y + prevY + (self->frames[frame + TRANSLATE_Y] - prevY) * percent - bone->y) * alpha; UNUSED(lastTime); UNUSED(firedEvents); UNUSED(eventsCount); } +int _spTranslateTimeline_getPropertyId (const spTimeline* self) { + return (SP_TIMELINE_TRANSLATE << 24) + SUB_CAST(spTranslateTimeline, self)->boneIndex; +} + spTranslateTimeline* spTranslateTimeline_create (int framesCount) { - return _spBaseTimeline_create(framesCount, SP_TIMELINE_TRANSLATE, TRANSLATE_ENTRIES, _spTranslateTimeline_apply); + return _spBaseTimeline_create(framesCount, SP_TIMELINE_TRANSLATE, TRANSLATE_ENTRIES, _spTranslateTimeline_apply, _spTranslateTimeline_getPropertyId); } void spTranslateTimeline_setFrame (spTranslateTimeline* self, int frameIndex, float time, float x, float y) { @@ -350,39 +365,71 @@ void spTranslateTimeline_setFrame (spTranslateTimeline* self, int frameIndex, fl /**/ void _spScaleTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha) { + int* eventsCount, float alpha, int setupPose, int mixingOut) { spBone *bone; int frame; - float prevX, prevY, frameTime, percent; + float frameTime, percent, x, y; + float *frames; + int framesCount; spScaleTimeline* self = SUB_CAST(spScaleTimeline, timeline); if (time < self->frames[0]) return; /* Time is before first frame. */ bone = skeleton->bones[self->boneIndex]; - if (time >= self->frames[self->framesCount - TRANSLATE_ENTRIES]) { /* Time is after last frame. */ - bone->scaleX += (bone->data->scaleX * self->frames[self->framesCount + TRANSLATE_PREV_X] - bone->scaleX) * alpha; - bone->scaleY += (bone->data->scaleY * self->frames[self->framesCount + TRANSLATE_PREV_Y] - bone->scaleY) * alpha; - return; + + frames = self->frames; + framesCount = self->framesCount; + if (time >= frames[framesCount - TRANSLATE_ENTRIES]) { /* Time is after last frame. */ + x = frames[framesCount + TRANSLATE_PREV_X] * bone->data->scaleX; + y = frames[framesCount + TRANSLATE_PREV_Y] * bone->data->scaleY; + } else { + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(frames, framesCount, time, TRANSLATE_ENTRIES); + x = frames[frame + TRANSLATE_PREV_X]; + y = frames[frame + TRANSLATE_PREV_Y]; + frameTime = frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSLATE_ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + TRANSLATE_PREV_TIME] - frameTime)); + + x = (x + (frames[frame + TRANSLATE_X] - x) * percent) * bone->data->scaleX; + y = (y + (frames[frame + TRANSLATE_Y] - y) * percent) * bone->data->scaleY; + } + if (alpha == 1) { + bone->scaleX = x; + bone->scaleY = y; + } else { + float bx, by; + if (setupPose) { + 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 (mixingOut) { + x = ABS(x) * SIGNUM(bx); + y = ABS(y) * SIGNUM(by); + } else { + bx = ABS(bx) * SIGNUM(x); + by = ABS(by) * SIGNUM(y); + } + bone->scaleX = bx + (x - bx) * alpha; + bone->scaleY = by + (y - by) * alpha; } - - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, TRANSLATE_ENTRIES); - prevX = self->frames[frame + TRANSLATE_PREV_X]; - prevY = self->frames[frame + TRANSLATE_PREV_Y]; - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSLATE_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + TRANSLATE_PREV_TIME] - frameTime)); - - bone->scaleX += (bone->data->scaleX * (prevX + (self->frames[frame + TRANSLATE_X] - prevX) * percent) - bone->scaleX) * alpha; - bone->scaleY += (bone->data->scaleY * (prevY + (self->frames[frame + TRANSLATE_Y] - prevY) * percent) - bone->scaleY) * alpha; UNUSED(lastTime); UNUSED(firedEvents); UNUSED(eventsCount); } +int _spScaleTimeline_getPropertyId (const spTimeline* timeline) { + return (SP_TIMELINE_SCALE << 24) + SUB_CAST(spScaleTimeline, timeline)->boneIndex; +} + spScaleTimeline* spScaleTimeline_create (int framesCount) { - return _spBaseTimeline_create(framesCount, SP_TIMELINE_SCALE, TRANSLATE_ENTRIES, _spScaleTimeline_apply); + return _spBaseTimeline_create(framesCount, SP_TIMELINE_SCALE, TRANSLATE_ENTRIES, _spScaleTimeline_apply, _spScaleTimeline_getPropertyId); } void spScaleTimeline_setFrame (spScaleTimeline* self, int frameIndex, float time, float x, float y) { @@ -392,39 +439,55 @@ void spScaleTimeline_setFrame (spScaleTimeline* self, int frameIndex, float time /**/ void _spShearTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha) { + int* eventsCount, float alpha, int setupPose, int mixingOut) { spBone *bone; int frame; - float prevX, prevY, frameTime, percent; + float frameTime, percent, x, y; + float *frames; + int framesCount; spShearTimeline* self = SUB_CAST(spShearTimeline, timeline); if (time < self->frames[0]) return; /* Time is before first frame. */ bone = skeleton->bones[self->boneIndex]; - if (time >= self->frames[self->framesCount - TRANSLATE_ENTRIES]) { /* Time is after last frame. */ - bone->shearX += (bone->data->shearX + self->frames[self->framesCount + TRANSLATE_PREV_X] - bone->shearX) * alpha; - bone->shearY += (bone->data->shearY + self->frames[self->framesCount + TRANSLATE_PREV_Y] - bone->shearY) * alpha; - return; + frames = self->frames; + framesCount = self->framesCount; + + if (time >= frames[framesCount - TRANSLATE_ENTRIES]) { /* Time is after last frame. */ + x = frames[framesCount + TRANSLATE_PREV_X]; + y = frames[framesCount + TRANSLATE_PREV_Y]; + } else { + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(frames, framesCount, time, TRANSLATE_ENTRIES); + x = frames[frame + TRANSLATE_PREV_X]; + y = frames[frame + TRANSLATE_PREV_Y]; + frameTime = frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSLATE_ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + TRANSLATE_PREV_TIME] - frameTime)); + + x = x + (frames[frame + TRANSLATE_X] - x) * percent; + y = y + (frames[frame + TRANSLATE_Y] - y) * percent; + } + if (setupPose) { + bone->shearX = bone->data->shearX + x * alpha; + bone->shearY = bone->data->shearY + y * alpha; + } else { + bone->shearX += (bone->data->shearX + x - bone->shearX) * alpha; + bone->shearY += (bone->data->shearY + y - bone->shearY) * alpha; } - - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, TRANSLATE_ENTRIES); - prevX = self->frames[frame + TRANSLATE_PREV_X]; - prevY = self->frames[frame + TRANSLATE_PREV_Y]; - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSLATE_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + TRANSLATE_PREV_TIME] - frameTime)); - - bone->shearX += (bone->data->shearX + prevX + (self->frames[frame + TRANSLATE_X] - prevX) * percent - bone->shearX) * alpha; - bone->shearY += (bone->data->shearY + prevY + (self->frames[frame + TRANSLATE_Y] - prevY) * percent - bone->shearY) * alpha; UNUSED(lastTime); UNUSED(firedEvents); UNUSED(eventsCount); } +int _spShearTimeline_getPropertyId (const spTimeline* timeline) { + return (SP_TIMELINE_SHEAR << 24) + SUB_CAST(spShearTimeline, timeline)->boneIndex; +} + spShearTimeline* spShearTimeline_create (int framesCount) { - return (spShearTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_SHEAR, 3, _spShearTimeline_apply); + return (spShearTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_SHEAR, 3, _spShearTimeline_apply, _spShearTimeline_getPropertyId); } void spShearTimeline_setFrame (spShearTimeline* self, int frameIndex, float time, float x, float y) { @@ -437,7 +500,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; void _spColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha) { + int* eventsCount, float alpha, int setupPose, int mixingOut) { spSlot *slot; int frame; float percent, frameTime; @@ -471,16 +534,22 @@ void _spColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f a += (self->frames[frame + COLOR_A] - a) * percent; } slot = skeleton->slots[self->slotIndex]; - if (alpha < 1) { - slot->r += (r - slot->r) * alpha; - slot->g += (g - slot->g) * alpha; - slot->b += (b - slot->b) * alpha; - slot->a += (a - slot->a) * alpha; - } else { + if (alpha == 1) { slot->r = r; slot->g = g; slot->b = b; slot->a = a; + } else { + if (setupPose) { + slot->r = slot->data->r; + slot->g = slot->data->g; + slot->b = slot->data->b; + slot->a = slot->data->a; + } + slot->r += (r - slot->r) * alpha; + slot->g += (g - slot->g) * alpha; + slot->b += (b - slot->b) * alpha; + slot->a += (a - slot->a) * alpha; } UNUSED(lastTime); @@ -488,8 +557,12 @@ void _spColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f UNUSED(eventsCount); } +int _spColorTimeline_getPropertyId (const spTimeline* timeline) { + return (SP_TIMELINE_COLOR << 24) + SUB_CAST(spColorTimeline, timeline)->slotIndex; +} + spColorTimeline* spColorTimeline_create (int framesCount) { - return (spColorTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_COLOR, 5, _spColorTimeline_apply); + return (spColorTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_COLOR, 5, _spColorTimeline_apply, _spColorTimeline_getPropertyId); } void spColorTimeline_setFrame (spColorTimeline* self, int frameIndex, float time, float r, float g, float b, float a) { @@ -504,11 +577,18 @@ void spColorTimeline_setFrame (spColorTimeline* self, int frameIndex, float time /**/ void _spAttachmentTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { + spEvent** firedEvents, int* eventsCount, float alpha, int setupPose, int mixingOut) { const char* attachmentName; spAttachmentTimeline* self = (spAttachmentTimeline*)timeline; int frameIndex; + if (mixingOut && setupPose) { + spSlot* slot = skeleton->slots[self->slotIndex]; + const char* attachmentName = slot->data->attachmentName; + spSlot_setAttachment(slot, attachmentName ? 0 : spSkeleton_getAttachmentForSlotIndex(skeleton, self->slotIndex, attachmentName)); + return; + } + if (time < self->frames[0]) return; if (time >= self->frames[self->framesCount - 1]) @@ -526,6 +606,10 @@ void _spAttachmentTimeline_apply (const spTimeline* timeline, spSkeleton* skelet UNUSED(alpha); } +int _spAttachmentTimeline_getPropertyId (const spTimeline* timeline) { + return (SP_TIMELINE_ATTACHMENT << 24) + SUB_CAST(spAttachmentTimeline, timeline)->slotIndex; +} + void _spAttachmentTimeline_dispose (spTimeline* timeline) { spAttachmentTimeline* self = SUB_CAST(spAttachmentTimeline, timeline); int i; @@ -541,7 +625,7 @@ void _spAttachmentTimeline_dispose (spTimeline* timeline) { spAttachmentTimeline* spAttachmentTimeline_create (int framesCount) { spAttachmentTimeline* self = NEW(spAttachmentTimeline); - _spTimeline_init(SUPER(self), SP_TIMELINE_ATTACHMENT, _spAttachmentTimeline_dispose, _spAttachmentTimeline_apply); + _spTimeline_init(SUPER(self), SP_TIMELINE_ATTACHMENT, _spAttachmentTimeline_dispose, _spAttachmentTimeline_apply, _spAttachmentTimeline_getPropertyId); CONST_CAST(int, self->framesCount) = framesCount; CONST_CAST(float*, self->frames) = CALLOC(float, framesCount); @@ -564,13 +648,13 @@ void spAttachmentTimeline_setFrame (spAttachmentTimeline* self, int frameIndex, /** Fires events for frames > lastTime and <= time. */ void _spEventTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha) { + int* eventsCount, float alpha, int setupPose, int mixingOut) { spEventTimeline* self = (spEventTimeline*)timeline; int frame; if (!firedEvents) return; if (lastTime > time) { /* Fire events after last time for looped animations. */ - _spEventTimeline_apply(timeline, skeleton, lastTime, (float)INT_MAX, firedEvents, eventsCount, alpha); + _spEventTimeline_apply(timeline, skeleton, lastTime, (float)INT_MAX, firedEvents, eventsCount, alpha, setupPose, mixingOut); lastTime = -1; } else if (lastTime >= self->frames[self->framesCount - 1]) /* Last time is after last frame. */ return; @@ -593,6 +677,10 @@ void _spEventTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f } } +int _spEventTimeline_getPropertyId (const spTimeline* timeline) { + return SP_TIMELINE_EVENT << 24; +} + void _spEventTimeline_dispose (spTimeline* timeline) { spEventTimeline* self = SUB_CAST(spEventTimeline, timeline); int i; @@ -608,7 +696,7 @@ void _spEventTimeline_dispose (spTimeline* timeline) { spEventTimeline* spEventTimeline_create (int framesCount) { spEventTimeline* self = NEW(spEventTimeline); - _spTimeline_init(SUPER(self), SP_TIMELINE_EVENT, _spEventTimeline_dispose, _spEventTimeline_apply); + _spTimeline_init(SUPER(self), SP_TIMELINE_EVENT, _spEventTimeline_dispose, _spEventTimeline_apply, _spEventTimeline_getPropertyId); CONST_CAST(int, self->framesCount) = framesCount; CONST_CAST(float*, self->frames) = CALLOC(float, framesCount); @@ -627,12 +715,17 @@ void spEventTimeline_setFrame (spEventTimeline* self, int frameIndex, spEvent* e /**/ void _spDrawOrderTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { + spEvent** firedEvents, int* eventsCount, float alpha, int setupPose, int mixingOut) { int i; int frame; const int* drawOrderToSetupIndex; spDrawOrderTimeline* self = (spDrawOrderTimeline*)timeline; + if (mixingOut && setupPose) { + memcpy(skeleton->drawOrder, skeleton->slots, self->slotsCount * sizeof(spSlot*)); + return; + } + if (time < self->frames[0]) return; /* Time is before first frame. */ if (time >= self->frames[self->framesCount - 1]) /* Time is after last frame. */ @@ -654,6 +747,10 @@ void _spDrawOrderTimeline_apply (const spTimeline* timeline, spSkeleton* skeleto UNUSED(alpha); } +int _spDrawOrderTimeline_getPropertyId (const spTimeline* timeline) { + return SP_TIMELINE_DRAWORDER << 24; +} + void _spDrawOrderTimeline_dispose (spTimeline* timeline) { spDrawOrderTimeline* self = SUB_CAST(spDrawOrderTimeline, timeline); int i; @@ -669,7 +766,7 @@ void _spDrawOrderTimeline_dispose (spTimeline* timeline) { spDrawOrderTimeline* spDrawOrderTimeline_create (int framesCount, int slotsCount) { spDrawOrderTimeline* self = NEW(spDrawOrderTimeline); - _spTimeline_init(SUPER(self), SP_TIMELINE_DRAWORDER, _spDrawOrderTimeline_dispose, _spDrawOrderTimeline_apply); + _spTimeline_init(SUPER(self), SP_TIMELINE_DRAWORDER, _spDrawOrderTimeline_dispose, _spDrawOrderTimeline_apply, _spDrawOrderTimeline_getPropertyId); CONST_CAST(int, self->framesCount) = framesCount; CONST_CAST(float*, self->frames) = CALLOC(float, framesCount); @@ -694,7 +791,7 @@ void spDrawOrderTimeline_setFrame (spDrawOrderTimeline* self, int frameIndex, fl /**/ void _spDeformTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, - int* eventsCount, float alpha) { + int* eventsCount, float alpha, int setupPose, int mixingOut) { int frame, i, vertexCount; float percent, frameTime; const float* prevVertices; @@ -765,6 +862,10 @@ void _spDeformTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, UNUSED(eventsCount); } +int _spDeformTimeline_getPropertyId (const spTimeline* timeline) { + return (SP_TIMELINE_DEFORM << 24) + SUB_CAST(spDeformTimeline, timeline)->slotIndex; +} + void _spDeformTimeline_dispose (spTimeline* timeline) { spDeformTimeline* self = SUB_CAST(spDeformTimeline, timeline); int i; @@ -780,7 +881,7 @@ void _spDeformTimeline_dispose (spTimeline* timeline) { spDeformTimeline* spDeformTimeline_create (int framesCount, int frameVerticesCount) { spDeformTimeline* self = NEW(spDeformTimeline); - _spCurveTimeline_init(SUPER(self), SP_TIMELINE_DEFORM, framesCount, _spDeformTimeline_dispose, _spDeformTimeline_apply); + _spCurveTimeline_init(SUPER(self), SP_TIMELINE_DEFORM, framesCount, _spDeformTimeline_dispose, _spDeformTimeline_apply, _spDeformTimeline_getPropertyId); CONST_CAST(int, self->framesCount) = framesCount; CONST_CAST(float*, self->frames) = CALLOC(float, self->framesCount); CONST_CAST(float**, self->frameVertices) = CALLOC(float*, framesCount); @@ -807,9 +908,11 @@ static const int IKCONSTRAINT_PREV_TIME = -3, IKCONSTRAINT_PREV_MIX = -2, IKCONS static const int IKCONSTRAINT_MIX = 1, IKCONSTRAINT_BEND_DIRECTION = 2; void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { + spEvent** firedEvents, int* eventsCount, float alpha, int setupPose, int mixingOut) { int frame; float frameTime, percent, mix; + float *frames; + int framesCount; spIkConstraint* constraint; spIkConstraintTimeline* self = (spIkConstraintTimeline*)timeline; @@ -817,9 +920,17 @@ void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skel constraint = skeleton->ikConstraints[self->ikConstraintIndex]; - if (time >= self->frames[self->framesCount - IKCONSTRAINT_ENTRIES]) { /* Time is after last frame. */ - constraint->mix += (self->frames[self->framesCount + IKCONSTRAINT_PREV_MIX] - constraint->mix) * alpha; - constraint->bendDirection = (int)self->frames[self->framesCount + IKCONSTRAINT_PREV_BEND_DIRECTION]; + frames = self->frames; + framesCount = self->framesCount; + if (time >= frames[framesCount - IKCONSTRAINT_ENTRIES]) { /* Time is after last frame. */ + if (setupPose) { + constraint->mix = constraint->data->mix + (frames[framesCount + IKCONSTRAINT_PREV_MIX] - constraint->data->mix) * alpha; + constraint->bendDirection = mixingOut ? constraint->data->bendDirection + : (int)frames[framesCount + IKCONSTRAINT_PREV_BEND_DIRECTION]; + } else { + constraint->mix += (frames[framesCount + IKCONSTRAINT_PREV_MIX] - constraint->mix) * alpha; + if (!mixingOut) constraint->bendDirection = (int)frames[framesCount + IKCONSTRAINT_PREV_BEND_DIRECTION]; + } return; } @@ -829,16 +940,25 @@ void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skel frameTime = self->frames[frame]; percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / IKCONSTRAINT_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + IKCONSTRAINT_PREV_TIME] - frameTime)); - constraint->mix += (mix + (self->frames[frame + IKCONSTRAINT_MIX] - mix) * percent - constraint->mix) * alpha; - constraint->bendDirection = (int)self->frames[frame + IKCONSTRAINT_PREV_BEND_DIRECTION]; + if (setupPose) { + constraint->mix = constraint->data->mix + (mix + (frames[frame + IKCONSTRAINT_MIX] - mix) * percent - constraint->data->mix) * alpha; + constraint->bendDirection = mixingOut ? constraint->data->bendDirection : (int)frames[frame + IKCONSTRAINT_PREV_BEND_DIRECTION]; + } else { + constraint->mix += (mix + (frames[frame + IKCONSTRAINT_MIX] - mix) * percent - constraint->mix) * alpha; + if (!mixingOut) constraint->bendDirection = (int)frames[frame + IKCONSTRAINT_PREV_BEND_DIRECTION]; + } UNUSED(lastTime); UNUSED(firedEvents); UNUSED(eventsCount); } +int _spIkConstraintTimeline_getPropertyId (const spTimeline* timeline) { + return (SP_TIMELINE_IKCONSTRAINT << 24) + SUB_CAST(spIkConstraintTimeline, timeline)->ikConstraintIndex; +} + spIkConstraintTimeline* spIkConstraintTimeline_create (int framesCount) { - return (spIkConstraintTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_IKCONSTRAINT, IKCONSTRAINT_ENTRIES, _spIkConstraintTimeline_apply); + return (spIkConstraintTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_IKCONSTRAINT, IKCONSTRAINT_ENTRIES, _spIkConstraintTimeline_apply, _spIkConstraintTimeline_getPropertyId); } void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameIndex, float time, float mix, int bendDirection) { @@ -860,46 +980,66 @@ static const int TRANSFORMCONSTRAINT_SCALE = 3; static const int TRANSFORMCONSTRAINT_SHEAR = 4; void _spTransformConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { + spEvent** firedEvents, int* eventsCount, float alpha, int setupPose, int mixingOut) { int frame; float frameTime, percent, rotate, translate, scale, shear; spTransformConstraint* constraint; spTransformConstraintTimeline* self = (spTransformConstraintTimeline*)timeline; + float *frames; + int framesCount; if (time < self->frames[0]) return; /* Time is before first frame. */ constraint = skeleton->transformConstraints[self->transformConstraintIndex]; - if (time >= self->frames[self->framesCount - TRANSFORMCONSTRAINT_ENTRIES]) { /* Time is after last frame. */ - int len = self->framesCount; - constraint->rotateMix += (self->frames[len + TRANSFORMCONSTRAINT_PREV_ROTATE] - constraint->rotateMix) * alpha; - constraint->translateMix += (self->frames[len + TRANSFORMCONSTRAINT_PREV_TRANSLATE] - constraint->translateMix) * alpha; - constraint->scaleMix += (self->frames[len + TRANSFORMCONSTRAINT_PREV_SCALE] - constraint->scaleMix) * alpha; - constraint->shearMix += (self->frames[len + TRANSFORMCONSTRAINT_PREV_SHEAR] - constraint->shearMix) * alpha; - return; + frames = self->frames; + framesCount = self->framesCount; + if (time >= frames[framesCount - TRANSFORMCONSTRAINT_ENTRIES]) { /* Time is after last frame. */ + int i = framesCount; + rotate = frames[i + TRANSFORMCONSTRAINT_PREV_ROTATE]; + translate = frames[i + TRANSFORMCONSTRAINT_PREV_TRANSLATE]; + scale = frames[i + TRANSFORMCONSTRAINT_PREV_SCALE]; + shear = frames[i + TRANSFORMCONSTRAINT_PREV_SHEAR]; + } else { + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(frames, framesCount, time, TRANSFORMCONSTRAINT_ENTRIES); + rotate = frames[frame + TRANSFORMCONSTRAINT_PREV_ROTATE]; + translate = frames[frame + TRANSFORMCONSTRAINT_PREV_TRANSLATE]; + scale = frames[frame + TRANSFORMCONSTRAINT_PREV_SCALE]; + shear = frames[frame + TRANSFORMCONSTRAINT_PREV_SHEAR]; + frameTime = frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSFORMCONSTRAINT_ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + TRANSFORMCONSTRAINT_PREV_TIME] - frameTime)); + + rotate += (frames[frame + TRANSFORMCONSTRAINT_ROTATE] - rotate) * percent; + translate += (frames[frame + TRANSFORMCONSTRAINT_TRANSLATE] - translate) * percent; + scale += (frames[frame + TRANSFORMCONSTRAINT_SCALE] - scale) * percent; + shear += (frames[frame + TRANSFORMCONSTRAINT_SHEAR] - shear) * percent; + } + if (setupPose) { + spTransformConstraintData* data = constraint->data; + constraint->rotateMix = data->rotateMix + (rotate - data->rotateMix) * alpha; + constraint->translateMix = data->translateMix + (translate - data->translateMix) * alpha; + constraint->scaleMix = data->scaleMix + (scale - data->scaleMix) * alpha; + constraint->shearMix = data->shearMix + (shear - data->shearMix) * alpha; + } else { + constraint->rotateMix += (rotate - constraint->rotateMix) * alpha; + constraint->translateMix += (translate - constraint->translateMix) * alpha; + constraint->scaleMix += (scale - constraint->scaleMix) * alpha; + constraint->shearMix += (shear - constraint->shearMix) * alpha; } - - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, TRANSFORMCONSTRAINT_ENTRIES); - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / TRANSFORMCONSTRAINT_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + TRANSFORMCONSTRAINT_PREV_TIME] - frameTime)); - - rotate = self->frames[frame + TRANSFORMCONSTRAINT_PREV_ROTATE]; - translate = self->frames[frame + TRANSFORMCONSTRAINT_PREV_TRANSLATE]; - scale = self->frames[frame + TRANSFORMCONSTRAINT_PREV_SCALE]; - shear = self->frames[frame + TRANSFORMCONSTRAINT_PREV_SHEAR]; - constraint->rotateMix += (rotate + (self->frames[frame + TRANSFORMCONSTRAINT_ROTATE] - rotate) * percent - constraint->rotateMix) * alpha; - constraint->translateMix += (translate + (self->frames[frame + TRANSFORMCONSTRAINT_TRANSLATE] - translate) * percent - constraint->translateMix) * alpha; - constraint->scaleMix += (scale + (self->frames[frame + TRANSFORMCONSTRAINT_SCALE] - scale) * percent - constraint->scaleMix) * alpha; - constraint->shearMix += (shear + (self->frames[frame + TRANSFORMCONSTRAINT_SHEAR] - shear) * percent - constraint->shearMix) * alpha; UNUSED(lastTime); UNUSED(firedEvents); UNUSED(eventsCount); } +int _spTransformConstraintTimeline_getPropertyId (const spTimeline* timeline) { + return (SP_TIMELINE_TRANSFORMCONSTRAINT << 24) + SUB_CAST(spTransformConstraintTimeline, timeline)->transformConstraintIndex; +} + spTransformConstraintTimeline* spTransformConstraintTimeline_create (int framesCount) { - return (spTransformConstraintTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_TRANSFORMCONSTRAINT, TRANSFORMCONSTRAINT_ENTRIES, _spTransformConstraintTimeline_apply); + return (spTransformConstraintTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_TRANSFORMCONSTRAINT, TRANSFORMCONSTRAINT_ENTRIES, _spTransformConstraintTimeline_apply, _spTransformConstraintTimeline_getPropertyId); } void spTransformConstraintTimeline_setFrame (spTransformConstraintTimeline* self, int frameIndex, float time, float rotateMix, float translateMix, float scaleMix, float shearMix) { @@ -918,37 +1058,48 @@ static const int PATHCONSTRAINTPOSITION_PREV_VALUE = -1; static const int PATHCONSTRAINTPOSITION_VALUE = 1; void _spPathConstraintPositionTimeline_apply(const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { + spEvent** firedEvents, int* eventsCount, float alpha, int setupPose, int mixingOut) { int frame; float frameTime, percent, position; spPathConstraint* constraint; spPathConstraintPositionTimeline* self = (spPathConstraintPositionTimeline*)timeline; + float* frames; + int framesCount; if (time < self->frames[0]) return; /* Time is before first frame. */ constraint = skeleton->pathConstraints[self->pathConstraintIndex]; - if (time >= self->frames[self->framesCount - PATHCONSTRAINTPOSITION_ENTRIES]) { /* Time is after last frame. */ - int len = self->framesCount; - constraint->position += (self->frames[len + PATHCONSTRAINTPOSITION_PREV_VALUE] - constraint->position) * alpha; - return; + frames = self->frames; + framesCount = self->framesCount; + if (time >= frames[framesCount - PATHCONSTRAINTPOSITION_ENTRIES]) /* Time is after last frame. */ + position = frames[framesCount + PATHCONSTRAINTPOSITION_PREV_VALUE]; + else { + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(frames, framesCount, time, PATHCONSTRAINTPOSITION_ENTRIES); + position = frames[frame + PATHCONSTRAINTPOSITION_PREV_VALUE]; + frameTime = frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / PATHCONSTRAINTPOSITION_ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + PATHCONSTRAINTPOSITION_PREV_TIME] - frameTime)); + + position += (frames[frame + PATHCONSTRAINTPOSITION_VALUE] - position) * percent; } - - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, PATHCONSTRAINTPOSITION_ENTRIES); - position = self->frames[frame + PATHCONSTRAINTPOSITION_PREV_VALUE]; - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / PATHCONSTRAINTPOSITION_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + PATHCONSTRAINTPOSITION_PREV_TIME] - frameTime)); - - constraint->position += (position + (self->frames[frame + PATHCONSTRAINTPOSITION_VALUE] - position) * percent - constraint->position) * alpha; + if (setupPose) + constraint->position = constraint->data->position + (position - constraint->data->position) * alpha; + else + constraint->position += (position - constraint->position) * alpha; UNUSED(lastTime); UNUSED(firedEvents); UNUSED(eventsCount); } +int _spPathConstraintPositionTimeline_getPropertyId (const spTimeline* timeline) { + return (SP_TIMELINE_PATHCONSTRAINTPOSITION << 24) + SUB_CAST(spPathConstraintPositionTimeline, timeline)->pathConstraintIndex; +} + spPathConstraintPositionTimeline* spPathConstraintPositionTimeline_create (int framesCount) { - return (spPathConstraintPositionTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_PATHCONSTRAINTPOSITION, PATHCONSTRAINTPOSITION_ENTRIES, _spPathConstraintPositionTimeline_apply); + return (spPathConstraintPositionTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_PATHCONSTRAINTPOSITION, PATHCONSTRAINTPOSITION_ENTRIES, _spPathConstraintPositionTimeline_apply, _spPathConstraintPositionTimeline_getPropertyId); } void spPathConstraintPositionTimeline_setFrame (spPathConstraintPositionTimeline* self, int frameIndex, float time, float value) { @@ -963,37 +1114,49 @@ static const int PATHCONSTRAINTSPACING_PREV_VALUE = -1; static const int PATHCONSTRAINTSPACING_VALUE = 1; void _spPathConstraintSpacingTimeline_apply(const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { + spEvent** firedEvents, int* eventsCount, float alpha, int setupPose, int mixingOut) { int frame; float frameTime, percent, spacing; spPathConstraint* constraint; spPathConstraintSpacingTimeline* self = (spPathConstraintSpacingTimeline*)timeline; + float* frames; + int framesCount; if (time < self->frames[0]) return; /* Time is before first frame. */ constraint = skeleton->pathConstraints[self->pathConstraintIndex]; - if (time >= self->frames[self->framesCount - PATHCONSTRAINTSPACING_ENTRIES]) { /* Time is after last frame. */ - int len = self->framesCount; - constraint->spacing += (self->frames[len + PATHCONSTRAINTSPACING_PREV_VALUE] - constraint->spacing) * alpha; - return; + frames = self->frames; + framesCount = self->framesCount; + if (time >= frames[framesCount - PATHCONSTRAINTSPACING_ENTRIES]) /* Time is after last frame. */ + spacing = frames[framesCount + PATHCONSTRAINTSPACING_PREV_VALUE]; + else { + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(frames, framesCount, time, PATHCONSTRAINTSPACING_ENTRIES); + spacing = frames[frame + PATHCONSTRAINTSPACING_PREV_VALUE]; + frameTime = frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / PATHCONSTRAINTSPACING_ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + PATHCONSTRAINTSPACING_PREV_TIME] - frameTime)); + + spacing += (frames[frame + PATHCONSTRAINTSPACING_VALUE] - spacing) * percent; } - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, PATHCONSTRAINTSPACING_ENTRIES); - spacing = self->frames[frame + PATHCONSTRAINTSPACING_PREV_VALUE]; - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / PATHCONSTRAINTSPACING_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + PATHCONSTRAINTSPACING_PREV_TIME] - frameTime)); - - constraint->spacing += (spacing + (self->frames[frame + PATHCONSTRAINTSPACING_VALUE] - spacing) * percent - constraint->spacing) * alpha; + if (setupPose) + constraint->spacing = constraint->data->spacing + (spacing - constraint->data->spacing) * alpha; + else + constraint->spacing += (spacing - constraint->spacing) * alpha; UNUSED(lastTime); UNUSED(firedEvents); UNUSED(eventsCount); } +int _spPathConstraintSpacingTimeline_getPropertyId (const spTimeline* timeline) { + return (SP_TIMELINE_PATHCONSTRAINTSPACING << 24) + SUB_CAST(spPathConstraintSpacingTimeline, timeline)->pathConstraintIndex; +} + spPathConstraintSpacingTimeline* spPathConstraintSpacingTimeline_create (int framesCount) { - return (spPathConstraintSpacingTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_PATHCONSTRAINTSPACING, PATHCONSTRAINTSPACING_ENTRIES, _spPathConstraintSpacingTimeline_apply); + return (spPathConstraintSpacingTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_PATHCONSTRAINTSPACING, PATHCONSTRAINTSPACING_ENTRIES, _spPathConstraintSpacingTimeline_apply, _spPathConstraintSpacingTimeline_getPropertyId); } void spPathConstraintSpacingTimeline_setFrame (spPathConstraintSpacingTimeline* self, int frameIndex, float time, float value) { @@ -1011,40 +1174,55 @@ static const int PATHCONSTRAINTMIX_ROTATE = 1; static const int PATHCONSTRAINTMIX_TRANSLATE = 2; void _spPathConstraintMixTimeline_apply(const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, - spEvent** firedEvents, int* eventsCount, float alpha) { + spEvent** firedEvents, int* eventsCount, float alpha, int setupPose, int mixingOut) { int frame; float frameTime, percent, rotate, translate; spPathConstraint* constraint; spPathConstraintMixTimeline* self = (spPathConstraintMixTimeline*)timeline; + float* frames; + int framesCount; if (time < self->frames[0]) return; /* Time is before first frame. */ constraint = skeleton->pathConstraints[self->pathConstraintIndex]; - if (time >= self->frames[self->framesCount - PATHCONSTRAINTMIX_ENTRIES]) { /* Time is after last frame. */ - int len = self->framesCount; - constraint->rotateMix += (self->frames[len + PATHCONSTRAINTMIX_PREV_ROTATE] - constraint->rotateMix) * alpha; - constraint->translateMix += (self->frames[len + PATHCONSTRAINTMIX_PREV_TRANSLATE] - constraint->translateMix) * alpha; - return; + frames = self->frames; + framesCount = self->framesCount; + if (time >= frames[framesCount - PATHCONSTRAINTMIX_ENTRIES]) { /* Time is after last frame. */ + rotate = frames[framesCount + PATHCONSTRAINTMIX_PREV_ROTATE]; + translate = frames[framesCount + PATHCONSTRAINTMIX_PREV_TRANSLATE]; + } else { + /* Interpolate between the previous frame and the current frame. */ + frame = binarySearch(frames, framesCount, time, PATHCONSTRAINTMIX_ENTRIES); + rotate = frames[frame + PATHCONSTRAINTMIX_PREV_ROTATE]; + translate = frames[frame + PATHCONSTRAINTMIX_PREV_TRANSLATE]; + frameTime = frames[frame]; + percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / PATHCONSTRAINTMIX_ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + PATHCONSTRAINTMIX_PREV_TIME] - frameTime)); + + rotate += (frames[frame + PATHCONSTRAINTMIX_ROTATE] - rotate) * percent; + translate += (frames[frame + PATHCONSTRAINTMIX_TRANSLATE] - translate) * percent; } - /* Interpolate between the previous frame and the current frame. */ - frame = binarySearch(self->frames, self->framesCount, time, PATHCONSTRAINTMIX_ENTRIES); - rotate = self->frames[frame + PATHCONSTRAINTMIX_PREV_ROTATE]; - translate = self->frames[frame + PATHCONSTRAINTMIX_PREV_TRANSLATE]; - frameTime = self->frames[frame]; - percent = spCurveTimeline_getCurvePercent(SUPER(self), frame / PATHCONSTRAINTMIX_ENTRIES - 1, 1 - (time - frameTime) / (self->frames[frame + PATHCONSTRAINTMIX_PREV_TIME] - frameTime)); - - constraint->rotateMix += (rotate + (self->frames[frame + PATHCONSTRAINTMIX_ROTATE] - rotate) * percent - constraint->rotateMix) * alpha; - constraint->translateMix += (translate + (self->frames[frame + PATHCONSTRAINTMIX_TRANSLATE] - translate) * percent - constraint->translateMix) * alpha; + if (setupPose) { + constraint->rotateMix = constraint->data->rotateMix + (rotate - constraint->data->rotateMix) * alpha; + constraint->translateMix = constraint->data->translateMix + (translate - constraint->data->translateMix) * alpha; + } else { + constraint->rotateMix += (rotate - constraint->rotateMix) * alpha; + constraint->translateMix += (translate - constraint->translateMix) * alpha; + } UNUSED(lastTime); UNUSED(firedEvents); UNUSED(eventsCount); } +int _spPathConstraintMixTimeline_getPropertyId (const spTimeline* timeline) { + return (SP_TIMELINE_PATHCONSTRAINTMIX << 24) + SUB_CAST(spPathConstraintMixTimeline, timeline)->pathConstraintIndex; +} + spPathConstraintMixTimeline* spPathConstraintMixTimeline_create (int framesCount) { - return (spPathConstraintMixTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_PATHCONSTRAINTMIX, PATHCONSTRAINTMIX_ENTRIES, _spPathConstraintMixTimeline_apply); + return (spPathConstraintMixTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_PATHCONSTRAINTMIX, PATHCONSTRAINTMIX_ENTRIES, _spPathConstraintMixTimeline_apply, _spPathConstraintMixTimeline_getPropertyId); } void spPathConstraintMixTimeline_setFrame (spPathConstraintMixTimeline* self, int frameIndex, float time, float rotateMix, float translateMix) {