[c] 4.0 porting, more timeline work.

This commit is contained in:
badlogic 2021-03-23 15:58:56 +01:00
parent a4c5b9937f
commit 22f6782fe5
3 changed files with 709 additions and 411 deletions

View File

@ -102,17 +102,23 @@ typedef enum {
#define SP_MAX_PROPERTY_IDS 2
typedef struct _spTimelineVtable {
void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction);
void (*dispose) (spTimeline* self);
} _spTimelineVtable;
struct spTimeline {
const void* const vtable;
_spTimelineVtable vtable;
spPropertyId propertyIds[SP_MAX_PROPERTY_IDS];
int propertyIdsCount;
spFloatArray frames;
spFloatArray *frames;
int frameEntries;
};
SP_API void spTimeline_dispose (spTimeline* self);
SP_API void spTimeline_apply (const spTimeline* self, struct spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction);
SP_API int spTimeline_getFrameEntries (const spTimeline* self);
SP_API int spTimeline_getFrameCount (const spTimeline* self);
SP_API float spTimeline_getDuration (const spTimeline* self);
@ -120,7 +126,7 @@ SP_API float spTimeline_getDuration (const spTimeline* self);
typedef struct spCurveTimeline {
spTimeline super;
float* curves; /* type, x, y, ... */
spFloatArray* curves; /* type, x, y, ... */
} spCurveTimeline;
SP_API void spCurveTimeline_setLinear (spCurveTimeline* self, int frameIndex);
@ -132,47 +138,94 @@ SP_API void spCurveTimeline_setStepped (spCurveTimeline* self, int frameIndex);
SP_API void spCurveTimeline_setCurve (spCurveTimeline* self, int frameIndex, float cx1, float cy1, float cx2, float cy2);
SP_API float spCurveTimeline_getCurvePercent (const spCurveTimeline* self, int frameIndex, float percent);
typedef struct spCurveTimeline spCurveTimeline1;
SP_API void spCurveTimeline1_setFrame(spCurveTimeline1* self, int frame, float time, float value);
SP_API float spCurveTimeline1_getCurveValue(spCurveTimeline1* self, float time);
typedef struct spCurveTimeline spCurveTimeline2;
SP_API void spCurveTimeline2_setFrame(spCurveTimeline1* self, int frame, float time, float value1, float value2);
/**/
typedef struct spBaseTimeline {
spCurveTimeline super;
int const framesCount;
float* const frames; /* time, angle, ... for rotate. time, x, y, ... for translate and scale. */
typedef struct spRotateTimeline {
spCurveTimeline1 super;
int boneIndex;
} spBaseTimeline;
} spRotateTimeline;
/**/
static const int ROTATE_PREV_TIME = -2, ROTATE_PREV_ROTATION = -1;
static const int ROTATE_ROTATION = 1;
static const int ROTATE_ENTRIES = 2;
typedef struct spBaseTimeline spRotateTimeline;
SP_API spRotateTimeline* spRotateTimeline_create (int framesCount);
SP_API spRotateTimeline* spRotateTimeline_create (int frameCount, int bezierCount, int boneIndex);
SP_API void spRotateTimeline_setFrame (spRotateTimeline* self, int frameIndex, float time, float angle);
/**/
static const int TRANSLATE_ENTRIES = 3;
typedef struct spTranslateTimeline {
spCurveTimeline2 super;
int boneIndex;
} spTranslateTimeline;
typedef struct spBaseTimeline spTranslateTimeline;
SP_API spTranslateTimeline* spTranslateTimeline_create (int framesCount);
SP_API spTranslateTimeline* spTranslateTimeline_create (int frameCount, int bezierCount, int boneIndex);
SP_API void spTranslateTimeline_setFrame (spTranslateTimeline* self, int frameIndex, float time, float x, float y);
/**/
typedef struct spBaseTimeline spScaleTimeline;
typedef struct spTranslateXTimeline {
spCurveTimeline1 super;
int boneIndex;
} spTranslateXTimeline;
SP_API spScaleTimeline* spScaleTimeline_create (int framesCount);
SP_API spTranslateXTimeline* spTranslateXTimeline_create (int frameCount, int bezierCount, int boneIndex);
SP_API void spTranslateXTimeline_setFrame (spTranslateXTimeline* self, int frame, float time, float x);
/**/
typedef struct spTranslateYTimeline {
spCurveTimeline1 super;
int boneIndex;
} spTranslateYTimeline;
SP_API spTranslateYTimeline* spTranslateYTimeline_create (int frameCount, int bezierCount, int boneIndex);
SP_API void spTranslateYTimeline_setFrame (spTranslateYTimeline* self, int frame, float time, float y);
/**/
typedef struct spScaleTimeline {
spCurveTimeline2 super;
int boneIndex;
} spScaleTimeline;
SP_API spScaleTimeline* spScaleTimeline_create (int frameCount, int bezierCount, int boneIndex);
SP_API void spScaleTimeline_setFrame (spScaleTimeline* self, int frameIndex, float time, float x, float y);
/**/
typedef struct spScaleXTimeline {
spCurveTimeline1 super;
int boneIndex;
} spScaleXTimeline;
SP_API spScaleXTimeline* spScaleXTimeline_create (int frameCount, int bezierCount, int boneIndex);
SP_API void spScaleXTimeline_setFrame (spScaleXTimeline* self, int frame, float time, float x);
/**/
typedef struct spScaleYTimeline {
spCurveTimeline1 super;
int boneIndex;
} spScaleYTimeline;
SP_API spScaleYTimeline* spScaleYTimeline_create (int frameCount, int bezierCount, int boneIndex);
SP_API void spScaleYTimeline_setFrame (spScaleYTimeline* self, int frame, float time, float y);
/**/
typedef struct spBaseTimeline spShearTimeline;
SP_API spShearTimeline* spShearTimeline_create (int framesCount);

