From 280024a6850550469e8df15a96de579f15b13ccc Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Mon, 22 Aug 2016 14:43:33 +0200 Subject: [PATCH] Added mixingOut parameter to Timeline#apply so timelines know which direction mixing is happening. See ScaleTimeline which uses this to know which scale sign to use. --- .../esotericsoftware/spine/BonePlotting.java | 2 +- .../esotericsoftware/spine/Box2DExample.java | 2 +- .../spine/EventTimelineTests.java | 8 +- .../com/esotericsoftware/spine/MixTest.java | 15 +- .../esotericsoftware/spine/NormalMapTest.java | 2 +- .../com/esotericsoftware/spine/Animation.java | 137 +++++++++++------- .../spine/AnimationState.java | 21 +-- .../spine/SkeletonViewer.java | 16 +- 8 files changed, 123 insertions(+), 80 deletions(-) diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/BonePlotting.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/BonePlotting.java index d6a56e548..ce059387e 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/BonePlotting.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/BonePlotting.java @@ -65,7 +65,7 @@ public class BonePlotting { for (Animation animation : skeletonData.getAnimations()) { float time = 0; while (time < animation.getDuration()) { - animation.apply(skeleton, time, time, false, null, 1, false); + animation.apply(skeleton, time, time, false, null, 1, false, false); skeleton.updateWorldTransform(); System.out .println(animation.getName() + "," + bone.getWorldX() + "," + bone.getWorldY() + "," + bone.getWorldRotationX()); diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/Box2DExample.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/Box2DExample.java index 22254da97..30b8c9163 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/Box2DExample.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/Box2DExample.java @@ -145,7 +145,7 @@ public class Box2DExample extends ApplicationAdapter { batch.setTransformMatrix(camera.view); batch.begin(); - animation.apply(skeleton, time, time, true, events, 1, false); + animation.apply(skeleton, time, time, true, events, 1, false, false); skeleton.x += 8 * delta; skeleton.updateWorldTransform(); skeletonRenderer.draw(batch, skeleton); diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/EventTimelineTests.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/EventTimelineTests.java index de61efff3..251ffe7ed 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/EventTimelineTests.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/EventTimelineTests.java @@ -177,7 +177,7 @@ public class EventTimelineTests { int beforeCount = firedEvents.size; Array original = new Array(firedEvents); - timeline.apply(skeleton, lastTimeLooped, timeLooped, firedEvents, 1, false); + timeline.apply(skeleton, lastTimeLooped, timeLooped, firedEvents, 1, false, false); while (beforeCount < firedEvents.size) { char fired = firedEvents.get(beforeCount).getData().getName().charAt(0); @@ -186,7 +186,7 @@ public class EventTimelineTests { } else { if (firedEvents.size > eventsCount) { if (print) System.out.println(lastTimeLooped + "->" + timeLooped + ": " + fired + " == ?"); - timeline.apply(skeleton, lastTimeLooped, timeLooped, original, 1, false); + timeline.apply(skeleton, lastTimeLooped, timeLooped, original, 1, false, false); fail("Too many events fired."); } } @@ -194,7 +194,7 @@ public class EventTimelineTests { System.out.println(lastTimeLooped + "->" + timeLooped + ": " + fired + " == " + events[eventIndex]); } if (fired != events[eventIndex]) { - timeline.apply(skeleton, lastTimeLooped, timeLooped, original, 1, false); + timeline.apply(skeleton, lastTimeLooped, timeLooped, original, 1, false, false); fail("Wrong event fired."); } eventIndex++; @@ -206,7 +206,7 @@ public class EventTimelineTests { i++; } if (firedEvents.size < eventsCount) { - timeline.apply(skeleton, lastTimeLooped, timeLooped, firedEvents, 1, false); + timeline.apply(skeleton, lastTimeLooped, timeLooped, firedEvents, 1, false, false); if (print) System.out.println(firedEvents); fail("Event not fired: " + events[eventIndex] + ", " + frames[eventIndex]); } diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/MixTest.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/MixTest.java index db0d80c9f..5c5269ffa 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/MixTest.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/MixTest.java @@ -104,22 +104,21 @@ public class MixTest extends ApplicationAdapter { skeleton.setX(-50); } else if (time > beforeJump + jump) { // just walk after jump - walkAnimation.apply(skeleton, time, time, true, events, 1, false); + walkAnimation.apply(skeleton, time, time, true, events, 1, false, false); } else if (time > blendOutStart) { // blend out jump - walkAnimation.apply(skeleton, time, time, true, events, 1, false); - jumpAnimation.apply(skeleton, time - beforeJump, time - beforeJump, false, events, 1 - (time - blendOutStart) / blendOut, - false); + walkAnimation.apply(skeleton, time, time, true, events, 1, false, false); + jumpAnimation.apply(skeleton, time - beforeJump, time - beforeJump, false, events, 1 - (time - blendOutStart) / blendOut, false, false); } else if (time > beforeJump + blendIn) { // just jump - jumpAnimation.apply(skeleton, time - beforeJump, time - beforeJump, false, events, 1, false); + jumpAnimation.apply(skeleton, time - beforeJump, time - beforeJump, false, events, 1, false, false); } else if (time > beforeJump) { // blend in jump - walkAnimation.apply(skeleton, time, time, true, events, 1, false); - jumpAnimation.apply(skeleton, time - beforeJump, time - beforeJump, false, events, (time - beforeJump) / blendIn, false); + walkAnimation.apply(skeleton, time, time, true, events, 1, false, false); + jumpAnimation.apply(skeleton, time - beforeJump, time - beforeJump, false, events, (time - beforeJump) / blendIn, false, false); } else { // just walk before jump - walkAnimation.apply(skeleton, time, time, true, events, 1, false); + walkAnimation.apply(skeleton, time, time, true, events, 1, false, false); } skeleton.updateWorldTransform(); diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/NormalMapTest.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/NormalMapTest.java index 6986e2876..b85e8b04a 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/NormalMapTest.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/NormalMapTest.java @@ -131,7 +131,7 @@ public class NormalMapTest extends ApplicationAdapter { public void render () { float lastTime = time; time += Gdx.graphics.getDeltaTime(); - if (animation != null) animation.apply(skeleton, lastTime, time, true, null, 1, false); + if (animation != null) animation.apply(skeleton, lastTime, time, true, null, 1, false, false); skeleton.updateWorldTransform(); skeleton.update(Gdx.graphics.getDeltaTime()); diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java index e3d257694..c6a467325 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java @@ -67,11 +67,13 @@ public class Animation { /** Poses the skeleton at the specified time for this animation mixed with the current or setup pose. * @param lastTime The last time the animation was applied. * @param events Any triggered events are added. May be null. - * @param alpha The amount of this animation that affects the current pose. - * @param setupPose If true, the animation is mixed with the setup pose, else it is mixed with the current pose. Pass true when - * alpha is 1. */ + * @param alpha The percentage between this animation's pose and the current pose. + * @param setupPose If true, the animation is mixed with the setup pose, else it is mixed with the current pose. Passing true + * when alpha is 1 is slightly more efficient. + * @param mixingOut True when mixing over time toward the setup or current pose, false when mixing toward the keyed pose. + * Irrelevant when alpha is 1. */ public void apply (Skeleton skeleton, float lastTime, float time, boolean loop, Array events, float alpha, - boolean setupPose) { + boolean setupPose, boolean mixingOut) { if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); if (loop && duration != 0) { @@ -81,7 +83,7 @@ public class Animation { Array timelines = this.timelines; for (int i = 0, n = timelines.size; i < n; i++) - timelines.get(i).apply(skeleton, lastTime, time, events, alpha, setupPose); + timelines.get(i).apply(skeleton, lastTime, time, events, alpha, setupPose, false); } public String getName () { @@ -135,9 +137,12 @@ public class Animation { static public interface Timeline { /** Sets the value(s) for the specified time. * @param events May be null to not collect fired events. - * @param setupPose If true, the timeline is mixed with the setup pose, else it is mixed with the current pose. Pass true - * when alpha is 1. */ - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose); + * @param setupPose If true, the timeline is mixed with the setup pose, else it is mixed with the current pose. Passing true + * when alpha is 1 is slightly more efficient. + * @param mixingOut True when mixing over time toward the setup or current pose, false when mixing toward the keyed pose. + * Irrelevant when alpha is 1. */ + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose, + boolean mixingOut); public int getId (); } @@ -274,9 +279,11 @@ public class Animation { frames[frameIndex + ROTATION] = degrees; } - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose) { + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose, + boolean mixingOut) { float[] frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + Bone bone = skeleton.bones.get(boneIndex); if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. @@ -297,13 +304,13 @@ public class Animation { float percent = getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); float amount = frames[frame + ROTATION] - prevRotation; - amount = amount - (16384 - (int)(16384.499999999996 - amount / 360)) * 360; + amount -= (16384 - (int)(16384.499999999996 - amount / 360)) * 360; + amount = prevRotation + amount * percent; if (setupPose) { - amount = prevRotation + amount * percent; - amount = amount - (16384 - (int)(16384.499999999996 - amount / 360)) * 360; + amount -= (16384 - (int)(16384.499999999996 - amount / 360)) * 360; bone.rotation = bone.data.rotation + amount * alpha; } else { - amount = bone.data.rotation + (prevRotation + amount * percent) - bone.rotation; + amount = bone.data.rotation + amount - bone.rotation; amount -= (16384 - (int)(16384.499999999996 - amount / 360)) * 360; bone.rotation += amount * alpha; } @@ -348,36 +355,35 @@ public class Animation { frames[frameIndex + Y] = y; } - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose) { + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose, + boolean mixingOut) { float[] frames = this.frames; if (time < frames[0]) return; // Time is before first frame. Bone bone = skeleton.bones.get(boneIndex); + float x, y; if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. - if (setupPose) { - bone.x = bone.data.x + frames[frames.length + PREV_X] * alpha; - bone.y = bone.data.y + frames[frames.length + PREV_Y] * alpha; - } else { - bone.x += (bone.data.x + frames[frames.length + PREV_X] - bone.x) * alpha; - bone.y += (bone.data.y + frames[frames.length + PREV_Y] - bone.y) * alpha; - } - return; - } - - // Interpolate between the previous frame and the current frame. - int frame = binarySearch(frames, time, ENTRIES); - float prevX = frames[frame + PREV_X]; - float prevY = frames[frame + PREV_Y]; - float frameTime = frames[frame]; - float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); - - if (setupPose) { - bone.x = bone.data.x + (prevX + (frames[frame + X] - prevX) * percent) * alpha; - bone.y = bone.data.y + (prevY + (frames[frame + Y] - prevY) * percent) * alpha; + x = frames[frames.length + PREV_X]; + y = frames[frames.length + PREV_Y]; } else { - bone.x += (bone.data.x + prevX + (frames[frame + X] - prevX) * percent - bone.x) * alpha; - bone.y += (bone.data.y + prevY + (frames[frame + Y] - prevY) * percent - bone.y) * alpha; + // Interpolate between the previous frame and the current frame. + int frame = binarySearch(frames, time, ENTRIES); + float prevX = frames[frame + PREV_X]; + float prevY = frames[frame + PREV_Y]; + float frameTime = frames[frame]; + float percent = getCurvePercent(frame / ENTRIES - 1, + 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime)); + + x = prevX + (frames[frame + X] - prevX) * percent; + y = prevY + (frames[frame + Y] - prevY) * percent; + } + if (setupPose) { + bone.x = bone.data.x + x * alpha; + bone.y = bone.data.y + y * alpha; + } else { + bone.x += (bone.data.x + x - bone.x) * alpha; + bone.y += (bone.data.y + y - bone.y) * alpha; } } } @@ -391,11 +397,13 @@ public class Animation { return (TimelineType.scale.ordinal() << 24) + boneIndex; } - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose) { + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose, + boolean mixingOut) { float[] frames = this.frames; if (time < frames[0]) return; // Time is before first frame. Bone bone = skeleton.bones.get(boneIndex); + float x, y; if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. x = frames[frames.length + PREV_X]; @@ -418,7 +426,22 @@ public class Animation { bone.scaleX = x; bone.scaleY = y; } else { - float bx = Math.abs(bone.scaleX) * Math.signum(x), by = Math.abs(bone.scaleY) * Math.signum(y); + float bx, by; + if (setupPose) { + bx = bone.data.scaleX; + by = bone.data.scaleY; + } else { + bx = bone.scaleX; + by = bone.scaleY; + } + // Mixing out uses sign of setup or current pose, else use sign of key. + if (mixingOut) { + x = Math.abs(x) * Math.signum(bx); + y = Math.abs(y) * Math.signum(by); + } else { + bx = Math.abs(bx) * Math.signum(x); + by = Math.abs(by) * Math.signum(y); + } bone.scaleX = bx + (x - bx) * alpha; bone.scaleY = by + (y - by) * alpha; } @@ -434,7 +457,8 @@ public class Animation { return (TimelineType.shear.ordinal() << 24) + boneIndex; } - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose) { + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose, + boolean mixingOut) { float[] frames = this.frames; if (time < frames[0]) return; // Time is before first frame. @@ -497,7 +521,8 @@ public class Animation { frames[frameIndex + A] = a; } - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose) { + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose, + boolean mixingOut) { float[] frames = this.frames; if (time < frames[0]) return; // Time is before first frame. @@ -573,7 +598,8 @@ public class Animation { attachmentNames[frameIndex] = attachmentName; } - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose) { + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose, + boolean mixingOut) { float[] frames = this.frames; if (time < frames[0]) return; // Time is before first frame. @@ -636,8 +662,8 @@ public class Animation { frameVertices[frameIndex] = vertices; } - public void apply (Skeleton skeleton, float lastTime, float time, Array firedEvents, float alpha, - boolean setupPose) { + public void apply (Skeleton skeleton, float lastTime, float time, Array firedEvents, float alpha, boolean setupPose, + boolean mixingOut) { Slot slot = skeleton.slots.get(slotIndex); Attachment slotAttachment = slot.attachment; if (!(slotAttachment instanceof VertexAttachment) || !((VertexAttachment)slotAttachment).applyDeform(attachment)) return; @@ -715,14 +741,14 @@ public class Animation { } /** Fires events for frames > lastTime and <= time. */ - public void apply (Skeleton skeleton, float lastTime, float time, Array firedEvents, float alpha, - boolean setupPose) { + public void apply (Skeleton skeleton, float lastTime, float time, Array firedEvents, float alpha, boolean setupPose, + boolean mixingOut) { if (firedEvents == null) return; float[] frames = this.frames; int frameCount = frames.length; if (lastTime > time) { // Fire events after last time for looped animations. - apply(skeleton, lastTime, Integer.MAX_VALUE, firedEvents, alpha, setupPose); + apply(skeleton, lastTime, Integer.MAX_VALUE, firedEvents, alpha, setupPose, mixingOut); lastTime = -1f; } else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame. return; @@ -776,8 +802,8 @@ public class Animation { drawOrders[frameIndex] = drawOrder; } - public void apply (Skeleton skeleton, float lastTime, float time, Array firedEvents, float alpha, - boolean setupPose) { + public void apply (Skeleton skeleton, float lastTime, float time, Array firedEvents, float alpha, boolean setupPose, + boolean mixingOut) { float[] frames = this.frames; if (time < frames[0]) return; // Time is before first frame. @@ -837,7 +863,8 @@ public class Animation { frames[frameIndex + BEND_DIRECTION] = bendDirection; } - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose) { + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose, + boolean mixingOut) { float[] frames = this.frames; if (time < frames[0]) return; // Time is before first frame. @@ -900,7 +927,8 @@ public class Animation { frames[frameIndex + SHEAR] = shearMix; } - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose) { + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose, + boolean mixingOut) { float[] frames = this.frames; if (time < frames[0]) return; // Time is before first frame. @@ -970,7 +998,8 @@ public class Animation { frames[frameIndex + VALUE] = value; } - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose) { + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose, + boolean mixingOut) { float[] frames = this.frames; if (time < frames[0]) return; // Time is before first frame. @@ -1001,7 +1030,8 @@ public class Animation { return (TimelineType.pathConstraintSpacing.ordinal() << 24) + pathConstraintIndex; } - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose) { + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose, + boolean mixingOut) { float[] frames = this.frames; if (time < frames[0]) return; // Time is before first frame. @@ -1062,7 +1092,8 @@ public class Animation { frames[frameIndex + TRANSLATE] = translateMix; } - public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose) { + public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, boolean setupPose, + boolean mixingOut) { float[] frames = this.frames; if (time < frames[0]) return; // Time is before first frame. diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java index eba5800df..c6a6c7bfc 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/AnimationState.java @@ -122,11 +122,12 @@ public class AnimationState { float mix = current.alpha; if (current.mixingFrom != null) { mix *= current.mixTime / current.mixDuration; + if (mix > 1) mix = 1; applyMixingFrom(current.mixingFrom, skeleton, mix); - if (mix >= 1) { - mix = 1; + if (mix == 1) { queue.end(current.mixingFrom); current.mixingFrom = null; + updateSetupPose(); } } @@ -134,7 +135,7 @@ public class AnimationState { Array timelines = current.animation.timelines; BooleanArray setupPose = current.setupPose; for (int ii = 0, n = timelines.size; ii < n; ii++) - timelines.get(ii).apply(skeleton, animationLast, animationTime, events, mix, setupPose.get(ii)); + timelines.get(ii).apply(skeleton, animationLast, animationTime, events, mix, setupPose.get(ii), false); queueEvents(current, animationTime); current.animationLast = animationTime; current.trackLast = current.trackTime; @@ -155,9 +156,9 @@ public class AnimationState { for (int i = 0, n = timelines.size; i < n; i++) { Timeline timeline = timelines.get(i); if (setupPose.get(i)) - timeline.apply(skeleton, animationLast, animationTime, events, alphaMix, true); + timeline.apply(skeleton, animationLast, animationTime, events, alphaMix, true, true); else - timeline.apply(skeleton, animationLast, animationTime, events, alphaFull, false); + timeline.apply(skeleton, animationLast, animationTime, events, alphaFull, false, false); } } else { for (int i = 0, n = timelines.size; i < n; i++) { @@ -165,9 +166,9 @@ public class AnimationState { if (!attachments && timeline instanceof AttachmentTimeline) continue; if (!drawOrder && timeline instanceof DrawOrderTimeline) continue; if (setupPose.get(i)) - timeline.apply(skeleton, animationLast, animationTime, events, alphaMix, true); + timeline.apply(skeleton, animationLast, animationTime, events, alphaMix, true, true); else - timeline.apply(skeleton, animationLast, animationTime, events, alphaFull, false); + timeline.apply(skeleton, animationLast, animationTime, events, alphaFull, false, false); } } @@ -282,9 +283,10 @@ public class AnimationState { updateSetupPose(entry); } else updateFirstSetupPose(entry); + i++; break; } - for (i++; i < n; i++) { + for (; i < n; i++) { TrackEntry entry = tracks.get(i); if (entry == null) continue; if (entry.mixingFrom != null) updateSetupPose(entry.mixingFrom); @@ -678,7 +680,8 @@ public class AnimationState { return trackTime >= animationEnd - animationStart; } - /** Seconds from 0 to the mix duration when mixing from the previous animation to this animation. */ + /** Seconds from 0 to the mix duration when mixing from the previous animation to this animation. May be slightly more than + * {@link #getMixDuration()}. */ public float getMixTime () { return mixTime; } diff --git a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java index 255f1ade7..3c8d0528a 100644 --- a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java +++ b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java @@ -205,12 +205,16 @@ public class SkeletonViewer extends ApplicationAdapter { // Configure skeleton from UI. if (ui.skinList.getSelected() != null) skeleton.setSkin(ui.skinList.getSelected()); - if (ui.animationList.getSelected() != null) - state.setAnimation(0, ui.animationList.getSelected(), ui.loopCheckbox.isChecked()); + if (ui.animationList.getSelected() != null) setAnimation(); if (reload) ui.toast("Reloaded."); } + void setAnimation () { + TrackEntry entry = state.setAnimation(0, ui.animationList.getSelected(), ui.loopCheckbox.isChecked()); + entry.setTrackEnd(Integer.MAX_VALUE); + } + public void render () { Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); @@ -486,11 +490,17 @@ public class SkeletonViewer extends ApplicationAdapter { if (name == null) state.clearTrack(0); else - state.setAnimation(0, name, loopCheckbox.isChecked()); + setAnimation(); } } }); + loopCheckbox.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + setAnimation(); + } + }); + skinList.addListener(new ChangeListener() { public void changed (ChangeEvent event, Actor actor) { if (skeleton != null) {