From e326db5f4b3b7844eed00a3723a720542440bcf6 Mon Sep 17 00:00:00 2001 From: badlogic Date: Thu, 6 Apr 2017 14:43:12 +0200 Subject: [PATCH] [c] Ported dipping problem fix, see #867 --- .../spine-c/include/spine/AnimationState.h | 10 ++- spine-c/spine-c/src/spine/AnimationState.c | 81 ++++++++++++++++--- spine-sfml/example/main.cpp | 1 + 3 files changed, 81 insertions(+), 11 deletions(-) diff --git a/spine-c/spine-c/include/spine/AnimationState.h b/spine-c/spine-c/include/spine/AnimationState.h index a2d68500d..7104e0a4a 100644 --- a/spine-c/spine-c/include/spine/AnimationState.h +++ b/spine-c/spine-c/include/spine/AnimationState.h @@ -61,6 +61,8 @@ struct spTrackEntry { float alpha, mixTime, mixDuration, mixAlpha; int* /*boolean*/ timelinesFirst; int timelinesFirstCount; + int* /*boolean*/ timelinesLast; + int timelinesLastCount; float* timelinesRotation; int timelinesRotationCount; void* rendererObject; @@ -79,6 +81,8 @@ struct spTrackEntry { alpha(0), mixTime(0), mixDuration(0), mixAlpha(0), timelinesFirst(0), timelinesFirstCount(0), + timelinesLast(0), + timelinesLastCount(0), timelinesRotation(0), timelinesRotationCount(0) { } @@ -95,6 +99,8 @@ struct spAnimationState { float timeScale; + int /*boolean*/ multipleMixing; + void* rendererObject; #ifdef __cplusplus @@ -103,7 +109,9 @@ struct spAnimationState { tracksCount(0), tracks(0), listener(0), - timeScale(0) { + timeScale(0), + multipleMixing(0), + rendererObject(0) { } #endif }; diff --git a/spine-c/spine-c/src/spine/AnimationState.c b/spine-c/spine-c/src/spine/AnimationState.c index cc3a30713..c2592c3b5 100644 --- a/spine-c/spine-c/src/spine/AnimationState.c +++ b/spine-c/spine-c/src/spine/AnimationState.c @@ -57,7 +57,7 @@ void _spAnimationState_ensureCapacityPropertyIDs(spAnimationState* self, int cap int _spAnimationState_addPropertyID(spAnimationState* self, int id); void _spAnimationState_setTimelinesFirst (spAnimationState* self, spTrackEntry* entry); void _spAnimationState_checkTimelinesFirst (spAnimationState* self, spTrackEntry* entry); -void _spAnimationState_checkTimelinesUsage (spAnimationState* self, spTrackEntry* entry); +void _spAnimationState_checkTimelinesUsage (spAnimationState* self, spTrackEntry* entry, int /*boolean*/ useTimelinesFirst); _spEventQueue* _spEventQueue_create (_spAnimationState* state) { _spEventQueue *self = CALLOC(_spEventQueue, 1); @@ -176,6 +176,7 @@ void _spEventQueue_drain (_spEventQueue* self) { void _spAnimationState_disposeTrackEntry (spTrackEntry* entry) { FREE(entry->timelinesFirst); + FREE(entry->timelinesLast); FREE(entry->timelinesRotation); FREE(entry); } @@ -370,6 +371,9 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* e int timelineCount; spTimeline** timelines; int* timelinesFirst; + int* timelinesLast; + float alphaBase; + float alphaMix; float alpha; int /*boolean*/ firstFrame; float* timelinesRotation; @@ -395,7 +399,9 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* e timelineCount = from->animation->timelinesCount; timelines = from->animation->timelines; timelinesFirst = from->timelinesFirst; - alpha = from->alpha * entry->mixAlpha * (1 - mix); + timelinesLast = self->multipleMixing ? 0 : from->timelinesLast; + alphaBase = from->alpha * entry->mixAlpha; + alphaMix = alphaBase * (1 - mix); firstFrame = from->timelinesRotationCount == 0; if (firstFrame) _spAnimationState_resizeTimelinesRotation(from, timelineCount << 1); @@ -404,6 +410,7 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* e for (i = 0; i < timelineCount; i++) { timeline = timelines[i]; setupPose = timelinesFirst[i]; + alpha = timelinesLast != 0 && setupPose && !timelinesLast[i] ? alphaBase : alphaMix; if (timeline->type == SP_TIMELINE_ROTATE) _spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, alpha, setupPose, timelinesRotation, i << 1, firstFrame); else { @@ -574,6 +581,7 @@ void spAnimationState_clearTrack (spAnimationState* self, int trackIndex) { void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEntry* current, int /*boolean*/ interrupt) { _spAnimationState* internal = SUB_CAST(_spAnimationState, self); spTrackEntry* from = _spAnimationState_expandToIndex(self, index); + spTrackEntry* mixingFrom = 0; self->tracks[index] = current; if (from) { @@ -581,10 +589,26 @@ void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEnt current->mixingFrom = from; current->mixTime = 0; - from->timelinesRotationCount = 0; + mixingFrom = from->mixingFrom; + if (mixingFrom != 0 && from->mixDuration > 0) { + if (self->multipleMixing && from->mixTime / from->mixDuration < 0.5 && mixingFrom->animation != SP_EMPTY_ANIMATION) { + current->mixingFrom = mixingFrom; + mixingFrom->mixingFrom = from; + mixingFrom->mixTime = from->mixDuration - from->mixTime; + mixingFrom->mixDuration = from->mixDuration; + from->mixingFrom = 0; + from = mixingFrom; + } - /* If not completely mixed in, set mixAlpha so mixing out happens from current mix to zero. */ - if (from->mixingFrom && from->mixDuration > 0) current->mixAlpha *= MIN(from->mixTime / from->mixDuration, 1); + current->mixAlpha *= MIN(from->mixTime / from->mixDuration, 1); + if (!self->multipleMixing) { + from->mixAlpha = 0; + from->mixTime = 0; + from->mixDuration = 0; + } + } + + from->timelinesRotationCount = 0; } _spEventQueue_start(internal->queue, current); @@ -740,8 +764,9 @@ void _spAnimationState_disposeNext (spAnimationState* self, spTrackEntry* entry) void _spAnimationState_animationsChanged (spAnimationState* self) { _spAnimationState* internal = SUB_CAST(_spAnimationState, self); - int i, n; + int i, n, ii, nn, lowestMixingFrom; spTrackEntry* entry; + spTimeline** timelines; internal->animationsChanged = 0; i = 0; n = self->tracksCount; @@ -758,6 +783,31 @@ void _spAnimationState_animationsChanged (spAnimationState* self) { entry = self->tracks[i]; if (entry) _spAnimationState_checkTimelinesFirst(self, entry); } + + if (self->multipleMixing) return; + + internal->propertyIDsCount = 0; + lowestMixingFrom = n; + for (i = 0; i < n; i++) { + entry = self->tracks[i]; + if (entry == 0 || entry->mixingFrom == 0) continue; + lowestMixingFrom = i; + break; + } + for (i = n - 1; i >= lowestMixingFrom; i--) { + entry = self->tracks[i]; + if (entry == 0) continue; + + timelines = entry->animation->timelines; + for (ii = 0, nn = entry->animation->timelinesCount; ii < nn; ii++) + _spAnimationState_addPropertyID(self, spTimeline_getPropertyId(timelines[ii])); + + entry = entry->mixingFrom; + while (entry != 0) { + _spAnimationState_checkTimelinesUsage(self, entry, 0); + entry = entry->mixingFrom; + } + } } float* _spAnimationState_resizeTimelinesRotation(spTrackEntry* entry, int newSize) { @@ -781,6 +831,17 @@ int* _spAnimationState_resizeTimelinesFirst(spTrackEntry* entry, int newSize) { return entry->timelinesFirst; } +int* _spAnimationState_resizeTimelinesLast(spTrackEntry* entry, int newSize) { + if (entry->timelinesLastCount != newSize) { + int* newTimelinesLast = CALLOC(int, newSize); + FREE(entry->timelinesLast); + entry->timelinesLast = newTimelinesLast; + entry->timelinesLastCount = newSize; + } + + return entry->timelinesLast; +} + void _spAnimationState_ensureCapacityPropertyIDs(spAnimationState* self, int capacity) { _spAnimationState* internal = SUB_CAST(_spAnimationState, self); if (internal->propertyIDsCapacity < capacity) { @@ -813,7 +874,7 @@ void _spAnimationState_setTimelinesFirst (spAnimationState* self, spTrackEntry* if (entry->mixingFrom) { _spAnimationState_setTimelinesFirst(self, entry->mixingFrom); - _spAnimationState_checkTimelinesUsage(self, entry); + _spAnimationState_checkTimelinesUsage(self, entry, -1); return; } @@ -828,16 +889,16 @@ void _spAnimationState_setTimelinesFirst (spAnimationState* self, spTrackEntry* void _spAnimationState_checkTimelinesFirst (spAnimationState* self, spTrackEntry* entry) { if (entry->mixingFrom) _spAnimationState_checkTimelinesFirst(self, entry->mixingFrom); - _spAnimationState_checkTimelinesUsage(self, entry); + _spAnimationState_checkTimelinesUsage(self, entry, -1); } -void _spAnimationState_checkTimelinesUsage (spAnimationState* self, spTrackEntry* entry) { +void _spAnimationState_checkTimelinesUsage (spAnimationState* self, spTrackEntry* entry, int /*boolean*/ useTimelinesFirst) { int i, n; int* usage; spTimeline** timelines; n = entry->animation->timelinesCount; timelines = entry->animation->timelines; - usage = _spAnimationState_resizeTimelinesFirst(entry, n); + usage = useTimelinesFirst ? _spAnimationState_resizeTimelinesFirst(entry, n) : _spAnimationState_resizeTimelinesLast(entry, n); for (i = 0; i < n; i++) usage[i] = _spAnimationState_addPropertyID(self, spTimeline_getPropertyId(timelines[i])); } diff --git a/spine-sfml/example/main.cpp b/spine-sfml/example/main.cpp index ca87d6ccd..a182cc982 100644 --- a/spine-sfml/example/main.cpp +++ b/spine-sfml/example/main.cpp @@ -116,6 +116,7 @@ void spineboy (SkeletonData* skeletonData, Atlas* atlas) { SkeletonDrawable* drawable = new SkeletonDrawable(skeletonData, stateData); drawable->timeScale = 1; + drawable->state->multipleMixing = -1; Skeleton* skeleton = drawable->skeleton; skeleton->flipX = false;