From e5d3d380c7c6bf28352caebf22ca482314d32195 Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Sat, 27 Sep 2014 01:02:57 +0200 Subject: [PATCH] Fixed AttachmentTimeline from missing first key. http://esotericsoftware.com/forum/viewtopic.php?p=16600#p16600 --- .../src/spine/animation/AttachmentTimeline.as | 15 +-- spine-c/src/spine/Animation.c | 2 +- spine-csharp/src/Animation.cs | 2 +- .../com/esotericsoftware/spine/Animation.java | 8 +- .../spine/AnimationState.java | 2 +- .../spine/AttachmentTimelineTests.java | 101 ++++++++++++++++++ .../spine/EventTimelineTests.java | 2 +- 7 files changed, 117 insertions(+), 15 deletions(-) create mode 100644 spine-libgdx/test/com/esotericsoftware/spine/AttachmentTimelineTests.java diff --git a/spine-as3/spine-as3/src/spine/animation/AttachmentTimeline.as b/spine-as3/spine-as3/src/spine/animation/AttachmentTimeline.as index 56c96a844..bcc807b0c 100644 --- a/spine-as3/spine-as3/src/spine/animation/AttachmentTimeline.as +++ b/spine-as3/spine-as3/src/spine/animation/AttachmentTimeline.as @@ -53,14 +53,15 @@ public class AttachmentTimeline implements Timeline { } public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector., alpha:Number) : void { - if (time < frames[0]) - return; // Time is before first frame. + var frames:Vector. = this.frames; + if (time < frames[0]) { + if (lastTime > time) apply(skeleton, lastTime, int.MAX_VALUE, null, 0); + return; + } else if (lastTime > time) // + lastTime = -1; - var frameIndex:int; - if (time >= frames[int(frames.length - 1)]) // Time is after last frame. - frameIndex = frames.length - 1; - else - frameIndex = Animation.binarySearch(frames, time, 1) - 1; + var frameIndex:int = time >= frames[frames.length - 1] ? frames.length - 1 : Animation.binarySearch1(frames, time) - 1; + if (frames[frameIndex] < lastTime) return; var attachmentName:String = attachmentNames[frameIndex]; skeleton.slots[slotIndex].attachment = attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slotIndex, attachmentName); diff --git a/spine-c/src/spine/Animation.c b/spine-c/src/spine/Animation.c index 9b3714e81..755da5738 100644 --- a/spine-c/src/spine/Animation.c +++ b/spine-c/src/spine/Animation.c @@ -479,7 +479,7 @@ void _spAttachmentTimeline_apply (const spTimeline* timeline, spSkeleton* skelet frameIndex = time >= self->frames[self->framesCount - 1] ? self->framesCount - 1 : binarySearch1(self->frames, self->framesCount, time) - 1; - if (self->frames[frameIndex] <= lastTime) return; + if (self->frames[frameIndex] < lastTime) return; attachmentName = self->attachmentNames[frameIndex]; spSlot_setAttachment(skeleton->slots[self->slotIndex], diff --git a/spine-csharp/src/Animation.cs b/spine-csharp/src/Animation.cs index d60878da6..cb824f0df 100644 --- a/spine-csharp/src/Animation.cs +++ b/spine-csharp/src/Animation.cs @@ -444,7 +444,7 @@ namespace Spine { lastTime = -1; int frameIndex = time >= frames[frames.Length - 1] ? frames.Length - 1 : Animation.binarySearch(frames, time) - 1; - if (frames[frameIndex] <= lastTime) return; + if (frames[frameIndex] < lastTime) return; String attachmentName = attachmentNames[frameIndex]; skeleton.slots[slotIndex].Attachment = diff --git a/spine-libgdx/src/com/esotericsoftware/spine/Animation.java b/spine-libgdx/src/com/esotericsoftware/spine/Animation.java index 918917ede..ae330ca46 100644 --- a/spine-libgdx/src/com/esotericsoftware/spine/Animation.java +++ b/spine-libgdx/src/com/esotericsoftware/spine/Animation.java @@ -86,8 +86,8 @@ public class Animation { if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); if (loop && duration != 0) { - lastTime %= duration; time %= duration; + lastTime %= duration; } Array timelines = this.timelines; @@ -468,8 +468,8 @@ public class Animation { static public class AttachmentTimeline implements Timeline { int slotIndex; - private final float[] frames; // time, ... - private final String[] attachmentNames; + final float[] frames; // time, ... + final String[] attachmentNames; public AttachmentTimeline (int frameCount) { frames = new float[frameCount]; @@ -511,7 +511,7 @@ public class Animation { lastTime = -1; int frameIndex = (time >= frames[frames.length - 1] ? frames.length : binarySearch(frames, time)) - 1; - if (frames[frameIndex] <= lastTime) return; + if (frames[frameIndex] < lastTime) return; String attachmentName = attachmentNames[frameIndex]; skeleton.slots.get(slotIndex).setAttachment( diff --git a/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java b/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java index e29e85306..a298b2982 100644 --- a/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java +++ b/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java @@ -304,7 +304,7 @@ public class AnimationState { TrackEntry next, previous; Animation animation; boolean loop; - float delay, time, lastTime, endTime, timeScale = 1; + float delay, time, lastTime = -1, endTime, timeScale = 1; float mixTime, mixDuration; AnimationStateListener listener; float mix = 1; diff --git a/spine-libgdx/test/com/esotericsoftware/spine/AttachmentTimelineTests.java b/spine-libgdx/test/com/esotericsoftware/spine/AttachmentTimelineTests.java new file mode 100644 index 000000000..2d98b20aa --- /dev/null +++ b/spine-libgdx/test/com/esotericsoftware/spine/AttachmentTimelineTests.java @@ -0,0 +1,101 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +package com.esotericsoftware.spine; + +import com.badlogic.gdx.utils.Array; +import com.esotericsoftware.spine.Animation.AttachmentTimeline; +import com.esotericsoftware.spine.Animation.Timeline; +import com.esotericsoftware.spine.attachments.Attachment; + +/** Unit tests for {@link AttachmentTimeline}. */ +public class AttachmentTimelineTests { + private final SkeletonData skeletonData; + private final Skeleton skeleton; + private Slot slot; + private AnimationState state; + + public AttachmentTimelineTests () { + skeletonData = new SkeletonData(); + + BoneData boneData = new BoneData("bone", null); + skeletonData.getBones().add(boneData); + + skeletonData.getSlots().add(new SlotData("slot", boneData)); + + Attachment attachment1 = new Attachment("attachment1") {}; + Attachment attachment2 = new Attachment("attachment2") {}; + + Skin skin = new Skin("skin"); + skin.addAttachment(0, "attachment1", attachment1); + skin.addAttachment(0, "attachment2", attachment2); + skeletonData.setDefaultSkin(skin); + + skeleton = new Skeleton(skeletonData); + slot = skeleton.findSlot("slot"); + + AttachmentTimeline timeline = new AttachmentTimeline(2); + timeline.setFrame(0, 0, "attachment1"); + timeline.setFrame(1, 0.5f, "attachment2"); + + Animation animation = new Animation("animation", Array.with((Timeline)timeline), 1); + animation.setDuration(1); + + state = new AnimationState(new AnimationStateData(skeletonData)); + state.setAnimation(0, animation, true); + + test(0, attachment1); + test(0, attachment1); + test(0.25f, attachment1); + test(0f, attachment1); + test(0.25f, attachment2); + test(0.25f, attachment2); + + System.out.println("AttachmentTimeline tests passed."); + } + + private void test (float delta, Attachment attachment) { + state.update(delta); + state.apply(skeleton); + if (slot.getAttachment() != attachment) + throw new FailException("Wrong attachment: " + slot.getAttachment() + " != " + attachment); + + } + + static class FailException extends RuntimeException { + public FailException (String message) { + super(message); + } + } + + static public void main (String[] args) throws Exception { + new AttachmentTimelineTests(); + } +} diff --git a/spine-libgdx/test/com/esotericsoftware/spine/EventTimelineTests.java b/spine-libgdx/test/com/esotericsoftware/spine/EventTimelineTests.java index 6f667eca1..1509193db 100644 --- a/spine-libgdx/test/com/esotericsoftware/spine/EventTimelineTests.java +++ b/spine-libgdx/test/com/esotericsoftware/spine/EventTimelineTests.java @@ -72,7 +72,7 @@ public class EventTimelineTests { test(0.1f, 0.2f, 0.3f, 0.4f); test(1, 2, 3, 4, 5, 6, 6, 7, 7, 8, 9, 10, 11, 11.01f, 12, 12, 12, 12); - System.out.println("All tests passed."); + System.out.println("EventTimeline tests passed."); } private void test (float... frames) {