Explorar o código

[c] Ported latest anim state changes.

badlogic %!s(int64=8) %!d(string=hai) anos
pai
achega
e324c05bfa

+ 11 - 12
spine-c/spine-c/include/spine/AnimationState.h

@@ -34,6 +34,7 @@
 #include <spine/Animation.h>
 #include <spine/AnimationStateData.h>
 #include <spine/Event.h>
+#include <spine/Array.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -48,6 +49,8 @@ typedef struct spTrackEntry spTrackEntry;
 
 typedef void (*spAnimationStateListener) (spAnimationState* state, spEventType type, spTrackEntry* entry, spEvent* event);
 
+_SP_ARRAY_DECLARE_TYPE(spTrackEntryArray, spTrackEntry*)
+
 struct spTrackEntry {
 	spAnimation* animation;
 	spTrackEntry* next;
@@ -58,11 +61,9 @@ struct spTrackEntry {
 	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;
-	int* /*boolean*/ timelinesLast;
-	int timelinesLastCount;
+	float alpha, mixTime, mixDuration, interruptAlpha;
+	spIntArray* timelineData;
+	spTrackEntryArray* timelineDipMix;
 	float* timelinesRotation;
 	int timelinesRotationCount;
 	void* rendererObject;
@@ -78,11 +79,9 @@ struct spTrackEntry {
 		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),
-		timelinesLast(0),
-		timelinesLastCount(0),
+		alpha(0), mixTime(0), mixDuration(0), interruptAlpha(0),
+		timelineData(0),
+		timelineDipMix(0),
 		timelinesRotation(0),
 		timelinesRotationCount(0) {
 	}
@@ -99,7 +98,7 @@ struct spAnimationState {
 
 	float timeScale;
 
-	int /*boolean*/ multipleMixing;
+	spTrackEntryArray* mixingTo;
 
 	void* rendererObject;
 
@@ -110,7 +109,7 @@ struct spAnimationState {
 		tracks(0),
 		listener(0),
 		timeScale(0),
-		multipleMixing(0),
+		mixingTo(0),
 		rendererObject(0) {
 	}
 #endif

+ 0 - 1
spine-c/spine-c/include/spine/Array.h

@@ -126,7 +126,6 @@ _SP_ARRAY_DECLARE_TYPE(spUnsignedShortArray, unsigned short)
 _SP_ARRAY_DECLARE_TYPE(spArrayFloatArray, spFloatArray*)
 _SP_ARRAY_DECLARE_TYPE(spArrayShortArray, spShortArray*)
 
-
 #ifdef __cplusplus
 }
 #endif

+ 149 - 155
spine-c/spine-c/src/spine/AnimationState.c

@@ -32,6 +32,12 @@
 #include <spine/extension.h>
 #include <limits.h>
 
+#define SUBSEQUENT 0
+#define FIRST 1
+#define DIP 2
+
+_SP_ARRAY_IMPLEMENT_TYPE(spTrackEntryArray, spTrackEntry*)
+
 static spAnimation* SP_EMPTY_ANIMATION = 0;
 void spAnimationState_disposeStatics () {
 	if (SP_EMPTY_ANIMATION) spAnimation_dispose(SP_EMPTY_ANIMATION);
@@ -42,7 +48,7 @@ void spAnimationState_disposeStatics () {
    the same function order in C as we have method order in Java */
 void _spAnimationState_disposeTrackEntry (spTrackEntry* entry);
 void _spAnimationState_disposeTrackEntries (spAnimationState* state, spTrackEntry* entry);
-void _spAnimationState_updateMixingFrom (spAnimationState* self, spTrackEntry* entry, float delta);
+int /*boolean*/ _spAnimationState_updateMixingFrom (spAnimationState* self, spTrackEntry* entry, float delta, int animationCount);
 float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* entry, spSkeleton* skeleton);
 void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline* timeline, spSkeleton* skeleton, float time, float alpha, int /*boolean*/ setupPose, float* timelinesRotation, int i, int /*boolean*/ firstFrame);
 void _spAnimationState_queueEvents (spAnimationState* self, spTrackEntry* entry, float animationTime);
@@ -55,9 +61,8 @@ float* _spAnimationState_resizeTimelinesRotation(spTrackEntry* entry, int newSiz
 int* _spAnimationState_resizeTimelinesFirst(spTrackEntry* entry, int newSize);
 void _spAnimationState_ensureCapacityPropertyIDs(spAnimationState* self, int capacity);
 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, int /*boolean*/ useTimelinesFirst);
+spTrackEntry* _spTrackEntry_setTimelineData(spTrackEntry* self, spTrackEntry* to, spTrackEntryArray* mixingToArray, spAnimationState* state);
+
 
 _spEventQueue* _spEventQueue_create (_spAnimationState* state) {
 	_spEventQueue *self = CALLOC(_spEventQueue, 1);
@@ -175,8 +180,8 @@ void _spEventQueue_drain (_spEventQueue* self) {
 }
 
 void _spAnimationState_disposeTrackEntry (spTrackEntry* entry) {
-	FREE(entry->timelinesFirst);
-	FREE(entry->timelinesLast);
+	spIntArray_dispose(entry->timelineData);
+	spTrackEntryArray_dispose(entry->timelineDipMix);
 	FREE(entry->timelinesRotation);
 	FREE(entry);
 }
@@ -216,6 +221,8 @@ spAnimationState* spAnimationState_create (spAnimationStateData* data) {
 	internal->propertyIDs = CALLOC(int, 128);
 	internal->propertyIDsCapacity = 128;
 
+	self->mixingTo = spTrackEntryArray_create(16);
+
 	return self;
 }
 
@@ -229,6 +236,7 @@ void spAnimationState_dispose (spAnimationState* self) {
 	FREE(internal->events);
 	FREE(internal->propertyIDs);
     FREE(internal);
+	spTrackEntryArray_dispose(self->mixingTo);
 }
 
 void spAnimationState_update (spAnimationState* self, float delta) {
@@ -277,7 +285,15 @@ void spAnimationState_update (spAnimationState* self, float delta) {
 				continue;
 			}
 		}
-        _spAnimationState_updateMixingFrom(self, current, delta);
+		if (current->mixingFrom != 0 && _spAnimationState_updateMixingFrom(self, current, delta, 2)) {
+			/* End mixing from entries once all have completed. */
+			spTrackEntry* from = current->mixingFrom;
+			current->mixingFrom = 0;
+			while (from != 0) {
+				_spEventQueue_end(internal->queue, from);
+				from = from->mixingFrom;
+			}
+		}
 
 		current->trackTime += currentDelta;
 	}
@@ -285,23 +301,32 @@ void spAnimationState_update (spAnimationState* self, float delta) {
 	_spEventQueue_drain(internal->queue);
 }
 
-void _spAnimationState_updateMixingFrom (spAnimationState* self, spTrackEntry* entry, float delta) {
-	spTrackEntry* from = entry->mixingFrom;		
+int /*boolean*/ _spAnimationState_updateMixingFrom (spAnimationState* self, spTrackEntry* entry, float delta, int animationCount) {
+	spTrackEntry* from = entry->mixingFrom;
+	int finished;
 	_spAnimationState* internal = SUB_CAST(_spAnimationState, self);
-	if (!from) return;
-    
-    _spAnimationState_updateMixingFrom(self, from, delta);
-
-	if (entry->mixTime >= entry->mixDuration && from->mixingFrom == 0 && entry->mixTime > 0) {
-        entry->mixingFrom = 0;
-		_spEventQueue_end(internal->queue, from);
-        return;
+	if (!from) return -1;
+
+	finished = _spAnimationState_updateMixingFrom(self, from, delta, animationCount + 1);
+
+	/* Require mixTime > 0 to ensure the mixing from entry was applied at least once. */
+	if (entry->mixTime > 0 && (entry->mixTime >= entry->mixDuration || entry->timeScale == 0)) {
+		if (animationCount > 5 && from->mixingFrom == 0) {
+			/* Limit linked list by speeding up and removing old entries. */
+			entry->interruptAlpha = MAX(0, entry->interruptAlpha - delta * 0.66f);
+			if (entry->interruptAlpha <= 0) {
+				entry->mixingFrom = 0;
+				_spEventQueue_end(internal->queue, from);
+			}
+		}
+		return finished;
 	}
 
 	from->animationLast = from->nextAnimationLast;
 	from->trackLast = from->nextTrackLast;
 	from->trackTime += delta * from->timeScale;
 	entry->mixTime += delta * entry->timeScale;
+	return 0;
 }
 
 void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
@@ -313,7 +338,6 @@ void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
 	spTimeline** timelines;
 	int /*boolean*/ firstFrame;
 	float* timelinesRotation;
-	int* timelinesFirst;
 	spTimeline* timeline;
 
 	if (internal->animationsChanged) _spAnimationState_animationsChanged(self);
@@ -338,17 +362,18 @@ void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
 			for (ii = 0; ii < timelineCount; ii++)
 				spTimeline_apply(timelines[ii], skeleton, animationLast, animationTime, internal->events, &internal->eventsCount, 1, 1, 0);
 		} else {
+			spIntArray* timelineData = current->timelineData;
+
 			firstFrame = current->timelinesRotationCount == 0;
 			if (firstFrame) _spAnimationState_resizeTimelinesRotation(current, timelineCount << 1);
 			timelinesRotation = current->timelinesRotation;
 
-			timelinesFirst = current->timelinesFirst;
 			for (ii = 0; ii < timelineCount; ii++) {
 				timeline = timelines[ii];
 				if (timeline->type == SP_TIMELINE_ROTATE)
-					_spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, mix, timelinesFirst[ii], timelinesRotation, ii << 1, firstFrame);
+					_spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, mix, timelineData->items[ii] > 0, timelinesRotation, ii << 1, firstFrame);
 				else
-					spTimeline_apply(timeline, skeleton, animationLast, animationTime, internal->events, &internal->eventsCount, mix, timelinesFirst[ii], 0);
+					spTimeline_apply(timeline, skeleton, animationLast, animationTime, internal->events, &internal->eventsCount, mix, timelineData->items[ii] > 0, 0);
 			}
 		}
 		_spAnimationState_queueEvents(self, current, animationTime);
@@ -360,7 +385,7 @@ void spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
 	_spEventQueue_drain(internal->queue);
 }
 
-float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* entry, spSkeleton* skeleton) {
+float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* to, spSkeleton* skeleton) {
 	_spAnimationState* internal = SUB_CAST(_spAnimationState, self);
 	float mix;
 	spEvent** events;
@@ -370,24 +395,24 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* e
 	float animationTime;
 	int timelineCount;
 	spTimeline** timelines;
-	int* timelinesFirst;
-	int* timelinesLast;
-	float alphaBase;
+	spIntArray* timelineData;
+	spTrackEntryArray* timelineDipMix;
+	float alphaDip;
 	float alphaMix;
 	float alpha;
 	int /*boolean*/ firstFrame;
 	float* timelinesRotation;
-	spTimeline* timeline;
-	int /*boolean*/ setupPose;
+	int /*boolean*/ first;
 	int i;
+	spTrackEntry* dipMix;
 
-	spTrackEntry* from = entry->mixingFrom;
+	spTrackEntry* from = to->mixingFrom;
 	if (from->mixingFrom) _spAnimationState_applyMixingFrom(self, from, skeleton);
 
-	if (entry->mixDuration == 0) /* Single frame mix to undo mixingFrom changes. */
+	if (to->mixDuration == 0) /* Single frame mix to undo mixingFrom changes. */
 		mix = 1;
 	else {
-		mix = entry->mixTime / entry->mixDuration;
+		mix = to->mixTime / to->mixDuration;
 		if (mix > 1) mix = 1;
 	}
 
@@ -398,31 +423,46 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* e
 	animationTime = spTrackEntry_getAnimationTime(from);
 	timelineCount = from->animation->timelinesCount;
 	timelines = from->animation->timelines;
-	timelinesFirst = from->timelinesFirst;
-	timelinesLast = self->multipleMixing ? 0 : from->timelinesLast;
-	alphaBase = from->alpha * entry->mixAlpha;
-	alphaMix = alphaBase * (1 - mix);
+	timelineData = from->timelineData;
+	timelineDipMix = from->timelineDipMix;
 
 	firstFrame = from->timelinesRotationCount == 0;
 	if (firstFrame) _spAnimationState_resizeTimelinesRotation(from, timelineCount << 1);
 	timelinesRotation = from->timelinesRotation;
 
+	first = 0;
+	alphaDip = from->alpha * to->interruptAlpha; alphaMix = alphaDip * (1 - mix);
 	for (i = 0; i < timelineCount; i++) {
-		timeline = timelines[i];
-		setupPose = timelinesFirst[i];
-		alpha = timelinesLast != 0 && setupPose && !timelinesLast[i] ? alphaBase : alphaMix;
+		spTimeline* timeline = timelines[i];
+		switch (timelineData->items[i]) {
+			case SUBSEQUENT:
+				first = 0;
+				alpha = alphaMix;
+				break;
+			case FIRST:
+				first = 1;
+				alpha = alphaMix;
+				break;
+			default:
+				first = 1;
+				alpha = alphaDip;
+				dipMix = timelineDipMix->items[i];
+				if (dipMix != 0) alpha *= MAX(0, 1 - dipMix->mixTime / dipMix->mixDuration);
+				break;
+		}
 		if (timeline->type == SP_TIMELINE_ROTATE)
-			_spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, alpha, setupPose, timelinesRotation, i << 1, firstFrame);
+			_spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, alpha, first, timelinesRotation, i << 1, firstFrame);
 		else {
-			if (!setupPose) {
+			if (!first) {
 				if (!attachments && timeline->type == SP_TIMELINE_ATTACHMENT) continue;
 				if (!drawOrder && timeline->type == SP_TIMELINE_DRAWORDER) continue;
 			}
-			spTimeline_apply(timeline, skeleton, animationLast, animationTime, events, &internal->eventsCount, alpha, setupPose, 1);
+			spTimeline_apply(timeline, skeleton, animationLast, animationTime, events, &internal->eventsCount, alpha, first, 1);
 		}
 	}
 
