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 bones = new Array(); BoneData target; - final IkConstraintPose setup = new IkConstraintPose(); boolean uniform; public IkConstraintData (String name) { super(name); } + public IkConstraintPose getSetupPose () { + return setup; + } + /** The bones that are constrained by this IK constraint. */ public Array getBones () { return bones; @@ -59,10 +63,6 @@ public class IkConstraintData extends ConstraintData { this.target = target; } - public IkConstraintPose getSetupPose () { - return setup; - } - /** When true and {@link IkConstraintPose#getCompress()} or {@link IkConstraintPose#getStretch()} is used, the bone is scaled * on both the X and Y axes. */ public boolean getUniform () { diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java index cd6dc4239..aa0b7e33f 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java @@ -52,11 +52,9 @@ public class PathConstraint implements Updatable { final PathConstraintData data; final Array bones; Slot slot; - PathConstraint applied; + final PathConstraintPose pose = new PathConstraintPose(), applied = new PathConstraintPose(); boolean active; - float position, spacing, mixRotate, mixX, mixY; - private final FloatArray spaces = new FloatArray(), positions = new FloatArray(); private final FloatArray world = new FloatArray(), curves = new FloatArray(), lengths = new FloatArray(); private final float[] segments = new float[10]; @@ -78,31 +76,25 @@ public class PathConstraint implements Updatable { slot = skeleton.slots.get(data.slot.index); - applied = new PathConstraint(data, bones, slot); - setupPose(); } /** Copy constructor. */ public PathConstraint (PathConstraint constraint, Skeleton skeleton) { this(constraint.data, skeleton); - setupPose(); + pose.set(constraint.pose); } public void setupPose () { - PathConstraintData data = this.data; - position = data.position; - spacing = data.spacing; - mixRotate = data.mixRotate; - mixX = data.mixX; - mixY = data.mixY; + pose.set(data.setup); } /** Applies the constraint to the constrained bones. */ public void update (Physics physics) { if (!(slot.applied.attachment instanceof PathAttachment pathAttachment)) return; - float mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY; + PathConstraintPose pose = applied; + float mixRotate = pose.mixRotate, mixX = pose.mixX, mixY = pose.mixY; if (mixRotate == 0 && mixX == 0 && mixY == 0) return; PathConstraintData data = this.data; @@ -110,7 +102,7 @@ public class PathConstraint implements Updatable { int boneCount = this.bones.size, spacesCount = tangents ? boneCount : boneCount + 1; Object[] bones = this.bones.items; float[] spaces = this.spaces.setSize(spacesCount), lengths = scale ? this.lengths.setSize(boneCount) : null; - float spacing = this.spacing; + float spacing = pose.spacing; switch (data.spacingMode) { case percent -> { @@ -224,7 +216,7 @@ public class PathConstraint implements Updatable { float[] computeWorldPositions (PathAttachment path, int spacesCount, boolean tangents) { Slot slot = this.slot; - float position = this.position; + float position = applied.position; float[] spaces = this.spaces.items, out = this.positions.setSize(spacesCount * 3 + 2), world; boolean closed = path.getClosed(); int verticesLength = path.getWorldVerticesLength(), curveCount = verticesLength / 6, prevCurve = NONE; @@ -480,51 +472,6 @@ public class PathConstraint implements Updatable { } } - /** 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; - } - /** The bones that will be modified by this path constraint. */ public Array getBones () { return bones; @@ -540,6 +487,14 @@ public class PathConstraint implements Updatable { this.slot = slot; } + public PathConstraintPose getPose () { + return pose; + } + + public PathConstraintPose getAppliedPose () { + return applied; + } + /** Returns false when this constraint won't be updated by * {@link Skeleton#updateWorldTransform(com.esotericsoftware.spine.Physics)} because a skin is required and the * {@link Skeleton#getSkin() active skin} does not contain this item. diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java index 6285c1fad..455a40672 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraintData.java @@ -35,18 +35,22 @@ import com.badlogic.gdx.utils.Array; *

* See Path constraints in the Spine User Guide. */ public class PathConstraintData extends ConstraintData { + final PathConstraintPose setup = new PathConstraintPose(); final Array bones = new Array(); SlotData slot; PositionMode positionMode; SpacingMode spacingMode; RotateMode rotateMode; float offsetRotation; - float position, spacing, mixRotate, mixX, mixY; public PathConstraintData (String name) { super(name); } + public PathConstraintPose getSetupPose () { + return setup; + } + /** The bones that will be modified by this path constraint. */ public Array getBones () { return bones; @@ -101,51 +105,6 @@ public class PathConstraintData extends ConstraintData { this.offsetRotation = offsetRotation; } - /** 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; - } - /** Controls how the first bone is positioned along the path. *

* 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 bones; BoneApplied source; - TransformConstraint applied; + final TransformConstraintPose pose = new TransformConstraintPose(), applied = new TransformConstraintPose(); boolean active; - float mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY; - public TransformConstraint (TransformConstraintData data, Array bones, BoneApplied source) { this.data = data; this.bones = bones; @@ -66,30 +64,24 @@ public class TransformConstraint implements Updatable { source = skeleton.bones.get(data.source.index).applied; - applied = new TransformConstraint(data, bones, source); - setupPose(); } /** Copy constructor. */ public TransformConstraint (TransformConstraint constraint, Skeleton skeleton) { this(constraint.data, skeleton); - setupPose(); + pose.set(constraint.pose); } public void setupPose () { - TransformConstraintData data = this.data; - mixRotate = data.mixRotate; - mixX = data.mixX; - mixY = data.mixY; - mixScaleX = data.mixScaleX; - mixScaleY = data.mixScaleY; - mixShearY = data.mixShearY; + pose.set(data.setup); } /** Applies the constraint to the constrained bones. */ public void update (Physics physics) { - if (mixRotate == 0 && mixX == 0 && mixY == 0 && mixScaleX == 0 && mixScaleY == 0 && mixShearY == 0) return; + TransformConstraintPose pose = applied; + if (pose.mixRotate == 0 && pose.mixX == 0 && pose.mixY == 0 && pose.mixScaleX == 0 && pose.mixScaleY == 0 + && pose.mixShearY == 0) return; TransformConstraintData data = this.data; boolean localFrom = data.localSource, localTarget = data.localTarget, additive = data.additive, clamp = data.clamp; @@ -105,7 +97,7 @@ public class TransformConstraint implements Updatable { Object[] toItems = from.to.items; for (int t = 0, tn = from.to.size; t < tn; t++) { var to = (ToProperty)toItems[t]; - if (to.mix(this) != 0) { + if (to.mix(pose) != 0) { float clamped = to.offset + value * to.scale; if (clamp) { if (to.offset < to.max) @@ -113,7 +105,7 @@ public class TransformConstraint implements Updatable { else clamped = clamp(clamped, to.max, to.offset); } - to.apply(this, bone, clamped, localTarget, additive); + to.apply(pose, bone, clamped, localTarget, additive); } } } @@ -139,58 +131,12 @@ public class TransformConstraint implements Updatable { this.source = source; } - /** A percentage (0-1) that controls the mix between the constrained and unconstrained rotation. */ - public float getMixRotate () { - return mixRotate; + public TransformConstraintPose getPose () { + return pose; } - 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; - } - - /** A percentage (0-1) that controls the mix between the constrained and unconstrained scale X. */ - public float getMixScaleX () { - return mixScaleX; - } - - public void setMixScaleX (float mixScaleX) { - this.mixScaleX = mixScaleX; - } - - /** A percentage (0-1) that controls the mix between the constrained and unconstrained scale X. */ - public float getMixScaleY () { - return mixScaleY; - } - - public void setMixScaleY (float mixScaleY) { - this.mixScaleY = mixScaleY; - } - - /** A percentage (0-1) that controls the mix between the constrained and unconstrained shear Y. */ - public float getMixShearY () { - return mixShearY; - } - - public void setMixShearY (float mixShearY) { - this.mixShearY = mixShearY; + public TransformConstraintPose getAppliedPose () { + return applied; } /** Returns false when this constraint won't be updated by diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java index 17c5baebe..547ceb699 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java @@ -37,9 +37,9 @@ import com.badlogic.gdx.utils.Array; *

* See Transform constraints in the Spine User Guide. */ public class TransformConstraintData extends ConstraintData { + final TransformConstraintPose setup = new TransformConstraintPose(); final Array bones = new Array(); BoneData source; - float mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY; float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY; boolean localSource, localTarget, additive, clamp; final Array properties = new Array(); @@ -48,6 +48,10 @@ public class TransformConstraintData extends ConstraintData { super(name); } + public TransformConstraintPose getSetupPose () { + return setup; + } + /** The bones that will be modified by this transform constraint. */ public Array getBones () { return bones; @@ -63,65 +67,6 @@ public class TransformConstraintData extends ConstraintData { this.source = source; } - /** The mapping of transform properties to other transform properties. */ - public Array getProperties () { - return properties; - } - - /** 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; - } - - /** A percentage (0-1) that controls the mix between the constrained and unconstrained scale X. */ - public float getMixScaleX () { - return mixScaleX; - } - - public void setMixScaleX (float mixScaleX) { - this.mixScaleX = mixScaleX; - } - - /** A percentage (0-1) that controls the mix between the constrained and unconstrained scale Y. */ - public float getMixScaleY () { - return mixScaleY; - } - - public void setMixScaleY (float mixScaleY) { - this.mixScaleY = mixScaleY; - } - - /** A percentage (0-1) that controls the mix between the constrained and unconstrained shear Y. */ - public float getMixShearY () { - return mixShearY; - } - - public void setMixShearY (float mixShearY) { - this.mixShearY = mixShearY; - } - /** An offset added to the constrained bone rotation. */ public float getOffsetRotation () { return offsetRotation; @@ -212,6 +157,11 @@ public class TransformConstraintData extends ConstraintData { this.clamp = clamp; } + /** The mapping of transform properties to other transform properties. */ + public Array getProperties () { + return properties; + } + /** Source property for a {@link TransformConstraint}. */ static abstract public class FromProperty { /** The value of this property that corresponds to {@link ToProperty#offset}. */ @@ -235,11 +185,11 @@ public class TransformConstraintData extends ConstraintData { /** The scale of the {@link FromProperty} value in relation to this property. */ public float scale; - /** Reads the mix for this property from the specified constraint. */ - abstract public float mix (TransformConstraint constraint); + /** Reads the mix for this property from the specified pose. */ + abstract public float mix (TransformConstraintPose pose); /** Applies the value to this property. */ - abstract public void apply (TransformConstraint constraint, BoneApplied bone, float value, boolean local, boolean additive); + abstract public void apply (TransformConstraintPose pose, BoneApplied bone, float value, boolean local, boolean additive); } static public class FromRotate extends FromProperty { @@ -253,14 +203,14 @@ public class TransformConstraintData extends ConstraintData { } static public class ToRotate extends ToProperty { - public float mix (TransformConstraint constraint) { - return constraint.mixRotate; + public float mix (TransformConstraintPose pose) { + return pose.mixRotate; } - public void apply (TransformConstraint constraint, BoneApplied bone, float value, boolean local, boolean additive) { + public void apply (TransformConstraintPose pose, BoneApplied bone, float value, boolean local, boolean additive) { if (local) { if (!additive) value -= bone.rotation; - bone.rotation += value * constraint.mixRotate; + bone.rotation += value * pose.mixRotate; } else { float a = bone.a, b = bone.b, c = bone.c, d = bone.d; value *= degRad; @@ -269,7 +219,7 @@ public class TransformConstraintData extends ConstraintData { value -= PI2; else if (value < -PI) // value += PI2; - value *= constraint.mixRotate; + value *= pose.mixRotate; float cos = cos(value), sin = sin(value); bone.a = cos * a - sin * c; bone.b = cos * b - sin * d; @@ -286,17 +236,17 @@ public class TransformConstraintData extends ConstraintData { } static public class ToX extends ToProperty { - public float mix (TransformConstraint constraint) { - return constraint.mixX; + public float mix (TransformConstraintPose pose) { + return pose.mixX; } - public void apply (TransformConstraint constraint, BoneApplied bone, float value, boolean local, boolean additive) { + public void apply (TransformConstraintPose pose, BoneApplied bone, float value, boolean local, boolean additive) { if (local) { if (!additive) value -= bone.x; - bone.x += value * constraint.mixX; + bone.x += value * pose.mixX; } else { if (!additive) value -= bone.worldX; - bone.worldX += value * constraint.mixX; + bone.worldX += value * pose.mixX; } } } @@ -308,17 +258,17 @@ public class TransformConstraintData extends ConstraintData { } static public class ToY extends ToProperty { - public float mix (TransformConstraint constraint) { - return constraint.mixY; + public float mix (TransformConstraintPose pose) { + return pose.mixY; } - public void apply (TransformConstraint constraint, BoneApplied bone, float value, boolean local, boolean additive) { + public void apply (TransformConstraintPose pose, BoneApplied bone, float value, boolean local, boolean additive) { if (local) { if (!additive) value -= bone.y; - bone.y += value * constraint.mixY; + bone.y += value * pose.mixY; } else { if (!additive) value -= bone.worldY; - bone.worldY += value * constraint.mixY; + bone.worldY += value * pose.mixY; } } } @@ -330,23 +280,23 @@ public class TransformConstraintData extends ConstraintData { } static public class ToScaleX extends ToProperty { - public float mix (TransformConstraint constraint) { - return constraint.mixScaleX; + public float mix (TransformConstraintPose pose) { + return pose.mixScaleX; } - public void apply (TransformConstraint constraint, BoneApplied bone, float value, boolean local, boolean additive) { + public void apply (TransformConstraintPose pose, BoneApplied bone, float value, boolean local, boolean additive) { if (local) { if (additive) - bone.scaleX *= 1 + ((value - 1) * constraint.mixScaleX); + bone.scaleX *= 1 + ((value - 1) * pose.mixScaleX); else if (bone.scaleX != 0) // - bone.scaleX = 1 + (value / bone.scaleX - 1) * constraint.mixScaleX; + bone.scaleX = 1 + (value / bone.scaleX - 1) * pose.mixScaleX; } else { float s; if (additive) - s = 1 + (value - 1) * constraint.mixScaleX; + s = 1 + (value - 1) * pose.mixScaleX; else { s = (float)Math.sqrt(bone.a * bone.a + bone.c * bone.c); - if (s != 0) s = 1 + (value / s - 1) * constraint.mixScaleX; + if (s != 0) s = 1 + (value / s - 1) * pose.mixScaleX; } bone.a *= s; bone.c *= s; @@ -361,23 +311,23 @@ public class TransformConstraintData extends ConstraintData { } static public class ToScaleY extends ToProperty { - public float mix (TransformConstraint constraint) { - return constraint.mixScaleY; + public float mix (TransformConstraintPose pose) { + return pose.mixScaleY; } - public void apply (TransformConstraint constraint, BoneApplied bone, float value, boolean local, boolean additive) { + public void apply (TransformConstraintPose pose, BoneApplied bone, float value, boolean local, boolean additive) { if (local) { if (additive) - bone.scaleY *= 1 + ((value - 1) * constraint.mixScaleY); + bone.scaleY *= 1 + ((value - 1) * pose.mixScaleY); else if (bone.scaleY != 0) // - bone.scaleY = 1 + (value / bone.scaleY - 1) * constraint.mixScaleY; + bone.scaleY = 1 + (value / bone.scaleY - 1) * pose.mixScaleY; } else { float s; if (additive) - s = 1 + (value - 1) * constraint.mixScaleY; + s = 1 + (value - 1) * pose.mixScaleY; else { s = (float)Math.sqrt(bone.b * bone.b + bone.d * bone.d); - if (s != 0) s = 1 + (value / s - 1) * constraint.mixScaleY; + if (s != 0) s = 1 + (value / s - 1) * pose.mixScaleY; } bone.b *= s; bone.d *= s; @@ -393,14 +343,14 @@ public class TransformConstraintData extends ConstraintData { } static public class ToShearY extends ToProperty { - public float mix (TransformConstraint constraint) { - return constraint.mixShearY; + public float mix (TransformConstraintPose pose) { + return pose.mixShearY; } - public void apply (TransformConstraint constraint, BoneApplied bone, float value, boolean local, boolean additive) { + public void apply (TransformConstraintPose pose, BoneApplied bone, float value, boolean local, boolean additive) { if (local) { if (!additive) value -= bone.shearY; - bone.shearY += value * constraint.mixShearY; + bone.shearY += value * pose.mixShearY; } else { float b = bone.b, d = bone.d, by = atan2(d, b); value = (value + 90) * degRad; @@ -413,7 +363,7 @@ public class TransformConstraintData extends ConstraintData { else if (value < -PI) // value += PI2; } - value = by + value * constraint.mixShearY; + value = by + value * pose.mixShearY; float s = (float)Math.sqrt(b * b + d * d); bone.b = cos(value) * s; bone.d = sin(value) * s; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintPose.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintPose.java new file mode 100644 index 000000000..5d234addb --- /dev/null +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintPose.java @@ -0,0 +1,98 @@ +/****************************************************************************** + * 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 transform constraint. */ +public class TransformConstraintPose { + float mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY; + + public void set (TransformConstraintPose pose) { + mixRotate = pose.mixRotate; + mixX = pose.mixX; + mixY = pose.mixY; + mixScaleX = pose.mixScaleX; + mixScaleY = pose.mixScaleY; + mixShearY = pose.mixShearY; + } + + /** 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; + } + + /** A percentage (0-1) that controls the mix between the constrained and unconstrained scale X. */ + public float getMixScaleX () { + return mixScaleX; + } + + public void setMixScaleX (float mixScaleX) { + this.mixScaleX = mixScaleX; + } + + /** A percentage (0-1) that controls the mix between the constrained and unconstrained scale X. */ + public float getMixScaleY () { + return mixScaleY; + } + + public void setMixScaleY (float mixScaleY) { + this.mixScaleY = mixScaleY; + } + + /** A percentage (0-1) that controls the mix between the constrained and unconstrained shear Y. */ + public float getMixShearY () { + return mixShearY; + } + + public void setMixShearY (float mixShearY) { + this.mixShearY = mixShearY; + } +}