From 18acce0354d6fe633c48b6e217dd314544692b16 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Tue, 19 Mar 2019 15:40:06 +0100 Subject: [PATCH] [csharp] Ported AnimationState and Animation changes of commit a321aa7. See #1303. --- spine-csharp/src/AnimationState.cs | 51 ++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/spine-csharp/src/AnimationState.cs b/spine-csharp/src/AnimationState.cs index 5f7f5e2d3..4dc38e3ba 100644 --- a/spine-csharp/src/AnimationState.cs +++ b/spine-csharp/src/AnimationState.cs @@ -67,6 +67,12 @@ namespace Spine { /// (which affects B and C). Without using D to mix out, A would be applied fully until mixing completes, then snap into /// place. internal const int HoldMix = 3; + /// 1) An attachment timeline in a subsequent track entry sets the attachment for the same slot as this attachment + /// timeline. + /// Result: This attachment timeline will not use MixDirection.out, which would otherwise show the setup mode attachment (or + /// none if not visible in setup mode). This allows deform timelines to be applied for the subsequent entry to mix from, rather + /// than mixing from the setup pose. + internal const int NotLast = 4; protected AnimationStateData data; private readonly ExposedList tracks = new ExposedList(); @@ -234,7 +240,7 @@ namespace Spine { for (int ii = 0; ii < timelineCount; ii++) { Timeline timeline = timelinesItems[ii]; - MixBlend timelineBlend = timelineMode[ii] == AnimationState.Subsequent ? blend : MixBlend.Setup; + MixBlend timelineBlend = (timelineMode[ii] & AnimationState.NotLast - 1) == AnimationState.Subsequent ? blend : MixBlend.Setup; var rotateTimeline = timeline as RotateTimeline; if (rotateTimeline != null) ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, @@ -292,7 +298,7 @@ namespace Spine { MixDirection direction = MixDirection.Out; MixBlend timelineBlend; float alpha; - switch (timelineMode[i]) { + switch (timelineMode[i] & AnimationState.NotLast - 1) { case AnimationState.Subsequent: if (!attachments && timeline is AttachmentTimeline) continue; if (!drawOrder && timeline is DrawOrderTimeline) continue; @@ -322,7 +328,7 @@ namespace Spine { } else { if (timelineBlend == MixBlend.Setup) { if (timeline is AttachmentTimeline) { - if (attachments) direction = MixDirection.In; + if (attachments || (timelineMode[i] & AnimationState.NotLast) == AnimationState.NotLast) direction = MixDirection.In; } else if (timeline is DrawOrderTimeline) { if (drawOrder) { direction = MixDirection.In; @@ -716,25 +722,34 @@ namespace Spine { private void AnimationsChanged () { animationsChanged = false; + // Process in the order that animations are applied. propertyIDs.Clear(); var tracksItems = tracks.Items; for (int i = 0, n = tracks.Count; i < n; i++) { TrackEntry entry = tracksItems[i]; if (entry == null) continue; - // Move to last entry, then iterate in reverse (the order animations are applied). - while (entry.mixingFrom != null) + while (entry.mixingFrom != null) // Move to last entry, then iterate in reverse. entry = entry.mixingFrom; do { - if (entry.mixingTo == null || entry.mixBlend != MixBlend.Add) SetTimelineModes(entry); + if (entry.mixingTo == null || entry.mixBlend != MixBlend.Add) ComputeHold(entry); entry = entry.mixingTo; } while (entry != null); + } + // Process in the reverse order that animations are applied. + propertyIDs.Clear(); + for (int i = tracks.Count - 1; i >= 0; i--) { + TrackEntry entry = tracksItems[i]; + do { + ComputeNotLast(entry); + entry = entry.mixingFrom; + } while (entry != null); } } - private void SetTimelineModes (TrackEntry entry) { + private void ComputeHold (TrackEntry entry) { TrackEntry to = entry.mixingTo; var timelines = entry.animation.timelines.Items; int timelinesCount = entry.animation.timelines.Count; @@ -753,12 +768,14 @@ namespace Spine { // outer: for (int i = 0; i < timelinesCount; i++) { - int id = timelines[i].PropertyId; + Timeline timeline = timelines[i]; + int id = timeline.PropertyId; if (!propertyIDs.Add(id)) timelineMode[i] = AnimationState.Subsequent; - else if (to == null || !HasTimeline(to, id)) + else if (to == null || timeline is AttachmentTimeline || timeline is DrawOrderTimeline + || timeline is EventTimeline || !HasTimeline(to, id)) { timelineMode[i] = AnimationState.First; - else { + } else { for (TrackEntry next = to.mixingTo; next != null; next = next.mixingTo) { if (HasTimeline(next, id)) continue; if (next.mixDuration > 0) { @@ -774,6 +791,20 @@ namespace Spine { } } + private void ComputeNotLast (TrackEntry entry) { + var timelines = entry.animation.timelines.Items; + int timelinesCount = entry.animation.timelines.Count; + int[] timelineMode = entry.timelineMode.Items; + var propertyIDs = this.propertyIDs; + + for (int i = 0; i < timelinesCount; i++) { + if (timelines[i] is AttachmentTimeline) { + AttachmentTimeline timeline = (AttachmentTimeline)timelines[i]; + if (!propertyIDs.Add(timeline.slotIndex)) timelineMode[i] |= AnimationState.NotLast; + } + } + } + static bool HasTimeline (TrackEntry entry, int id) { var timelines = entry.animation.timelines.Items; for (int i = 0, n = entry.animation.timelines.Count; i < n; i++)