mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-08 08:14:53 +08:00
FFD for spine-c and spine-sfml.
This commit is contained in:
parent
6432e43ea2
commit
99a8de4bb4
@ -32,6 +32,7 @@
|
||||
#define SPINE_ANIMATION_H_
|
||||
|
||||
#include <spine/Event.h>
|
||||
#include <spine/Attachment.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -81,7 +82,8 @@ typedef enum {
|
||||
SP_TIMELINE_COLOR,
|
||||
SP_TIMELINE_ATTACHMENT,
|
||||
SP_TIMELINE_EVENT,
|
||||
SP_TIMELINE_DRAWORDER
|
||||
SP_TIMELINE_DRAWORDER,
|
||||
SP_TIMELINE_FFD
|
||||
} spTimelineType;
|
||||
|
||||
struct spTimeline {
|
||||
@ -135,7 +137,7 @@ typedef spCurveTimeline CurveTimeline;
|
||||
|
||||
typedef struct spBaseTimeline {
|
||||
spCurveTimeline super;
|
||||
int const framesLength;
|
||||
int const framesCount;
|
||||
float* const frames; /* time, angle, ... for rotate. time, x, y, ... for translate and scale. */
|
||||
int boneIndex;
|
||||
} spRotateTimeline;
|
||||
@ -182,7 +184,7 @@ typedef spScaleTimeline ScaleTimeline;
|
||||
|
||||
typedef struct {
|
||||
spCurveTimeline super;
|
||||
int const framesLength;
|
||||
int const framesCount;
|
||||
float* const frames; /* time, r, g, b, a, ... */
|
||||
int slotIndex;
|
||||
} spColorTimeline;
|
||||
@ -201,7 +203,7 @@ typedef spColorTimeline ColorTimeline;
|
||||
|
||||
typedef struct {
|
||||
spTimeline super;
|
||||
int const framesLength;
|
||||
int const framesCount;
|
||||
float* const frames; /* time, ... */
|
||||
int slotIndex;
|
||||
const char** const attachmentNames;
|
||||
@ -222,7 +224,7 @@ typedef spAttachmentTimeline AttachmentTimeline;
|
||||
|
||||
typedef struct {
|
||||
spTimeline super;
|
||||
int const framesLength;
|
||||
int const framesCount;
|
||||
float* const frames; /* time, ... */
|
||||
spEvent** const events;
|
||||
} spEventTimeline;
|
||||
@ -241,7 +243,7 @@ typedef spEventTimeline EventTimeline;
|
||||
|
||||
typedef struct {
|
||||
spTimeline super;
|
||||
int const framesLength;
|
||||
int const framesCount;
|
||||
float* const frames; /* time, ... */
|
||||
const int** const drawOrders;
|
||||
int const slotCount;
|
||||
@ -257,6 +259,28 @@ typedef spDrawOrderTimeline DrawOrderTimeline;
|
||||
#define DrawOrderTimeline_setFrame(...) spDrawOrderTimeline_setFrame(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/**/
|
||||
|
||||
typedef struct {
|
||||
spCurveTimeline super;
|
||||
int const framesCount;
|
||||
float* const frames; /* time, ... */
|
||||
int const frameVerticesCount;
|
||||
const float** const frameVertices;
|
||||
int slotIndex;
|
||||
spAttachment* attachment;
|
||||
} spFFDTimeline;
|
||||
|
||||
spFFDTimeline* spFFDTimeline_create (int frameCount, int frameVerticesCount);
|
||||
|
||||
void spFFDTimeline_setFrame (spFFDTimeline* self, int frameIndex, float time, float* vertices);
|
||||
|
||||
#ifdef SPINE_SHORT_NAMES
|
||||
typedef spFFDTimeline FFDTimeline;
|
||||
#define FFDTimeline_create(...) spFFDTimeline_create(__VA_ARGS__)
|
||||
#define FFDTimeline_setFrame(...) spFFDTimeline_setFrame(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -48,6 +48,7 @@ typedef struct spSlot {
|
||||
float r, g, b, a;
|
||||
spAttachment* const attachment;
|
||||
|
||||
int attachmentVerticesCapacity;
|
||||
int attachmentVerticesCount;
|
||||
float* attachmentVertices;
|
||||
} spSlot;
|
||||
|
||||
@ -233,8 +233,8 @@ struct spBaseTimeline* _spBaseTimeline_create (int frameCount, spTimelineType ty
|
||||
struct spBaseTimeline* self = NEW(struct spBaseTimeline);
|
||||
_spCurveTimeline_init(SUPER(self), type, frameCount, _spBaseTimeline_dispose, apply);
|
||||
|
||||
CONST_CAST(int, self->framesLength) = frameCount * frameSize;
|
||||
CONST_CAST(float*, self->frames) = CALLOC(float, self->framesLength);
|
||||
CONST_CAST(int, self->framesCount) = frameCount * frameSize;
|
||||
CONST_CAST(float*, self->frames) = CALLOC(float, self->framesCount);
|
||||
|
||||
return self;
|
||||
}
|
||||
@ -256,8 +256,8 @@ void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
|
||||
|
||||
bone = skeleton->bones[self->boneIndex];
|
||||
|
||||
if (time >= self->frames[self->framesLength - 2]) { /* Time is after last frame. */
|
||||
float amount = bone->data->rotation + self->frames[self->framesLength - 1] - bone->rotation;
|
||||
if (time >= self->frames[self->framesCount - 2]) { /* Time is after last frame. */
|
||||
float amount = bone->data->rotation + self->frames[self->framesCount - 1] - bone->rotation;
|
||||
while (amount > 180)
|
||||
amount -= 360;
|
||||
while (amount < -180)
|
||||
@ -266,8 +266,8 @@ void _spRotateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton,
|
||||
return;
|
||||
}
|
||||
|
||||
/* Interpolate between the last frame and the current frame. */
|
||||
frameIndex = binarySearch(self->frames, self->framesLength, time, 2);
|
||||
/* Interpolate between the previous frame and the current frame. */
|
||||
frameIndex = binarySearch(self->frames, self->framesCount, time, 2);
|
||||
lastFrameValue = self->frames[frameIndex - 1];
|
||||
frameTime = self->frames[frameIndex];
|
||||
percent = 1 - (time - frameTime) / (self->frames[frameIndex + ROTATE_LAST_FRAME_TIME] - frameTime);
|
||||
@ -314,14 +314,14 @@ void _spTranslateTimeline_apply (const spTimeline* timeline, spSkeleton* skeleto
|
||||
|
||||
bone = skeleton->bones[self->boneIndex];
|
||||
|
||||
if (time >= self->frames[self->framesLength - 3]) { /* Time is after last frame. */
|
||||
bone->x += (bone->data->x + self->frames[self->framesLength - 2] - bone->x) * alpha;
|
||||
bone->y += (bone->data->y + self->frames[self->framesLength - 1] - bone->y) * alpha;
|
||||
if (time >= self->frames[self->framesCount - 3]) { /* Time is after last frame. */
|
||||
bone->x += (bone->data->x + self->frames[self->framesCount - 2] - bone->x) * alpha;
|
||||
bone->y += (bone->data->y + self->frames[self->framesCount - 1] - bone->y) * alpha;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Interpolate between the last frame and the current frame. */
|
||||
frameIndex = binarySearch(self->frames, self->framesLength, time, 3);
|
||||
/* Interpolate between the previous frame and the current frame. */
|
||||
frameIndex = binarySearch(self->frames, self->framesCount, time, 3);
|
||||
lastFrameX = self->frames[frameIndex - 2];
|
||||
lastFrameY = self->frames[frameIndex - 1];
|
||||
frameTime = self->frames[frameIndex];
|
||||
@ -358,14 +358,14 @@ void _spScaleTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
|
||||
if (time < self->frames[0]) return; /* Time is before first frame. */
|
||||
|
||||
bone = skeleton->bones[self->boneIndex];
|
||||
if (time >= self->frames[self->framesLength - 3]) { /* Time is after last frame. */
|
||||
bone->scaleX += (bone->data->scaleX - 1 + self->frames[self->framesLength - 2] - bone->scaleX) * alpha;
|
||||
bone->scaleY += (bone->data->scaleY - 1 + self->frames[self->framesLength - 1] - bone->scaleY) * alpha;
|
||||
if (time >= self->frames[self->framesCount - 3]) { /* Time is after last frame. */
|
||||
bone->scaleX += (bone->data->scaleX - 1 + self->frames[self->framesCount - 2] - bone->scaleX) * alpha;
|
||||
bone->scaleY += (bone->data->scaleY - 1 + self->frames[self->framesCount - 1] - bone->scaleY) * alpha;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Interpolate between the last frame and the current frame. */
|
||||
frameIndex = binarySearch(self->frames, self->framesLength, time, 3);
|
||||
/* Interpolate between the previous frame and the current frame. */
|
||||
frameIndex = binarySearch(self->frames, self->framesCount, time, 3);
|
||||
lastFrameX = self->frames[frameIndex - 2];
|
||||
lastFrameY = self->frames[frameIndex - 1];
|
||||
frameTime = self->frames[frameIndex];
|
||||
@ -406,16 +406,16 @@ void _spColorTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
|
||||
|
||||
slot = skeleton->slots[self->slotIndex];
|
||||
|
||||
if (time >= self->frames[self->framesLength - 5]) {
|
||||
if (time >= self->frames[self->framesCount - 5]) {
|
||||
/* Time is after last frame. */
|
||||
int i = self->framesLength - 1;
|
||||
int i = self->framesCount - 1;
|
||||
r = self->frames[i - 3];
|
||||
g = self->frames[i - 2];
|
||||
b = self->frames[i - 1];
|
||||
a = self->frames[i];
|
||||
} else {
|
||||
/* Interpolate between the last frame and the current frame. */
|
||||
frameIndex = binarySearch(self->frames, self->framesLength, time, 5);
|
||||
/* Interpolate between the previous frame and the current frame. */
|
||||
frameIndex = binarySearch(self->frames, self->framesCount, time, 5);
|
||||
lastFrameR = self->frames[frameIndex - 4];
|
||||
lastFrameG = self->frames[frameIndex - 3];
|
||||
lastFrameB = self->frames[frameIndex - 2];
|
||||
@ -465,10 +465,10 @@ void _spAttachmentTimeline_apply (const spTimeline* timeline, spSkeleton* skelet
|
||||
|
||||
if (time < self->frames[0]) return; /* Time is before first frame. */
|
||||
|
||||
if (time >= self->frames[self->framesLength - 1]) /* Time is after last frame. */
|
||||
frameIndex = self->framesLength - 1;
|
||||
if (time >= self->frames[self->framesCount - 1]) /* Time is after last frame. */
|
||||
frameIndex = self->framesCount - 1;
|
||||
else
|
||||
frameIndex = binarySearch(self->frames, self->framesLength, time, 1) - 1;
|
||||
frameIndex = binarySearch(self->frames, self->framesCount, time, 1) - 1;
|
||||
|
||||
attachmentName = self->attachmentNames[frameIndex];
|
||||
spSlot_setAttachment(skeleton->slots[self->slotIndex],
|
||||
@ -481,7 +481,7 @@ void _spAttachmentTimeline_dispose (spTimeline* timeline) {
|
||||
|
||||
_spTimeline_deinit(timeline);
|
||||
|
||||
for (i = 0; i < self->framesLength; ++i)
|
||||
for (i = 0; i < self->framesCount; ++i)
|
||||
FREE(self->attachmentNames[i]);
|
||||
FREE(self->attachmentNames);
|
||||
FREE(self->frames);
|
||||
@ -492,7 +492,7 @@ spAttachmentTimeline* spAttachmentTimeline_create (int frameCount) {
|
||||
spAttachmentTimeline* self = NEW(spAttachmentTimeline);
|
||||
_spTimeline_init(SUPER(self), SP_TIMELINE_ATTACHMENT, _spAttachmentTimeline_dispose, _spAttachmentTimeline_apply);
|
||||
|
||||
CONST_CAST(int, self->framesLength) = frameCount;
|
||||
CONST_CAST(int, self->framesCount) = frameCount;
|
||||
CONST_CAST(float*, self->frames) = CALLOC(float, frameCount);
|
||||
CONST_CAST(char**, self->attachmentNames) = CALLOC(char*, frameCount);
|
||||
|
||||
@ -521,22 +521,22 @@ void _spEventTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, f
|
||||
if (lastTime > time) { /* Fire events after last time for looped animations. */
|
||||
_spEventTimeline_apply(timeline, skeleton, lastTime, (float)INT_MAX, firedEvents, eventCount, alpha);
|
||||
lastTime = -1;
|
||||
} else if (lastTime >= self->frames[self->framesLength - 1]) /* Last time is after last frame. */
|
||||
return;
|
||||
} else if (lastTime >= self->frames[self->framesCount - 1]) /* Last time is after last frame. */
|
||||
return;
|
||||
if (time < self->frames[0]) return; /* Time is before first frame. */
|
||||
|
||||
if (lastTime < self->frames[0])
|
||||
frameIndex = 0;
|
||||
else {
|
||||
float frame;
|
||||
frameIndex = binarySearch(self->frames, self->framesLength, lastTime, 1);
|
||||
frameIndex = binarySearch(self->frames, self->framesCount, lastTime, 1);
|
||||
frame = self->frames[frameIndex];
|
||||
while (frameIndex > 0) { /* Fire multiple events with the same frame. */
|
||||
if (self->frames[frameIndex - 1] != frame) break;
|
||||
frameIndex--;
|
||||
}
|
||||
}
|
||||
for (; frameIndex < self->framesLength && time >= self->frames[frameIndex]; frameIndex++) {
|
||||
for (; frameIndex < self->framesCount && time >= self->frames[frameIndex]; frameIndex++) {
|
||||
firedEvents[*eventCount] = self->events[frameIndex];
|
||||
(*eventCount)++;
|
||||
}
|
||||
@ -548,7 +548,7 @@ void _spEventTimeline_dispose (spTimeline* timeline) {
|
||||
|
||||
_spTimeline_deinit(timeline);
|
||||
|
||||
for (i = 0; i < self->framesLength; ++i)
|
||||
for (i = 0; i < self->framesCount; ++i)
|
||||
spEvent_dispose(self->events[i]);
|
||||
FREE(self->events);
|
||||
FREE(self->frames);
|
||||
@ -559,7 +559,7 @@ spEventTimeline* spEventTimeline_create (int frameCount) {
|
||||
spEventTimeline* self = NEW(spEventTimeline);
|
||||
_spTimeline_init(SUPER(self), SP_TIMELINE_EVENT, _spEventTimeline_dispose, _spEventTimeline_apply);
|
||||
|
||||
CONST_CAST(int, self->framesLength) = frameCount;
|
||||
CONST_CAST(int, self->framesCount) = frameCount;
|
||||
CONST_CAST(float*, self->frames) = CALLOC(float, frameCount);
|
||||
CONST_CAST(spEvent**, self->events) = CALLOC(spEvent*, frameCount);
|
||||
|
||||
@ -584,10 +584,10 @@ void _spDrawOrderTimeline_apply (const spTimeline* timeline, spSkeleton* skeleto
|
||||
|
||||
if (time < self->frames[0]) return; /* Time is before first frame. */
|
||||
|
||||
if (time >= self->frames[self->framesLength - 1]) /* Time is after last frame. */
|
||||
frameIndex = self->framesLength - 1;
|
||||
if (time >= self->frames[self->framesCount - 1]) /* Time is after last frame. */
|
||||
frameIndex = self->framesCount - 1;
|
||||
else
|
||||
frameIndex = binarySearch(self->frames, self->framesLength, time, 1) - 1;
|
||||
frameIndex = binarySearch(self->frames, self->framesCount, time, 1) - 1;
|
||||
|
||||
drawOrderToSetupIndex = self->drawOrders[frameIndex];
|
||||
if (!drawOrderToSetupIndex)
|
||||
@ -604,7 +604,7 @@ void _spDrawOrderTimeline_dispose (spTimeline* timeline) {
|
||||
|
||||
_spTimeline_deinit(timeline);
|
||||
|
||||
for (i = 0; i < self->framesLength; ++i)
|
||||
for (i = 0; i < self->framesCount; ++i)
|
||||
FREE(self->drawOrders[i]);
|
||||
FREE(self->drawOrders);
|
||||
FREE(self->frames);
|
||||
@ -615,7 +615,7 @@ spDrawOrderTimeline* spDrawOrderTimeline_create (int frameCount, int slotCount)
|
||||
spDrawOrderTimeline* self = NEW(spDrawOrderTimeline);
|
||||
_spTimeline_init(SUPER(self), SP_TIMELINE_DRAWORDER, _spDrawOrderTimeline_dispose, _spDrawOrderTimeline_apply);
|
||||
|
||||
CONST_CAST(int, self->framesLength) = frameCount;
|
||||
CONST_CAST(int, self->framesCount) = frameCount;
|
||||
CONST_CAST(float*, self->frames) = CALLOC(float, frameCount);
|
||||
CONST_CAST(int**, self->drawOrders) = CALLOC(int*, frameCount);
|
||||
CONST_CAST(int, self->slotCount) = slotCount;
|
||||
@ -634,3 +634,80 @@ void spDrawOrderTimeline_setFrame (spDrawOrderTimeline* self, int frameIndex, fl
|
||||
memcpy(CONST_CAST(int*, self->drawOrders[frameIndex]), drawOrder, self->slotCount * sizeof(int));
|
||||
}
|
||||
}
|
||||
|
||||
/**/
|
||||
|
||||
void _spFFDTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents,
|
||||
int* eventCount, float alpha) {
|
||||
int frameIndex, i;
|
||||
float percent, frameTime;
|
||||
spFFDTimeline* self = (spFFDTimeline*)timeline;
|
||||
|
||||
spSlot *slot = skeleton->slots[self->slotIndex];
|
||||
if (slot->attachment != self->attachment) return;
|
||||
|
||||
if (time < self->frames[0]) {
|
||||
slot->attachmentVerticesCount = 0;
|
||||
return; /* Time is before first frame. */
|
||||
}
|
||||
|
||||
if (slot->attachmentVerticesCount < self->frameVerticesCount) {
|
||||
if (slot->attachmentVerticesCapacity < self->frameVerticesCount) {
|
||||
FREE(slot->attachmentVertices);
|
||||
slot->attachmentVertices = MALLOC(float, self->frameVerticesCount);
|
||||
slot->attachmentVerticesCapacity = self->frameVerticesCount;
|
||||
}
|
||||
slot->attachmentVerticesCount = self->frameVerticesCount;
|
||||
}
|
||||
|
||||
if (time >= self->frames[self->framesCount - 1]) {
|
||||
/* Time is after last frame. */
|
||||
const float* lastVertices = self->frameVertices[self->framesCount - 1];
|
||||
if (alpha < 1) {
|
||||
for (i = 0; i < self->frameVerticesCount; i++)
|
||||
slot->attachmentVertices[i] += (lastVertices[i] - slot->attachmentVertices[i]) * alpha;
|
||||
} else
|
||||
memcpy(slot->attachmentVertices, lastVertices, self->frameVerticesCount);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Interpolate between the previous frame and the current frame. */
|
||||
frameIndex = binarySearch(self->frames, self->framesCount, time, 1);
|
||||
frameTime = self->frames[frameIndex];
|
||||
percent = 1 - (time - frameTime) / (self->frames[frameIndex - 1] - frameTime);
|
||||
percent = spCurveTimeline_getCurvePercent(SUPER(self), frameIndex - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent));
|
||||
|
||||
const float* prevVertices = self->frameVertices[frameIndex - 1];
|
||||
const float* nextVertices = self->frameVertices[frameIndex];
|
||||
|
||||
if (alpha < 1) {
|
||||
for (i = 0; i < self->frameVerticesCount; i++) {
|
||||
float prev = prevVertices[i];
|
||||
slot->attachmentVertices[i] += (prev + (nextVertices[i] - prev) * percent - slot->attachmentVertices[i]) * alpha;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < self->frameVerticesCount; i++) {
|
||||
float prev = prevVertices[i];
|
||||
slot->attachmentVertices[i] = prev + (nextVertices[i] - prev) * percent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
spFFDTimeline* spFFDTimeline_create (int frameCount, int frameVerticesCount) {
|
||||
spFFDTimeline* self = SUB_CAST(spFFDTimeline, _spBaseTimeline_create(frameCount, SP_TIMELINE_FFD, 1, _spFFDTimeline_apply));
|
||||
CONST_CAST(float**, self->frameVertices) = CALLOC(float*, frameCount);
|
||||
CONST_CAST(int, self->frameVerticesCount) = frameVerticesCount;
|
||||
return self;
|
||||
}
|
||||
|
||||
void spFFDTimeline_setFrame (spFFDTimeline* self, int frameIndex, float time, float* vertices) {
|
||||
self->frames[frameIndex] = time;
|
||||
|
||||
FREE(self->frameVertices[frameIndex]);
|
||||
if (!vertices)
|
||||
self->frameVertices[frameIndex] = 0;
|
||||
else {
|
||||
self->frameVertices[frameIndex] = MALLOC(float, self->frameVerticesCount);
|
||||
memcpy(CONST_CAST(float*, self->frameVertices[frameIndex]), vertices, self->frameVerticesCount * sizeof(float));
|
||||
}
|
||||
}
|
||||
|
||||
@ -111,7 +111,7 @@ static const char* parse_string (Json *item, const char* str) {
|
||||
while (*ptr != '\"' && *ptr && ++len)
|
||||
if (*ptr++ == '\\') ptr++; /* Skip escaped quotes. */
|
||||
|
||||
out = (char*)malloc(len + 1); /* This is how long we need for the string, roughly. */
|
||||
out = MALLOC(char, len + 1); /* The length needed for the string, roughly. */
|
||||
if (!out) return 0;
|
||||
|
||||
ptr = str + 1;
|
||||
|
||||
@ -74,13 +74,12 @@ void spMeshAttachment_updateUVs (spMeshAttachment* self) {
|
||||
void spMeshAttachment_computeWorldVertices (spMeshAttachment* self, float x, float y, spSlot* slot, float* worldVertices) {
|
||||
int i;
|
||||
float* vertices = self->vertices;
|
||||
spBone* bone = slot->bone;
|
||||
const spBone* bone = slot->bone;
|
||||
x += bone->worldX;
|
||||
y += bone->worldY;
|
||||
if (slot->attachmentVerticesCount == self->verticesCount) vertices = slot->attachmentVertices;
|
||||
for (i = 0; i < self->verticesCount; i += 2) {
|
||||
float vx = vertices[i];
|
||||
float vy = vertices[i + 1];
|
||||
const float vx = vertices[i], vy = vertices[i + 1];
|
||||
worldVertices[i] = vx * bone->m00 + vy * bone->m01 + x;
|
||||
worldVertices[i + 1] = vx * bone->m10 + vy * bone->m11 + y;
|
||||
}
|
||||
|
||||
@ -105,7 +105,7 @@ void spRegionAttachment_updateOffset (spRegionAttachment* self) {
|
||||
}
|
||||
|
||||
void spRegionAttachment_computeWorldVertices (spRegionAttachment* self, float x, float y, spBone* bone, float* vertices) {
|
||||
float* offset = self->offset;
|
||||
const float* offset = self->offset;
|
||||
x += bone->worldX;
|
||||
y += bone->worldY;
|
||||
vertices[SP_VERTEX_X1] = offset[SP_VERTEX_X1] * bone->m00 + offset[SP_VERTEX_Y1] * bone->m01 + x;
|
||||
|
||||
@ -104,18 +104,24 @@ static void readCurve (spCurveTimeline* timeline, int frameIndex, Json* frame) {
|
||||
static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* root, spSkeletonData *skeletonData) {
|
||||
int i;
|
||||
spAnimation* animation;
|
||||
Json* frame;
|
||||
float duration;
|
||||
|
||||
Json* bones = Json_getItem(root, "bones");
|
||||
Json* slots = Json_getItem(root, "slots");
|
||||
Json* ffd = Json_getItem(root, "ffd");
|
||||
Json* drawOrder = Json_getItem(root, "draworder");
|
||||
Json* events = Json_getItem(root, "events");
|
||||
Json *boneMap, *slotMap;
|
||||
Json *boneMap, *slotMap, *ffdMap;
|
||||
|
||||
int timelineCount = 0;
|
||||
for (boneMap = bones ? bones->child : 0; boneMap; boneMap = boneMap->next)
|
||||
timelineCount += boneMap->size;
|
||||
for (slotMap = slots ? slots->child : 0; slotMap; slotMap = slotMap->next)
|
||||
timelineCount += slotMap->size;
|
||||
for (ffdMap = ffd ? ffd->child : 0; ffdMap; ffdMap = ffdMap->next)
|
||||
for (slotMap = ffdMap->child; slotMap; slotMap = slotMap->next)
|
||||
timelineCount += slotMap->size;
|
||||
if (events) ++timelineCount;
|
||||
if (drawOrder) ++timelineCount;
|
||||
|
||||
@ -124,6 +130,50 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
|
||||
skeletonData->animations[skeletonData->animationCount] = animation;
|
||||
++skeletonData->animationCount;
|
||||
|
||||
for (slotMap = slots ? slots->child : 0; slotMap; slotMap = slotMap->next) {
|
||||
Json *timelineArray;
|
||||
|
||||
int slotIndex = spSkeletonData_findSlotIndex(skeletonData, slotMap->name);
|
||||
if (slotIndex == -1) {
|
||||
spAnimation_dispose(animation);
|
||||
_spSkeletonJson_setError(self, root, "Slot not found: ", slotMap->name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (timelineArray = slotMap->child; timelineArray; timelineArray = timelineArray->next) {
|
||||
if (strcmp(timelineArray->name, "color") == 0) {
|
||||
spColorTimeline *timeline = spColorTimeline_create(timelineArray->size);
|
||||
timeline->slotIndex = slotIndex;
|
||||
for (frame = timelineArray->child, i = 0; frame; frame = frame->next, ++i) {
|
||||
const char* s = Json_getString(frame, "color", 0);
|
||||
spColorTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), toColor(s, 0), toColor(s, 1), toColor(s, 2),
|
||||
toColor(s, 3));
|
||||
readCurve(SUPER(timeline), i, frame);
|
||||
}
|
||||
animation->timelines[animation->timelineCount++] = SUPER_CAST(spTimeline, timeline);
|
||||
duration = timeline->frames[timelineArray->size * 5 - 5];
|
||||
if (duration > animation->duration) animation->duration = duration;
|
||||
|
||||
} else if (strcmp(timelineArray->name, "attachment") == 0) {
|
||||
spAttachmentTimeline *timeline = spAttachmentTimeline_create(timelineArray->size);
|
||||
timeline->slotIndex = slotIndex;
|
||||
for (frame = timelineArray->child, i = 0; frame; frame = frame->next, ++i) {
|
||||
Json* name = Json_getItem(frame, "name");
|
||||
spAttachmentTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0),
|
||||
name->type == Json_NULL ? 0 : name->valueString);
|
||||
}
|
||||
animation->timelines[animation->timelineCount++] = SUPER_CAST(spTimeline, timeline);
|
||||
duration = timeline->frames[timelineArray->size - 1];
|
||||
if (duration > animation->duration) animation->duration = duration;
|
||||
|
||||
} else {
|
||||
spAnimation_dispose(animation);
|
||||
_spSkeletonJson_setError(self, 0, "Invalid timeline type for a slot: ", timelineArray->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (boneMap = bones ? bones->child : 0; boneMap; boneMap = boneMap->next) {
|
||||
Json *timelineArray;
|
||||
|
||||
@ -135,9 +185,6 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
|
||||
}
|
||||
|
||||
for (timelineArray = boneMap->child; timelineArray; timelineArray = timelineArray->next) {
|
||||
Json* frame;
|
||||
float duration;
|
||||
|
||||
if (strcmp(timelineArray->name, "rotate") == 0) {
|
||||
spRotateTimeline *timeline = spRotateTimeline_create(timelineArray->size);
|
||||
timeline->boneIndex = boneIndex;
|
||||
@ -145,7 +192,7 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
|
||||
spRotateTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), Json_getFloat(frame, "angle", 0));
|
||||
readCurve(SUPER(timeline), i, frame);
|
||||
}
|
||||
animation->timelines[animation->timelineCount++] = (spTimeline*)timeline;
|
||||
animation->timelines[animation->timelineCount++] = SUPER_CAST(spTimeline, timeline);
|
||||
duration = timeline->frames[timelineArray->size * 2 - 2];
|
||||
if (duration > animation->duration) animation->duration = duration;
|
||||
|
||||
@ -161,7 +208,7 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
|
||||
Json_getFloat(frame, "y", 0) * scale);
|
||||
readCurve(SUPER(timeline), i, frame);
|
||||
}
|
||||
animation->timelines[animation->timelineCount++] = (spTimeline*)timeline;
|
||||
animation->timelines[animation->timelineCount++] = SUPER_CAST(spTimeline, timeline);
|
||||
duration = timeline->frames[timelineArray->size * 3 - 3];
|
||||
if (duration > animation->duration) animation->duration = duration;
|
||||
} else {
|
||||
@ -173,83 +220,75 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
|
||||
}
|
||||
}
|
||||
|
||||
for (slotMap = slots ? slots->child : 0; slotMap; slotMap = slotMap->next) {
|
||||
Json *timelineArray;
|
||||
for (ffdMap = ffd ? ffd->child : 0; ffdMap; ffdMap = ffdMap->next) {
|
||||
spSkin* skin = spSkeletonData_findSkin(skeletonData, ffdMap->name);
|
||||
for (slotMap = ffdMap->child; slotMap; slotMap = slotMap->next) {
|
||||
int slotIndex = spSkeletonData_findSlotIndex(skeletonData, slotMap->name);
|
||||
Json* timelineArray;
|
||||
for (timelineArray = slotMap->child; timelineArray; timelineArray = timelineArray->next) {
|
||||
Json* frame;
|
||||
int verticesCount;
|
||||
float* tempVertices;
|
||||
spFFDTimeline *timeline;
|
||||
|
||||
int slotIndex = spSkeletonData_findSlotIndex(skeletonData, slotMap->name);
|
||||
if (slotIndex == -1) {
|
||||
spAnimation_dispose(animation);
|
||||
_spSkeletonJson_setError(self, root, "Slot not found: ", slotMap->name);
|
||||
return 0;
|
||||
}
|
||||
spAttachment* attachment = spSkin_getAttachment(skin, slotIndex, timelineArray->name);
|
||||
if (!attachment) {
|
||||
spAnimation_dispose(animation);
|
||||
_spSkeletonJson_setError(self, 0, "Attachment not found: ", timelineArray->name);
|
||||
return 0;
|
||||
}
|
||||
if (attachment->type == SP_ATTACHMENT_MESH)
|
||||
verticesCount = SUB_CAST(spMeshAttachment, attachment)->verticesCount;
|
||||
else if (attachment->type == SP_ATTACHMENT_SKINNED_MESH)
|
||||
verticesCount = SUB_CAST(spSkinnedMeshAttachment, attachment)->weightsCount / 3 * 2;
|
||||
|
||||
for (timelineArray = slotMap->child; timelineArray; timelineArray = timelineArray->next) {
|
||||
Json* frame;
|
||||
float duration;
|
||||
|
||||
if (strcmp(timelineArray->name, "color") == 0) {
|
||||
spColorTimeline *timeline = spColorTimeline_create(timelineArray->size);
|
||||
timeline = spFFDTimeline_create(timelineArray->size, verticesCount);
|
||||
timeline->slotIndex = slotIndex;
|
||||
timeline->attachment = attachment;
|
||||
|
||||
tempVertices = MALLOC(float, verticesCount);
|
||||
for (frame = timelineArray->child, i = 0; frame; frame = frame->next, ++i) {
|
||||
const char* s = Json_getString(frame, "color", 0);
|
||||
spColorTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), toColor(s, 0), toColor(s, 1), toColor(s, 2),
|
||||
toColor(s, 3));
|
||||
Json* vertices = Json_getItem(frame, "vertices");
|
||||
float* frameVertices;
|
||||
if (!vertices) {
|
||||
if (attachment->type == SP_ATTACHMENT_MESH)
|
||||
frameVertices = SUB_CAST(spMeshAttachment, attachment)->vertices;
|
||||
else {
|
||||
frameVertices = tempVertices;
|
||||
memset(frameVertices, 0, sizeof(float) * verticesCount);
|
||||
}
|
||||
} else {
|
||||
int v, start = Json_getInt(frame, "offset", 0);
|
||||
Json* vertex;
|
||||
frameVertices = tempVertices;
|
||||
memset(frameVertices, 0, sizeof(float) * start);
|
||||
if (self->scale == 1) {
|
||||
for (vertex = vertices->child, v = start; vertex; vertex = vertex->next, ++v)
|
||||
frameVertices[v] = vertex->valueFloat;
|
||||
} else {
|
||||
for (vertex = vertices->child, v = start; vertex; vertex = vertex->next, ++v)
|
||||
frameVertices[v] = vertex->valueFloat * self->scale;
|
||||
}
|
||||
memset(frameVertices + v, 0, sizeof(float) * (verticesCount - v));
|
||||
if (attachment->type == SP_ATTACHMENT_MESH) {
|
||||
float* meshVertices = SUB_CAST(spMeshAttachment, attachment)->vertices;
|
||||
for (v = 0; v < verticesCount; ++v)
|
||||
frameVertices[v] += meshVertices[v];
|
||||
}
|
||||
}
|
||||
spFFDTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), frameVertices);
|
||||
readCurve(SUPER(timeline), i, frame);
|
||||
}
|
||||
animation->timelines[animation->timelineCount++] = (spTimeline*)timeline;
|
||||
duration = timeline->frames[timelineArray->size * 5 - 5];
|
||||
if (duration > animation->duration) animation->duration = duration;
|
||||
FREE(tempVertices);
|
||||
|
||||
} else if (strcmp(timelineArray->name, "attachment") == 0) {
|
||||
spAttachmentTimeline *timeline = spAttachmentTimeline_create(timelineArray->size);
|
||||
timeline->slotIndex = slotIndex;
|
||||
for (frame = timelineArray->child, i = 0; frame; frame = frame->next, ++i) {
|
||||
Json* name = Json_getItem(frame, "name");
|
||||
spAttachmentTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0),
|
||||
name->type == Json_NULL ? 0 : name->valueString);
|
||||
}
|
||||
animation->timelines[animation->timelineCount++] = (spTimeline*)timeline;
|
||||
animation->timelines[animation->timelineCount++] = SUPER_CAST(spTimeline, timeline);
|
||||
duration = timeline->frames[timelineArray->size - 1];
|
||||
if (duration > animation->duration) animation->duration = duration;
|
||||
|
||||
} else {
|
||||
spAnimation_dispose(animation);
|
||||
_spSkeletonJson_setError(self, 0, "Invalid timeline type for a slot: ", timelineArray->name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (events) {
|
||||
Json* frame;
|
||||
float duration;
|
||||
|
||||
spEventTimeline* timeline = spEventTimeline_create(events->size);
|
||||
for (frame = events->child, i = 0; frame; frame = frame->next, ++i) {
|
||||
spEvent* event;
|
||||
const char* stringValue;
|
||||
spEventData* eventData = spSkeletonData_findEvent(skeletonData, Json_getString(frame, "name", 0));
|
||||
if (!eventData) {
|
||||
spAnimation_dispose(animation);
|
||||
_spSkeletonJson_setError(self, 0, "Event not found: ", Json_getString(frame, "name", 0));
|
||||
return 0;
|
||||
}
|
||||
event = spEvent_create(eventData);
|
||||
event->intValue = Json_getInt(frame, "int", eventData->intValue);
|
||||
event->floatValue = Json_getFloat(frame, "float", eventData->floatValue);
|
||||
stringValue = Json_getString(frame, "string", eventData->stringValue);
|
||||
if (stringValue) MALLOC_STR(event->stringValue, stringValue);
|
||||
spEventTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), event);
|
||||
}
|
||||
animation->timelines[animation->timelineCount++] = (spTimeline*)timeline;
|
||||
duration = timeline->frames[events->size - 1];
|
||||
if (duration > animation->duration) animation->duration = duration;
|
||||
}
|
||||
|
||||
if (drawOrder) {
|
||||
Json* frame;
|
||||
float duration;
|
||||
|
||||
spDrawOrderTimeline* timeline = spDrawOrderTimeline_create(drawOrder->size, skeletonData->slotCount);
|
||||
for (frame = drawOrder->child, i = 0; frame; frame = frame->next, ++i) {
|
||||
int ii;
|
||||
@ -289,11 +328,36 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
|
||||
spDrawOrderTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), drawOrder);
|
||||
FREE(drawOrder);
|
||||
}
|
||||
animation->timelines[animation->timelineCount++] = (spTimeline*)timeline;
|
||||
animation->timelines[animation->timelineCount++] = SUPER_CAST(spTimeline, timeline);
|
||||
duration = timeline->frames[drawOrder->size - 1];
|
||||
if (duration > animation->duration) animation->duration = duration;
|
||||
}
|
||||
|
||||
if (events) {
|
||||
Json* frame;
|
||||
|
||||
spEventTimeline* timeline = spEventTimeline_create(events->size);
|
||||
for (frame = events->child, i = 0; frame; frame = frame->next, ++i) {
|
||||
spEvent* event;
|
||||
const char* stringValue;
|
||||
spEventData* eventData = spSkeletonData_findEvent(skeletonData, Json_getString(frame, "name", 0));
|
||||
if (!eventData) {
|
||||
spAnimation_dispose(animation);
|
||||
_spSkeletonJson_setError(self, 0, "Event not found: ", Json_getString(frame, "name", 0));
|
||||
return 0;
|
||||
}
|
||||
event = spEvent_create(eventData);
|
||||
event->intValue = Json_getInt(frame, "int", eventData->intValue);
|
||||
event->floatValue = Json_getFloat(frame, "float", eventData->floatValue);
|
||||
stringValue = Json_getString(frame, "string", eventData->stringValue);
|
||||
if (stringValue) MALLOC_STR(event->stringValue, stringValue);
|
||||
spEventTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), event);
|
||||
}
|
||||
animation->timelines[animation->timelineCount++] = SUPER_CAST(spTimeline, timeline);
|
||||
duration = timeline->frames[events->size - 1];
|
||||
if (duration > animation->duration) animation->duration = duration;
|
||||
}
|
||||
|
||||
return animation;
|
||||
}
|
||||
|
||||
@ -446,7 +510,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
|
||||
|
||||
switch (attachment->type) {
|
||||
case SP_ATTACHMENT_REGION: {
|
||||
spRegionAttachment* region = (spRegionAttachment*)attachment;
|
||||
spRegionAttachment* region = SUB_CAST(spRegionAttachment, attachment);
|
||||
if (path) MALLOC_STR(region->path, path);
|
||||
region->x = Json_getFloat(attachmentMap, "x", 0) * self->scale;
|
||||
region->y = Json_getFloat(attachmentMap, "y", 0) * self->scale;
|
||||
@ -468,7 +532,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
|
||||
break;
|
||||
}
|
||||
case SP_ATTACHMENT_MESH: {
|
||||
spMeshAttachment* mesh = (spMeshAttachment*)attachment;
|
||||
spMeshAttachment* mesh = SUB_CAST(spMeshAttachment, attachment);
|
||||
|
||||
MALLOC_STR(mesh->path, path);
|
||||
|
||||
@ -515,7 +579,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
|
||||
break;
|
||||
}
|
||||
case SP_ATTACHMENT_SKINNED_MESH: {
|
||||
spSkinnedMeshAttachment* mesh = (spSkinnedMeshAttachment*)attachment;
|
||||
spSkinnedMeshAttachment* mesh = SUB_CAST(spSkinnedMeshAttachment, attachment);
|
||||
int verticesCount, b, w, nn;
|
||||
float* vertices;
|
||||
|
||||
@ -545,12 +609,11 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
|
||||
for (i = 0, b = 0, w = 0; i < verticesCount;) {
|
||||
int boneCount = (int)vertices[i++];
|
||||
mesh->bones[b++] = boneCount;
|
||||
for (nn = i + boneCount * 4; i < nn;) {
|
||||
mesh->bones[b++] = (int)vertices[i];
|
||||
mesh->weights[w++] = vertices[i + 1] * self->scale;
|
||||
mesh->weights[w++] = vertices[i + 2] * self->scale;
|
||||
mesh->weights[w++] = vertices[i + 3];
|
||||
i += 4;
|
||||
for (nn = i + boneCount * 4; i < nn; i += 4, ++b, w += 3) {
|
||||
mesh->bones[b] = (int)vertices[i];
|
||||
mesh->weights[w] = vertices[i + 1] * self->scale;
|
||||
mesh->weights[w + 1] = vertices[i + 2] * self->scale;
|
||||
mesh->weights[w + 2] = vertices[i + 3];
|
||||
}
|
||||
}
|
||||
|
||||
@ -587,7 +650,7 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
|
||||
break;
|
||||
}
|
||||
case SP_ATTACHMENT_BOUNDING_BOX: {
|
||||
spBoundingBoxAttachment* box = (spBoundingBoxAttachment*)attachment;
|
||||
spBoundingBoxAttachment* box = SUB_CAST(spBoundingBoxAttachment, attachment);
|
||||
entry = Json_getItem(attachmentMap, "vertices");
|
||||
box->verticesCount = entry->size;
|
||||
box->vertices = MALLOC(float, entry->size);
|
||||
|
||||
@ -79,11 +79,11 @@ void spSkinnedMeshAttachment_computeWorldVertices (spSkinnedMeshAttachment* self
|
||||
if (slot->attachmentVerticesCount == 0) {
|
||||
for (; v < self->bonesCount; w += 2) {
|
||||
float wx = 0, wy = 0;
|
||||
int nn = self->bones[v] + v;
|
||||
const int nn = self->bones[v] + v;
|
||||
v++;
|
||||
for (; v <= nn; v++, b += 3) {
|
||||
spBone* bone = skeletonBones[self->bones[v]];
|
||||
float vx = self->weights[b], vy = self->weights[b + 1], weight = self->weights[b + 2];
|
||||
const spBone* bone = skeletonBones[self->bones[v]];
|
||||
const float vx = self->weights[b], vy = self->weights[b + 1], weight = self->weights[b + 2];
|
||||
wx += (vx * bone->m00 + vy * bone->m01 + bone->worldX) * weight;
|
||||
wy += (vx * bone->m10 + vy * bone->m11 + bone->worldY) * weight;
|
||||
}
|
||||
@ -91,14 +91,14 @@ void spSkinnedMeshAttachment_computeWorldVertices (spSkinnedMeshAttachment* self
|
||||
worldVertices[w + 1] = wy + y;
|
||||
}
|
||||
} else {
|
||||
float* ffd = slot->attachmentVertices;
|
||||
const float* ffd = slot->attachmentVertices;
|
||||
for (; v < self->bonesCount; w += 2) {
|
||||
float wx = 0, wy = 0;
|
||||
int nn = self->bones[v] + v;
|
||||
const int nn = self->bones[v] + v;
|
||||
v++;
|
||||
for (; v <= nn; v++, b += 3, f += 2) {
|
||||
spBone* bone = skeletonBones[self->bones[v]];
|
||||
float vx = self->weights[b] + ffd[f], vy = self->weights[b + 1] + ffd[f + 1], weight = self->weights[b + 2];
|
||||
const spBone* bone = skeletonBones[self->bones[v]];
|
||||
const float vx = self->weights[b] + ffd[f], vy = self->weights[b + 1] + ffd[f + 1], weight = self->weights[b + 2];
|
||||
wx += (vx * bone->m00 + vy * bone->m01 + bone->worldX) * weight;
|
||||
wy += (vx * bone->m10 + vy * bone->m11 + bone->worldY) * weight;
|
||||
}
|
||||
|
||||
@ -135,7 +135,7 @@ void spineboy () {
|
||||
}
|
||||
|
||||
void goblins () {
|
||||
// Load atlas, skeleton, and animations.
|
||||
// Load atlas, skeleton, and animations.
|
||||
Atlas* atlas = Atlas_readAtlasFile("../data/goblins-ffd.atlas");
|
||||
SkeletonJson* json = SkeletonJson_create(atlas);
|
||||
SkeletonData *skeletonData = SkeletonJson_readSkeletonDataFile(json, "../data/goblins-ffd.json");
|
||||
@ -154,7 +154,7 @@ void goblins () {
|
||||
skeleton->flipY = false;
|
||||
Skeleton_setSkinByName(skeleton, "goblin");
|
||||
Skeleton_setSlotsToSetupPose(skeleton);
|
||||
// Skeleton_setAttachment(skeleton, "left hand item", "dagger");
|
||||
//Skeleton_setAttachment(skeleton, "left hand item", "dagger");
|
||||
|
||||
skeleton->x = 320;
|
||||
skeleton->y = 590;
|
||||
@ -185,6 +185,6 @@ void goblins () {
|
||||
}
|
||||
|
||||
int main () {
|
||||
// spineboy();
|
||||
spineboy();
|
||||
goblins();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user