diff --git a/spine-c/spine-c/include/spine/Animation.h b/spine-c/spine-c/include/spine/Animation.h index ed5fd42e4..242896f1a 100644 --- a/spine-c/spine-c/include/spine/Animation.h +++ b/spine-c/spine-c/include/spine/Animation.h @@ -101,8 +101,17 @@ typedef enum { SP_TIMELINE_TRANSLATE, SP_TIMELINE_DEFORM, SP_TIMELINE_SEQUENCE, + SP_TIMELINE_INHERIT, SP_TIMELINE_IKCONSTRAINT, SP_TIMELINE_PATHCONSTRAINTMIX, + SP_TIMELINE_PHYSICSCONSTRAINT_INERTIA, + SP_TIMELINE_PHYSICSCONSTRAINT_STRENGTH, + SP_TIMELINE_PHYSICSCONSTRAINT_DAMPING, + SP_TIMELINE_PHYSICSCONSTRAINT_MASS, + SP_TIMELINE_PHYSICSCONSTRAINT_WIND, + SP_TIMELINE_PHYSICSCONSTRAINT_GRAVITY, + SP_TIMELINE_PHYSICSCONSTRAINT_MIX, + SP_TIMELINE_PHYSICSCONSTRAINT_RESET, SP_TIMELINE_RGB2, SP_TIMELINE_RGBA2, SP_TIMELINE_RGBA, @@ -122,19 +131,28 @@ typedef enum { SP_PROPERTY_SCALEY = 1 << 4, SP_PROPERTY_SHEARX = 1 << 5, SP_PROPERTY_SHEARY = 1 << 6, - SP_PROPERTY_RGB = 1 << 7, - SP_PROPERTY_ALPHA = 1 << 8, - SP_PROPERTY_RGB2 = 1 << 9, - SP_PROPERTY_ATTACHMENT = 1 << 10, - SP_PROPERTY_DEFORM = 1 << 11, - SP_PROPERTY_EVENT = 1 << 12, - SP_PROPERTY_DRAWORDER = 1 << 13, - SP_PROPERTY_IKCONSTRAINT = 1 << 14, - SP_PROPERTY_TRANSFORMCONSTRAINT = 1 << 15, - SP_PROPERTY_PATHCONSTRAINT_POSITION = 1 << 16, - SP_PROPERTY_PATHCONSTRAINT_SPACING = 1 << 17, - SP_PROPERTY_PATHCONSTRAINT_MIX = 1 << 18, - SP_PROPERTY_SEQUENCE = 1 << 19 + SP_PROPERTY_INHERIT = 1 << 7, + SP_PROPERTY_RGB = 1 << 8, + SP_PROPERTY_ALPHA = 1 << 9, + SP_PROPERTY_RGB2 = 1 << 10, + SP_PROPERTY_ATTACHMENT = 1 << 11, + SP_PROPERTY_DEFORM = 1 << 12, + SP_PROPERTY_EVENT = 1 << 13, + SP_PROPERTY_DRAWORDER = 1 << 14, + SP_PROPERTY_IKCONSTRAINT = 1 << 15, + SP_PROPERTY_TRANSFORMCONSTRAINT = 1 << 16, + SP_PROPERTY_PATHCONSTRAINT_POSITION = 1 << 17, + SP_PROPERTY_PATHCONSTRAINT_SPACING = 1 << 18, + SP_PROPERTY_PATHCONSTRAINT_MIX = 1 << 19, + SP_PROPERTY_PHYSICSCONSTRAINT_INERTIA = 1 << 20, + SP_PROPERTY_PHYSICSCONSTRAINT_STRENGTH = 1 << 21, + SP_PROPERTY_PHYSICSCONSTRAINT_DAMPING = 1 << 22, + SP_PROPERTY_PHYSICSCONSTRAINT_MASS = 1 << 23, + SP_PROPERTY_PHYSICSCONSTRAINT_WIND = 1 << 24, + SP_PROPERTY_PHYSICSCONSTRAINT_GRAVITY = 1 << 25, + SP_PROPERTY_PHYSICSCONSTRAINT_MIX = 1 << 26, + SP_PROPERTY_PHYSICSCONSTRAINT_RESET = 1 << 27, + SP_PROPERTY_SEQUENCE = 1 << 28 } spProperty; #define SP_MAX_PROPERTY_IDS 3 @@ -196,6 +214,14 @@ SP_API void spCurveTimeline1_setFrame(spCurveTimeline1 *self, int frame, float t SP_API float spCurveTimeline1_getCurveValue(spCurveTimeline1 *self, float time); +SP_API float spCurveTimeline1_getRelativeValue(spCurveTimeline1 *timeline, float time, float alpha, spMixBlend blend, float current, float setup); + +SP_API float spCurveTimeline1_getAbsoluteValue(spCurveTimeline1 *timeline, float time, float alpha, spMixBlend blend, float current, float setup); + +SP_API float spCurveTimeline1_getAbsoluteValue2(spCurveTimeline1 *timeline, float time, float alpha, spMixBlend blend, float current, float setup, float value); + +SP_API float spCurveTimeline1_getScaleValue (spCurveTimeline1 *timeline, float time, float alpha, spMixBlend blend, spMixDirection direction, float current, float setup); + typedef struct spCurveTimeline spCurveTimeline2; SP_API void spCurveTimeline2_setFrame(spCurveTimeline1 *self, int frame, float time, float value1, float value2); @@ -437,6 +463,18 @@ SP_API spDrawOrderTimeline *spDrawOrderTimeline_create(int framesCount, int slot SP_API void spDrawOrderTimeline_setFrame(spDrawOrderTimeline *self, int frameIndex, float time, const int *drawOrder); +/**/ + +typedef struct spInheritTimeline { + spTimeline super; + int boneIndex; +} spInheritTimeline; + +SP_API spInheritTimeline *spInheritTimeline_create(int framesCount, int boneIndex); + +SP_API void spInheritTimeline_setFrame(spDrawOrderTimeline *self, int frameIndex, float time, spInherit inherit); + + /**/ typedef struct spIkConstraintTimeline { @@ -508,6 +546,27 @@ spPathConstraintMixTimeline_setFrame(spPathConstraintMixTimeline *self, int fram /**/ +typedef struct spPhysicsConstraintTimeline { + spCurveTimeline super; + int physicsConstraintIndex; +} spPhysicsConstraintTimeline; + +SP_API spPhysicsConstraintTimeline * +spPhysicsConstraintTimeline_create(int framesCount, int bezierCount, int physicsConstraintIndex, spTimelineType type); + +SP_API void spPhysicsConstraintTimeline_setFrame(spPhysicsConstraintTimeline *self, int frame, float time, float value); + +/**/ + +typedef struct spPhysicsConstraintResetTimeline { + spTimeline super; + int physicsConstraintIndex; +} spPhysicsConstraintResetTimeline; + +SP_API spPhysicsConstraintResetTimeline *spPhysicsConstraintResetTimeline_create(int framesCount, int boneIndex); + +SP_API void spPhysicsConstraintResetTimeline_setFrame(spPhysicsConstraintResetTimeline *self, int frameIndex, float time); + #ifdef __cplusplus } #endif diff --git a/spine-c/spine-c/include/spine/AnimationState.h b/spine-c/spine-c/include/spine/AnimationState.h index 20a9fad43..02349b946 100644 --- a/spine-c/spine-c/include/spine/AnimationState.h +++ b/spine-c/spine-c/include/spine/AnimationState.h @@ -69,7 +69,7 @@ struct spTrackEntry { int /*boolean*/ holdPrevious; int /*boolean*/ reverse; int /*boolean*/ shortestRotation; - float eventThreshold, attachmentThreshold, drawOrderThreshold; + float eventThreshold, mixAttachmentThreshold, alphaAttachmentThreshold, mixDrawOrderThreshold; float animationStart, animationEnd, animationLast, nextAnimationLast; float delay, trackTime, trackLast, nextTrackLast, trackEnd, timeScale; float alpha, mixTime, mixDuration, interruptAlpha, totalAlpha; @@ -146,6 +146,10 @@ SP_API void spTrackEntry_resetRotationDirections(spTrackEntry *entry); SP_API float spTrackEntry_getTrackComplete(spTrackEntry *entry); +SP_API void spTrackEntry_setMixDuration(spTrackEntry *entry, float mixDuration, float delay); + +SP_API int/*bool*/ spTrackEntry_wasApplied(spTrackEntry *entry); + SP_API void spAnimationState_clearNext(spAnimationState *self, spTrackEntry *entry); /** Use this to dispose static memory before your app exits to appease your memory leak detector*/ diff --git a/spine-c/spine-c/include/spine/IkConstraint.h b/spine-c/spine-c/include/spine/IkConstraint.h index 0f6b9a898..49786df19 100644 --- a/spine-c/spine-c/include/spine/IkConstraint.h +++ b/spine-c/spine-c/include/spine/IkConstraint.h @@ -62,6 +62,8 @@ SP_API void spIkConstraint_dispose(spIkConstraint *self); SP_API void spIkConstraint_update(spIkConstraint *self); +SP_API void spIkConstraint_setToSetupPose(spIkConstraint *self); + SP_API void spIkConstraint_apply1(spBone *bone, float targetX, float targetY, int /*boolean*/ compress, int /*boolean*/ stretch, int /*boolean*/ uniform, float alpha); diff --git a/spine-c/spine-c/include/spine/PathConstraint.h b/spine-c/spine-c/include/spine/PathConstraint.h index 2b190bfda..8fa0d4e39 100644 --- a/spine-c/spine-c/include/spine/PathConstraint.h +++ b/spine-c/spine-c/include/spine/PathConstraint.h @@ -78,6 +78,8 @@ SP_API void spPathConstraint_dispose(spPathConstraint *self); SP_API void spPathConstraint_update(spPathConstraint *self); +SP_API void spPathConstraint_setToSetupPose(spPathConstraint *self); + SP_API float *spPathConstraint_computeWorldPositions(spPathConstraint *self, spPathAttachment *path, int spacesCount, int/*bool*/ tangents); diff --git a/spine-c/spine-c/include/spine/Skeleton.h b/spine-c/spine-c/include/spine/Skeleton.h index 2afc3d264..59537cf68 100644 --- a/spine-c/spine-c/include/spine/Skeleton.h +++ b/spine-c/spine-c/include/spine/Skeleton.h @@ -130,6 +130,10 @@ SP_API spPathConstraint *spSkeleton_findPathConstraint(const spSkeleton *self, c /* Returns 0 if the physics constraint was not found. */ SP_API spPhysicsConstraint *spSkeleton_findPhysicsConstraint(const spSkeleton *self, const char *constraintName); +SP_API void spSkeleton_physicsTranslate(spSkeleton *self, float x, float y); + +SP_API void spSkeleton_physicsRotate(spSkeleton *self, float x, float y, float degrees); + #ifdef __cplusplus } #endif diff --git a/spine-c/spine-c/include/spine/Skin.h b/spine-c/spine-c/include/spine/Skin.h index c7a5f576a..ae646fc29 100644 --- a/spine-c/spine-c/include/spine/Skin.h +++ b/spine-c/spine-c/include/spine/Skin.h @@ -35,6 +35,7 @@ #include #include #include +#include #include #ifdef __cplusplus @@ -54,6 +55,8 @@ _SP_ARRAY_DECLARE_TYPE(spTransformConstraintDataArray, spTransformConstraintData _SP_ARRAY_DECLARE_TYPE(spPathConstraintDataArray, spPathConstraintData*) +_SP_ARRAY_DECLARE_TYPE(spPhysicsConstraintDataArray, spPhysicsConstraintData*) + typedef struct spSkin { char *name; @@ -61,6 +64,7 @@ typedef struct spSkin { spIkConstraintDataArray *ikConstraints; spTransformConstraintDataArray *transformConstraints; spPathConstraintDataArray *pathConstraints; + spPhysicsConstraintDataArray *physicsConstraints; spColor color; } spSkin; diff --git a/spine-c/spine-c/include/spine/TransformConstraint.h b/spine-c/spine-c/include/spine/TransformConstraint.h index db8e8d340..30158cfd9 100644 --- a/spine-c/spine-c/include/spine/TransformConstraint.h +++ b/spine-c/spine-c/include/spine/TransformConstraint.h @@ -56,6 +56,8 @@ SP_API void spTransformConstraint_dispose(spTransformConstraint *self); SP_API void spTransformConstraint_update(spTransformConstraint *self); +SP_API void spTransformConstraint_setToSetupPose(spTransformConstraint *self); + #ifdef __cplusplus } #endif diff --git a/spine-c/spine-c/src/spine/Animation.c b/spine-c/spine-c/src/spine/Animation.c index 125ed2625..3a80425bb 100644 --- a/spine-c/spine-c/src/spine/Animation.c +++ b/spine-c/spine-c/src/spine/Animation.c @@ -298,6 +298,110 @@ float spCurveTimeline1_getCurveValue(spCurveTimeline1 *self, float time) { return _spCurveTimeline_getBezierValue(self, time, i, CURVE1_VALUE, curveType - CURVE_BEZIER); } +float spCurveTimeline1_getRelativeValue(spCurveTimeline1 *self, float time, float alpha, spMixBlend blend, float current, float setup) { + float *frames = self->super.frames->items; + if (time < frames[0]) { + switch (blend) { + case SP_MIX_BLEND_SETUP: + return setup; + case SP_MIX_BLEND_FIRST: + return current + (setup - current) * alpha; + default: + return current; + } + } + float value = spCurveTimeline1_getCurveValue(self, time); + switch (blend) { + case SP_MIX_BLEND_SETUP: + return setup + value * alpha; + case SP_MIX_BLEND_FIRST: + case SP_MIX_BLEND_REPLACE: + value += setup - current; + break; + case SP_MIX_BLEND_ADD: + break; + } + return current + value * alpha; +} + +float spCurveTimeline1_getAbsoluteValue(spCurveTimeline1 *self, float time, float alpha, spMixBlend blend, float current, float setup) { + float *frames = self->super.frames->items; + if (time < frames[0]) { + switch (blend) { + case SP_MIX_BLEND_SETUP: + return setup; + case SP_MIX_BLEND_FIRST: + return current + (setup - current) * alpha; + default: + return current; + } + } + float value = spCurveTimeline1_getCurveValue(self, time); + if (blend == SP_MIX_BLEND_SETUP) return setup + (value - setup) * alpha; + return current + (value - current) * alpha; +} + +float spCurveTimeline1_getAbsoluteValue2(spCurveTimeline1 *self, float time, float alpha, spMixBlend blend, float current, float setup, float value) { + float *frames = self->super.frames->items; + if (time < frames[0]) { + switch (blend) { + case SP_MIX_BLEND_SETUP: + return setup; + case SP_MIX_BLEND_FIRST: + return current + (setup - current) * alpha; + default: + return current; + } + } + if (blend == SP_MIX_BLEND_SETUP) return setup + (value - setup) * alpha; + return current + (value - current) * alpha; +} + +float spCurveTimeline1_getScaleValue (spCurveTimeline1 *self, float time, float alpha, spMixBlend blend, spMixDirection direction, float current, float setup) { + float *frames = self->super.frames->items; + if (time < frames[0]) { + switch (blend) { + case SP_MIX_BLEND_SETUP: + return setup; + case SP_MIX_BLEND_FIRST: + return current + (setup - current) * alpha; + default: + return current; + } + } + float value = spCurveTimeline1_getCurveValue(self, time) * setup; + if (alpha == 1) { + if (blend == SP_MIX_BLEND_ADD) return current + value - setup; + return value; + } + // Mixing out uses sign of setup or current pose, else use sign of key. + if (direction == SP_MIX_DIRECTION_OUT) { + switch (blend) { + case SP_MIX_BLEND_SETUP: + return setup + (ABS(value) * SIGNUM(setup) - setup) * alpha; + case SP_MIX_BLEND_FIRST: + case SP_MIX_BLEND_REPLACE: + return current + (ABS(value) * SIGNUM(current) - current) * alpha; + default: + break; + } + } else { + float s; + switch (blend) { + case SP_MIX_BLEND_SETUP: + s = ABS(setup) * SIGNUM(value); + return s + (value - s) * alpha; + case SP_MIX_BLEND_FIRST: + case SP_MIX_BLEND_REPLACE: + s = ABS(current) * SIGNUM(value); + return s + (value - s) * alpha; + default: + break; + } + } + return current + (value - setup) * alpha; +} + #define CURVE2_ENTRIES 3 #define CURVE2_VALUE1 1 #define CURVE2_VALUE2 2 @@ -314,40 +418,11 @@ SP_API void spCurveTimeline2_setFrame(spCurveTimeline1 *self, int frame, float t void _spRotateTimeline_apply(spTimeline *timeline, spSkeleton *skeleton, float lastTime, float time, spEvent **firedEvents, int *eventsCount, float alpha, spMixBlend blend, spMixDirection direction) { - spBone *bone; - float r; spRotateTimeline *self = SUB_CAST(spRotateTimeline, timeline); - float *frames = self->super.super.frames->items; + spBone *bone = skeleton->bones[self->boneIndex]; + if (bone->active) bone->rotation = spCurveTimeline1_getRelativeValue(SUPER(self), time, alpha, blend, bone->rotation, bone->data->rotation); - bone = skeleton->bones[self->boneIndex]; - if (!bone->active) return; - - if (time < frames[0]) { - switch (blend) { - case SP_MIX_BLEND_SETUP: - bone->rotation = bone->data->rotation; - return; - case SP_MIX_BLEND_FIRST: - bone->rotation += (bone->data->rotation - bone->rotation) * alpha; - default: { - } - } - return; - } - - r = spCurveTimeline1_getCurveValue(SUPER(self), time); - switch (blend) { - case SP_MIX_BLEND_SETUP: - bone->rotation = bone->data->rotation + r * alpha; - break; - case SP_MIX_BLEND_FIRST: - case SP_MIX_BLEND_REPLACE: - r += bone->data->rotation - bone->rotation; - case SP_MIX_BLEND_ADD: - bone->rotation += r * alpha; - } - - UNUSED(lastTime); + UNUSED(lastTime); UNUSED(firedEvents); UNUSED(eventsCount); UNUSED(direction); @@ -709,69 +784,12 @@ void spScaleTimeline_setFrame(spScaleTimeline *self, int frame, float time, floa void _spScaleXTimeline_apply(spTimeline *timeline, spSkeleton *skeleton, float lastTime, float time, spEvent **firedEvents, int *eventsCount, float alpha, spMixBlend blend, spMixDirection direction) { - spBone *bone; - float x; - spScaleXTimeline *self = SUB_CAST(spScaleXTimeline, timeline); - float *frames = self->super.super.frames->items; + spBone *bone = skeleton->bones[self->boneIndex]; - bone = skeleton->bones[self->boneIndex]; - if (!bone->active) return; + if (bone->active) bone->scaleX = spCurveTimeline1_getScaleValue(SUPER(self), time, alpha, blend, direction, bone->scaleX, bone->data->scaleX); - if (time < frames[0]) { - switch (blend) { - case SP_MIX_BLEND_SETUP: - bone->scaleX = bone->data->scaleX; - return; - case SP_MIX_BLEND_FIRST: - bone->scaleX += (bone->data->scaleX - bone->scaleX) * alpha; - default: { - } - } - return; - } - - x = spCurveTimeline1_getCurveValue(SUPER(self), time) * bone->data->scaleX; - if (alpha == 1) { - if (blend == SP_MIX_BLEND_ADD) - bone->scaleX += x - bone->data->scaleX; - else - bone->scaleX = x; - } else { - /* Mixing out uses sign of setup or current pose, else use sign of key. */ - float bx; - if (direction == SP_MIX_DIRECTION_OUT) { - switch (blend) { - case SP_MIX_BLEND_SETUP: - bx = bone->data->scaleX; - bone->scaleX = bx + (ABS(x) * SIGNUM(bx) - bx) * alpha; - break; - case SP_MIX_BLEND_FIRST: - case SP_MIX_BLEND_REPLACE: - bx = bone->scaleX; - bone->scaleX = bx + (ABS(x) * SIGNUM(bx) - bx) * alpha; - break; - case SP_MIX_BLEND_ADD: - bone->scaleX += (x - bone->data->scaleX) * alpha; - } - } else { - switch (blend) { - case SP_MIX_BLEND_SETUP: - bx = ABS(bone->data->scaleX) * SIGNUM(x); - bone->scaleX = bx + (x - bx) * alpha; - break; - case SP_MIX_BLEND_FIRST: - case SP_MIX_BLEND_REPLACE: - bx = ABS(bone->scaleX) * SIGNUM(x); - bone->scaleX = bx + (x - bx) * alpha; - break; - case SP_MIX_BLEND_ADD: - bone->scaleX += (x - bone->data->scaleX) * alpha; - } - } - } - - UNUSED(lastTime); + UNUSED(lastTime); UNUSED(firedEvents); UNUSED(eventsCount); } @@ -795,69 +813,12 @@ void spScaleXTimeline_setFrame(spScaleXTimeline *self, int frame, float time, fl void _spScaleYTimeline_apply(spTimeline *timeline, spSkeleton *skeleton, float lastTime, float time, spEvent **firedEvents, int *eventsCount, float alpha, spMixBlend blend, spMixDirection direction) { - spBone *bone; - float y; - spScaleYTimeline *self = SUB_CAST(spScaleYTimeline, timeline); - float *frames = self->super.super.frames->items; + spBone *bone = skeleton->bones[self->boneIndex]; - bone = skeleton->bones[self->boneIndex]; - if (!bone->active) return; + if (bone->active) bone->scaleY = spCurveTimeline1_getScaleValue(SUPER(self), time, alpha, blend, direction, bone->scaleX, bone->data->scaleY); - if (time < frames[0]) { - switch (blend) { - case SP_MIX_BLEND_SETUP: - bone->scaleY = bone->data->scaleY; - return; - case SP_MIX_BLEND_FIRST: - bone->scaleY += (bone->data->scaleY - bone->scaleY) * alpha; - default: { - } - } - return; - } - - y = spCurveTimeline1_getCurveValue(SUPER(self), time) * bone->data->scaleY; - if (alpha == 1) { - if (blend == SP_MIX_BLEND_ADD) - bone->scaleY += y - bone->data->scaleY; - else - bone->scaleY = y; - } else { - /* Mixing out uses sign of setup or current pose, else use sign of key. */ - float by = 0; - if (direction == SP_MIX_DIRECTION_OUT) { - switch (blend) { - case SP_MIX_BLEND_SETUP: - by = bone->data->scaleY; - bone->scaleY = by + (ABS(y) * SIGNUM(by) - by) * alpha; - break; - case SP_MIX_BLEND_FIRST: - case SP_MIX_BLEND_REPLACE: - by = bone->scaleY; - bone->scaleY = by + (ABS(y) * SIGNUM(by) - by) * alpha; - break; - case SP_MIX_BLEND_ADD: - bone->scaleY += (y - bone->data->scaleY) * alpha; - } - } else { - switch (blend) { - case SP_MIX_BLEND_SETUP: - by = ABS(bone->data->scaleY) * SIGNUM(y); - bone->scaleY = by + (y - by) * alpha; - break; - case SP_MIX_BLEND_FIRST: - case SP_MIX_BLEND_REPLACE: - by = ABS(bone->scaleY) * SIGNUM(y); - bone->scaleY = by + (y - by) * alpha; - break; - case SP_MIX_BLEND_ADD: - bone->scaleY += (y - bone->data->scaleY) * alpha; - } - } - } - - UNUSED(lastTime); + UNUSED(lastTime); UNUSED(firedEvents); UNUSED(eventsCount); } @@ -970,41 +931,12 @@ void spShearTimeline_setFrame(spShearTimeline *self, int frame, float time, floa void _spShearXTimeline_apply(spTimeline *timeline, spSkeleton *skeleton, float lastTime, float time, spEvent **firedEvents, int *eventsCount, float alpha, spMixBlend blend, spMixDirection direction) { - spBone *bone; - float x; - spShearXTimeline *self = SUB_CAST(spShearXTimeline, timeline); - float *frames = self->super.super.frames->items; + spBone *bone = skeleton->bones[self->boneIndex]; - bone = skeleton->bones[self->boneIndex]; - if (!bone->active) return; + if (bone->active) bone->shearX = spCurveTimeline1_getRelativeValue(SUPER(self), time, alpha, blend, bone->shearX, bone->data->shearX); - if (time < frames[0]) { - switch (blend) { - case SP_MIX_BLEND_SETUP: - bone->shearX = bone->data->shearX; - return; - case SP_MIX_BLEND_FIRST: - bone->shearX += (bone->data->shearX - bone->shearX) * alpha; - default: { - } - } - return; - } - - x = spCurveTimeline1_getCurveValue(SUPER(self), time); - switch (blend) { - case SP_MIX_BLEND_SETUP: - bone->shearX = bone->data->shearX + x * alpha; - break; - case SP_MIX_BLEND_FIRST: - case SP_MIX_BLEND_REPLACE: - bone->shearX += (bone->data->shearX + x - bone->shearX) * alpha; - break; - case SP_MIX_BLEND_ADD: - bone->shearX += x * alpha; - } - UNUSED(lastTime); + UNUSED(lastTime); UNUSED(firedEvents); UNUSED(eventsCount); UNUSED(direction); @@ -1029,42 +961,12 @@ void spShearXTimeline_setFrame(spShearXTimeline *self, int frame, float time, fl void _spShearYTimeline_apply(spTimeline *timeline, spSkeleton *skeleton, float lastTime, float time, spEvent **firedEvents, int *eventsCount, float alpha, spMixBlend blend, spMixDirection direction) { - spBone *bone; - float y; - spShearYTimeline *self = SUB_CAST(spShearYTimeline, timeline); - float *frames = self->super.super.frames->items; + spBone *bone = skeleton->bones[self->boneIndex]; - bone = skeleton->bones[self->boneIndex]; - if (!bone->active) return; + if (bone->active) bone->shearY = spCurveTimeline1_getRelativeValue(SUPER(self), time, alpha, blend, bone->shearY, bone->data->shearY); - if (time < frames[0]) { - switch (blend) { - case SP_MIX_BLEND_SETUP: - bone->shearY = bone->data->shearY; - return; - case SP_MIX_BLEND_FIRST: - bone->shearY += (bone->data->shearY - bone->shearY) * alpha; - default: { - } - } - return; - } - - y = spCurveTimeline1_getCurveValue(SUPER(self), time); - switch (blend) { - case SP_MIX_BLEND_SETUP: - bone->shearY = bone->data->shearY + y * alpha; - break; - case SP_MIX_BLEND_FIRST: - case SP_MIX_BLEND_REPLACE: - bone->shearY += (bone->data->shearY + y - bone->shearY) * alpha; - break; - case SP_MIX_BLEND_ADD: - bone->shearY += y * alpha; - } - - UNUSED(lastTime); + UNUSED(lastTime); UNUSED(firedEvents); UNUSED(eventsCount); UNUSED(direction); @@ -2053,7 +1955,7 @@ void _spSequenceTimeline_apply(spTimeline *timeline, spSkeleton *skeleton, float count = sequence->regions->size; mode = modeAndIndex & 0xf; if (mode != SP_SEQUENCE_MODE_HOLD) { - index += (int) (((time - before) / delay + 0.00001)); + index += (int) (((time - before) / delay + 0.0001)); switch (mode) { case SP_SEQUENCE_MODE_ONCE: index = MIN(count - 1, index); @@ -2252,6 +2154,53 @@ void spDrawOrderTimeline_setFrame(spDrawOrderTimeline *self, int frame, float ti } } +/**/ +void _spInheritTimeline_apply(spTimeline *timeline, spSkeleton *skeleton, float lastTime, float time, + spEvent **firedEvents, int *eventsCount, float alpha, spMixBlend blend, + spMixDirection direction) { + spInheritTimeline *self = (spInheritTimeline *)timeline; + spBone *bone = skeleton->bones[self->boneIndex]; + float *frames = self->super.frames->items; + if (!bone->active) return; + + if (time < frames[0]) { + if (blend == SP_MIX_BLEND_SETUP || blend == SP_MIX_BLEND_FIRST) bone->inherit = bone->data->inherit; + return; + } + int idx = search2(self->super.frames, time, 2) + 1; + bone->inherit = (spInherit) frames[idx]; + + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); + UNUSED(alpha); + UNUSED(direction); +} + +void _spInheritTimeline_dispose(spTimeline *timeline) { + // no-op, spTimeline_dispose disposes frames. + UNUSED(timeline); +} + +spInheritTimeline *spInheritTimeline_create(int framesCount, int boneIndex) { + spInheritTimeline *self = NEW(spInheritTimeline); + spPropertyId ids[1]; + ids[0] = (spPropertyId) SP_PROPERTY_INHERIT << 32; + _spTimeline_init(SUPER(self), framesCount, 2, ids, 1, SP_TIMELINE_INHERIT, _spInheritTimeline_dispose, + _spInheritTimeline_apply, 0); + + self->boneIndex = boneIndex; + + return self; +} + +void spInheritTimeline_setFrame(spDrawOrderTimeline *self, int frame, float time, spInherit inherit) { + frame *= 2; + self->super.frames->items[frame] = time; + self->super.frames->items[frame + 1] = inherit; +} + + /**/ static const int IKCONSTRAINT_ENTRIES = 6; @@ -2515,35 +2464,9 @@ static const int PATHCONSTRAINTPOSITION_VALUE = 1; void _spPathConstraintPositionTimeline_apply(spTimeline *timeline, spSkeleton *skeleton, float lastTime, float time, spEvent **firedEvents, int *eventsCount, float alpha, spMixBlend blend, spMixDirection direction) { - float position; - spPathConstraint *constraint; - spPathConstraintPositionTimeline *self = (spPathConstraintPositionTimeline *) timeline; - float *frames; - - constraint = skeleton->pathConstraints[self->pathConstraintIndex]; - if (!constraint->active) return; - - frames = self->super.super.frames->items; - - if (time < frames[0]) { - switch (blend) { - case SP_MIX_BLEND_SETUP: - constraint->position = constraint->data->position; - return; - case SP_MIX_BLEND_FIRST: - constraint->position += (constraint->data->position - constraint->position) * alpha; - return; - default: - return; - } - } - - position = spCurveTimeline1_getCurveValue(SUPER(self), time); - - if (blend == SP_MIX_BLEND_SETUP) - constraint->position = constraint->data->position + (position - constraint->data->position) * alpha; - else - constraint->position += (position - constraint->position) * alpha; + spPathConstraintPositionTimeline *self = (spPathConstraintPositionTimeline *) timeline; + spPathConstraint *constraint = skeleton->pathConstraints[self->pathConstraintIndex]; + if (constraint->active) constraint->position = spCurveTimeline1_getAbsoluteValue(SUPER(self), time, alpha, blend, constraint->position, constraint->data->position); UNUSED(lastTime); UNUSED(firedEvents); @@ -2577,40 +2500,14 @@ static const int PATHCONSTRAINTSPACING_VALUE = 1; void _spPathConstraintSpacingTimeline_apply(spTimeline *timeline, spSkeleton *skeleton, float lastTime, float time, spEvent **firedEvents, int *eventsCount, float alpha, spMixBlend blend, spMixDirection direction) { - float spacing; - spPathConstraint *constraint; - spPathConstraintSpacingTimeline *self = (spPathConstraintSpacingTimeline *) timeline; - float *frames; + spPathConstraintSpacingTimeline *self = (spPathConstraintSpacingTimeline *) timeline; + spPathConstraint *constraint = skeleton->pathConstraints[self->pathConstraintIndex]; + if (constraint->active) constraint->spacing = spCurveTimeline1_getAbsoluteValue(SUPER(self), time, alpha, blend, constraint->spacing, constraint->data->spacing); - constraint = skeleton->pathConstraints[self->pathConstraintIndex]; - if (!constraint->active) return; - - frames = self->super.super.frames->items; - - if (time < frames[0]) { - switch (blend) { - case SP_MIX_BLEND_SETUP: - constraint->spacing = constraint->data->spacing; - return; - case SP_MIX_BLEND_FIRST: - constraint->spacing += (constraint->data->spacing - constraint->spacing) * alpha; - return; - default: - return; - } - } - - spacing = spCurveTimeline1_getCurveValue(SUPER(self), time); - - if (blend == SP_MIX_BLEND_SETUP) - constraint->spacing = constraint->data->spacing + (spacing - constraint->data->spacing) * alpha; - else - constraint->spacing += (spacing - constraint->spacing) * alpha; - - UNUSED(lastTime); - UNUSED(firedEvents); - UNUSED(eventsCount); - UNUSED(direction); + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); + UNUSED(direction); } spPathConstraintSpacingTimeline * @@ -2740,3 +2637,226 @@ void spPathConstraintMixTimeline_setFrame(spPathConstraintMixTimeline *self, int frames[frame + PATHCONSTRAINTMIX_X] = mixX; frames[frame + PATHCONSTRAINTMIX_Y] = mixY; } + +/**/ + +int/*bool*/ _spPhysicsConstraintTimeline_global(spPhysicsConstraintData *data, spTimelineType type) { + switch(type) { + case SP_TIMELINE_PHYSICSCONSTRAINT_INERTIA: + return data->inertiaGlobal; + case SP_TIMELINE_PHYSICSCONSTRAINT_STRENGTH: + return data->strengthGlobal; + case SP_TIMELINE_PHYSICSCONSTRAINT_DAMPING: + return data->dampingGlobal; + case SP_TIMELINE_PHYSICSCONSTRAINT_MASS: + return data->massGlobal; + case SP_TIMELINE_PHYSICSCONSTRAINT_WIND: + return data->windGlobal; + case SP_TIMELINE_PHYSICSCONSTRAINT_GRAVITY: + return data->gravityGlobal; + case SP_TIMELINE_PHYSICSCONSTRAINT_MIX: + return data->mixGlobal; + default: + // should never happen + return 0; + } +} + +void _spPhysicsConstraintTimeline_set(spPhysicsConstraint *constraint, spTimelineType type, float value) { + switch(type) { + case SP_TIMELINE_PHYSICSCONSTRAINT_INERTIA: + constraint->inertia = value; + break; + case SP_TIMELINE_PHYSICSCONSTRAINT_STRENGTH: + constraint->strength = value; + break; + case SP_TIMELINE_PHYSICSCONSTRAINT_DAMPING: + constraint->damping = value; + break; + case SP_TIMELINE_PHYSICSCONSTRAINT_MASS: + constraint->massInverse = value; + break; + case SP_TIMELINE_PHYSICSCONSTRAINT_WIND: + constraint->wind = value; + break; + case SP_TIMELINE_PHYSICSCONSTRAINT_GRAVITY: + constraint->gravity = value; + break; + case SP_TIMELINE_PHYSICSCONSTRAINT_MIX: + constraint->mix = value; + break; + default: + // should never happen + break; + } +} + +float _spPhysicsConstraintTimeline_get(spPhysicsConstraint *constraint, spTimelineType type) { + switch(type) { + case SP_TIMELINE_PHYSICSCONSTRAINT_INERTIA: + return constraint->inertia; + case SP_TIMELINE_PHYSICSCONSTRAINT_STRENGTH: + return constraint->strength; + case SP_TIMELINE_PHYSICSCONSTRAINT_DAMPING: + return constraint->damping; + case SP_TIMELINE_PHYSICSCONSTRAINT_MASS: + return constraint->massInverse; + case SP_TIMELINE_PHYSICSCONSTRAINT_WIND: + return constraint->wind; + case SP_TIMELINE_PHYSICSCONSTRAINT_GRAVITY: + return constraint->gravity; + case SP_TIMELINE_PHYSICSCONSTRAINT_MIX: + return constraint->mix; + default: + // should never happen + return 0; + } +} + +float _spPhysicsConstraintTimeline_setup(spPhysicsConstraint *constraint, spTimelineType type) { + switch(type) { + case SP_TIMELINE_PHYSICSCONSTRAINT_INERTIA: + return constraint->data->inertia; + case SP_TIMELINE_PHYSICSCONSTRAINT_STRENGTH: + return constraint->data->strength; + case SP_TIMELINE_PHYSICSCONSTRAINT_DAMPING: + return constraint->data->damping; + case SP_TIMELINE_PHYSICSCONSTRAINT_MASS: + return constraint->data->massInverse; + case SP_TIMELINE_PHYSICSCONSTRAINT_WIND: + return constraint->data->wind; + case SP_TIMELINE_PHYSICSCONSTRAINT_GRAVITY: + return constraint->data->gravity; + case SP_TIMELINE_PHYSICSCONSTRAINT_MIX: + return constraint->data->mix; + default: + // should never happen + return 0; + } +} + +void _spPhysicsConstraintTimeline_apply(spTimeline *timeline, spSkeleton *skeleton, float lastTime, float time, + spEvent **firedEvents, int *eventsCount, float alpha, spMixBlend blend, + spMixDirection direction) { + spPhysicsConstraintTimeline *self = SUB_CAST(spPhysicsConstraintTimeline, timeline); + spTimelineType type = self->super.super.type; + float *frames = self->super.super.frames->items; + if (self->physicsConstraintIndex == -1) { + float value = time >= frames[0] ? spCurveTimeline1_getCurveValue(SUPER(self), time) : 0; + + spPhysicsConstraint **physicsConstraints = skeleton->physicsConstraints; + for (int i = 0; i < skeleton->physicsConstraintsCount; i++) { + spPhysicsConstraint *constraint = physicsConstraints[i]; + if (constraint->active && _spPhysicsConstraintTimeline_global(constraint->data, type)) + _spPhysicsConstraintTimeline_set(constraint, type,spCurveTimeline1_getAbsoluteValue2(SUPER(self), time, alpha, blend, _spPhysicsConstraintTimeline_get(constraint, type), _spPhysicsConstraintTimeline_setup(constraint, type), value)); + } + } else { + spPhysicsConstraint *constraint = skeleton->physicsConstraints[self->physicsConstraintIndex]; + if (constraint->active) _spPhysicsConstraintTimeline_set(constraint, type, spCurveTimeline1_getAbsoluteValue(SUPER(self), time, alpha, blend, _spPhysicsConstraintTimeline_get(constraint, type), _spPhysicsConstraintTimeline_setup(constraint, type))); + } + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); + UNUSED(direction); +} + +spPhysicsConstraintTimeline * +spPhysicsConstraintTimeline_create(int frameCount, int bezierCount, int physicsConstraintIndex, spTimelineType type) { + spPhysicsConstraintTimeline *timeline = NEW(spPhysicsConstraintTimeline); + spPropertyId ids[1]; + spPropertyId id; + switch(type) { + case SP_TIMELINE_PHYSICSCONSTRAINT_INERTIA: + id = SP_PROPERTY_PHYSICSCONSTRAINT_INERTIA; + break; + case SP_TIMELINE_PHYSICSCONSTRAINT_STRENGTH: + id = SP_PROPERTY_PHYSICSCONSTRAINT_STRENGTH; + break; + case SP_TIMELINE_PHYSICSCONSTRAINT_DAMPING: + id = SP_PROPERTY_PHYSICSCONSTRAINT_DAMPING; + break; + case SP_TIMELINE_PHYSICSCONSTRAINT_MASS: + id = SP_PROPERTY_PHYSICSCONSTRAINT_MASS; + break; + case SP_TIMELINE_PHYSICSCONSTRAINT_WIND: + id = SP_PROPERTY_PHYSICSCONSTRAINT_WIND; + break; + case SP_TIMELINE_PHYSICSCONSTRAINT_GRAVITY: + id = SP_PROPERTY_PHYSICSCONSTRAINT_GRAVITY; + break; + case SP_TIMELINE_PHYSICSCONSTRAINT_MIX: + id = SP_PROPERTY_PHYSICSCONSTRAINT_MIX; + break; + default: + // should never happen + id = SP_PROPERTY_PHYSICSCONSTRAINT_INERTIA; + } + ids[0] = ((spPropertyId) id << 32) | physicsConstraintIndex; + _spCurveTimeline_init(SUPER(timeline), frameCount, CURVE1_ENTRIES, bezierCount, ids, 1, type, + _spCurveTimeline_dispose, _spPhysicsConstraintTimeline_apply, _spCurveTimeline_setBezier); + timeline->physicsConstraintIndex = physicsConstraintIndex; + return timeline; +} + +void spPhysicsConstraintTimeline_setFrame(spPhysicsConstraintTimeline *self, int frame, float time, float value) { + spCurveTimeline1_setFrame(SUPER(self), frame, time, value); +} + +/**/ +void _spPhysicsConstraintResetTimeline_apply(spTimeline *timeline, spSkeleton *skeleton, float lastTime, float time, + spEvent **firedEvents, int *eventsCount, float alpha, spMixBlend blend, + spMixDirection direction) { + spPhysicsConstraintResetTimeline *self = (spPhysicsConstraintResetTimeline *)timeline; + spPhysicsConstraint *constraint = NULL; + if (self->physicsConstraintIndex != -1) { + constraint = skeleton->physicsConstraints[self->physicsConstraintIndex]; + if (!constraint->active) return; + } + + float *frames = SUPER(self)->frames->items; + if (lastTime > time) {// Apply after lastTime for looped animations. + _spPhysicsConstraintResetTimeline_apply(SUPER(self), skeleton, lastTime, INT_MAX, NULL, 0, alpha, blend, direction); + lastTime = -1; + } else if (lastTime >= frames[SUPER(self)->frameCount - 1])// Last time is after last frame. + return; + if (time < frames[0]) return; + + if (lastTime < frames[0] || time >= frames[search(self->super.frames, lastTime) + 1]) { + if (constraint != NULL) + spPhysicsConstraint_reset(constraint); + else { + spPhysicsConstraint **physicsConstraints = skeleton->physicsConstraints; + for (int i = 0; i < skeleton->physicsConstraintsCount; i++) { + constraint = physicsConstraints[i]; + if (constraint->active) spPhysicsConstraint_reset(constraint); + } + } + } + + UNUSED(lastTime); + UNUSED(firedEvents); + UNUSED(eventsCount); + UNUSED(alpha); + UNUSED(direction); +} + +void _spPhysicsConstraintResetTimeline_dispose(spTimeline *timeline) { + // no-op, spTimeline_dispose disposes frames. + UNUSED(timeline); +} + +spPhysicsConstraintResetTimeline *spPhysicsConstraintResetTimeline_create(int framesCount, int physicsConstraintIndex) { + spPhysicsConstraintResetTimeline *self = NEW(spPhysicsConstraintResetTimeline); + spPropertyId ids[1]; + ids[0] = (spPropertyId) SP_PROPERTY_PHYSICSCONSTRAINT_RESET << 32; + _spTimeline_init(SUPER(self), framesCount, 1, ids, 1, SP_TIMELINE_PHYSICSCONSTRAINT_RESET, _spPhysicsConstraintResetTimeline_dispose, + _spPhysicsConstraintResetTimeline_apply, 0); + + self->physicsConstraintIndex = physicsConstraintIndex; + + return self; +} + +void spPhysicsResetTimeline_setFrame(spPhysicsConstraintResetTimeline *self, int frame, float time) { + self->super.frames->items[frame] = time; +} diff --git a/spine-c/spine-c/src/spine/AnimationState.c b/spine-c/spine-c/src/spine/AnimationState.c index 47a0b08b5..f8fffd7ce 100644 --- a/spine-c/spine-c/src/spine/AnimationState.c +++ b/spine-c/spine-c/src/spine/AnimationState.c @@ -390,18 +390,19 @@ int spAnimationState_apply(spAnimationState *self, spSkeleton *skeleton) { if (internal->animationsChanged) _spAnimationState_animationsChanged(self); for (i = 0, n = self->tracksCount; i < n; i++) { - float mix; + float alpha; current = self->tracks[i]; if (!current || current->delay > 0) continue; applied = -1; blend = i == 0 ? SP_MIX_BLEND_FIRST : current->mixBlend; /* Apply mixing from entries first. */ - mix = current->alpha; + alpha = current->alpha; if (current->mixingFrom) - mix *= _spAnimationState_applyMixingFrom(self, current, skeleton, blend); + alpha *= _spAnimationState_applyMixingFrom(self, current, skeleton, blend); else if (current->trackTime >= current->trackEnd && current->next == 0) - mix = 0; + alpha = 0; + int/*bool*/ attachments = alpha >= current->alphaAttachmentThreshold; /* Apply current entry. */ animationLast = current->animationLast; @@ -414,14 +415,14 @@ int spAnimationState_apply(spAnimationState *self, spSkeleton *skeleton) { applyEvents = NULL; } timelines = current->animation->timelines->items; - if ((i == 0 && mix == 1) || blend == SP_MIX_BLEND_ADD) { + if ((i == 0 && alpha == 1) || blend == SP_MIX_BLEND_ADD) { for (ii = 0; ii < timelineCount; ii++) { timeline = timelines[ii]; if (timeline->type == SP_TIMELINE_ATTACHMENT) { - _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, applyTime, blend, -1); + _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, applyTime, blend, attachments); } else { spTimeline_apply(timelines[ii], skeleton, animationLast, applyTime, applyEvents, - &internal->eventsCount, mix, blend, SP_MIX_DIRECTION_IN); + &internal->eventsCount, alpha, blend, SP_MIX_DIRECTION_IN); } } } else { @@ -436,13 +437,13 @@ int spAnimationState_apply(spAnimationState *self, spSkeleton *skeleton) { timeline = timelines[ii]; timelineBlend = timelineMode->items[ii] == SUBSEQUENT ? blend : SP_MIX_BLEND_SETUP; if (!shortestRotation && timeline->type == SP_TIMELINE_ROTATE) - _spAnimationState_applyRotateTimeline(self, timeline, skeleton, applyTime, mix, timelineBlend, - timelinesRotation, ii << 1, firstFrame); + _spAnimationState_applyRotateTimeline(self, timeline, skeleton, applyTime, alpha, timelineBlend, + timelinesRotation, ii << 1, firstFrame); else if (timeline->type == SP_TIMELINE_ATTACHMENT) - _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, applyTime, timelineBlend, -1); + _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, applyTime, timelineBlend, attachments); else spTimeline_apply(timeline, skeleton, animationLast, applyTime, applyEvents, &internal->eventsCount, - mix, timelineBlend, SP_MIX_DIRECTION_IN); + alpha, timelineBlend, SP_MIX_DIRECTION_IN); } } _spAnimationState_queueEvents(self, current, animationTime); @@ -500,8 +501,8 @@ float _spAnimationState_applyMixingFrom(spAnimationState *self, spTrackEntry *to if (blend != SP_MIX_BLEND_FIRST) blend = from->mixBlend; } - attachments = mix < from->attachmentThreshold; - drawOrder = mix < from->drawOrderThreshold; + attachments = mix < from->mixAttachmentThreshold; + drawOrder = mix < from->mixDrawOrderThreshold; timelineCount = from->animation->timelines->size; timelines = from->animation->timelines->items; alphaHold = from->alpha * to->interruptAlpha; @@ -566,7 +567,7 @@ float _spAnimationState_applyMixingFrom(spAnimationState *self, spTrackEntry *to timelinesRotation, i << 1, firstFrame); else if (timeline->type == SP_TIMELINE_ATTACHMENT) _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, applyTime, timelineBlend, - attachments); + attachments && alpha >= from->alphaAttachmentThreshold); else { if (drawOrder && timeline->type == SP_TIMELINE_DRAWORDER && timelineBlend == SP_MIX_BLEND_SETUP) @@ -664,8 +665,8 @@ void _spAnimationState_applyRotateTimeline(spAnimationState *self, spTimeline *t /* Mix between rotations using the direction of the shortest route on the first frame while detecting crosses. */ diff = r2 - r1; - diff -= (16384 - (int) (16384.499999999996 - diff / 360)) * 360; - if (diff == 0) { + diff -= CEIL(diff / 360 - 0.5) * 360; + if (diff == 0) { total = timelinesRotation[i]; } else { float lastTotal, lastDiff, loops; @@ -714,10 +715,16 @@ void _spAnimationState_queueEvents(spAnimationState *self, spTrackEntry *entry, } /* Queue complete if completed a loop iteration or the animation. */ - if (entry->loop) - complete = duration == 0 || (trackLastWrapped > FMOD(entry->trackTime, duration)); - else - complete = (animationTime >= animationEnd && entry->animationLast < animationEnd); + if (entry->loop) { + if (duration == 0) + complete = -1; + else { + int cycles = (int) (entry->trackTime / duration); + complete = cycles > 0 && cycles > (int) (entry->trackLast / duration); + } + } else { + complete = (animationTime >= animationEnd && entry->animationLast < animationEnd); + } if (complete) _spEventQueue_complete(internal->queue, entry); /* Queue events after complete. */ @@ -910,8 +917,9 @@ _spAnimationState_trackEntry(spAnimationState *self, int trackIndex, spAnimation entry->next = 0; entry->eventThreshold = 0; - entry->attachmentThreshold = 0; - entry->drawOrderThreshold = 0; + entry->mixAttachmentThreshold = 0; + entry->alphaAttachmentThreshold = 0; + entry->mixDrawOrderThreshold = 0; entry->animationStart = 0; entry->animationEnd = animation->duration; @@ -1051,6 +1059,16 @@ float spTrackEntry_getTrackComplete(spTrackEntry *entry) { return entry->trackTime; /* Next update. */ } +void spTrackEntry_setMixDuration(spTrackEntry *entry, float mixDuration, float delay) { + entry->mixDuration = mixDuration; + if (entry->previous && delay <= 0) delay += spTrackEntry_getTrackComplete(entry) - mixDuration; + entry->delay = delay; +} + +int spTrackEntry_wasApplied(spTrackEntry *entry) { + return entry->nextTrackLast != -1; +} + void _spTrackEntry_computeHold(spTrackEntry *entry, spAnimationState *state) { spTrackEntry *to; spTimeline **timelines; diff --git a/spine-c/spine-c/src/spine/Debug.c b/spine-c/spine-c/src/spine/Debug.c index 8b8a31816..1ba5d4465 100644 --- a/spine-c/spine-c/src/spine/Debug.c +++ b/spine-c/spine-c/src/spine/Debug.c @@ -209,6 +209,13 @@ void spDebug_printTimeline(spTimeline *timeline) { spSequenceTimeline *t = (spSequenceTimeline *) timeline; _spDebug_printTimelineBase(&t->super); } + case SP_TIMELINE_INHERIT: { + spInheritTimeline *t = (spInheritTimeline *) timeline; + _spDebug_printTimelineBase(&t->super); + } + default: { + _spDebug_printTimelineBase(timeline); + } } } diff --git a/spine-c/spine-c/src/spine/IkConstraint.c b/spine-c/spine-c/src/spine/IkConstraint.c index 7ef900aea..0ef09b023 100644 --- a/spine-c/spine-c/src/spine/IkConstraint.c +++ b/spine-c/spine-c/src/spine/IkConstraint.c @@ -71,6 +71,14 @@ void spIkConstraint_update(spIkConstraint *self) { } } +void spIkConstraint_setToSetupPose(spIkConstraint *self) { + self->bendDirection = self->data->bendDirection; + self->compress = self->data->compress; + self->stretch = self->data->stretch; + self->softness = self->data->softness; + self->mix = self->data->mix; +} + void spIkConstraint_apply1(spBone *bone, float targetX, float targetY, int /*boolean*/ compress, int /*boolean*/ stretch, int /*boolean*/ uniform, float alpha) { spBone *p = bone->parent; diff --git a/spine-c/spine-c/src/spine/IkConstraintData.c b/spine-c/spine-c/src/spine/IkConstraintData.c index c2fe09e3b..631a325cb 100644 --- a/spine-c/spine-c/src/spine/IkConstraintData.c +++ b/spine-c/spine-c/src/spine/IkConstraintData.c @@ -33,11 +33,11 @@ spIkConstraintData *spIkConstraintData_create(const char *name) { spIkConstraintData *self = NEW(spIkConstraintData); MALLOC_STR(self->name, name); - self->bendDirection = 1; + self->bendDirection = 0; self->compress = 0; self->stretch = 0; self->uniform = 0; - self->mix = 1; + self->mix = 0; return self; } diff --git a/spine-c/spine-c/src/spine/PathConstraint.c b/spine-c/spine-c/src/spine/PathConstraint.c index 61b0842bc..0ee3676d5 100644 --- a/spine-c/spine-c/src/spine/PathConstraint.c +++ b/spine-c/spine-c/src/spine/PathConstraint.c @@ -117,13 +117,9 @@ void spPathConstraint_update(spPathConstraint *self) { for (i = 0, n = spacesCount - 1; i < n; i++) { spBone *bone = bones[i]; setupLength = bone->data->length; - if (setupLength < EPSILON) - lengths[i] = 0; - else { - x = setupLength * bone->a; - y = setupLength * bone->c; - lengths[i] = SQRT(x * x + y * y); - } + x = setupLength * bone->a; + y = setupLength * bone->c; + lengths[i] = SQRT(x * x + y * y); } } for (i = 1, n = spacesCount; i < n; i++) spaces[i] = spacing; @@ -225,6 +221,15 @@ void spPathConstraint_update(spPathConstraint *self) { } } +void spPathConstraint_setToSetupPose(spPathConstraint *self) { + spPathConstraintData *data = self->data; + self->position = data->position; + self->spacing = data->spacing; + self->mixRotate = data->mixRotate; + self->mixX = data->mixX; + self->mixY = data->mixY; +} + static void _addBeforePosition(float p, float *temp, int i, float *out, int o) { float x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = ATAN2(dy, dx); out[o] = x1 + p * COS(r); diff --git a/spine-c/spine-c/src/spine/PointAttachment.c b/spine-c/spine-c/src/spine/PointAttachment.c index 00c056074..dcb6a9180 100644 --- a/spine-c/spine-c/src/spine/PointAttachment.c +++ b/spine-c/spine-c/src/spine/PointAttachment.c @@ -58,10 +58,8 @@ void spPointAttachment_computeWorldPosition(spPointAttachment *self, spBone *bon } float spPointAttachment_computeWorldRotation(spPointAttachment *self, spBone *bone) { - float cosine, sine, x, y; - cosine = COS_DEG(self->rotation); - sine = SIN_DEG(self->rotation); - x = cosine * bone->a + sine * bone->b; - y = cosine * bone->c + sine * bone->d; - return ATAN2(y, x) * RAD_DEG; + float r = self->rotation * DEG_RAD, cosine = COS(r), sine = SIN(r); + float x = cosine * bone->a + sine * bone->b; + float y = cosine * bone->c + sine * bone->d; + return ATAN2DEG(y, x); } diff --git a/spine-c/spine-c/src/spine/Skeleton.c b/spine-c/spine-c/src/spine/Skeleton.c index b07d259fc..d640f1ce4 100644 --- a/spine-c/spine-c/src/spine/Skeleton.c +++ b/spine-c/spine-c/src/spine/Skeleton.c @@ -60,6 +60,11 @@ spSkeleton *spSkeleton_create(spSkeletonData *data) { _spSkeleton *internal = NEW(_spSkeleton); spSkeleton *self = SUPER(internal); self->data = data; + self->skin = NULL; + spColor_setFromFloats(&self->color, 1, 1, 1, 1); + self->scaleX = 1; + self->scaleY = 1; + self->time = 0; self->bonesCount = self->data->bonesCount; self->bones = MALLOC(spBone *, self->bonesCount); @@ -116,6 +121,12 @@ spSkeleton *spSkeleton_create(spSkeletonData *data) { for (i = 0; i < self->data->pathConstraintsCount; i++) self->pathConstraints[i] = spPathConstraint_create(self->data->pathConstraints[i], self); + self->physicsConstraintsCount = data->physicsConstraintsCount; + self->physicsConstraints = MALLOC(spPhysicsConstraint *, self->physicsConstraintsCount); + for (i = 0; i < self->data->physicsConstraintsCount; i++) + self->physicsConstraints[i] = spPhysicsConstraint_create(self->data->physicsConstraints[i], self); + + spColor_setFromFloats(&self->color, 1, 1, 1, 1); self->scaleX = 1; @@ -156,6 +167,10 @@ void spSkeleton_dispose(spSkeleton *self) { spPathConstraint_dispose(self->pathConstraints[i]); FREE(self->pathConstraints); + for (i = 0; i < self->physicsConstraintsCount; i++) + spPhysicsConstraint_dispose(self->physicsConstraints[i]); + FREE(self->physicsConstraints); + FREE(self->drawOrder); FREE(self); } @@ -324,17 +339,35 @@ static void _sortTransformConstraint(_spSkeleton *const internal, spTransformCon constrained[i]->sorted = 1; } +static void _sortPhysicsConstraint(_spSkeleton *const internal, spPhysicsConstraint *constraint) { + spBone *bone = constraint->bone; + constraint->active = constraint->bone->active && (!constraint->data->skinRequired || (internal->super.skin != 0 && + spPhysicsConstraintDataArray_contains( + internal->super.skin->physicsConstraints, + constraint->data))); + if (!constraint->active) + return; + + _sortBone(internal, bone); + _addToUpdateCache(internal, SP_UPDATE_PHYSICS_CONSTRAINT, constraint); + + _sortReset(bone->children, bone->childrenCount); + bone->sorted = -1; +} + void spSkeleton_updateCache(spSkeleton *self) { int i, ii; spBone **bones; spIkConstraint **ikConstraints; spPathConstraint **pathConstraints; spTransformConstraint **transformConstraints; - int ikCount, transformCount, pathCount, constraintCount; + spPhysicsConstraint **physicsConstraints; + int ikCount, transformCount, pathCount, physicsCount, constraintCount; _spSkeleton *internal = SUB_CAST(_spSkeleton, self); internal->updateCacheCapacity = - self->bonesCount + self->ikConstraintsCount + self->transformConstraintsCount + self->pathConstraintsCount; + self->bonesCount + self->ikConstraintsCount + self->transformConstraintsCount + self->pathConstraintsCount + + self->physicsConstraintsCount; FREE(internal->updateCache); internal->updateCache = MALLOC(_spUpdate, internal->updateCacheCapacity); internal->updateCacheCount = 0; @@ -362,10 +395,12 @@ void spSkeleton_updateCache(spSkeleton *self) { ikConstraints = self->ikConstraints; transformConstraints = self->transformConstraints; pathConstraints = self->pathConstraints; + physicsConstraints = self->physicsConstraints; ikCount = self->ikConstraintsCount; transformCount = self->transformConstraintsCount; pathCount = self->pathConstraintsCount; - constraintCount = ikCount + transformCount + pathCount; + physicsCount = self->physicsConstraintsCount; + constraintCount = ikCount + transformCount + pathCount + physicsCount; i = 0; continue_outer: @@ -396,6 +431,15 @@ continue_outer: goto continue_outer; } } + + for (ii = 0; ii < physicsCount; ii++) { + spPhysicsConstraint *physicsConstraint = physicsConstraints[ii]; + if (physicsConstraint->data->order == i) { + _sortPhysicsConstraint(internal, physicsConstraint); + i++; + goto continue_outer; + } + } } for (i = 0; i < self->bonesCount; ++i) @@ -495,33 +539,19 @@ void spSkeleton_setBonesToSetupPose(const spSkeleton *self) { spBone_setToSetupPose(self->bones[i]); for (i = 0; i < self->ikConstraintsCount; ++i) { - spIkConstraint *ikConstraint = self->ikConstraints[i]; - ikConstraint->bendDirection = ikConstraint->data->bendDirection; - ikConstraint->compress = ikConstraint->data->compress; - ikConstraint->stretch = ikConstraint->data->stretch; - ikConstraint->softness = ikConstraint->data->softness; - ikConstraint->mix = ikConstraint->data->mix; + spIkConstraint_setToSetupPose(self->ikConstraints[i]); } for (i = 0; i < self->transformConstraintsCount; ++i) { - spTransformConstraint *constraint = self->transformConstraints[i]; - spTransformConstraintData *data = constraint->data; - constraint->mixRotate = data->mixRotate; - constraint->mixX = data->mixX; - constraint->mixY = data->mixY; - constraint->mixScaleX = data->mixScaleX; - constraint->mixScaleY = data->mixScaleY; - constraint->mixShearY = data->mixShearY; + spTransformConstraint_setToSetupPose(self->transformConstraints[i]); } for (i = 0; i < self->pathConstraintsCount; ++i) { - spPathConstraint *constraint = self->pathConstraints[i]; - spPathConstraintData *data = constraint->data; - constraint->position = data->position; - constraint->spacing = data->spacing; - constraint->mixRotate = data->mixRotate; - constraint->mixX = data->mixX; - constraint->mixY = data->mixY; + spPathConstraint_setToSetupPose(self->pathConstraints[i]); + } + + for (i = 0; i < self->physicsConstraintsCount; ++i) { + spPhysicsConstraint_setToSetupPose(self->physicsConstraints[i]); } } @@ -645,3 +675,15 @@ spPhysicsConstraint *spSkeleton_findPhysicsConstraint(const spSkeleton *self, co if (strcmp(self->physicsConstraints[i]->data->name, constraintName) == 0) return self->physicsConstraints[i]; return 0; } + +void spSkeleton_physicsTranslate(spSkeleton *self, float x, float y) { + for (int i = 0; i < (int) self->physicsConstraintsCount; i++) { + spPhysicsConstraint_translate(self->physicsConstraints[i], x, y); + } +} + +void spSkeleton_physicsRotate(spSkeleton *self, float x, float y, float degrees) { + for (int i = 0; i < (int) self->physicsConstraintsCount; i++) { + spPhysicsConstraint_rotate(self->physicsConstraints[i], x, y, degrees); + } +} diff --git a/spine-c/spine-c/src/spine/Skin.c b/spine-c/spine-c/src/spine/Skin.c index 423edf712..390b93ce5 100644 --- a/spine-c/spine-c/src/spine/Skin.c +++ b/spine-c/spine-c/src/spine/Skin.c @@ -39,6 +39,8 @@ _SP_ARRAY_IMPLEMENT_TYPE(spTransformConstraintDataArray, spTransformConstraintDa _SP_ARRAY_IMPLEMENT_TYPE(spPathConstraintDataArray, spPathConstraintData *) +_SP_ARRAY_IMPLEMENT_TYPE(spPhysicsConstraintDataArray, spPhysicsConstraintData *) + _Entry *_Entry_create(int slotIndex, const char *name, spAttachment *attachment) { _Entry *self = NEW(_Entry); self->slotIndex = slotIndex; @@ -72,6 +74,7 @@ spSkin *spSkin_create(const char *name) { self->ikConstraints = spIkConstraintDataArray_create(4); self->transformConstraints = spTransformConstraintDataArray_create(4); self->pathConstraints = spPathConstraintDataArray_create(4); + self->physicsConstraints = spPhysicsConstraintDataArray_create(4); spColor_setFromFloats(&self->color, 0.99607843f, 0.61960787f, 0.30980393f, 1); return self; } @@ -104,6 +107,7 @@ void spSkin_dispose(spSkin *self) { spIkConstraintDataArray_dispose(self->ikConstraints); spTransformConstraintDataArray_dispose(self->transformConstraints); spPathConstraintDataArray_dispose(self->pathConstraints); + spPhysicsConstraintDataArray_dispose(self->physicsConstraints); FREE(self->name); FREE(self); } @@ -198,6 +202,11 @@ void spSkin_addSkin(spSkin *self, const spSkin *other) { spPathConstraintDataArray_add(self->pathConstraints, other->pathConstraints->items[i]); } + for (i = 0; i < other->physicsConstraints->size; i++) { + if (!spPhysicsConstraintDataArray_contains(self->physicsConstraints, other->physicsConstraints->items[i])) + spPhysicsConstraintDataArray_add(self->physicsConstraints, other->physicsConstraints->items[i]); + } + entry = spSkin_getAttachments(other); while (entry) { spSkin_setAttachment(self, entry->slotIndex, entry->name, entry->attachment); @@ -229,6 +238,11 @@ void spSkin_copySkin(spSkin *self, const spSkin *other) { spPathConstraintDataArray_add(self->pathConstraints, other->pathConstraints->items[i]); } + for (i = 0; i < other->physicsConstraints->size; i++) { + if (!spPhysicsConstraintDataArray_contains(self->physicsConstraints, other->physicsConstraints->items[i])) + spPhysicsConstraintDataArray_add(self->physicsConstraints, other->physicsConstraints->items[i]); + } + entry = spSkin_getAttachments(other); while (entry) { if (entry->attachment->type == SP_ATTACHMENT_MESH) { @@ -279,4 +293,5 @@ void spSkin_clear(spSkin *self) { spIkConstraintDataArray_clear(self->ikConstraints); spTransformConstraintDataArray_clear(self->transformConstraints); spPathConstraintDataArray_clear(self->pathConstraints); + spPhysicsConstraintDataArray_clear(self->physicsConstraints); } diff --git a/spine-c/spine-c/src/spine/TransformConstraint.c b/spine-c/spine-c/src/spine/TransformConstraint.c index 059347e73..c657f61b5 100644 --- a/spine-c/spine-c/src/spine/TransformConstraint.c +++ b/spine-c/spine-c/src/spine/TransformConstraint.c @@ -193,8 +193,8 @@ void _spTransformConstraint_applyAbsoluteLocal(spTransformConstraint *self) { rotation = bone->arotation; if (mixRotate != 0) { r = target->arotation - rotation + self->data->offsetRotation; - r -= (16384 - (int) (16384.499999999996 - r / 360)) * 360; - rotation += r * mixRotate; + r -= CEIL(r / 360 - 0.5) * 360; + rotation += r * mixRotate; } x = bone->ax, y = bone->ay; @@ -210,8 +210,8 @@ void _spTransformConstraint_applyAbsoluteLocal(spTransformConstraint *self) { shearY = bone->ashearY; if (mixShearY != 0) { r = target->ashearY - shearY + self->data->offsetShearY; - r -= (16384 - (int) (16384.499999999996 - r / 360)) * 360; - shearY += r * mixShearY; + r -= CEIL(r / 360 - 0.5) * 360; + shearY += r * mixShearY; } spBone_updateWorldTransformWith(bone, x, y, rotation, scaleX, scaleY, bone->ashearX, shearY); @@ -257,3 +257,13 @@ void spTransformConstraint_update(spTransformConstraint *self) { _spTransformConstraint_applyAbsoluteWorld(self); } } + +void spTransformConstraint_setToSetupPose(spTransformConstraint *self) { + spTransformConstraintData *data = self->data; + self->mixRotate = data->mixRotate; + self->mixX = data->mixX; + self->mixY = data->mixY; + self->mixScaleX = data->mixScaleX; + self->mixScaleY = data->mixScaleY; + self->mixShearY = data->mixShearY; +}