diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java index efd4cb7d1..9320c6f76 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java @@ -1980,7 +1980,7 @@ public class Animation { return ENTRIES; } - /** The index of the IK constraint in {@link Skeleton#getIkConstraints()} that will be changed when this timeline is + /** The index of the IK constraint in {@link Skeleton#getConstraints()} that will be changed when this timeline is * applied. */ public int getIkConstraintIndex () { return constraintIndex; @@ -2004,7 +2004,7 @@ public class Animation { public void apply (Skeleton skeleton, float lastTime, float time, @Null Array events, float alpha, MixBlend blend, MixDirection direction, boolean appliedPose) { - IkConstraint constraint = skeleton.ikConstraints.get(constraintIndex); + var constraint = (IkConstraint)skeleton.constraints.get(constraintIndex); if (!constraint.active) return; IkConstraintPose pose = appliedPose ? constraint.applied : constraint.pose, setup = constraint.data.setup; @@ -2090,8 +2090,8 @@ public class Animation { return ENTRIES; } - /** The index of the transform constraint in {@link Skeleton#getTransformConstraints()} that will be changed when this - * timeline is applied. */ + /** The index of the transform constraint in {@link Skeleton#getConstraints()} that will be changed when this timeline is + * applied. */ public int getTransformConstraintIndex () { return constraintIndex; } @@ -2114,7 +2114,7 @@ public class Animation { public void apply (Skeleton skeleton, float lastTime, float time, @Null Array events, float alpha, MixBlend blend, MixDirection direction, boolean appliedPose) { - TransformConstraint constraint = skeleton.transformConstraints.get(constraintIndex); + var constraint = (TransformConstraint)skeleton.constraints.get(constraintIndex); if (!constraint.active) return; TransformConstraintPose pose = appliedPose ? constraint.applied : constraint.pose; @@ -2205,7 +2205,7 @@ public class Animation { constraintIndex = pathConstraintIndex; } - /** The index of the path constraint in {@link Skeleton#getPathConstraints()} that will be changed when this timeline is + /** The index of the path constraint in {@link Skeleton#getConstraints()} that will be changed when this timeline is * applied. */ public int getPathConstraintIndex () { return constraintIndex; @@ -2214,7 +2214,7 @@ public class Animation { public void apply (Skeleton skeleton, float lastTime, float time, @Null Array events, float alpha, MixBlend blend, MixDirection direction, boolean appliedPose) { - PathConstraint constraint = skeleton.pathConstraints.get(constraintIndex); + var constraint = (PathConstraint)skeleton.constraints.get(constraintIndex); if (constraint.active) { PathConstraintPose pose = appliedPose ? constraint.applied : constraint.pose; pose.position = getAbsoluteValue(time, alpha, blend, pose.position, constraint.data.setup.position); @@ -2231,7 +2231,7 @@ public class Animation { constraintIndex = pathConstraintIndex; } - /** The index of the path constraint in {@link Skeleton#getPathConstraints()} that will be changed when this timeline is + /** The index of the path constraint in {@link Skeleton#getConstraints()} that will be changed when this timeline is * applied. */ public int getPathConstraintIndex () { return constraintIndex; @@ -2240,7 +2240,7 @@ public class Animation { public void apply (Skeleton skeleton, float lastTime, float time, @Null Array events, float alpha, MixBlend blend, MixDirection direction, boolean appliedPose) { - PathConstraint constraint = skeleton.pathConstraints.get(constraintIndex); + var constraint = (PathConstraint)skeleton.constraints.get(constraintIndex); if (constraint.active) { PathConstraintPose pose = appliedPose ? constraint.applied : constraint.pose; pose.spacing = getAbsoluteValue(time, alpha, blend, pose.spacing, constraint.data.setup.spacing); @@ -2265,7 +2265,7 @@ public class Animation { return ENTRIES; } - /** The index of the path constraint in {@link Skeleton#getPathConstraints()} that will be changed when this timeline is + /** The index of the path constraint in {@link Skeleton#getConstraints()} that will be changed when this timeline is * applied. */ public int getPathConstraintIndex () { return constraintIndex; @@ -2285,7 +2285,7 @@ public class Animation { public void apply (Skeleton skeleton, float lastTime, float time, @Null Array events, float alpha, MixBlend blend, MixDirection direction, boolean appliedPose) { - PathConstraint constraint = skeleton.pathConstraints.get(constraintIndex); + var constraint = (PathConstraint)skeleton.constraints.get(constraintIndex); if (!constraint.active) return; PathConstraintPose pose = appliedPose ? constraint.applied : constraint.pose; @@ -2362,20 +2362,19 @@ public class Animation { public void apply (Skeleton skeleton, float lastTime, float time, @Null Array events, float alpha, MixBlend blend, MixDirection direction, boolean appliedPose) { - PhysicsConstraint constraint; if (constraintIndex == -1) { float value = time >= frames[0] ? getCurveValue(time) : 0; - Object[] constraints = skeleton.physicsConstraints.items; - for (int i = 0, n = skeleton.physicsConstraints.size; i < n; i++) { - constraint = (PhysicsConstraint)constraints[i]; + Object[] constraints = skeleton.physics.items; + for (int i = 0, n = skeleton.physics.size; i < n; i++) { + var constraint = (PhysicsConstraint)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 { - constraint = skeleton.physicsConstraints.get(constraintIndex); + var constraint = (PhysicsConstraint)skeleton.constraints.get(constraintIndex); if (constraint.active) { PhysicsConstraintPose pose = appliedPose ? constraint.applied : constraint.pose; set(pose, getAbsoluteValue(time, alpha, blend, get(pose), get(constraint.data.setup))); @@ -2557,7 +2556,7 @@ public class Animation { PhysicsConstraint constraint = null; if (constraintIndex != -1) { - constraint = skeleton.physicsConstraints.get(constraintIndex); + constraint = (PhysicsConstraint)skeleton.constraints.get(constraintIndex); if (!constraint.active) return; } @@ -2574,8 +2573,8 @@ public class Animation { if (constraint != null) constraint.reset(skeleton); else { - Object[] constraints = skeleton.physicsConstraints.items; - for (int i = 0, n = skeleton.physicsConstraints.size; i < n; i++) { + Object[] constraints = skeleton.physics.items; + for (int i = 0, n = skeleton.physics.size; i < n; i++) { constraint = (PhysicsConstraint)constraints[i]; if (constraint.active) constraint.reset(skeleton); } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Constraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Constraint.java index e131b3f4e..f68105e91 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Constraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Constraint.java @@ -1,10 +1,21 @@ package com.esotericsoftware.spine; -abstract public class Constraint, P extends Pose> extends PosedActive implements Update { +abstract public class Constraint< // + T extends Constraint, // + D extends ConstraintData, // + P extends Pose> // + extends PosedActive implements Update { + public Constraint (D data, P pose, P constrained) { super(data, pose, constrained); } - abstract public void sort (); + abstract public T copy (Skeleton skeleton); + + abstract void sort (Skeleton skeleton); + + boolean isSourceActive () { + return true; + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/ConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/ConstraintData.java new file mode 100644 index 000000000..7685856f8 --- /dev/null +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/ConstraintData.java @@ -0,0 +1,14 @@ + +package com.esotericsoftware.spine; + +abstract public class ConstraintData< // + T extends Constraint, // + P extends Pose> // + extends PosedData

{ + + public ConstraintData (String name, P setup) { + super(name, setup); + } + + abstract public T create (Skeleton skeleton); +} diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Event.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Event.java index c5dbf7f47..a07833667 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Event.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Event.java @@ -39,7 +39,7 @@ import com.esotericsoftware.spine.AnimationState.AnimationStateListener; * AnimationStateListener {@link AnimationStateListener#event(com.esotericsoftware.spine.AnimationState.TrackEntry, Event)}, and * Events in the Spine User Guide. */ public class Event { - private final EventData data; + final EventData data; int intValue; float floatValue; String stringValue; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java index 11a3bb114..ac357fb50 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java @@ -39,7 +39,7 @@ import com.esotericsoftware.spine.BoneData.Inherit; * the last bone is as close to the target bone as possible. *

* See IK constraints in the Spine User Guide. */ -public class IkConstraint extends Constraint { +public class IkConstraint extends Constraint { final Array bones; Bone target; @@ -54,10 +54,10 @@ public class IkConstraint extends Constraint target = skeleton.bones.get(data.target.index); } - /** Copy constructor. */ - public IkConstraint (IkConstraint constraint, Skeleton skeleton) { - this(constraint.data, skeleton); - pose.set(constraint.pose); + public IkConstraint copy (Skeleton skeleton) { + var copy = new IkConstraint(data, skeleton); + copy.pose.set(pose); + return copy; } /** Applies the constraint to the constrained bones. */ @@ -73,8 +73,29 @@ public class IkConstraint extends Constraint } } - public void sort () { - // BOZO + void sort (Skeleton skeleton) { + skeleton.sortBone(target); + + Bone parent = bones.first().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; + skeleton.resetCache(child); + skeleton.sortBone(child); + + skeleton.updateCache.add(this); + + skeleton.sortReset(parent.children); + child.sorted = true; + } + } + + boolean isSourceActive () { + return target.active; } /** The 1 or 2 bones that will be modified by this IK constraint. */ diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java index f590e90d4..92fc97e48 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java @@ -34,7 +34,7 @@ import com.badlogic.gdx.utils.Array; /** Stores the setup pose for an {@link IkConstraint}. *

* See IK constraints in the Spine User Guide. */ -public class IkConstraintData extends PosedData { +public class IkConstraintData extends ConstraintData { final Array bones = new Array(); BoneData target; boolean uniform; @@ -43,6 +43,10 @@ public class IkConstraintData extends PosedData { super(name, new IkConstraintPose()); } + public IkConstraint create (Skeleton skeleton) { + return new IkConstraint(this, skeleton); + } + /** The bones that are constrained by this IK constraint. */ public Array getBones () { return bones; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java index f5751cc14..6f30ddf22 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java @@ -39,13 +39,15 @@ import com.badlogic.gdx.utils.FloatArray; import com.esotericsoftware.spine.PathConstraintData.PositionMode; import com.esotericsoftware.spine.PathConstraintData.RotateMode; import com.esotericsoftware.spine.PathConstraintData.SpacingMode; +import com.esotericsoftware.spine.Skin.SkinEntry; +import com.esotericsoftware.spine.attachments.Attachment; import com.esotericsoftware.spine.attachments.PathAttachment; /** Stores the current pose for a path constraint. A path constraint adjusts the rotation, translation, and scale of the * constrained bones so they follow a {@link PathAttachment}. *

* See Path constraints in the Spine User Guide. */ -public class PathConstraint extends Constraint { +public class PathConstraint extends Constraint { static final int NONE = -1, BEFORE = -2, AFTER = -3; static final float epsilon = 0.00001f; @@ -67,10 +69,10 @@ public class PathConstraint extends Constraint * See Path constraints in the Spine User Guide. */ -public class PathConstraintData extends PosedData { +public class PathConstraintData extends ConstraintData { final Array bones = new Array(); SlotData slot; PositionMode positionMode; @@ -46,6 +46,10 @@ public class PathConstraintData extends PosedData { super(name, new PathConstraintPose()); } + public PathConstraint create (Skeleton skeleton) { + return new PathConstraint(this, skeleton); + } + /** The bones that will be modified by this path constraint. */ public Array getBones () { return bones; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java index 59942b18c..95cd72d6a 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PhysicsConstraint.java @@ -34,7 +34,7 @@ import static com.esotericsoftware.spine.utils.SpineUtils.*; /** Stores the current pose for a physics constraint. A physics constraint applies physics to bones. *

* See Physics constraints in the Spine User Guide. */ -public class PhysicsConstraint extends Constraint { +public class PhysicsConstraint extends Constraint { BonePose bone; boolean reset = true; @@ -52,10 +52,10 @@ public class PhysicsConstraint extends Constraint * See Physics constraints in the Spine User Guide. */ -public class PhysicsConstraintData extends PosedData { +public class PhysicsConstraintData extends ConstraintData { BoneData bone; float x, y, rotate, scaleX, shearX, limit, step; boolean inertiaGlobal, strengthGlobal, dampingGlobal, massGlobal, windGlobal, gravityGlobal, mixGlobal; @@ -41,6 +41,10 @@ public class PhysicsConstraintData extends PosedData { super(name, new PhysicsConstraintPose()); } + public PhysicsConstraint create (Skeleton skeleton) { + return new PhysicsConstraint(this, skeleton); + } + /** The bone constrained by this physics constraint. */ public BoneData getBone () { return bone; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Posed.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Posed.java index 9c47f317e..50d66c629 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Posed.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Posed.java @@ -1,7 +1,11 @@ package com.esotericsoftware.spine; -abstract public class Posed, P extends Pose, A extends P> { +abstract public class Posed< // + D extends PosedData

, // + P extends Pose, // + A extends P> { + final D data; final P pose; final A constrained; @@ -13,7 +17,6 @@ abstract public class Posed, P extends Pose, A extends P> this.pose = pose; this.constrained = constrained; applied = (A)pose; - setupPose(); } public void setupPose () { diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PosedActive.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PosedActive.java index fee548886..388cb8964 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PosedActive.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PosedActive.java @@ -1,11 +1,17 @@ package com.esotericsoftware.spine; -abstract public class PosedActive, P extends Pose, A extends P> extends Posed { +abstract public class PosedActive< // + D extends PosedData

, // + P extends Pose, // + A extends P> // + extends Posed { + boolean active; public PosedActive (D data, P pose, A constrained) { super(data, pose, constrained); + setupPose(); } /** Returns false when this constraint won't be updated by diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PosedData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PosedData.java index f8f652d0c..28ff10dae 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PosedData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PosedData.java @@ -35,16 +35,6 @@ abstract public class PosedData

{ final P setup; boolean skinRequired; - int order; // BOZO - Remove order. - - public int getOrder () { - return order; - } - - public void setOrder (int order) { - this.order = order; - } - public PosedData (String name, P setup) { if (name == null) throw new IllegalArgumentException("name cannot be null."); this.name = name; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java index 240f19bf5..9e6c5b8cc 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java @@ -37,13 +37,9 @@ import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.FloatArray; import com.badlogic.gdx.utils.Null; -import com.esotericsoftware.spine.Animation.BoneTimeline; -import com.esotericsoftware.spine.Animation.Timeline; -import com.esotericsoftware.spine.Skin.SkinEntry; import com.esotericsoftware.spine.attachments.Attachment; import com.esotericsoftware.spine.attachments.ClippingAttachment; import com.esotericsoftware.spine.attachments.MeshAttachment; -import com.esotericsoftware.spine.attachments.PathAttachment; import com.esotericsoftware.spine.attachments.RegionAttachment; import com.esotericsoftware.spine.utils.SkeletonClipping; @@ -58,11 +54,8 @@ public class Skeleton { final Array bones; final Array slots; Array drawOrder; - final Array sliders; - final Array ikConstraints; - final Array transformConstraints; - final Array pathConstraints; - final Array physicsConstraints; + final Array constraints; + final Array physics; final Array updateCache = new Array(); final Array resetCache = new Array(); @Null Skin skin; @@ -95,25 +88,13 @@ public class Skeleton { drawOrder.add(slot); } - sliders = new Array(data.sliders.size); - for (SliderData constraint : data.sliders) - sliders.add(new Slider(constraint)); - - ikConstraints = new Array(data.ikConstraints.size); - for (IkConstraintData constraint : data.ikConstraints) - ikConstraints.add(new IkConstraint(constraint, this)); - - transformConstraints = new Array(data.transformConstraints.size); - for (TransformConstraintData constraint : data.transformConstraints) - transformConstraints.add(new TransformConstraint(constraint, this)); - - pathConstraints = new Array(data.pathConstraints.size); - for (PathConstraintData constraint : data.pathConstraints) - pathConstraints.add(new PathConstraint(constraint, this)); - - physicsConstraints = new Array(data.physicsConstraints.size); - for (PhysicsConstraintData constraint : data.physicsConstraints) - physicsConstraints.add(new PhysicsConstraint(constraint, this)); + constraints = new Array(data.constraints.size); + physics = new Array(); + for (ConstraintData constraintData : data.constraints) { + Constraint constraint = constraintData.create(this); + if (constraint instanceof PhysicsConstraint physicsConstraint) physics.add(physicsConstraint); + constraints.add(constraint); + } color = new Color(1, 1, 1, 1); @@ -141,32 +122,20 @@ public class Skeleton { 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)); + slots.add(new Slot(slot, bone, this)); } drawOrder = new Array(slots.size); for (Slot slot : skeleton.drawOrder) drawOrder.add(slots.get(slot.data.index)); - sliders = new Array(skeleton.sliders.size); - for (Slider constraint : skeleton.sliders) - sliders.add(new Slider(constraint)); - - ikConstraints = new Array(skeleton.ikConstraints.size); - for (IkConstraint constraint : skeleton.ikConstraints) - ikConstraints.add(new IkConstraint(constraint, skeleton)); - - transformConstraints = new Array(skeleton.transformConstraints.size); - for (TransformConstraint constraint : skeleton.transformConstraints) - transformConstraints.add(new TransformConstraint(constraint, skeleton)); - - pathConstraints = new Array(skeleton.pathConstraints.size); - for (PathConstraint constraint : skeleton.pathConstraints) - pathConstraints.add(new PathConstraint(constraint, skeleton)); - - physicsConstraints = new Array(skeleton.physicsConstraints.size); - for (PhysicsConstraint constraint : skeleton.physicsConstraints) - physicsConstraints.add(new PhysicsConstraint(constraint, skeleton)); + physics = new Array(skeleton.physics.size); + constraints = new Array(skeleton.constraints.size); + for (Constraint other : skeleton.constraints) { + Constraint constraint = other.copy(this); + if (constraint instanceof PhysicsConstraint physicsConstraint) physics.add(physicsConstraint); + constraints.add(constraint); + } skin = skeleton.skin; color = new Color(skeleton.color); @@ -194,9 +163,9 @@ public class Skeleton { bone.setConstrained(false); } if (skin != null) { - Object[] skinBones = skin.bones.items; + Object[] objects = skin.bones.items; for (int i = 0, n = skin.bones.size; i < n; i++) { - var bone = (Bone)bones[((BoneData)skinBones[i]).index]; + var bone = (Bone)objects[((BoneData)objects[i]).index]; do { bone.sorted = false; bone.active = true; @@ -205,232 +174,34 @@ public class Skeleton { } } - int sliderCount = sliders.size, ikCount = ikConstraints.size, transformCount = transformConstraints.size, - pathCount = pathConstraints.size, physicsCount = physicsConstraints.size; - Object[] sliders = this.sliders.items, ikConstraints = this.ikConstraints.items, - transformConstraints = this.transformConstraints.items, pathConstraints = this.pathConstraints.items, - physicsConstraints = this.physicsConstraints.items; - for (int ii = 0; ii < sliderCount; ii++) - ((Slider)sliders[ii]).setConstrained(false); - for (int ii = 0; ii < ikCount; ii++) - ((IkConstraint)ikConstraints[ii]).setConstrained(false); - for (int ii = 0; ii < transformCount; ii++) - ((TransformConstraint)transformConstraints[ii]).setConstrained(false); - for (int ii = 0; ii < pathCount; ii++) - ((PathConstraint)pathConstraints[ii]).setConstrained(false); - for (int ii = 0; ii < physicsCount; ii++) - ((PhysicsConstraint)physicsConstraints[ii]).setConstrained(false); - - int constraintCount = ikCount + transformCount + pathCount + physicsCount; - outer: - for (int i = 0; i < constraintCount; i++) { - for (int ii = 0; ii < sliderCount; ii++) { - var constraint = (Slider)sliders[ii]; - if (constraint.data.order == i) { - sortSlider(constraint); - continue outer; - } - } - for (int ii = 0; ii < ikCount; ii++) { - var constraint = (IkConstraint)ikConstraints[ii]; - if (constraint.data.order == i) { - sortIkConstraint(constraint); - continue outer; - } - } - for (int ii = 0; ii < transformCount; ii++) { - var constraint = (TransformConstraint)transformConstraints[ii]; - if (constraint.data.order == i) { - sortTransformConstraint(constraint); - continue outer; - } - } - for (int ii = 0; ii < pathCount; ii++) { - var constraint = (PathConstraint)pathConstraints[ii]; - if (constraint.data.order == i) { - sortPathConstraint(constraint); - continue outer; - } - } - for (int ii = 0; ii < physicsCount; ii++) { - var constraint = (PhysicsConstraint)physicsConstraints[ii]; - if (constraint.data.order == i) { - sortPhysicsConstraint(constraint); - continue outer; - } - } + Object[] objects = constraints.items; + int n = constraints.size; + for (int i = 0; i < n; i++) + ((Constraint)objects[i]).setConstrained(false); + for (int i = 0; i < n; i++) { + var constraint = (Constraint)objects[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]); - Object[] updateCache = this.updateCache.items; - for (int i = 0, n = this.updateCache.size; i < n; i++) - if (updateCache[i] instanceof Bone bone) updateCache[i] = bone.applied; + objects = this.updateCache.items; + n = this.updateCache.size; + for (int i = 0; i < n; i++) + if (objects[i] instanceof Bone bone) objects[i] = bone.applied; } - private void sortIkConstraint (IkConstraint constraint) { - constraint.active = constraint.target.active - && (!constraint.data.skinRequired || (skin != null && skin.constraints.contains(constraint.data, true))); - if (!constraint.active) return; - - sortBone(constraint.target); - - Array constrained = constraint.bones; - Bone parent = constrained.first().bone; - sortBone(parent); - resetCache(parent); - if (constrained.size == 1) { - updateCache.add(constraint); - sortReset(parent.children); - } else { - Bone child = constrained.peek().bone; - resetCache(child); - sortBone(child); - - updateCache.add(constraint); - - sortReset(parent.children); - child.sorted = true; - } - } - - private void sortTransformConstraint (TransformConstraint constraint) { - constraint.active = constraint.source.active - && (!constraint.data.skinRequired || (skin != null && skin.constraints.contains(constraint.data, true))); - if (!constraint.active) return; - - sortBone(constraint.source); - - Object[] constrained = constraint.bones.items; - int boneCount = constraint.bones.size; - if (constraint.data.localSource) { - for (int i = 0; i < boneCount; i++) { - Bone child = ((BonePose)constrained[i]).bone; - resetCache(child); - sortBone(child.parent); - sortBone(child); - } - } else { - for (int i = 0; i < boneCount; i++) { - Bone bone = ((BonePose)constrained[i]).bone; - resetCache(bone); - sortBone(bone); - } - } - - updateCache.add(constraint); - - for (int i = 0; i < boneCount; i++) - sortReset(((BonePose)constrained[i]).bone.children); - for (int i = 0; i < boneCount; i++) - ((BonePose)constrained[i]).bone.sorted = true; - } - - private void sortPathConstraint (PathConstraint constraint) { - constraint.active = constraint.slot.bone.active - && (!constraint.data.skinRequired || (skin != null && skin.constraints.contains(constraint.data, true))); - if (!constraint.active) return; - - Slot slot = constraint.slot; - int slotIndex = slot.getData().index; - Bone slotBone = slot.bone; - if (skin != null) sortPathConstraintAttachment(skin, slotIndex, slotBone); - if (data.defaultSkin != null && data.defaultSkin != skin) - sortPathConstraintAttachment(data.defaultSkin, slotIndex, slotBone); - - sortPathConstraintAttachment(slot.pose.attachment, slotBone); - - Object[] constrained = constraint.bones.items; - int boneCount = constraint.bones.size; - for (int i = 0; i < boneCount; i++) { - Bone bone = ((BonePose)constrained[i]).bone; - resetCache(bone); - sortBone(bone); - } - - updateCache.add(constraint); - - for (int i = 0; i < boneCount; i++) - sortReset(((BonePose)constrained[i]).bone.children); - for (int i = 0; i < boneCount; i++) - ((BonePose)constrained[i]).bone.sorted = true; - } - - private void sortPathConstraintAttachment (Skin skin, int slotIndex, Bone slotBone) { - Object[] entries = skin.attachments.orderedItems().items; - for (int i = 0, n = skin.attachments.size; i < n; i++) { - var entry = (SkinEntry)entries[i]; - if (entry.slotIndex == slotIndex) sortPathConstraintAttachment(entry.attachment, slotBone); - } - } - - private void sortPathConstraintAttachment (Attachment attachment, Bone slotBone) { - if (!(attachment instanceof PathAttachment pathAttachment)) return; - int[] pathBones = pathAttachment.getBones(); - if (pathBones == null) - sortBone(slotBone); - else { - Object[] bones = this.bones.items; - for (int i = 0, n = pathBones.length; i < n;) { - int nn = pathBones[i++]; - nn += i; - while (i < nn) - sortBone((Bone)bones[pathBones[i++]]); - } - } - } - - private void sortPhysicsConstraint (PhysicsConstraint constraint) { - Bone bone = constraint.bone.bone; - constraint.active = bone.active - && (!constraint.data.skinRequired || (skin != null && skin.constraints.contains(constraint.data, true))); - if (!constraint.active) return; - - sortBone(bone); - - resetCache(bone); - updateCache.add(constraint); - - sortReset(bone.children); - bone.sorted = true; - } - - private void sortSlider (Slider constraint) { - constraint.active = !constraint.data.skinRequired || (skin != null && skin.constraints.contains(constraint.data, true)); - if (!constraint.active) return; - - Object[] timelines = constraint.data.animation.timelines.items; - int timelineCount = constraint.data.animation.timelines.size; - - Object[] bones = this.bones.items; - for (int i = 0; i < timelineCount; i++) { - var timeline = (Timeline)timelines[i]; - if (timeline instanceof BoneTimeline boneTimeline) sortBone((Bone)bones[boneTimeline.getBoneIndex()]); - } - - updateCache.add(constraint); - - for (int i = 0; i < timelineCount; i++) { - if (timelines[i] instanceof BoneTimeline boneTimeline) { - var bone = (Bone)bones[boneTimeline.getBoneIndex()]; - resetCache(bone); - sortReset(bone.children); - bone.sorted = false; - } - } - for (int i = 0; i < timelineCount; i++) - if (timelines[i] instanceof BoneTimeline boneTimeline) sortBone((Bone)bones[boneTimeline.getBoneIndex()]); - } - - private void resetCache (Posed object) { - if (!resetCache.contains(object, true)) { + void resetCache (Posed object) { + if (!resetCache.contains(object, true)) { // BOZO resetCache.add(object); object.setConstrained(true); } } - private void sortBone (Bone bone) { + void sortBone (Bone bone) { if (bone.sorted) return; Bone parent = bone.parent; if (parent != null) sortBone(parent); @@ -438,7 +209,7 @@ public class Skeleton { updateCache.add(bone); } - private void sortReset (Array bones) { + void sortReset (Array bones) { Object[] items = bones.items; for (int i = 0, n = bones.size; i < n; i++) { var bone = (Bone)items[i]; @@ -453,13 +224,13 @@ public class Skeleton { * See World transforms in the Spine * Runtimes Guide. */ public void updateWorldTransform (Physics physics) { - Object[] resetCache = this.resetCache.items; + Object[] objects = this.resetCache.items; for (int i = 0, n = this.resetCache.size; i < n; i++) - ((Posed)resetCache[i]).resetAppliedPose(); + ((Posed)objects[i]).resetAppliedPose(); - Object[] updateCache = this.updateCache.items; + objects = this.updateCache.items; for (int i = 0, n = this.updateCache.size; i < n; i++) - ((Update)updateCache[i]).update(this, physics); + ((Update)objects[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 @@ -470,9 +241,9 @@ public class Skeleton { public void updateWorldTransform (Physics physics, BonePose parent) { if (parent == null) throw new IllegalArgumentException("parent cannot be null."); - Object[] resetCache = this.resetCache.items; + Object[] objects = this.resetCache.items; for (int i = 0, n = this.resetCache.size; i < n; i++) - ((Posed)resetCache[i]).resetAppliedPose(); + ((Posed)objects[i]).resetAppliedPose(); // Apply the parent bone transform to the root bone. The root bone always inherits scale, rotation and reflection. BonePose rootBone = getRootBone().applied; @@ -492,9 +263,9 @@ public class Skeleton { rootBone.d = (pc * lb + pd * ld) * scaleY; // Update everything except root bone. - Object[] updateCache = this.updateCache.items; + objects = this.updateCache.items; for (int i = 0, n = this.updateCache.size; i < n; i++) { - var updatable = (Update)updateCache[i]; + var updatable = (Update)objects[i]; if (updatable != rootBone) updatable.update(this, physics); } } @@ -507,29 +278,13 @@ public class Skeleton { /** Sets the bones and constraints to their setup pose values. */ public void setupPoseBones () { - Object[] bones = this.bones.items; + Object[] objects = this.bones.items; for (int i = 0, n = this.bones.size; i < n; i++) - ((Bone)bones[i]).setupPose(); + ((Bone)objects[i]).setupPose(); - Object[] constraints = sliders.items; - for (int i = 0, n = sliders.size; i < n; i++) - ((Slider)constraints[i]).setupPose(); - - constraints = ikConstraints.items; - for (int i = 0, n = ikConstraints.size; i < n; i++) - ((IkConstraint)constraints[i]).setupPose(); - - constraints = transformConstraints.items; - for (int i = 0, n = transformConstraints.size; i < n; i++) - ((TransformConstraint)constraints[i]).setupPose(); - - constraints = pathConstraints.items; - for (int i = 0, n = pathConstraints.size; i < n; i++) - ((PathConstraint)constraints[i]).setupPose(); - - constraints = physicsConstraints.items; - for (int i = 0, n = physicsConstraints.size; i < n; i++) - ((PhysicsConstraint)constraints[i]).setupPose(); + objects = constraints.items; + for (int i = 0, n = constraints.size; i < n; i++) + ((Constraint)objects[i]).setupPose(); } /** Sets the slots and draw order to their setup pose values. */ @@ -684,87 +439,22 @@ public class Skeleton { slot.pose.setAttachment(attachment); } - /** The skeleton's sliders. */ - public Array getSliders () { - return sliders; + /** The skeleton's constraints. */ + public Array getConstraints () { + return constraints; } - /** Finds a slider by comparing each slider's name. It is more efficient to cache the results of this method than to call it - * repeatedly. */ - public @Null Slider findSlider (String constraintName) { - if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Object[] sliders = this.sliders.items; - for (int i = 0, n = this.sliders.size; i < n; i++) { - var slider = (Slider)sliders[i]; - if (slider.data.name.equals(constraintName)) return slider; - } - return null; - } - - /** The skeleton's IK constraints. */ - public Array getIkConstraints () { - return ikConstraints; - } - - /** Finds an IK constraint by comparing each IK constraint's name. It is more efficient to cache the results of this method - * than to call it repeatedly. */ - public @Null IkConstraint findIkConstraint (String constraintName) { - if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Object[] ikConstraints = this.ikConstraints.items; - for (int i = 0, n = this.ikConstraints.size; i < n; i++) { - var ikConstraint = (IkConstraint)ikConstraints[i]; - if (ikConstraint.data.name.equals(constraintName)) return ikConstraint; - } - return null; - } - - /** The skeleton's transform constraints. */ - public Array getTransformConstraints () { - return transformConstraints; - } - - /** Finds a transform constraint by comparing each transform constraint's name. It is more efficient to cache the results of - * this method than to call it repeatedly. */ - public @Null TransformConstraint findTransformConstraint (String constraintName) { - if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Object[] transformConstraints = this.transformConstraints.items; - for (int i = 0, n = this.transformConstraints.size; i < n; i++) { - var constraint = (TransformConstraint)transformConstraints[i]; - if (constraint.data.name.equals(constraintName)) return constraint; - } - return null; - } - - /** The skeleton's path constraints. */ - public Array getPathConstraints () { - return pathConstraints; - } - - /** Finds a path constraint by comparing each path constraint's name. It is more efficient to cache the results of this method - * than to call it repeatedly. */ - public @Null PathConstraint findPathConstraint (String constraintName) { - if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Object[] pathConstraints = this.pathConstraints.items; - for (int i = 0, n = this.pathConstraints.size; i < n; i++) { - var constraint = (PathConstraint)pathConstraints[i]; - if (constraint.data.name.equals(constraintName)) return constraint; - } - return null; - } - - /** The skeleton's physics constraints. */ public Array getPhysicsConstraints () { - return physicsConstraints; + return physics; } - /** Finds a physics constraint by comparing each physics constraint's name. It is more efficient to cache the results of this - * method than to call it repeatedly. */ - public @Null PhysicsConstraint findPhysicsConstraint (String constraintName) { + public @Null T findConstraint (String constraintName, Class type) { if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Object[] physicsConstraints = this.physicsConstraints.items; - for (int i = 0, n = this.physicsConstraints.size; i < n; i++) { - var constraint = (PhysicsConstraint)physicsConstraints[i]; - if (constraint.data.name.equals(constraintName)) return constraint; + if (type == null) throw new IllegalArgumentException("type cannot be null."); + Object[] 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; } return null; } @@ -796,31 +486,33 @@ public class Skeleton { float[] vertices = null; short[] triangles = null; Attachment attachment = slot.pose.attachment; - if (attachment instanceof RegionAttachment region) { - verticesLength = 8; - vertices = temp.setSize(8); - region.computeWorldVertices(slot, vertices, 0, 2); - triangles = quadTriangles; - } else if (attachment instanceof MeshAttachment mesh) { - verticesLength = mesh.getWorldVerticesLength(); - vertices = temp.setSize(verticesLength); - mesh.computeWorldVertices(this, slot, 0, verticesLength, vertices, 0, 2); - triangles = mesh.getTriangles(); - } else if (attachment instanceof ClippingAttachment clip && clipper != null) { - clipper.clipStart(this, slot, clip); - continue; - } - if (vertices != null) { - if (clipper != null && clipper.isClipping() && clipper.clipTriangles(vertices, triangles, triangles.length)) { - vertices = clipper.getClippedVertices().items; - verticesLength = clipper.getClippedVertices().size; + if (attachment != null) { + if (attachment instanceof RegionAttachment region) { + verticesLength = 8; + vertices = temp.setSize(8); + region.computeWorldVertices(slot, vertices, 0, 2); + triangles = quadTriangles; + } else if (attachment instanceof MeshAttachment mesh) { + verticesLength = mesh.getWorldVerticesLength(); + vertices = temp.setSize(verticesLength); + mesh.computeWorldVertices(this, slot, 0, verticesLength, vertices, 0, 2); + triangles = mesh.getTriangles(); + } else if (attachment instanceof ClippingAttachment clip && clipper != null) { + clipper.clipStart(this, slot, clip); + continue; } - for (int ii = 0; ii < verticesLength; ii += 2) { - float x = vertices[ii], y = vertices[ii + 1]; - minX = Math.min(minX, x); - minY = Math.min(minY, y); - maxX = Math.max(maxX, x); - maxY = Math.max(maxY, y); + if (vertices != null) { + if (clipper != null && clipper.isClipping() && clipper.clipTriangles(vertices, triangles, triangles.length)) { + vertices = clipper.getClippedVertices().items; + verticesLength = clipper.getClippedVertices().size; + } + for (int ii = 0; ii < verticesLength; ii += 2) { + float x = vertices[ii], y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } } } if (clipper != null) clipper.clipEnd(slot); @@ -908,15 +600,15 @@ public class Skeleton { /** Calls {@link PhysicsConstraint#translate(float, float)} for each physics constraint. */ public void physicsTranslate (float x, float y) { - Object[] physicsConstraints = this.physicsConstraints.items; - for (int i = 0, n = this.physicsConstraints.size; i < n; i++) + Object[] physicsConstraints = this.physics.items; + for (int i = 0, n = this.physics.size; i < n; i++) ((PhysicsConstraint)physicsConstraints[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.physicsConstraints.items; - for (int i = 0, n = this.physicsConstraints.size; i < n; i++) + Object[] physicsConstraints = this.physics.items; + for (int i = 0, n = this.physics.size; i < n; i++) ((PhysicsConstraint)physicsConstraints[i]).rotate(x, y, degrees); } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java index 635041d3a..c628fadd5 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java @@ -137,6 +137,11 @@ public class SkeletonBinary extends SkeletonLoader { static public final int SLOT_RGB2 = 4; static public final int SLOT_ALPHA = 5; + static public final int CONSTRAINT_IK = 0; + static public final int CONSTRAINT_PATH = 1; + static public final int CONSTRAINT_TRANSFORM = 2; + static public final int CONSTRAINT_PHYSICS = 3; + static public final int ATTACHMENT_DEFORM = 0; static public final int ATTACHMENT_SEQUENCE = 1; @@ -253,164 +258,155 @@ public class SkeletonBinary extends SkeletonLoader { slots[i] = data; } - // IK constraints. - o = skeletonData.ikConstraints.setSize(n = input.readInt(true)); + // Constraints. + o = skeletonData.constraints.setSize(n = input.readInt(true)); for (int i = 0, nn; i < n; i++) { - var data = new IkConstraintData(input.readString()); - data.order = input.readInt(true); - Object[] 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)]; - int flags = input.read(); - data.skinRequired = (flags & 1) != 0; - data.uniform = (flags & 2) != 0; - IkConstraintPose setup = data.setup; - setup.bendDirection = (flags & 4) != 0 ? 1 : -1; - setup.compress = (flags & 8) != 0; - setup.stretch = (flags & 16) != 0; - if ((flags & 32) != 0) setup.mix = (flags & 64) != 0 ? input.readFloat() : 1; - if ((flags & 128) != 0) setup.softness = input.readFloat() * scale; - o[i] = data; - } - - // Transform constraints. - o = skeletonData.transformConstraints.setSize(n = input.readInt(true)); - for (int i = 0, nn; i < n; i++) { - var data = new TransformConstraintData(input.readString()); - data.order = input.readInt(true); - Object[] 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)]; - 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); - for (int ii = 0, tn; ii < nn; ii++) { - float fromScale = 1; - FromProperty from; - switch (input.readByte()) { - case 0 -> from = new FromRotate(); - case 1 -> { - from = new FromX(); - fromScale = scale; - } - case 2 -> { - from = new FromY(); - fromScale = scale; - } - case 3 -> from = new FromScaleX(); - case 4 -> from = new FromScaleY(); - case 5 -> from = new FromShearY(); - default -> from = null; - } - from.offset = input.readFloat() * fromScale; - Object[] tos = from.to.setSize(tn = input.readByte()); - for (int t = 0; t < tn; t++) { - float toScale = 1; - ToProperty to; + switch (input.readByte()) { + case CONSTRAINT_IK -> { + var data = new IkConstraintData(input.readString()); + Object[] 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)]; + int flags = input.read(); + data.skinRequired = (flags & 1) != 0; + data.uniform = (flags & 2) != 0; + IkConstraintPose setup = data.setup; + setup.bendDirection = (flags & 4) != 0 ? 1 : -1; + setup.compress = (flags & 8) != 0; + setup.stretch = (flags & 16) != 0; + if ((flags & 32) != 0) setup.mix = (flags & 64) != 0 ? input.readFloat() : 1; + if ((flags & 128) != 0) setup.softness = input.readFloat() * scale; + o[i] = data; + } + case CONSTRAINT_TRANSFORM -> { + var data = new TransformConstraintData(input.readString()); + Object[] 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)]; + 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); + for (int ii = 0, tn; ii < nn; ii++) { + float fromScale = 1; + FromProperty from; switch (input.readByte()) { - case 0 -> to = new ToRotate(); + case 0 -> from = new FromRotate(); case 1 -> { - to = new ToX(); - toScale = scale; + from = new FromX(); + fromScale = scale; } case 2 -> { - to = new ToY(); - toScale = scale; + from = new FromY(); + fromScale = scale; } - case 3 -> to = new ToScaleX(); - case 4 -> to = new ToScaleY(); - case 5 -> to = new ToShearY(); - default -> to = null; + case 3 -> from = new FromScaleX(); + case 4 -> from = new FromScaleY(); + case 5 -> from = new FromShearY(); + default -> from = null; } - to.offset = input.readFloat() * toScale; - to.max = input.readFloat() * toScale; - to.scale = input.readFloat() * toScale / fromScale; - tos[t] = to; + from.offset = input.readFloat() * fromScale; + Object[] tos = from.to.setSize(tn = input.readByte()); + for (int t = 0; t < tn; t++) { + float toScale = 1; + ToProperty to; + switch (input.readByte()) { + case 0 -> to = new ToRotate(); + case 1 -> { + to = new ToX(); + toScale = scale; + } + case 2 -> { + to = new ToY(); + toScale = scale; + } + case 3 -> to = new ToScaleX(); + case 4 -> to = new ToScaleY(); + case 5 -> to = new ToShearY(); + default -> to = null; + } + to.offset = input.readFloat() * toScale; + to.max = input.readFloat() * toScale; + to.scale = input.readFloat() * toScale / fromScale; + tos[t] = to; + } + froms[ii] = from; } - froms[ii] = from; + flags = input.read(); + if ((flags & 1) != 0) data.offsetRotation = input.readFloat(); + if ((flags & 2) != 0) data.offsetX = input.readFloat() * scale; + if ((flags & 4) != 0) data.offsetY = input.readFloat() * scale; + if ((flags & 8) != 0) data.offsetScaleX = input.readFloat(); + if ((flags & 16) != 0) data.offsetScaleY = input.readFloat(); + if ((flags & 32) != 0) data.offsetShearY = input.readFloat(); + flags = input.read(); + TransformConstraintPose setup = data.setup; + if ((flags & 1) != 0) setup.mixRotate = input.readFloat(); + if ((flags & 2) != 0) setup.mixX = input.readFloat(); + if ((flags & 4) != 0) setup.mixY = input.readFloat(); + if ((flags & 8) != 0) setup.mixScaleX = input.readFloat(); + if ((flags & 16) != 0) setup.mixScaleY = input.readFloat(); + if ((flags & 32) != 0) setup.mixShearY = input.readFloat(); + o[i] = data; + } + case CONSTRAINT_PATH -> { + var data = new PathConstraintData(input.readString()); + Object[] 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)]; + int flags = input.read(); + data.skinRequired = (flags & 1) != 0; + data.positionMode = PositionMode.values[flags & 2]; + data.spacingMode = SpacingMode.values[(flags >> 2) & 3]; + data.rotateMode = RotateMode.values[(flags >> 4) & 3]; + if ((flags & 128) != 0) data.offsetRotation = input.readFloat(); + PathConstraintPose setup = data.setup; + setup.position = input.readFloat(); + if (data.positionMode == PositionMode.fixed) setup.position *= scale; + setup.spacing = input.readFloat(); + if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) setup.spacing *= scale; + setup.mixRotate = input.readFloat(); + setup.mixX = input.readFloat(); + setup.mixY = input.readFloat(); + o[i] = data; + } + case CONSTRAINT_PHYSICS -> { + var data = new PhysicsConstraintData(input.readString()); + data.bone = (BoneData)bones[input.readInt(true)]; + int flags = input.read(); + data.skinRequired = (flags & 1) != 0; + if ((flags & 2) != 0) data.x = input.readFloat(); + if ((flags & 4) != 0) data.y = input.readFloat(); + if ((flags & 8) != 0) data.rotate = input.readFloat(); + if ((flags & 16) != 0) data.scaleX = input.readFloat(); + if ((flags & 32) != 0) data.shearX = input.readFloat(); + data.limit = ((flags & 64) != 0 ? input.readFloat() : 5000) * scale; + data.step = 1f / input.readUnsignedByte(); + PhysicsConstraintPose setup = data.setup; + setup.inertia = input.readFloat(); + setup.strength = input.readFloat(); + setup.damping = input.readFloat(); + setup.massInverse = (flags & 128) != 0 ? input.readFloat() : 1; + setup.wind = input.readFloat(); + setup.gravity = input.readFloat(); + flags = input.read(); + if ((flags & 1) != 0) data.inertiaGlobal = true; + if ((flags & 2) != 0) data.strengthGlobal = true; + if ((flags & 4) != 0) data.dampingGlobal = true; + if ((flags & 8) != 0) data.massGlobal = true; + if ((flags & 16) != 0) data.windGlobal = true; + if ((flags & 32) != 0) data.gravityGlobal = true; + if ((flags & 64) != 0) data.mixGlobal = true; + setup.mix = (flags & 128) != 0 ? input.readFloat() : 1; + o[i] = data; + } } - flags = input.read(); - if ((flags & 1) != 0) data.offsetRotation = input.readFloat(); - if ((flags & 2) != 0) data.offsetX = input.readFloat() * scale; - if ((flags & 4) != 0) data.offsetY = input.readFloat() * scale; - if ((flags & 8) != 0) data.offsetScaleX = input.readFloat(); - if ((flags & 16) != 0) data.offsetScaleY = input.readFloat(); - if ((flags & 32) != 0) data.offsetShearY = input.readFloat(); - flags = input.read(); - TransformConstraintPose setup = data.setup; - if ((flags & 1) != 0) setup.mixRotate = input.readFloat(); - if ((flags & 2) != 0) setup.mixX = input.readFloat(); - if ((flags & 4) != 0) setup.mixY = input.readFloat(); - if ((flags & 8) != 0) setup.mixScaleX = input.readFloat(); - if ((flags & 16) != 0) setup.mixScaleY = input.readFloat(); - if ((flags & 32) != 0) setup.mixShearY = input.readFloat(); - o[i] = data; - } - - // Path constraints. - o = skeletonData.pathConstraints.setSize(n = input.readInt(true)); - for (int i = 0, nn; i < n; i++) { - var data = new PathConstraintData(input.readString()); - data.order = input.readInt(true); - data.skinRequired = input.readBoolean(); - Object[] 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)]; - int flags = input.read(); - data.positionMode = PositionMode.values[flags & 1]; - data.spacingMode = SpacingMode.values[(flags >> 1) & 3]; - data.rotateMode = RotateMode.values[(flags >> 3) & 3]; - if ((flags & 128) != 0) data.offsetRotation = input.readFloat(); - PathConstraintPose setup = data.setup; - setup.position = input.readFloat(); - if (data.positionMode == PositionMode.fixed) setup.position *= scale; - setup.spacing = input.readFloat(); - if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) setup.spacing *= scale; - setup.mixRotate = input.readFloat(); - setup.mixX = input.readFloat(); - setup.mixY = input.readFloat(); - o[i] = data; - } - - // Physics constraints. - o = skeletonData.physicsConstraints.setSize(n = input.readInt(true)); - for (int i = 0; i < n; i++) { - var data = new PhysicsConstraintData(input.readString()); - data.order = input.readInt(true); - data.bone = (BoneData)bones[input.readInt(true)]; - int flags = input.read(); - data.skinRequired = (flags & 1) != 0; - if ((flags & 2) != 0) data.x = input.readFloat(); - if ((flags & 4) != 0) data.y = input.readFloat(); - if ((flags & 8) != 0) data.rotate = input.readFloat(); - if ((flags & 16) != 0) data.scaleX = input.readFloat(); - if ((flags & 32) != 0) data.shearX = input.readFloat(); - data.limit = ((flags & 64) != 0 ? input.readFloat() : 5000) * scale; - data.step = 1f / input.readUnsignedByte(); - PhysicsConstraintPose setup = data.setup; - setup.inertia = input.readFloat(); - setup.strength = input.readFloat(); - setup.damping = input.readFloat(); - setup.massInverse = (flags & 128) != 0 ? input.readFloat() : 1; - setup.wind = input.readFloat(); - setup.gravity = input.readFloat(); - flags = input.read(); - if ((flags & 1) != 0) data.inertiaGlobal = true; - if ((flags & 2) != 0) data.strengthGlobal = true; - if ((flags & 4) != 0) data.dampingGlobal = true; - if ((flags & 8) != 0) data.massGlobal = true; - if ((flags & 16) != 0) data.windGlobal = true; - if ((flags & 32) != 0) data.gravityGlobal = true; - if ((flags & 64) != 0) data.mixGlobal = true; - setup.mix = (flags & 128) != 0 ? input.readFloat() : 1; - o[i] = data; } // Default skin. @@ -487,23 +483,15 @@ public class SkeletonBinary extends SkeletonLoader { if (nonessential) Color.rgba8888ToColor(skin.color, input.readInt()); - Object[] bones = skin.bones.setSize(input.readInt(true)), items = skeletonData.bones.items; - for (int i = 0, n = skin.bones.size; i < n; i++) - bones[i] = items[input.readInt(true)]; + int n; + Object[] from = skeletonData.bones.items, to = skin.bones.setSize(n = input.readInt(true)); + for (int i = 0; i < n; i++) + to[i] = from[input.readInt(true)]; - items = skeletonData.ikConstraints.items; - for (int i = 0, n = input.readInt(true); i < n; i++) - skin.constraints.add((PosedData)items[input.readInt(true)]); - items = skeletonData.transformConstraints.items; - for (int i = 0, n = input.readInt(true); i < n; i++) - skin.constraints.add((PosedData)items[input.readInt(true)]); - items = skeletonData.pathConstraints.items; - for (int i = 0, n = input.readInt(true); i < n; i++) - skin.constraints.add((PosedData)items[input.readInt(true)]); - items = skeletonData.physicsConstraints.items; - for (int i = 0, n = input.readInt(true); i < n; i++) - skin.constraints.add((PosedData)items[input.readInt(true)]); - skin.constraints.shrink(); + from = skeletonData.constraints.items; + to = skin.constraints.setSize(n = input.readInt(true)); + for (int i = 0; i < n; i++) + to[i] = from[input.readInt(true)]; slotCount = input.readInt(true); } @@ -981,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); - PathConstraintData data = skeletonData.pathConstraints.get(index); + var data = (PathConstraintData)skeletonData.constraints.get(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) { @@ -1158,7 +1146,7 @@ public class SkeletonBinary extends SkeletonLoader { event.floatValue = input.readFloat(); event.stringValue = input.readString(); if (event.stringValue == null) event.stringValue = eventData.stringValue; - if (event.getData().audioPath != null) { + if (event.data.audioPath != null) { event.volume = input.readFloat(); event.balance = input.readFloat(); } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java index 21acc90ec..396a7de23 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonData.java @@ -44,11 +44,7 @@ public class SkeletonData { @Null Skin defaultSkin; final Array events = new Array(); final Array animations = new Array(); - final Array sliders = new Array(); - final Array ikConstraints = new Array(); - final Array transformConstraints = new Array(); - final Array pathConstraints = new Array(); - final Array physicsConstraints = new Array(); + final Array constraints = new Array(); float x, y, width, height, referenceScale = 100; @Null String version, hash; @@ -160,97 +156,20 @@ public class SkeletonData { return null; } - // --- Sliders + // --- Constraints. - /** The skeleton's sliders. */ - public Array getSliders () { - return sliders; + /** The skeleton's constraints. */ + public Array getConstraints () { + return constraints; } - /** Finds a slider by comparing each IK constraint's name. It is more efficient to cache the results of this method than to - * call it multiple times. */ - public @Null SliderData findSlider (String constraintName) { + public @Null T findConstraint (String constraintName, Class type) { if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Object[] sliders = this.sliders.items; - for (int i = 0, n = this.sliders.size; i < n; i++) { - var constraint = (SliderData)sliders[i]; - if (constraint.name.equals(constraintName)) return constraint; - } - return null; - } - - // --- IK constraints - - /** The skeleton's IK constraints. */ - public Array getIkConstraints () { - return ikConstraints; - } - - /** Finds an IK constraint by comparing each IK constraint's name. It is more efficient to cache the results of this method - * than to call it multiple times. */ - public @Null IkConstraintData findIkConstraint (String constraintName) { - if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Object[] ikConstraints = this.ikConstraints.items; - for (int i = 0, n = this.ikConstraints.size; i < n; i++) { - var constraint = (IkConstraintData)ikConstraints[i]; - if (constraint.name.equals(constraintName)) return constraint; - } - return null; - } - - // --- Transform constraints - - /** The skeleton's transform constraints. */ - public Array getTransformConstraints () { - return transformConstraints; - } - - /** Finds a transform constraint by comparing each transform constraint's name. It is more efficient to cache the results of - * this method than to call it multiple times. */ - public @Null TransformConstraintData findTransformConstraint (String constraintName) { - if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Object[] transformConstraints = this.transformConstraints.items; - for (int i = 0, n = this.transformConstraints.size; i < n; i++) { - var constraint = (TransformConstraintData)transformConstraints[i]; - if (constraint.name.equals(constraintName)) return constraint; - } - return null; - } - - // --- Path constraints - - /** The skeleton's path constraints. */ - public Array getPathConstraints () { - return pathConstraints; - } - - /** Finds a path constraint by comparing each path constraint's name. It is more efficient to cache the results of this method - * than to call it multiple times. */ - public @Null PathConstraintData findPathConstraint (String constraintName) { - if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Object[] pathConstraints = this.pathConstraints.items; - for (int i = 0, n = this.pathConstraints.size; i < n; i++) { - var constraint = (PathConstraintData)pathConstraints[i]; - if (constraint.name.equals(constraintName)) return constraint; - } - return null; - } - - // --- Physics constraints - - /** The skeleton's physics constraints. */ - public Array getPhysicsConstraints () { - return physicsConstraints; - } - - /** Finds a physics constraint by comparing each physics constraint's name. It is more efficient to cache the results of this - * method than to call it multiple times. */ - public @Null PhysicsConstraintData findPhysicsConstraint (String constraintName) { - if (constraintName == null) throw new IllegalArgumentException("constraintName cannot be null."); - Object[] physicsConstraints = this.physicsConstraints.items; - for (int i = 0, n = this.physicsConstraints.size; i < n; i++) { - var constraint = (PhysicsConstraintData)physicsConstraints[i]; - if (constraint.name.equals(constraintName)) return constraint; + if (type == null) throw new IllegalArgumentException("type cannot be null."); + Object[] 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; } return null; } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java index eb0b195a1..81203dc0f 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java @@ -215,198 +215,194 @@ public class SkeletonJson extends SkeletonLoader { skeletonData.slots.add(data); } - // IK constraints. - for (JsonValue constraintMap = root.getChild("ik"); constraintMap != null; constraintMap = constraintMap.next) { - var data = new IkConstraintData(constraintMap.getString("name")); - data.order = constraintMap.getInt("order", 0); - data.skinRequired = constraintMap.getBoolean("skin", false); + // Constraints. + for (JsonValue constraintMap = root.getChild("constraints"); constraintMap != null; constraintMap = constraintMap.next) { + switch (constraintMap.getString("type")) { + case "ik" -> { + var data = new IkConstraintData(constraintMap.getString("name")); + data.skinRequired = constraintMap.getBoolean("skin", false); - for (JsonValue entry = constraintMap.getChild("bones"); entry != null; entry = entry.next) { - BoneData bone = skeletonData.findBone(entry.asString()); - if (bone == null) throw new SerializationException("IK bone not found: " + entry); - data.bones.add(bone); + for (JsonValue entry = constraintMap.getChild("bones"); entry != null; entry = entry.next) { + BoneData bone = skeletonData.findBone(entry.asString()); + if (bone == null) throw new SerializationException("IK bone not found: " + entry); + data.bones.add(bone); + } + + String targetName = constraintMap.getString("target"); + data.target = skeletonData.findBone(targetName); + if (data.target == null) throw new SerializationException("IK target bone not found: " + targetName); + + data.uniform = constraintMap.getBoolean("uniform", false); + IkConstraintPose setup = data.setup; + setup.mix = constraintMap.getFloat("mix", 1); + setup.softness = constraintMap.getFloat("softness", 0) * scale; + setup.bendDirection = constraintMap.getBoolean("bendPositive", true) ? 1 : -1; + setup.compress = constraintMap.getBoolean("compress", false); + setup.stretch = constraintMap.getBoolean("stretch", false); + + skeletonData.constraints.add(data); } + case "transform" -> { + var data = new TransformConstraintData(constraintMap.getString("name")); + data.skinRequired = constraintMap.getBoolean("skin", false); - String targetName = constraintMap.getString("target"); - data.target = skeletonData.findBone(targetName); - if (data.target == null) throw new SerializationException("IK target bone not found: " + targetName); - - data.uniform = constraintMap.getBoolean("uniform", false); - IkConstraintPose setup = data.setup; - setup.mix = constraintMap.getFloat("mix", 1); - setup.softness = constraintMap.getFloat("softness", 0) * scale; - setup.bendDirection = constraintMap.getBoolean("bendPositive", true) ? 1 : -1; - setup.compress = constraintMap.getBoolean("compress", false); - setup.stretch = constraintMap.getBoolean("stretch", false); - - skeletonData.ikConstraints.add(data); - } - - // Transform constraints. - for (JsonValue constraintMap = root.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) { - var data = new TransformConstraintData(constraintMap.getString("name")); - data.order = constraintMap.getInt("order", 0); - data.skinRequired = constraintMap.getBoolean("skin", false); - - for (JsonValue entry = constraintMap.getChild("bones"); entry != null; entry = entry.next) { - BoneData bone = skeletonData.findBone(entry.asString()); - if (bone == null) throw new SerializationException("Transform constraint bone not found: " + entry); - data.bones.add(bone); - } - - String sourceName = constraintMap.getString("source"); - data.source = skeletonData.findBone(sourceName); - if (data.source == null) throw new SerializationException("Transform constraint source bone not found: " + sourceName); - - data.localSource = constraintMap.getBoolean("localSource", false); - data.localTarget = constraintMap.getBoolean("localTarget", false); - data.additive = constraintMap.getBoolean("additive", false); - data.clamp = constraintMap.getBoolean("clamp", false); - - boolean rotate = false, x = false, y = false, scaleX = false, scaleY = false, shearY = false; - for (JsonValue fromEntry = constraintMap.getChild("properties"); fromEntry != null; fromEntry = fromEntry.next) { - float fromScale = 1; - FromProperty from; - switch (fromEntry.name) { - case "rotate" -> from = new FromRotate(); - case "x" -> { - from = new FromX(); - fromScale = scale; + for (JsonValue entry = constraintMap.getChild("bones"); entry != null; entry = entry.next) { + BoneData bone = skeletonData.findBone(entry.asString()); + if (bone == null) throw new SerializationException("Transform constraint bone not found: " + entry); + data.bones.add(bone); } - case "y" -> { - from = new FromY(); - fromScale = scale; - } - case "scaleX" -> from = new FromScaleX(); - case "scaleY" -> from = new FromScaleY(); - case "shearY" -> from = new FromShearY(); - default -> throw new SerializationException("Invalid transform constraint from property: " + fromEntry.name); - } - from.offset = fromEntry.getFloat("offset", 0) * fromScale; - for (JsonValue toEntry = fromEntry.getChild("to"); toEntry != null; toEntry = toEntry.next) { - float toScale = 1; - ToProperty to; - switch (toEntry.name) { - case "rotate" -> { - rotate = true; - to = new ToRotate(); - } + + String sourceName = constraintMap.getString("source"); + data.source = skeletonData.findBone(sourceName); + if (data.source == null) + throw new SerializationException("Transform constraint source bone not found: " + sourceName); + + data.localSource = constraintMap.getBoolean("localSource", false); + data.localTarget = constraintMap.getBoolean("localTarget", false); + data.additive = constraintMap.getBoolean("additive", false); + data.clamp = constraintMap.getBoolean("clamp", false); + + boolean rotate = false, x = false, y = false, scaleX = false, scaleY = false, shearY = false; + for (JsonValue fromEntry = constraintMap.getChild("properties"); fromEntry != null; fromEntry = fromEntry.next) { + float fromScale = 1; + FromProperty from; + switch (fromEntry.name) { + case "rotate" -> from = new FromRotate(); case "x" -> { - x = true; - to = new ToX(); - toScale = scale; + from = new FromX(); + fromScale = scale; } case "y" -> { - y = true; - to = new ToY(); - toScale = scale; + from = new FromY(); + fromScale = scale; } - case "scaleX" -> { - scaleX = true; - to = new ToScaleX(); + case "scaleX" -> from = new FromScaleX(); + case "scaleY" -> from = new FromScaleY(); + case "shearY" -> from = new FromShearY(); + default -> throw new SerializationException("Invalid transform constraint from property: " + fromEntry.name); } - case "scaleY" -> { - scaleY = true; - to = new ToScaleY(); + from.offset = fromEntry.getFloat("offset", 0) * fromScale; + for (JsonValue toEntry = fromEntry.getChild("to"); toEntry != null; toEntry = toEntry.next) { + float toScale = 1; + ToProperty to; + switch (toEntry.name) { + case "rotate" -> { + rotate = true; + to = new ToRotate(); + } + case "x" -> { + x = true; + to = new ToX(); + toScale = scale; + } + case "y" -> { + y = true; + to = new ToY(); + toScale = scale; + } + case "scaleX" -> { + scaleX = true; + to = new ToScaleX(); + } + case "scaleY" -> { + scaleY = true; + to = new ToScaleY(); + } + case "shearY" -> { + shearY = true; + to = new ToShearY(); + } + default -> throw new SerializationException("Invalid transform constraint to property: " + toEntry.name); + } + to.offset = toEntry.getFloat("offset", 0) * toScale; + to.max = toEntry.getFloat("max", 1) * toScale; + to.scale = toEntry.getFloat("scale") * toScale / fromScale; + from.to.add(to); } - case "shearY" -> { - shearY = true; - to = new ToShearY(); - } - default -> throw new SerializationException("Invalid transform constraint to property: " + toEntry.name); - } - to.offset = toEntry.getFloat("offset", 0) * toScale; - to.max = toEntry.getFloat("max", 1) * toScale; - to.scale = toEntry.getFloat("scale") * toScale / fromScale; - from.to.add(to); + if (from.to.notEmpty()) data.properties.add(from); } - if (from.to.notEmpty()) data.properties.add(from); + + data.offsetRotation = constraintMap.getFloat("rotation", 0); + data.offsetX = constraintMap.getFloat("x", 0) * scale; + data.offsetY = constraintMap.getFloat("y", 0) * scale; + data.offsetScaleX = constraintMap.getFloat("scaleX", 0); + data.offsetScaleY = constraintMap.getFloat("scaleY", 0); + data.offsetShearY = constraintMap.getFloat("shearY", 0); + + TransformConstraintPose setup = data.setup; + if (rotate) setup.mixRotate = constraintMap.getFloat("mixRotate", 1); + if (x) setup.mixX = constraintMap.getFloat("mixX", 1); + if (y) setup.mixY = constraintMap.getFloat("mixY", setup.mixX); + if (scaleX) setup.mixScaleX = constraintMap.getFloat("mixScaleX", 1); + if (scaleY) setup.mixScaleY = constraintMap.getFloat("mixScaleY", setup.mixScaleX); + if (shearY) setup.mixShearY = constraintMap.getFloat("mixShearY", 1); + + skeletonData.constraints.add(data); } + case "path" -> { + var data = new PathConstraintData(constraintMap.getString("name")); + data.skinRequired = constraintMap.getBoolean("skin", false); - data.offsetRotation = constraintMap.getFloat("rotation", 0); - data.offsetX = constraintMap.getFloat("x", 0) * scale; - data.offsetY = constraintMap.getFloat("y", 0) * scale; - data.offsetScaleX = constraintMap.getFloat("scaleX", 0); - data.offsetScaleY = constraintMap.getFloat("scaleY", 0); - data.offsetShearY = constraintMap.getFloat("shearY", 0); + for (JsonValue entry = constraintMap.getChild("bones"); entry != null; entry = entry.next) { + BoneData bone = skeletonData.findBone(entry.asString()); + if (bone == null) throw new SerializationException("Path bone not found: " + entry); + data.bones.add(bone); + } - TransformConstraintPose setup = data.setup; - if (rotate) setup.mixRotate = constraintMap.getFloat("mixRotate", 1); - if (x) setup.mixX = constraintMap.getFloat("mixX", 1); - if (y) setup.mixY = constraintMap.getFloat("mixY", setup.mixX); - if (scaleX) setup.mixScaleX = constraintMap.getFloat("mixScaleX", 1); - if (scaleY) setup.mixScaleY = constraintMap.getFloat("mixScaleY", setup.mixScaleX); - if (shearY) setup.mixShearY = constraintMap.getFloat("mixShearY", 1); + String slotName = constraintMap.getString("slot"); + data.slot = skeletonData.findSlot(slotName); + if (data.slot == null) throw new SerializationException("Path slot not found: " + slotName); - skeletonData.transformConstraints.add(data); - } + data.positionMode = PositionMode.valueOf(constraintMap.getString("positionMode", "percent")); + data.spacingMode = SpacingMode.valueOf(constraintMap.getString("spacingMode", "length")); + data.rotateMode = RotateMode.valueOf(constraintMap.getString("rotateMode", "tangent")); + data.offsetRotation = constraintMap.getFloat("rotation", 0); + PathConstraintPose setup = data.setup; + setup.position = constraintMap.getFloat("position", 0); + if (data.positionMode == PositionMode.fixed) setup.position *= scale; + setup.spacing = constraintMap.getFloat("spacing", 0); + if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) setup.spacing *= scale; + setup.mixRotate = constraintMap.getFloat("mixRotate", 1); + setup.mixX = constraintMap.getFloat("mixX", 1); + setup.mixY = constraintMap.getFloat("mixY", 1); - // Path constraints. - for (JsonValue constraintMap = root.getChild("path"); constraintMap != null; constraintMap = constraintMap.next) { - var data = new PathConstraintData(constraintMap.getString("name")); - data.order = constraintMap.getInt("order", 0); - data.skinRequired = constraintMap.getBoolean("skin", false); - - for (JsonValue entry = constraintMap.getChild("bones"); entry != null; entry = entry.next) { - BoneData bone = skeletonData.findBone(entry.asString()); - if (bone == null) throw new SerializationException("Path bone not found: " + entry); - data.bones.add(bone); + skeletonData.constraints.add(data); } + case "physics" -> { + var data = new PhysicsConstraintData(constraintMap.getString("name")); + data.skinRequired = constraintMap.getBoolean("skin", false); - String slotName = constraintMap.getString("slot"); - data.slot = skeletonData.findSlot(slotName); - if (data.slot == null) throw new SerializationException("Path slot not found: " + slotName); + String boneName = constraintMap.getString("bone"); + data.bone = skeletonData.findBone(boneName); + if (data.bone == null) throw new SerializationException("Physics bone not found: " + boneName); - data.positionMode = PositionMode.valueOf(constraintMap.getString("positionMode", "percent")); - data.spacingMode = SpacingMode.valueOf(constraintMap.getString("spacingMode", "length")); - data.rotateMode = RotateMode.valueOf(constraintMap.getString("rotateMode", "tangent")); - data.offsetRotation = constraintMap.getFloat("rotation", 0); - PathConstraintPose setup = data.setup; - setup.position = constraintMap.getFloat("position", 0); - if (data.positionMode == PositionMode.fixed) setup.position *= scale; - setup.spacing = constraintMap.getFloat("spacing", 0); - if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) setup.spacing *= scale; - setup.mixRotate = constraintMap.getFloat("mixRotate", 1); - setup.mixX = constraintMap.getFloat("mixX", 1); - setup.mixY = constraintMap.getFloat("mixY", 1); + data.x = constraintMap.getFloat("x", 0); + data.y = constraintMap.getFloat("y", 0); + data.rotate = constraintMap.getFloat("rotate", 0); + data.scaleX = constraintMap.getFloat("scaleX", 0); + data.shearX = constraintMap.getFloat("shearX", 0); + data.limit = constraintMap.getFloat("limit", 5000) * scale; + data.step = 1f / constraintMap.getInt("fps", 60); + PhysicsConstraintPose setup = data.setup; + setup.inertia = constraintMap.getFloat("inertia", 1); + setup.strength = constraintMap.getFloat("strength", 100); + setup.damping = constraintMap.getFloat("damping", 1); + setup.massInverse = 1 / constraintMap.getFloat("mass", 1); + setup.wind = constraintMap.getFloat("wind", 0); + setup.gravity = constraintMap.getFloat("gravity", 0); + setup.mix = constraintMap.getFloat("mix", 1); + data.inertiaGlobal = constraintMap.getBoolean("inertiaGlobal", false); + data.strengthGlobal = constraintMap.getBoolean("strengthGlobal", false); + data.dampingGlobal = constraintMap.getBoolean("dampingGlobal", false); + data.massGlobal = constraintMap.getBoolean("massGlobal", false); + data.windGlobal = constraintMap.getBoolean("windGlobal", false); + data.gravityGlobal = constraintMap.getBoolean("gravityGlobal", false); + data.mixGlobal = constraintMap.getBoolean("mixGlobal", false); - skeletonData.pathConstraints.add(data); - } - - // Physics constraints. - for (JsonValue constraintMap = root.getChild("physics"); constraintMap != null; constraintMap = constraintMap.next) { - var data = new PhysicsConstraintData(constraintMap.getString("name")); - data.order = constraintMap.getInt("order", 0); - data.skinRequired = constraintMap.getBoolean("skin", false); - - String boneName = constraintMap.getString("bone"); - data.bone = skeletonData.findBone(boneName); - if (data.bone == null) throw new SerializationException("Physics bone not found: " + boneName); - - data.x = constraintMap.getFloat("x", 0); - data.y = constraintMap.getFloat("y", 0); - data.rotate = constraintMap.getFloat("rotate", 0); - data.scaleX = constraintMap.getFloat("scaleX", 0); - data.shearX = constraintMap.getFloat("shearX", 0); - data.limit = constraintMap.getFloat("limit", 5000) * scale; - data.step = 1f / constraintMap.getInt("fps", 60); - PhysicsConstraintPose setup = data.setup; - setup.inertia = constraintMap.getFloat("inertia", 1); - setup.strength = constraintMap.getFloat("strength", 100); - setup.damping = constraintMap.getFloat("damping", 1); - setup.massInverse = 1 / constraintMap.getFloat("mass", 1); - setup.wind = constraintMap.getFloat("wind", 0); - setup.gravity = constraintMap.getFloat("gravity", 0); - setup.mix = constraintMap.getFloat("mix", 1); - data.inertiaGlobal = constraintMap.getBoolean("inertiaGlobal", false); - data.strengthGlobal = constraintMap.getBoolean("strengthGlobal", false); - data.dampingGlobal = constraintMap.getBoolean("dampingGlobal", false); - data.massGlobal = constraintMap.getBoolean("massGlobal", false); - data.windGlobal = constraintMap.getBoolean("windGlobal", false); - data.gravityGlobal = constraintMap.getBoolean("gravityGlobal", false); - data.mixGlobal = constraintMap.getBoolean("mixGlobal", false); - - skeletonData.physicsConstraints.add(data); + skeletonData.constraints.add(data); + } + // BOZO! - Sliders. + } } // Skins. @@ -419,22 +415,22 @@ public class SkeletonJson extends SkeletonLoader { } skin.bones.shrink(); for (JsonValue entry = skinMap.getChild("ik"); entry != null; entry = entry.next) { - IkConstraintData constraint = skeletonData.findIkConstraint(entry.asString()); + IkConstraintData constraint = skeletonData.findConstraint(entry.asString(), IkConstraintData.class); if (constraint == null) throw new SerializationException("Skin IK constraint not found: " + entry); skin.constraints.add(constraint); } for (JsonValue entry = skinMap.getChild("transform"); entry != null; entry = entry.next) { - TransformConstraintData constraint = skeletonData.findTransformConstraint(entry.asString()); + TransformConstraintData constraint = skeletonData.findConstraint(entry.asString(), TransformConstraintData.class); if (constraint == null) throw new SerializationException("Skin transform constraint not found: " + entry); skin.constraints.add(constraint); } for (JsonValue entry = skinMap.getChild("path"); entry != null; entry = entry.next) { - PathConstraintData constraint = skeletonData.findPathConstraint(entry.asString()); + PathConstraintData constraint = skeletonData.findConstraint(entry.asString(), PathConstraintData.class); if (constraint == null) throw new SerializationException("Skin path constraint not found: " + entry); skin.constraints.add(constraint); } for (JsonValue entry = skinMap.getChild("physics"); entry != null; entry = entry.next) { - PhysicsConstraintData constraint = skeletonData.findPhysicsConstraint(entry.asString()); + PhysicsConstraintData constraint = skeletonData.findConstraint(entry.asString(), PhysicsConstraintData.class); if (constraint == null) throw new SerializationException("Skin physics constraint not found: " + entry); skin.constraints.add(constraint); } @@ -463,7 +459,7 @@ public class SkeletonJson extends SkeletonLoader { Object[] items = linkedMeshes.items; for (int i = 0, n = linkedMeshes.size; i < n; i++) { var linkedMesh = (LinkedMesh)items[i]; - Skin skin = linkedMesh.skin == null ? skeletonData.getDefaultSkin() : skeletonData.findSkin(linkedMesh.skin); + 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); if (parent == null) throw new SerializationException("Parent mesh not found: " + linkedMesh.parent); @@ -501,7 +497,7 @@ public class SkeletonJson extends SkeletonLoader { skeletonData.skins.shrink(); skeletonData.events.shrink(); skeletonData.animations.shrink(); - skeletonData.ikConstraints.shrink(); + skeletonData.constraints.shrink(); return skeletonData; } @@ -896,9 +892,9 @@ public class SkeletonJson extends SkeletonLoader { for (JsonValue timelineMap = map.getChild("ik"); timelineMap != null; timelineMap = timelineMap.next) { JsonValue keyMap = timelineMap.child; if (keyMap == null) continue; - IkConstraintData constraint = skeletonData.findIkConstraint(timelineMap.name); + IkConstraintData constraint = skeletonData.findConstraint(timelineMap.name, IkConstraintData.class); var timeline = new IkConstraintTimeline(timelineMap.size, timelineMap.size << 1, - skeletonData.getIkConstraints().indexOf(constraint, true)); + skeletonData.constraints.indexOf(constraint, true)); float time = keyMap.getFloat("time", 0); float mix = keyMap.getFloat("mix", 1), softness = keyMap.getFloat("softness", 0) * scale; for (int frame = 0, bezier = 0;; frame++) { @@ -928,9 +924,9 @@ public class SkeletonJson extends SkeletonLoader { for (JsonValue timelineMap = map.getChild("transform"); timelineMap != null; timelineMap = timelineMap.next) { JsonValue keyMap = timelineMap.child; if (keyMap == null) continue; - TransformConstraintData constraint = skeletonData.findTransformConstraint(timelineMap.name); + TransformConstraintData constraint = skeletonData.findConstraint(timelineMap.name, TransformConstraintData.class); var timeline = new TransformConstraintTimeline(timelineMap.size, timelineMap.size * 6, - skeletonData.getTransformConstraints().indexOf(constraint, true)); + skeletonData.constraints.indexOf(constraint, true)); float time = keyMap.getFloat("time", 0); float mixRotate = keyMap.getFloat("mixRotate", 1); float mixX = keyMap.getFloat("mixX", 1), mixY = keyMap.getFloat("mixY", mixX); @@ -971,9 +967,9 @@ public class SkeletonJson extends SkeletonLoader { // Path constraint timelines. for (JsonValue constraintMap = map.getChild("path"); constraintMap != null; constraintMap = constraintMap.next) { - PathConstraintData constraint = skeletonData.findPathConstraint(constraintMap.name); + PathConstraintData constraint = skeletonData.findConstraint(constraintMap.name, PathConstraintData.class); if (constraint == null) throw new SerializationException("Path constraint not found: " + constraintMap.name); - int index = skeletonData.pathConstraints.indexOf(constraint, true); + int index = skeletonData.constraints.indexOf(constraint, true); for (JsonValue timelineMap = constraintMap.child; timelineMap != null; timelineMap = timelineMap.next) { JsonValue keyMap = timelineMap.child; if (keyMap == null) continue; @@ -1026,9 +1022,9 @@ public class SkeletonJson extends SkeletonLoader { for (JsonValue constraintMap = map.getChild("physics"); constraintMap != null; constraintMap = constraintMap.next) { int index = -1; if (!constraintMap.name.isEmpty()) { - PhysicsConstraintData constraint = skeletonData.findPhysicsConstraint(constraintMap.name); + PhysicsConstraintData constraint = skeletonData.findConstraint(constraintMap.name, PhysicsConstraintData.class); if (constraint == null) throw new SerializationException("Physics constraint not found: " + constraintMap.name); - index = skeletonData.physicsConstraints.indexOf(constraint, true); + index = skeletonData.constraints.indexOf(constraint, true); } for (JsonValue timelineMap = constraintMap.child; timelineMap != null; timelineMap = timelineMap.next) { JsonValue keyMap = timelineMap.child; @@ -1179,7 +1175,7 @@ public class SkeletonJson extends SkeletonLoader { event.intValue = keyMap.getInt("int", eventData.intValue); event.floatValue = keyMap.getFloat("float", eventData.floatValue); event.stringValue = keyMap.getString("string", eventData.stringValue); - if (event.getData().audioPath != null) { + if (event.data.audioPath != null) { event.volume = keyMap.getFloat("volume", eventData.volume); event.balance = keyMap.getFloat("balance", eventData.balance); } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java index a335d2699..9ad09067c 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java @@ -54,7 +54,7 @@ public class SkeletonRenderer { /** Renders the specified skeleton. If the batch is a PolygonSpriteBatch, {@link #draw(PolygonSpriteBatch, Skeleton)} is * called. If the batch is a TwoColorPolygonBatch, {@link #draw(TwoColorPolygonBatch, Skeleton)} is called. Otherwise the - * skeleton is rendered without two color tinting and any mesh attachments will throw an exception. + * skeleton is rendered without two color tinting and any mesh or clipping attachments will throw an exception. *

* This method may change the batch's {@link Batch#setBlendFunctionSeparate(int, int, int, int) blending function}. The * previous blend function is not restored, since that could result in unnecessary flushes, depending on what is rendered @@ -145,76 +145,75 @@ public class SkeletonRenderer { Object[] drawOrder = skeleton.drawOrder.items; for (int i = 0, n = skeleton.drawOrder.size; i < n; i++) { var slot = (Slot)drawOrder[i]; - if (!slot.bone.active) { - clipper.clipEnd(slot); - continue; - } - SlotPose pose = slot.applied; - Texture texture = null; - Attachment attachment = pose.attachment; - if (attachment instanceof RegionAttachment region) { - verticesLength = 20; - vertices = this.vertices.items; - region.computeWorldVertices(slot, vertices, 0, 5); - triangles = quadTriangles; - texture = region.getRegion().getTexture(); - uvs = region.getUVs(); - color = region.getColor(); + if (slot.bone.active) { + SlotPose pose = slot.applied; + Attachment attachment = pose.attachment; + if (attachment != null) { + Texture texture = null; + if (attachment instanceof RegionAttachment region) { + verticesLength = 20; + vertices = this.vertices.items; + region.computeWorldVertices(slot, vertices, 0, 5); + triangles = quadTriangles; + texture = region.getRegion().getTexture(); + uvs = region.getUVs(); + color = region.getColor(); - } else if (attachment instanceof MeshAttachment mesh) { - int count = mesh.getWorldVerticesLength(); - verticesLength = (count >> 1) * 5; - vertices = this.vertices.setSize(verticesLength); - mesh.computeWorldVertices(skeleton, slot, 0, count, vertices, 0, 5); - triangles = mesh.getTriangles(); - texture = mesh.getRegion().getTexture(); - uvs = mesh.getUVs(); - color = mesh.getColor(); + } else if (attachment instanceof MeshAttachment mesh) { + int count = mesh.getWorldVerticesLength(); + verticesLength = (count >> 1) * 5; + vertices = this.vertices.setSize(verticesLength); + mesh.computeWorldVertices(skeleton, slot, 0, count, vertices, 0, 5); + triangles = mesh.getTriangles(); + texture = mesh.getRegion().getTexture(); + uvs = mesh.getUVs(); + color = mesh.getColor(); - } else if (attachment instanceof ClippingAttachment clip) { - clipper.clipStart(skeleton, slot, clip); - continue; + } else if (attachment instanceof ClippingAttachment clip) { + clipper.clipStart(skeleton, slot, clip); + continue; - } else if (attachment instanceof SkeletonAttachment skeletonAttachment) { - Skeleton attachmentSkeleton = skeletonAttachment.getSkeleton(); - if (attachmentSkeleton != null) draw(batch, attachmentSkeleton); - } - - if (texture != null) { - Color slotColor = pose.getColor(); - float alpha = a * slotColor.a * color.a * 255; - float multiplier = pmaColors ? alpha : 255; - - BlendMode slotBlendMode = slot.data.getBlendMode(); - if (slotBlendMode != blendMode) { - if (slotBlendMode == BlendMode.additive && pmaColors) { - slotBlendMode = BlendMode.normal; - alpha = 0; + } else if (attachment instanceof SkeletonAttachment skeletonAttachment) { + Skeleton attachmentSkeleton = skeletonAttachment.getSkeleton(); + if (attachmentSkeleton != null) draw(batch, attachmentSkeleton); } - blendMode = slotBlendMode; - blendMode.apply(batch, pmaBlendModes); - } - float c = NumberUtils.intToFloatColor((int)alpha << 24 // - | (int)(b * slotColor.b * color.b * multiplier) << 16 // - | (int)(g * slotColor.g * color.g * multiplier) << 8 // - | (int)(r * slotColor.r * color.r * multiplier)); + if (texture != null) { + Color slotColor = pose.getColor(); + float alpha = a * slotColor.a * color.a * 255; + float multiplier = pmaColors ? alpha : 255; - if (clipper.isClipping() && clipper.clipTriangles(vertices, triangles, triangles.length, uvs, c, 0, false, 5)) { - FloatArray clippedVertices = clipper.getClippedVertices(); - ShortArray clippedTriangles = clipper.getClippedTriangles(); - batch.draw(texture, clippedVertices.items, 0, clippedVertices.size, clippedTriangles.items, 0, - clippedTriangles.size); - } else { - for (int v = 2, u = 0; v < verticesLength; v += 5, u += 2) { - vertices[v] = c; - vertices[v + 1] = uvs[u]; - vertices[v + 2] = uvs[u + 1]; + BlendMode slotBlendMode = slot.data.getBlendMode(); + if (slotBlendMode != blendMode) { + if (slotBlendMode == BlendMode.additive && pmaColors) { + slotBlendMode = BlendMode.normal; + alpha = 0; + } + blendMode = slotBlendMode; + blendMode.apply(batch, pmaBlendModes); + } + + float c = NumberUtils.intToFloatColor((int)alpha << 24 // + | (int)(b * slotColor.b * color.b * multiplier) << 16 // + | (int)(g * slotColor.g * color.g * multiplier) << 8 // + | (int)(r * slotColor.r * color.r * multiplier)); + + if (clipper.isClipping() && clipper.clipTriangles(vertices, triangles, triangles.length, uvs, c, 0, false, 5)) { + FloatArray clippedVertices = clipper.getClippedVertices(); + ShortArray clippedTriangles = clipper.getClippedTriangles(); + batch.draw(texture, clippedVertices.items, 0, clippedVertices.size, clippedTriangles.items, 0, + clippedTriangles.size); + } else { + for (int v = 2, u = 0; v < verticesLength; v += 5, u += 2) { + vertices[v] = c; + vertices[v + 1] = uvs[u]; + vertices[v + 2] = uvs[u + 1]; + } + batch.draw(texture, vertices, 0, verticesLength, triangles, 0, triangles.length); + } } - batch.draw(texture, vertices, 0, verticesLength, triangles, 0, triangles.length); } } - clipper.clipEnd(slot); } clipper.clipEnd(); @@ -240,85 +239,85 @@ public class SkeletonRenderer { Object[] drawOrder = skeleton.drawOrder.items; for (int i = 0, n = skeleton.drawOrder.size; i < n; i++) { var slot = (Slot)drawOrder[i]; - if (!slot.bone.active) { - clipper.clipEnd(slot); - continue; - } - SlotPose pose = slot.applied; - Texture texture = null; - Attachment attachment = pose.attachment; - if (attachment instanceof RegionAttachment region) { - verticesLength = 24; - vertices = this.vertices.items; - region.computeWorldVertices(slot, vertices, 0, 6); - triangles = quadTriangles; - texture = region.getRegion().getTexture(); - uvs = region.getUVs(); - color = region.getColor(); + if (slot.bone.active) { + SlotPose pose = slot.applied; + Attachment attachment = pose.attachment; + if (attachment != null) { + Texture texture = null; + if (attachment instanceof RegionAttachment region) { + verticesLength = 24; + vertices = this.vertices.items; + region.computeWorldVertices(slot, vertices, 0, 6); + triangles = quadTriangles; + texture = region.getRegion().getTexture(); + uvs = region.getUVs(); + color = region.getColor(); - } else if (attachment instanceof MeshAttachment mesh) { - int count = mesh.getWorldVerticesLength(); - verticesLength = count * 3; - vertices = this.vertices.setSize(verticesLength); - mesh.computeWorldVertices(skeleton, slot, 0, count, vertices, 0, 6); - triangles = mesh.getTriangles(); - texture = mesh.getRegion().getTexture(); - uvs = mesh.getUVs(); - color = mesh.getColor(); + } else if (attachment instanceof MeshAttachment mesh) { + int count = mesh.getWorldVerticesLength(); + verticesLength = count * 3; + vertices = this.vertices.setSize(verticesLength); + mesh.computeWorldVertices(skeleton, slot, 0, count, vertices, 0, 6); + triangles = mesh.getTriangles(); + texture = mesh.getRegion().getTexture(); + uvs = mesh.getUVs(); + color = mesh.getColor(); - } else if (attachment instanceof ClippingAttachment clip) { - clipper.clipStart(skeleton, slot, clip); - continue; + } else if (attachment instanceof ClippingAttachment clip) { + clipper.clipStart(skeleton, slot, clip); + continue; - } else if (attachment instanceof SkeletonAttachment skeletonAttachment) { - Skeleton attachmentSkeleton = skeletonAttachment.getSkeleton(); - if (attachmentSkeleton != null) draw(batch, attachmentSkeleton); - } - - if (texture != null) { - Color lightColor = pose.getColor(); - float alpha = a * lightColor.a * color.a * 255; - float multiplier = pmaColors ? alpha : 255; - - BlendMode slotBlendMode = slot.data.getBlendMode(); - if (slotBlendMode != blendMode) { - if (slotBlendMode == BlendMode.additive && pmaColors) { - slotBlendMode = BlendMode.normal; - alpha = 0; + } else if (attachment instanceof SkeletonAttachment skeletonAttachment) { + Skeleton attachmentSkeleton = skeletonAttachment.getSkeleton(); + if (attachmentSkeleton != null) draw(batch, attachmentSkeleton); } - blendMode = slotBlendMode; - blendMode.apply(batch, pmaBlendModes); - } - float red = r * color.r * multiplier; - float green = g * color.g * multiplier; - float blue = b * color.b * multiplier; - float light = NumberUtils.intToFloatColor((int)alpha << 24 // - | (int)(blue * lightColor.b) << 16 // - | (int)(green * lightColor.g) << 8 // - | (int)(red * lightColor.r)); - Color darkColor = pose.getDarkColor(); - float dark = darkColor == null ? 0 - : NumberUtils.intToFloatColor((int)(blue * darkColor.b) << 16 // - | (int)(green * darkColor.g) << 8 // - | (int)(red * darkColor.r)); + if (texture != null) { + Color lightColor = pose.getColor(); + float alpha = a * lightColor.a * color.a * 255; + float multiplier = pmaColors ? alpha : 255; - if (clipper.isClipping() && clipper.clipTriangles(vertices, triangles, triangles.length, uvs, light, dark, true, 6)) { - FloatArray clippedVertices = clipper.getClippedVertices(); - ShortArray clippedTriangles = clipper.getClippedTriangles(); - batch.drawTwoColor(texture, clippedVertices.items, 0, clippedVertices.size, clippedTriangles.items, 0, - clippedTriangles.size); - } else { - for (int v = 2, u = 0; v < verticesLength; v += 6, u += 2) { - vertices[v] = light; - vertices[v + 1] = dark; - vertices[v + 2] = uvs[u]; - vertices[v + 3] = uvs[u + 1]; + BlendMode slotBlendMode = slot.data.getBlendMode(); + if (slotBlendMode != blendMode) { + if (slotBlendMode == BlendMode.additive && pmaColors) { + slotBlendMode = BlendMode.normal; + alpha = 0; + } + blendMode = slotBlendMode; + blendMode.apply(batch, pmaBlendModes); + } + + float red = r * color.r * multiplier; + float green = g * color.g * multiplier; + float blue = b * color.b * multiplier; + float light = NumberUtils.intToFloatColor((int)alpha << 24 // + | (int)(blue * lightColor.b) << 16 // + | (int)(green * lightColor.g) << 8 // + | (int)(red * lightColor.r)); + Color darkColor = pose.getDarkColor(); + float dark = darkColor == null ? 0 + : NumberUtils.intToFloatColor((int)(blue * darkColor.b) << 16 // + | (int)(green * darkColor.g) << 8 // + | (int)(red * darkColor.r)); + + if (clipper.isClipping() + && clipper.clipTriangles(vertices, triangles, triangles.length, uvs, light, dark, true, 6)) { + FloatArray clippedVertices = clipper.getClippedVertices(); + ShortArray clippedTriangles = clipper.getClippedTriangles(); + batch.drawTwoColor(texture, clippedVertices.items, 0, clippedVertices.size, clippedTriangles.items, 0, + clippedTriangles.size); + } else { + for (int v = 2, u = 0; v < verticesLength; v += 6, u += 2) { + vertices[v] = light; + vertices[v + 1] = dark; + vertices[v + 2] = uvs[u]; + vertices[v + 3] = uvs[u + 1]; + } + batch.drawTwoColor(texture, vertices, 0, verticesLength, triangles, 0, triangles.length); + } } - batch.drawTwoColor(texture, vertices, 0, verticesLength, triangles, 0, triangles.length); } } - clipper.clipEnd(slot); } clipper.clipEnd(); diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java index 6246155ca..a4c6f2d49 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skin.java @@ -45,7 +45,7 @@ public class Skin { final String name; final OrderedSet attachments = new OrderedSet(); final Array bones = new Array(0); - final Array constraints = new Array(0); + final Array constraints = new Array(0); private final SkinEntry lookup = new SkinEntry(0, "", null); // Nonessential. @@ -71,7 +71,7 @@ public class Skin { for (BoneData data : skin.bones) if (!bones.contains(data, true)) bones.add(data); - for (PosedData data : skin.constraints) + for (ConstraintData data : skin.constraints) if (!constraints.contains(data, true)) constraints.add(data); for (SkinEntry entry : skin.attachments.orderedItems()) @@ -86,7 +86,7 @@ public class Skin { for (BoneData data : skin.bones) if (!bones.contains(data, true)) bones.add(data); - for (PosedData data : skin.constraints) + for (ConstraintData data : skin.constraints) if (!constraints.contains(data, true)) constraints.add(data); for (SkinEntry entry : skin.attachments.orderedItems()) { @@ -134,7 +134,7 @@ public class Skin { return bones; } - public Array getConstraints () { + public Array getConstraints () { return constraints; } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slider.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slider.java index 6040b234e..b97355447 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slider.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slider.java @@ -29,21 +29,23 @@ 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.Timeline; /** Stores the setup pose for a {@link PhysicsConstraint}. *

* See Physics constraints in the Spine User Guide. */ -public class Slider extends Constraint { +public class Slider extends Constraint { public Slider (SliderData data) { super(data, new SliderPose(), new SliderPose()); } - /** Copy constructor. */ - public Slider (Slider slider) { - this(slider.data); - pose.set(slider.pose); + public Slider copy (Skeleton skeleton) { + var copy = new Slider(data); + copy.pose.set(pose); + return copy; } public void update (Skeleton skeleton, Physics physics) { @@ -51,6 +53,28 @@ public class Slider extends Constraint { data.animation.apply(skeleton, pose.time, pose.time, false, null, pose.mix, MixBlend.replace, MixDirection.in, true); } - public void sort () { + void sort (Skeleton skeleton) { + Object[] 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()]); + } + + skeleton.updateCache.add(this); + + for (int i = 0; i < timelineCount; i++) { + if (timelines[i] instanceof BoneTimeline boneTimeline) { + var bone = (Bone)bones[boneTimeline.getBoneIndex()]; + skeleton.resetCache(bone); + skeleton.sortReset(bone.children); + bone.sorted = false; + } + } + for (int i = 0; i < timelineCount; i++) + if (timelines[i] instanceof BoneTimeline boneTimeline) skeleton.sortBone((Bone)bones[boneTimeline.getBoneIndex()]); } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SliderData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SliderData.java index 199fe0ade..55fbc47dc 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SliderData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SliderData.java @@ -32,13 +32,17 @@ package com.esotericsoftware.spine; /** Stores the setup pose for a {@link PhysicsConstraint}. *

* See Physics constraints in the Spine User Guide. */ -public class SliderData extends PosedData { +public class SliderData extends ConstraintData { Animation animation; public SliderData (String name) { super(name, new SliderPose()); } + public Slider create (Skeleton skeleton) { + return new Slider(this); + } + public Animation getAnimation () { return animation; } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slot.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slot.java index caea1f964..18425c6a5 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slot.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Slot.java @@ -35,12 +35,14 @@ import com.badlogic.gdx.graphics.Color; * state for an attachment. State cannot be stored in an attachment itself because attachments are stateless and may be shared * across multiple skeletons. */ public class Slot extends Posed { + final Skeleton skeleton; final Bone bone; int attachmentState; public Slot (SlotData data, Skeleton skeleton) { 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); if (data.setup.darkColor != null) { pose.darkColor = new Color(); @@ -50,9 +52,12 @@ public class Slot extends Posed { } /** Copy constructor. */ - public Slot (Slot slot, Bone bone) { + public Slot (Slot slot, Bone bone, Skeleton skeleton) { super(slot.data, new SlotPose(), new SlotPose()); + if (bone == null) throw new IllegalArgumentException("bone cannot be null."); + if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); this.bone = bone; + this.skeleton = skeleton; if (data.setup.darkColor != null) { pose.darkColor = new Color(); applied.darkColor = new Color(); @@ -64,4 +69,16 @@ public class Slot extends Posed { public Bone getBone () { return bone; } + + public void setupPose () { + pose.color.set(data.setup.color); + if (pose.darkColor != null) pose.darkColor.set(data.setup.darkColor); + pose.sequenceIndex = pose.sequenceIndex; + if (data.attachmentName == null) + pose.setAttachment(null); + else { + pose.attachment = null; + pose.setAttachment(skeleton.getAttachment(data.index, data.attachmentName)); + } + } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java index f4a9d5b05..8a4eaa4bf 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java @@ -40,7 +40,7 @@ import com.esotericsoftware.spine.TransformConstraintData.ToProperty; * bones to match that of the source bone. *

* See Transform constraints in the Spine User Guide. */ -public class TransformConstraint extends Constraint { +public class TransformConstraint extends Constraint { final Array bones; Bone source; @@ -55,10 +55,10 @@ public class TransformConstraint extends Constraint * See Transform constraints in the Spine User Guide. */ -public class TransformConstraintData extends PosedData { +public class TransformConstraintData extends ConstraintData { final Array bones = new Array(); BoneData source; float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY; @@ -47,6 +47,10 @@ public class TransformConstraintData extends PosedData super(name, new TransformConstraintPose()); } + public TransformConstraint create (Skeleton skeleton) { + return new TransformConstraint(this, skeleton); + } + /** The bones that will be modified by this transform constraint. */ public Array getBones () { return bones;