[libgdx] Skip bones in update cache when a slider mix is 0.

This commit is contained in:
Nathan Sweet 2025-04-19 19:12:27 -04:00
parent 20683ff9ce
commit adfcb434a5
5 changed files with 32 additions and 13 deletions

View File

@ -65,4 +65,11 @@ public class Bone extends PosedActive<BoneData, BoneLocal, BonePose> {
public Array<Bone> getChildren () { public Array<Bone> getChildren () {
return children; return children;
} }
void resetUpdate () {
applied.update = 0;
Bone[] children = this.children.items;
for (int i = 0, n = this.children.size; i < n; i++)
children[i].resetUpdate();
}
} }

View File

@ -15,24 +15,23 @@ public class BonePose extends BoneLocal implements Update {
Bone bone; Bone bone;
float a, b, worldX; float a, b, worldX;
float c, d, worldY; float c, d, worldY;
int update;
BonePose () { BonePose () {
} }
/** Computes the world transform using the parent bone and this bone's local applied transform. */ /** Called by {@link Skeleton#updateCache()} to compute the world transform, if needed. */
public void updateWorldTransform (Skeleton skeleton) { public void update (Skeleton skeleton, Physics physics) {
update(skeleton, null); if (update != skeleton.update) updateWorldTransform(skeleton);
} }
/** Computes the world transform using the parent bone and this bone's local transform. /** Computes the world transform using the parent bone's applied pose and this pose. Child bones are not updated.
* <p>
* See {@link #updateWorldTransform(float, float, float, float, float, float, float)}. */
/** Computes the world transform using the parent bone and the specified local transform. The applied transform is set to the
* specified local transform. Child bones are not updated.
* <p> * <p>
* 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 (Skeleton skeleton, Physics physics) { public void updateWorldTransform (Skeleton skeleton) {
update = skeleton.update;
if (bone.parent == null) { // Root bone. if (bone.parent == null) { // Root bone.
float sx = skeleton.scaleX, sy = skeleton.scaleY; float sx = skeleton.scaleX, sy = skeleton.scaleY;
float rx = (rotation + shearX) * degRad; float rx = (rotation + shearX) * degRad;
@ -140,6 +139,8 @@ public class BonePose extends BoneLocal implements Update {
* Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. The local 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 updateLocalTransform (Skeleton skeleton) { public void updateLocalTransform (Skeleton skeleton) {
update = skeleton.update;
if (bone.parent == null) { if (bone.parent == null) {
x = worldX - skeleton.x; x = worldX - skeleton.x;
y = worldY - skeleton.y; y = worldY - skeleton.y;
@ -353,8 +354,8 @@ public class BonePose extends BoneLocal implements Update {
/** 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 #updateLocalTransform(Skeleton)} should be called and * After changes are made to the world transform, {@link #updateLocalTransform(Skeleton)} should be called on this bone and any
* {@link #update(Skeleton, Physics)} will need to be called on any child bones, recursively. */ * 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

@ -61,6 +61,7 @@ public class Skeleton {
@Null Skin skin; @Null Skin skin;
final Color color; final Color color;
float x, y, scaleX = 1, scaleY = 1, time; float x, y, scaleX = 1, scaleY = 1, time;
int update;
public Skeleton (SkeletonData data) { public Skeleton (SkeletonData data) {
if (data == null) throw new IllegalArgumentException("data cannot be null."); if (data == null) throw new IllegalArgumentException("data cannot be null.");
@ -224,6 +225,8 @@ public class Skeleton {
* 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 updateWorldTransform (Physics physics) { public void updateWorldTransform (Physics physics) {
update++;
Posed[] resetCache = this.resetCache.items; Posed[] resetCache = this.resetCache.items;
for (int i = 0, n = this.resetCache.size; i < n; i++) for (int i = 0, n = this.resetCache.size; i < n; i++)
resetCache[i].resetAppliedPose(); resetCache[i].resetAppliedPose();
@ -241,6 +244,8 @@ public class Skeleton {
public void updateWorldTransform (Physics physics, BonePose parent) { public void updateWorldTransform (Physics physics, BonePose parent) {
if (parent == null) throw new IllegalArgumentException("parent cannot be null."); if (parent == null) throw new IllegalArgumentException("parent cannot be null.");
update++;
Posed[] resetCache = this.resetCache.items; Posed[] resetCache = this.resetCache.items;
for (int i = 0, n = this.resetCache.size; i < n; i++) for (int i = 0, n = this.resetCache.size; i < n; i++)
resetCache[i].resetAppliedPose(); resetCache[i].resetAppliedPose();

View File

@ -55,12 +55,17 @@ public class Slider extends Constraint<Slider, SliderData, SliderPose> {
if (pose.mix == 0) return; if (pose.mix == 0) return;
SliderPose pose = applied; SliderPose pose = applied;
data.animation.apply(skeleton, pose.time, pose.time, false, null, pose.mix, MixBlend.replace, MixDirection.in, true); data.animation.apply(skeleton, pose.time, pose.time, false, null, pose.mix, MixBlend.replace, MixDirection.in, true);
Timeline[] timelines = data.animation.timelines.items;
int timelineCount = data.animation.timelines.size;
Bone[] bones = skeleton.bones.items;
for (int i = 0; i < timelineCount; i++)
if (timelines[i] instanceof BoneTimeline boneTimeline) bones[boneTimeline.getBoneIndex()].resetUpdate();
} }
void sort (Skeleton skeleton) { void sort (Skeleton skeleton) {
Timeline[] timelines = data.animation.timelines.items; Timeline[] timelines = data.animation.timelines.items;
int timelineCount = data.animation.timelines.size; int timelineCount = data.animation.timelines.size;
Bone[] bones = skeleton.bones.items; Bone[] bones = skeleton.bones.items;
for (int i = 0; i < timelineCount; i++) for (int i = 0; i < timelineCount; i++)
if (timelines[i] instanceof BoneTimeline boneTimeline) skeleton.sortBone(bones[boneTimeline.getBoneIndex()]); if (timelines[i] instanceof BoneTimeline boneTimeline) skeleton.sortBone(bones[boneTimeline.getBoneIndex()]);
@ -72,6 +77,7 @@ public class Slider extends Constraint<Slider, SliderData, SliderPose> {
Timeline t = timelines[i]; Timeline t = timelines[i];
if (t instanceof BoneTimeline timeline) { if (t instanceof BoneTimeline timeline) {
Bone bone = bones[timeline.getBoneIndex()]; Bone bone = bones[timeline.getBoneIndex()];
skeleton.resetCache(bone);
skeleton.sortReset(bone.children); skeleton.sortReset(bone.children);
bone.sorted = false; bone.sorted = false;
} else if (t instanceof SlotTimeline timeline) } else if (t instanceof SlotTimeline timeline)

View File

@ -94,7 +94,7 @@ public class TransformConstraint extends Constraint<TransformConstraint, Transfo
} }
} }
if (localTarget) if (localTarget)
bone.update(skeleton, null); bone.updateWorldTransform(skeleton);
else else
bone.updateLocalTransform(skeleton); bone.updateLocalTransform(skeleton);
} }