From 99a8de4bb4d84dbc958fbe4cce7c6f630bfa7c47 Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Tue, 29 Apr 2014 20:28:27 +0200 Subject: [PATCH] FFD for spine-c and spine-sfml. --- spine-c/include/spine/Animation.h | 36 +++- spine-c/include/spine/Slot.h | 1 + spine-c/src/spine/Animation.c | 149 +++++++++++---- spine-c/src/spine/Json.c | 2 +- spine-c/src/spine/MeshAttachment.c | 5 +- spine-c/src/spine/RegionAttachment.c | 2 +- spine-c/src/spine/SkeletonJson.c | 223 ++++++++++++++-------- spine-c/src/spine/SkinnedMeshAttachment.c | 14 +- spine-sfml/example/main.cpp | 6 +- 9 files changed, 301 insertions(+), 137 deletions(-) diff --git a/spine-c/include/spine/Animation.h b/spine-c/include/spine/Animation.h index 8ed499e04..17bbf550d 100644 --- a/spine-c/include/spine/Animation.h +++ b/spine-c/include/spine/Animation.h @@ -32,6 +32,7 @@ #define SPINE_ANIMATION_H_ #include +#include #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 diff --git a/spine-c/include/spine/Slot.h b/spine-c/include/spine/Slot.h index 3a317a840..bb4cce6ee 100644 --- a/spine-c/include/spine/Slot.h +++ b/spine-c/include/spine/Slot.h @@ -48,6 +48,7 @@ typedef struct spSlot { float r, g, b, a; spAttachment* const attachment; + int attachmentVerticesCapacity; int attachmentVerticesCount; float* attachmentVertices; } spSlot; diff --git a/spine-c/src/spine/Animation.c b/spine-c/src/spine/Animation.c index a53accaed..34a711427 100644 --- a/spine-c/src/spine/Animation.c +++ b/spine-c/src/spine/Animation.c @@ -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)); + } +} diff --git a/spine-c/src/spine/Json.c b/spine-c/src/spine/Json.c index 941d807d6..3a467accf 100644 --- a/spine-c/src/spine/Json.c +++ b/spine-c/src/spine/Json.c @@ -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; diff --git a/spine-c/src/spine/MeshAttachment.c b/spine-c/src/spine/MeshAttachment.c index 5d1c6c954..b5010ce86 100644 --- a/spine-c/src/spine/MeshAttachment.c +++ b/spine-c/src/spine/MeshAttachment.c @@ -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; } diff --git a/spine-c/src/spine/RegionAttachment.c b/spine-c/src/spine/RegionAttachment.c index 89aa1618e..d4e08e56e 100644 --- a/spine-c/src/spine/RegionAttachment.c +++ b/spine-c/src/spine/RegionAttachment.c @@ -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; diff --git a/spine-c/src/spine/SkeletonJson.c b/spine-c/src/spine/SkeletonJson.c index b3f277c49..dd4179812 100644 --- a/spine-c/src/spine/SkeletonJson.c +++ b/spine-c/src/spine/SkeletonJson.c @@ -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); diff --git a/spine-c/src/spine/SkinnedMeshAttachment.c b/spine-c/src/spine/SkinnedMeshAttachment.c index f7a9c3040..0d162fc13 100644 --- a/spine-c/src/spine/SkinnedMeshAttachment.c +++ b/spine-c/src/spine/SkinnedMeshAttachment.c @@ -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; } diff --git a/spine-sfml/example/main.cpp b/spine-sfml/example/main.cpp index 6953ac0ca..96e68fbab 100644 --- a/spine-sfml/example/main.cpp +++ b/spine-sfml/example/main.cpp @@ -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(); }