Browse Source

[c] Port AnimationState deform mixing while attachment timelines mix out.

badlogic 5 years ago
parent
commit
7732838d6f

+ 4 - 1
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
 };

+ 3 - 1
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) {

+ 10 - 8
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;
 	}
 

+ 85 - 49
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;
-		}
-	}
-}

+ 2 - 1
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);