mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-06 18:56:54 +08:00
Changed Timeline#apply to enum parameters, AnimationState special cases track 0 to apply setup pose before first key.
This commit is contained in:
parent
a8577b78a7
commit
5540b47f21
@ -31,6 +31,8 @@
|
|||||||
package com.esotericsoftware.spine;
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
import com.badlogic.gdx.files.FileHandle;
|
import com.badlogic.gdx.files.FileHandle;
|
||||||
|
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||||
|
import com.esotericsoftware.spine.Animation.MixPose;
|
||||||
import com.esotericsoftware.spine.attachments.AttachmentLoader;
|
import com.esotericsoftware.spine.attachments.AttachmentLoader;
|
||||||
import com.esotericsoftware.spine.attachments.BoundingBoxAttachment;
|
import com.esotericsoftware.spine.attachments.BoundingBoxAttachment;
|
||||||
import com.esotericsoftware.spine.attachments.ClippingAttachment;
|
import com.esotericsoftware.spine.attachments.ClippingAttachment;
|
||||||
@ -74,7 +76,7 @@ public class BonePlotting {
|
|||||||
for (Animation animation : skeletonData.getAnimations()) {
|
for (Animation animation : skeletonData.getAnimations()) {
|
||||||
float time = 0;
|
float time = 0;
|
||||||
while (time < animation.getDuration()) {
|
while (time < animation.getDuration()) {
|
||||||
animation.apply(skeleton, time, time, false, null, 1, false, false);
|
animation.apply(skeleton, time, time, false, null, 1, MixPose.current, MixDirection.in);
|
||||||
skeleton.updateWorldTransform();
|
skeleton.updateWorldTransform();
|
||||||
System.out
|
System.out
|
||||||
.println(animation.getName() + "," + bone.getWorldX() + "," + bone.getWorldY() + "," + bone.getWorldRotationX());
|
.println(animation.getName() + "," + bone.getWorldX() + "," + bone.getWorldY() + "," + bone.getWorldRotationX());
|
||||||
|
|||||||
@ -30,6 +30,8 @@
|
|||||||
|
|
||||||
package com.esotericsoftware.spine;
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||||
|
import com.esotericsoftware.spine.Animation.MixPose;
|
||||||
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
|
import com.esotericsoftware.spine.attachments.AtlasAttachmentLoader;
|
||||||
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
import com.esotericsoftware.spine.attachments.RegionAttachment;
|
||||||
|
|
||||||
@ -144,7 +146,7 @@ public class Box2DExample extends ApplicationAdapter {
|
|||||||
batch.setTransformMatrix(camera.view);
|
batch.setTransformMatrix(camera.view);
|
||||||
batch.begin();
|
batch.begin();
|
||||||
|
|
||||||
animation.apply(skeleton, time, time, true, events, 1, false, false);
|
animation.apply(skeleton, time, time, true, events, 1, MixPose.current, MixDirection.in);
|
||||||
skeleton.x += 8 * delta;
|
skeleton.x += 8 * delta;
|
||||||
skeleton.updateWorldTransform();
|
skeleton.updateWorldTransform();
|
||||||
skeletonRenderer.draw(batch, skeleton);
|
skeletonRenderer.draw(batch, skeleton);
|
||||||
|
|||||||
@ -31,7 +31,8 @@
|
|||||||
package com.esotericsoftware.spine;
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
import com.esotericsoftware.spine.Animation.EventTimeline;
|
import com.esotericsoftware.spine.Animation.EventTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||||
|
import com.esotericsoftware.spine.Animation.MixPose;
|
||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
import com.badlogic.gdx.utils.StringBuilder;
|
import com.badlogic.gdx.utils.StringBuilder;
|
||||||
|
|
||||||
@ -176,7 +177,7 @@ public class EventTimelineTests {
|
|||||||
|
|
||||||
int beforeCount = firedEvents.size;
|
int beforeCount = firedEvents.size;
|
||||||
Array<Event> original = new Array(firedEvents);
|
Array<Event> original = new Array(firedEvents);
|
||||||
timeline.apply(skeleton, lastTimeLooped, timeLooped, firedEvents, 1, false, false);
|
timeline.apply(skeleton, lastTimeLooped, timeLooped, firedEvents, 1, MixPose.current, MixDirection.in);
|
||||||
|
|
||||||
while (beforeCount < firedEvents.size) {
|
while (beforeCount < firedEvents.size) {
|
||||||
char fired = firedEvents.get(beforeCount).getData().getName().charAt(0);
|
char fired = firedEvents.get(beforeCount).getData().getName().charAt(0);
|
||||||
@ -185,7 +186,7 @@ public class EventTimelineTests {
|
|||||||
} else {
|
} else {
|
||||||
if (firedEvents.size > eventsCount) {
|
if (firedEvents.size > eventsCount) {
|
||||||
if (print) System.out.println(lastTimeLooped + "->" + timeLooped + ": " + fired + " == ?");
|
if (print) System.out.println(lastTimeLooped + "->" + timeLooped + ": " + fired + " == ?");
|
||||||
timeline.apply(skeleton, lastTimeLooped, timeLooped, original, 1, false, false);
|
timeline.apply(skeleton, lastTimeLooped, timeLooped, original, 1, MixPose.current, MixDirection.in);
|
||||||
fail("Too many events fired.");
|
fail("Too many events fired.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -193,7 +194,7 @@ public class EventTimelineTests {
|
|||||||
System.out.println(lastTimeLooped + "->" + timeLooped + ": " + fired + " == " + events[eventIndex]);
|
System.out.println(lastTimeLooped + "->" + timeLooped + ": " + fired + " == " + events[eventIndex]);
|
||||||
}
|
}
|
||||||
if (fired != events[eventIndex]) {
|
if (fired != events[eventIndex]) {
|
||||||
timeline.apply(skeleton, lastTimeLooped, timeLooped, original, 1, false, false);
|
timeline.apply(skeleton, lastTimeLooped, timeLooped, original, 1, MixPose.current, MixDirection.in);
|
||||||
fail("Wrong event fired.");
|
fail("Wrong event fired.");
|
||||||
}
|
}
|
||||||
eventIndex++;
|
eventIndex++;
|
||||||
@ -205,7 +206,7 @@ public class EventTimelineTests {
|
|||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
if (firedEvents.size < eventsCount) {
|
if (firedEvents.size < eventsCount) {
|
||||||
timeline.apply(skeleton, lastTimeLooped, timeLooped, firedEvents, 1, false, false);
|
timeline.apply(skeleton, lastTimeLooped, timeLooped, firedEvents, 1, MixPose.current, MixDirection.in);
|
||||||
if (print) System.out.println(firedEvents);
|
if (print) System.out.println(firedEvents);
|
||||||
fail("Event not fired: " + events[eventIndex] + ", " + frames[eventIndex]);
|
fail("Event not fired: " + events[eventIndex] + ", " + frames[eventIndex]);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,6 +37,8 @@ import com.badlogic.gdx.graphics.GL20;
|
|||||||
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
|
||||||
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
|
||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
|
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||||
|
import com.esotericsoftware.spine.Animation.MixPose;
|
||||||
|
|
||||||
public class MixTest extends ApplicationAdapter {
|
public class MixTest extends ApplicationAdapter {
|
||||||
SpriteBatch batch;
|
SpriteBatch batch;
|
||||||
@ -103,21 +105,23 @@ public class MixTest extends ApplicationAdapter {
|
|||||||
skeleton.setX(-50);
|
skeleton.setX(-50);
|
||||||
} else if (time > beforeJump + jump) {
|
} else if (time > beforeJump + jump) {
|
||||||
// just walk after jump
|
// just walk after jump
|
||||||
walkAnimation.apply(skeleton, time, time, true, events, 1, false, false);
|
walkAnimation.apply(skeleton, time, time, true, events, 1, MixPose.current, MixDirection.in);
|
||||||
} else if (time > blendOutStart) {
|
} else if (time > blendOutStart) {
|
||||||
// blend out jump
|
// blend out jump
|
||||||
walkAnimation.apply(skeleton, time, time, true, events, 1, false, false);
|
walkAnimation.apply(skeleton, time, time, true, events, 1, MixPose.current, MixDirection.in);
|
||||||
jumpAnimation.apply(skeleton, time - beforeJump, time - beforeJump, false, events, 1 - (time - blendOutStart) / blendOut, false, false);
|
jumpAnimation.apply(skeleton, time - beforeJump, time - beforeJump, false, events, 1 - (time - blendOutStart) / blendOut,
|
||||||
|
MixPose.current, MixDirection.in);
|
||||||
} else if (time > beforeJump + blendIn) {
|
} else if (time > beforeJump + blendIn) {
|
||||||
// just jump
|
// just jump
|
||||||
jumpAnimation.apply(skeleton, time - beforeJump, time - beforeJump, false, events, 1, false, false);
|
jumpAnimation.apply(skeleton, time - beforeJump, time - beforeJump, false, events, 1, MixPose.current, MixDirection.in);
|
||||||
} else if (time > beforeJump) {
|
} else if (time > beforeJump) {
|
||||||
// blend in jump
|
// blend in jump
|
||||||
walkAnimation.apply(skeleton, time, time, true, events, 1, false, false);
|
walkAnimation.apply(skeleton, time, time, true, events, 1, MixPose.current, MixDirection.in);
|
||||||
jumpAnimation.apply(skeleton, time - beforeJump, time - beforeJump, false, events, (time - beforeJump) / blendIn, false, false);
|
jumpAnimation.apply(skeleton, time - beforeJump, time - beforeJump, false, events, (time - beforeJump) / blendIn,
|
||||||
|
MixPose.current, MixDirection.in);
|
||||||
} else {
|
} else {
|
||||||
// just walk before jump
|
// just walk before jump
|
||||||
walkAnimation.apply(skeleton, time, time, true, events, 1, false, false);
|
walkAnimation.apply(skeleton, time, time, true, events, 1, MixPose.current, MixDirection.in);
|
||||||
}
|
}
|
||||||
|
|
||||||
skeleton.updateWorldTransform();
|
skeleton.updateWorldTransform();
|
||||||
|
|||||||
@ -56,6 +56,8 @@ import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
|
|||||||
import com.badlogic.gdx.scenes.scene2d.ui.Window;
|
import com.badlogic.gdx.scenes.scene2d.ui.Window;
|
||||||
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
|
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
|
||||||
import com.badlogic.gdx.utils.Align;
|
import com.badlogic.gdx.utils.Align;
|
||||||
|
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||||
|
import com.esotericsoftware.spine.Animation.MixPose;
|
||||||
|
|
||||||
public class NormalMapTest extends ApplicationAdapter {
|
public class NormalMapTest extends ApplicationAdapter {
|
||||||
String skeletonPath, animationName;
|
String skeletonPath, animationName;
|
||||||
@ -130,7 +132,7 @@ public class NormalMapTest extends ApplicationAdapter {
|
|||||||
public void render () {
|
public void render () {
|
||||||
float lastTime = time;
|
float lastTime = time;
|
||||||
time += Gdx.graphics.getDeltaTime();
|
time += Gdx.graphics.getDeltaTime();
|
||||||
if (animation != null) animation.apply(skeleton, lastTime, time, true, null, 1, false, false);
|
if (animation != null) animation.apply(skeleton, lastTime, time, true, null, 1, MixPose.current, MixDirection.in);
|
||||||
skeleton.updateWorldTransform();
|
skeleton.updateWorldTransform();
|
||||||
skeleton.update(Gdx.graphics.getDeltaTime());
|
skeleton.update(Gdx.graphics.getDeltaTime());
|
||||||
|
|
||||||
|
|||||||
@ -30,6 +30,9 @@
|
|||||||
|
|
||||||
package com.esotericsoftware.spine;
|
package com.esotericsoftware.spine;
|
||||||
|
|
||||||
|
import static com.esotericsoftware.spine.Animation.MixDirection.*;
|
||||||
|
import static com.esotericsoftware.spine.Animation.MixPose.*;
|
||||||
|
|
||||||
import com.badlogic.gdx.graphics.Color;
|
import com.badlogic.gdx.graphics.Color;
|
||||||
import com.badlogic.gdx.math.MathUtils;
|
import com.badlogic.gdx.math.MathUtils;
|
||||||
import com.badlogic.gdx.utils.Array;
|
import com.badlogic.gdx.utils.Array;
|
||||||
@ -66,9 +69,9 @@ public class Animation {
|
|||||||
|
|
||||||
/** Applies all the animation's timelines to the specified skeleton.
|
/** Applies all the animation's timelines to the specified skeleton.
|
||||||
* <p>
|
* <p>
|
||||||
* See Timeline {@link Timeline#apply(Skeleton, float, float, Array, float, boolean, boolean)}. */
|
* See Timeline {@link Timeline#apply(Skeleton, float, float, Array, float, MixPose, MixDirection)}. */
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, boolean loop, Array<Event> events, float alpha,
|
public void apply (Skeleton skeleton, float lastTime, float time, boolean loop, Array<Event> events, float alpha, MixPose pose,
|
||||||
boolean setupPose, boolean mixingOut) {
|
MixDirection direction) {
|
||||||
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
|
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
|
||||||
|
|
||||||
if (loop && duration != 0) {
|
if (loop && duration != 0) {
|
||||||
@ -78,7 +81,7 @@ public class Animation {
|
|||||||
|
|
||||||
Array<Timeline> timelines = this.timelines;
|
Array<Timeline> timelines = this.timelines;
|
||||||
for (int i = 0, n = timelines.size; i < n; i++)
|
for (int i = 0, n = timelines.size; i < n; i++)
|
||||||
timelines.get(i).apply(skeleton, lastTime, time, events, alpha, setupPose, mixingOut);
|
timelines.get(i).apply(skeleton, lastTime, time, events, alpha, pose, direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The animation's name, which is unique within the skeleton. */
|
/** The animation's name, which is unique within the skeleton. */
|
||||||
@ -142,23 +145,43 @@ public class Animation {
|
|||||||
* interpolate between the keys.
|
* interpolate between the keys.
|
||||||
* @param events If any events are fired, they are added to this list. Can be null to ignore firing events or if the
|
* @param events If any events are fired, they are added to this list. Can be null to ignore firing events or if the
|
||||||
* timeline does not fire events.
|
* timeline does not fire events.
|
||||||
* @param alpha 0 results in the value of the current or setup pose (depending on <code>setupPose</code>). 1 results in the
|
* @param alpha 0 applies the current or setup pose value (depending on <code>setupPose</code>). 1 applies the timeline
|
||||||
* value from the timeline. Between 0 and 1 results in a value mixed between the current or setup pose and the
|
* value. Between 0 and 1 applies a value between the current or setup pose and the timeline value. By adjusting
|
||||||
* value from the timeline. By adjusting <code>alpha</code> over time, an animation can be mixed in or out.
|
* <code>alpha</code> over time, an animation can be mixed in or out. <code>alpha</code> can also be useful to
|
||||||
* <code>alpha</code> can also be useful to apply animations on top of each other.
|
* apply animations on top of each other (layered).
|
||||||
* @param setupPose Controls mixing when <code>alpha</code> < 1. When true the value from the timeline is mixed with the
|
* @param pose Controls how mixing is applied when <code>alpha</code> < 1.
|
||||||
* value from the setup pose. When false the value from the timeline is mixed with the value from the current
|
* @param direction Indicates whether the timeline is mixing in or out. Used by timelines which perform instant transitions,
|
||||||
* pose. Passing true when <code>alpha</code> is 1 is slightly more efficient for most timelines.
|
* such as {@link DrawOrderTimeline} or {@link AttachmentTimeline}. */
|
||||||
* @param mixingOut True when changing <code>alpha</code> over time toward 0 (the setup or current pose), false when
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, MixPose pose,
|
||||||
* changing <code>alpha</code> toward 1 (the timeline's pose). Used for timelines which perform instant
|
MixDirection direction);
|
||||||
* transitions, such as {@link DrawOrderTimeline} or {@link AttachmentTimeline}. */
|
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, boolean setupPose,
|
|
||||||
boolean mixingOut);
|
|
||||||
|
|
||||||
/** Uniquely encodes both the type of this timeline and the skeleton property that it affects. */
|
/** Uniquely encodes both the type of this timeline and the skeleton property that it affects. */
|
||||||
public int getPropertyId ();
|
public int getPropertyId ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Controls how a timeline is mixed with the setup or current pose.
|
||||||
|
* <p>
|
||||||
|
* See Timeline {@link Timeline#apply(Skeleton, float, float, Array, float, MixPose, MixDirection)}. */
|
||||||
|
static public enum MixPose {
|
||||||
|
/** The timeline value is mixed with the setup pose (the current pose is not used). */
|
||||||
|
setup,
|
||||||
|
/** The timeline value is mixed with the current pose. The setup pose is used as the timeline value before the first key,
|
||||||
|
* except for timelines which perform instant transitions, such as {@link DrawOrderTimeline} or
|
||||||
|
* {@link AttachmentTimeline}. */
|
||||||
|
current,
|
||||||
|
/** The timeline value is mixed with the current pose. No change is made before the first key (the current pose is kept
|
||||||
|
* until the first key). */
|
||||||
|
currentLayered
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Indicates whether a timeline's <code>alpha</code> is mixing out over time toward 0 (the setup or current pose) or mixing in
|
||||||
|
* toward 1 (the timeline's pose).
|
||||||
|
* <p>
|
||||||
|
* See Timeline {@link Timeline#apply(Skeleton, float, float, Array, float, MixPose, MixDirection)}. */
|
||||||
|
static public enum MixDirection {
|
||||||
|
in, out
|
||||||
|
}
|
||||||
|
|
||||||
static private enum TimelineType {
|
static private enum TimelineType {
|
||||||
rotate, translate, scale, shear, //
|
rotate, translate, scale, shear, //
|
||||||
attachment, color, deform, //
|
attachment, color, deform, //
|
||||||
@ -295,18 +318,26 @@ public class Animation {
|
|||||||
frames[frameIndex + ROTATION] = degrees;
|
frames[frameIndex + ROTATION] = degrees;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, boolean setupPose,
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, MixPose pose,
|
||||||
boolean mixingOut) {
|
MixDirection direction) {
|
||||||
|
|
||||||
Bone bone = skeleton.bones.get(boneIndex);
|
Bone bone = skeleton.bones.get(boneIndex);
|
||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
if (setupPose) bone.rotation = bone.data.rotation;
|
switch (pose) {
|
||||||
|
case setup:
|
||||||
|
bone.rotation = bone.data.rotation;
|
||||||
|
return;
|
||||||
|
case current:
|
||||||
|
float r = bone.data.rotation - bone.rotation;
|
||||||
|
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
|
||||||
|
bone.rotation += r * alpha;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||||
if (setupPose)
|
if (pose == setup)
|
||||||
bone.rotation = bone.data.rotation + frames[frames.length + PREV_ROTATION] * alpha;
|
bone.rotation = bone.data.rotation + frames[frames.length + PREV_ROTATION] * alpha;
|
||||||
else {
|
else {
|
||||||
float r = bone.data.rotation + frames[frames.length + PREV_ROTATION] - bone.rotation;
|
float r = bone.data.rotation + frames[frames.length + PREV_ROTATION] - bone.rotation;
|
||||||
@ -325,7 +356,7 @@ public class Animation {
|
|||||||
float r = frames[frame + ROTATION] - prevRotation;
|
float r = frames[frame + ROTATION] - prevRotation;
|
||||||
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
|
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
|
||||||
r = prevRotation + r * percent;
|
r = prevRotation + r * percent;
|
||||||
if (setupPose) {
|
if (pose == setup) {
|
||||||
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
|
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
|
||||||
bone.rotation = bone.data.rotation + r * alpha;
|
bone.rotation = bone.data.rotation + r * alpha;
|
||||||
} else {
|
} else {
|
||||||
@ -377,15 +408,20 @@ public class Animation {
|
|||||||
frames[frameIndex + Y] = y;
|
frames[frameIndex + Y] = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, boolean setupPose,
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, MixPose pose,
|
||||||
boolean mixingOut) {
|
MixDirection direction) {
|
||||||
|
|
||||||
Bone bone = skeleton.bones.get(boneIndex);
|
Bone bone = skeleton.bones.get(boneIndex);
|
||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
if (setupPose) {
|
switch (pose) {
|
||||||
|
case setup:
|
||||||
bone.x = bone.data.x;
|
bone.x = bone.data.x;
|
||||||
bone.y = bone.data.y;
|
bone.y = bone.data.y;
|
||||||
|
return;
|
||||||
|
case current:
|
||||||
|
bone.x += (bone.data.x - bone.x) * alpha;
|
||||||
|
bone.y += (bone.data.y - bone.y) * alpha;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -406,7 +442,7 @@ public class Animation {
|
|||||||
x += (frames[frame + X] - x) * percent;
|
x += (frames[frame + X] - x) * percent;
|
||||||
y += (frames[frame + Y] - y) * percent;
|
y += (frames[frame + Y] - y) * percent;
|
||||||
}
|
}
|
||||||
if (setupPose) {
|
if (pose == setup) {
|
||||||
bone.x = bone.data.x + x * alpha;
|
bone.x = bone.data.x + x * alpha;
|
||||||
bone.y = bone.data.y + y * alpha;
|
bone.y = bone.data.y + y * alpha;
|
||||||
} else {
|
} else {
|
||||||
@ -426,15 +462,20 @@ public class Animation {
|
|||||||
return (TimelineType.scale.ordinal() << 24) + boneIndex;
|
return (TimelineType.scale.ordinal() << 24) + boneIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, boolean setupPose,
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, MixPose pose,
|
||||||
boolean mixingOut) {
|
MixDirection direction) {
|
||||||
|
|
||||||
Bone bone = skeleton.bones.get(boneIndex);
|
Bone bone = skeleton.bones.get(boneIndex);
|
||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
if (setupPose) {
|
switch (pose) {
|
||||||
|
case setup:
|
||||||
bone.scaleX = bone.data.scaleX;
|
bone.scaleX = bone.data.scaleX;
|
||||||
bone.scaleY = bone.data.scaleY;
|
bone.scaleY = bone.data.scaleY;
|
||||||
|
return;
|
||||||
|
case current:
|
||||||
|
bone.scaleX += (bone.data.scaleX - bone.scaleX) * alpha;
|
||||||
|
bone.scaleY += (bone.data.scaleY - bone.scaleY) * alpha;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -460,7 +501,7 @@ public class Animation {
|
|||||||
bone.scaleY = y;
|
bone.scaleY = y;
|
||||||
} else {
|
} else {
|
||||||
float bx, by;
|
float bx, by;
|
||||||
if (setupPose) {
|
if (pose == setup) {
|
||||||
bx = bone.data.scaleX;
|
bx = bone.data.scaleX;
|
||||||
by = bone.data.scaleY;
|
by = bone.data.scaleY;
|
||||||
} else {
|
} else {
|
||||||
@ -468,7 +509,7 @@ public class Animation {
|
|||||||
by = bone.scaleY;
|
by = bone.scaleY;
|
||||||
}
|
}
|
||||||
// Mixing out uses sign of setup or current pose, else use sign of key.
|
// Mixing out uses sign of setup or current pose, else use sign of key.
|
||||||
if (mixingOut) {
|
if (direction == out) {
|
||||||
x = Math.abs(x) * Math.signum(bx);
|
x = Math.abs(x) * Math.signum(bx);
|
||||||
y = Math.abs(y) * Math.signum(by);
|
y = Math.abs(y) * Math.signum(by);
|
||||||
} else {
|
} else {
|
||||||
@ -491,15 +532,20 @@ public class Animation {
|
|||||||
return (TimelineType.shear.ordinal() << 24) + boneIndex;
|
return (TimelineType.shear.ordinal() << 24) + boneIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, boolean setupPose,
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, MixPose pose,
|
||||||
boolean mixingOut) {
|
MixDirection direction) {
|
||||||
|
|
||||||
Bone bone = skeleton.bones.get(boneIndex);
|
Bone bone = skeleton.bones.get(boneIndex);
|
||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
if (setupPose) {
|
switch (pose) {
|
||||||
|
case setup:
|
||||||
bone.shearX = bone.data.shearX;
|
bone.shearX = bone.data.shearX;
|
||||||
bone.shearY = bone.data.shearY;
|
bone.shearY = bone.data.shearY;
|
||||||
|
return;
|
||||||
|
case current:
|
||||||
|
bone.shearX += (bone.data.shearX - bone.shearX) * alpha;
|
||||||
|
bone.shearY += (bone.data.shearY - bone.shearY) * alpha;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -520,7 +566,7 @@ public class Animation {
|
|||||||
x = x + (frames[frame + X] - x) * percent;
|
x = x + (frames[frame + X] - x) * percent;
|
||||||
y = y + (frames[frame + Y] - y) * percent;
|
y = y + (frames[frame + Y] - y) * percent;
|
||||||
}
|
}
|
||||||
if (setupPose) {
|
if (pose == setup) {
|
||||||
bone.shearX = bone.data.shearX + x * alpha;
|
bone.shearX = bone.data.shearX + x * alpha;
|
||||||
bone.shearY = bone.data.shearY + y * alpha;
|
bone.shearY = bone.data.shearY + y * alpha;
|
||||||
} else {
|
} else {
|
||||||
@ -573,13 +619,21 @@ public class Animation {
|
|||||||
frames[frameIndex + A] = a;
|
frames[frameIndex + A] = a;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, boolean setupPose,
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, MixPose pose,
|
||||||
boolean mixingOut) {
|
MixDirection direction) {
|
||||||
|
|
||||||
Slot slot = skeleton.slots.get(slotIndex);
|
Slot slot = skeleton.slots.get(slotIndex);
|
||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
if (setupPose) slot.color.set(slot.data.color);
|
switch (pose) {
|
||||||
|
case setup:
|
||||||
|
slot.color.set(slot.data.color);
|
||||||
|
return;
|
||||||
|
case current:
|
||||||
|
Color color = slot.color, setup = slot.data.color;
|
||||||
|
color.add((setup.r - color.r) * alpha, (setup.g - color.g) * alpha, (setup.b - color.b) * alpha,
|
||||||
|
(setup.a - color.a) * alpha);
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -610,7 +664,7 @@ public class Animation {
|
|||||||
slot.color.set(r, g, b, a);
|
slot.color.set(r, g, b, a);
|
||||||
else {
|
else {
|
||||||
Color color = slot.color;
|
Color color = slot.color;
|
||||||
if (setupPose) color.set(slot.data.color);
|
if (pose == setup) color.set(slot.data.color);
|
||||||
color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha);
|
color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -663,15 +717,22 @@ public class Animation {
|
|||||||
frames[frameIndex + B2] = b2;
|
frames[frameIndex + B2] = b2;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, boolean setupPose,
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, MixPose pose,
|
||||||
boolean mixingOut) {
|
MixDirection direction) {
|
||||||
|
|
||||||
Slot slot = skeleton.slots.get(slotIndex);
|
Slot slot = skeleton.slots.get(slotIndex);
|
||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
if (setupPose) {
|
switch (pose) {
|
||||||
|
case setup:
|
||||||
slot.color.set(slot.data.color);
|
slot.color.set(slot.data.color);
|
||||||
slot.darkColor.set(slot.data.darkColor);
|
slot.darkColor.set(slot.data.darkColor);
|
||||||
|
return;
|
||||||
|
case current:
|
||||||
|
Color light = slot.color, dark = slot.darkColor, setupLight = slot.data.color, setupDark = slot.data.darkColor;
|
||||||
|
light.add((setupLight.r - light.r) * alpha, (setupLight.g - light.g) * alpha, (setupLight.b - light.b) * alpha,
|
||||||
|
(setupLight.a - light.a) * alpha);
|
||||||
|
dark.add((setupDark.r - dark.r) * alpha, (setupDark.g - dark.g) * alpha, (setupDark.b - dark.b) * alpha, 0);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -712,9 +773,8 @@ public class Animation {
|
|||||||
slot.color.set(r, g, b, a);
|
slot.color.set(r, g, b, a);
|
||||||
slot.darkColor.set(r2, g2, b2, 1);
|
slot.darkColor.set(r2, g2, b2, 1);
|
||||||
} else {
|
} else {
|
||||||
Color light = slot.color;
|
Color light = slot.color, dark = slot.darkColor;
|
||||||
Color dark = slot.darkColor;
|
if (pose == setup) {
|
||||||
if (setupPose) {
|
|
||||||
light.set(slot.data.color);
|
light.set(slot.data.color);
|
||||||
dark.set(slot.data.darkColor);
|
dark.set(slot.data.darkColor);
|
||||||
}
|
}
|
||||||
@ -770,11 +830,11 @@ public class Animation {
|
|||||||
attachmentNames[frameIndex] = attachmentName;
|
attachmentNames[frameIndex] = attachmentName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, boolean setupPose,
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, MixPose pose,
|
||||||
boolean mixingOut) {
|
MixDirection direction) {
|
||||||
|
|
||||||
Slot slot = skeleton.slots.get(slotIndex);
|
Slot slot = skeleton.slots.get(slotIndex);
|
||||||
if (mixingOut && setupPose) {
|
if (direction == out && pose == setup) {
|
||||||
String attachmentName = slot.data.attachmentName;
|
String attachmentName = slot.data.attachmentName;
|
||||||
slot.setAttachment(attachmentName == null ? null : skeleton.getAttachment(slotIndex, attachmentName));
|
slot.setAttachment(attachmentName == null ? null : skeleton.getAttachment(slotIndex, attachmentName));
|
||||||
return;
|
return;
|
||||||
@ -782,7 +842,7 @@ public class Animation {
|
|||||||
|
|
||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
if (setupPose) {
|
if (pose == setup) {
|
||||||
String attachmentName = slot.data.attachmentName;
|
String attachmentName = slot.data.attachmentName;
|
||||||
slot.setAttachment(attachmentName == null ? null : skeleton.getAttachment(slotIndex, attachmentName));
|
slot.setAttachment(attachmentName == null ? null : skeleton.getAttachment(slotIndex, attachmentName));
|
||||||
}
|
}
|
||||||
@ -853,31 +913,39 @@ public class Animation {
|
|||||||
frameVertices[frameIndex] = vertices;
|
frameVertices[frameIndex] = vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> firedEvents, float alpha, boolean setupPose,
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, MixPose pose,
|
||||||
boolean mixingOut) {
|
MixDirection direction) {
|
||||||
|
|
||||||
Slot slot = skeleton.slots.get(slotIndex);
|
Slot slot = skeleton.slots.get(slotIndex);
|
||||||
Attachment slotAttachment = slot.attachment;
|
Attachment slotAttachment = slot.attachment;
|
||||||
if (!(slotAttachment instanceof VertexAttachment) || !((VertexAttachment)slotAttachment).applyDeform(attachment)) return;
|
if (!(slotAttachment instanceof VertexAttachment) || !((VertexAttachment)slotAttachment).applyDeform(attachment)) return;
|
||||||
|
|
||||||
FloatArray verticesArray = slot.getAttachmentVertices();
|
FloatArray verticesArray = slot.getAttachmentVertices();
|
||||||
float[] frames = this.frames;
|
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
|
||||||
if (setupPose) verticesArray.size = 0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
float[][] frameVertices = this.frameVertices;
|
float[][] frameVertices = this.frameVertices;
|
||||||
int vertexCount = frameVertices[0].length;
|
int vertexCount = frameVertices[0].length;
|
||||||
if (verticesArray.size != vertexCount && !setupPose) alpha = 1; // Don't mix from uninitialized slot vertices.
|
if (verticesArray.size != vertexCount && pose != setup) alpha = 1; // Don't mix from uninitialized slot vertices.
|
||||||
float[] vertices = verticesArray.setSize(vertexCount);
|
float[] vertices = verticesArray.setSize(vertexCount);
|
||||||
|
|
||||||
|
float[] frames = this.frames;
|
||||||
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
|
switch (pose) {
|
||||||
|
case setup:
|
||||||
|
verticesArray.size = 0;
|
||||||
|
return;
|
||||||
|
case current:
|
||||||
|
alpha = 1 - alpha;
|
||||||
|
for (int i = 0; i < vertexCount; i++)
|
||||||
|
vertices[i] *= alpha;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (time >= frames[frames.length - 1]) { // Time is after last frame.
|
if (time >= frames[frames.length - 1]) { // Time is after last frame.
|
||||||
float[] lastVertices = frameVertices[frames.length - 1];
|
float[] lastVertices = frameVertices[frames.length - 1];
|
||||||
if (alpha == 1) {
|
if (alpha == 1) {
|
||||||
// Vertex positions or deform offsets, no alpha.
|
// Vertex positions or deform offsets, no alpha.
|
||||||
System.arraycopy(lastVertices, 0, vertices, 0, vertexCount);
|
System.arraycopy(lastVertices, 0, vertices, 0, vertexCount);
|
||||||
} else if (setupPose) {
|
} else if (pose == setup) {
|
||||||
VertexAttachment vertexAttachment = (VertexAttachment)slotAttachment;
|
VertexAttachment vertexAttachment = (VertexAttachment)slotAttachment;
|
||||||
if (vertexAttachment.getBones() == null) {
|
if (vertexAttachment.getBones() == null) {
|
||||||
// Unweighted vertex positions, with alpha.
|
// Unweighted vertex positions, with alpha.
|
||||||
@ -912,7 +980,7 @@ public class Animation {
|
|||||||
float prev = prevVertices[i];
|
float prev = prevVertices[i];
|
||||||
vertices[i] = prev + (nextVertices[i] - prev) * percent;
|
vertices[i] = prev + (nextVertices[i] - prev) * percent;
|
||||||
}
|
}
|
||||||
} else if (setupPose) {
|
} else if (pose == setup) {
|
||||||
VertexAttachment vertexAttachment = (VertexAttachment)slotAttachment;
|
VertexAttachment vertexAttachment = (VertexAttachment)slotAttachment;
|
||||||
if (vertexAttachment.getBones() == null) {
|
if (vertexAttachment.getBones() == null) {
|
||||||
// Unweighted vertex positions, with alpha.
|
// Unweighted vertex positions, with alpha.
|
||||||
@ -974,15 +1042,15 @@ public class Animation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Fires events for frames > <code>lastTime</code> and <= <code>time</code>. */
|
/** Fires events for frames > <code>lastTime</code> and <= <code>time</code>. */
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> firedEvents, float alpha, boolean setupPose,
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> firedEvents, float alpha, MixPose pose,
|
||||||
boolean mixingOut) {
|
MixDirection direction) {
|
||||||
|
|
||||||
if (firedEvents == null) return;
|
if (firedEvents == null) return;
|
||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
int frameCount = frames.length;
|
int frameCount = frames.length;
|
||||||
|
|
||||||
if (lastTime > time) { // Fire events after last time for looped animations.
|
if (lastTime > time) { // Fire events after last time for looped animations.
|
||||||
apply(skeleton, lastTime, Integer.MAX_VALUE, firedEvents, alpha, setupPose, mixingOut);
|
apply(skeleton, lastTime, Integer.MAX_VALUE, firedEvents, alpha, pose, direction);
|
||||||
lastTime = -1f;
|
lastTime = -1f;
|
||||||
} else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame.
|
} else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame.
|
||||||
return;
|
return;
|
||||||
@ -1041,19 +1109,19 @@ public class Animation {
|
|||||||
drawOrders[frameIndex] = drawOrder;
|
drawOrders[frameIndex] = drawOrder;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> firedEvents, float alpha, boolean setupPose,
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, MixPose pose,
|
||||||
boolean mixingOut) {
|
MixDirection direction) {
|
||||||
|
|
||||||
Array<Slot> drawOrder = skeleton.drawOrder;
|
Array<Slot> drawOrder = skeleton.drawOrder;
|
||||||
Array<Slot> slots = skeleton.slots;
|
Array<Slot> slots = skeleton.slots;
|
||||||
if (mixingOut && setupPose) {
|
if (direction == out && pose == setup) {
|
||||||
System.arraycopy(slots.items, 0, drawOrder.items, 0, slots.size);
|
System.arraycopy(slots.items, 0, drawOrder.items, 0, slots.size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
if (setupPose) System.arraycopy(slots.items, 0, drawOrder.items, 0, slots.size);
|
if (pose == setup) System.arraycopy(slots.items, 0, drawOrder.items, 0, slots.size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1114,27 +1182,32 @@ public class Animation {
|
|||||||
frames[frameIndex + BEND_DIRECTION] = bendDirection;
|
frames[frameIndex + BEND_DIRECTION] = bendDirection;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, boolean setupPose,
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, MixPose pose,
|
||||||
boolean mixingOut) {
|
MixDirection direction) {
|
||||||
|
|
||||||
IkConstraint constraint = skeleton.ikConstraints.get(ikConstraintIndex);
|
IkConstraint constraint = skeleton.ikConstraints.get(ikConstraintIndex);
|
||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
if (setupPose) {
|
switch (pose) {
|
||||||
|
case setup:
|
||||||
constraint.mix = constraint.data.mix;
|
constraint.mix = constraint.data.mix;
|
||||||
constraint.bendDirection = constraint.data.bendDirection;
|
constraint.bendDirection = constraint.data.bendDirection;
|
||||||
|
return;
|
||||||
|
case current:
|
||||||
|
constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
|
||||||
|
constraint.bendDirection = constraint.data.bendDirection;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||||
if (setupPose) {
|
if (pose == setup) {
|
||||||
constraint.mix = constraint.data.mix + (frames[frames.length + PREV_MIX] - constraint.data.mix) * alpha;
|
constraint.mix = constraint.data.mix + (frames[frames.length + PREV_MIX] - constraint.data.mix) * alpha;
|
||||||
constraint.bendDirection = mixingOut ? constraint.data.bendDirection
|
constraint.bendDirection = direction == out ? constraint.data.bendDirection
|
||||||
: (int)frames[frames.length + PREV_BEND_DIRECTION];
|
: (int)frames[frames.length + PREV_BEND_DIRECTION];
|
||||||
} else {
|
} else {
|
||||||
constraint.mix += (frames[frames.length + PREV_MIX] - constraint.mix) * alpha;
|
constraint.mix += (frames[frames.length + PREV_MIX] - constraint.mix) * alpha;
|
||||||
if (!mixingOut) constraint.bendDirection = (int)frames[frames.length + PREV_BEND_DIRECTION];
|
if (direction == in) constraint.bendDirection = (int)frames[frames.length + PREV_BEND_DIRECTION];
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1145,12 +1218,13 @@ public class Animation {
|
|||||||
float frameTime = frames[frame];
|
float frameTime = frames[frame];
|
||||||
float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
float percent = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||||
|
|
||||||
if (setupPose) {
|
if (pose == setup) {
|
||||||
constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha;
|
constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha;
|
||||||
constraint.bendDirection = mixingOut ? constraint.data.bendDirection : (int)frames[frame + PREV_BEND_DIRECTION];
|
constraint.bendDirection = direction == out ? constraint.data.bendDirection
|
||||||
|
: (int)frames[frame + PREV_BEND_DIRECTION];
|
||||||
} else {
|
} else {
|
||||||
constraint.mix += (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha;
|
constraint.mix += (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha;
|
||||||
if (!mixingOut) constraint.bendDirection = (int)frames[frame + PREV_BEND_DIRECTION];
|
if (direction == in) constraint.bendDirection = (int)frames[frame + PREV_BEND_DIRECTION];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1198,18 +1272,25 @@ public class Animation {
|
|||||||
frames[frameIndex + SHEAR] = shearMix;
|
frames[frameIndex + SHEAR] = shearMix;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, boolean setupPose,
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, MixPose pose,
|
||||||
boolean mixingOut) {
|
MixDirection direction) {
|
||||||
|
|
||||||
TransformConstraint constraint = skeleton.transformConstraints.get(transformConstraintIndex);
|
TransformConstraint constraint = skeleton.transformConstraints.get(transformConstraintIndex);
|
||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
if (setupPose) {
|
TransformConstraintData data = constraint.data;
|
||||||
TransformConstraintData data = constraint.data;
|
switch (pose) {
|
||||||
|
case setup:
|
||||||
constraint.rotateMix = data.rotateMix;
|
constraint.rotateMix = data.rotateMix;
|
||||||
constraint.translateMix = data.translateMix;
|
constraint.translateMix = data.translateMix;
|
||||||
constraint.scaleMix = data.scaleMix;
|
constraint.scaleMix = data.scaleMix;
|
||||||
constraint.shearMix = data.shearMix;
|
constraint.shearMix = data.shearMix;
|
||||||
|
return;
|
||||||
|
case current:
|
||||||
|
constraint.rotateMix += (data.rotateMix - constraint.rotateMix) * alpha;
|
||||||
|
constraint.translateMix += (data.translateMix - constraint.translateMix) * alpha;
|
||||||
|
constraint.scaleMix += (data.scaleMix - constraint.scaleMix) * alpha;
|
||||||
|
constraint.shearMix += (data.shearMix - constraint.shearMix) * alpha;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1237,7 +1318,7 @@ public class Animation {
|
|||||||
scale += (frames[frame + SCALE] - scale) * percent;
|
scale += (frames[frame + SCALE] - scale) * percent;
|
||||||
shear += (frames[frame + SHEAR] - shear) * percent;
|
shear += (frames[frame + SHEAR] - shear) * percent;
|
||||||
}
|
}
|
||||||
if (setupPose) {
|
if (pose == setup) {
|
||||||
TransformConstraintData data = constraint.data;
|
TransformConstraintData data = constraint.data;
|
||||||
constraint.rotateMix = data.rotateMix + (rotate - data.rotateMix) * alpha;
|
constraint.rotateMix = data.rotateMix + (rotate - data.rotateMix) * alpha;
|
||||||
constraint.translateMix = data.translateMix + (translate - data.translateMix) * alpha;
|
constraint.translateMix = data.translateMix + (translate - data.translateMix) * alpha;
|
||||||
@ -1293,13 +1374,19 @@ public class Animation {
|
|||||||
frames[frameIndex + VALUE] = position;
|
frames[frameIndex + VALUE] = position;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, boolean setupPose,
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, MixPose pose,
|
||||||
boolean mixingOut) {
|
MixDirection direction) {
|
||||||
|
|
||||||
PathConstraint constraint = skeleton.pathConstraints.get(pathConstraintIndex);
|
PathConstraint constraint = skeleton.pathConstraints.get(pathConstraintIndex);
|
||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
if (setupPose) constraint.position = constraint.data.position;
|
switch (pose) {
|
||||||
|
case setup:
|
||||||
|
constraint.position = constraint.data.position;
|
||||||
|
return;
|
||||||
|
case current:
|
||||||
|
constraint.position += (constraint.data.position - constraint.position) * alpha;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1316,7 +1403,7 @@ public class Animation {
|
|||||||
|
|
||||||
position += (frames[frame + VALUE] - position) * percent;
|
position += (frames[frame + VALUE] - position) * percent;
|
||||||
}
|
}
|
||||||
if (setupPose)
|
if (pose == setup)
|
||||||
constraint.position = constraint.data.position + (position - constraint.data.position) * alpha;
|
constraint.position = constraint.data.position + (position - constraint.data.position) * alpha;
|
||||||
else
|
else
|
||||||
constraint.position += (position - constraint.position) * alpha;
|
constraint.position += (position - constraint.position) * alpha;
|
||||||
@ -1333,13 +1420,19 @@ public class Animation {
|
|||||||
return (TimelineType.pathConstraintSpacing.ordinal() << 24) + pathConstraintIndex;
|
return (TimelineType.pathConstraintSpacing.ordinal() << 24) + pathConstraintIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, boolean setupPose,
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, MixPose pose,
|
||||||
boolean mixingOut) {
|
MixDirection direction) {
|
||||||
|
|
||||||
PathConstraint constraint = skeleton.pathConstraints.get(pathConstraintIndex);
|
PathConstraint constraint = skeleton.pathConstraints.get(pathConstraintIndex);
|
||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
if (setupPose) constraint.spacing = constraint.data.spacing;
|
switch (pose) {
|
||||||
|
case setup:
|
||||||
|
constraint.spacing = constraint.data.spacing;
|
||||||
|
return;
|
||||||
|
case current:
|
||||||
|
constraint.spacing += (constraint.data.spacing - constraint.spacing) * alpha;
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1357,7 +1450,7 @@ public class Animation {
|
|||||||
spacing += (frames[frame + VALUE] - spacing) * percent;
|
spacing += (frames[frame + VALUE] - spacing) * percent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setupPose)
|
if (pose == setup)
|
||||||
constraint.spacing = constraint.data.spacing + (spacing - constraint.data.spacing) * alpha;
|
constraint.spacing = constraint.data.spacing + (spacing - constraint.data.spacing) * alpha;
|
||||||
else
|
else
|
||||||
constraint.spacing += (spacing - constraint.spacing) * alpha;
|
constraint.spacing += (spacing - constraint.spacing) * alpha;
|
||||||
@ -1406,15 +1499,20 @@ public class Animation {
|
|||||||
frames[frameIndex + TRANSLATE] = translateMix;
|
frames[frameIndex + TRANSLATE] = translateMix;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, boolean setupPose,
|
public void apply (Skeleton skeleton, float lastTime, float time, Array<Event> events, float alpha, MixPose pose,
|
||||||
boolean mixingOut) {
|
MixDirection direction) {
|
||||||
|
|
||||||
PathConstraint constraint = skeleton.pathConstraints.get(pathConstraintIndex);
|
PathConstraint constraint = skeleton.pathConstraints.get(pathConstraintIndex);
|
||||||
float[] frames = this.frames;
|
float[] frames = this.frames;
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
if (setupPose) {
|
switch (pose) {
|
||||||
|
case setup:
|
||||||
constraint.rotateMix = constraint.data.rotateMix;
|
constraint.rotateMix = constraint.data.rotateMix;
|
||||||
constraint.translateMix = constraint.data.translateMix;
|
constraint.translateMix = constraint.data.translateMix;
|
||||||
|
return;
|
||||||
|
case current:
|
||||||
|
constraint.rotateMix += (constraint.data.rotateMix - constraint.rotateMix) * alpha;
|
||||||
|
constraint.translateMix += (constraint.data.translateMix - constraint.translateMix) * alpha;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1436,7 +1534,7 @@ public class Animation {
|
|||||||
translate += (frames[frame + TRANSLATE] - translate) * percent;
|
translate += (frames[frame + TRANSLATE] - translate) * percent;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setupPose) {
|
if (pose == setup) {
|
||||||
constraint.rotateMix = constraint.data.rotateMix + (rotate - constraint.data.rotateMix) * alpha;
|
constraint.rotateMix = constraint.data.rotateMix + (rotate - constraint.data.rotateMix) * alpha;
|
||||||
constraint.translateMix = constraint.data.translateMix + (translate - constraint.data.translateMix) * alpha;
|
constraint.translateMix = constraint.data.translateMix + (translate - constraint.data.translateMix) * alpha;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -40,6 +40,8 @@ import com.badlogic.gdx.utils.Pool;
|
|||||||
import com.badlogic.gdx.utils.Pool.Poolable;
|
import com.badlogic.gdx.utils.Pool.Poolable;
|
||||||
import com.esotericsoftware.spine.Animation.AttachmentTimeline;
|
import com.esotericsoftware.spine.Animation.AttachmentTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.DrawOrderTimeline;
|
import com.esotericsoftware.spine.Animation.DrawOrderTimeline;
|
||||||
|
import com.esotericsoftware.spine.Animation.MixDirection;
|
||||||
|
import com.esotericsoftware.spine.Animation.MixPose;
|
||||||
import com.esotericsoftware.spine.Animation.RotateTimeline;
|
import com.esotericsoftware.spine.Animation.RotateTimeline;
|
||||||
import com.esotericsoftware.spine.Animation.Timeline;
|
import com.esotericsoftware.spine.Animation.Timeline;
|
||||||
|
|
||||||
@ -170,11 +172,12 @@ public class AnimationState {
|
|||||||
TrackEntry current = tracks.get(i);
|
TrackEntry current = tracks.get(i);
|
||||||
if (current == null || current.delay > 0) continue;
|
if (current == null || current.delay > 0) continue;
|
||||||
applied = true;
|
applied = true;
|
||||||
|
MixPose currentPose = i == 0 ? MixPose.current : MixPose.currentLayered;
|
||||||
|
|
||||||
// Apply mixing from entries first.
|
// Apply mixing from entries first.
|
||||||
float mix = current.alpha;
|
float mix = current.alpha;
|
||||||
if (current.mixingFrom != null)
|
if (current.mixingFrom != null)
|
||||||
mix *= applyMixingFrom(current, skeleton);
|
mix *= applyMixingFrom(current, skeleton, currentPose);
|
||||||
else if (current.trackTime >= current.trackEnd && current.next == null) //
|
else if (current.trackTime >= current.trackEnd && current.next == null) //
|
||||||
mix = 0; // Set to setup pose the last time the entry will be applied.
|
mix = 0; // Set to setup pose the last time the entry will be applied.
|
||||||
|
|
||||||
@ -184,7 +187,7 @@ public class AnimationState {
|
|||||||
Object[] timelines = current.animation.timelines.items;
|
Object[] timelines = current.animation.timelines.items;
|
||||||
if (mix == 1) {
|
if (mix == 1) {
|
||||||
for (int ii = 0; ii < timelineCount; ii++)
|
for (int ii = 0; ii < timelineCount; ii++)
|
||||||
((Timeline)timelines[ii]).apply(skeleton, animationLast, animationTime, events, 1, true, false);
|
((Timeline)timelines[ii]).apply(skeleton, animationLast, animationTime, events, 1, MixPose.setup, MixDirection.in);
|
||||||
} else {
|
} else {
|
||||||
int[] timelineData = current.timelineData.items;
|
int[] timelineData = current.timelineData.items;
|
||||||
|
|
||||||
@ -194,11 +197,11 @@ public class AnimationState {
|
|||||||
|
|
||||||
for (int ii = 0; ii < timelineCount; ii++) {
|
for (int ii = 0; ii < timelineCount; ii++) {
|
||||||
Timeline timeline = (Timeline)timelines[ii];
|
Timeline timeline = (Timeline)timelines[ii];
|
||||||
if (timeline instanceof RotateTimeline) {
|
MixPose pose = timelineData[ii] >= FIRST ? MixPose.setup : currentPose;
|
||||||
applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineData[ii] >= FIRST, timelinesRotation,
|
if (timeline instanceof RotateTimeline)
|
||||||
ii << 1, firstFrame);
|
applyRotateTimeline(timeline, skeleton, animationTime, mix, pose, timelinesRotation, ii << 1, firstFrame);
|
||||||
} else
|
else
|
||||||
timeline.apply(skeleton, animationLast, animationTime, events, mix, timelineData[ii] >= FIRST, false);
|
timeline.apply(skeleton, animationLast, animationTime, events, mix, pose, MixDirection.in);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
queueEvents(current, animationTime);
|
queueEvents(current, animationTime);
|
||||||
@ -211,9 +214,9 @@ public class AnimationState {
|
|||||||
return applied;
|
return applied;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float applyMixingFrom (TrackEntry to, Skeleton skeleton) {
|
private float applyMixingFrom (TrackEntry to, Skeleton skeleton, MixPose currentPose) {
|
||||||
TrackEntry from = to.mixingFrom;
|
TrackEntry from = to.mixingFrom;
|
||||||
if (from.mixingFrom != null) applyMixingFrom(from, skeleton);
|
if (from.mixingFrom != null) applyMixingFrom(from, skeleton, currentPose);
|
||||||
|
|
||||||
float mix;
|
float mix;
|
||||||
if (to.mixDuration == 0) // Single frame mix to undo mixingFrom changes.
|
if (to.mixDuration == 0) // Single frame mix to undo mixingFrom changes.
|
||||||
@ -235,26 +238,28 @@ public class AnimationState {
|
|||||||
if (firstFrame) from.timelinesRotation.setSize(timelineCount << 1);
|
if (firstFrame) from.timelinesRotation.setSize(timelineCount << 1);
|
||||||
float[] timelinesRotation = from.timelinesRotation.items;
|
float[] timelinesRotation = from.timelinesRotation.items;
|
||||||
|
|
||||||
boolean first;
|
MixPose pose;
|
||||||
float alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha;
|
float alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha;
|
||||||
from.totalAlpha = 0;
|
from.totalAlpha = 0;
|
||||||
for (int i = 0; i < timelineCount; i++) {
|
for (int i = 0; i < timelineCount; i++) {
|
||||||
Timeline timeline = (Timeline)timelines[i];
|
Timeline timeline = (Timeline)timelines[i];
|
||||||
switch (timelineData[i]) {
|
switch (timelineData[i]) {
|
||||||
case SUBSEQUENT:
|
case SUBSEQUENT:
|
||||||
first = false;
|
if (!attachments && timeline instanceof AttachmentTimeline) continue;
|
||||||
|
if (!drawOrder && timeline instanceof DrawOrderTimeline) continue;
|
||||||
|
pose = currentPose;
|
||||||
alpha = alphaMix;
|
alpha = alphaMix;
|
||||||
break;
|
break;
|
||||||
case FIRST:
|
case FIRST:
|
||||||
first = true;
|
pose = MixPose.setup;
|
||||||
alpha = alphaMix;
|
alpha = alphaMix;
|
||||||
break;
|
break;
|
||||||
case DIP:
|
case DIP:
|
||||||
first = true;
|
pose = MixPose.setup;
|
||||||
alpha = alphaDip;
|
alpha = alphaDip;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
first = true;
|
pose = MixPose.setup;
|
||||||
alpha = alphaDip;
|
alpha = alphaDip;
|
||||||
TrackEntry dipMix = (TrackEntry)timelineDipMix[i];
|
TrackEntry dipMix = (TrackEntry)timelineDipMix[i];
|
||||||
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
||||||
@ -262,14 +267,9 @@ public class AnimationState {
|
|||||||
}
|
}
|
||||||
from.totalAlpha += alpha;
|
from.totalAlpha += alpha;
|
||||||
if (timeline instanceof RotateTimeline)
|
if (timeline instanceof RotateTimeline)
|
||||||
applyRotateTimeline(timeline, skeleton, animationTime, alpha, first, timelinesRotation, i << 1, firstFrame);
|
applyRotateTimeline(timeline, skeleton, animationTime, alpha, pose, timelinesRotation, i << 1, firstFrame);
|
||||||
else {
|
else
|
||||||
if (!first) {
|
timeline.apply(skeleton, animationLast, animationTime, events, alpha, pose, MixDirection.out);
|
||||||
if (!attachments && timeline instanceof AttachmentTimeline) continue;
|
|
||||||
if (!drawOrder && timeline instanceof DrawOrderTimeline) continue;
|
|
||||||
}
|
|
||||||
timeline.apply(skeleton, animationLast, animationTime, events, alpha, first, true);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (to.mixDuration > 0) queueEvents(from, animationTime);
|
if (to.mixDuration > 0) queueEvents(from, animationTime);
|
||||||
@ -280,13 +280,13 @@ public class AnimationState {
|
|||||||
return mix;
|
return mix;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyRotateTimeline (Timeline timeline, Skeleton skeleton, float time, float alpha, boolean setupPose,
|
private void applyRotateTimeline (Timeline timeline, Skeleton skeleton, float time, float alpha, MixPose pose,
|
||||||
float[] timelinesRotation, int i, boolean firstFrame) {
|
float[] timelinesRotation, int i, boolean firstFrame) {
|
||||||
|
|
||||||
if (firstFrame) timelinesRotation[i] = 0;
|
if (firstFrame) timelinesRotation[i] = 0;
|
||||||
|
|
||||||
if (alpha == 1) {
|
if (alpha == 1) {
|
||||||
timeline.apply(skeleton, 0, time, null, 1, setupPose, false);
|
timeline.apply(skeleton, 0, time, null, 1, pose, MixDirection.in);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,7 +294,7 @@ public class AnimationState {
|
|||||||
Bone bone = skeleton.bones.get(rotateTimeline.boneIndex);
|
Bone bone = skeleton.bones.get(rotateTimeline.boneIndex);
|
||||||
float[] frames = rotateTimeline.frames;
|
float[] frames = rotateTimeline.frames;
|
||||||
if (time < frames[0]) { // Time is before first frame.
|
if (time < frames[0]) { // Time is before first frame.
|
||||||
if (setupPose) bone.rotation = bone.data.rotation;
|
if (pose == MixPose.setup) bone.rotation = bone.data.rotation;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,8 +315,8 @@ public class AnimationState {
|
|||||||
r2 -= (16384 - (int)(16384.499999999996 - r2 / 360)) * 360;
|
r2 -= (16384 - (int)(16384.499999999996 - r2 / 360)) * 360;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.
|
// Mix between rotations using the direction of the shortest route on the first frame.
|
||||||
float r1 = setupPose ? bone.data.rotation : bone.rotation;
|
float r1 = pose == MixPose.setup ? bone.data.rotation : bone.rotation;
|
||||||
float total, diff = r2 - r1;
|
float total, diff = r2 - r1;
|
||||||
if (diff == 0)
|
if (diff == 0)
|
||||||
total = timelinesRotation[i];
|
total = timelinesRotation[i];
|
||||||
|
|||||||
@ -35,7 +35,8 @@ import com.esotericsoftware.spine.AnimationState.AnimationStateListener;
|
|||||||
|
|
||||||
/** Stores the current pose values for an {@link Event}.
|
/** Stores the current pose values for an {@link Event}.
|
||||||
* <p>
|
* <p>
|
||||||
* See Timeline {@link Timeline#apply(Skeleton, float, float, com.badlogic.gdx.utils.Array, float, boolean, boolean)},
|
* See Timeline
|
||||||
|
* {@link Timeline#apply(Skeleton, float, float, com.badlogic.gdx.utils.Array, float, com.esotericsoftware.spine.Animation.MixPose, com.esotericsoftware.spine.Animation.MixDirection)},
|
||||||
* AnimationStateListener {@link AnimationStateListener#event(com.esotericsoftware.spine.AnimationState.TrackEntry, Event)}, and
|
* AnimationStateListener {@link AnimationStateListener#event(com.esotericsoftware.spine.AnimationState.TrackEntry, Event)}, and
|
||||||
* <a href="http://esotericsoftware.com/spine-events">Events</a> in the Spine User Guide. */
|
* <a href="http://esotericsoftware.com/spine-events">Events</a> in the Spine User Guide. */
|
||||||
public class Event {
|
public class Event {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user