-	if (entry->mixDuration > 0) _spAnimationState_queueEvents(self, from, animationTime);
+
+	if (to->mixDuration > 0) _spAnimationState_queueEvents(self, from, animationTime);
 	internal->eventsCount = 0;
 	from->nextAnimationLast = animationTime;
 	from->nextTrackLast = from->trackTime;
@@ -581,7 +621,6 @@ 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) {
@@ -589,25 +628,9 @@ void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEnt
 		current->mixingFrom = from;
 		current->mixTime = 0;
 
-		mixingFrom = from->mixingFrom;
-		if (mixingFrom != 0 && from->mixDuration > 0) {
-			if (self->multipleMixing) {
-				current->mixAlpha *= MIN(from->mixTime / from->mixDuration, 1);
-			} else {
-				if (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;
-				}
-				
-				from->mixAlpha = 0;
-				from->mixTime = 0;
-				from->mixDuration = 0;
-			}
-		}
+		/* Store the interrupted mix percentage. */
+		if (from->mixingFrom != 0 && from->mixDuration > 0)
+			current->interruptAlpha *= MIN(1, from->mixTime / from->mixDuration);
 
 		from->timelinesRotationCount = 0;
 	}
@@ -747,9 +770,12 @@ spTrackEntry* _spAnimationState_trackEntry (spAnimationState* self, int trackInd
 	entry->timeScale = 1;
 
 	entry->alpha = 1;
-	entry->mixAlpha = 1;
+	entry->interruptAlpha = 1;
 	entry->mixTime = 0;
 	entry->mixDuration = !last ? 0 : spAnimationStateData_getMix(self->data, last->animation, animation);
+
+	entry->timelineData = spIntArray_create(16);
+	entry->timelineDipMix = spTrackEntryArray_create(16);
 	return entry;
 }
 
