FFD for spine-c and spine-sfml.

This commit is contained in:
NathanSweet 2014-04-29 20:28:27 +02:00
parent 6432e43ea2
commit 99a8de4bb4
9 changed files with 301 additions and 137 deletions

View File

@ -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

View File

@ -48,6 +48,7 @@ typedef struct spSlot {
float r, g, b, a;
spAttachment* const attachment;
int attachmentVerticesCapacity;
int attachmentVerticesCount;
float* attachmentVertices;
} spSlot;

View File

@ -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));
}
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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();
}