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 ba17bb8b3..296e1b30a 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java @@ -2072,9 +2072,9 @@ public class Animation { } } - /** Changes a transform constraint's {@link TransformConstraint#getMixRotate()}, {@link TransformConstraint#getMixX()}, - * {@link TransformConstraint#getMixY()}, {@link TransformConstraint#getMixScaleX()}, - * {@link TransformConstraint#getMixScaleY()}, and {@link TransformConstraint#getMixShearY()}. */ + /** Changes a transform constraint's {@link TransformConstraintPose#getMixRotate()}, {@link TransformConstraintPose#getMixX()}, + * {@link TransformConstraintPose#getMixY()}, {@link TransformConstraintPose#getMixScaleX()}, + * {@link TransformConstraintPose#getMixScaleY()}, and {@link TransformConstraintPose#getMixShearY()}. */ static public class TransformConstraintTimeline extends CurveTimeline { static public final int ENTRIES = 7; static private final int ROTATE = 1, X = 2, Y = 3, SCALEX = 4, SCALEY = 5, SHEARY = 6; @@ -2116,27 +2116,27 @@ public class Animation { TransformConstraint constraint = skeleton.transformConstraints.get(constraintIndex); if (!constraint.active) return; - if (appliedPose) constraint = constraint.applied; + TransformConstraintPose pose = appliedPose ? constraint.applied : constraint.pose; float[] frames = this.frames; if (time < frames[0]) { - TransformConstraintData data = constraint.data; + TransformConstraintPose setup = constraint.data.setup; switch (blend) { case setup: - constraint.mixRotate = data.mixRotate; - constraint.mixX = data.mixX; - constraint.mixY = data.mixY; - constraint.mixScaleX = data.mixScaleX; - constraint.mixScaleY = data.mixScaleY; - constraint.mixShearY = data.mixShearY; + pose.mixRotate = setup.mixRotate; + pose.mixX = setup.mixX; + pose.mixY = setup.mixY; + pose.mixScaleX = setup.mixScaleX; + pose.mixScaleY = setup.mixScaleY; + pose.mixShearY = setup.mixShearY; return; case first: - constraint.mixRotate += (data.mixRotate - constraint.mixRotate) * alpha; - constraint.mixX += (data.mixX - constraint.mixX) * alpha; - constraint.mixY += (data.mixY - constraint.mixY) * alpha; - constraint.mixScaleX += (data.mixScaleX - constraint.mixScaleX) * alpha; - constraint.mixScaleY += (data.mixScaleY - constraint.mixScaleY) * alpha; - constraint.mixShearY += (data.mixShearY - constraint.mixShearY) * alpha; + pose.mixRotate += (setup.mixRotate - pose.mixRotate) * alpha; + pose.mixX += (setup.mixX - pose.mixX) * alpha; + pose.mixY += (setup.mixY - pose.mixY) * alpha; + pose.mixScaleX += (setup.mixScaleX - pose.mixScaleX) * alpha; + pose.mixScaleY += (setup.mixScaleY - pose.mixScaleY) * alpha; + pose.mixShearY += (setup.mixShearY - pose.mixShearY) * alpha; } return; } @@ -2178,25 +2178,25 @@ public class Animation { } if (blend == setup) { - TransformConstraintData data = constraint.data; - constraint.mixRotate = data.mixRotate + (rotate - data.mixRotate) * alpha; - constraint.mixX = data.mixX + (x - data.mixX) * alpha; - constraint.mixY = data.mixY + (y - data.mixY) * alpha; - constraint.mixScaleX = data.mixScaleX + (scaleX - data.mixScaleX) * alpha; - constraint.mixScaleY = data.mixScaleY + (scaleY - data.mixScaleY) * alpha; - constraint.mixShearY = data.mixShearY + (shearY - data.mixShearY) * alpha; + TransformConstraintPose setup = constraint.data.setup; + pose.mixRotate = setup.mixRotate + (rotate - setup.mixRotate) * alpha; + pose.mixX = setup.mixX + (x - setup.mixX) * alpha; + pose.mixY = setup.mixY + (y - setup.mixY) * alpha; + pose.mixScaleX = setup.mixScaleX + (scaleX - setup.mixScaleX) * alpha; + pose.mixScaleY = setup.mixScaleY + (scaleY - setup.mixScaleY) * alpha; + pose.mixShearY = setup.mixShearY + (shearY - setup.mixShearY) * alpha; } else { - constraint.mixRotate += (rotate - constraint.mixRotate) * alpha; - constraint.mixX += (x - constraint.mixX) * alpha; - constraint.mixY += (y - constraint.mixY) * alpha; - constraint.mixScaleX += (scaleX - constraint.mixScaleX) * alpha; - constraint.mixScaleY += (scaleY - constraint.mixScaleY) * alpha; - constraint.mixShearY += (shearY - constraint.mixShearY) * alpha; + pose.mixRotate += (rotate - pose.mixRotate) * alpha; + pose.mixX += (x - pose.mixX) * alpha; + pose.mixY += (y - pose.mixY) * alpha; + pose.mixScaleX += (scaleX - pose.mixScaleX) * alpha; + pose.mixScaleY += (scaleY - pose.mixScaleY) * alpha; + pose.mixShearY += (shearY - pose.mixShearY) * alpha; } } } - /** Changes a path constraint's {@link PathConstraint#getPosition()}. */ + /** Changes a path constraint's {@link PathConstraintPose#getPosition()}. */ static public class PathConstraintPositionTimeline extends CurveTimeline1 { final int constraintIndex; @@ -2216,13 +2216,13 @@ public class Animation { PathConstraint constraint = skeleton.pathConstraints.get(constraintIndex); if (constraint.active) { - if (appliedPose) constraint = constraint.applied; - constraint.position = getAbsoluteValue(time, alpha, blend, constraint.position, constraint.data.position); + PathConstraintPose pose = appliedPose ? constraint.applied : constraint.pose; + pose.position = getAbsoluteValue(time, alpha, blend, pose.position, constraint.data.setup.position); } } } - /** Changes a path constraint's {@link PathConstraint#getSpacing()}. */ + /** Changes a path constraint's {@link PathConstraintPose#getSpacing()}. */ static public class PathConstraintSpacingTimeline extends CurveTimeline1 { final int constraintIndex; @@ -2242,14 +2242,14 @@ public class Animation { PathConstraint constraint = skeleton.pathConstraints.get(constraintIndex); if (constraint.active) { - if (appliedPose) constraint = constraint.applied; - constraint.spacing = getAbsoluteValue(time, alpha, blend, constraint.spacing, constraint.data.spacing); + PathConstraintPose pose = appliedPose ? constraint.applied : constraint.pose; + pose.spacing = getAbsoluteValue(time, alpha, blend, pose.spacing, constraint.data.setup.spacing); } } } - /** Changes a path constraint's {@link PathConstraint#getMixRotate()}, {@link PathConstraint#getMixX()}, and - * {@link PathConstraint#getMixY()}. */ + /** Changes a path constraint's {@link PathConstraintPose#getMixRotate()}, {@link PathConstraintPose#getMixX()}, and + * {@link PathConstraintPose#getMixY()}. */ static public class PathConstraintMixTimeline extends CurveTimeline { static public final int ENTRIES = 4; static private final int ROTATE = 1, X = 2, Y = 3; @@ -2287,21 +2287,21 @@ public class Animation { PathConstraint constraint = skeleton.pathConstraints.get(constraintIndex); if (!constraint.active) return; - if (appliedPose) constraint = constraint.applied; + PathConstraintPose pose = appliedPose ? constraint.applied : constraint.pose; float[] frames = this.frames; if (time < frames[0]) { - PathConstraintData data = constraint.data; + PathConstraintPose setup = constraint.data.setup; switch (blend) { case setup: - constraint.mixRotate = data.mixRotate; - constraint.mixX = data.mixX; - constraint.mixY = data.mixY; + pose.mixRotate = setup.mixRotate; + pose.mixX = setup.mixX; + pose.mixY = setup.mixY; return; case first: - constraint.mixRotate += (data.mixRotate - constraint.mixRotate) * alpha; - constraint.mixX += (data.mixX - constraint.mixX) * alpha; - constraint.mixY += (data.mixY - constraint.mixY) * alpha; + pose.mixRotate += (setup.mixRotate - pose.mixRotate) * alpha; + pose.mixX += (setup.mixX - pose.mixX) * alpha; + pose.mixY += (setup.mixY - pose.mixY) * alpha; } return; } @@ -2331,14 +2331,14 @@ public class Animation { } if (blend == setup) { - PathConstraintData data = constraint.data; - constraint.mixRotate = data.mixRotate + (rotate - data.mixRotate) * alpha; - constraint.mixX = data.mixX + (x - data.mixX) * alpha; - constraint.mixY = data.mixY + (y - data.mixY) * alpha; + PathConstraintPose setup = constraint.data.setup; + pose.mixRotate = setup.mixRotate + (rotate - setup.mixRotate) * alpha; + pose.mixX = setup.mixX + (x - setup.mixX) * alpha; + pose.mixY = setup.mixY + (y - setup.mixY) * alpha; } else { - constraint.mixRotate += (rotate - constraint.mixRotate) * alpha; - constraint.mixX += (x - constraint.mixX) * alpha; - constraint.mixY += (y - constraint.mixY) * alpha; + pose.mixRotate += (rotate - pose.mixRotate) * alpha; + pose.mixX += (x - pose.mixX) * alpha; + pose.mixY += (y - pose.mixY) * alpha; } } } @@ -2370,44 +2370,38 @@ public class Animation { for (int i = 0, n = skeleton.physicsConstraints.size; i < n; i++) { constraint = (PhysicsConstraint)constraints[i]; if (constraint.active && global(constraint.data)) { - if (appliedPose) constraint = constraint.applied; - set(constraint, getAbsoluteValue(time, alpha, blend, get(constraint), setup(constraint), value)); + PhysicsConstraintPose pose = appliedPose ? constraint.applied : constraint.pose; + set(pose, getAbsoluteValue(time, alpha, blend, get(pose), get(constraint.data.setup), value)); } } } else { constraint = skeleton.physicsConstraints.get(constraintIndex); if (constraint.active) { - if (appliedPose) constraint = constraint.applied; - set(constraint, getAbsoluteValue(time, alpha, blend, get(constraint), setup(constraint))); + PhysicsConstraintPose pose = appliedPose ? constraint.applied : constraint.pose; + set(pose, getAbsoluteValue(time, alpha, blend, get(pose), get(constraint.data.setup))); } } } - abstract protected float setup (PhysicsConstraint constraint); + abstract protected float get (PhysicsConstraintPose pose); - abstract protected float get (PhysicsConstraint constraint); - - abstract protected void set (PhysicsConstraint constraint, float value); + abstract protected void set (PhysicsConstraintPose pose, float value); abstract protected boolean global (PhysicsConstraintData constraint); } - /** Changes a physics constraint's {@link PhysicsConstraint#getInertia()}. */ + /** Changes a physics constraint's {@link PhysicsConstraintPose#getInertia()}. */ static public class PhysicsConstraintInertiaTimeline extends PhysicsConstraintTimeline { public PhysicsConstraintInertiaTimeline (int frameCount, int bezierCount, int physicsConstraintIndex) { super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintInertia); } - protected float setup (PhysicsConstraint constraint) { - return constraint.data.inertia; + protected float get (PhysicsConstraintPose pose) { + return pose.inertia; } - protected float get (PhysicsConstraint constraint) { - return constraint.inertia; - } - - protected void set (PhysicsConstraint constraint, float value) { - constraint.inertia = value; + protected void set (PhysicsConstraintPose pose, float value) { + pose.inertia = value; } protected boolean global (PhysicsConstraintData constraint) { @@ -2415,22 +2409,18 @@ public class Animation { } } - /** Changes a physics constraint's {@link PhysicsConstraint#getStrength()}. */ + /** Changes a physics constraint's {@link PhysicsConstraintPose#getStrength()}. */ static public class PhysicsConstraintStrengthTimeline extends PhysicsConstraintTimeline { public PhysicsConstraintStrengthTimeline (int frameCount, int bezierCount, int physicsConstraintIndex) { super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintStrength); } - protected float setup (PhysicsConstraint constraint) { - return constraint.data.strength; + protected float get (PhysicsConstraintPose pose) { + return pose.strength; } - protected float get (PhysicsConstraint constraint) { - return constraint.strength; - } - - protected void set (PhysicsConstraint constraint, float value) { - constraint.strength = value; + protected void set (PhysicsConstraintPose pose, float value) { + pose.strength = value; } protected boolean global (PhysicsConstraintData constraint) { @@ -2438,22 +2428,18 @@ public class Animation { } } - /** Changes a physics constraint's {@link PhysicsConstraint#getDamping()}. */ + /** Changes a physics constraint's {@link PhysicsConstraintPose#getDamping()}. */ static public class PhysicsConstraintDampingTimeline extends PhysicsConstraintTimeline { public PhysicsConstraintDampingTimeline (int frameCount, int bezierCount, int physicsConstraintIndex) { super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintDamping); } - protected float setup (PhysicsConstraint constraint) { - return constraint.data.damping; + protected float get (PhysicsConstraintPose pose) { + return pose.damping; } - protected float get (PhysicsConstraint constraint) { - return constraint.damping; - } - - protected void set (PhysicsConstraint constraint, float value) { - constraint.damping = value; + protected void set (PhysicsConstraintPose pose, float value) { + pose.damping = value; } protected boolean global (PhysicsConstraintData constraint) { @@ -2461,22 +2447,18 @@ public class Animation { } } - /** Changes a physics constraint's {@link PhysicsConstraint#getMassInverse()}. The timeline values are not inverted. */ + /** Changes a physics constraint's {@link PhysicsConstraintPose#getMassInverse()}. The timeline values are not inverted. */ static public class PhysicsConstraintMassTimeline extends PhysicsConstraintTimeline { public PhysicsConstraintMassTimeline (int frameCount, int bezierCount, int physicsConstraintIndex) { super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintMass); } - protected float setup (PhysicsConstraint constraint) { - return 1 / constraint.data.massInverse; + protected float get (PhysicsConstraintPose pose) { + return 1 / pose.massInverse; } - protected float get (PhysicsConstraint constraint) { - return 1 / constraint.massInverse; - } - - protected void set (PhysicsConstraint constraint, float value) { - constraint.massInverse = 1 / value; + protected void set (PhysicsConstraintPose pose, float value) { + pose.massInverse = 1 / value; } protected boolean global (PhysicsConstraintData constraint) { @@ -2484,22 +2466,18 @@ public class Animation { } } - /** Changes a physics constraint's {@link PhysicsConstraint#getWind()}. */ + /** Changes a physics constraint's {@link PhysicsConstraintPose#getWind()}. */ static public class PhysicsConstraintWindTimeline extends PhysicsConstraintTimeline { public PhysicsConstraintWindTimeline (int frameCount, int bezierCount, int physicsConstraintIndex) { super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintWind); } - protected float setup (PhysicsConstraint constraint) { - return constraint.data.wind; + protected float get (PhysicsConstraintPose pose) { + return pose.wind; } - protected float get (PhysicsConstraint constraint) { - return constraint.wind; - } - - protected void set (PhysicsConstraint constraint, float value) { - constraint.wind = value; + protected void set (PhysicsConstraintPose pose, float value) { + pose.wind = value; } protected boolean global (PhysicsConstraintData constraint) { @@ -2507,22 +2485,18 @@ public class Animation { } } - /** Changes a physics constraint's {@link PhysicsConstraint#getGravity()}. */ + /** Changes a physics constraint's {@link PhysicsConstraintPose#getGravity()}. */ static public class PhysicsConstraintGravityTimeline extends PhysicsConstraintTimeline { public PhysicsConstraintGravityTimeline (int frameCount, int bezierCount, int physicsConstraintIndex) { super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintGravity); } - protected float setup (PhysicsConstraint constraint) { - return constraint.data.gravity; + protected float get (PhysicsConstraintPose pose) { + return pose.gravity; } - protected float get (PhysicsConstraint constraint) { - return constraint.gravity; - } - - protected void set (PhysicsConstraint constraint, float value) { - constraint.gravity = value; + protected void set (PhysicsConstraintPose pose, float value) { + pose.gravity = value; } protected boolean global (PhysicsConstraintData constraint) { @@ -2530,22 +2504,18 @@ public class Animation { } } - /** Changes a physics constraint's {@link PhysicsConstraint#getMix()}. */ + /** Changes a physics constraint's {@link PhysicsConstraintPose#getMix()}. */ static public class PhysicsConstraintMixTimeline extends PhysicsConstraintTimeline { public PhysicsConstraintMixTimeline (int frameCount, int bezierCount, int physicsConstraintIndex) { super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintMix); } - protected float setup (PhysicsConstraint constraint) { - return constraint.data.mix; + protected float get (PhysicsConstraintPose pose) { + return pose.mix; } - protected float get (PhysicsConstraint constraint) { - return constraint.mix; - } - - protected void set (PhysicsConstraint constraint, float value) { - constraint.mix = value; + protected void set (PhysicsConstraintPose pose, float value) { + pose.mix = value; } protected boolean global (PhysicsConstraintData constraint) { @@ -2601,17 +2571,13 @@ public class Animation { if (time < frames[0]) return; if (lastTime < frames[0] || time >= frames[search(frames, lastTime) + 1]) { - if (constraint != null) { - if (appliedPose) constraint = constraint.applied; + if (constraint != null) constraint.reset(); - } else { + else { Object[] constraints = skeleton.physicsConstraints.items; for (int i = 0, n = skeleton.physicsConstraints.size; i < n; i++) { constraint = (PhysicsConstraint)constraints[i]; - if (constraint.active) { - if (appliedPose) constraint = constraint.applied; - constraint.reset(); - } + if (constraint.active) constraint.reset(); } } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java index 323718227..41c6eb707 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java @@ -63,7 +63,7 @@ public class IkConstraint implements Updatable { /** Copy constructor. */ public IkConstraint (IkConstraint constraint, Skeleton skeleton) { this(constraint.data, skeleton); - setupPose(); + pose.set(constraint.pose); } public void setupPose () { @@ -72,15 +72,15 @@ public class IkConstraint implements Updatable { /** Applies the constraint to the constrained bones. */ public void update (Physics physics) { - IkConstraintPose pose = applied; - if (pose.mix == 0) return; + IkConstraintPose a = applied; + if (a.mix == 0) return; BoneApplied target = this.target; Object[] bones = this.bones.items; switch (this.bones.size) { - case 1 -> apply((BoneApplied)bones[0], target.worldX, target.worldY, pose.compress, pose.stretch, data.uniform, pose.mix); + case 1 -> apply((BoneApplied)bones[0], target.worldX, target.worldY, a.compress, a.stretch, data.uniform, a.mix); case 2 -> // - apply((BoneApplied)bones[0], (BoneApplied)bones[1], target.worldX, target.worldY, pose.bendDirection, pose.stretch, - data.uniform, pose.softness, pose.mix); + apply((BoneApplied)bones[0], (BoneApplied)bones[1], target.worldX, target.worldY, a.bendDirection, a.stretch, + data.uniform, a.softness, a.mix); } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java index f04a5f9a2..81ea32789 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java @@ -35,15 +35,19 @@ import com.badlogic.gdx.utils.Array; *
* See IK constraints in the Spine User Guide. */
public class IkConstraintData extends ConstraintData {
+ final IkConstraintPose setup = new IkConstraintPose();
final Array
* See Path constraints in the Spine User Guide. */
public class PathConstraintData extends ConstraintData {
+ final PathConstraintPose setup = new PathConstraintPose();
final Array
* See Position mode in the Spine User
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintPose.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintPose.java
new file mode 100644
index 000000000..e21293f90
--- /dev/null
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintPose.java
@@ -0,0 +1,88 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated April 5, 2025. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2025, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "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 SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) 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
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+package com.esotericsoftware.spine;
+
+/** Stores a pose for a path constraint. */
+public class PathConstraintPose {
+ float position, spacing, mixRotate, mixX, mixY;
+
+ public void set (PathConstraintPose pose) {
+ position = pose.position;
+ spacing = pose.spacing;
+ mixRotate = pose.mixRotate;
+ mixX = pose.mixX;
+ mixY = pose.mixY;
+ }
+
+ /** The position along the path. */
+ public float getPosition () {
+ return position;
+ }
+
+ public void setPosition (float position) {
+ this.position = position;
+ }
+
+ /** The spacing between bones. */
+ public float getSpacing () {
+ return spacing;
+ }
+
+ public void setSpacing (float spacing) {
+ this.spacing = spacing;
+ }
+
+ /** A percentage (0-1) that controls the mix between the constrained and unconstrained rotation. */
+ public float getMixRotate () {
+ return mixRotate;
+ }
+
+ public void setMixRotate (float mixRotate) {
+ this.mixRotate = mixRotate;
+ }
+
+ /** A percentage (0-1) that controls the mix between the constrained and unconstrained translation X. */
+ public float getMixX () {
+ return mixX;
+ }
+
+ public void setMixX (float mixX) {
+ this.mixX = mixX;
+ }
+
+ /** A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y. */
+ public float getMixY () {
+ return mixY;
+ }
+
+ public void setMixY (float mixY) {
+ this.mixY = mixY;
+ }
+}
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java
index 09a0ebcd5..8fa8b0cbc 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java
@@ -38,11 +38,9 @@ public class PhysicsConstraint implements Updatable {
final PhysicsConstraintData data;
final Skeleton skeleton;
BoneApplied bone;
- PhysicsConstraint applied;
+ final PhysicsConstraintPose pose = new PhysicsConstraintPose(), applied = new PhysicsConstraintPose();
boolean active;
- float inertia, strength, damping, massInverse, wind, gravity, mix;
-
boolean reset = true;
float ux, uy, cx, cy, tx, ty;
float xOffset, xVelocity;
@@ -65,15 +63,13 @@ public class PhysicsConstraint implements Updatable {
bone = skeleton.bones.get(data.bone.index).applied;
- applied = new PhysicsConstraint(data, skeleton, bone);
-
setupPose();
}
/** Copy constructor. */
public PhysicsConstraint (PhysicsConstraint constraint, Skeleton skeleton) {
this(constraint.data, skeleton);
- setupPose();
+ pose.set(constraint.pose);
}
public void reset () {
@@ -91,14 +87,7 @@ public class PhysicsConstraint implements Updatable {
}
public void setupPose () {
- PhysicsConstraintData data = this.data;
- inertia = data.inertia;
- strength = data.strength;
- damping = data.damping;
- massInverse = data.massInverse;
- wind = data.wind;
- gravity = data.gravity;
- mix = data.mix;
+ pose.set(data.setup);
}
/** Translates the physics constraint so next {@link #update(Physics)} forces are applied as if the bone moved an additional
@@ -120,7 +109,8 @@ public class PhysicsConstraint implements Updatable {
/** Applies the constraint to the constrained bones. */
public void update (Physics physics) {
- float mix = this.mix;
+ PhysicsConstraintPose pose = applied;
+ float mix = pose.mix;
if (mix == 0) return;
boolean x = data.x > 0, y = data.y > 0, rotateOrShearX = data.rotate > 0 || data.shearX > 0, scaleX = data.scaleX > 0;
@@ -145,7 +135,7 @@ public class PhysicsConstraint implements Updatable {
ux = bx;
uy = by;
} else {
- float a = remaining, i = inertia, t = data.step, f = skeleton.data.referenceScale, d = -1;
+ float a = remaining, i = pose.inertia, t = data.step, f = skeleton.data.referenceScale, d = -1;
float qx = data.limit * delta, qy = qx * Math.abs(skeleton.scaleY);
qx *= Math.abs(skeleton.scaleX);
if (x || y) {
@@ -160,8 +150,9 @@ public class PhysicsConstraint implements Updatable {
uy = by;
}
if (a >= t) {
- d = (float)Math.pow(damping, 60 * t);
- float m = massInverse * t, e = strength, w = wind * f * skeleton.scaleX, g = gravity * f * skeleton.scaleY;
+ d = (float)Math.pow(pose.damping, 60 * t);
+ float m = pose.massInverse * t, e = pose.strength, w = pose.wind * f * skeleton.scaleX,
+ g = pose.gravity * f * skeleton.scaleY;
do {
if (x) {
xVelocity += (w - xOffset * e) * m;
@@ -209,8 +200,8 @@ public class PhysicsConstraint implements Updatable {
}
a = remaining;
if (a >= t) {
- if (d == -1) d = (float)Math.pow(damping, 60 * t);
- float m = massInverse * t, e = strength, w = wind, g = gravity, h = l / f;
+ if (d == -1) d = (float)Math.pow(pose.damping, 60 * t);
+ float m = pose.massInverse * t, e = pose.strength, w = pose.wind, g = pose.gravity, h = l / f;
while (true) {
a -= t;
if (scaleX) {
@@ -283,6 +274,15 @@ public class PhysicsConstraint implements Updatable {
bone.updateLocalTransform();
}
+ /** The physics constraint's setup pose data. */
+ public PhysicsConstraintData getData () {
+ return data;
+ }
+
+ public Skeleton getSkeleton () {
+ return skeleton;
+ }
+
/** The bone constrained by this physics constraint. */
public BoneApplied getBone () {
return bone;
@@ -292,61 +292,12 @@ public class PhysicsConstraint implements Updatable {
this.bone = bone;
}
- public float getInertia () {
- return inertia;
+ public PhysicsConstraintPose getPose () {
+ return pose;
}
- public void setInertia (float inertia) {
- this.inertia = inertia;
- }
-
- public float getStrength () {
- return strength;
- }
-
- public void setStrength (float strength) {
- this.strength = strength;
- }
-
- public float getDamping () {
- return damping;
- }
-
- public void setDamping (float damping) {
- this.damping = damping;
- }
-
- public float getMassInverse () {
- return massInverse;
- }
-
- public void setMassInverse (float massInverse) {
- this.massInverse = massInverse;
- }
-
- public float getWind () {
- return wind;
- }
-
- public void setWind (float wind) {
- this.wind = wind;
- }
-
- public float getGravity () {
- return gravity;
- }
-
- public void setGravity (float gravity) {
- this.gravity = gravity;
- }
-
- /** A percentage (0-1) that controls the mix between the constrained and unconstrained poses. */
- public float getMix () {
- return mix;
- }
-
- public void setMix (float mix) {
- this.mix = mix;
+ public PhysicsConstraintPose getAppliedPose () {
+ return applied;
}
/** Returns false when this constraint won't be updated by
@@ -360,11 +311,6 @@ public class PhysicsConstraint implements Updatable {
return active;
}
- /** The physics constraint's setup pose data. */
- public PhysicsConstraintData getData () {
- return data;
- }
-
public String toString () {
return data.name;
}
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraintData.java
index ec78e64ed..9ee259251 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraintData.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraintData.java
@@ -33,15 +33,19 @@ package com.esotericsoftware.spine;
*
* See Physics constraints in the Spine User Guide. */
public class PhysicsConstraintData extends ConstraintData {
+ final PhysicsConstraintPose setup = new PhysicsConstraintPose();
BoneData bone;
- float x, y, rotate, scaleX, shearX, limit;
- float step, inertia, strength, damping, massInverse, wind, gravity, mix;
+ float x, y, rotate, scaleX, shearX, limit, step;
boolean inertiaGlobal, strengthGlobal, dampingGlobal, massGlobal, windGlobal, gravityGlobal, mixGlobal;
public PhysicsConstraintData (String name) {
super(name);
}
+ public PhysicsConstraintPose getSetupPose () {
+ return setup;
+ }
+
/** The bone constrained by this physics constraint. */
public BoneData getBone () {
return bone;
@@ -107,63 +111,6 @@ public class PhysicsConstraintData extends ConstraintData {
this.limit = limit;
}
- public float getInertia () {
- return inertia;
- }
-
- public void setInertia (float inertia) {
- this.inertia = inertia;
- }
-
- public float getStrength () {
- return strength;
- }
-
- public void setStrength (float strength) {
- this.strength = strength;
- }
-
- public float getDamping () {
- return damping;
- }
-
- public void setDamping (float damping) {
- this.damping = damping;
- }
-
- public float getMassInverse () {
- return massInverse;
- }
-
- public void setMassInverse (float massInverse) {
- this.massInverse = massInverse;
- }
-
- public float getWind () {
- return wind;
- }
-
- public void setWind (float wind) {
- this.wind = wind;
- }
-
- public float getGravity () {
- return gravity;
- }
-
- public void setGravity (float gravity) {
- this.gravity = gravity;
- }
-
- /** A percentage (0-1) that controls the mix between the constrained and unconstrained poses. */
- public float getMix () {
- return mix;
- }
-
- public void setMix (float mix) {
- this.mix = mix;
- }
-
public boolean getInertiaGlobal () {
return inertiaGlobal;
}
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraintPose.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraintPose.java
new file mode 100644
index 000000000..2bf89ecc4
--- /dev/null
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraintPose.java
@@ -0,0 +1,102 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated April 5, 2025. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2025, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "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 SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) 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
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+package com.esotericsoftware.spine;
+
+/** Stores a pose for a physics constraint. */
+public class PhysicsConstraintPose {
+ float inertia, strength, damping, massInverse, wind, gravity, mix;
+
+ public void set (PhysicsConstraintPose pose) {
+ inertia = pose.inertia;
+ strength = pose.strength;
+ damping = pose.damping;
+ massInverse = pose.massInverse;
+ wind = pose.wind;
+ gravity = pose.gravity;
+ mix = pose.mix;
+ }
+
+ public float getInertia () {
+ return inertia;
+ }
+
+ public void setInertia (float inertia) {
+ this.inertia = inertia;
+ }
+
+ public float getStrength () {
+ return strength;
+ }
+
+ public void setStrength (float strength) {
+ this.strength = strength;
+ }
+
+ public float getDamping () {
+ return damping;
+ }
+
+ public void setDamping (float damping) {
+ this.damping = damping;
+ }
+
+ public float getMassInverse () {
+ return massInverse;
+ }
+
+ public void setMassInverse (float massInverse) {
+ this.massInverse = massInverse;
+ }
+
+ public float getWind () {
+ return wind;
+ }
+
+ public void setWind (float wind) {
+ this.wind = wind;
+ }
+
+ public float getGravity () {
+ return gravity;
+ }
+
+ public void setGravity (float gravity) {
+ this.gravity = gravity;
+ }
+
+ /** A percentage (0-1) that controls the mix between the constrained and unconstrained poses. */
+ public float getMix () {
+ return mix;
+ }
+
+ public void setMix (float mix) {
+ this.mix = mix;
+ }
+}
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java
index 434f0081c..9e6c63040 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java
@@ -38,7 +38,6 @@ import com.badlogic.gdx.utils.FloatArray;
import com.badlogic.gdx.utils.Null;
import com.esotericsoftware.spine.Animation.BoneTimeline;
-import com.esotericsoftware.spine.Animation.Timeline;
import com.esotericsoftware.spine.Skin.SkinEntry;
import com.esotericsoftware.spine.attachments.Attachment;
import com.esotericsoftware.spine.attachments.ClippingAttachment;
@@ -256,21 +255,24 @@ public class Skeleton {
constraint.active = !constraint.data.skinRequired || (skin != null && skin.constraints.contains(constraint.data, true));
if (!constraint.active) return;
+ Object[] timelines = constraint.data.animation.timelines.items;
+ int timelineCount = constraint.data.animation.timelines.size;
+
Object[] bones = this.bones.items;
- for (Timeline timeline : constraint.animation.timelines)
- if (timeline instanceof BoneTimeline boneTimeline) sortBone((Bone)bones[boneTimeline.getBoneIndex()]);
+ for (int i = 0; i < timelineCount; i++)
+ if (timelines[i] instanceof BoneTimeline boneTimeline) sortBone((Bone)bones[boneTimeline.getBoneIndex()]);
updateCache.add(constraint);
- for (Timeline timeline : constraint.animation.timelines) {
- if (timeline instanceof BoneTimeline boneTimeline) {
+ for (int i = 0; i < timelineCount; i++) {
+ if (timelines[i] instanceof BoneTimeline boneTimeline) {
var bone = (Bone)bones[boneTimeline.getBoneIndex()];
sortReset(bone.children);
bone.sorted = false;
}
}
- for (Timeline timeline : constraint.animation.timelines)
- if (timeline instanceof BoneTimeline boneTimeline) sortBone((Bone)bones[boneTimeline.getBoneIndex()]);
+ for (int i = 0; i < timelineCount; i++)
+ if (timelines[i] instanceof BoneTimeline boneTimeline) sortBone((Bone)bones[boneTimeline.getBoneIndex()]);
}
private void sortIkConstraint (IkConstraint constraint) {
@@ -347,9 +349,9 @@ public class Skeleton {
updateCache.add(constraint);
for (int i = 0; i < boneCount; i++)
- sortReset(((Bone)constrained[i]).children);
+ sortReset(((BoneApplied)constrained[i]).bone.children);
for (int i = 0; i < boneCount; i++)
- ((Bone)constrained[i]).sorted = true;
+ ((BoneApplied)constrained[i]).bone.sorted = true;
}
private void sortPathConstraintAttachment (Skin skin, int slotIndex, Bone slotBone) {
@@ -371,7 +373,7 @@ public class Skeleton {
int nn = pathBones[i++];
nn += i;
while (i < nn)
- sortBone(((BoneApplied)bones[pathBones[i++]]).bone);
+ sortBone((Bone)bones[pathBones[i++]]);
}
}
}
@@ -428,8 +430,26 @@ public class Skeleton {
var constraint = (IkConstraint)objects[i];
if (constraint.active) constraint.applied.set(constraint.pose);
}
-
- // BOZO! - Reset the rest.
+ objects = pathConstraints.items;
+ for (int i = 0, n = pathConstraints.size; i < n; i++) {
+ var constraint = (PathConstraint)objects[i];
+ if (constraint.active) constraint.applied.set(constraint.pose);
+ }
+ objects = transformConstraints.items;
+ for (int i = 0, n = transformConstraints.size; i < n; i++) {
+ var constraint = (TransformConstraint)objects[i];
+ if (constraint.active) constraint.applied.set(constraint.pose);
+ }
+ objects = physicsConstraints.items;
+ for (int i = 0, n = physicsConstraints.size; i < n; i++) {
+ var constraint = (PhysicsConstraint)objects[i];
+ if (constraint.active) constraint.applied.set(constraint.pose);
+ }
+ objects = sliders.items;
+ for (int i = 0, n = sliders.size; i < n; i++) {
+ var constraint = (Slider)objects[i];
+ if (constraint.active) constraint.applied.set(constraint.pose);
+ }
Object[] updateCache = this.updateCache.items;
for (int i = 0, n = this.updateCache.size; i < n; i++)
@@ -444,12 +464,41 @@ public class Skeleton {
public void updateWorldTransform (Physics physics, BoneApplied parent) {
if (parent == null) throw new IllegalArgumentException("parent cannot be null.");
- Object[] bones = this.bones.items;
- for (int i = 1, n = this.bones.size; i < n; i++) { // Skip root bone.
- var bone = (Bone)bones[i];
+ Object[] objects = this.bones.items;
+ for (int i = 0, n = this.bones.size; i < n; i++) {
+ var bone = (Bone)objects[i];
if (bone.active) bone.applied.set(bone.pose);
}
- // BOZO! - Reset the rest.
+ objects = this.slots.items;
+ for (int i = 0, n = this.slots.size; i < n; i++) {
+ var slot = (Slot)objects[i];
+ if (slot.bone.active) slot.applied.set(slot.pose);
+ }
+ objects = ikConstraints.items;
+ for (int i = 0, n = ikConstraints.size; i < n; i++) {
+ var constraint = (IkConstraint)objects[i];
+ if (constraint.active) constraint.applied.set(constraint.pose);
+ }
+ objects = pathConstraints.items;
+ for (int i = 0, n = pathConstraints.size; i < n; i++) {
+ var constraint = (PathConstraint)objects[i];
+ if (constraint.active) constraint.applied.set(constraint.pose);
+ }
+ objects = transformConstraints.items;
+ for (int i = 0, n = transformConstraints.size; i < n; i++) {
+ var constraint = (TransformConstraint)objects[i];
+ if (constraint.active) constraint.applied.set(constraint.pose);
+ }
+ objects = physicsConstraints.items;
+ for (int i = 0, n = physicsConstraints.size; i < n; i++) {
+ var constraint = (PhysicsConstraint)objects[i];
+ if (constraint.active) constraint.applied.set(constraint.pose);
+ }
+ objects = sliders.items;
+ for (int i = 0, n = sliders.size; i < n; i++) {
+ var constraint = (Slider)objects[i];
+ if (constraint.active) constraint.applied.set(constraint.pose);
+ }
// Apply the parent bone transform to the root bone. The root bone always inherits scale, rotation and reflection.
BoneApplied rootBone = getRootBone().applied;
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java
index b25b6d930..ac72e6884 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java
@@ -343,12 +343,13 @@ public class SkeletonBinary extends SkeletonLoader {
if ((flags & 16) != 0) data.offsetScaleY = input.readFloat();
if ((flags & 32) != 0) data.offsetShearY = input.readFloat();
flags = input.read();
- if ((flags & 1) != 0) data.mixRotate = input.readFloat();
- if ((flags & 2) != 0) data.mixX = input.readFloat();
- if ((flags & 4) != 0) data.mixY = input.readFloat();
- if ((flags & 8) != 0) data.mixScaleX = input.readFloat();
- if ((flags & 16) != 0) data.mixScaleY = input.readFloat();
- if ((flags & 32) != 0) data.mixShearY = input.readFloat();
+ TransformConstraintPose setup = data.getSetupPose();
+ if ((flags & 1) != 0) setup.mixRotate = input.readFloat();
+ if ((flags & 2) != 0) setup.mixX = input.readFloat();
+ if ((flags & 4) != 0) setup.mixY = input.readFloat();
+ if ((flags & 8) != 0) setup.mixScaleX = input.readFloat();
+ if ((flags & 16) != 0) setup.mixScaleY = input.readFloat();
+ if ((flags & 32) != 0) setup.mixShearY = input.readFloat();
o[i] = data;
}
@@ -367,13 +368,14 @@ public class SkeletonBinary extends SkeletonLoader {
data.spacingMode = SpacingMode.values[(flags >> 1) & 3];
data.rotateMode = RotateMode.values[(flags >> 3) & 3];
if ((flags & 128) != 0) data.offsetRotation = input.readFloat();
- data.position = input.readFloat();
- if (data.positionMode == PositionMode.fixed) data.position *= scale;
- data.spacing = input.readFloat();
- if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) data.spacing *= scale;
- data.mixRotate = input.readFloat();
- data.mixX = input.readFloat();
- data.mixY = input.readFloat();
+ PathConstraintPose setup = data.setup;
+ setup.position = input.readFloat();
+ if (data.positionMode == PositionMode.fixed) setup.position *= scale;
+ setup.spacing = input.readFloat();
+ if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) setup.spacing *= scale;
+ setup.mixRotate = input.readFloat();
+ setup.mixX = input.readFloat();
+ setup.mixY = input.readFloat();
o[i] = data;
}
@@ -392,12 +394,13 @@ public class SkeletonBinary extends SkeletonLoader {
if ((flags & 32) != 0) data.shearX = input.readFloat();
data.limit = ((flags & 64) != 0 ? input.readFloat() : 5000) * scale;
data.step = 1f / input.readUnsignedByte();
- data.inertia = input.readFloat();
- data.strength = input.readFloat();
- data.damping = input.readFloat();
- data.massInverse = (flags & 128) != 0 ? input.readFloat() : 1;
- data.wind = input.readFloat();
- data.gravity = input.readFloat();
+ PhysicsConstraintPose setup = data.getSetupPose();
+ setup.inertia = input.readFloat();
+ setup.strength = input.readFloat();
+ setup.damping = input.readFloat();
+ setup.massInverse = (flags & 128) != 0 ? input.readFloat() : 1;
+ setup.wind = input.readFloat();
+ setup.gravity = input.readFloat();
flags = input.read();
if ((flags & 1) != 0) data.inertiaGlobal = true;
if ((flags & 2) != 0) data.strengthGlobal = true;
@@ -406,7 +409,7 @@ public class SkeletonBinary extends SkeletonLoader {
if ((flags & 16) != 0) data.windGlobal = true;
if ((flags & 32) != 0) data.gravityGlobal = true;
if ((flags & 64) != 0) data.mixGlobal = true;
- data.mix = (flags & 128) != 0 ? input.readFloat() : 1;
+ setup.mix = (flags & 128) != 0 ? input.readFloat() : 1;
o[i] = data;
}
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java
index 17fad77cb..e944bcb55 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java
@@ -330,12 +330,13 @@ public class SkeletonJson extends SkeletonLoader {
data.offsetScaleY = constraintMap.getFloat("scaleY", 0);
data.offsetShearY = constraintMap.getFloat("shearY", 0);
- if (rotate) data.mixRotate = constraintMap.getFloat("mixRotate", 1);
- if (x) data.mixX = constraintMap.getFloat("mixX", 1);
- if (y) data.mixY = constraintMap.getFloat("mixY", data.mixX);
- if (scaleX) data.mixScaleX = constraintMap.getFloat("mixScaleX", 1);
- if (scaleY) data.mixScaleY = constraintMap.getFloat("mixScaleY", data.mixScaleX);
- if (shearY) data.mixShearY = constraintMap.getFloat("mixShearY", 1);
+ TransformConstraintPose setup = data.setup;
+ if (rotate) setup.mixRotate = constraintMap.getFloat("mixRotate", 1);
+ if (x) setup.mixX = constraintMap.getFloat("mixX", 1);
+ if (y) setup.mixY = constraintMap.getFloat("mixY", setup.mixX);
+ if (scaleX) setup.mixScaleX = constraintMap.getFloat("mixScaleX", 1);
+ if (scaleY) setup.mixScaleY = constraintMap.getFloat("mixScaleY", setup.mixScaleX);
+ if (shearY) setup.mixShearY = constraintMap.getFloat("mixShearY", 1);
skeletonData.transformConstraints.add(data);
}
@@ -360,13 +361,14 @@ public class SkeletonJson extends SkeletonLoader {
data.spacingMode = SpacingMode.valueOf(constraintMap.getString("spacingMode", "length"));
data.rotateMode = RotateMode.valueOf(constraintMap.getString("rotateMode", "tangent"));
data.offsetRotation = constraintMap.getFloat("rotation", 0);
- data.position = constraintMap.getFloat("position", 0);
- if (data.positionMode == PositionMode.fixed) data.position *= scale;
- data.spacing = constraintMap.getFloat("spacing", 0);
- if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) data.spacing *= scale;
- data.mixRotate = constraintMap.getFloat("mixRotate", 1);
- data.mixX = constraintMap.getFloat("mixX", 1);
- data.mixY = constraintMap.getFloat("mixY", 1);
+ PathConstraintPose setup = data.setup;
+ setup.position = constraintMap.getFloat("position", 0);
+ if (data.positionMode == PositionMode.fixed) setup.position *= scale;
+ setup.spacing = constraintMap.getFloat("spacing", 0);
+ if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) setup.spacing *= scale;
+ setup.mixRotate = constraintMap.getFloat("mixRotate", 1);
+ setup.mixX = constraintMap.getFloat("mixX", 1);
+ setup.mixY = constraintMap.getFloat("mixY", 1);
skeletonData.pathConstraints.add(data);
}
@@ -388,13 +390,14 @@ public class SkeletonJson extends SkeletonLoader {
data.shearX = constraintMap.getFloat("shearX", 0);
data.limit = constraintMap.getFloat("limit", 5000) * scale;
data.step = 1f / constraintMap.getInt("fps", 60);
- data.inertia = constraintMap.getFloat("inertia", 1);
- data.strength = constraintMap.getFloat("strength", 100);
- data.damping = constraintMap.getFloat("damping", 1);
- data.massInverse = 1 / constraintMap.getFloat("mass", 1);
- data.wind = constraintMap.getFloat("wind", 0);
- data.gravity = constraintMap.getFloat("gravity", 0);
- data.mix = constraintMap.getFloat("mix", 1);
+ PhysicsConstraintPose setup = data.getSetupPose();
+ setup.inertia = constraintMap.getFloat("inertia", 1);
+ setup.strength = constraintMap.getFloat("strength", 100);
+ setup.damping = constraintMap.getFloat("damping", 1);
+ setup.massInverse = 1 / constraintMap.getFloat("mass", 1);
+ setup.wind = constraintMap.getFloat("wind", 0);
+ setup.gravity = constraintMap.getFloat("gravity", 0);
+ setup.mix = constraintMap.getFloat("mix", 1);
data.inertiaGlobal = constraintMap.getBoolean("inertiaGlobal", false);
data.strengthGlobal = constraintMap.getBoolean("strengthGlobal", false);
data.dampingGlobal = constraintMap.getBoolean("dampingGlobal", false);
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slider.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slider.java
index f1912ab49..0dfcbdf31 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slider.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slider.java
@@ -38,8 +38,7 @@ import com.esotericsoftware.spine.Animation.MixDirection;
public class Slider implements Updatable {
final SliderData data;
final Skeleton skeleton;
- Animation animation;
- float time, mix;
+ final SliderPose pose = new SliderPose(), applied = new SliderPose();
boolean active;
@@ -59,14 +58,20 @@ public class Slider implements Updatable {
}
public void update (Physics physics) {
- animation.apply(skeleton, time, time, false, null, mix, MixBlend.replace, MixDirection.in, true);
+ SliderPose pose = applied;
+ data.animation.apply(skeleton, pose.time, pose.time, false, null, pose.mix, MixBlend.replace, MixDirection.in, true);
}
public void setupPose () {
- SliderData data = this.data;
- animation = data.animation;
- time = data.time;
- mix = data.mix;
+ pose.set(data.setup);
+ }
+
+ public SliderPose getPose () {
+ return pose;
+ }
+
+ public SliderPose getAppliedPose () {
+ return applied;
}
/** Returns false when this constraint won't be updated by
@@ -80,27 +85,7 @@ public class Slider implements Updatable {
return active;
}
- public Animation getAnimation () {
- return animation;
- }
-
- public void setAnimation (Animation animation) {
- this.animation = animation;
- }
-
- public float getTime () {
- return time;
- }
-
- public void setTime (float time) {
- this.time = time;
- }
-
- public float getMix () {
- return mix;
- }
-
- public void setMix (float mix) {
- this.mix = mix;
+ public String toString () {
+ return data.name;
}
}
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SliderData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SliderData.java
index 321a11d62..38f91740b 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SliderData.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SliderData.java
@@ -33,13 +33,17 @@ package com.esotericsoftware.spine;
*
* See Physics constraints in the Spine User Guide. */
public class SliderData extends ConstraintData {
+ final SliderPose setup = new SliderPose();
Animation animation;
- float time, mix;
public SliderData (String name) {
super(name);
}
+ public SliderPose getSetupPose () {
+ return setup;
+ }
+
public Animation getAnimation () {
return animation;
}
@@ -47,20 +51,4 @@ public class SliderData extends ConstraintData {
public void setAnimation (Animation animation) {
this.animation = animation;
}
-
- public float getTime () {
- return time;
- }
-
- public void setTime (float time) {
- this.time = time;
- }
-
- public float getMix () {
- return mix;
- }
-
- public void setMix (float mix) {
- this.mix = mix;
- }
}
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SliderPose.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SliderPose.java
new file mode 100644
index 000000000..b613f6d3c
--- /dev/null
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SliderPose.java
@@ -0,0 +1,57 @@
+/******************************************************************************
+ * Spine Runtimes License Agreement
+ * Last updated April 5, 2025. Replaces all prior versions.
+ *
+ * Copyright (c) 2013-2025, Esoteric Software LLC
+ *
+ * Integration of the Spine Runtimes into software or otherwise creating
+ * derivative works of the Spine Runtimes is permitted under the terms and
+ * conditions of Section 2 of the Spine Editor License Agreement:
+ * http://esotericsoftware.com/spine-editor-license
+ *
+ * Otherwise, it is permitted to integrate the Spine Runtimes into software
+ * or otherwise create derivative works of the Spine Runtimes (collectively,
+ * "Products"), provided that each user of the Products must obtain their own
+ * Spine Editor license and redistribution of the Products in any form must
+ * include this license and copyright notice.
+ *
+ * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "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 SOFTWARE LLC BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
+ * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) 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
+ * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *****************************************************************************/
+
+package com.esotericsoftware.spine;
+
+/** Stores a pose for a slider. */
+public class SliderPose {
+ float time, mix;
+
+ public void set (SliderPose pose) {
+ time = pose.time;
+ mix = pose.mix;
+ }
+
+
+ public float getTime () {
+ return time;
+ }
+
+ public void setTime (float time) {
+ this.time = time;
+ }
+
+ public float getMix () {
+ return mix;
+ }
+
+ public void setMix (float mix) {
+ this.mix = mix;
+ }
+}
diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java
index 813eb1688..6e2692e8e 100644
--- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java
+++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java
@@ -44,11 +44,9 @@ public class TransformConstraint implements Updatable {
final TransformConstraintData data;
final Array
* See Transform constraints in the Spine User Guide. */
public class TransformConstraintData extends ConstraintData {
+ final TransformConstraintPose setup = new TransformConstraintPose();
final Array