diff --git a/spine-c/spine-c/include/spine/AnimationState.h b/spine-c/spine-c/include/spine/AnimationState.h index c83c28b83..d0bfc9550 100644 --- a/spine-c/spine-c/include/spine/AnimationState.h +++ b/spine-c/spine-c/include/spine/AnimationState.h @@ -107,6 +107,8 @@ struct spAnimationState { void* rendererObject; void* userData; + int unkeyedState; + #ifdef __cplusplus spAnimationState() : data(0), @@ -115,7 +117,8 @@ struct spAnimationState { listener(0), timeScale(0), rendererObject(0), - userData(0) { + userData(0), + unkeyedState(0) { } #endif }; diff --git a/spine-c/spine-c/include/spine/Slot.h b/spine-c/spine-c/include/spine/Slot.h index a3e080c95..aa0415e5d 100644 --- a/spine-c/spine-c/include/spine/Slot.h +++ b/spine-c/spine-c/include/spine/Slot.h @@ -44,7 +44,8 @@ typedef struct spSlot { spBone* const bone; spColor color; spColor* darkColor; - spAttachment* const attachment; + spAttachment* attachment; + int attachmentState; int deformCapacity; int deformCount; @@ -57,6 +58,7 @@ typedef struct spSlot { color(), darkColor(0), attachment(0), + attachmentState(0), deformCapacity(0), deformCount(0), deform(0) { diff --git a/spine-c/spine-c/src/spine/Animation.c b/spine-c/spine-c/src/spine/Animation.c index 8a53361c4..62db7a263 100644 --- a/spine-c/spine-c/src/spine/Animation.c +++ b/spine-c/spine-c/src/spine/Animation.c @@ -819,6 +819,10 @@ void spTwoColorTimeline_setFrame (spTwoColorTimeline* self, int frameIndex, floa /**/ +static void _spSetAttachment(spAttachmentTimeline* timeline, spSkeleton* skeleton, spSlot* slot, const char* attachmentName) { + slot->attachment = attachmentName == NULL ? NULL : spSkeleton_getAttachmentForSlotIndex(skeleton, timeline->slotIndex, attachmentName); +} + void _spAttachmentTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time, spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) { const char* attachmentName; @@ -827,17 +831,15 @@ void _spAttachmentTimeline_apply (const spTimeline* timeline, spSkeleton* skelet spSlot* slot = skeleton->slots[self->slotIndex]; if (!slot->bone->active) return; - if (direction == SP_MIX_DIRECTION_OUT && blend == SP_MIX_BLEND_SETUP) { - attachmentName = slot->data->attachmentName; - spSlot_setAttachment(slot, attachmentName ? spSkeleton_getAttachmentForSlotIndex(skeleton, self->slotIndex, attachmentName) : 0); + if (direction == SP_MIX_DIRECTION_OUT) { + if (blend == SP_MIX_BLEND_SETUP) + _spSetAttachment(self, skeleton, slot, slot->data->attachmentName); return; } if (time < self->frames[0]) { if (blend == SP_MIX_BLEND_SETUP || blend == SP_MIX_BLEND_FIRST) { - attachmentName = slot->data->attachmentName; - spSlot_setAttachment(skeleton->slots[self->slotIndex], - attachmentName ? spSkeleton_getAttachmentForSlotIndex(skeleton, self->slotIndex, attachmentName) : 0); + _spSetAttachment(self, skeleton, slot, slot->data->attachmentName); } return; } @@ -1230,8 +1232,8 @@ void _spDrawOrderTimeline_apply (const spTimeline* timeline, spSkeleton* skeleto const int* drawOrderToSetupIndex; spDrawOrderTimeline* self = (spDrawOrderTimeline*)timeline; - if (direction == SP_MIX_DIRECTION_OUT && blend == SP_MIX_BLEND_SETUP) { - memcpy(skeleton->drawOrder, skeleton->slots, self->slotsCount * sizeof(spSlot*)); + if (direction == SP_MIX_DIRECTION_OUT ) { + if (blend == SP_MIX_BLEND_SETUP) memcpy(skeleton->drawOrder, skeleton->slots, self->slotsCount * sizeof(spSlot*)); return; } diff --git a/spine-c/spine-c/src/spine/AnimationState.c b/spine-c/spine-c/src/spine/AnimationState.c index 7fc675dde..c5442d291 100644 --- a/spine-c/spine-c/src/spine/AnimationState.c +++ b/spine-c/spine-c/src/spine/AnimationState.c @@ -35,7 +35,9 @@ #define FIRST 1 #define HOLD 2 #define HOLD_MIX 3 -#define NOT_LAST 4 + +#define SETUP 1 +#define CURRENT 2 _SP_ARRAY_IMPLEMENT_TYPE(spTrackEntryArray, spTrackEntry*) @@ -52,6 +54,7 @@ void _spAnimationState_disposeTrackEntries (spAnimationState* state, spTrackEntr int /*boolean*/ _spAnimationState_updateMixingFrom (spAnimationState* self, spTrackEntry* entry, float delta); float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* entry, spSkeleton* skeleton, spMixBlend currentBlend); void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline* timeline, spSkeleton* skeleton, float time, float alpha, spMixBlend blend, float* timelinesRotation, int i, int /*boolean*/ firstFrame); +void _spAnimationState_applyAttachmentTimeline(spAnimationState* self, spTimeline* timeline, spSkeleton* skeleton, float animationTime, spMixBlend blend, int /*bool*/ firstFrame); void _spAnimationState_queueEvents (spAnimationState* self, spTrackEntry* entry, float animationTime); void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEntry* current, int /*boolean*/ interrupt); spTrackEntry* _spAnimationState_expandToIndex (spAnimationState* self, int index); @@ -63,7 +66,6 @@ int* _spAnimationState_resizeTimelinesFirst(spTrackEntry* entry, int newSize); void _spAnimationState_ensureCapacityPropertyIDs(spAnimationState* self, int capacity); int _spAnimationState_addPropertyID(spAnimationState* self, int id); void _spTrackEntry_computeHold(spTrackEntry* self, spAnimationState* state); -void _spTrackEntry_computeNotLast(spTrackEntry* self, spAnimationState* state); _spEventQueue* _spEventQueue_create (_spAnimationState* state) { _spEventQueue *self = CALLOC(_spEventQueue, 1); @@ -356,6 +358,10 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) { int applied = 0; spMixBlend blend; spMixBlend timelineBlend; + int setupState = 0; + spSlot** slots = NULL; + spSlot* slot = NULL; + const char* attachmentName = NULL; if (internal->animationsChanged) _spAnimationState_animationsChanged(self); @@ -378,8 +384,14 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) { timelineCount = current->animation->timelinesCount; timelines = current->animation->timelines; if ((i == 0 && mix == 1) || blend == SP_MIX_BLEND_ADD) { - for (ii = 0; ii < timelineCount; ii++) - spTimeline_apply(timelines[ii], skeleton, animationLast, animationTime, internal->events, &internal->eventsCount, mix, blend, SP_MIX_DIRECTION_IN); + for (ii = 0; ii < timelineCount; ii++) { + if (timeline->type == SP_TIMELINE_ATTACHMENT) { + _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, animationTime, blend, -1); + } else { + spTimeline_apply(timelines[ii], skeleton, animationLast, animationTime, internal->events, + &internal->eventsCount, mix, blend, SP_MIX_DIRECTION_IN); + } + } } else { spIntArray* timelineMode = current->timelineMode; @@ -389,9 +401,11 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) { for (ii = 0; ii < timelineCount; ii++) { timeline = timelines[ii]; - timelineBlend = (timelineMode->items[ii] & (NOT_LAST - 1)) == SUBSEQUENT ? blend : SP_MIX_BLEND_SETUP; + timelineBlend = timelineMode->items[ii] == SUBSEQUENT ? blend : SP_MIX_BLEND_SETUP; if (timeline->type == SP_TIMELINE_ROTATE) _spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame); + else if (timeline->type == SP_TIMELINE_ATTACHMENT) + _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, animationTime, timelineBlend, -1); else spTimeline_apply(timeline, skeleton, animationLast, animationTime, internal->events, &internal->eventsCount, mix, timelineBlend, SP_MIX_DIRECTION_IN); } @@ -402,6 +416,17 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) { current->nextTrackLast = current->trackTime; } + setupState = self->unkeyedState + SETUP; + slots = skeleton->slots; + for (i = 0, n = skeleton->slotsCount; i < n; i++) { + slot = slots[i]; + if (slot->attachmentState == setupState) { + attachmentName = slot->data->attachmentName; + slot->attachment = attachmentName == NULL ? NULL : spSkeleton_getAttachmentForSlotIndex(skeleton, slot->data->index, attachmentName); + } + } + self->unkeyedState += 2; + _spEventQueue_drain(internal->queue); return applied; } @@ -465,14 +490,10 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* t spMixDirection direction = SP_MIX_DIRECTION_OUT; spTimeline *timeline = timelines[i]; - switch (timelineMode->items[i] & (NOT_LAST - 1)) { + switch (timelineMode->items[i]) { case SUBSEQUENT: - timelineBlend = blend; - if (!attachments && timeline->type == SP_TIMELINE_ATTACHMENT) { - if ((timelineMode->items[i] & NOT_LAST) == NOT_LAST) continue; - timelineBlend = SP_MIX_BLEND_SETUP; - } if (!drawOrder && timeline->type == SP_TIMELINE_DRAWORDER) continue; + timelineBlend = blend; alpha = alphaMix; break; case FIRST: @@ -493,15 +514,11 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* t if (timeline->type == SP_TIMELINE_ROTATE) _spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame); + else if (timeline->type == SP_TIMELINE_ATTACHMENT) + _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, animationTime, timelineBlend, attachments); else { - if (timelineBlend == SP_MIX_BLEND_SETUP) { - if (timeline->type == SP_TIMELINE_ATTACHMENT) { - if (attachments || (timelineMode->items[i] & NOT_LAST) == NOT_LAST) direction = SP_MIX_DIRECTION_IN; - } else if (timeline->type == SP_TIMELINE_DRAWORDER) { - if (drawOrder) direction = SP_MIX_DIRECTION_IN; - } - } - + if (drawOrder && timeline->type == SP_TIMELINE_DRAWORDER && timelineBlend == SP_MIX_BLEND_SETUP) + direction = SP_MIX_DIRECTION_IN; spTimeline_apply(timeline, skeleton, animationLast, animationTime, events, &internal->eventsCount, alpha, timelineBlend, direction); } @@ -517,6 +534,55 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* t return mix; } +static void _spAnimationState_setAttachment(spAnimationState* self, spSkeleton* skeleton, spSlot* slot, const char* attachmentName, int /*bool*/ attachments) { + slot->attachment = attachmentName == NULL ? NULL : spSkeleton_getAttachmentForSlotIndex(skeleton, slot->data->index, attachmentName); + if (attachments) slot->attachmentState = self->unkeyedState + CURRENT; +} + +/* @param target After the first and before the last entry. */ +static int binarySearch1 (float *values, int valuesLength, float target) { + int low = 0, current; + int high = valuesLength - 2; + if (high == 0) return 1; + current = high >> 1; + while (1) { + if (values[(current + 1)] <= target) + low = current + 1; + else + high = current; + if (low == high) return low + 1; + current = (low + high) >> 1; + } + return 0; +} + +void _spAnimationState_applyAttachmentTimeline(spAnimationState* self, spTimeline* timeline, spSkeleton* skeleton, float time, spMixBlend blend, int /*bool*/ attachments) { + spAttachmentTimeline* attachmentTimeline; + spSlot* slot; + int frameIndex; + float* frames; + + attachmentTimeline = SUB_CAST(spAttachmentTimeline, timeline); + slot = skeleton->slots[attachmentTimeline->slotIndex]; + if (!slot->bone->active) return; + + frames = attachmentTimeline->frames; + if (time < frames[0]) { + if (blend == SP_MIX_BLEND_SETUP || blend == SP_MIX_BLEND_FIRST) + _spAnimationState_setAttachment(self, skeleton, slot, slot->data->attachmentName, attachments); + } + else { + if (time >= frames[attachmentTimeline->framesCount - 1]) + frameIndex = attachmentTimeline->framesCount - 1; + else + frameIndex = binarySearch1(frames, attachmentTimeline->framesCount, time) - 1; + _spAnimationState_setAttachment(self, skeleton, slot, attachmentTimeline->attachmentNames[frameIndex], attachments); + } + + /* If an attachment wasn't set (ie before the first frame or attachments is false), set the setup attachment later.*/ + if (slot->attachmentState <= self->unkeyedState) slot->attachmentState = self->unkeyedState + SETUP; +} + void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline* timeline, spSkeleton* skeleton, float time, float alpha, spMixBlend blend, float* timelinesRotation, int i, int /*boolean*/ firstFrame ) { @@ -874,17 +940,6 @@ void _spAnimationState_animationsChanged (spAnimationState* self) { entry = entry->mixingTo; } while (entry != 0); } - - internal->propertyIDsCount = 0; - i = self->tracksCount - 1; - for (; i >= 0; i--) { - entry = self->tracks[i]; - if (!entry) continue; - while (entry != 0) { - _spTrackEntry_computeNotLast(entry, self); - entry = entry->mixingFrom; - } - } } float* _spAnimationState_resizeTimelinesRotation(spTrackEntry* entry, int newSize) { @@ -999,22 +1054,3 @@ void _spTrackEntry_computeHold(spTrackEntry* entry, spAnimationState* state) { } } } - -void _spTrackEntry_computeNotLast(spTrackEntry* entry, spAnimationState* state) { - spTimeline** timelines ; - int timelinesCount; - int* timelineMode; - int i; - - timelines = entry->animation->timelines; - timelinesCount = entry->animation->timelinesCount; - timelineMode = entry->timelineMode->items; - - i = 0; - for (; i < timelinesCount; i++) { - if (timelines[i]->type == SP_TIMELINE_ATTACHMENT) { - spAttachmentTimeline* timeline = SUB_CAST(spAttachmentTimeline, timelines[i]); - if (!_spAnimationState_addPropertyID(state, timeline->slotIndex)) timelineMode[i] |= NOT_LAST; - } - } -} diff --git a/spine-c/spine-c/src/spine/extension.c b/spine-c/spine-c/src/spine/extension.c index ded675977..ebfab358a 100644 --- a/spine-c/spine-c/src/spine/extension.c +++ b/spine-c/spine-c/src/spine/extension.c @@ -84,6 +84,7 @@ void _spSetRandom (float (*random) ()) { char* _spReadFile (const char* path, int* length) { char *data; + size_t result; FILE *file = fopen(path, "rb"); if (!file) return 0; @@ -92,7 +93,7 @@ char* _spReadFile (const char* path, int* length) { fseek(file, 0, SEEK_SET); data = MALLOC(char, *length); - size_t result = fread(data, 1, *length, file); + result = fread(data, 1, *length, file); UNUSED(result); fclose(file);