View File

@ -247,26 +247,6 @@ void _spAttachment_deinit (spAttachment* self);
void _spVertexAttachment_init (spVertexAttachment* self);
void _spVertexAttachment_deinit (spVertexAttachment* self);
/**/
void _spTimeline_init (spTimeline* self,
void (*dispose) (spTimeline* self),
void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction),
int (*getFrameEntries) (const spTimeline* self),
spPropertyId* propertyIds, int propertyIdsCount);
void _spTimeline_deinit (spTimeline* self);
/**/
void _spCurveTimeline_init (spCurveTimeline* self, int framesCount,
void (*dispose) (spTimeline* self),
void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction),
int (*getPropertyId) (const spTimeline* self),
spPropertyId* propertyIds, int propertyIdsCount);
void _spCurveTimeline_deinit (spCurveTimeline* self);
int _spCurveTimeline_binarySearch (float *values, int valuesLength, float target, int step);
#ifdef __cplusplus
}
#endif

View File

@ -79,195 +79,181 @@ void spAnimation_apply (const spAnimation* self, spSkeleton* skeleton, float las
spTimeline_apply(self->timelines->items[i], skeleton, lastTime, time, events, eventsCount, alpha, blend, direction);
}
static search (float* values, int valuesCount, float time) {
int i;
for (i = 1; i < valuesCount; i++)
if (values[i] > time) return i - 1;
return valuesCount - 1;
}
static search2 (float* values, int valuesCount, float time, int step) {
int i;
for (i = step; i < valuesCount; i += step)
if (values[i] > time) return i - step;
return valuesCount - step;
}
/**/
typedef struct _spTimelineVtable {
void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction);
int (*getFrameEntries) (const spTimeline* self);
void (*dispose) (spTimeline* self);
} _spTimelineVtable;
void _spTimeline_init (spTimeline* self, /**/
void (*dispose) (spTimeline* self), /**/
void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction),
int (*getFrameEntries) (const spTimeline* self),
void _spTimeline_init (spTimeline* self,
int frameCount,
int frameEntries,
spPropertyId* propertyIds,
int propertyIdsCount
int propertyIdsCount,
void (*dispose) (spTimeline* self),
void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction)
) {
int i, n;
CONST_CAST(_spTimelineVtable*, self->vtable) = NEW(_spTimelineVtable);
VTABLE(spTimeline, self)->dispose = dispose;
VTABLE(spTimeline, self)->apply = apply;
VTABLE(spTimeline, self)->getFrameEntries = getFrameEntries;
self->frames = spFloatArray_create(frameCount * frameEntries);
self->frameEntries = frameEntries;
self->vtable.dispose = dispose;
self->vtable.apply = apply;
for (i = 0, n = propertyIdsCount; i < n; i++)
self->propertyIds[i] = propertyIds[i];
}
void _spTimeline_deinit (spTimeline* self) {
FREE(self->vtable);
}
void spTimeline_dispose (spTimeline* self) {
VTABLE(spTimeline, self)->dispose(self);
spFloatArray_dispose(self->frames);
self->vtable.dispose(self);
FREE(self);
}
void spTimeline_apply (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
VTABLE(spTimeline, self)->apply(self, skeleton, lastTime, time, firedEvents, eventsCount, alpha, blend, direction);
}
int spTimeline_getFrameEntries (const spTimeline* self) {
return VTABLE(spTimeline, self)->getFrameEntries(self);
self->vtable.apply(self, skeleton, lastTime, time, firedEvents, eventsCount, alpha, blend, direction);
}
int spTimeline_getFrameCount (const spTimeline* self) {
return self->frames.size / VTABLE(spTimeline, self)->getFrameEntries(self);
return self->frames->size / self->frameEntries;
}
float spTimeline_getDuration (const spTimeline* self) {
return self->frames.items[self->frames.size - VTABLE(spTimeline, self)->getFrameEntries(self)];
return self->frames->items[self->frames->size - self->frameEntries];
}
/**/
static const float CURVE_LINEAR = 0, CURVE_STEPPED = 1, CURVE_BEZIER = 2;
static const int BEZIER_SIZE = 10 * 2 - 1;
#define CURVE_LINEAR 0
#define CURVE_STEPPED 1
#define CURVE_BEZIER 2
#define BEZIER_SIZE 18
void _spCurveTimeline_init (spCurveTimeline* self, spTimelineType type, int framesCount, /**/
void (*dispose) (spTimeline* self), /**/
void _spCurveTimeline_init (spCurveTimeline* self,
int frameCount,
int frameEntries,
int bezierCount,
spPropertyId* propertyIds,
int propertyIdsCount,
void (*dispose) (spTimeline* self),
void (*apply) (const spTimeline* self, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction),
int (*getPropertyId)(const spTimeline* self)
int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction)
) {
_spTimeline_init(SUPER(self), type, dispose, apply, getPropertyId);
self->curves = CALLOC(float, (framesCount - 1) * BEZIER_SIZE);
_spTimeline_init(SUPER(self), frameCount, frameEntries, propertyIds, propertyIdsCount, dispose, apply);
self->curves = spFloatArray_create(frameCount + bezierCount * BEZIER_SIZE);
}
void _spCurveTimeline_deinit (spCurveTimeline* self) {
_spTimeline_deinit(SUPER(self));
FREE(self->curves);
void _spCurveTimeline_dispose (spTimeline* self) {
spFloatArray_dispose(SUB_CAST(spCurveTimeline, self)->curves);
}
void _spCurveTimeline_setBezier (spCurveTimeline* self, int bezier, int frame, float value, float time1, float value1, float cx1, float cy1, float cx2, float cy2, float time2, float value2) {
float tmpx, tmpy, dddx, dddy,ddx, ddy, dx, dy, x, y;
int i = spTimeline_getFrameCount(SUPER(self)) + bezier * BEZIER_SIZE, n;
float* curves = self->curves->items;
if (value == 0) curves[frame] = CURVE_BEZIER + i;
tmpx = (time1 - cx1 * 2 + cx2) * 0.03; tmpy = (value1 - cy1 * 2 + cy2) * 0.03;
dddx = ((cx1 - cx2) * 3 - time1 + time2) * 0.006; dddy = ((cy1 - cy2) * 3 - value1 + value2) * 0.006;
ddx = tmpx * 2 + dddx; ddy = tmpy * 2 + dddy;
dx = (cx1 - time1) * 0.3 + tmpx + dddx * 0.16666667; dy = (cy1 - value1) * 0.3 + tmpy + dddy * 0.16666667;
x = time1 + dx, y = value1 + dy;
for (n = i + BEZIER_SIZE; i < n; i += 2) {
curves[i] = x;
curves[i + 1] = y;
dx += ddx;
dy += ddy;
ddx += dddx;
ddy += dddy;
x += dx;
y += dy;
}
}
float _spCurveTimeline_getBezierValue(spCurveTimeline* self, float time, int frame, int valueOffset, int i) {
float* curves = self->curves->items;
float* frames = SUPER(self)->frames->items;
float x, y;
int n;
if (curves[i] > time) {
x = frames[frame]; y = frames[frame + valueOffset];
return y + (time - x) / (curves[i] - x) * (curves[i + 1] - y);
}
n = i + BEZIER_SIZE;
for (i += 2; i < n; i += 2) {
if (curves[i] >= time) {
x = curves[i - 2]; y = curves[i - 1];
return y + (time - x) / (curves[i] - x) * (curves[i + 1] - y);
}
}
frame += self->super.frameEntries;
x = curves[n - 2]; y = curves[n - 1];
return y + (time - x) / (frames[frame] - x) * (frames[frame + valueOffset] - y);
}
void spCurveTimeline_setLinear (spCurveTimeline* self, int frameIndex) {
self->curves[frameIndex * BEZIER_SIZE] = CURVE_LINEAR;
self->curves->items[frameIndex * BEZIER_SIZE] = CURVE_LINEAR;
}
void spCurveTimeline_setStepped (spCurveTimeline* self, int frameIndex) {
self->curves[frameIndex * BEZIER_SIZE] = CURVE_STEPPED;
self->curves->items[frameIndex * BEZIER_SIZE] = CURVE_STEPPED;
}
void spCurveTimeline_setCurve (spCurveTimeline* self, int frameIndex, float cx1, float cy1, float cx2, float cy2) {
float tmpx = (-cx1 * 2 + cx2) * 0.03f, tmpy = (-cy1 * 2 + cy2) * 0.03f;
float dddfx = ((cx1 - cx2) * 3 + 1) * 0.006f, dddfy = ((cy1 - cy2) * 3 + 1) * 0.006f;
float ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy;
float dfx = cx1 * 0.3f + tmpx + dddfx * 0.16666667f, dfy = cy1 * 0.3f + tmpy + dddfy * 0.16666667f;
float x = dfx, y = dfy;
#define CURVE1_ENTRIES 2
#define CURVE1_VALUE 1
int i = frameIndex * BEZIER_SIZE, n = i + BEZIER_SIZE - 1;
self->curves[i++] = CURVE_BEZIER;
for (; i < n; i += 2) {
self->curves[i] = x;
self->curves[i + 1] = y;
dfx += ddfx;
dfy += ddfy;
ddfx += dddfx;
ddfy += dddfy;
x += dfx;
y += dfy;
}
void spCurveTimeline1_setFrame(spCurveTimeline1* self, int frame, float time, float value) {
float *frames = self->super.frames->items;
frame <<= 1;
frames[frame] = time;
frames[frame + CURVE1_VALUE] = value;
}
float spCurveTimeline_getCurvePercent (const spCurveTimeline* self, int frameIndex, float percent) {
float x, y;
int i = frameIndex * BEZIER_SIZE, start, n;
float type = self->curves[i];
percent = CLAMP(percent, 0, 1);
if (type == CURVE_LINEAR) return percent;
if (type == CURVE_STEPPED) return 0;
i++;
x = 0;
for (start = i, n = i + BEZIER_SIZE - 1; i < n; i += 2) {
x = self->curves[i];
if (x >= percent) {
float prevX, prevY;
if (i == start) {
prevX = 0;
prevY = 0;
} else {
prevX = self->curves[i - 2];
prevY = self->curves[i - 1];
}
return prevY + (self->curves[i + 1] - prevY) * (percent - prevX) / (x - prevX);
float spCurveTimeline1_getCurveValue(spCurveTimeline1* self, float time) {
float *frames = self->super.frames->items;
float *curves = self->curves->items;
int i = self->super.frames->size - 2;
int ii, curveType;
for (ii = 2; ii <= i; ii += 2) {
if (frames[ii] > time) {
i = ii - 2;
break;
}
}
y = self->curves[i - 1];
return y + (1 - y) * (percent - x) / (1 - x); /* Last point is 1,1. */
}
/* @param target After the first and before the last entry. */
static int binarySearch (float *values, int valuesLength, float target, int step) {
int low = 0, current;
int high = valuesLength / step - 2;
if (high == 0) return step;
current = high >> 1;
while (1) {
if (values[(current + 1) * step] <= target)
low = current + 1;
else
high = current;
if (low == high) return (low + 1) * step;
current = (low + high) >> 1;
curveType = (int)curves[i >> 1];
switch (curveType) {
case CURVE_LINEAR: {
float before = frames[i], value = frames[i + CURVE1_VALUE];
return value + (time - before) / (frames[i + CURVE1_ENTRIES] - before) *
(frames[i + CURVE1_ENTRIES + CURVE1_VALUE] - value);
}
return 0;
}
int _spCurveTimeline_binarySearch (float *values, int valuesLength, float target, int step) {
return binarySearch(values, valuesLength, target, step);
}
/* @param target After the first and before the last entry. */
static int binarySearch1 (float *values, int valuesLength, float target) {
int low = 0, current;
int high = valuesLength - 2;
if (high == 0) return 1;
current = high >> 1;
while (1) {
if (values[(current + 1)] <= target)
low = current + 1;
else
high = current;
if (low == high) return low + 1;
current = (low + high) >> 1;
case CURVE_STEPPED:
return frames[i + CURVE1_VALUE];
}
return 0;
return _spCurveTimeline_getBezierValue(self, time, i, CURVE1_VALUE, curveType - CURVE_BEZIER);
}
/**/
#define CURVE2_ENTRIES 3
#define CURVE2_VALUE1 1
#define CURVE2_VALUE2 2
void _spBaseTimeline_dispose (spTimeline* timeline) {
struct spBaseTimeline* self = SUB_CAST(struct spBaseTimeline, timeline);
_spCurveTimeline_deinit(SUPER(self));
FREE(self->frames);
FREE(self);
}
/* 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, spMixBlend blend, spMixDirection direction),
int (*getPropertyId) (const spTimeline* self)
) {
struct spBaseTimeline* self = NEW(struct spBaseTimeline);
_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);
return self;
SP_API void spCurveTimeline2_setFrame(spCurveTimeline1* self, int frame, float time, float value1, float value2) {
float *frames = self->super.frames->items;
frame *= CURVE2_ENTRIES;
frames[frame] = time;
frames[frame + CURVE2_VALUE1] = value1;
frames[frame + CURVE2_VALUE2] = value2;
}
/**/
@ -276,30 +262,26 @@ void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction
) {
spBone *bone;
int frame;
float prevRotation, frameTime, percent, r;
float r;
spRotateTimeline* self = SUB_CAST(spRotateTimeline, timeline);
float *frames = self->super.super.frames->items;
bone = skeleton->bones[self->boneIndex];
if (!bone->active) return;
if (time < self->frames[0]) {
if (time < frames[0]) {
switch (blend) {
case SP_MIX_BLEND_SETUP:
bone->rotation = bone->data->rotation;
return;
case SP_MIX_BLEND_FIRST:
r = bone->data->rotation - bone->rotation;
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
bone->rotation += r * alpha;
case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
; /* to appease compiler */
bone->rotation += (bone->data->rotation - bone->rotation) * alpha;
default: {}
}
return;
}
if (time >= self->frames[self->framesCount - ROTATE_ENTRIES]) { /* Time is after last frame. */
r = self->frames[self->framesCount + ROTATE_PREV_ROTATION];
r = spCurveTimeline1_getCurveValue(SUPER(self), time);
switch (blend) {
case SP_MIX_BLEND_SETUP:
bone->rotation = bone->data->rotation + r * alpha;
@ -307,31 +289,9 @@ void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
case SP_MIX_BLEND_FIRST:
case SP_MIX_BLEND_REPLACE:
r += bone->data->rotation - bone->rotation;
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360; /* Wrap within -180 and 180. */
case SP_MIX_BLEND_ADD:
bone->rotation += r * alpha;
}
return;
}
/* Interpolate between the previous frame and the current frame. */
frame = binarySearch(self->frames, self->framesCount, time, ROTATE_ENTRIES);
prevRotation = self->frames[frame + ROTATE_PREV_ROTATION];
frameTime = self->frames[frame];
percent = spCurveTimeline_getCurvePercent(SUPER(self), (frame >> 1) - 1, 1 - (time - frameTime) / (self->frames[frame + ROTATE_PREV_TIME] - frameTime));
r = self->frames[frame + ROTATE_ROTATION] - prevRotation;
r = prevRotation + (r - (16384 - (int)(16384.499999999996 - r / 360)) * 360) * percent;
switch (blend) {
case SP_MIX_BLEND_SETUP:
bone->rotation = bone->data->rotation + (r - (16384 - (int)(16384.499999999996 - r / 360)) * 360) * 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 - (16384 - (int)(16384.499999999996 - r / 360)) * 360) * alpha;
}
UNUSED(lastTime);
UNUSED(firedEvents);
@ -339,40 +299,36 @@ void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
UNUSED(direction);
}
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, _spRotateTimeline_getPropertyId);
spRotateTimeline* spRotateTimeline_create (int frameCount, int bezierCount, int boneIndex) {
spRotateTimeline* timeline = NEW(spRotateTimeline);
spPropertyId ids[1];
ids[0] = ((spPropertyId)SP_PROPERTY_ROTATE << 32) | boneIndex;
_spCurveTimeline_init(SUPER(timeline), frameCount, CURVE1_ENTRIES, bezierCount, ids, 1, _spCurveTimeline_dispose, _spRotateTimeline_apply);
timeline->boneIndex = boneIndex;
return timeline;
}
void spRotateTimeline_setFrame (spRotateTimeline* self, int frameIndex, float time, float degrees) {
frameIndex <<= 1;
self->frames[frameIndex] = time;
self->frames[frameIndex + ROTATE_ROTATION] = degrees;
spCurveTimeline1_setFrame(SUPER(self), frameIndex, time, degrees);
}
/**/
static const int TRANSLATE_PREV_TIME = -3, TRANSLATE_PREV_X = -2, TRANSLATE_PREV_Y = -1;
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, spMixBlend blend, spMixDirection direction
) {
spBone *bone;
int frame;
float frameTime, percent;
float x, y;
float *frames;
int framesCount;
float x, y, t;
int i, curveType;
spTranslateTimeline* self = SUB_CAST(spTranslateTimeline, timeline);
float *frames = self->super.super.frames->items;
float *curves = self->super.curves->items;
bone = skeleton->bones[self->boneIndex];
if (!bone->active) return;
if (time < self->frames[0]) {
if (time < frames[0]) {
switch (blend) {
case SP_MIX_BLEND_SETUP:
bone->x = bone->data->x;
@ -381,30 +337,34 @@ void _spTranslateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleto
case SP_MIX_BLEND_FIRST:
bone->x += (bone->data->x - bone->x) * alpha;
bone->y += (bone->data->y - bone->y) * alpha;
case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
; /* to appease compiler */
default: {}
}
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;
i = search(frames, time, CURVE2_ENTRIES);
curveType = (int)curves[i / CURVE2_ENTRIES];
switch (curveType) {
case CURVE_LINEAR: {
float before = frames[i];
x = frames[i + CURVE2_VALUE1];
y = frames[i + CURVE2_VALUE2];
t = (time - before) / (frames[i + CURVE2_ENTRIES] - before);
x += (frames[i + CURVE2_ENTRIES + CURVE2_VALUE1] - x) * t;
y += (frames[i + CURVE2_ENTRIES + CURVE2_VALUE2] - y) * t;
break;
}
case CURVE_STEPPED: {
x = frames[i + CURVE2_VALUE1];
y = frames[i + CURVE2_VALUE2];
break;
}
default: {
x = _spCurveTimeline_getBezierValue(SUPER(self), time, i, CURVE2_VALUE1, curveType - CURVE_BEZIER);
y = _spCurveTimeline_getBezierValue(SUPER(self), time, i, CURVE2_VALUE2, curveType + BEZIER_SIZE - CURVE_BEZIER);
}
}
switch (blend) {
case SP_MIX_BLEND_SETUP:
bone->x = bone->data->x + x * alpha;
@ -426,19 +386,138 @@ void _spTranslateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleto
UNUSED(direction);
}
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, _spTranslateTimeline_getPropertyId);
spTranslateTimeline* spTranslateTimeline_create (int frameCount, int bezierCount, int boneIndex) {
spTranslateTimeline* timeline = NEW(spTranslateTimeline);
spPropertyId ids[2];
ids[0] = ((spPropertyId)SP_PROPERTY_X << 32) | boneIndex;
ids[1] = ((spPropertyId)SP_PROPERTY_Y << 32) | boneIndex;
_spCurveTimeline_init(SUPER(timeline), frameCount, CURVE2_ENTRIES, bezierCount, ids, 2, _spCurveTimeline_dispose, _spTranslateTimeline_apply);
timeline->boneIndex = boneIndex;
return timeline;
}
void spTranslateTimeline_setFrame (spTranslateTimeline* self, int frameIndex, float time, float x, float y) {
frameIndex *= TRANSLATE_ENTRIES;
self->frames[frameIndex] = time;
self->frames[frameIndex + TRANSLATE_X] = x;
self->frames[frameIndex + TRANSLATE_Y] = y;
spCurveTimeline2_setFrame(SUPER(self), frameIndex, time, x, y);
}
/**/
void _spTranslateXTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction
) {
spBone *bone;
float x, t;
int i, curveType;
spTranslateXTimeline* self = SUB_CAST(spTranslateXTimeline, timeline);
float *frames = self->super.super.frames->items;
float *curves = self->super.curves->items;
bone = skeleton->bones[self->boneIndex];
if (!bone->active) return;
if (time < frames[0]) {
switch (blend) {
case SP_MIX_BLEND_SETUP:
bone->x = bone->data->x;
return;
case SP_MIX_BLEND_FIRST:
bone->x += (bone->data->x - bone->x) * alpha;
default: {}
}
return;
}
x = spCurveTimeline1_getCurveValue(SUPER(self), time);
switch (blend) {
case SP_MIX_BLEND_SETUP:
bone->x = bone->data->x + x * alpha;
break;
case SP_MIX_BLEND_FIRST:
case SP_MIX_BLEND_REPLACE:
bone->x += (bone->data->x + x - bone->x) * alpha;
break;
case SP_MIX_BLEND_ADD:
bone->x += x * alpha;
}
UNUSED(lastTime);
UNUSED(firedEvents);
UNUSED(eventsCount);
UNUSED(direction);
}
spTranslateXTimeline* spTranslateXTimeline_create (int frameCount, int bezierCount, int boneIndex) {
spTranslateXTimeline* timeline = NEW(spTranslateXTimeline);
spPropertyId ids[1];
ids[0] = ((spPropertyId)SP_PROPERTY_X << 32) | boneIndex;
_spCurveTimeline_init(SUPER(timeline), frameCount, CURVE1_ENTRIES, bezierCount, ids, 1, _spCurveTimeline_dispose, _spTranslateXTimeline_apply);
timeline->boneIndex = boneIndex;
return timeline;
}
void spTranslateXTimeline_setFrame (spTranslateXTimeline* self, int frame, float time, float x) {
spCurveTimeline1_setFrame(SUPER(self), frame, time, x);
}
/**/
void _spTranslateYTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction
) {
spBone *bone;
int frame;
float y, t;
int i, curveType;
spTranslateXTimeline* self = SUB_CAST(spTranslateXTimeline, timeline);
float *frames = self->super.super.frames->items;
float *curves = self->super.curves->items;
bone = skeleton->bones[self->boneIndex];
if (!bone->active) return;
if (time < frames[0]) {
switch (blend) {
case SP_MIX_BLEND_SETUP:
bone->y = bone->data->y;
return;
case SP_MIX_BLEND_FIRST:
bone->y += (bone->data->y - bone->y) * alpha;
default: {}
}
return;
}
y = spCurveTimeline1_getCurveValue(SUPER(self), time);
switch (blend) {
case SP_MIX_BLEND_SETUP:
bone->y = bone->data->y + y * alpha;
break;
case SP_MIX_BLEND_FIRST:
case SP_MIX_BLEND_REPLACE:
bone->y += (bone->data->y + y - bone->y) * alpha;
break;
case SP_MIX_BLEND_ADD:
bone->y += y * alpha;
}
UNUSED(lastTime);
UNUSED(firedEvents);
UNUSED(eventsCount);
}
spTranslateYTimeline* spTranslateYTimeline_create (int frameCount, int bezierCount, int boneIndex) {
spTranslateYTimeline* timeline = NEW(spTranslateYTimeline);
spPropertyId ids[1];
ids[0] = ((spPropertyId)SP_PROPERTY_Y << 32) | boneIndex;
_spCurveTimeline_init(SUPER(timeline), frameCount, CURVE1_ENTRIES, bezierCount, ids, 1, _spCurveTimeline_dispose, _spTranslateYTimeline_apply);
timeline->boneIndex = boneIndex;
return timeline;
}
void spTranslateYTimeline_setFrame (spTranslateYTimeline* self, int frame, float time, float y) {
spCurveTimeline1_setFrame(SUPER(self), frame, time, y);
}
/**/
@ -447,16 +526,16 @@ void _spScaleTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction
) {
spBone *bone;
int frame;
float frameTime, percent, x, y;
float *frames;
int framesCount;
int i, curveType;
float x, y, t;
spScaleTimeline* self = SUB_CAST(spScaleTimeline, timeline);
float *frames = self->super.super.frames->items;
float *curves = self->super.curves->items;
bone = skeleton->bones[self->boneIndex];
if (!bone->active) return;
if (time < self->frames[0]) {
if (time < frames[0]) {
switch (blend) {
case SP_MIX_BLEND_SETUP:
bone->scaleX = bone->data->scaleX;
@ -465,30 +544,36 @@ void _spScaleTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
case SP_MIX_BLEND_FIRST:
bone->scaleX += (bone->data->scaleX - bone->scaleX) * alpha;
bone->scaleY += (bone->data->scaleY - bone->scaleY) * alpha;
case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
; /* to appease compiler */
default: {}
}
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;
i = search(frames, time, CURVE2_ENTRIES);
curveType = (int)curves[i / CURVE2_ENTRIES];
switch (curveType) {
case CURVE_LINEAR: {
float before = frames[i];
x = frames[i + CURVE2_VALUE1];
y = frames[i + CURVE2_VALUE2];
t = (time - before) / (frames[i + CURVE2_ENTRIES] - before);
x += (frames[i + CURVE2_ENTRIES + CURVE2_VALUE1] - x) * t;
y += (frames[i + CURVE2_ENTRIES + CURVE2_VALUE2] - y) * t;
break;
}
case CURVE_STEPPED: {
x = frames[i + CURVE2_VALUE1];
y = frames[i + CURVE2_VALUE2];
break;
}
default: {
x = _spCurveTimeline_getBezierValue(SUPER(self), time, i, CURVE2_VALUE1, curveType - CURVE_BEZIER);
y = _spCurveTimeline_getBezierValue(SUPER(self), time, i, CURVE2_VALUE2, curveType + BEZIER_SIZE - CURVE_BEZIER);
}
}
x *= bone->data->scaleX;
y *= bone->data->scaleY;
if (alpha == 1) {
if (blend == SP_MIX_BLEND_ADD) {
bone->scaleX += x - bone->data->scaleX;
@ -549,16 +634,196 @@ void _spScaleTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
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, _spScaleTimeline_getPropertyId);
spScaleTimeline* spScaleTimeline_create (int frameCount, int bezierCount, int boneIndex) {
spScaleTimeline* timeline = NEW(spScaleTimeline);
spPropertyId ids[2];
ids[0] = ((spPropertyId)SP_PROPERTY_SCALEX << 32) | boneIndex;
ids[1] = ((spPropertyId)SP_PROPERTY_SCALEY << 32) | boneIndex;
_spCurveTimeline_init(SUPER(timeline), frameCount, CURVE2_ENTRIES, bezierCount, ids, 2, _spCurveTimeline_dispose, _spScaleTimeline_apply);
timeline->boneIndex = boneIndex;
return timeline;
}
void spScaleTimeline_setFrame (spScaleTimeline* self, int frameIndex, float time, float x, float y) {
spTranslateTimeline_setFrame(self, frameIndex, time, x, y);
spCurveTimeline2_setFrame(SUPER(self), frameIndex, time, x, y);
}
/**/
void _spScaleXTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction
) {
spBone *bone;
int frame;
float x, t;
int i, curveType;
spTranslateXTimeline* self = SUB_CAST(spTranslateXTimeline, timeline);
float *frames = self->super.super.frames->items;
float *curves = self->super.curves->items;
bone = skeleton->bones[self->boneIndex];
if (!bone->active) return;
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:
bx = bone->scaleX;
bone->scaleX = bx + (ABS(x) * SIGNUM(bx) - 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:
bx = SIGNUM(x);
bone->scaleX = ABS(bone->scaleX) * bx + (x - ABS(bone->data->scaleX) * bx) * alpha;
}
}
}
UNUSED(lastTime);
UNUSED(firedEvents);
UNUSED(eventsCount);
}
spScaleXTimeline* spScaleXTimeline_create (int frameCount, int bezierCount, int boneIndex) {
spScaleXTimeline* timeline = NEW(spScaleXTimeline);
spPropertyId ids[1];
ids[0] = ((spPropertyId)SP_PROPERTY_SCALEX << 32) | boneIndex;
_spCurveTimeline_init(SUPER(timeline), frameCount, CURVE1_ENTRIES, bezierCount, ids, 1, _spCurveTimeline_dispose, _spScaleXTimeline_apply);
timeline->boneIndex = boneIndex;
return timeline;
}
void spScaleXTimeline_setFrame (spScaleXTimeline* self, int frame, float time, float y) {
spCurveTimeline1_setFrame(SUPER(self), frame, time, y);
}
/**/
void _spScaleYTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction
) {
spBone *bone;
int frame;
float y, t;
int i, curveType;
spTranslateXTimeline* self = SUB_CAST(spTranslateXTimeline, timeline);
float *frames = self->super.super.frames->items;
float *curves = self->super.curves->items;
bone = skeleton->bones[self->boneIndex];
if (!bone->active) return;
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:
by = bone->scaleY;
bone->scaleY = by + (ABS(y) * SIGNUM(by) - 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:
by = SIGNUM(y);
bone->scaleY = ABS(bone->scaleY) * by + (y - ABS(bone->data->scaleY) * by) * alpha;
}
}
}
UNUSED(lastTime);
UNUSED(firedEvents);
UNUSED(eventsCount);
}
spScaleYTimeline* spScaleYTimeline_create (int frameCount, int bezierCount, int boneIndex) {
spScaleYTimeline* timeline = NEW(spScaleYTimeline);
spPropertyId ids[1];
ids[0] = ((spPropertyId)SP_PROPERTY_SCALEY << 32) | boneIndex;
_spCurveTimeline_init(SUPER(timeline), frameCount, CURVE1_ENTRIES, bezierCount, ids, 1, _spCurveTimeline_dispose, _spScaleYTimeline_apply);
timeline->boneIndex = boneIndex;
return timeline;
}
void spScaleYTimeline_setFrame (spScaleYTimeline* self, int frame, float time, float y) {
spCurveTimeline1_setFrame(SUPER(self), frame, time, y);
}
/**/