[libgdx] Give all arrays types, direct array access, removed casts.

This commit is contained in:
Nathan Sweet 2025-04-18 12:40:54 -04:00
parent 6c1d2f625e
commit 1f92218c23
26 changed files with 461 additions and 599 deletions

View File

@ -73,7 +73,9 @@ public class AttachmentTimelineTests {
timeline.setFrame(0, 0, "attachment1");
timeline.setFrame(1, 0.5f, "attachment2");
Animation animation = new Animation("animation", Array.with((Timeline)timeline), 1);
Array<Timeline> timelines = new Array(true, 1, Timeline[]::new);
timelines.add(timeline);
Animation animation = new Animation("animation", timelines, 1);
animation.setDuration(1);
state = new AnimationState(new AnimationStateData(skeletonData));

View File

@ -72,9 +72,9 @@ public class Animation {
int n = timelines.size;
timelineIds.clear(n);
Object[] items = timelines.items;
Timeline[] items = timelines.items;
for (int i = 0; i < n; i++)
timelineIds.addAll(((Timeline)items[i]).getPropertyIds());
timelineIds.addAll(items[i].getPropertyIds());
}
/** Returns true if this animation contains a timeline with any of the specified property IDs. */
@ -123,9 +123,9 @@ public class Animation {
if (lastTime > 0) lastTime %= duration;
}
Object[] timelines = this.timelines.items;
Timeline[] timelines = this.timelines.items;
for (int i = 0, n = this.timelines.size; i < n; i++)
((Timeline)timelines[i]).apply(skeleton, lastTime, time, events, alpha, blend, direction, appliedPose);
timelines[i].apply(skeleton, lastTime, time, events, alpha, blend, direction, appliedPose);
}
/** The animation's name, which is unique across all animations in the skeleton. */
@ -265,12 +265,6 @@ public class Animation {
}
}
/** An interface for timelines which change the property of a bone. */
static public interface BoneTimeline {
/** The index of the bone in {@link Skeleton#getBones()} that will be changed when this timeline is applied. */
public int getBoneIndex ();
}
/** An interface for timelines which change the property of a slot. */
static public interface SlotTimeline {
/** The index of the slot in {@link Skeleton#getSlots()} that will be changed when this timeline is applied. */
@ -544,12 +538,17 @@ public class Animation {
}
}
/** Changes a bone's local {@link BoneLocal#getRotation()}. */
static public class RotateTimeline extends CurveTimeline1 implements BoneTimeline {
/** An interface for timelines which change the property of a bone. */
static public interface BoneTimeline {
/** The index of the bone in {@link Skeleton#getBones()} that will be changed when this timeline is applied. */
public int getBoneIndex ();
}
static abstract public class BoneTimeline1 extends CurveTimeline1 implements BoneTimeline {
final int boneIndex;
public RotateTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, Property.rotate.ordinal() + "|" + boneIndex);
public BoneTimeline1 (int frameCount, int bezierCount, int boneIndex, Property property) {
super(frameCount, bezierCount, property.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
}
@ -560,36 +559,55 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex);
if (bone.active) {
BoneLocal pose = appliedPose ? bone.applied : bone.pose;
pose.rotation = getRelativeValue(time, alpha, blend, pose.rotation, bone.data.setup.rotation);
}
Bone bone = skeleton.bones.items[boneIndex];
if (bone.active) apply(appliedPose ? bone.applied : bone.pose, bone.data.setup, time, alpha, blend, direction);
}
abstract protected void apply (BoneLocal pose, BoneLocal setup, float time, float alpha, MixBlend blend,
MixDirection direction);
}
static abstract public class BoneTimeline2 extends CurveTimeline2 implements BoneTimeline {
final int boneIndex;
public BoneTimeline2 (int frameCount, int bezierCount, int boneIndex, Property property1, Property property2) {
super(frameCount, bezierCount, property1.ordinal() + "|" + boneIndex, property2.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.items[boneIndex];
if (bone.active) apply(appliedPose ? bone.applied : bone.pose, bone.data.setup, time, alpha, blend, direction);
}
abstract protected void apply (BoneLocal pose, BoneLocal setup, float time, float alpha, MixBlend blend,
MixDirection direction);
}
/** Changes a bone's local {@link BoneLocal#getRotation()}. */
static public class RotateTimeline extends BoneTimeline1 {
public RotateTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, boneIndex, Property.rotate);
}
protected void apply (BoneLocal pose, BoneLocal setup, float time, float alpha, MixBlend blend, MixDirection direction) {
pose.rotation = getRelativeValue(time, alpha, blend, pose.rotation, setup.rotation);
}
}
/** Changes a bone's local {@link BoneLocal#getX()} and {@link BoneLocal#getY()}. */
static public class TranslateTimeline extends CurveTimeline2 implements BoneTimeline {
final int boneIndex;
static public class TranslateTimeline extends BoneTimeline2 {
public TranslateTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, //
Property.x.ordinal() + "|" + boneIndex, //
Property.y.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
super(frameCount, bezierCount, boneIndex, Property.x, Property.y);
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex);
if (!bone.active) return;
BoneLocal pose = appliedPose ? bone.applied : bone.pose, setup = bone.data.setup;
protected void apply (BoneLocal pose, BoneLocal setup, float time, float alpha, MixBlend blend, MixDirection direction) {
float[] frames = this.frames;
if (time < frames[0]) {
switch (blend) {
@ -642,75 +660,34 @@ public class Animation {
}
/** Changes a bone's local {@link BoneLocal#getX()}. */
static public class TranslateXTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex;
static public class TranslateXTimeline extends BoneTimeline1 {
public TranslateXTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, Property.x.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
super(frameCount, bezierCount, boneIndex, Property.x);
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex);
if (bone.active) {
BoneLocal pose = appliedPose ? bone.applied : bone.pose;
pose.x = getRelativeValue(time, alpha, blend, pose.x, bone.data.setup.x);
}
protected void apply (BoneLocal pose, BoneLocal setup, float time, float alpha, MixBlend blend, MixDirection direction) {
pose.x = getRelativeValue(time, alpha, blend, pose.x, setup.x);
}
}
/** Changes a bone's local {@link BoneLocal#getY()}. */
static public class TranslateYTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex;
static public class TranslateYTimeline extends BoneTimeline1 {
public TranslateYTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, Property.y.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
super(frameCount, bezierCount, boneIndex, Property.y);
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex);
if (bone.active) {
BoneLocal pose = appliedPose ? bone.applied : bone.pose;
pose.y = getRelativeValue(time, alpha, blend, pose.y, bone.data.setup.y);
}
protected void apply (BoneLocal pose, BoneLocal setup, float time, float alpha, MixBlend blend, MixDirection direction) {
pose.y = getRelativeValue(time, alpha, blend, pose.y, setup.y);
}
}
/** Changes a bone's local {@link BoneLocal#getScaleX()} and {@link BoneLocal#getScaleY()}. */
static public class ScaleTimeline extends CurveTimeline2 implements BoneTimeline {
final int boneIndex;
static public class ScaleTimeline extends BoneTimeline2 {
public ScaleTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, //
Property.scaleX.ordinal() + "|" + boneIndex, //
Property.scaleY.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
super(frameCount, bezierCount, boneIndex, Property.scaleX, Property.scaleY);
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex);
if (!bone.active) return;
BoneLocal pose = appliedPose ? bone.applied : bone.pose, setup = bone.data.setup;
protected void apply (BoneLocal pose, BoneLocal setup, float time, float alpha, MixBlend blend, MixDirection direction) {
float[] frames = this.frames;
if (time < frames[0]) {
switch (blend) {
@ -802,75 +779,34 @@ public class Animation {
}
/** Changes a bone's local {@link BoneLocal#getScaleX()}. */
static public class ScaleXTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex;
static public class ScaleXTimeline extends BoneTimeline1 {
public ScaleXTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, Property.scaleX.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
super(frameCount, bezierCount, boneIndex, Property.scaleX);
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex);
if (bone.active) {
BoneLocal pose = appliedPose ? bone.applied : bone.pose;
pose.scaleX = getScaleValue(time, alpha, blend, direction, pose.scaleX, bone.data.setup.scaleX);
}
protected void apply (BoneLocal pose, BoneLocal setup, float time, float alpha, MixBlend blend, MixDirection direction) {
pose.scaleX = getScaleValue(time, alpha, blend, direction, pose.scaleX, setup.scaleX);
}
}
/** Changes a bone's local {@link BoneLocal#getScaleY()}. */
static public class ScaleYTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex;
static public class ScaleYTimeline extends BoneTimeline1 {
public ScaleYTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, Property.scaleY.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
super(frameCount, bezierCount, boneIndex, Property.scaleY);
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex);
if (bone.active) {
BoneLocal pose = appliedPose ? bone.applied : bone.pose;
pose.scaleY = getScaleValue(time, alpha, blend, direction, pose.scaleY, bone.data.setup.scaleY);
}
protected void apply (BoneLocal pose, BoneLocal setup, float time, float alpha, MixBlend blend, MixDirection direction) {
pose.scaleY = getScaleValue(time, alpha, blend, direction, pose.scaleY, setup.scaleY);
}
}
/** Changes a bone's local {@link BoneLocal#getShearX()} and {@link BoneLocal#getShearY()}. */
static public class ShearTimeline extends CurveTimeline2 implements BoneTimeline {
final int boneIndex;
static public class ShearTimeline extends BoneTimeline2 {
public ShearTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, //
Property.shearX.ordinal() + "|" + boneIndex, //
Property.shearY.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
super(frameCount, bezierCount, boneIndex, Property.shearX, Property.shearY);
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex);
if (!bone.active) return;
BoneLocal pose = appliedPose ? bone.applied : bone.pose, setup = bone.data.setup;
protected void apply (BoneLocal pose, BoneLocal setup, float time, float alpha, MixBlend blend, MixDirection direction) {
float[] frames = this.frames;
if (time < frames[0]) {
switch (blend) {
@ -923,50 +859,24 @@ public class Animation {
}
/** Changes a bone's local {@link BoneLocal#getShearX()}. */
static public class ShearXTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex;
static public class ShearXTimeline extends BoneTimeline1 {
public ShearXTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, Property.shearX.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
super(frameCount, bezierCount, boneIndex, Property.shearX);
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex);
if (bone.active) {
BoneLocal pose = appliedPose ? bone.applied : bone.pose;
pose.shearX = getRelativeValue(time, alpha, blend, pose.shearX, bone.data.setup.shearX);
}
protected void apply (BoneLocal pose, BoneLocal setup, float time, float alpha, MixBlend blend, MixDirection direction) {
pose.shearX = getRelativeValue(time, alpha, blend, pose.shearX, setup.shearX);
}
}
/** Changes a bone's local {@link BoneLocal#getShearY()}. */
static public class ShearYTimeline extends CurveTimeline1 implements BoneTimeline {
final int boneIndex;
static public class ShearYTimeline extends BoneTimeline1 {
public ShearYTimeline (int frameCount, int bezierCount, int boneIndex) {
super(frameCount, bezierCount, Property.shearY.ordinal() + "|" + boneIndex);
this.boneIndex = boneIndex;
super(frameCount, bezierCount, boneIndex, Property.shearY);
}
public int getBoneIndex () {
return boneIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex);
if (bone.active) {
BoneLocal pose = appliedPose ? bone.applied : bone.pose;
pose.shearY = getRelativeValue(time, alpha, blend, pose.shearY, bone.data.setup.shearY);
}
protected void apply (BoneLocal pose, BoneLocal setup, float time, float alpha, MixBlend blend, MixDirection direction) {
pose.shearY = getRelativeValue(time, alpha, blend, pose.shearY, setup.shearY);
}
}
@ -1002,7 +912,7 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Bone bone = skeleton.bones.get(boneIndex);
Bone bone = skeleton.bones.items[boneIndex];
if (!bone.active) return;
BoneLocal pose = appliedPose ? bone.applied : bone.pose;
@ -1020,28 +930,43 @@ public class Animation {
}
}
/** Changes a slot's {@link SlotPose#getColor()}. */
static public class RGBATimeline extends CurveTimeline implements SlotTimeline {
static public final int ENTRIES = 5;
static private final int R = 1, G = 2, B = 3, A = 4;
static abstract public class SlotCurveTimeline extends CurveTimeline implements SlotTimeline {
final int slotIndex;
public RGBATimeline (int frameCount, int bezierCount, int slotIndex) {
super(frameCount, bezierCount, //
Property.rgb.ordinal() + "|" + slotIndex, //
Property.alpha.ordinal() + "|" + slotIndex);
public SlotCurveTimeline (int frameCount, int bezierCount, int slotIndex, String... propertyIds) {
super(frameCount, bezierCount, propertyIds);
this.slotIndex = slotIndex;
}
public int getFrameEntries () {
return ENTRIES;
}
public int getSlotIndex () {
return slotIndex;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Slot slot = skeleton.slots.items[slotIndex];
if (slot.bone.active) apply(slot, appliedPose ? slot.applied : slot.pose, time, alpha, blend);
}
abstract protected void apply (Slot slot, SlotPose pose, float time, float alpha, MixBlend blend);
}
/** Changes a slot's {@link SlotPose#getColor()}. */
static public class RGBATimeline extends SlotCurveTimeline {
static public final int ENTRIES = 5;
static private final int R = 1, G = 2, B = 3, A = 4;
public RGBATimeline (int frameCount, int bezierCount, int slotIndex) {
super(frameCount, bezierCount, slotIndex, //
Property.rgb.ordinal() + "|" + slotIndex, //
Property.alpha.ordinal() + "|" + slotIndex);
}
public int getFrameEntries () {
return ENTRIES;
}
/** Sets the time and color for the specified frame.
* @param frame Between 0 and <code>frameCount</code>, inclusive.
* @param time The frame time in seconds. */
@ -1054,13 +979,7 @@ public class Animation {
frames[frame + A] = a;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Slot slot = skeleton.slots.get(slotIndex);
if (!slot.bone.active) return;
SlotPose pose = appliedPose ? slot.applied : slot.pose;
protected void apply (Slot slot, SlotPose pose, float time, float alpha, MixBlend blend) {
float[] frames = this.frames;
Color color = pose.color;
if (time < frames[0]) {
@ -1114,25 +1033,18 @@ public class Animation {
}
/** Changes the RGB for a slot's {@link SlotPose#getColor()}. */
static public class RGBTimeline extends CurveTimeline implements SlotTimeline {
static public class RGBTimeline extends SlotCurveTimeline {
static public final int ENTRIES = 4;
static private final int R = 1, G = 2, B = 3;
final int slotIndex;
public RGBTimeline (int frameCount, int bezierCount, int slotIndex) {
super(frameCount, bezierCount, Property.rgb.ordinal() + "|" + slotIndex);
this.slotIndex = slotIndex;
super(frameCount, bezierCount, slotIndex, Property.rgb.ordinal() + "|" + slotIndex);
}
public int getFrameEntries () {
return ENTRIES;
}
public int getSlotIndex () {
return slotIndex;
}
/** Sets the time and color for the specified frame.
* @param frame Between 0 and <code>frameCount</code>, inclusive.
* @param time The frame time in seconds. */
@ -1144,13 +1056,7 @@ public class Animation {
frames[frame + B] = b;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Slot slot = skeleton.slots.get(slotIndex);
if (!slot.bone.active) return;
SlotPose pose = appliedPose ? slot.applied : slot.pose;
protected void apply (Slot slot, SlotPose pose, float time, float alpha, MixBlend blend) {
float[] frames = this.frames;
Color color = pose.color;
if (time < frames[0]) {
@ -1227,7 +1133,7 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Slot slot = skeleton.slots.get(slotIndex);
Slot slot = skeleton.slots.items[slotIndex];
if (!slot.bone.active) return;
SlotPose pose = appliedPose ? slot.applied : slot.pose;
@ -1256,30 +1162,21 @@ public class Animation {
}
/** Changes a slot's {@link SlotPose#getColor()} and {@link SlotPose#getDarkColor()} for two color tinting. */
static public class RGBA2Timeline extends CurveTimeline implements SlotTimeline {
static public class RGBA2Timeline extends SlotCurveTimeline {
static public final int ENTRIES = 8;
static private final int R = 1, G = 2, B = 3, A = 4, R2 = 5, G2 = 6, B2 = 7;
final int slotIndex;
public RGBA2Timeline (int frameCount, int bezierCount, int slotIndex) {
super(frameCount, bezierCount, //
super(frameCount, bezierCount, slotIndex, //
Property.rgb.ordinal() + "|" + slotIndex, //
Property.alpha.ordinal() + "|" + slotIndex, //
Property.rgb2.ordinal() + "|" + slotIndex);
this.slotIndex = slotIndex;
}
public int getFrameEntries () {
return ENTRIES;
}
/** The index of the slot in {@link Skeleton#getSlots()} that will be changed when this timeline is applied. The
* {@link SlotPose#getDarkColor()} must not be null. */
public int getSlotIndex () {
return slotIndex;
}
/** Sets the time, light color, and dark color for the specified frame.
* @param frame Between 0 and <code>frameCount</code>, inclusive.
* @param time The frame time in seconds. */
@ -1295,13 +1192,7 @@ public class Animation {
frames[frame + B2] = b2;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Slot slot = skeleton.slots.get(slotIndex);
if (!slot.bone.active) return;
SlotPose pose = appliedPose ? slot.applied : slot.pose;
protected void apply (Slot slot, SlotPose pose, float time, float alpha, MixBlend blend) {
float[] frames = this.frames;
Color light = pose.color, dark = pose.darkColor;
if (time < frames[0]) {
@ -1387,29 +1278,20 @@ public class Animation {
}
/** Changes the RGB for a slot's {@link SlotPose#getColor()} and {@link SlotPose#getDarkColor()} for two color tinting. */
static public class RGB2Timeline extends CurveTimeline implements SlotTimeline {
static public class RGB2Timeline extends SlotCurveTimeline {
static public final int ENTRIES = 7;
static private final int R = 1, G = 2, B = 3, R2 = 4, G2 = 5, B2 = 6;
final int slotIndex;
public RGB2Timeline (int frameCount, int bezierCount, int slotIndex) {
super(frameCount, bezierCount, //
super(frameCount, bezierCount, slotIndex, //
Property.rgb.ordinal() + "|" + slotIndex, //
Property.rgb2.ordinal() + "|" + slotIndex);
this.slotIndex = slotIndex;
}
public int getFrameEntries () {
return ENTRIES;
}
/** The index of the slot in {@link Skeleton#getSlots()} that will be changed when this timeline is applied. The
* {@link SlotPose#getDarkColor()} must not be null. */
public int getSlotIndex () {
return slotIndex;
}
/** Sets the time, light color, and dark color for the specified frame.
* @param frame Between 0 and <code>frameCount</code>, inclusive.
* @param time The frame time in seconds. */
@ -1424,13 +1306,7 @@ public class Animation {
frames[frame + B2] = b2;
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Slot slot = skeleton.slots.get(slotIndex);
if (!slot.bone.active) return;
SlotPose pose = appliedPose ? slot.applied : slot.pose;
protected void apply (Slot slot, SlotPose pose, float time, float alpha, MixBlend blend) {
float[] frames = this.frames;
Color light = pose.color, dark = pose.darkColor;
if (time < frames[0]) {
@ -1555,7 +1431,7 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Slot slot = skeleton.slots.get(slotIndex);
Slot slot = skeleton.slots.items[slotIndex];
if (!slot.bone.active) return;
SlotPose pose = appliedPose ? slot.applied : slot.pose;
@ -1578,14 +1454,12 @@ public class Animation {
}
/** Changes a slot's {@link SlotPose#getDeform()} to deform a {@link VertexAttachment}. */
static public class DeformTimeline extends CurveTimeline implements SlotTimeline {
final int slotIndex;
static public class DeformTimeline extends SlotCurveTimeline {
final VertexAttachment attachment;
private final float[][] vertices;
public DeformTimeline (int frameCount, int bezierCount, int slotIndex, VertexAttachment attachment) {
super(frameCount, bezierCount, Property.deform.ordinal() + "|" + slotIndex + "|" + attachment.getId());
this.slotIndex = slotIndex;
super(frameCount, bezierCount, slotIndex, Property.deform.ordinal() + "|" + slotIndex + "|" + attachment.getId());
this.attachment = attachment;
vertices = new float[frameCount][];
}
@ -1594,10 +1468,6 @@ public class Animation {
return frames.length;
}
public int getSlotIndex () {
return slotIndex;
}
/** The attachment that will be deformed.
* <p>
* See {@link VertexAttachment#getTimelineAttachment()}. */
@ -1671,12 +1541,7 @@ public class Animation {
return y + (1 - y) * (time - x) / (frames[frame + getFrameEntries()] - x);
}
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Slot slot = skeleton.slots.get(slotIndex);
if (!slot.bone.active) return;
SlotPose pose = appliedPose ? slot.applied : slot.pose;
protected void apply (Slot slot, SlotPose pose, float time, float alpha, MixBlend blend) {
if (!(pose.attachment instanceof VertexAttachment vertexAttachment)
|| vertexAttachment.getTimelineAttachment() != attachment) return;
@ -1954,8 +1819,8 @@ public class Animation {
if (drawOrderToSetupIndex == null)
arraycopy(skeleton.slots.items, 0, skeleton.drawOrder.items, 0, skeleton.slots.size);
else {
Object[] slots = skeleton.slots.items;
Object[] drawOrder = skeleton.drawOrder.items;
Slot[] slots = skeleton.slots.items;
Slot[] drawOrder = skeleton.drawOrder.items;
for (int i = 0, n = drawOrderToSetupIndex.length; i < n; i++)
drawOrder[i] = slots[drawOrderToSetupIndex[i]];
}
@ -2004,12 +1869,13 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
var constraint = (IkConstraint)skeleton.constraints.get(constraintIndex);
var constraint = (IkConstraint)skeleton.constraints.items[constraintIndex];
if (!constraint.active) return;
IkConstraintPose pose = appliedPose ? constraint.applied : constraint.pose, setup = constraint.data.setup;
IkConstraintPose pose = appliedPose ? constraint.applied : constraint.pose;
float[] frames = this.frames;
if (time < frames[0]) {
IkConstraintPose setup = constraint.data.setup;
switch (blend) {
case setup:
pose.mix = setup.mix;
@ -2049,6 +1915,7 @@ public class Animation {
}
if (blend == MixBlend.setup) {
IkConstraintPose setup = constraint.data.setup;
pose.mix = setup.mix + (mix - setup.mix) * alpha;
pose.softness = setup.softness + (softness - setup.softness) * alpha;
if (direction == out) {
@ -2114,7 +1981,7 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
var constraint = (TransformConstraint)skeleton.constraints.get(constraintIndex);
var constraint = (TransformConstraint)skeleton.constraints.items[constraintIndex];
if (!constraint.active) return;
TransformConstraintPose pose = appliedPose ? constraint.applied : constraint.pose;
@ -2214,7 +2081,7 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
var constraint = (PathConstraint)skeleton.constraints.get(constraintIndex);
var constraint = (PathConstraint)skeleton.constraints.items[constraintIndex];
if (constraint.active) {
PathConstraintPose pose = appliedPose ? constraint.applied : constraint.pose;
pose.position = getAbsoluteValue(time, alpha, blend, pose.position, constraint.data.setup.position);
@ -2240,7 +2107,7 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
var constraint = (PathConstraint)skeleton.constraints.get(constraintIndex);
var constraint = (PathConstraint)skeleton.constraints.items[constraintIndex];
if (constraint.active) {
PathConstraintPose pose = appliedPose ? constraint.applied : constraint.pose;
pose.spacing = getAbsoluteValue(time, alpha, blend, pose.spacing, constraint.data.setup.spacing);
@ -2285,7 +2152,7 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
var constraint = (PathConstraint)skeleton.constraints.get(constraintIndex);
var constraint = (PathConstraint)skeleton.constraints.items[constraintIndex];
if (!constraint.active) return;
PathConstraintPose pose = appliedPose ? constraint.applied : constraint.pose;
@ -2365,16 +2232,16 @@ public class Animation {
if (constraintIndex == -1) {
float value = time >= frames[0] ? getCurveValue(time) : 0;
Object[] constraints = skeleton.physics.items;
PhysicsConstraint[] constraints = skeleton.physics.items;
for (int i = 0, n = skeleton.physics.size; i < n; i++) {
var constraint = (PhysicsConstraint)constraints[i];
PhysicsConstraint constraint = constraints[i];
if (constraint.active && global(constraint.data)) {
PhysicsConstraintPose pose = appliedPose ? constraint.applied : constraint.pose;
set(pose, getAbsoluteValue(time, alpha, blend, get(pose), get(constraint.data.setup), value));
}
}
} else {
var constraint = (PhysicsConstraint)skeleton.constraints.get(constraintIndex);
var constraint = (PhysicsConstraint)skeleton.constraints.items[constraintIndex];
if (constraint.active) {
PhysicsConstraintPose pose = appliedPose ? constraint.applied : constraint.pose;
set(pose, getAbsoluteValue(time, alpha, blend, get(pose), get(constraint.data.setup)));
@ -2556,7 +2423,7 @@ public class Animation {
PhysicsConstraint constraint = null;
if (constraintIndex != -1) {
constraint = (PhysicsConstraint)skeleton.constraints.get(constraintIndex);
constraint = (PhysicsConstraint)skeleton.constraints.items[constraintIndex];
if (!constraint.active) return;
}
@ -2573,9 +2440,9 @@ public class Animation {
if (constraint != null)
constraint.reset(skeleton);
else {
Object[] constraints = skeleton.physics.items;
PhysicsConstraint[] constraints = skeleton.physics.items;
for (int i = 0, n = skeleton.physics.size; i < n; i++) {
constraint = (PhysicsConstraint)constraints[i];
constraint = constraints[i];
if (constraint.active) constraint.reset(skeleton);
}
}
@ -2623,7 +2490,7 @@ public class Animation {
public void apply (Skeleton skeleton, float lastTime, float time, @Null Array<Event> events, float alpha, MixBlend blend,
MixDirection direction, boolean appliedPose) {
Slot slot = skeleton.slots.get(slotIndex);
Slot slot = skeleton.slots.items[slotIndex];
if (!slot.bone.active) return;
SlotPose pose = appliedPose ? slot.applied : slot.pose;

View File

@ -51,7 +51,7 @@ import com.esotericsoftware.spine.Animation.Timeline;
* <p>
* See <a href='https://esotericsoftware.com/spine-applying-animations/'>Applying Animations</a> in the Spine Runtimes Guide. */
public class AnimationState {
static final Animation emptyAnimation = new Animation("<empty>", new Array(0), 0);
static final Animation emptyAnimation = new Animation("<empty>", new Array(true, 0, Timeline[]::new), 0);
/** 1) A previously applied timeline has set this property.<br>
* Result: Mix from the current pose to the timeline pose. */
@ -87,9 +87,9 @@ public class AnimationState {
static private final int SETUP = 1, CURRENT = 2;
private AnimationStateData data;
final Array<TrackEntry> tracks = new Array();
private final Array<Event> events = new Array();
final SnapshotArray<AnimationStateListener> listeners = new SnapshotArray();
final Array<TrackEntry> tracks = new Array(true, 4, TrackEntry[]::new);
private final Array<Event> events = new Array(true, 4, Event[]::new);
final SnapshotArray<AnimationStateListener> listeners = new SnapshotArray(true, 16, AnimationStateListener[]::new);
private final EventQueue queue = new EventQueue();
private final ObjectSet<String> propertyIds = new ObjectSet();
boolean animationsChanged;
@ -114,9 +114,9 @@ public class AnimationState {
/** Increments each track entry {@link TrackEntry#getTrackTime()}, setting queued animations as current if needed. */
public void update (float delta) {
delta *= timeScale;
Object[] tracks = this.tracks.items;
TrackEntry[] tracks = this.tracks.items;
for (int i = 0, n = this.tracks.size; i < n; i++) {
var current = (TrackEntry)tracks[i];
TrackEntry current = tracks[i];
if (current == null) continue;
current.animationLast = current.nextAnimationLast;
@ -206,9 +206,9 @@ public class AnimationState {
Array<Event> events = this.events;
boolean applied = false;
Object[] tracks = this.tracks.items;
TrackEntry[] tracks = this.tracks.items;
for (int i = 0, n = this.tracks.size; i < n; i++) {
var current = (TrackEntry)tracks[i];
TrackEntry current = tracks[i];
if (current == null || current.delay > 0) continue;
applied = true;
@ -231,17 +231,15 @@ public class AnimationState {
applyEvents = null;
}
int timelineCount = current.animation.timelines.size;
Object[] timelines = current.animation.timelines.items;
Timeline[] timelines = current.animation.timelines.items;
if ((i == 0 && alpha == 1) || blend == MixBlend.add) {
if (i == 0) attachments = true;
for (int ii = 0; ii < timelineCount; ii++) {
Object timeline = timelines[ii];
Timeline timeline = timelines[ii];
if (timeline instanceof AttachmentTimeline attachmentTimeline)
applyAttachmentTimeline(attachmentTimeline, skeleton, applyTime, blend, attachments);
else {
((Timeline)timeline).apply(skeleton, animationLast, applyTime, applyEvents, alpha, blend, MixDirection.in,
false);
}
else
timeline.apply(skeleton, animationLast, applyTime, applyEvents, alpha, blend, MixDirection.in, false);
}
} else {
int[] timelineMode = current.timelineMode.items;
@ -252,7 +250,7 @@ public class AnimationState {
float[] timelinesRotation = current.timelinesRotation.items;
for (int ii = 0; ii < timelineCount; ii++) {
var timeline = (Timeline)timelines[ii];
Timeline timeline = timelines[ii];
MixBlend timelineBlend = timelineMode[ii] == SUBSEQUENT ? blend : MixBlend.setup;
if (!shortestRotation && timeline instanceof RotateTimeline rotateTimeline) {
applyRotateTimeline(rotateTimeline, skeleton, applyTime, alpha, timelineBlend, timelinesRotation, ii << 1,
@ -273,9 +271,9 @@ public class AnimationState {
// subsequent timelines see any deform, but the subsequent timelines don't set an attachment (eg they are also mixing out or
// the time is before the first key).
int setupState = unkeyedState + SETUP;
Object[] slots = skeleton.slots.items;
Slot[] slots = skeleton.slots.items;
for (int i = 0, n = skeleton.slots.size; i < n; i++) {
var slot = (Slot)slots[i];
var slot = slots[i];
if (slot.attachmentState == setupState) {
String attachmentName = slot.data.attachmentName;
slot.pose.setAttachment(attachmentName == null ? null : skeleton.getAttachment(slot.data.index, attachmentName));
@ -303,7 +301,7 @@ public class AnimationState {
boolean attachments = mix < from.mixAttachmentThreshold, drawOrder = mix < from.mixDrawOrderThreshold;
int timelineCount = from.animation.timelines.size;
Object[] timelines = from.animation.timelines.items;
Timeline[] timelines = from.animation.timelines.items;
float alphaHold = from.alpha * to.interruptAlpha, alphaMix = alphaHold * (1 - mix);
float animationLast = from.animationLast, animationTime = from.getAnimationTime(), applyTime = animationTime;
Array<Event> events = null;
@ -315,10 +313,10 @@ public class AnimationState {
if (blend == MixBlend.add) {
for (int i = 0; i < timelineCount; i++)
((Timeline)timelines[i]).apply(skeleton, animationLast, applyTime, events, alphaMix, blend, MixDirection.out, false);
timelines[i].apply(skeleton, animationLast, applyTime, events, alphaMix, blend, MixDirection.out, false);
} else {
int[] timelineMode = from.timelineMode.items;
Object[] timelineHoldMix = from.timelineHoldMix.items;
TrackEntry[] timelineHoldMix = from.timelineHoldMix.items;
boolean shortestRotation = from.shortestRotation;
boolean firstFrame = !shortestRotation && from.timelinesRotation.size != timelineCount << 1;
@ -327,7 +325,7 @@ public class AnimationState {
from.totalAlpha = 0;
for (int i = 0; i < timelineCount; i++) {
var timeline = (Timeline)timelines[i];
Timeline timeline = timelines[i];
MixDirection direction = MixDirection.out;
MixBlend timelineBlend;
float alpha;
@ -351,7 +349,7 @@ public class AnimationState {
break;
default: // HOLD_MIX
timelineBlend = MixBlend.setup;
var holdMix = (TrackEntry)timelineHoldMix[i];
TrackEntry holdMix = timelineHoldMix[i];
alpha = alphaHold * Math.max(0, 1 - holdMix.mixTime / holdMix.mixDuration);
break;
}
@ -385,7 +383,7 @@ public class AnimationState {
private void applyAttachmentTimeline (AttachmentTimeline timeline, Skeleton skeleton, float time, MixBlend blend,
boolean attachments) {
Slot slot = skeleton.slots.get(timeline.slotIndex);
Slot slot = skeleton.slots.items[timeline.slotIndex];
if (!slot.bone.active) return;
if (time < timeline.frames[0]) { // Time is before first frame.
@ -415,7 +413,7 @@ public class AnimationState {
return;
}
Bone bone = skeleton.bones.get(timeline.boneIndex);
Bone bone = skeleton.bones.items[timeline.boneIndex];
if (!bone.active) return;
BoneLocal pose = bone.pose, setup = bone.data.setup;
float[] frames = timeline.frames;
@ -475,10 +473,10 @@ public class AnimationState {
float trackLastWrapped = entry.trackLast % duration;
// Queue events before complete.
Object[] events = this.events.items;
Event[] events = this.events.items;
int i = 0, n = this.events.size;
for (; i < n; i++) {
var event = (Event)events[i];
Event event = events[i];
if (event.time < trackLastWrapped) break;
if (event.time > animationEnd) continue; // Discard events outside animation start/end.
queue.event(entry, event);
@ -499,7 +497,7 @@ public class AnimationState {
// Queue events after complete.
for (; i < n; i++) {
var event = (Event)events[i];
Event event = events[i];
if (event.time < animationStart) continue; // Discard events outside animation start/end.
queue.event(entry, event);
}
@ -526,7 +524,7 @@ public class AnimationState {
public void clearTrack (int trackIndex) {
if (trackIndex < 0) throw new IllegalArgumentException("trackIndex must be >= 0.");
if (trackIndex >= tracks.size) return;
TrackEntry current = tracks.get(trackIndex);
TrackEntry current = tracks.items[trackIndex];
if (current == null) return;
queue.end(current);
@ -543,14 +541,14 @@ public class AnimationState {
entry = from;
}
tracks.set(current.trackIndex, null);
tracks.items[current.trackIndex] = null;
queue.drain();
}
private void setCurrent (int index, TrackEntry current, boolean interrupt) {
TrackEntry from = expandToIndex(index);
tracks.set(index, current);
tracks.items[index] = current;
current.previous = null;
if (from != null) {
@ -594,7 +592,7 @@ public class AnimationState {
if (current != null) {
if (current.nextTrackLast == -1 && current.animation == animation) {
// Don't mix from an entry that was never applied.
tracks.set(trackIndex, current.mixingFrom);
tracks.items[trackIndex] = current.mixingFrom;
queue.interrupt(current);
queue.end(current);
clearNext(current);
@ -704,9 +702,9 @@ public class AnimationState {
public void setEmptyAnimations (float mixDuration) {
boolean oldDrainDisabled = queue.drainDisabled;
queue.drainDisabled = true;
Object[] tracks = this.tracks.items;
TrackEntry[] tracks = this.tracks.items;
for (int i = 0, n = this.tracks.size; i < n; i++) {
var current = (TrackEntry)tracks[i];
TrackEntry current = tracks[i];
if (current != null) setEmptyAnimation(current.trackIndex, mixDuration);
}
queue.drainDisabled = oldDrainDisabled;
@ -714,7 +712,7 @@ public class AnimationState {
}
private TrackEntry expandToIndex (int index) {
if (index < tracks.size) return tracks.get(index);
if (index < tracks.size) return tracks.items[index];
tracks.ensureCapacity(index - tracks.size + 1);
tracks.size = index + 1;
return null;
@ -772,9 +770,9 @@ public class AnimationState {
// Process in the order that animations are applied.
propertyIds.clear(2048);
int n = tracks.size;
Object[] tracks = this.tracks.items;
TrackEntry[] tracks = this.tracks.items;
for (int i = 0; i < n; i++) {
var entry = (TrackEntry)tracks[i];
TrackEntry entry = tracks[i];
if (entry == null) continue;
while (entry.mixingFrom != null) // Move to last entry, then iterate in reverse.
entry = entry.mixingFrom;
@ -787,22 +785,22 @@ public class AnimationState {
private void computeHold (TrackEntry entry) {
TrackEntry to = entry.mixingTo;
Object[] timelines = entry.animation.timelines.items;
Timeline[] timelines = entry.animation.timelines.items;
int timelinesCount = entry.animation.timelines.size;
int[] timelineMode = entry.timelineMode.setSize(timelinesCount);
entry.timelineHoldMix.clear();
Object[] timelineHoldMix = entry.timelineHoldMix.setSize(timelinesCount);
TrackEntry[] timelineHoldMix = entry.timelineHoldMix.setSize(timelinesCount);
ObjectSet<String> propertyIds = this.propertyIds;
if (to != null && to.holdPrevious) {
for (int i = 0; i < timelinesCount; i++)
timelineMode[i] = propertyIds.addAll(((Timeline)timelines[i]).getPropertyIds()) ? HOLD_FIRST : HOLD_SUBSEQUENT;
timelineMode[i] = propertyIds.addAll(timelines[i].getPropertyIds()) ? HOLD_FIRST : HOLD_SUBSEQUENT;
return;
}
outer:
for (int i = 0; i < timelinesCount; i++) {
var timeline = (Timeline)timelines[i];
Timeline timeline = timelines[i];
String[] ids = timeline.getPropertyIds();
if (!propertyIds.addAll(ids))
timelineMode[i] = SUBSEQUENT;
@ -828,7 +826,7 @@ public class AnimationState {
public @Null TrackEntry getCurrent (int trackIndex) {
if (trackIndex < 0) throw new IllegalArgumentException("trackIndex must be >= 0.");
if (trackIndex >= tracks.size) return null;
return tracks.get(trackIndex);
return tracks.items[trackIndex];
}
/** Adds a listener to receive events for all track entries. */
@ -883,9 +881,9 @@ public class AnimationState {
public String toString () {
var buffer = new StringBuilder(64);
Object[] tracks = this.tracks.items;
TrackEntry[] tracks = this.tracks.items;
for (int i = 0, n = this.tracks.size; i < n; i++) {
var entry = (TrackEntry)tracks[i];
TrackEntry entry = tracks[i];
if (entry == null) continue;
if (buffer.length() > 0) buffer.append(", ");
buffer.append(entry.toString());
@ -910,7 +908,7 @@ public class AnimationState {
MixBlend mixBlend = MixBlend.replace;
final IntArray timelineMode = new IntArray();
final Array<TrackEntry> timelineHoldMix = new Array();
final Array<TrackEntry> timelineHoldMix = new Array(true, 8, TrackEntry[]::new);
final FloatArray timelinesRotation = new FloatArray();
public void reset () {
@ -1366,43 +1364,44 @@ public class AnimationState {
drainDisabled = true;
SnapshotArray<AnimationStateListener> listenersArray = AnimationState.this.listeners;
Object[] objects = this.objects.items;
for (int i = 0; i < this.objects.size; i += 2) {
var type = (EventType)objects.get(i);
var entry = (TrackEntry)objects.get(i + 1);
int listenersCount = listenersArray.size;
Object[] listeners = listenersArray.begin();
var type = (EventType)objects[i];
var entry = (TrackEntry)objects[i + 1];
int nn = listenersArray.size;
AnimationStateListener[] listeners = listenersArray.begin();
switch (type) {
case start:
if (entry.listener != null) entry.listener.start(entry);
for (int ii = 0; ii < listenersCount; ii++)
((AnimationStateListener)listeners[ii]).start(entry);
for (int ii = 0; ii < nn; ii++)
listeners[ii].start(entry);
break;
case interrupt:
if (entry.listener != null) entry.listener.interrupt(entry);
for (int ii = 0; ii < listenersCount; ii++)
((AnimationStateListener)listeners[ii]).interrupt(entry);
for (int ii = 0; ii < nn; ii++)
listeners[ii].interrupt(entry);
break;
case end:
if (entry.listener != null) entry.listener.end(entry);
for (int ii = 0; ii < listenersCount; ii++)
((AnimationStateListener)listeners[ii]).end(entry);
for (int ii = 0; ii < nn; ii++)
listeners[ii].end(entry);
// Fall through.
case dispose:
if (entry.listener != null) entry.listener.dispose(entry);
for (int ii = 0; ii < listenersCount; ii++)
((AnimationStateListener)listeners[ii]).dispose(entry);
for (int ii = 0; ii < nn; ii++)
listeners[ii].dispose(entry);
trackEntryPool.free(entry);
break;
case complete:
if (entry.listener != null) entry.listener.complete(entry);
for (int ii = 0; ii < listenersCount; ii++)
((AnimationStateListener)listeners[ii]).complete(entry);
for (int ii = 0; ii < nn; ii++)
listeners[ii].complete(entry);
break;
case event:
var event = (Event)objects.get(i++ + 2);
var event = (Event)objects[i++ + 2];
if (entry.listener != null) entry.listener.event(entry, event);
for (int ii = 0; ii < listenersCount; ii++)
((AnimationStateListener)listeners[ii]).event(entry, event);
for (int ii = 0; ii < nn; ii++)
listeners[ii].event(entry, event);
break;
}
listenersArray.end();

View File

@ -40,7 +40,7 @@ import com.badlogic.gdx.utils.Null;
* constraint or application code modifies the world transform after it was computed from the local transform. */
public class Bone extends PosedActive<BoneData, BoneLocal, BonePose> {
@Null final Bone parent;
final Array<Bone> children = new Array();
final Array<Bone> children = new Array(true, 4, Bone[]::new);
boolean sorted;
public Bone (BoneData data, @Null Bone parent) {

View File

@ -47,11 +47,11 @@ public class IkConstraint extends Constraint<IkConstraint, IkConstraintData, IkC
super(data, new IkConstraintPose(), new IkConstraintPose());
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
bones = new Array(data.bones.size);
bones = new Array(true, data.bones.size, BonePose[]::new);
for (BoneData boneData : data.bones)
bones.add(skeleton.bones.get(boneData.index).constrained);
bones.add(skeleton.bones.items[boneData.index].constrained);
target = skeleton.bones.get(data.target.index);
target = skeleton.bones.items[data.target.index];
}
public IkConstraint copy (Skeleton skeleton) {
@ -65,25 +65,25 @@ public class IkConstraint extends Constraint<IkConstraint, IkConstraintData, IkC
IkConstraintPose a = applied;
if (a.mix == 0) return;
BonePose target = this.target.applied;
Object[] bones = this.bones.items;
BonePose[] bones = this.bones.items;
switch (this.bones.size) {
case 1 -> apply(skeleton, (BonePose)bones[0], target.worldX, target.worldY, a.compress, a.stretch, data.uniform, a.mix);
case 2 -> apply(skeleton, (BonePose)bones[0], (BonePose)bones[1], target.worldX, target.worldY, a.bendDirection, a.stretch,
data.uniform, a.softness, a.mix);
case 1 -> apply(skeleton, bones[0], target.worldX, target.worldY, a.compress, a.stretch, data.uniform, a.mix);
case 2 -> apply(skeleton, bones[0], bones[1], target.worldX, target.worldY, a.bendDirection, a.stretch, data.uniform,
a.softness, a.mix);
}
}
void sort (Skeleton skeleton) {
skeleton.sortBone(target);
Bone parent = bones.first().bone;
Bone parent = bones.items[0].bone;
skeleton.sortBone(parent);
skeleton.resetCache(parent);
if (bones.size == 1) {
skeleton.updateCache.add(this);
skeleton.sortReset(parent.children);
} else {
Bone child = bones.peek().bone;
Bone child = bones.items[1].bone;
skeleton.resetCache(child);
skeleton.sortBone(child);

View File

@ -35,7 +35,7 @@ import com.badlogic.gdx.utils.Array;
* <p>
* See <a href="https://esotericsoftware.com/spine-ik-constraints">IK constraints</a> in the Spine User Guide. */
public class IkConstraintData extends ConstraintData<IkConstraint, IkConstraintPose> {
final Array<BoneData> bones = new Array();
final Array<BoneData> bones = new Array(true, 2, BoneData[]::new);
BoneData target;
boolean uniform;

View File

@ -62,11 +62,11 @@ public class PathConstraint extends Constraint<PathConstraint, PathConstraintDat
super(data, new PathConstraintPose(), new PathConstraintPose());
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
bones = new Array(data.bones.size);
bones = new Array(true, data.bones.size, BonePose[]::new);
for (BoneData boneData : data.bones)
bones.add(skeleton.bones.get(boneData.index).constrained);
bones.add(skeleton.bones.items[boneData.index].constrained);
slot = skeleton.slots.get(data.slot.index);
slot = skeleton.slots.items[data.slot.index];
}
public PathConstraint copy (Skeleton skeleton) {
@ -86,7 +86,7 @@ public class PathConstraint extends Constraint<PathConstraint, PathConstraintDat
PathConstraintData data = this.data;
boolean tangents = data.rotateMode == RotateMode.tangent, scale = data.rotateMode == RotateMode.chainScale;
int boneCount = this.bones.size, spacesCount = tangents ? boneCount : boneCount + 1;
Object[] bones = this.bones.items;
BonePose[] bones = this.bones.items;
float[] spaces = this.spaces.setSize(spacesCount), lengths = scale ? this.lengths.setSize(boneCount) : null;
float spacing = pose.spacing;
@ -94,7 +94,7 @@ public class PathConstraint extends Constraint<PathConstraint, PathConstraintDat
case percent -> {
if (scale) {
for (int i = 0, n = spacesCount - 1; i < n; i++) {
var bone = (BonePose)bones[i];
BonePose bone = bones[i];
float setupLength = bone.bone.data.length;
float x = setupLength * bone.a, y = setupLength * bone.c;
lengths[i] = (float)Math.sqrt(x * x + y * y);
@ -105,7 +105,7 @@ public class PathConstraint extends Constraint<PathConstraint, PathConstraintDat
case proportional -> {
float sum = 0;
for (int i = 0, n = spacesCount - 1; i < n;) {
var bone = (BonePose)bones[i];
BonePose bone = bones[i];
float setupLength = bone.bone.data.length;
if (setupLength < epsilon) {
if (scale) lengths[i] = 0;
@ -127,7 +127,7 @@ public class PathConstraint extends Constraint<PathConstraint, PathConstraintDat
default -> {
boolean lengthSpacing = data.spacingMode == SpacingMode.length;
for (int i = 0, n = spacesCount - 1; i < n;) {
var bone = (BonePose)bones[i];
BonePose bone = bones[i];
float setupLength = bone.bone.data.length;
if (setupLength < epsilon) {
if (scale) lengths[i] = 0;
@ -153,7 +153,7 @@ public class PathConstraint extends Constraint<PathConstraint, PathConstraintDat
offsetRotation *= p.a * p.d - p.b * p.c > 0 ? degRad : -degRad;
}
for (int i = 0, p = 3; i < boneCount; i++, p += 3) {
var bone = (BonePose)bones[i];
BonePose bone = bones[i];
bone.worldX += (boneX - bone.worldX) * mixX;
bone.worldY += (boneY - bone.worldY) * mixY;
float x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY;
@ -467,10 +467,10 @@ public class PathConstraint extends Constraint<PathConstraint, PathConstraintDat
sortPathConstraintAttachment(skeleton, slot.pose.attachment, slotBone);
Object[] bones = this.bones.items;
BonePose[] bones = this.bones.items;
int boneCount = this.bones.size;
for (int i = 0; i < boneCount; i++) {
Bone bone = ((BonePose)bones[i]).bone;
Bone bone = bones[i].bone;
skeleton.resetCache(bone);
skeleton.sortBone(bone);
}
@ -478,9 +478,9 @@ public class PathConstraint extends Constraint<PathConstraint, PathConstraintDat
skeleton.updateCache.add(this);
for (int i = 0; i < boneCount; i++)
skeleton.sortReset(((BonePose)bones[i]).bone.children);
skeleton.sortReset(bones[i].bone.children);
for (int i = 0; i < boneCount; i++)
((BonePose)bones[i]).bone.sorted = true;
bones[i].bone.sorted = true;
}
private void sortPathConstraintAttachment (Skeleton skeleton, Skin skin, int slotIndex, Bone slotBone) {
@ -497,12 +497,12 @@ public class PathConstraint extends Constraint<PathConstraint, PathConstraintDat
if (pathBones == null)
skeleton.sortBone(slotBone);
else {
Object[] bones = skeleton.bones.items;
Bone[] bones = skeleton.bones.items;
for (int i = 0, n = pathBones.length; i < n;) {
int nn = pathBones[i++];
nn += i;
while (i < nn)
skeleton.sortBone((Bone)bones[pathBones[i++]]);
skeleton.sortBone(bones[pathBones[i++]]);
}
}
}

View File

@ -35,7 +35,7 @@ import com.badlogic.gdx.utils.Array;
* <p>
* See <a href="https://esotericsoftware.com/spine-path-constraints">Path constraints</a> in the Spine User Guide. */
public class PathConstraintData extends ConstraintData<PathConstraint, PathConstraintPose> {
final Array<BoneData> bones = new Array();
final Array<BoneData> bones = new Array(true, 0, BoneData[]::new);
SlotData slot;
PositionMode positionMode;
SpacingMode spacingMode;

View File

@ -49,7 +49,7 @@ public class PhysicsConstraint extends Constraint<PhysicsConstraint, PhysicsCons
super(data, new PhysicsConstraintPose(), new PhysicsConstraintPose());
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
bone = skeleton.bones.get(data.bone.index).constrained;
bone = skeleton.bones.items[data.bone.index].constrained;
}
public PhysicsConstraint copy (Skeleton skeleton) {

View File

@ -36,15 +36,11 @@ abstract public class Posed< //
return applied;
}
public A getConstrainedPose () {
return constrained;
}
public void setConstrained (boolean constrained) {
void setConstrained (boolean constrained) {
applied = constrained ? this.constrained : (A)pose;
}
public void resetAppliedPose () {
void resetAppliedPose () {
applied.set(pose);
}

View File

@ -57,7 +57,7 @@ public class Skeleton {
final Array<Constraint> constraints;
final Array<PhysicsConstraint> physics;
final Array updateCache = new Array();
final Array<Posed> resetCache = new Array();
final Array<Posed> resetCache = new Array(true, 16, Posed[]::new);
@Null Skin skin;
final Color color;
float x, y, scaleX = 1, scaleY = 1, time;
@ -66,35 +66,36 @@ public class Skeleton {
if (data == null) throw new IllegalArgumentException("data cannot be null.");
this.data = data;
bones = new Array(data.bones.size);
Object[] bones = this.bones.items;
bones = new Array(true, data.bones.size, Bone[]::new);
Bone[] bones = this.bones.items;
for (BoneData boneData : data.bones) {
Bone bone;
if (boneData.parent == null)
bone = new Bone(boneData, null);
else {
var parent = (Bone)bones[boneData.parent.index];
Bone parent = bones[boneData.parent.index];
bone = new Bone(boneData, parent);
parent.children.add(bone);
}
this.bones.add(bone);
}
slots = new Array(data.slots.size);
drawOrder = new Array(data.slots.size);
slots = new Array(true, data.slots.size, Slot[]::new);
drawOrder = new Array(true, data.slots.size, Slot[]::new);
for (SlotData slotData : data.slots) {
var slot = new Slot(slotData, this);
slots.add(slot);
drawOrder.add(slot);
}
constraints = new Array(data.constraints.size);
physics = new Array();
physics = new Array(true, 8, PhysicsConstraint[]::new);
constraints = new Array(true, data.constraints.size, Constraint[]::new);
for (ConstraintData constraintData : data.constraints) {
Constraint constraint = constraintData.create(this);
if (constraint instanceof PhysicsConstraint physicsConstraint) physics.add(physicsConstraint);
constraints.add(constraint);
}
physics.shrink();
color = new Color(1, 1, 1, 1);
@ -106,31 +107,29 @@ public class Skeleton {
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
data = skeleton.data;
bones = new Array(skeleton.bones.size);
bones = new Array(true, skeleton.bones.size, Bone[]::new);
for (Bone bone : skeleton.bones) {
Bone newBone;
if (bone.parent == null)
newBone = new Bone(bone, null);
else {
Bone parent = bones.get(bone.parent.data.index);
Bone parent = bones.items[bone.parent.data.index];
newBone = new Bone(bone, parent);
parent.children.add(newBone);
}
bones.add(newBone);
}
slots = new Array(skeleton.slots.size);
for (Slot slot : skeleton.slots) {
Bone bone = bones.get(slot.bone.data.index);
slots.add(new Slot(slot, bone, this));
}
slots = new Array(true, skeleton.slots.size, Slot[]::new);
for (Slot slot : skeleton.slots)
slots.add(new Slot(slot, bones.items[slot.bone.data.index], this));
drawOrder = new Array(slots.size);
drawOrder = new Array(true, slots.size, Slot[]::new);
for (Slot slot : skeleton.drawOrder)
drawOrder.add(slots.get(slot.data.index));
drawOrder.add(slots.items[slot.data.index]);
physics = new Array(skeleton.physics.size);
constraints = new Array(skeleton.constraints.size);
physics = new Array(true, skeleton.physics.size, PhysicsConstraint[]::new);
constraints = new Array(true, skeleton.constraints.size, Constraint[]::new);
for (Constraint other : skeleton.constraints) {
Constraint constraint = other.copy(this);
if (constraint instanceof PhysicsConstraint physicsConstraint) physics.add(physicsConstraint);
@ -155,17 +154,17 @@ public class Skeleton {
resetCache.clear();
int boneCount = bones.size;
Object[] bones = this.bones.items;
Bone[] bones = this.bones.items;
for (int i = 0; i < boneCount; i++) {
var bone = (Bone)bones[i];
Bone bone = bones[i];
bone.sorted = bone.data.skinRequired;
bone.active = !bone.sorted;
bone.setConstrained(false);
}
if (skin != null) {
Object[] objects = skin.bones.items;
BoneData[] skinBones = skin.bones.items;
for (int i = 0, n = skin.bones.size; i < n; i++) {
var bone = (Bone)objects[((BoneData)objects[i]).index];
var bone = bones[skinBones[i].index];
do {
bone.sorted = false;
bone.active = true;
@ -174,30 +173,30 @@ public class Skeleton {
}
}
Object[] objects = constraints.items;
int n = constraints.size;
Constraint[] constraints = this.constraints.items;
int n = this.constraints.size;
for (int i = 0; i < n; i++)
((Constraint)objects[i]).setConstrained(false);
constraints[i].setConstrained(false);
for (int i = 0; i < n; i++) {
var constraint = (Constraint<?, ?, ?>)objects[i];
Constraint<?, ?, ?> constraint = constraints[i];
constraint.active = constraint.isSourceActive()
&& (!constraint.data.skinRequired || (skin != null && skin.constraints.contains(constraint.data, true)));
if (constraint.active) constraint.sort(this);
}
for (int i = 0; i < boneCount; i++)
sortBone((Bone)bones[i]);
sortBone(bones[i]);
objects = this.updateCache.items;
Object[] updateCache = this.updateCache.items;
n = this.updateCache.size;
for (int i = 0; i < n; i++)
if (objects[i] instanceof Bone bone) objects[i] = bone.applied;
if (updateCache[i] instanceof Bone bone) updateCache[i] = bone.applied;
}
void resetCache (Posed object) {
if (!resetCache.contains(object, true)) { // BOZO
resetCache.add(object);
if (object.pose == object.applied) {
object.setConstrained(true);
resetCache.add(object);
}
}
@ -210,9 +209,9 @@ public class Skeleton {
}
void sortReset (Array<Bone> bones) {
Object[] items = bones.items;
Bone[] items = bones.items;
for (int i = 0, n = bones.size; i < n; i++) {
var bone = (Bone)items[i];
Bone bone = items[i];
if (!bone.active) continue;
if (bone.sorted) sortReset(bone.children);
bone.sorted = false;
@ -224,13 +223,13 @@ public class Skeleton {
* See <a href="https://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> in the Spine
* Runtimes Guide. */
public void updateWorldTransform (Physics physics) {
Object[] objects = this.resetCache.items;
Posed[] resetCache = this.resetCache.items;
for (int i = 0, n = this.resetCache.size; i < n; i++)
((Posed)objects[i]).resetAppliedPose();
resetCache[i].resetAppliedPose();
objects = this.updateCache.items;
Object[] updateCache = this.updateCache.items;
for (int i = 0, n = this.updateCache.size; i < n; i++)
((Update)objects[i]).update(this, physics);
((Update)updateCache[i]).update(this, physics);
}
/** Temporarily sets the root bone as a child of the specified bone, then updates the world transform for each bone and applies
@ -241,9 +240,9 @@ public class Skeleton {
public void updateWorldTransform (Physics physics, BonePose parent) {
if (parent == null) throw new IllegalArgumentException("parent cannot be null.");
Object[] objects = this.resetCache.items;
Posed[] resetCache = this.resetCache.items;
for (int i = 0, n = this.resetCache.size; i < n; i++)
((Posed)objects[i]).resetAppliedPose();
resetCache[i].resetAppliedPose();
// Apply the parent bone transform to the root bone. The root bone always inherits scale, rotation and reflection.
BonePose rootBone = getRootBone().applied;
@ -263,9 +262,9 @@ public class Skeleton {
rootBone.d = (pc * lb + pd * ld) * scaleY;
// Update everything except root bone.
objects = this.updateCache.items;
Object[] updateCache = this.updateCache.items;
for (int i = 0, n = this.updateCache.size; i < n; i++) {
var updatable = (Update)objects[i];
var updatable = (Update)updateCache[i];
if (updatable != rootBone) updatable.update(this, physics);
}
}
@ -278,22 +277,22 @@ public class Skeleton {
/** Sets the bones and constraints to their setup pose values. */
public void setupPoseBones () {
Object[] objects = this.bones.items;
Bone[] bones = this.bones.items;
for (int i = 0, n = this.bones.size; i < n; i++)
((Bone)objects[i]).setupPose();
bones[i].setupPose();
objects = constraints.items;
for (int i = 0, n = constraints.size; i < n; i++)
((Constraint)objects[i]).setupPose();
Constraint[] constraints = this.constraints.items;
for (int i = 0, n = this.constraints.size; i < n; i++)
constraints[i].setupPose();
}
/** Sets the slots and draw order to their setup pose values. */
public void setupPoseSlots () {
Object[] slots = this.slots.items;
Slot[] slots = this.slots.items;
int n = this.slots.size;
arraycopy(slots, 0, drawOrder.items, 0, n);
for (int i = 0; i < n; i++)
((Slot)slots[i]).setupPose();
slots[i].setupPose();
}
/** The skeleton's setup pose data. */
@ -320,11 +319,9 @@ public class Skeleton {
* repeatedly. */
public @Null Bone findBone (String boneName) {
if (boneName == null) throw new IllegalArgumentException("boneName cannot be null.");
Object[] bones = this.bones.items;
for (int i = 0, n = this.bones.size; i < n; i++) {
var bone = (Bone)bones[i];
if (bone.data.name.equals(boneName)) return bone;
}
Bone[] bones = this.bones.items;
for (int i = 0, n = this.bones.size; i < n; i++)
if (bones[i].data.name.equals(boneName)) return bones[i];
return null;
}
@ -337,11 +334,9 @@ public class Skeleton {
* repeatedly. */
public @Null Slot findSlot (String slotName) {
if (slotName == null) throw new IllegalArgumentException("slotName cannot be null.");
Object[] slots = this.slots.items;
for (int i = 0, n = this.slots.size; i < n; i++) {
var slot = (Slot)slots[i];
if (slot.data.name.equals(slotName)) return slot;
}
Slot[] slots = this.slots.items;
for (int i = 0, n = this.slots.size; i < n; i++)
if (slots[i].data.name.equals(slotName)) return slots[i];
return null;
}
@ -384,9 +379,9 @@ public class Skeleton {
if (skin != null)
newSkin.attachAll(this, skin);
else {
Object[] slots = this.slots.items;
Slot[] slots = this.slots.items;
for (int i = 0, n = this.slots.size; i < n; i++) {
var slot = (Slot)slots[i];
Slot slot = slots[i];
String name = slot.data.attachmentName;
if (name != null) {
Attachment attachment = newSkin.getAttachment(i, name);
@ -451,10 +446,10 @@ public class Skeleton {
public @Null <T extends Constraint> T findConstraint (String constraintName, Class<T> type) {
if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null.");
if (type == null) throw new IllegalArgumentException("type cannot be null.");
Object[] constraints = this.constraints.items;
Constraint[] constraints = this.constraints.items;
for (int i = 0, n = this.constraints.size; i < n; i++) {
Object constraint = constraints[i];
if (type.isInstance(constraint) && ((PosedData)constraint).name.equals(constraintName)) return (T)constraint;
Constraint constraint = constraints[i];
if (type.isInstance(constraint) && constraint.data.name.equals(constraintName)) return (T)constraint;
}
return null;
}
@ -477,10 +472,10 @@ public class Skeleton {
if (offset == null) throw new IllegalArgumentException("offset cannot be null.");
if (size == null) throw new IllegalArgumentException("size cannot be null.");
if (temp == null) throw new IllegalArgumentException("temp cannot be null.");
Object[] drawOrder = this.drawOrder.items;
Slot[] drawOrder = this.drawOrder.items;
float minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE;
for (int i = 0, n = this.drawOrder.size; i < n; i++) {
var slot = (Slot)drawOrder[i];
Slot slot = drawOrder[i];
if (!slot.bone.active) continue;
int verticesLength = 0;
float[] vertices = null;
@ -601,16 +596,16 @@ public class Skeleton {
/** Calls {@link PhysicsConstraint#translate(float, float)} for each physics constraint. */
public void physicsTranslate (float x, float y) {
Object[] physicsConstraints = this.physics.items;
PhysicsConstraint[] constraints = this.physics.items;
for (int i = 0, n = this.physics.size; i < n; i++)
((PhysicsConstraint)physicsConstraints[i]).translate(x, y);
constraints[i].translate(x, y);
}
/** Calls {@link PhysicsConstraint#rotate(float, float, float)} for each physics constraint. */
public void physicsRotate (float x, float y, float degrees) {
Object[] physicsConstraints = this.physics.items;
PhysicsConstraint[] constraints = this.physics.items;
for (int i = 0, n = this.physics.size; i < n; i++)
((PhysicsConstraint)physicsConstraints[i]).rotate(x, y, degrees);
constraints[i].rotate(x, y, degrees);
}
/** Returns the skeleton's time. This is used for time-based manipulations, such as {@link PhysicsConstraint}.

View File

@ -162,7 +162,7 @@ public class SkeletonBinary extends SkeletonLoader {
static public final int CURVE_STEPPED = 1;
static public final int CURVE_BEZIER = 2;
private final Array<LinkedMesh> linkedMeshes = new Array();
private final Array<LinkedMesh> linkedMeshes = new Array(true, 8, LinkedMesh[]::new);
public SkeletonBinary (AttachmentLoader attachmentLoader) {
super(attachmentLoader);
@ -217,10 +217,10 @@ public class SkeletonBinary extends SkeletonLoader {
o[i] = input.readString();
// Bones.
Object[] bones = skeletonData.bones.setSize(n = input.readInt(true));
BoneData[] bones = skeletonData.bones.setSize(n = input.readInt(true));
for (int i = 0; i < n; i++) {
String name = input.readString();
BoneData parent = i == 0 ? null : (BoneData)bones[input.readInt(true)];
BoneData parent = i == 0 ? null : bones[input.readInt(true)];
var data = new BoneData(i, name, parent);
BoneLocal setup = data.setup;
setup.rotation = input.readFloat();
@ -242,10 +242,10 @@ public class SkeletonBinary extends SkeletonLoader {
}
// Slots.
Object[] slots = skeletonData.slots.setSize(n = input.readInt(true));
SlotData[] slots = skeletonData.slots.setSize(n = input.readInt(true));
for (int i = 0; i < n; i++) {
String slotName = input.readString();
var boneData = (BoneData)bones[input.readInt(true)];
var boneData = bones[input.readInt(true)];
var data = new SlotData(i, slotName, boneData);
Color.rgba8888ToColor(data.setup.color, input.readInt());
@ -264,10 +264,10 @@ public class SkeletonBinary extends SkeletonLoader {
switch (input.readByte()) {
case CONSTRAINT_IK -> {
var data = new IkConstraintData(input.readString());
Object[] constraintBones = data.bones.setSize(nn = input.readInt(true));
BoneData[] constraintBones = data.bones.setSize(nn = input.readInt(true));
for (int ii = 0; ii < nn; ii++)
constraintBones[ii] = bones[input.readInt(true)];
data.target = (BoneData)bones[input.readInt(true)];
data.target = bones[input.readInt(true)];
int flags = input.read();
data.skinRequired = (flags & 1) != 0;
data.uniform = (flags & 2) != 0;
@ -281,17 +281,17 @@ public class SkeletonBinary extends SkeletonLoader {
}
case CONSTRAINT_TRANSFORM -> {
var data = new TransformConstraintData(input.readString());
Object[] constraintBones = data.bones.setSize(nn = input.readInt(true));
BoneData[] constraintBones = data.bones.setSize(nn = input.readInt(true));
for (int ii = 0; ii < nn; ii++)
constraintBones[ii] = bones[input.readInt(true)];
data.source = (BoneData)bones[input.readInt(true)];
data.source = bones[input.readInt(true)];
int flags = input.read();
data.skinRequired = (flags & 1) != 0;
data.localSource = (flags & 2) != 0;
data.localTarget = (flags & 4) != 0;
data.additive = (flags & 8) != 0;
data.clamp = (flags & 16) != 0;
Object[] froms = data.properties.setSize(nn = flags >> 5);
FromProperty[] froms = data.properties.setSize(nn = flags >> 5);
for (int ii = 0, tn; ii < nn; ii++) {
float fromScale = 1;
FromProperty from;
@ -311,7 +311,7 @@ public class SkeletonBinary extends SkeletonLoader {
default -> from = null;
}
from.offset = input.readFloat() * fromScale;
Object[] tos = from.to.setSize(tn = input.readByte());
ToProperty[] tos = from.to.setSize(tn = input.readByte());
for (int t = 0; t < tn; t++) {
float toScale = 1;
ToProperty to;
@ -356,10 +356,10 @@ public class SkeletonBinary extends SkeletonLoader {
}
case CONSTRAINT_PATH -> {
var data = new PathConstraintData(input.readString());
Object[] constraintBones = data.bones.setSize(nn = input.readInt(true));
BoneData[] constraintBones = data.bones.setSize(nn = input.readInt(true));
for (int ii = 0; ii < nn; ii++)
constraintBones[ii] = bones[input.readInt(true)];
data.slot = (SlotData)slots[input.readInt(true)];
data.slot = slots[input.readInt(true)];
int flags = input.read();
data.skinRequired = (flags & 1) != 0;
data.positionMode = PositionMode.values[flags & 2];
@ -378,7 +378,7 @@ public class SkeletonBinary extends SkeletonLoader {
}
case CONSTRAINT_PHYSICS -> {
var data = new PhysicsConstraintData(input.readString());
data.bone = (BoneData)bones[input.readInt(true)];
data.bone = bones[input.readInt(true)];
int flags = input.read();
data.skinRequired = (flags & 1) != 0;
if ((flags & 2) != 0) data.x = input.readFloat();
@ -426,10 +426,10 @@ public class SkeletonBinary extends SkeletonLoader {
// Linked meshes.
n = linkedMeshes.size;
Object[] items = linkedMeshes.items;
LinkedMesh[] items = linkedMeshes.items;
for (int i = 0; i < n; i++) {
var linkedMesh = (LinkedMesh)items[i];
Skin skin = skeletonData.skins.get(linkedMesh.skinIndex);
LinkedMesh linkedMesh = items[i];
Skin skin = skeletonData.skins.items[linkedMesh.skinIndex];
Attachment parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent);
if (parent == null) throw new SerializationException("Parent mesh not found: " + linkedMesh.parent);
linkedMesh.mesh.setTimelineAttachment(linkedMesh.inheritTimelines ? (VertexAttachment)parent : linkedMesh.mesh);
@ -656,7 +656,7 @@ public class SkeletonBinary extends SkeletonLoader {
ClippingAttachment clip = attachmentLoader.newClippingAttachment(skin, name);
if (clip == null) return null;
clip.setEndSlot(skeletonData.slots.get(endSlotIndex));
clip.setEndSlot(skeletonData.slots.items[endSlotIndex]);
clip.setWorldVerticesLength(vertices.length);
clip.setVertices(vertices.vertices);
clip.setBones(vertices.bones);
@ -720,7 +720,7 @@ public class SkeletonBinary extends SkeletonLoader {
}
private Animation readAnimation (SkeletonInput input, String name, SkeletonData skeletonData) throws IOException {
var timelines = new Array<Timeline>(input.readInt(true));
var timelines = new Array<Timeline>(true, input.readInt(true), Timeline[]::new);
float scale = this.scale;
// Slot timelines.
@ -969,7 +969,7 @@ public class SkeletonBinary extends SkeletonLoader {
// Path constraint timelines.
for (int i = 0, n = input.readInt(true); i < n; i++) {
int index = input.readInt(true);
var data = (PathConstraintData)skeletonData.constraints.get(index);
var data = (PathConstraintData)skeletonData.constraints.items[index];
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) {
int type = input.readByte(), frameCount = input.readInt(true), bezierCount = input.readInt(true);
switch (type) {
@ -1036,7 +1036,7 @@ public class SkeletonBinary extends SkeletonLoader {
// Attachment timelines.
for (int i = 0, n = input.readInt(true); i < n; i++) {
Skin skin = skeletonData.skins.get(input.readInt(true));
Skin skin = skeletonData.skins.items[input.readInt(true)];
for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) {
int slotIndex = input.readInt(true);
for (int iii = 0, nnn = input.readInt(true); iii < nnn; iii++) {
@ -1140,7 +1140,7 @@ public class SkeletonBinary extends SkeletonLoader {
var timeline = new EventTimeline(eventCount);
for (int i = 0; i < eventCount; i++) {
float time = input.readFloat();
EventData eventData = skeletonData.events.get(input.readInt(true));
EventData eventData = skeletonData.events.items[input.readInt(true)];
var event = new Event(time, eventData);
event.intValue = input.readInt(false);
event.floatValue = input.readFloat();
@ -1156,9 +1156,9 @@ public class SkeletonBinary extends SkeletonLoader {
}
float duration = 0;
Object[] items = timelines.items;
Timeline[] items = timelines.items;
for (int i = 0, n = timelines.size; i < n; i++)
duration = Math.max(duration, ((Timeline)items[i]).getDuration());
duration = Math.max(duration, items[i].getDuration());
return new Animation(name, timelines, duration);
}

View File

@ -41,8 +41,8 @@ import com.esotericsoftware.spine.attachments.BoundingBoxAttachment;
* provided along with convenience methods for doing hit detection. */
public class SkeletonBounds {
private float minX, minY, maxX, maxY;
private Array<BoundingBoxAttachment> boundingBoxes = new Array();
private Array<FloatArray> polygons = new Array();
private Array<BoundingBoxAttachment> boundingBoxes = new Array(true, 8, BoundingBoxAttachment[]::new);
private Array<FloatArray> polygons = new Array(true, 8, FloatArray[]::new);
private Pool<FloatArray> polygonPool = new Pool() {
protected Object newObject () {
return new FloatArray();
@ -55,17 +55,17 @@ public class SkeletonBounds {
* SkeletonBounds AABB methods will always return true. */
public void update (Skeleton skeleton, boolean updateAabb) {
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
Array<BoundingBoxAttachment> boundingBoxes = this.boundingBoxes;
Array<FloatArray> polygons = this.polygons;
Object[] slots = skeleton.slots.items;
int slotCount = skeleton.slots.size;
boundingBoxes.clear();
polygonPool.freeAll(polygons);
polygons.clear();
Slot[] slots = skeleton.slots.items;
int slotCount = skeleton.slots.size;
for (int i = 0; i < slotCount; i++) {
var slot = (Slot)slots[i];
Slot slot = slots[i];
if (!slot.bone.active) continue;
Attachment attachment = slot.applied.attachment;
if (attachment instanceof BoundingBoxAttachment boundingBox) {
@ -90,9 +90,9 @@ public class SkeletonBounds {
private void aabbCompute () {
float minX = Integer.MAX_VALUE, minY = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE, maxY = Integer.MIN_VALUE;
Object[] polygons = this.polygons.items;
FloatArray[] polygons = this.polygons.items;
for (int i = 0, n = this.polygons.size; i < n; i++) {
var polygon = (FloatArray)polygons[i];
FloatArray polygon = polygons[i];
float[] vertices = polygon.items;
for (int ii = 0, nn = polygon.size; ii < nn; ii += 2) {
float x = vertices[ii];
@ -143,9 +143,9 @@ public class SkeletonBounds {
/** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more
* efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */
public @Null BoundingBoxAttachment containsPoint (float x, float y) {
Object[] polygons = this.polygons.items;
FloatArray[] polygons = this.polygons.items;
for (int i = 0, n = this.polygons.size; i < n; i++)
if (containsPoint((FloatArray)polygons[i], x, y)) return boundingBoxes.get(i);
if (containsPoint(polygons[i], x, y)) return boundingBoxes.items[i];
return null;
}
@ -173,9 +173,9 @@ public class SkeletonBounds {
* is usually more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns
* true. */
public @Null BoundingBoxAttachment intersectsSegment (float x1, float y1, float x2, float y2) {
Object[] polygons = this.polygons.items;
FloatArray[] polygons = this.polygons.items;
for (int i = 0, n = this.polygons.size; i < n; i++)
if (intersectsSegment((FloatArray)polygons[i], x1, y1, x2, y2)) return boundingBoxes.get(i);
if (intersectsSegment(polygons[i], x1, y1, x2, y2)) return boundingBoxes.items[i];
return null;
}
@ -248,6 +248,6 @@ public class SkeletonBounds {
public @Null FloatArray getPolygon (BoundingBoxAttachment boundingBox) {
if (boundingBox == null) throw new IllegalArgumentException("boundingBox cannot be null.");
int index = boundingBoxes.indexOf(boundingBox, true);
return index == -1 ? null : polygons.get(index);
return index == -1 ? null : polygons.items[index];
}
}

View File

@ -38,13 +38,13 @@ import com.badlogic.gdx.utils.Null;
* Guide. */
public class SkeletonData {
@Null String name;
final Array<BoneData> bones = new Array(); // Ordered parents first.
final Array<SlotData> slots = new Array(); // Setup pose draw order.
final Array<Skin> skins = new Array();
final Array<BoneData> bones = new Array(true, 0, BoneData[]::new); // Ordered parents first.
final Array<SlotData> slots = new Array(true, 0, SlotData[]::new); // Setup pose draw order.
final Array<Skin> skins = new Array(true, 0, Skin[]::new);
@Null Skin defaultSkin;
final Array<EventData> events = new Array();
final Array<Animation> animations = new Array();
final Array<ConstraintData> constraints = new Array();
final Array<EventData> events = new Array(true, 0, EventData[]::new);
final Array<Animation> animations = new Array(true, 0, Animation[]::new);
final Array<ConstraintData> constraints = new Array(true, 0, ConstraintData[]::new);
float x, y, width, height, referenceScale = 100;
@Null String version, hash;
@ -67,11 +67,9 @@ public class SkeletonData {
* multiple times. */
public @Null BoneData findBone (String boneName) {
if (boneName == null) throw new IllegalArgumentException("boneName cannot be null.");
Object[] bones = this.bones.items;
for (int i = 0, n = this.bones.size; i < n; i++) {
var bone = (BoneData)bones[i];
if (bone.name.equals(boneName)) return bone;
}
BoneData[] bones = this.bones.items;
for (int i = 0, n = this.bones.size; i < n; i++)
if (bones[i].name.equals(boneName)) return bones[i];
return null;
}
@ -86,11 +84,9 @@ public class SkeletonData {
* multiple times. */
public @Null SlotData findSlot (String slotName) {
if (slotName == null) throw new IllegalArgumentException("slotName cannot be null.");
Object[] slots = this.slots.items;
for (int i = 0, n = this.slots.size; i < n; i++) {
var slot = (SlotData)slots[i];
if (slot.name.equals(slotName)) return slot;
}
SlotData[] slots = this.slots.items;
for (int i = 0, n = this.slots.size; i < n; i++)
if (slots[i].name.equals(slotName)) return slots[i];
return null;
}
@ -148,11 +144,9 @@ public class SkeletonData {
* call it multiple times. */
public @Null Animation findAnimation (String animationName) {
if (animationName == null) throw new IllegalArgumentException("animationName cannot be null.");
Object[] animations = this.animations.items;
for (int i = 0, n = this.animations.size; i < n; i++) {
var animation = (Animation)animations[i];
if (animation.name.equals(animationName)) return animation;
}
Animation[] animations = this.animations.items;
for (int i = 0, n = this.animations.size; i < n; i++)
if (animations[i].name.equals(animationName)) return animations[i];
return null;
}
@ -166,10 +160,10 @@ public class SkeletonData {
public @Null <T extends ConstraintData> T findConstraint (String constraintName, Class<T> type) {
if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null.");
if (type == null) throw new IllegalArgumentException("type cannot be null.");
Object[] constraints = this.constraints.items;
ConstraintData[] constraints = this.constraints.items;
for (int i = 0, n = this.constraints.size; i < n; i++) {
Object constraint = constraints[i];
if (type.isInstance(constraint) && ((PosedData)constraint).name.equals(constraintName)) return (T)constraint;
ConstraintData constraint = constraints[i];
if (type.isInstance(constraint) && constraint.name.equals(constraintName)) return (T)constraint;
}
return null;
}

View File

@ -121,7 +121,7 @@ import com.esotericsoftware.spine.attachments.VertexAttachment;
* <a href="https://esotericsoftware.com/spine-loading-skeleton-data#JSON-and-binary-data">JSON and binary data</a> in the Spine
* Runtimes Guide. */
public class SkeletonJson extends SkeletonLoader {
private final Array<LinkedMesh> linkedMeshes = new Array();
private final Array<LinkedMesh> linkedMeshes = new Array(true, 8, LinkedMesh[]::new);
public SkeletonJson (AttachmentLoader attachmentLoader) {
super(attachmentLoader);
@ -456,9 +456,9 @@ public class SkeletonJson extends SkeletonLoader {
}
// Linked meshes.
Object[] items = linkedMeshes.items;
LinkedMesh[] items = linkedMeshes.items;
for (int i = 0, n = linkedMeshes.size; i < n; i++) {
var linkedMesh = (LinkedMesh)items[i];
LinkedMesh linkedMesh = items[i];
Skin skin = linkedMesh.skin == null ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin);
if (skin == null) throw new SerializationException("Skin not found: " + linkedMesh.skin);
Attachment parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent);
@ -656,7 +656,7 @@ public class SkeletonJson extends SkeletonLoader {
private void readAnimation (JsonValue map, String name, SkeletonData skeletonData) {
float scale = this.scale;
var timelines = new Array<Timeline>();
var timelines = new Array<Timeline>(true, 16, Timeline[]::new);
// Slot timelines.
for (JsonValue slotMap = map.getChild("slots"); slotMap != null; slotMap = slotMap.next) {
@ -1186,9 +1186,9 @@ public class SkeletonJson extends SkeletonLoader {
timelines.shrink();
float duration = 0;
Object[] items = timelines.items;
Timeline[] items = timelines.items;
for (int i = 0, n = timelines.size; i < n; i++)
duration = Math.max(duration, ((Timeline)items[i]).getDuration());
duration = Math.max(duration, items[i].getDuration());
skeletonData.animations.add(new Animation(name, timelines, duration));
}

View File

@ -76,9 +76,9 @@ public class SkeletonRenderer {
float[] vertices = this.vertices.items;
Color skeletonColor = skeleton.color;
float r = skeletonColor.r, g = skeletonColor.g, b = skeletonColor.b, a = skeletonColor.a;
Object[] drawOrder = skeleton.drawOrder.items;
Slot[] drawOrder = skeleton.drawOrder.items;
for (int i = 0, n = skeleton.drawOrder.size; i < n; i++) {
var slot = (Slot)drawOrder[i];
Slot slot = drawOrder[i];
if (!slot.bone.active) continue;
SlotPose pose = slot.applied;
Attachment attachment = pose.attachment;
@ -142,9 +142,9 @@ public class SkeletonRenderer {
short[] triangles = null;
Color color = null, skeletonColor = skeleton.color;
float r = skeletonColor.r, g = skeletonColor.g, b = skeletonColor.b, a = skeletonColor.a;
Object[] drawOrder = skeleton.drawOrder.items;
Slot[] drawOrder = skeleton.drawOrder.items;
for (int i = 0, n = skeleton.drawOrder.size; i < n; i++) {
var slot = (Slot)drawOrder[i];
Slot slot = drawOrder[i];
if (slot.bone.active) {
SlotPose pose = slot.applied;
Attachment attachment = pose.attachment;
@ -237,9 +237,9 @@ public class SkeletonRenderer {
short[] triangles = null;
Color color = null, skeletonColor = skeleton.color;
float r = skeletonColor.r, g = skeletonColor.g, b = skeletonColor.b, a = skeletonColor.a;
Object[] drawOrder = skeleton.drawOrder.items;
Slot[] drawOrder = skeleton.drawOrder.items;
for (int i = 0, n = skeleton.drawOrder.size; i < n; i++) {
var slot = (Slot)drawOrder[i];
Slot slot = drawOrder[i];
if (slot.bone.active) {
SlotPose pose = slot.applied;
Attachment attachment = pose.attachment;

View File

@ -79,14 +79,15 @@ public class SkeletonRendererDebug {
Gdx.gl.glBlendFunc(srcFunc, GL20.GL_ONE_MINUS_SRC_ALPHA);
ShapeRenderer shapes = this.shapes;
Array<Bone> bones = skeleton.bones;
Array<Slot> slots = skeleton.slots;
Bone[] bones = skeleton.bones.items;
Slot[] slots = skeleton.slots.items;
int boneCount = skeleton.bones.size, slotCount = skeleton.slots.size;
shapes.begin(ShapeType.Filled);
if (drawBones) {
for (int i = 0, n = bones.size; i < n; i++) {
Bone bone = bones.get(i);
for (int i = 0; i < boneCount; i++) {
Bone bone = bones[i];
if (bone.parent == null || !bone.active) continue;
float length = bone.data.length, width = boneWidth;
if (length == 0) {
@ -105,8 +106,8 @@ public class SkeletonRendererDebug {
if (drawPoints) {
shapes.setColor(boneOriginColor);
for (int i = 0, n = slots.size; i < n; i++) {
Slot slot = slots.get(i);
for (int i = 0; i < slotCount; i++) {
Slot slot = slots[i];
if (!slot.bone.active) continue;
if (!(slot.applied.attachment instanceof PointAttachment point)) continue;
point.computeWorldPosition(slot.bone.applied, temp1);
@ -120,8 +121,8 @@ public class SkeletonRendererDebug {
if (drawRegionAttachments) {
shapes.setColor(attachmentLineColor);
for (int i = 0, n = slots.size; i < n; i++) {
Slot slot = slots.get(i);
for (int i = 0; i < slotCount; i++) {
Slot slot = slots[i];
if (!slot.bone.active) continue;
if (slot.pose.attachment instanceof RegionAttachment region) {
float[] vertices = this.vertices.items;
@ -135,8 +136,8 @@ public class SkeletonRendererDebug {
}
if (drawMeshHull || drawMeshTriangles) {
for (int i = 0, n = slots.size; i < n; i++) {
Slot slot = slots.get(i);
for (int i = 0; i < slotCount; i++) {
Slot slot = slots[i];
if (!slot.bone.active) continue;
if (!(slot.pose.attachment instanceof MeshAttachment mesh)) continue;
float[] vertices = this.vertices.setSize(mesh.getWorldVerticesLength());
@ -174,15 +175,15 @@ public class SkeletonRendererDebug {
Array<FloatArray> polygons = bounds.getPolygons();
Array<BoundingBoxAttachment> boxes = bounds.getBoundingBoxes();
for (int i = 0, n = polygons.size; i < n; i++) {
FloatArray polygon = polygons.get(i);
shapes.setColor(boxes.get(i).getColor());
FloatArray polygon = polygons.items[i];
shapes.setColor(boxes.items[i].getColor());
shapes.polygon(polygon.items, 0, polygon.size);
}
}
if (drawClipping) {
for (int i = 0, n = slots.size; i < n; i++) {
Slot slot = slots.get(i);
for (int i = 0; i < slotCount; i++) {
Slot slot = slots[i];
if (!slot.bone.active) continue;
if (!(slot.pose.attachment instanceof ClippingAttachment clip)) continue;
int nn = clip.getWorldVerticesLength();
@ -196,8 +197,8 @@ public class SkeletonRendererDebug {
}
if (drawPaths) {
for (int i = 0, n = slots.size; i < n; i++) {
Slot slot = slots.get(i);
for (int i = 0; i < slotCount; i++) {
Slot slot = slots[i];
if (!slot.bone.active) continue;
if (!(slot.pose.attachment instanceof PathAttachment path)) continue;
int nn = path.getWorldVerticesLength();
@ -236,8 +237,8 @@ public class SkeletonRendererDebug {
if (drawBones) {
shapes.setColor(boneOriginColor);
for (int i = 0, n = bones.size; i < n; i++) {
Bone bone = bones.get(i);
for (int i = 0; i < boneCount; i++) {
Bone bone = bones[i];
if (!bone.active) continue;
shapes.circle(bone.applied.worldX, bone.applied.worldY, 3 * scale, 8);
}
@ -245,8 +246,8 @@ public class SkeletonRendererDebug {
if (drawPoints) {
shapes.setColor(boneOriginColor);
for (int i = 0, n = slots.size; i < n; i++) {
Slot slot = slots.get(i);
for (int i = 0; i < slotCount; i++) {
Slot slot = slots[i];
if (!slot.bone.active) continue;
if (!(slot.pose.attachment instanceof PointAttachment point)) continue;
point.computeWorldPosition(slot.bone.applied, temp1);

View File

@ -44,8 +44,8 @@ import com.esotericsoftware.spine.attachments.MeshAttachment;
public class Skin {
final String name;
final OrderedSet<SkinEntry> attachments = new OrderedSet();
final Array<BoneData> bones = new Array(0);
final Array<ConstraintData> constraints = new Array(0);
final Array<BoneData> bones = new Array(true, 0, BoneData[]::new);
final Array<ConstraintData> constraints = new Array(true, 0, ConstraintData[]::new);
private final SkinEntry lookup = new SkinEntry(0, "", null);
// Nonessential.
@ -154,12 +154,11 @@ public class Skin {
/** Attach each attachment in this skin if the corresponding attachment in the old skin is currently attached. */
void attachAll (Skeleton skeleton, Skin oldSkin) {
Object[] slots = skeleton.slots.items;
Slot[] slots = skeleton.slots.items;
for (SkinEntry entry : oldSkin.attachments.orderedItems()) {
int slotIndex = entry.slotIndex;
SlotPose slot = ((Slot)slots[slotIndex]).pose;
SlotPose slot = slots[entry.slotIndex].pose;
if (slot.attachment == entry.attachment) {
Attachment attachment = getAttachment(slotIndex, entry.name);
Attachment attachment = getAttachment(entry.slotIndex, entry.name);
if (attachment != null) slot.setAttachment(attachment);
}
}

View File

@ -32,6 +32,7 @@ package com.esotericsoftware.spine;
import com.esotericsoftware.spine.Animation.BoneTimeline;
import com.esotericsoftware.spine.Animation.MixBlend;
import com.esotericsoftware.spine.Animation.MixDirection;
import com.esotericsoftware.spine.Animation.SlotTimeline;
import com.esotericsoftware.spine.Animation.Timeline;
/** Stores the setup pose for a {@link PhysicsConstraint}.
@ -54,27 +55,36 @@ public class Slider extends Constraint<Slider, SliderData, SliderPose> {
}
void sort (Skeleton skeleton) {
Object[] timelines = data.animation.timelines.items;
Timeline[] timelines = data.animation.timelines.items;
int timelineCount = data.animation.timelines.size;
// BOZO - Sort and reset other timeline types.
Object[] bones = skeleton.bones.items;
for (int i = 0; i < timelineCount; i++) {
var timeline = (Timeline)timelines[i];
if (timeline instanceof BoneTimeline boneTimeline) skeleton.sortBone((Bone)bones[boneTimeline.getBoneIndex()]);
}
Bone[] bones = skeleton.bones.items;
for (int i = 0; i < timelineCount; i++)
if (timelines[i] instanceof BoneTimeline boneTimeline) skeleton.sortBone(bones[boneTimeline.getBoneIndex()]);
skeleton.updateCache.add(this);
Slot[] slots = skeleton.slots.items;
for (int i = 0; i < timelineCount; i++) {
if (timelines[i] instanceof BoneTimeline boneTimeline) {
var bone = (Bone)bones[boneTimeline.getBoneIndex()];
skeleton.resetCache(bone);
Timeline timeline = timelines[i];
if (timeline instanceof BoneTimeline boneTimeline) {
Bone bone = bones[boneTimeline.getBoneIndex()];
skeleton.sortBone(bone);
skeleton.sortReset(bone.children);
bone.sorted = false;
}
} else if (timeline instanceof SlotTimeline slotTimeline) //
skeleton.resetCache(slots[slotTimeline.getSlotIndex()]);
// BOZO!
// skeleton.resetCache(skeleton.constraints.items[constraintIndex]);
// if (constraintIndex == -1) {
// Object[] constraints = skeleton.physics.items;
// for (int i = 0, n = skeleton.physics.size; i < n; i++)
// skeleton.resetCache((PhysicsConstraint)constraints[i]);
// } else
// skeleton.resetCache(skeleton.constraints.items[constraintIndex]);
}
for (int i = 0; i < timelineCount; i++)
if (timelines[i] instanceof BoneTimeline boneTimeline) skeleton.sortBone((Bone)bones[boneTimeline.getBoneIndex()]);
if (timelines[i] instanceof BoneTimeline boneTimeline) skeleton.sortBone(bones[boneTimeline.getBoneIndex()]);
}
}

View File

@ -43,7 +43,7 @@ public class Slot extends Posed<SlotData, SlotPose, SlotPose> {
super(data, new SlotPose(), new SlotPose());
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
this.skeleton = skeleton;
bone = skeleton.bones.get(data.boneData.index);
bone = skeleton.bones.items[data.boneData.index];
if (data.setup.darkColor != null) {
pose.darkColor = new Color();
applied.darkColor = new Color();

View File

@ -48,11 +48,11 @@ public class TransformConstraint extends Constraint<TransformConstraint, Transfo
super(data, new TransformConstraintPose(), new TransformConstraintPose());
if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null.");
bones = new Array(data.bones.size);
bones = new Array(true, data.bones.size, BonePose[]::new);
for (BoneData boneData : data.bones)
bones.add(skeleton.bones.get(boneData.index).constrained);
bones.add(skeleton.bones.items[boneData.index].constrained);
source = skeleton.bones.get(data.source.index);
source = skeleton.bones.items[data.source.index];
}
public TransformConstraint copy (Skeleton skeleton) {
@ -70,18 +70,17 @@ public class TransformConstraint extends Constraint<TransformConstraint, Transfo
TransformConstraintData data = this.data;
boolean localFrom = data.localSource, localTarget = data.localTarget, additive = data.additive, clamp = data.clamp;
BonePose source = this.source.applied;
Object[] fromItems = data.properties.items;
FromProperty[] fromItems = data.properties.items;
int fn = data.properties.size;
Object[] bones = this.bones.items;
BonePose[] bones = this.bones.items;
for (int i = 0, n = this.bones.size; i < n; i++) {
var bone = (BonePose)bones[i];
if (bone.bone.applied != bone.bone.constrained) System.out.println();
BonePose bone = bones[i];
for (int f = 0; f < fn; f++) {
var from = (FromProperty)fromItems[f];
FromProperty from = fromItems[f];
float value = from.value(data, source, localFrom) - from.offset;
Object[] toItems = from.to.items;
ToProperty[] toItems = from.to.items;
for (int t = 0, tn = from.to.size; t < tn; t++) {
var to = (ToProperty)toItems[t];
ToProperty to = toItems[t];
if (to.mix(pose) != 0) {
float clamped = to.offset + value * to.scale;
if (clamp) {
@ -104,18 +103,18 @@ public class TransformConstraint extends Constraint<TransformConstraint, Transfo
void sort (Skeleton skeleton) {
skeleton.sortBone(source);
Object[] bones = this.bones.items;
BonePose[] bones = this.bones.items;
int boneCount = this.bones.size;
if (data.localSource) {
for (int i = 0; i < boneCount; i++) {
Bone child = ((BonePose)bones[i]).bone;
Bone child = bones[i].bone;
skeleton.resetCache(child);
skeleton.sortBone(child.parent);
skeleton.sortBone(child);
}
} else {
for (int i = 0; i < boneCount; i++) {
Bone bone = ((BonePose)bones[i]).bone;
Bone bone = bones[i].bone;
skeleton.resetCache(bone);
skeleton.sortBone(bone);
}
@ -124,9 +123,9 @@ public class TransformConstraint extends Constraint<TransformConstraint, Transfo
skeleton.updateCache.add(this);
for (int i = 0; i < boneCount; i++)
skeleton.sortReset(((BonePose)bones[i]).bone.children);
skeleton.sortReset(bones[i].bone.children);
for (int i = 0; i < boneCount; i++)
((BonePose)bones[i]).bone.sorted = true;
bones[i].bone.sorted = true;
}
boolean isSourceActive () {

View File

@ -37,11 +37,11 @@ import com.badlogic.gdx.utils.Array;
* <p>
* See <a href="https://esotericsoftware.com/spine-transform-constraints">Transform constraints</a> in the Spine User Guide. */
public class TransformConstraintData extends ConstraintData<TransformConstraint, TransformConstraintPose> {
final Array<BoneData> bones = new Array();
final Array<BoneData> bones = new Array(true, 0, BoneData[]::new);
BoneData source;
float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY;
boolean localSource, localTarget, additive, clamp;
final Array<FromProperty> properties = new Array();
final Array<FromProperty> properties = new Array(true, 1, FromProperty[]::new);
public TransformConstraintData (String name) {
super(name, new TransformConstraintPose());
@ -167,7 +167,7 @@ public class TransformConstraintData extends ConstraintData<TransformConstraint,
public float offset;
/** Constrained properties. */
public final Array<ToProperty> to = new Array();
public final Array<ToProperty> to = new Array(true, 1, ToProperty[]::new);
/** Reads this property from the specified bone. */
abstract public float value (TransformConstraintData data, BonePose source, boolean local);

View File

@ -111,14 +111,14 @@ abstract public class VertexAttachment extends Attachment {
v += n + 1;
skip += n;
}
Object[] skeletonBones = skeleton.getBones().items;
Bone[] skeletonBones = skeleton.getBones().items;
if (deformArray.size == 0) {
for (int w = offset, b = skip * 3; w < count; w += stride) {
float wx = 0, wy = 0;
int n = bones[v++];
n += v;
for (; v < n; v++, b += 3) {
BonePose bone = ((Bone)skeletonBones[bones[v]]).getAppliedPose();
BonePose bone = skeletonBones[bones[v]].getAppliedPose();
float vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2];
wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight;
wy += (vx * bone.getC() + vy * bone.getD() + bone.getWorldY()) * weight;
@ -133,7 +133,7 @@ abstract public class VertexAttachment extends Attachment {
int n = bones[v++];
n += v;
for (; v < n; v++, b += 3, f += 2) {
BonePose bone = ((Bone)skeletonBones[bones[v]]).getAppliedPose();
BonePose bone = skeletonBones[bones[v]].getAppliedPose();
float vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2];
wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight;
wy += (vx * bone.getC() + vy * bone.getD() + bone.getWorldY()) * weight;

View File

@ -61,7 +61,7 @@ public class SkeletonActorPool extends Pool<SkeletonActor> {
this.skeletonData = skeletonData;
this.stateData = stateData;
obtained = new Array(false, initialCapacity);
obtained = new Array(false, initialCapacity, SkeletonActor[]::new);
skeletonPool = new Pool<Skeleton>(initialCapacity, max) {
protected Skeleton newObject () {
@ -91,10 +91,10 @@ public class SkeletonActorPool extends Pool<SkeletonActor> {
/** Each obtained skeleton actor that is no longer playing an animation is removed from the stage and returned to the pool. */
public void freeComplete () {
Object[] obtained = this.obtained.items;
SkeletonActor[] obtained = this.obtained.items;
outer:
for (int i = this.obtained.size - 1; i >= 0; i--) {
var actor = (SkeletonActor)obtained[i];
SkeletonActor actor = obtained[i];
Array<TrackEntry> tracks = actor.state.getTracks();
for (int ii = 0, nn = tracks.size; ii < nn; ii++)
if (tracks.get(ii) != null) continue outer;

View File

@ -88,7 +88,7 @@ public class SkeletonClipping {
public boolean clipTriangles (float[] vertices, short[] triangles, int trianglesLength) {
FloatArray clipOutput = this.clipOutput, clippedVertices = this.clippedVertices;
ShortArray clippedTriangles = this.clippedTriangles;
Object[] polygons = clippingPolygons.items;
FloatArray[] polygons = clippingPolygons.items;
int polygonsCount = clippingPolygons.size;
short index = 0;
@ -108,7 +108,7 @@ public class SkeletonClipping {
for (int p = 0; p < polygonsCount; p++) {
int s = clippedVertices.size;
if (clip(x1, y1, x2, y2, x3, y3, (FloatArray)polygons[p], clipOutput)) {
if (clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) {
clipOutputItems = clipOutput.items;
int clipOutputLength = clipOutput.size;
if (clipOutputLength == 0) continue;
@ -160,7 +160,7 @@ public class SkeletonClipping {
FloatArray clipOutput = this.clipOutput, clippedVertices = this.clippedVertices;
ShortArray clippedTriangles = this.clippedTriangles;
Object[] polygons = clippingPolygons.items;
FloatArray[] polygons = clippingPolygons.items;
int polygonsCount = clippingPolygons.size;
short index = 0;
@ -183,7 +183,7 @@ public class SkeletonClipping {
for (int p = 0; p < polygonsCount; p++) {
int s = clippedVertices.size;
if (clip(x1, y1, x2, y2, x3, y3, (FloatArray)polygons[p], clipOutput)) {
if (clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) {
clipOutputItems = clipOutput.items;
int clipOutputLength = clipOutput.size;
if (clipOutputLength == 0) continue;
@ -277,7 +277,7 @@ public class SkeletonClipping {
FloatArray clipOutput = this.clipOutput, clippedVertices = this.clippedVertices;
FloatArray clippedUvs = this.clippedUvs;
ShortArray clippedTriangles = this.clippedTriangles;
Object[] polygons = clippingPolygons.items;
FloatArray[] polygons = clippingPolygons.items;
int polygonsCount = clippingPolygons.size;
int vertexSize = 2;
@ -300,7 +300,7 @@ public class SkeletonClipping {
for (int p = 0; p < polygonsCount; p++) {
int s = clippedVertices.size;
if (clip(x1, y1, x2, y2, x3, y3, (FloatArray)polygons[p], clipOutput)) {
if (clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) {
int clipOutputLength = clipOutput.size;
if (clipOutputLength == 0) continue;
float d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1;

View File

@ -36,8 +36,8 @@ import com.badlogic.gdx.utils.Pool;
import com.badlogic.gdx.utils.ShortArray;
class Triangulator {
private final Array<FloatArray> convexPolygons = new Array(false, 16);
private final Array<ShortArray> convexPolygonsIndices = new Array(false, 16);
private final Array<FloatArray> convexPolygons = new Array(false, 8, FloatArray[]::new);
private final Array<ShortArray> convexPolygonsIndices = new Array(false, 8, FloatArray[]::new);
private final ShortArray indicesArray = new ShortArray();
private final BooleanArray isConcaveArray = new BooleanArray();
@ -204,14 +204,15 @@ class Triangulator {
}
// Go through the list of polygons and try to merge the remaining triangles with the found triangle fans.
Object[] convexPolygonsIndicesItems = convexPolygonsIndices.items, convexPolygonsItems = convexPolygons.items;
ShortArray[] convexPolygonsIndicesItems = convexPolygonsIndices.items;
FloatArray[] convexPolygonsItems = convexPolygons.items;
for (int i = 0, n = convexPolygons.size; i < n; i++) {
polygonIndices = (ShortArray)convexPolygonsIndicesItems[i];
polygonIndices = convexPolygonsIndicesItems[i];
if (polygonIndices.size == 0) continue;
int firstIndex = polygonIndices.first();
int lastIndex = polygonIndices.get(polygonIndices.size - 1);
int lastIndex = polygonIndices.items[polygonIndices.size - 1];
polygon = (FloatArray)convexPolygonsItems[i];
polygon = convexPolygonsItems[i];
int o = polygon.size - 4;
float[] p = polygon.items;
float prevPrevX = p[o], prevPrevY = p[o + 1];
@ -222,14 +223,14 @@ class Triangulator {
for (int ii = 0; ii < n; ii++) {
if (ii == i) continue;
var otherIndices = (ShortArray)convexPolygonsIndicesItems[ii];
ShortArray otherIndices = convexPolygonsIndicesItems[ii];
if (otherIndices.size != 3) continue;
int otherFirstIndex = otherIndices.first();
int otherSecondIndex = otherIndices.get(1);
int otherLastIndex = otherIndices.get(2);
int otherSecondIndex = otherIndices.items[1];
int otherLastIndex = otherIndices.items[2];
var otherPoly = (FloatArray)convexPolygonsItems[ii];
float x3 = otherPoly.get(otherPoly.size - 2), y3 = otherPoly.get(otherPoly.size - 1);
FloatArray otherPoly = convexPolygonsItems[ii];
float x3 = otherPoly.items[otherPoly.size - 2], y3 = otherPoly.items[otherPoly.size - 1];
if (otherFirstIndex != firstIndex || otherSecondIndex != lastIndex) continue;
int winding1 = winding(prevPrevX, prevPrevY, prevX, prevY, x3, y3);
@ -251,7 +252,7 @@ class Triangulator {
// Remove empty polygons that resulted from the merge step above.
for (int i = convexPolygons.size - 1; i >= 0; i--) {
polygon = (FloatArray)convexPolygonsItems[i];
polygon = convexPolygonsItems[i];
if (polygon.size == 0) {
convexPolygons.removeIndex(i);
polygonPool.free(polygon);
@ -259,7 +260,6 @@ class Triangulator {
polygonIndicesPool.free(polygonIndices);
}
}
return convexPolygons;
}