Эх сурвалжийг харах

[c] 4.0 porting, AnimationState

badlogic 4 жил өмнө
parent
commit
f74e80ae89

+ 4 - 0
spine-c/spine-c/include/spine/AnimationState.h

@@ -53,6 +53,7 @@ _SP_ARRAY_DECLARE_TYPE(spTrackEntryArray, spTrackEntry*)
 
 struct spTrackEntry {
 	spAnimation* animation;
+	spTrackEntry* previous;
 	spTrackEntry* next;
 	spTrackEntry* mixingFrom;
 	spTrackEntry* mixingTo;
@@ -60,6 +61,7 @@ struct spTrackEntry {
 	int trackIndex;
 	int /*boolean*/ loop;
 	int /*boolean*/ holdPrevious;
+	int /*boolean*/ reverse;
 	float eventThreshold, attachmentThreshold, drawOrderThreshold;
 	float animationStart, animationEnd, animationLast, nextAnimationLast;
 	float delay, trackTime, trackLast, nextTrackLast, trackEnd, timeScale;
@@ -120,6 +122,8 @@ SP_API void spAnimationState_clearListenerNotifications(spAnimationState* self);
 
 SP_API float spTrackEntry_getAnimationTime (spTrackEntry* entry);
 
+SP_API float spTrackEntry_getTrackComplete(spTrackEntry* entry);
+
 /** Use this to dispose static memory before your app exits to appease your memory leak detector*/
 SP_API void spAnimationState_disposeStatics ();
 

+ 1 - 1
spine-c/spine-c/include/spine/extension.h

@@ -216,7 +216,7 @@ struct _spAnimationState {
 
 	_spEventQueue* queue;
 
-	int* propertyIDs;
+	spPropertyId* propertyIDs;
 	int propertyIDsCount;
 	int propertyIDsCapacity;
 

+ 91 - 83
spine-c/spine-c/src/spine/AnimationState.c

@@ -63,9 +63,8 @@ spTrackEntry* _spAnimationState_trackEntry (spAnimationState* self, int trackInd
 void _spAnimationState_disposeNext (spAnimationState* self, spTrackEntry* entry);
 void _spAnimationState_animationsChanged (spAnimationState* self);
 float* _spAnimationState_resizeTimelinesRotation(spTrackEntry* entry, int newSize);
-int* _spAnimationState_resizeTimelinesFirst(spTrackEntry* entry, int newSize);
 void _spAnimationState_ensureCapacityPropertyIDs(spAnimationState* self, int capacity);
-int _spAnimationState_addPropertyID(spAnimationState* self, int id);
+int _spAnimationState_addPropertyID(spAnimationState* self, spPropertyId id);
 void _spTrackEntry_computeHold(spTrackEntry* self, spAnimationState* state);
 
 _spEventQueue* _spEventQueue_create (_spAnimationState* state) {
@@ -237,7 +236,7 @@ spAnimationState* spAnimationState_create (spAnimationStateData* data) {
 	internal->queue = _spEventQueue_create(internal);
 	internal->events = CALLOC(spEvent*, 128);
 
-	internal->propertyIDs = CALLOC(int, 128);
+	internal->propertyIDs = CALLOC(spPropertyId, 128);
 	internal->propertyIDsCapacity = 128;
 
 	return self;
@@ -363,6 +362,8 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
 	spSlot** slots = NULL;
 	spSlot* slot = NULL;
     const char* attachmentName = NULL;
+	spEvent** applyEvents = NULL;
+	float applyTime;
 
 	if (internal->animationsChanged) _spAnimationState_animationsChanged(self);
 
@@ -382,15 +383,21 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
 
 		/* Apply current entry. */
 		animationLast = current->animationLast; animationTime = spTrackEntry_getAnimationTime(current);
-		timelineCount = current->animation->timelinesCount;
-		timelines = current->animation->timelines;
+		timelineCount = current->animation->timelines->size;
+		applyEvents = internal->events;
+		applyTime = animationTime;
+		if (current->reverse) {
+			applyTime = current->animation->duration - applyTime;
+			applyEvents = NULL;
+		}
+		timelines = current->animation->timelines->items;
 		if ((i == 0 && mix == 1) || blend == SP_MIX_BLEND_ADD) {
 			for (ii = 0; ii < timelineCount; ii++) {
                 timeline = timelines[ii];
-			    if (timeline->type == SP_TIMELINE_ATTACHMENT) {
-                    _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, animationTime, blend, -1);
+			    if (timeline->propertyIds[0] == SP_PROPERTY_ATTACHMENT) {
+                    _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, applyTime, blend, -1);
 			    } else {
-                    spTimeline_apply(timelines[ii], skeleton, animationLast, animationTime, internal->events,
+                    spTimeline_apply(timelines[ii], skeleton, animationLast, applyTime, applyEvents,
                                      &internal->eventsCount, mix, blend, SP_MIX_DIRECTION_IN);
                 }
             }
@@ -404,12 +411,12 @@ int spAnimationState_apply (spAnimationState* self, spSkeleton* skeleton) {
 			for (ii = 0; ii < timelineCount; ii++) {
 				timeline = timelines[ii];
 				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);
+				if (timeline->propertyIds[0] == SP_PROPERTY_ROTATE)
+					_spAnimationState_applyRotateTimeline(self, timeline, skeleton, applyTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
+				else if (timeline->propertyIds[0] == SP_PROPERTY_ATTACHMENT)
+				    _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, applyTime, timelineBlend, -1);
 				else
-					spTimeline_apply(timeline, skeleton, animationLast, animationTime, internal->events, &internal->eventsCount, mix, timelineBlend, SP_MIX_DIRECTION_IN);
+					spTimeline_apply(timeline, skeleton, animationLast, applyTime, applyEvents, &internal->eventsCount, mix, timelineBlend, SP_MIX_DIRECTION_IN);
 			}
 		}
 		_spAnimationState_queueEvents(self, current, animationTime);
@@ -453,6 +460,7 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* t
 	float* timelinesRotation;
 	int i;
 	spTrackEntry* holdMix;
+	float applyTime;
 
 	spTrackEntry* from = to->mixingFrom;
 	if (from->mixingFrom) _spAnimationState_applyMixingFrom(self, from, skeleton, blend);
@@ -466,18 +474,25 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* t
 		if (blend != SP_MIX_BLEND_FIRST) blend = from->mixBlend;
 	}
 
-	events = mix < from->eventThreshold ? internal->events : 0;
 	attachments = mix < from->attachmentThreshold;
 	drawOrder = mix < from->drawOrderThreshold;
+	timelineCount = from->animation->timelines->size;
+	timelines = from->animation->timelines->items;
+	alphaHold = from->alpha * to->interruptAlpha; alphaMix = alphaHold * (1 - mix);
 	animationLast = from->animationLast;
 	animationTime = spTrackEntry_getAnimationTime(from);
-	timelineCount = from->animation->timelinesCount;
-	timelines = from->animation->timelines;
-	alphaHold = from->alpha * to->interruptAlpha; alphaMix = alphaHold * (1 - mix);
+	applyTime = animationTime;
+	events = NULL;
+	if (from->reverse) {
+		applyTime = from->animation->duration - applyTime;
+	} else {
+		if (mix < from->eventThreshold) events = internal->events;
+	}
+
 	if (blend == SP_MIX_BLEND_ADD) {
 		for (i = 0; i < timelineCount; i++) {
 			spTimeline *timeline = timelines[i];
-			spTimeline_apply(timeline, skeleton, animationLast, animationTime, events, &internal->eventsCount, alphaMix, blend, SP_MIX_DIRECTION_OUT);
+			spTimeline_apply(timeline, skeleton, animationLast, applyTime, events, &internal->eventsCount, alphaMix, blend, SP_MIX_DIRECTION_OUT);
 		}
 	} else {
 		timelineMode = from->timelineMode;
@@ -494,7 +509,7 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* t
 
 			switch (timelineMode->items[i]) {
 				case SUBSEQUENT:
-					if (!drawOrder && timeline->type == SP_TIMELINE_DRAWORDER) continue;
+					if (!drawOrder && timeline->propertyIds[0] == SP_PROPERTY_DRAWORDER) continue;
                     timelineBlend = blend;
 					alpha = alphaMix;
 					break;
@@ -517,15 +532,15 @@ float _spAnimationState_applyMixingFrom (spAnimationState* self, spTrackEntry* t
 					break;
 			}
 			from->totalAlpha += alpha;
-			if (timeline->type == SP_TIMELINE_ROTATE)
-				_spAnimationState_applyRotateTimeline(self, timeline, skeleton, animationTime, alpha, timelineBlend,
+			if (timeline->propertyIds[0] == SP_PROPERTY_ROTATE)
+				_spAnimationState_applyRotateTimeline(self, timeline, skeleton, applyTime, alpha, timelineBlend,
 					timelinesRotation, i << 1, firstFrame);
-			else if (timeline->type == SP_TIMELINE_ATTACHMENT)
-			    _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, animationTime, timelineBlend, attachments);
+			else if (timeline->propertyIds[0] == SP_PROPERTY_ATTACHMENT)
+			    _spAnimationState_applyAttachmentTimeline(self, timeline, skeleton, applyTime, timelineBlend, attachments);
 			else {
-                if (drawOrder && timeline->type == SP_TIMELINE_DRAWORDER && timelineBlend == SP_MIX_BLEND_SETUP)
+                if (drawOrder && timeline->propertyIds[0] == SP_PROPERTY_DRAWORDER && timelineBlend == SP_MIX_BLEND_SETUP)
                     direction = SP_MIX_DIRECTION_IN;
-				spTimeline_apply(timeline, skeleton, animationLast, animationTime, events, &internal->eventsCount,
+				spTimeline_apply(timeline, skeleton, animationLast, applyTime, events, &internal->eventsCount,
 					alpha, timelineBlend, direction);
 			}
 		}
@@ -572,17 +587,12 @@ void _spAnimationState_applyAttachmentTimeline(spAnimationState* self, spTimelin
     slot = skeleton->slots[attachmentTimeline->slotIndex];
     if (!slot->bone->active) return;
 
-    frames = attachmentTimeline->frames;
+    frames = attachmentTimeline->super.frames->items;
     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);
+    } else {
+        _spAnimationState_setAttachment(self, skeleton, slot, attachmentTimeline->attachmentNames[binarySearch1(frames, attachmentTimeline->super.frames->size, time)], attachments);
     }
 
     /* If an attachment wasn't set (ie before the first frame or attachments is false), set the setup attachment later.*/
@@ -612,7 +622,7 @@ void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline*
 	}
 
 	rotateTimeline = SUB_CAST(spRotateTimeline, timeline);
-	frames = rotateTimeline->frames;
+	frames = rotateTimeline->super.super.frames->items;
 	bone = skeleton->bones[rotateTimeline->boneIndex];
 	if (!bone->active) return;
 	if (time < frames[0]) {
@@ -627,21 +637,7 @@ void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline*
 		}
 	} else {
 		r1 = blend == SP_MIX_BLEND_SETUP ? bone->data->rotation : bone->rotation;
-		if (time >= frames[rotateTimeline->framesCount - ROTATE_ENTRIES]) /* Time is after last frame. */
-			r2 = bone->data->rotation + frames[rotateTimeline->framesCount + ROTATE_PREV_ROTATION];
-		else {
-			/* Interpolate between the previous frame and the current frame. */
-			frame = _spCurveTimeline_binarySearch(frames, rotateTimeline->framesCount, time, ROTATE_ENTRIES);
-			prevRotation = frames[frame + ROTATE_PREV_ROTATION];
-			frameTime = frames[frame];
-			percent = spCurveTimeline_getCurvePercent(SUPER(rotateTimeline), (frame >> 1) - 1,
-				1 - (time - frameTime) / (frames[frame + ROTATE_PREV_TIME] - frameTime));
-
-			r2 = frames[frame + ROTATE_ROTATION] - prevRotation;
-			r2 -= (16384 - (int) (16384.499999999996 - r2 / 360)) * 360;
-			r2 = prevRotation + r2 * percent + bone->data->rotation;
-			r2 -= (16384 - (int) (16384.499999999996 - r2 / 360)) * 360;
-		}
+		r2 = bone->data->rotation + spCurveTimeline1_getCurveValue(&rotateTimeline->super, time);
 	}
 
 	/* Mix between rotations using the direction of the shortest route on the first frame while detecting crosses. */
@@ -671,8 +667,7 @@ void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline*
 		timelinesRotation[i] = total;
 	}
 	timelinesRotation[i + 1] = diff;
-	r1 += total * alpha;
-	bone->rotation = r1 - (16384 - (int)(16384.499999999996 - r1 / 360)) * 360;
+	bone->rotation = r1 + total * alpha;
 }
 
 void _spAnimationState_queueEvents (spAnimationState* self, spTrackEntry* entry, float animationTime) {
@@ -708,6 +703,10 @@ void _spAnimationState_queueEvents (spAnimationState* self, spTrackEntry* entry,
 	}
 }
 
+void spAnimationState_clearNext(spTrackEntry* entry) {
+	_spAnimationState_disposeTrackEntry(entry);
+}
+
 void spAnimationState_clearTracks (spAnimationState* self) {
 	_spAnimationState* internal = SUB_CAST(_spAnimationState, self);
 	int i, n, oldDrainDisabled;
@@ -752,6 +751,7 @@ void _spAnimationState_setCurrent (spAnimationState* self, int index, spTrackEnt
 	_spAnimationState* internal = SUB_CAST(_spAnimationState, self);
 	spTrackEntry* from = _spAnimationState_expandToIndex(self, index);
 	self->tracks[index] = current;
+	current->previous = NULL;
 
 	if (from) {
 		if (interrupt) _spEventQueue_interrupt(internal->queue, from);
@@ -823,18 +823,8 @@ spTrackEntry* spAnimationState_addAnimation (spAnimationState* self, int trackIn
 		_spEventQueue_drain(internal->queue);
 	} else {
 		last->next = entry;
-		if (delay <= 0) {
-			float duration = last->animationEnd - last->animationStart;
-			if (duration != 0) {
-				if (last->loop) {
-					delay += duration * (1 + (int) (last->trackTime / duration));
-				} else {
-					delay += MAX(duration, last->trackTime);
-				}
-				delay -= spAnimationStateData_getMix(self->data, last->animation, animation);
-			} else
-				delay = last->trackTime;
-		}
+		entry->previous = last;
+		if (delay <= 0) delay += spTrackEntry_getTrackComplete(last) - entry->mixDuration;
 	}
 
 	entry->delay = delay;
@@ -850,10 +840,10 @@ spTrackEntry* spAnimationState_setEmptyAnimation(spAnimationState* self, int tra
 
 spTrackEntry* spAnimationState_addEmptyAnimation(spAnimationState* self, int trackIndex, float mixDuration, float delay) {
 	spTrackEntry* entry;
-	if (delay <= 0) delay -= mixDuration;
-	entry = spAnimationState_addAnimation(self, trackIndex, SP_EMPTY_ANIMATION, 0, delay);
+	entry = spAnimationState_addAnimation(self, trackIndex, SP_EMPTY_ANIMATION, 0, delay <= 0 ? 1 : delay);
 	entry->mixDuration = mixDuration;
 	entry->trackEnd = mixDuration;
+	if (delay <= 0 && entry->previous != NULL) entry->delay = spTrackEntry_getTrackComplete(entry->previous) - entry->mixDuration;
 	return entry;
 }
 
@@ -888,6 +878,9 @@ spTrackEntry* _spAnimationState_trackEntry (spAnimationState* self, int trackInd
 	entry->animation = animation;
 	entry->loop = loop;
 	entry->holdPrevious = 0;
+	entry->reverse = 0;
+	entry->previous = 0;
+	entry->next = 0;
 
 	entry->eventThreshold = 0;
 	entry->attachmentThreshold = 0;
@@ -961,15 +954,15 @@ float* _spAnimationState_resizeTimelinesRotation(spTrackEntry* entry, int newSiz
 void _spAnimationState_ensureCapacityPropertyIDs(spAnimationState* self, int capacity) {
 	_spAnimationState* internal = SUB_CAST(_spAnimationState, self);
 	if (internal->propertyIDsCapacity < capacity) {
-		int *newPropertyIDs = CALLOC(int, capacity << 1);
-		memcpy(newPropertyIDs, internal->propertyIDs, sizeof(int) * internal->propertyIDsCount);
+		spPropertyId *newPropertyIDs = CALLOC(spPropertyId, capacity << 1);
+		memcpy(newPropertyIDs, internal->propertyIDs, sizeof(spPropertyId) * internal->propertyIDsCount);
 		FREE(internal->propertyIDs);
 		internal->propertyIDs = newPropertyIDs;
 		internal->propertyIDsCapacity = capacity << 1;
 	}
 }
 
-int _spAnimationState_addPropertyID(spAnimationState* self, int id) {
+int _spAnimationState_addPropertyID(spAnimationState* self, spPropertyId id) {
 	int i, n;
 	_spAnimationState* internal = SUB_CAST(_spAnimationState, self);
 
@@ -983,6 +976,18 @@ int _spAnimationState_addPropertyID(spAnimationState* self, int id) {
 	return 1;
 }
 
+int _spAnimationState_addPropertyIDs(spAnimationState* self, spPropertyId *ids, int numIds) {
+	int i, n;
+	_spAnimationState* internal = SUB_CAST(_spAnimationState, self);
+	int oldSize = internal->propertyIDsCount;
+
+	for (i = 0, n = numIds; i < n; i++) {
+		_spAnimationState_addPropertyID(self, ids[i]);
+	}
+
+	return internal->propertyIDsCount != oldSize;
+}
+
 spTrackEntry* spAnimationState_getCurrent (spAnimationState* self, int trackIndex) {
 	if (trackIndex >= self->tracksCount) return 0;
 	return self->tracks[trackIndex];
@@ -1002,12 +1007,13 @@ 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;
+float spTrackEntry_getTrackComplete(spTrackEntry* entry) {
+	float duration = entry->animationEnd - entry->animationStart;
+	if (duration != 0) {
+		if (entry->loop) return duration * (1 + (int)(entry->trackTime / duration)); /* Completion of next loop. */
+		if (entry->trackTime < duration) return duration; /* Before duration. */
+	}
+	return entry->trackTime; /* Next update. */
 }
 
 void _spTrackEntry_computeHold(spTrackEntry* entry, spAnimationState* state) {
@@ -1020,16 +1026,17 @@ void _spTrackEntry_computeHold(spTrackEntry* entry, spAnimationState* state) {
 	int i;
 
 	to = entry->mixingTo;
-	timelines = entry->animation->timelines;
-	timelinesCount = entry->animation->timelinesCount;
+	timelines = entry->animation->timelines->items;
+	timelinesCount = entry->animation->timelines->size;
 	timelineMode = spIntArray_setSize(entry->timelineMode, timelinesCount)->items;
 	spTrackEntryArray_clear(entry->timelineHoldMix);
 	timelineHoldMix = spTrackEntryArray_setSize(entry->timelineHoldMix, timelinesCount)->items;
 
 	if (to != 0 && to->holdPrevious) {
 		for (i = 0; i < timelinesCount; i++) {
-			int id = spTimeline_getPropertyId(timelines[i]);
-			timelineMode[i] = _spAnimationState_addPropertyID(state, id) ? HOLD_FIRST : HOLD_SUBSEQUENT;
+			spPropertyId* ids = timelines[i]->propertyIds;
+			int numIds = timelines[i]->propertyIdsCount;
+			timelineMode[i] = _spAnimationState_addPropertyIDs(state, ids, numIds) ? HOLD_FIRST : HOLD_SUBSEQUENT;
 		}
 		return;
 	}
@@ -1038,15 +1045,16 @@ void _spTrackEntry_computeHold(spTrackEntry* entry, spAnimationState* state) {
 	continue_outer:
 	for (; i < timelinesCount; i++) {
 		spTimeline* timeline = timelines[i];
-		int id = spTimeline_getPropertyId(timeline);
-		if (!_spAnimationState_addPropertyID(state, id))
+		spPropertyId *ids = timeline->propertyIds;
+		int numIds = timeline->propertyIdsCount;
+		if (!_spAnimationState_addPropertyIDs(state, ids, numIds))
 			timelineMode[i] = SUBSEQUENT;
-		else if (to == 0 || timeline->type == SP_TIMELINE_ATTACHMENT || timeline->type == SP_TIMELINE_DRAWORDER ||
-				timeline->type == SP_TIMELINE_EVENT || !_spTrackEntry_hasTimeline(to, id)) {
+		else if (to == 0 || timeline->propertyIds[0] == SP_PROPERTY_ATTACHMENT || timeline->propertyIds[0] == SP_PROPERTY_DRAWORDER ||
+				timeline->propertyIds[0] == SP_PROPERTY_EVENT || !spAnimation_hasTimeline(to->animation, ids, numIds)) {
 			timelineMode[i] = FIRST;
 		} else {
 			for (next = to->mixingTo; next != 0; next = next->mixingTo) {
-				if (_spTrackEntry_hasTimeline(next, id)) continue;
+				if (spAnimation_hasTimeline(next->animation, ids, numIds)) continue;
 				if (next->mixDuration > 0) {
 					timelineMode[i] = HOLD_MIX;
 					timelineHoldMix[i] = next;