[libgdx] BonePose/Applied classes.

This commit is contained in:
Nathan Sweet 2025-04-12 22:08:54 -04:00
parent 71ef2d5f98
commit cab6f73396
14 changed files with 327 additions and 256 deletions

View File

@ -544,7 +544,7 @@ public class Animation {
} }
} }
/** Changes a bone's local {@link Bone#getRotation()}. */ /** Changes a bone's local {@link BonePose#getRotation()}. */
static public class RotateTimeline extends CurveTimeline1 implements BoneTimeline { static public class RotateTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex; final int boneIndex;
@ -560,15 +560,15 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend, public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) { MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex); Bone pose = skeleton.bones.get(boneIndex);
if (bone.active) { if (pose.active) {
if (appliedPose) bone = bone.applied; BonePose bone = appliedPose ? pose.applied : pose;
bone.rotation = getRelativeValue(time, alpha, blend, bone.rotation, bone.data.rotation); bone.rotation = getRelativeValue(time, alpha, blend, bone.rotation, pose.data.rotation);
} }
} }
} }
/** Changes a bone's local {@link Bone#getX()} and {@link Bone#getY()}. */ /** Changes a bone's local {@link BonePose#getX()} and {@link BonePose#getY()}. */
static public class TranslateTimeline extends CurveTimeline2 implements BoneTimeline { static public class TranslateTimeline extends CurveTimeline2 implements BoneTimeline {
final int boneIndex; final int boneIndex;
@ -586,20 +586,20 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend, public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) { MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex); Bone pose = skeleton.bones.get(boneIndex);
if (!bone.active) return; if (!pose.active) return;
if (appliedPose) bone = bone.applied; BonePose bone = appliedPose ? pose.applied : pose;
float[] frames = this.frames; float[] frames = this.frames;
if (time < frames[0]) { if (time < frames[0]) {
switch (blend) { switch (blend) {
case setup: case setup:
bone.x = bone.data.x; bone.x = pose.data.x;
bone.y = bone.data.y; bone.y = pose.data.y;
return; return;
case first: case first:
bone.x += (bone.data.x - bone.x) * alpha; bone.x += (pose.data.x - bone.x) * alpha;
bone.y += (bone.data.y - bone.y) * alpha; bone.y += (pose.data.y - bone.y) * alpha;
} }
return; return;
} }
@ -626,13 +626,13 @@ public class Animation {
switch (blend) { switch (blend) {
case setup: case setup:
bone.x = bone.data.x + x * alpha; bone.x = pose.data.x + x * alpha;
bone.y = bone.data.y + y * alpha; bone.y = pose.data.y + y * alpha;
break; break;
case first: case first:
case replace: case replace:
bone.x += (bone.data.x + x - bone.x) * alpha; bone.x += (pose.data.x + x - bone.x) * alpha;
bone.y += (bone.data.y + y - bone.y) * alpha; bone.y += (pose.data.y + y - bone.y) * alpha;
break; break;
case add: case add:
bone.x += x * alpha; bone.x += x * alpha;
@ -641,7 +641,7 @@ public class Animation {
} }
} }
/** Changes a bone's local {@link Bone#getX()}. */ /** Changes a bone's local {@link BonePose#getX()}. */
static public class TranslateXTimeline extends CurveTimeline1 implements BoneTimeline { static public class TranslateXTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex; final int boneIndex;
@ -657,15 +657,15 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend, public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) { MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex); Bone pose = skeleton.bones.get(boneIndex);
if (bone.active) { if (pose.active) {
if (appliedPose) bone = bone.applied; BonePose bone = appliedPose ? pose.applied : pose;
bone.x = getRelativeValue(time, alpha, blend, bone.x, bone.data.x); bone.x = getRelativeValue(time, alpha, blend, bone.x, pose.data.x);
} }
} }
} }
/** Changes a bone's local {@link Bone#getY()}. */ /** Changes a bone's local {@link BonePose#getY()}. */
static public class TranslateYTimeline extends CurveTimeline1 implements BoneTimeline { static public class TranslateYTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex; final int boneIndex;
@ -681,15 +681,15 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend, public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) { MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex); Bone pose = skeleton.bones.get(boneIndex);
if (bone.active) { if (pose.active) {
if (appliedPose) bone = bone.applied; BonePose bone = appliedPose ? pose.applied : pose;
bone.y = getRelativeValue(time, alpha, blend, bone.y, bone.data.y); bone.y = getRelativeValue(time, alpha, blend, bone.y, pose.data.y);
} }
} }
} }
/** Changes a bone's local {@link Bone#getScaleX()} and {@link Bone#getScaleY()}. */ /** Changes a bone's local {@link BonePose#getScaleX()} and {@link BonePose#getScaleY()}. */
static public class ScaleTimeline extends CurveTimeline2 implements BoneTimeline { static public class ScaleTimeline extends CurveTimeline2 implements BoneTimeline {
final int boneIndex; final int boneIndex;
@ -707,20 +707,20 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend, public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) { MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex); Bone pose = skeleton.bones.get(boneIndex);
if (!bone.active) return; if (!pose.active) return;
if (appliedPose) bone = bone.applied; BonePose bone = appliedPose ? pose.applied : pose;
float[] frames = this.frames; float[] frames = this.frames;
if (time < frames[0]) { if (time < frames[0]) {
switch (blend) { switch (blend) {
case setup: case setup:
bone.scaleX = bone.data.scaleX; bone.scaleX = pose.data.scaleX;
bone.scaleY = bone.data.scaleY; bone.scaleY = pose.data.scaleY;
return; return;
case first: case first:
bone.scaleX += (bone.data.scaleX - bone.scaleX) * alpha; bone.scaleX += (pose.data.scaleX - bone.scaleX) * alpha;
bone.scaleY += (bone.data.scaleY - bone.scaleY) * alpha; bone.scaleY += (pose.data.scaleY - bone.scaleY) * alpha;
} }
return; return;
} }
@ -744,13 +744,13 @@ public class Animation {
x = getBezierValue(time, i, VALUE1, curveType - BEZIER); x = getBezierValue(time, i, VALUE1, curveType - BEZIER);
y = getBezierValue(time, i, VALUE2, curveType + BEZIER_SIZE - BEZIER); y = getBezierValue(time, i, VALUE2, curveType + BEZIER_SIZE - BEZIER);
} }
x *= bone.data.scaleX; x *= pose.data.scaleX;
y *= bone.data.scaleY; y *= pose.data.scaleY;
if (alpha == 1) { if (alpha == 1) {
if (blend == add) { if (blend == add) {
bone.scaleX += x - bone.data.scaleX; bone.scaleX += x - pose.data.scaleX;
bone.scaleY += y - bone.data.scaleY; bone.scaleY += y - pose.data.scaleY;
} else { } else {
bone.scaleX = x; bone.scaleX = x;
bone.scaleY = y; bone.scaleY = y;
@ -761,8 +761,8 @@ public class Animation {
if (direction == out) { if (direction == out) {
switch (blend) { switch (blend) {
case setup: case setup:
bx = bone.data.scaleX; bx = pose.data.scaleX;
by = bone.data.scaleY; by = pose.data.scaleY;
bone.scaleX = bx + (Math.abs(x) * Math.signum(bx) - bx) * alpha; bone.scaleX = bx + (Math.abs(x) * Math.signum(bx) - bx) * alpha;
bone.scaleY = by + (Math.abs(y) * Math.signum(by) - by) * alpha; bone.scaleY = by + (Math.abs(y) * Math.signum(by) - by) * alpha;
break; break;
@ -774,14 +774,14 @@ public class Animation {
bone.scaleY = by + (Math.abs(y) * Math.signum(by) - by) * alpha; bone.scaleY = by + (Math.abs(y) * Math.signum(by) - by) * alpha;
break; break;
case add: case add:
bone.scaleX += (x - bone.data.scaleX) * alpha; bone.scaleX += (x - pose.data.scaleX) * alpha;
bone.scaleY += (y - bone.data.scaleY) * alpha; bone.scaleY += (y - pose.data.scaleY) * alpha;
} }
} else { } else {
switch (blend) { switch (blend) {
case setup: case setup:
bx = Math.abs(bone.data.scaleX) * Math.signum(x); bx = Math.abs(pose.data.scaleX) * Math.signum(x);
by = Math.abs(bone.data.scaleY) * Math.signum(y); by = Math.abs(pose.data.scaleY) * Math.signum(y);
bone.scaleX = bx + (x - bx) * alpha; bone.scaleX = bx + (x - bx) * alpha;
bone.scaleY = by + (y - by) * alpha; bone.scaleY = by + (y - by) * alpha;
break; break;
@ -793,15 +793,15 @@ public class Animation {
bone.scaleY = by + (y - by) * alpha; bone.scaleY = by + (y - by) * alpha;
break; break;
case add: case add:
bone.scaleX += (x - bone.data.scaleX) * alpha; bone.scaleX += (x - pose.data.scaleX) * alpha;
bone.scaleY += (y - bone.data.scaleY) * alpha; bone.scaleY += (y - pose.data.scaleY) * alpha;
} }
} }
} }
} }
} }
/** Changes a bone's local {@link Bone#getScaleX()}. */ /** Changes a bone's local {@link BonePose#getScaleX()}. */
static public class ScaleXTimeline extends CurveTimeline1 implements BoneTimeline { static public class ScaleXTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex; final int boneIndex;
@ -817,15 +817,15 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend, public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) { MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex); Bone pose = skeleton.bones.get(boneIndex);
if (bone.active) { if (pose.active) {
if (appliedPose) bone = bone.applied; BonePose bone = appliedPose ? pose.applied : pose;
bone.scaleX = getScaleValue(time, alpha, blend, direction, bone.scaleX, bone.data.scaleX); bone.scaleX = getScaleValue(time, alpha, blend, direction, bone.scaleX, pose.data.scaleX);
} }
} }
} }
/** Changes a bone's local {@link Bone#getScaleY()}. */ /** Changes a bone's local {@link BonePose#getScaleY()}. */
static public class ScaleYTimeline extends CurveTimeline1 implements BoneTimeline { static public class ScaleYTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex; final int boneIndex;
@ -841,15 +841,15 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend, public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) { MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex); Bone pose = skeleton.bones.get(boneIndex);
if (bone.active) { if (pose.active) {
if (appliedPose) bone = bone.applied; BonePose bone = appliedPose ? pose.applied : pose;
bone.scaleY = getScaleValue(time, alpha, blend, direction, bone.scaleY, bone.data.scaleY); bone.scaleY = getScaleValue(time, alpha, blend, direction, bone.scaleY, pose.data.scaleY);
} }
} }
} }
/** Changes a bone's local {@link Bone#getShearX()} and {@link Bone#getShearY()}. */ /** Changes a bone's local {@link BonePose#getShearX()} and {@link BonePose#getShearY()}. */
static public class ShearTimeline extends CurveTimeline2 implements BoneTimeline { static public class ShearTimeline extends CurveTimeline2 implements BoneTimeline {
final int boneIndex; final int boneIndex;
@ -867,20 +867,20 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend, public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) { MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex); Bone pose = skeleton.bones.get(boneIndex);
if (!bone.active) return; if (!pose.active) return;
if (appliedPose) bone = bone.applied; BonePose bone = appliedPose ? pose.applied : pose;
float[] frames = this.frames; float[] frames = this.frames;
if (time < frames[0]) { if (time < frames[0]) {
switch (blend) { switch (blend) {
case setup: case setup:
bone.shearX = bone.data.shearX; bone.shearX = pose.data.shearX;
bone.shearY = bone.data.shearY; bone.shearY = pose.data.shearY;
return; return;
case first: case first:
bone.shearX += (bone.data.shearX - bone.shearX) * alpha; bone.shearX += (pose.data.shearX - bone.shearX) * alpha;
bone.shearY += (bone.data.shearY - bone.shearY) * alpha; bone.shearY += (pose.data.shearY - bone.shearY) * alpha;
} }
return; return;
} }
@ -907,13 +907,13 @@ public class Animation {
switch (blend) { switch (blend) {
case setup: case setup:
bone.shearX = bone.data.shearX + x * alpha; bone.shearX = pose.data.shearX + x * alpha;
bone.shearY = bone.data.shearY + y * alpha; bone.shearY = pose.data.shearY + y * alpha;
break; break;
case first: case first:
case replace: case replace:
bone.shearX += (bone.data.shearX + x - bone.shearX) * alpha; bone.shearX += (pose.data.shearX + x - bone.shearX) * alpha;
bone.shearY += (bone.data.shearY + y - bone.shearY) * alpha; bone.shearY += (pose.data.shearY + y - bone.shearY) * alpha;
break; break;
case add: case add:
bone.shearX += x * alpha; bone.shearX += x * alpha;
@ -922,7 +922,7 @@ public class Animation {
} }
} }
/** Changes a bone's local {@link Bone#getShearX()}. */ /** Changes a bone's local {@link BonePose#getShearX()}. */
static public class ShearXTimeline extends CurveTimeline1 implements BoneTimeline { static public class ShearXTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex; final int boneIndex;
@ -938,15 +938,15 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend, public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) { MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex); Bone pose = skeleton.bones.get(boneIndex);
if (bone.active) { if (pose.active) {
if (appliedPose) bone = bone.applied; BonePose bone = appliedPose ? pose.applied : pose;
bone.shearX = getRelativeValue(time, alpha, blend, bone.shearX, bone.data.shearX); bone.shearX = getRelativeValue(time, alpha, blend, bone.shearX, pose.data.shearX);
} }
} }
} }
/** Changes a bone's local {@link Bone#getShearY()}. */ /** Changes a bone's local {@link BonePose#getShearY()}. */
static public class ShearYTimeline extends CurveTimeline1 implements BoneTimeline { static public class ShearYTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex; final int boneIndex;
@ -962,15 +962,15 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend, public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) { MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex); Bone pose = skeleton.bones.get(boneIndex);
if (bone.active) { if (pose.active) {
if (appliedPose) bone = bone.applied; BonePose bone = appliedPose ? pose.applied : pose;
bone.shearY = getRelativeValue(time, alpha, blend, bone.shearY, bone.data.shearY); bone.shearY = getRelativeValue(time, alpha, blend, bone.shearY, pose.data.shearY);
} }
} }
} }
/** Changes a bone's {@link Bone#getInherit()}. */ /** Changes a bone's {@link BonePose#getInherit()}. */
static public class InheritTimeline extends Timeline implements BoneTimeline { static public class InheritTimeline extends Timeline implements BoneTimeline {
static public final int ENTRIES = 2; static public final int ENTRIES = 2;
static private final int INHERIT = 1; static private final int INHERIT = 1;
@ -1002,18 +1002,18 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend, public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) { MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex); Bone pose = skeleton.bones.get(boneIndex);
if (!bone.active) return; if (!pose.active) return;
if (appliedPose) bone = bone.applied; BonePose bone = appliedPose ? pose.applied : pose;
if (direction == out) { if (direction == out) {
if (blend == setup) bone.inherit = bone.data.inherit; if (blend == setup) bone.inherit = pose.data.inherit;
return; return;
} }
float[] frames = this.frames; float[] frames = this.frames;
if (time < frames[0]) { if (time < frames[0]) {
if (blend == setup || blend == first) bone.inherit = bone.data.inherit; if (blend == setup || blend == first) bone.inherit = pose.data.inherit;
return; return;
} }
bone.inherit = Inherit.values[(int)frames[search(frames, time, ENTRIES) + INHERIT]]; bone.inherit = Inherit.values[(int)frames[search(frames, time, ENTRIES) + INHERIT]];

View File

@ -32,32 +32,20 @@ package com.esotericsoftware.spine;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Null; import com.badlogic.gdx.utils.Null;
import com.esotericsoftware.spine.BoneData.Inherit;
/** Stores a bone's current pose. /** Stores a bone's current pose.
* <p> * <p>
* A bone has a local transform which is used to compute its world transform. A bone also has an applied transform, which is a * A bone has a local transform which is used to compute its world transform. A bone also has an applied transform, which is a
* local transform that can be applied to compute the world transform. The local transform and applied transform may differ if a * local transform that can be applied to compute the world transform. The local transform and applied transform may differ if a
* constraint or application code modifies the world transform after it was computed from the local transform. */ * constraint or application code modifies the world transform after it was computed from the local transform. */
public class Bone { public class Bone extends BonePose {
final BoneData data; final BoneData data;
final Skeleton skeleton; final Skeleton skeleton;
@Null final Bone parent; @Null final Bone parent;
final Array<Bone> children; final Array<Bone> children;
BoneApplied applied; final BoneApplied applied = new BoneApplied(this);
float x, y, rotation, scaleX, scaleY, shearX, shearY;
Inherit inherit;
boolean sorted, active; boolean sorted, active;
Bone (Bone bone) {
this.data = bone.data;
this.skeleton = bone.skeleton;
this.parent = bone.parent;
this.children = bone.children;
}
public Bone (BoneData data, Skeleton skeleton, @Null Bone parent) { public Bone (BoneData data, Skeleton skeleton, @Null Bone parent) {
if (data == null) throw new IllegalArgumentException("data cannot be null."); if (data == null) throw new IllegalArgumentException("data cannot be null.");
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
@ -66,27 +54,16 @@ public class Bone {
this.parent = parent; this.parent = parent;
children = new Array(); children = new Array();
applied = new BoneApplied(this);
setToSetupPose(); setToSetupPose();
} }
/** Copy constructor. Does not copy the {@link #getChildren()} bones. */ /** Copy constructor. Does not copy the {@link #getChildren()} bones. */
public Bone (Bone bone, Skeleton skeleton, @Null Bone parent) { public Bone (Bone bone, Skeleton skeleton, @Null Bone parent) {
if (bone == null) throw new IllegalArgumentException("bone cannot be null."); super(bone);
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
this.skeleton = skeleton; this.skeleton = skeleton;
this.parent = parent; this.parent = parent;
children = new Array(); children = new Array();
data = bone.data; data = bone.data;
x = bone.x;
y = bone.y;
rotation = bone.rotation;
scaleX = bone.scaleX;
scaleY = bone.scaleY;
shearX = bone.shearX;
shearY = bone.shearY;
inherit = bone.inherit;
} }
/** Sets this bone's local transform to the setup pose. */ /** Sets this bone's local transform to the setup pose. */
@ -122,98 +99,17 @@ public class Bone {
return children; return children;
} }
/** Returns false when this bone won't be updated by
* {@link Skeleton#updateWorldTransform(com.esotericsoftware.spine.Skeleton.Physics)} because a skin is required and the
* {@link Skeleton#getSkin() active skin} does not contain this item.
* @see Skin#getBones()
* @see Skin#getConstraints()
* @see BoneData#getSkinRequired()
* @see Skeleton#updateCache() */
public boolean isActive () { public boolean isActive () {
return active; return active;
} }
/** The local x translation. */
public float getX () {
return x;
}
public void setX (float x) {
this.x = x;
}
/** The local y translation. */
public float getY () {
return y;
}
public void setY (float y) {
this.y = y;
}
public void setPosition (float x, float y) {
this.x = x;
this.y = y;
}
/** The local rotation in degrees, counter clockwise. */
public float getRotation () {
return rotation;
}
public void setRotation (float rotation) {
this.rotation = rotation;
}
/** The local scaleX. */
public float getScaleX () {
return scaleX;
}
public void setScaleX (float scaleX) {
this.scaleX = scaleX;
}
/** The local scaleY. */
public float getScaleY () {
return scaleY;
}
public void setScaleY (float scaleY) {
this.scaleY = scaleY;
}
public void setScale (float scaleX, float scaleY) {
this.scaleX = scaleX;
this.scaleY = scaleY;
}
public void setScale (float scale) {
scaleX = scale;
scaleY = scale;
}
/** The local shearX. */
public float getShearX () {
return shearX;
}
public void setShearX (float shearX) {
this.shearX = shearX;
}
/** The local shearY. */
public float getShearY () {
return shearY;
}
public void setShearY (float shearY) {
this.shearY = shearY;
}
/** Determines how parent world transforms affect this bone. */
public Inherit getInherit () {
return inherit;
}
public void setInherit (Inherit inherit) {
if (inherit == null) throw new IllegalArgumentException("inherit cannot be null.");
this.inherit = inherit;
}
/** Returns the bone for applied pose. */ /** Returns the bone for applied pose. */
public BoneApplied getApplied () { public BoneApplied getApplied () {
return applied; return applied;

View File

@ -11,21 +11,20 @@ import com.badlogic.gdx.utils.Null;
import com.esotericsoftware.spine.BoneData.Inherit; import com.esotericsoftware.spine.BoneData.Inherit;
import com.esotericsoftware.spine.Skeleton.Physics; import com.esotericsoftware.spine.Skeleton.Physics;
public class BoneApplied extends Bone implements Updatable { public class BoneApplied extends BonePose implements Updatable {
final Bone pose; final Bone pose;
@Null final BoneApplied parentApplied; @Null final BoneApplied parent;
float a, b, worldX; float a, b, worldX;
float c, d, worldY; float c, d, worldY;
BoneApplied (Bone bone) { BoneApplied (Bone bone) {
super(bone);
pose = bone; pose = bone;
parentApplied = parent == null ? null : parent.applied; parent = bone.parent == null ? null : bone.parent.applied;
} }
/** Computes the world transform using the parent bone and this bone's local applied transform. */ /** Computes the world transform using the parent bone and this bone's local applied transform. */
public void updateWorldTransform () { public void updateWorldTransform () {
updateWorldTransform(); update(null);
} }
/** Computes the world transform using the parent bone and this bone's local transform. /** Computes the world transform using the parent bone and this bone's local transform.
@ -37,9 +36,10 @@ public class BoneApplied extends Bone implements Updatable {
* See <a href="https://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine * See <a href="https://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine
* Runtimes Guide. */ * Runtimes Guide. */
public void update (Physics physics) { public void update (Physics physics) {
BoneApplied parent = parentApplied; Skeleton skeleton = pose.skeleton;
BoneApplied parent = this.parent;
if (parent == null) { // Root bone. if (parent == null) { // Root bone.
Skeleton skeleton = this.skeleton;
float sx = skeleton.scaleX, sy = skeleton.scaleY; float sx = skeleton.scaleX, sy = skeleton.scaleY;
float rx = (rotation + shearX) * degRad; float rx = (rotation + shearX) * degRad;
float ry = (rotation + 90 + shearY) * degRad; float ry = (rotation + 90 + shearY) * degRad;
@ -136,16 +136,18 @@ public class BoneApplied extends Bone implements Updatable {
d *= skeleton.scaleY; d *= skeleton.scaleY;
} }
/** Computes the applied transform values from the world transform. /** Computes the local transform values from the world transform.
* <p> * <p>
* If the world transform is modified (by a constraint, {@link #rotateWorld(float)}, etc) then this method should be called so * If the world transform is modified (by a constraint, {@link #rotateWorld(float)}, etc) then this method should be called so
* the applied transform matches the world transform. The applied transform may be needed by other code (eg to apply another * the local transform matches the world transform. The local transform may be needed by other code (eg to apply another
* constraint). * constraint).
* <p> * <p>
* Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. The applied transform after * Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. The local transform after
* calling this method is equivalent to the local transform used to compute the world transform, but may not be identical. */ * calling this method is equivalent to the local transform used to compute the world transform, but may not be identical. */
public void updateAppliedTransform () { public void updateLocalTransform () {
BoneApplied parent = parentApplied; Skeleton skeleton = pose.skeleton;
BoneApplied parent = this.parent;
if (parent == null) { if (parent == null) {
x = worldX - skeleton.x; x = worldX - skeleton.x;
y = worldY - skeleton.y; y = worldY - skeleton.y;
@ -222,7 +224,7 @@ public class BoneApplied extends Bone implements Updatable {
} }
} }
/** Part of the world transform matrix for the X axis. If changed, {@link #updateAppliedTransform()} should be called. */ /** Part of the world transform matrix for the X axis. If changed, {@link #updateLocalTransform()} should be called. */
public float getA () { public float getA () {
return a; return a;
} }
@ -231,7 +233,7 @@ public class BoneApplied extends Bone implements Updatable {
this.a = a; this.a = a;
} }
/** Part of the world transform matrix for the Y axis. If changed, {@link #updateAppliedTransform()} should be called. */ /** Part of the world transform matrix for the Y axis. If changed, {@link #updateLocalTransform()} should be called. */
public float getB () { public float getB () {
return b; return b;
} }
@ -240,7 +242,7 @@ public class BoneApplied extends Bone implements Updatable {
this.b = b; this.b = b;
} }
/** Part of the world transform matrix for the X axis. If changed, {@link #updateAppliedTransform()} should be called. */ /** Part of the world transform matrix for the X axis. If changed, {@link #updateLocalTransform()} should be called. */
public float getC () { public float getC () {
return c; return c;
} }
@ -249,7 +251,7 @@ public class BoneApplied extends Bone implements Updatable {
this.c = c; this.c = c;
} }
/** Part of the world transform matrix for the Y axis. If changed, {@link #updateAppliedTransform()} should be called. */ /** Part of the world transform matrix for the Y axis. If changed, {@link #updateLocalTransform()} should be called. */
public float getD () { public float getD () {
return d; return d;
} }
@ -258,7 +260,7 @@ public class BoneApplied extends Bone implements Updatable {
this.d = d; this.d = d;
} }
/** The world X position. If changed, {@link #updateAppliedTransform()} should be called. */ /** The world X position. If changed, {@link #updateLocalTransform()} should be called. */
public float getWorldX () { public float getWorldX () {
return worldX; return worldX;
} }
@ -267,7 +269,7 @@ public class BoneApplied extends Bone implements Updatable {
this.worldX = worldX; this.worldX = worldX;
} }
/** The world Y position. If changed, {@link #updateAppliedTransform()} should be called. */ /** The world Y position. If changed, {@link #updateLocalTransform()} should be called. */
public float getWorldY () { public float getWorldY () {
return worldY; return worldY;
} }
@ -333,13 +335,13 @@ public class BoneApplied extends Bone implements Updatable {
/** Transforms a point from world coordinates to the parent bone's local coordinates. */ /** Transforms a point from world coordinates to the parent bone's local coordinates. */
public Vector2 worldToParent (Vector2 world) { public Vector2 worldToParent (Vector2 world) {
if (world == null) throw new IllegalArgumentException("world cannot be null."); if (world == null) throw new IllegalArgumentException("world cannot be null.");
return parent == null ? world : parentApplied.worldToLocal(world); return parent == null ? world : parent.worldToLocal(world);
} }
/** Transforms a point from the parent bone's coordinates to world coordinates. */ /** Transforms a point from the parent bone's coordinates to world coordinates. */
public Vector2 parentToWorld (Vector2 world) { public Vector2 parentToWorld (Vector2 world) {
if (world == null) throw new IllegalArgumentException("world cannot be null."); if (world == null) throw new IllegalArgumentException("world cannot be null.");
return parent == null ? world : parentApplied.localToWorld(world); return parent == null ? world : parent.localToWorld(world);
} }
/** Transforms a world rotation to a local rotation. */ /** Transforms a world rotation to a local rotation. */
@ -358,8 +360,8 @@ public class BoneApplied extends Bone implements Updatable {
/** Rotates the world transform the specified amount. /** Rotates the world transform the specified amount.
* <p> * <p>
* After changes are made to the world transform, {@link #updateAppliedTransform()} should be called and * After changes are made to the world transform, {@link #updateLocalTransform()} should be called and {@link #update(Physics)}
* {@link #update(Physics)} will need to be called on any child bones, recursively. */ * will need to be called on any child bones, recursively. */
public void rotateWorld (float degrees) { public void rotateWorld (float degrees) {
degrees *= degRad; degrees *= degRad;
float sin = sin(degrees), cos = cos(degrees); float sin = sin(degrees), cos = cos(degrees);

View File

@ -34,7 +34,7 @@ import com.badlogic.gdx.utils.Null;
import com.esotericsoftware.spine.Skeleton.Physics; import com.esotericsoftware.spine.Skeleton.Physics;
/** Stores the setup pose for a {@link Bone}. */ /** Stores the setup pose for a {@link BonePose}. */
public class BoneData { public class BoneData {
final int index; final int index;
final String name; final String name;

View File

@ -0,0 +1,145 @@
/******************************************************************************
* 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;
import com.esotericsoftware.spine.BoneData.Inherit;
/** Stores a bone's current pose.
* <p>
* A bone has a local transform which is used to compute its world transform. A bone also has an applied transform, which is a
* local transform that can be applied to compute the world transform. The local transform and applied transform may differ if a
* constraint or application code modifies the world transform after it was computed from the local transform. */
public class BonePose {
float x, y, rotation, scaleX, scaleY, shearX, shearY;
Inherit inherit;
BonePose () {
}
/** Copy constructor. */
public BonePose (BonePose bone) {
x = bone.x;
y = bone.y;
rotation = bone.rotation;
scaleX = bone.scaleX;
scaleY = bone.scaleY;
shearX = bone.shearX;
shearY = bone.shearY;
inherit = bone.inherit;
}
/** The local x translation. */
public float getX () {
return x;
}
public void setX (float x) {
this.x = x;
}
/** The local y translation. */
public float getY () {
return y;
}
public void setY (float y) {
this.y = y;
}
public void setPosition (float x, float y) {
this.x = x;
this.y = y;
}
/** The local rotation in degrees, counter clockwise. */
public float getRotation () {
return rotation;
}
public void setRotation (float rotation) {
this.rotation = rotation;
}
/** The local scaleX. */
public float getScaleX () {
return scaleX;
}
public void setScaleX (float scaleX) {
this.scaleX = scaleX;
}
/** The local scaleY. */
public float getScaleY () {
return scaleY;
}
public void setScaleY (float scaleY) {
this.scaleY = scaleY;
}
public void setScale (float scaleX, float scaleY) {
this.scaleX = scaleX;
this.scaleY = scaleY;
}
public void setScale (float scale) {
scaleX = scale;
scaleY = scale;
}
/** The local shearX. */
public float getShearX () {
return shearX;
}
public void setShearX (float shearX) {
this.shearX = shearX;
}
/** The local shearY. */
public float getShearY () {
return shearY;
}
public void setShearY (float shearY) {
this.shearY = shearY;
}
/** Determines how parent world transforms affect this bone. */
public Inherit getInherit () {
return inherit;
}
public void setInherit (Inherit inherit) {
if (inherit == null) throw new IllegalArgumentException("inherit cannot be null.");
this.inherit = inherit;
}
}

View File

@ -107,7 +107,7 @@ public class IkConstraint implements Updatable {
} }
/** The bone that is the IK target. */ /** The bone that is the IK target. */
public Bone getTarget () { public BoneApplied getTarget () {
return target; return target;
} }
@ -167,6 +167,13 @@ public class IkConstraint implements Updatable {
this.stretch = stretch; this.stretch = stretch;
} }
/** Returns false when this constraint won't be updated by
* {@link Skeleton#updateWorldTransform(com.esotericsoftware.spine.Skeleton.Physics)} because a skin is required and the
* {@link Skeleton#getSkin() active skin} does not contain this item.
* @see Skin#getBones()
* @see Skin#getConstraints()
* @see ConstraintData#getSkinRequired()
* @see Skeleton#updateCache() */
public boolean isActive () { public boolean isActive () {
return active; return active;
} }
@ -184,20 +191,21 @@ public class IkConstraint implements Updatable {
static public void apply (BoneApplied bone, float targetX, float targetY, boolean compress, boolean stretch, boolean uniform, static public void apply (BoneApplied bone, float targetX, float targetY, boolean compress, boolean stretch, boolean uniform,
float alpha) { float alpha) {
if (bone == null) throw new IllegalArgumentException("bone cannot be null."); if (bone == null) throw new IllegalArgumentException("bone cannot be null.");
BoneApplied p = bone.parentApplied; BoneApplied p = bone.parent;
float pa = p.a, pb = p.b, pc = p.c, pd = p.d; float pa = p.a, pb = p.b, pc = p.c, pd = p.d;
float rotationIK = -bone.shearX - bone.rotation, tx, ty; float rotationIK = -bone.shearX - bone.rotation, tx, ty;
switch (bone.inherit) { switch (bone.inherit) {
case onlyTranslation: case onlyTranslation:
tx = (targetX - bone.worldX) * Math.signum(bone.skeleton.scaleX); tx = (targetX - bone.worldX) * Math.signum(bone.pose.skeleton.scaleX);
ty = (targetY - bone.worldY) * Math.signum(bone.skeleton.scaleY); ty = (targetY - bone.worldY) * Math.signum(bone.pose.skeleton.scaleY);
break; break;
case noRotationOrReflection: case noRotationOrReflection:
float s = Math.abs(pa * pd - pb * pc) / Math.max(0.0001f, pa * pa + pc * pc); float s = Math.abs(pa * pd - pb * pc) / Math.max(0.0001f, pa * pa + pc * pc);
float sa = pa / bone.skeleton.scaleX; Skeleton skeleton = bone.pose.skeleton;
float sc = pc / bone.skeleton.scaleY; float sa = pa / skeleton.scaleX;
pb = -sc * s * bone.skeleton.scaleX; float sc = pc / skeleton.scaleY;
pd = sa * s * bone.skeleton.scaleY; pb = -sc * s * skeleton.scaleX;
pd = sa * s * skeleton.scaleY;
rotationIK += atan2Deg(sc, sa); rotationIK += atan2Deg(sc, sa);
// Fall through. // Fall through.
default: default:
@ -225,7 +233,7 @@ public class IkConstraint implements Updatable {
ty = targetY - bone.worldY; ty = targetY - bone.worldY;
} }
} }
float b = bone.data.length * bone.scaleX; float b = bone.pose.data.length * bone.scaleX;
if (b > 0.0001f) { if (b > 0.0001f) {
float dd = tx * tx + ty * ty; float dd = tx * tx + ty * ty;
if ((compress && dd < b * b) || (stretch && dd > b * b)) { if ((compress && dd < b * b) || (stretch && dd > b * b)) {
@ -274,7 +282,7 @@ public class IkConstraint implements Updatable {
cwx = a * child.x + b * child.y + parent.worldX; cwx = a * child.x + b * child.y + parent.worldX;
cwy = c * child.x + d * child.y + parent.worldY; cwy = c * child.x + d * child.y + parent.worldY;
} }
BoneApplied pp = parent.parentApplied; BoneApplied pp = parent.parent;
a = pp.a; a = pp.a;
b = pp.b; b = pp.b;
c = pp.c; c = pp.c;
@ -282,7 +290,7 @@ public class IkConstraint implements Updatable {
float id = a * d - b * c, x = cwx - pp.worldX, y = cwy - pp.worldY; float id = a * d - b * c, x = cwx - pp.worldX, y = cwy - pp.worldY;
id = Math.abs(id) <= 0.0001f ? 0 : 1 / id; id = Math.abs(id) <= 0.0001f ? 0 : 1 / id;
float dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; float dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py;
float l1 = (float)Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2; float l1 = (float)Math.sqrt(dx * dx + dy * dy), l2 = child.pose.data.length * csx, a1, a2;
if (l1 < 0.0001f) { if (l1 < 0.0001f) {
apply(parent, targetX, targetY, false, stretch, false, alpha); apply(parent, targetX, targetY, false, stretch, false, alpha);
child.rotation = 0; child.rotation = 0;

View File

@ -119,7 +119,7 @@ public class PathConstraint implements Updatable {
if (scale) { if (scale) {
for (int i = 0, n = spacesCount - 1; i < n; i++) { for (int i = 0, n = spacesCount - 1; i < n; i++) {
var bone = (BoneApplied)bones[i]; var bone = (BoneApplied)bones[i];
float setupLength = bone.data.length; float setupLength = bone.pose.data.length;
float x = setupLength * bone.a, y = setupLength * bone.c; float x = setupLength * bone.a, y = setupLength * bone.c;
lengths[i] = (float)Math.sqrt(x * x + y * y); lengths[i] = (float)Math.sqrt(x * x + y * y);
} }
@ -130,7 +130,7 @@ public class PathConstraint implements Updatable {
float sum = 0; float sum = 0;
for (int i = 0, n = spacesCount - 1; i < n;) { for (int i = 0, n = spacesCount - 1; i < n;) {
var bone = (BoneApplied)bones[i]; var bone = (BoneApplied)bones[i];
float setupLength = bone.data.length; float setupLength = bone.pose.data.length;
if (setupLength < epsilon) { if (setupLength < epsilon) {
if (scale) lengths[i] = 0; if (scale) lengths[i] = 0;
spaces[++i] = spacing; spaces[++i] = spacing;
@ -152,7 +152,7 @@ public class PathConstraint implements Updatable {
boolean lengthSpacing = data.spacingMode == SpacingMode.length; boolean lengthSpacing = data.spacingMode == SpacingMode.length;
for (int i = 0, n = spacesCount - 1; i < n;) { for (int i = 0, n = spacesCount - 1; i < n;) {
var bone = (BoneApplied)bones[i]; var bone = (BoneApplied)bones[i];
float setupLength = bone.data.length; float setupLength = bone.pose.data.length;
if (setupLength < epsilon) { if (setupLength < epsilon) {
if (scale) lengths[i] = 0; if (scale) lengths[i] = 0;
spaces[++i] = spacing; spaces[++i] = spacing;
@ -203,7 +203,7 @@ public class PathConstraint implements Updatable {
if (tip) { if (tip) {
cos = cos(r); cos = cos(r);
sin = sin(r); sin = sin(r);
float length = bone.data.length; float length = bone.pose.data.length;
boneX += (length * (cos * a - sin * c) - dx) * mixRotate; boneX += (length * (cos * a - sin * c) - dx) * mixRotate;
boneY += (length * (sin * a + cos * c) - dy) * mixRotate; boneY += (length * (sin * a + cos * c) - dy) * mixRotate;
} else } else
@ -220,7 +220,7 @@ public class PathConstraint implements Updatable {
bone.c = sin * a + cos * c; bone.c = sin * a + cos * c;
bone.d = sin * b + cos * d; bone.d = sin * b + cos * d;
} }
bone.updateAppliedTransform(); bone.updateLocalTransform();
} }
} }
@ -542,6 +542,13 @@ public class PathConstraint implements Updatable {
this.slot = slot; this.slot = slot;
} }
/** Returns false when this constraint won't be updated by
* {@link Skeleton#updateWorldTransform(com.esotericsoftware.spine.Skeleton.Physics)} because a skin is required and the
* {@link Skeleton#getSkin() active skin} does not contain this item.
* @see Skin#getBones()
* @see Skin#getConstraints()
* @see ConstraintData#getSkinRequired()
* @see Skeleton#updateCache() */
public boolean isActive () { public boolean isActive () {
return active; return active;
} }

View File

@ -127,7 +127,7 @@ public class PhysicsConstraint implements Updatable {
boolean x = data.x > 0, y = data.y > 0, rotateOrShearX = data.rotate > 0 || data.shearX > 0, scaleX = data.scaleX > 0; boolean x = data.x > 0, y = data.y > 0, rotateOrShearX = data.rotate > 0 || data.shearX > 0, scaleX = data.scaleX > 0;
BoneApplied bone = this.bone; BoneApplied bone = this.bone;
float l = bone.data.length; float l = bone.pose.data.length;
switch (physics) { switch (physics) {
case none: case none:
@ -282,7 +282,7 @@ public class PhysicsConstraint implements Updatable {
tx = l * bone.a; tx = l * bone.a;
ty = l * bone.c; ty = l * bone.c;
} }
bone.updateAppliedTransform(); bone.updateLocalTransform();
} }
/** The bone constrained by this physics constraint. */ /** The bone constrained by this physics constraint. */
@ -351,6 +351,13 @@ public class PhysicsConstraint implements Updatable {
this.mix = mix; this.mix = mix;
} }
/** Returns false when this constraint won't be updated by
* {@link Skeleton#updateWorldTransform(com.esotericsoftware.spine.Skeleton.Physics)} because a skin is required and the
* {@link Skeleton#getSkin() active skin} does not contain this item.
* @see Skin#getBones()
* @see Skin#getConstraints()
* @see ConstraintData#getSkinRequired()
* @see Skeleton#updateCache() */
public boolean isActive () { public boolean isActive () {
return active; return active;
} }

View File

@ -273,7 +273,7 @@ public class Skeleton {
} }
private void sortIkConstraint (IkConstraint constraint) { private void sortIkConstraint (IkConstraint constraint) {
constraint.active = constraint.target.active constraint.active = constraint.target.pose.active
&& (!constraint.data.skinRequired || (skin != null && skin.constraints.contains(constraint.data, true))); && (!constraint.data.skinRequired || (skin != null && skin.constraints.contains(constraint.data, true)));
if (!constraint.active) return; if (!constraint.active) return;
@ -297,7 +297,7 @@ public class Skeleton {
} }
private void sortTransformConstraint (TransformConstraint constraint) { private void sortTransformConstraint (TransformConstraint constraint) {
constraint.active = constraint.source.active constraint.active = constraint.source.pose.active
&& (!constraint.data.skinRequired || (skin != null && skin.constraints.contains(constraint.data, true))); && (!constraint.data.skinRequired || (skin != null && skin.constraints.contains(constraint.data, true)));
if (!constraint.active) return; if (!constraint.active) return;
@ -319,7 +319,7 @@ public class Skeleton {
updateCache.add(constraint); updateCache.add(constraint);
for (int i = 0; i < boneCount; i++) for (int i = 0; i < boneCount; i++)
sortReset(((BoneApplied)constrained[i]).children); sortReset(((BoneApplied)constrained[i]).pose.children);
for (int i = 0; i < boneCount; i++) for (int i = 0; i < boneCount; i++)
((BoneApplied)constrained[i]).pose.sorted = true; ((BoneApplied)constrained[i]).pose.sorted = true;
} }

View File

@ -70,8 +70,15 @@ public class Slider implements Updatable {
mix = data.mix; mix = data.mix;
} }
/** Returns false when this constraint won't be updated by
* {@link Skeleton#updateWorldTransform(com.esotericsoftware.spine.Skeleton.Physics)} because a skin is required and the
* {@link Skeleton#getSkin() active skin} does not contain this item.
* @see Skin#getBones()
* @see Skin#getConstraints()
* @see ConstraintData#getSkinRequired()
* @see Skeleton#updateCache() */
public boolean isActive () { public boolean isActive () {
return true; return active;
} }
public Animation getAnimation () { public Animation getAnimation () {

View File

@ -122,7 +122,7 @@ public class TransformConstraint implements Updatable {
if (localTarget) if (localTarget)
bone.update(null); bone.update(null);
else else
bone.updateAppliedTransform(); bone.updateLocalTransform();
} }
} }
@ -195,6 +195,13 @@ public class TransformConstraint implements Updatable {
this.mixShearY = mixShearY; this.mixShearY = mixShearY;
} }
/** Returns false when this constraint won't be updated by
* {@link Skeleton#updateWorldTransform(com.esotericsoftware.spine.Skeleton.Physics)} because a skin is required and the
* {@link Skeleton#getSkin() active skin} does not contain this item.
* @see Skin#getBones()
* @see Skin#getConstraints()
* @see ConstraintData#getSkinRequired()
* @see Skeleton#updateCache() */
public boolean isActive () { public boolean isActive () {
return active; return active;
} }

View File

@ -35,13 +35,4 @@ import com.esotericsoftware.spine.Skeleton.Physics;
public interface Updatable { public interface Updatable {
/** @param physics Determines how physics and other non-deterministic updates are applied. */ /** @param physics Determines how physics and other non-deterministic updates are applied. */
public void update (Physics physics); public void update (Physics physics);
/** Returns false when this item won't be updated by
* {@link Skeleton#updateWorldTransform(com.esotericsoftware.spine.Skeleton.Physics)} because a skin is required and the
* {@link Skeleton#getSkin() active skin} does not contain this item.
* @see Skin#getBones()
* @see Skin#getConstraints()
* @see BoneData#getSkinRequired()
* @see ConstraintData#getSkinRequired() */
public boolean isActive ();
} }

View File

@ -36,7 +36,7 @@ import com.badlogic.gdx.graphics.g2d.TextureAtlas.AtlasRegion;
import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.Null; import com.badlogic.gdx.utils.Null;
import com.esotericsoftware.spine.Bone; import com.esotericsoftware.spine.BonePose;
import com.esotericsoftware.spine.BoneApplied; import com.esotericsoftware.spine.BoneApplied;
import com.esotericsoftware.spine.Slot; import com.esotericsoftware.spine.Slot;

View File

@ -34,8 +34,9 @@ import static com.esotericsoftware.spine.utils.SpineUtils.*;
import com.badlogic.gdx.utils.FloatArray; import com.badlogic.gdx.utils.FloatArray;
import com.badlogic.gdx.utils.Null; import com.badlogic.gdx.utils.Null;
import com.esotericsoftware.spine.Bone; import com.esotericsoftware.spine.BonePose;
import com.esotericsoftware.spine.BoneApplied; import com.esotericsoftware.spine.BoneApplied;
import com.esotericsoftware.spine.Bone;
import com.esotericsoftware.spine.Skeleton; import com.esotericsoftware.spine.Skeleton;
import com.esotericsoftware.spine.Slot; import com.esotericsoftware.spine.Slot;