@@ -765,48 +791,22 @@ void _spAnimationState_disposeNext (spAnimationState* self, spTrackEntry* entry)
 
 void _spAnimationState_animationsChanged (spAnimationState* self) {
 	_spAnimationState* internal = SUB_CAST(_spAnimationState, self);
-	int i, n, ii, nn, lowestMixingFrom;
+	int i, n;
 	spTrackEntry* entry;
-	spTimeline** timelines;
+	spTrackEntry* lastEntry = 0;
+	spTrackEntryArray* mixingTo;
 	internal->animationsChanged = 0;
 
-	i = 0; n = self->tracksCount;
 	internal->propertyIDsCount = 0;
+	i = 0; n = self->tracksCount;
 
-	for (; i < n; i++) {
-		entry = self->tracks[i];
-		if (!entry) continue;
-		_spAnimationState_setTimelinesFirst(self, entry);
-		i++;
-		break;
-	}
-	for (; i < n; i++) {
-		entry = self->tracks[i];
-		if (entry) _spAnimationState_checkTimelinesFirst(self, entry);
-	}
-
-	if (self->multipleMixing) return;
+	mixingTo = self->mixingTo;
 
-	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--) {
+	for (;i < n; 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;
+		if (entry != 0) {
+			_spTrackEntry_setTimelineData(entry, lastEntry, mixingTo, self);
+			lastEntry = entry;
 		}
 	}
 }
