diff --git a/spine-c/include/spine/AnimationState.h b/spine-c/include/spine/AnimationState.h index ce11c02bd..0817e2a80 100644 --- a/spine-c/include/spine/AnimationState.h +++ b/spine-c/include/spine/AnimationState.h @@ -44,40 +44,45 @@ typedef enum { } spEventType; typedef struct spAnimationState spAnimationState; - -typedef void (*spAnimationStateListener) (spAnimationState* state, int trackIndex, spEventType type, spEvent* event, - int loopCount); - typedef struct spTrackEntry spTrackEntry; -struct spTrackEntry { - spAnimationState* const state; - spTrackEntry* next; - spTrackEntry* previous; - spAnimation* animation; - int/*bool*/loop; - float delay, time, lastTime, endTime, timeScale; - spAnimationStateListener listener; - float mixTime, mixDuration, mix; - void* rendererObject; +typedef void (*spAnimationStateListener) (spAnimationState* state, spEventType type, spTrackEntry* entry, spEvent* event); + +struct spTrackEntry { + spAnimation* animation; + spTrackEntry* next; + spTrackEntry* mixingFrom; + spAnimationStateListener listener; + int trackIndex; + int /*boolean*/ loop; + float eventThreshold, attachmentThreshold, drawOrderThreshold; + float animationStart, animationEnd, animationLast, nextAnimationLast; + float delay, trackTime, trackLast, nextTrackLast, trackEnd, timeScale; + float alpha, mixTime, mixDuration, mixAlpha; + int* /*boolean*/ timelinesFirst; + int timelinesFirstCount; + float* timelinesRotation; + int timelinesRotationCount; #ifdef __cplusplus spTrackEntry() : - state(0), - next(0), - previous(0), animation(0), - loop(0), - delay(0), time(0), lastTime(0), endTime(0), timeScale(0), + next(0), mixingFrom(0), listener(0), - mixTime(0), mixDuration(0), mix(0), - rendererObject(0) { + trackIndex(0), + loop(0), + eventThreshold(0), attachmentThreshold(0), drawOrderThreshold(0), + animationStart(0), animationEnd(0), animationLast(0), nextAnimationLast(0), + delay(0), trackTime(0), trackLast(0), nextTrackLast(0), trackEnd(0), timeScale(0), + alpha(0), mixTime(0), mixDuration(0), mixAlpha(0), + timelinesFirst(0), + timelinesFirstCount(0), + timelinesRotation(0), + timelinesRotationCount(0) { } #endif }; -typedef struct spEventQueue spEventQueue; - struct spAnimationState { spAnimationStateData* const data; @@ -93,12 +98,7 @@ struct spAnimationState { data(0), tracks(0), tracksCount(0), - events(0), - eventsCount(0), listener(0), - queue(0), - propertyIDs(0), - animationsChanged(0), timeScale(0) { } #endif diff --git a/spine-c/include/spine/extension.h b/spine-c/include/spine/extension.h index 0ea9a5943..602a1d392 100644 --- a/spine-c/include/spine/extension.h +++ b/spine-c/include/spine/extension.h @@ -171,21 +171,41 @@ char* _readFile (const char* path, int* length); /**/ +typedef union _spEventQueueItem { + int type; + spTrackEntry* entry; + spEvent* event; +} _spEventQueueItem; + +typedef struct _spEventQueue { + spAnimationState* state; + _spEventQueueItem* objects; + int objectsCount; + int objectsCapacity; + int /*boolean*/ drainDisabled; + +#ifdef __cplusplus + _spEventQueue() : + state(0), + objects(0), + objectsCount(0), + drainDisabled(0) { + } +#endif +} _spEventQueue; + typedef struct _spAnimationState { spAnimationState super; int eventsCount; spEvent** events; - spEventQueue* queue; + _spEventQueue* queue; void* propertyIDs; int /*boolean*/ animationsChanged; - spTrackEntry* (*createTrackEntry) (spAnimationState* self); - void (*disposeTrackEntry) (spTrackEntry* entry); - #ifdef __cplusplus _spAnimationState() : super(), @@ -193,15 +213,11 @@ typedef struct _spAnimationState { events(0), queue(0), propertyIDs(0), - animationsChanged(0), - createTrackEntry(0), - disposeTrackEntry(0) { + animationsChanged(0) { } #endif } _spAnimationState; -spTrackEntry* _spTrackEntry_create (spAnimationState* self); -void _spTrackEntry_dispose (spTrackEntry* self); /**/ diff --git a/spine-c/src/spine/AnimationState.c b/spine-c/src/spine/AnimationState.c index d64bca18f..76399127d 100644 --- a/spine-c/src/spine/AnimationState.c +++ b/spine-c/src/spine/AnimationState.c @@ -32,291 +32,104 @@ #include #include -spTrackEntry* _spTrackEntry_create (spAnimationState* state) { - spTrackEntry* self = NEW(spTrackEntry); - CONST_CAST(spAnimationState*, self->state) = state; - self->timeScale = 1; - self->lastTime = -1; - self->mix = 1; +_spEventQueue* _spEventQueue_create (spAnimationState* state) { + _spEventQueue *self = MALLOC(_spEventQueue, 1); + self->state = state; + self->objectsCount = 0; + self->objectsCapacity = 16; + self->objects = MALLOC(_spEventQueueItem, self->objectsCapacity * sizeof(_spEventQueueItem)); + self->drainDisabled = 0; return self; } -void _spTrackEntry_dispose (spTrackEntry* self) { - if (self->previous) SUB_CAST(_spAnimationState, self->state)->disposeTrackEntry(self->previous); - FREE(self); +void _spEventQueue_free (_spEventQueue* self) { + if (!self) return; + if (self->objects) FREE(self->objects); } -/**/ - -spTrackEntry* _spAnimationState_createTrackEntry (spAnimationState* self) { - return _spTrackEntry_create(self); -} - -void _spAnimationState_disposeTrackEntry (spTrackEntry* entry) { - _spTrackEntry_dispose(entry); -} - -spAnimationState* spAnimationState_create (spAnimationStateData* data) { - _spAnimationState* internal = NEW(_spAnimationState); - spAnimationState* self = SUPER(internal); - internal->events = MALLOC(spEvent*, 64); - self->timeScale = 1; - CONST_CAST(spAnimationStateData*, self->data) = data; - internal->createTrackEntry = _spAnimationState_createTrackEntry; - internal->disposeTrackEntry = _spAnimationState_disposeTrackEntry; - return self; -} - -void _spAnimationState_disposeAllEntries (spAnimationState* self, spTrackEntry* entry) { - _spAnimationState* internal = SUB_CAST(_spAnimationState, self); - while (entry) { - spTrackEntry* next = entry->next; - internal->disposeTrackEntry(entry); - entry = next; +void _spEventQueue_ensureCapacity (_spEventQueue* self, int newElements) { + if (self->objectsCount + newElements > self->objectsCapacity) { + _spEventQueueItem* newObjects; + self->objectsCapacity <<= 1; + newObjects = MALLOC(_spEventQueueItem, self->objectsCapacity); + memcpy(newObjects, self->objects, self->objectsCount * sizeof(_spEventQueueItem)); + FREE(self->objects); + self->objects = newObjects; } } -void spAnimationState_dispose (spAnimationState* self) { - int i; - _spAnimationState* internal = SUB_CAST(_spAnimationState, self); - FREE(internal->events); - for (i = 0; i < self->tracksCount; ++i) - _spAnimationState_disposeAllEntries(self, self->tracks[i]); - FREE(self->tracks); - FREE(self); +void _spEventQueue_addType (_spEventQueue* self, spEventType type) { + _spEventQueue_ensureCapacity(self, 1); + self->objects[self->objectsCount++].type = type; } -void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEntry* entry); +void _spEventQueue_addEntry (_spEventQueue* self, spTrackEntry* entry) { + _spEventQueue_ensureCapacity(self, 1); + self->objects[self->objectsCount++].entry = entry; +} -void spAnimationState_update (spAnimationState* self, float delta) { +void _spEventQueue_addEvent (_spEventQueue* self, spEvent* event) { + _spEventQueue_ensureCapacity(self, 1); + self->objects[self->objectsCount++].event = event; +} + +void _spEventQueue_start (_spEventQueue* self, spTrackEntry* entry) { + _spAnimationState* internalState = (_spAnimationState*)self->state; + _spEventQueue_addType(self, SP_ANIMATION_START); + _spEventQueue_addEntry(self, entry); + internalState->animationsChanged = 1; +} + +void _spEventQueue_interrupt (_spEventQueue* self, spTrackEntry* entry) { + _spEventQueue_addType(self, SP_ANIMATION_INTERRUPT); + _spEventQueue_addEntry(self, entry); +} + +void _spEventQueue_end (_spEventQueue* self, spTrackEntry* entry) { + _spAnimationState* internalState = (_spAnimationState*)self->state; + _spEventQueue_addType(self, SP_ANIMATION_END); + _spEventQueue_addEntry(self, entry); + internalState->animationsChanged = 1; +} + +void _spEventQueue_dispose (_spEventQueue* self, spTrackEntry* entry) { + _spEventQueue_addType(self, SP_ANIMATION_DISPOSE); + _spEventQueue_addEntry(self, entry); +} + +void _spEventQueue_complete (_spEventQueue* self, spTrackEntry* entry) { + _spEventQueue_addType(self, SP_ANIMATION_COMPLETE); + _spEventQueue_addEntry(self, entry); +} + +void _spEventQueue_event (_spEventQueue* self, spTrackEntry* entry, spEvent* event) { + _spEventQueue_addType(self, SP_ANIMATION_EVENT); + _spEventQueue_addEntry(self, entry); + _spEventQueue_addEvent(self, event); +} + +void _spEventQueue_clear (_spEventQueue* self) { + self->objectsCount = 0; +} + +void _spEventQueue_drain (_spEventQueue* self) { int i; - float previousDelta; - delta *= self->timeScale; - for (i = 0; i < self->tracksCount; ++i) { - spTrackEntry* current = self->tracks[i]; - if (!current) continue; - - current->time += delta * current->timeScale; - if (current->previous) { - previousDelta = delta * current->previous->timeScale; - current->previous->time += previousDelta; - current->mixTime += previousDelta; - } - - if (current->next) { - current->next->time = current->lastTime - current->next->delay; - if (current->next->time >= 0) _spAnimationState_setCurrent(self, i, current->next); + if (self->drainDisabled) return; + self->drainDisabled = 1; + for (i = 0; i < self->objectsCount; i += 2) { + spEventType type = self->objects[i].type; + spTrackEntry* entry = self->objects[i+1].entry; + if (type != SP_ANIMATION_EVENT) { + if (entry->listener) entry->listener(self->state, type, entry, 0); + if (self->state->listener) self->state->listener(self->state, type, entry, 0); } else { - /* End non-looping animation when it reaches its end time and there is no next entry. */ - if (!current->loop && current->lastTime >= current->endTime) spAnimationState_clearTrack(self, i); + spEvent* event = self->objects[i+2].event; + if (entry->listener) entry->listener(self->state, type, entry, event); + if (self->state->listener) self->state->listener(self->state, type, entry, event); + i++; } } -} - -void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) { - _spAnimationState* internal = SUB_CAST(_spAnimationState, self); - - int i, ii; - int eventsCount; - int entryChanged; - float time; - spTrackEntry* previous; - for (i = 0; i < self->tracksCount; ++i) { - spTrackEntry* current = self->tracks[i]; - if (!current) continue; - - eventsCount = 0; - - time = current->time; - if (!current->loop && time > current->endTime) time = current->endTime; - - previous = current->previous; - if (!previous) { - if (current->mix == 1) { - spAnimation_apply(current->animation, skeleton, current->lastTime, time, - current->loop, internal->events, &eventsCount); - } else { - spAnimation_mix(current->animation, skeleton, current->lastTime, time, - current->loop, internal->events, &eventsCount, current->mix); - } - } else { - float alpha = current->mixTime / current->mixDuration * current->mix; - - float previousTime = previous->time; - if (!previous->loop && previousTime > previous->endTime) previousTime = previous->endTime; - spAnimation_apply(previous->animation, skeleton, previousTime, previousTime, previous->loop, 0, 0); - - if (alpha >= 1) { - alpha = 1; - internal->disposeTrackEntry(current->previous); - current->previous = 0; - } - spAnimation_mix(current->animation, skeleton, current->lastTime, time, - current->loop, internal->events, &eventsCount, alpha); - } - - entryChanged = 0; - for (ii = 0; ii < eventsCount; ++ii) { - spEvent* event = internal->events[ii]; - if (current->listener) { - current->listener(self, i, SP_ANIMATION_EVENT, event, 0); - if (self->tracks[i] != current) { - entryChanged = 1; - break; - } - } - if (self->listener) { - self->listener(self, i, SP_ANIMATION_EVENT, event, 0); - if (self->tracks[i] != current) { - entryChanged = 1; - break; - } - } - } - if (entryChanged) continue; - - /* Check if completed the animation or a loop iteration. */ - if (current->loop ? (FMOD(current->lastTime, current->endTime) > FMOD(time, current->endTime)) - : (current->lastTime < current->endTime && time >= current->endTime)) { - int count = (int)(time / current->endTime); - if (current->listener) { - current->listener(self, i, SP_ANIMATION_COMPLETE, 0, count); - if (self->tracks[i] != current) continue; - } - if (self->listener) { - self->listener(self, i, SP_ANIMATION_COMPLETE, 0, count); - if (self->tracks[i] != current) continue; - } - } - - current->lastTime = current->time; - } -} - -void spAnimationState_clearTracks (spAnimationState* self) { - int i; - for (i = 0; i < self->tracksCount; ++i) - spAnimationState_clearTrack(self, i); - self->tracksCount = 0; -} - -void spAnimationState_clearTrack (spAnimationState* self, int trackIndex) { - spTrackEntry* current; - if (trackIndex >= self->tracksCount) return; - current = self->tracks[trackIndex]; - if (!current) return; - - if (current->listener) current->listener(self, trackIndex, SP_ANIMATION_END, 0, 0); - if (self->listener) self->listener(self, trackIndex, SP_ANIMATION_END, 0, 0); - - self->tracks[trackIndex] = 0; - - _spAnimationState_disposeAllEntries(self, current); -} - -spTrackEntry* _spAnimationState_expandToIndex (spAnimationState* self, int index) { - spTrackEntry** newTracks; - if (index < self->tracksCount) return self->tracks[index]; - newTracks = CALLOC(spTrackEntry*, index + 1); - memcpy(newTracks, self->tracks, self->tracksCount * sizeof(spTrackEntry*)); - FREE(self->tracks); - self->tracks = newTracks; - self->tracksCount = index + 1; - return 0; -} - -void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEntry* entry) { - _spAnimationState* internal = SUB_CAST(_spAnimationState, self); - - spTrackEntry* current = _spAnimationState_expandToIndex(self, index); - if (current) { - spTrackEntry* previous = current->previous; - current->previous = 0; - - if (current->listener) current->listener(self, index, SP_ANIMATION_END, 0, 0); - if (self->listener) self->listener(self, index, SP_ANIMATION_END, 0, 0); - - entry->mixDuration = spAnimationStateData_getMix(self->data, current->animation, entry->animation); - if (entry->mixDuration > 0) { - entry->mixTime = 0; - /* If a mix is in progress, mix from the closest animation. */ - if (previous && current->mixTime / current->mixDuration < 0.5f) { - entry->previous = previous; - previous = current; - } else - entry->previous = current; - } else - internal->disposeTrackEntry(current); - - if (previous) internal->disposeTrackEntry(previous); - } - - self->tracks[index] = entry; - - if (entry->listener) { - entry->listener(self, index, SP_ANIMATION_START, 0, 0); - if (self->tracks[index] != entry) return; - } - if (self->listener) self->listener(self, index, SP_ANIMATION_START, 0, 0); -} - -spTrackEntry* spAnimationState_setAnimationByName (spAnimationState* self, int trackIndex, const char* animationName, - int/*bool*/loop) { - spAnimation* animation = spSkeletonData_findAnimation(self->data->skeletonData, animationName); - return spAnimationState_setAnimation(self, trackIndex, animation, loop); -} - -spTrackEntry* spAnimationState_setAnimation (spAnimationState* self, int trackIndex, spAnimation* animation, int/*bool*/loop) { - _spAnimationState* internal = SUB_CAST(_spAnimationState, self); - - spTrackEntry* entry; - spTrackEntry* current = _spAnimationState_expandToIndex(self, trackIndex); - if (current) _spAnimationState_disposeAllEntries(self, current->next); - - entry = internal->createTrackEntry(self); - entry->animation = animation; - entry->loop = loop; - entry->endTime = animation->duration; - _spAnimationState_setCurrent(self, trackIndex, entry); - return entry; -} - -spTrackEntry* spAnimationState_addAnimationByName (spAnimationState* self, int trackIndex, const char* animationName, - int/*bool*/loop, float delay) { - spAnimation* animation = spSkeletonData_findAnimation(self->data->skeletonData, animationName); - return spAnimationState_addAnimation(self, trackIndex, animation, loop, delay); -} - -spTrackEntry* spAnimationState_addAnimation (spAnimationState* self, int trackIndex, spAnimation* animation, int/*bool*/loop, - float delay) { - _spAnimationState* internal = SUB_CAST(_spAnimationState, self); - spTrackEntry* last; - - spTrackEntry* entry = internal->createTrackEntry(self); - entry->animation = animation; - entry->loop = loop; - entry->endTime = animation->duration; - - last = _spAnimationState_expandToIndex(self, trackIndex); - if (last) { - while (last->next) - last = last->next; - last->next = entry; - } else - self->tracks[trackIndex] = entry; - - if (delay <= 0) { - if (last) - delay += last->endTime - spAnimationStateData_getMix(self->data, last->animation, animation); - else - delay = 0; - } - entry->delay = delay; - - return entry; -} - -spTrackEntry* spAnimationState_getCurrent (spAnimationState* self, int trackIndex) { - if (trackIndex >= self->tracksCount) return 0; - return self->tracks[trackIndex]; + + _spEventQueue_clear(self); + self->drainDisabled = 0; } diff --git a/spine-lua/Animation.lua b/spine-lua/Animation.lua index 69583b813..891f99e1b 100644 --- a/spine-lua/Animation.lua +++ b/spine-lua/Animation.lua @@ -522,7 +522,7 @@ function Animation.ColorTimeline.new (frameCount) local slot = skeleton.slots[self.slotIndex] if time < frames[0] then if setupPose then - slot.color.setFromt(slot.data.color) + slot.color:setFrom(slot.data.color) end return end diff --git a/spine-sfml/example/main.cpp b/spine-sfml/example/main.cpp index 306149b37..4ac13458f 100644 --- a/spine-sfml/example/main.cpp +++ b/spine-sfml/example/main.cpp @@ -39,22 +39,25 @@ using namespace spine; #include #include -void callback (AnimationState* state, int trackIndex, EventType type, Event* event, int loopCount) { - TrackEntry* entry = AnimationState_getCurrent(state, trackIndex); +void callback (AnimationState* state, EventType type, TrackEntry* entry, Event* event) { const char* animationName = (entry && entry->animation) ? entry->animation->name : 0; switch (type) { case ANIMATION_START: - printf("%d start: %s\n", trackIndex, animationName); + printf("%d start: %s\n", entry->trackIndex, animationName); break; + case ANIMATION_INTERRUPT: + printf("%d interrupt: %s\n", entry->trackIndex, animationName); case ANIMATION_END: - printf("%d end: %s\n", trackIndex, animationName); + printf("%d end: %s\n", entry->trackIndex, animationName); break; case ANIMATION_COMPLETE: - printf("%d complete: %s, %d\n", trackIndex, animationName, loopCount); + printf("%d complete: %s\n", entry->trackIndex, animationName); break; + case ANIMATION_DISPOSE: + printf("%d dispose: %s\n", entry->trackIndex, animationName); case ANIMATION_EVENT: - printf("%d event: %s, %s: %d, %f, %s\n", trackIndex, animationName, event->data->name, event->intValue, event->floatValue, + printf("%d event: %s, %s: %d, %f, %s\n", entry->trackIndex, animationName, event->data->name, event->intValue, event->floatValue, event->stringValue); break; }