@@ -821,28 +821,6 @@ float* _spAnimationState_resizeTimelinesRotation(spTrackEntry* entry, int newSiz
 	return entry->timelinesRotation;
 }
 
-int* _spAnimationState_resizeTimelinesFirst(spTrackEntry* entry, int newSize) {
-	if (entry->timelinesFirstCount != newSize) {
-		int* newTimelinesFirst = CALLOC(int, newSize);
-		FREE(entry->timelinesFirst);
-		entry->timelinesFirst = newTimelinesFirst;
-		entry->timelinesFirstCount = 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) {
@@ -868,42 +846,6 @@ int _spAnimationState_addPropertyID(spAnimationState* self, int id) {
 	return 1;
 }
 
-void _spAnimationState_setTimelinesFirst (spAnimationState* self, spTrackEntry* entry) {
-	int i, n;
-	int* usage;
-	spTimeline** timelines;
-
-	if (entry->mixingFrom) {
-		_spAnimationState_setTimelinesFirst(self, entry->mixingFrom);
-		_spAnimationState_checkTimelinesUsage(self, entry, -1);
-		return;
-	}
-
-	n = entry->animation->timelinesCount;
-	timelines = entry->animation->timelines;
-	usage = _spAnimationState_resizeTimelinesFirst(entry, n);
-	for (i = 0; i < n; i++) {
-		_spAnimationState_addPropertyID(self, spTimeline_getPropertyId(timelines[i]));
-		usage[i] = 1;
-	}
-}
-
-void _spAnimationState_checkTimelinesFirst (spAnimationState* self, spTrackEntry* entry) {
-	if (entry->mixingFrom) _spAnimationState_checkTimelinesFirst(self, entry->mixingFrom);
-	_spAnimationState_checkTimelinesUsage(self, entry, -1);
-}
-
-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 = useTimelinesFirst ? _spAnimationState_resizeTimelinesFirst(entry, n) : _spAnimationState_resizeTimelinesLast(entry, n);
-	for (i = 0; i < n; i++)
-		usage[i] = _spAnimationState_addPropertyID(self, spTimeline_getPropertyId(timelines[i]));
-}
-
 spTrackEntry* spAnimationState_getCurrent (spAnimationState* self, int trackIndex) {
 	if (trackIndex >= self->tracksCount) return 0;
 	return self->tracks[trackIndex];
@@ -922,3 +864,55 @@ float spTrackEntry_getAnimationTime (spTrackEntry* entry) {
 	}
 	return MIN(entry->trackTime + entry->animationStart, entry->animationEnd);
 }
+
+int /*boolean*/ _spTrackEntry_hasTimeline(spTrackEntry* self, int id) {
+	spTimeline** timelines = self->animation->timelines;
+	int i, n;
+	for (i = 0, n = self->animation->timelinesCount; i < n; i++)
+		if (spTimeline_getPropertyId(timelines[i]) == id) return 1;
+	return 0;
+}
+
+spTrackEntry* _spTrackEntry_setTimelineData(spTrackEntry* self, spTrackEntry* to, spTrackEntryArray* mixingToArray, spAnimationState* state) {
+	spTrackEntry* lastEntry;
+	spTrackEntry** mixingTo;
+	int mixingToLast;
+	spTimeline** timelines;
+	int timelinesCount;
+	int* timelineData;
+	spTrackEntry** timelineDipMix;
+	int i, ii;
+
+	if (to != 0) spTrackEntryArray_add(mixingToArray, to);
+	lastEntry = self->mixingFrom != 0 ? _spTrackEntry_setTimelineData(self->mixingFrom, self, mixingToArray, state) : self;
+	if (to != 0) spTrackEntryArray_pop(mixingToArray);
+
+	mixingTo = mixingToArray->items;
+	mixingToLast = mixingToArray->size - 1;
+	timelines = self->animation->timelines;
+	timelinesCount = self->animation->timelinesCount;
+	timelineData = spIntArray_setSize(self->timelineData, timelinesCount)->items;
+	timelineDipMix = spTrackEntryArray_setSize(self->timelineDipMix, timelinesCount)->items;
+
+	outer:
+	for (i = 0; i < timelinesCount; i++) {
+		int id = spTimeline_getPropertyId(timelines[i]);
+		if (!_spAnimationState_addPropertyID(state, id))
+			timelineData[i] = SUBSEQUENT;
+		else if (to == 0 || !_spTrackEntry_hasTimeline(to, id))
+			timelineData[i] = FIRST;
+		else {
+			timelineData[i] = DIP;
+			for (ii = mixingToLast; ii >= 0; ii--) {
+				spTrackEntry* entry = mixingTo[ii];
+				if (!_spTrackEntry_hasTimeline(entry, id)) {
+					if (entry->mixDuration > 0) timelineDipMix[i] = entry;
+					i++;
+					goto outer;
+				}
+			}
+			timelineDipMix[i] = 0;
+		}
+	}
+	return lastEntry;
+}

+ 0 - 1
spine-sfml/example/main.cpp

@@ -116,7 +116,6 @@ 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;