mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 22:34:53 +08:00
[libgdx] Constraint order from appearance in data. updateCache sorting moved to constraints.
This commit is contained in:
parent
fff1606b6d
commit
d115ca83dd
@ -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<Event> 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<Event> 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<Event> 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<Event> 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<Event> 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<Event> 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);
|
||||
}
|
||||
|
||||
@ -1,10 +1,21 @@
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
abstract public class Constraint<D extends PosedData<P>, P extends Pose> extends PosedActive<D, P, P> implements Update {
|
||||
abstract public class Constraint< //
|
||||
T extends Constraint<T, D, P>, //
|
||||
D extends ConstraintData<T, P>, //
|
||||
P extends Pose> //
|
||||
extends PosedActive<D, P, P> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,14 @@
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
abstract public class ConstraintData< //
|
||||
T extends Constraint, //
|
||||
P extends Pose> //
|
||||
extends PosedData<P> {
|
||||
|
||||
public ConstraintData (String name, P setup) {
|
||||
super(name, setup);
|
||||
}
|
||||
|
||||
abstract public T create (Skeleton skeleton);
|
||||
}
|
||||
@ -39,7 +39,7 @@ import com.esotericsoftware.spine.AnimationState.AnimationStateListener;
|
||||
* AnimationStateListener {@link AnimationStateListener#event(com.esotericsoftware.spine.AnimationState.TrackEntry, Event)}, and
|
||||
* <a href="https://esotericsoftware.com/spine-events">Events</a> in the Spine User Guide. */
|
||||
public class Event {
|
||||
private final EventData data;
|
||||
final EventData data;
|
||||
int intValue;
|
||||
float floatValue;
|
||||
String stringValue;
|
||||
|
||||
@ -39,7 +39,7 @@ import com.esotericsoftware.spine.BoneData.Inherit;
|
||||
* the last bone is as close to the target bone as possible.
|
||||
* <p>
|
||||
* See <a href="https://esotericsoftware.com/spine-ik-constraints">IK constraints</a> in the Spine User Guide. */
|
||||
public class IkConstraint extends Constraint<IkConstraintData, IkConstraintPose> {
|
||||
public class IkConstraint extends Constraint<IkConstraint, IkConstraintData, IkConstraintPose> {
|
||||
final Array<BonePose> bones;
|
||||
Bone target;
|
||||
|
||||
@ -54,10 +54,10 @@ public class IkConstraint extends Constraint<IkConstraintData, IkConstraintPose>
|
||||
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<IkConstraintData, IkConstraintPose>
|
||||
}
|
||||
}
|
||||
|
||||
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. */
|
||||
|
||||
@ -34,7 +34,7 @@ import com.badlogic.gdx.utils.Array;
|
||||
/** Stores the setup pose for an {@link IkConstraint}.
|
||||
* <p>
|
||||
* See <a href="https://esotericsoftware.com/spine-ik-constraints">IK constraints</a> in the Spine User Guide. */
|
||||
public class IkConstraintData extends PosedData<IkConstraintPose> {
|
||||
public class IkConstraintData extends ConstraintData<IkConstraint, IkConstraintPose> {
|
||||
final Array<BoneData> bones = new Array();
|
||||
BoneData target;
|
||||
boolean uniform;
|
||||
@ -43,6 +43,10 @@ public class IkConstraintData extends PosedData<IkConstraintPose> {
|
||||
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<BoneData> getBones () {
|
||||
return bones;
|
||||
|
||||
@ -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}.
|
||||
* <p>
|
||||
* See <a href="https://esotericsoftware.com/spine-path-constraints">Path constraints</a> in the Spine User Guide. */
|
||||
public class PathConstraint extends Constraint<PathConstraintData, PathConstraintPose> {
|
||||
public class PathConstraint extends Constraint<PathConstraint, PathConstraintData, PathConstraintPose> {
|
||||
static final int NONE = -1, BEFORE = -2, AFTER = -3;
|
||||
static final float epsilon = 0.00001f;
|
||||
|
||||
@ -67,10 +69,10 @@ public class PathConstraint extends Constraint<PathConstraintData, PathConstrain
|
||||
slot = skeleton.slots.get(data.slot.index);
|
||||
}
|
||||
|
||||
/** Copy constructor. */
|
||||
public PathConstraint (PathConstraint constraint, Skeleton skeleton) {
|
||||
this(constraint.data, skeleton);
|
||||
pose.set(constraint.pose);
|
||||
public PathConstraint copy (Skeleton skeleton) {
|
||||
var copy = new PathConstraint(data, skeleton);
|
||||
copy.pose.set(pose);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** Applies the constraint to the constrained bones. */
|
||||
@ -456,7 +458,57 @@ public class PathConstraint extends Constraint<PathConstraintData, PathConstrain
|
||||
}
|
||||
}
|
||||
|
||||
public void sort () {
|
||||
void sort (Skeleton skeleton) {
|
||||
int slotIndex = slot.getData().index;
|
||||
Bone slotBone = slot.bone;
|
||||
if (skeleton.skin != null) sortPathConstraintAttachment(skeleton, skeleton.skin, slotIndex, slotBone);
|
||||
if (skeleton.data.defaultSkin != null && skeleton.data.defaultSkin != skeleton.skin)
|
||||
sortPathConstraintAttachment(skeleton, skeleton.data.defaultSkin, slotIndex, slotBone);
|
||||
|
||||
sortPathConstraintAttachment(skeleton, slot.pose.attachment, slotBone);
|
||||
|
||||
Object[] bones = this.bones.items;
|
||||
int boneCount = this.bones.size;
|
||||
for (int i = 0; i < boneCount; i++) {
|
||||
Bone bone = ((BonePose)bones[i]).bone;
|
||||
skeleton.resetCache(bone);
|
||||
skeleton.sortBone(bone);
|
||||
}
|
||||
|
||||
skeleton.updateCache.add(this);
|
||||
|
||||
for (int i = 0; i < boneCount; i++)
|
||||
skeleton.sortReset(((BonePose)bones[i]).bone.children);
|
||||
for (int i = 0; i < boneCount; i++)
|
||||
((BonePose)bones[i]).bone.sorted = true;
|
||||
}
|
||||
|
||||
private void sortPathConstraintAttachment (Skeleton skeleton, 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(skeleton, entry.attachment, slotBone);
|
||||
}
|
||||
}
|
||||
|
||||
private void sortPathConstraintAttachment (Skeleton skeleton, Attachment attachment, Bone slotBone) {
|
||||
if (!(attachment instanceof PathAttachment pathAttachment)) return;
|
||||
int[] pathBones = pathAttachment.getBones();
|
||||
if (pathBones == null)
|
||||
skeleton.sortBone(slotBone);
|
||||
else {
|
||||
Object[] bones = skeleton.bones.items;
|
||||
for (int i = 0, n = pathBones.length; i < n;) {
|
||||
int nn = pathBones[i++];
|
||||
nn += i;
|
||||
while (i < nn)
|
||||
skeleton.sortBone((Bone)bones[pathBones[i++]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean isSourceActive () {
|
||||
return slot.bone.active;
|
||||
}
|
||||
|
||||
/** The bones that will be modified by this path constraint. */
|
||||
|
||||
@ -34,7 +34,7 @@ import com.badlogic.gdx.utils.Array;
|
||||
/** Stores the setup pose for a {@link PathConstraint}.
|
||||
* <p>
|
||||
* See <a href="https://esotericsoftware.com/spine-path-constraints">Path constraints</a> in the Spine User Guide. */
|
||||
public class PathConstraintData extends PosedData<PathConstraintPose> {
|
||||
public class PathConstraintData extends ConstraintData<PathConstraint, PathConstraintPose> {
|
||||
final Array<BoneData> bones = new Array();
|
||||
SlotData slot;
|
||||
PositionMode positionMode;
|
||||
@ -46,6 +46,10 @@ public class PathConstraintData extends PosedData<PathConstraintPose> {
|
||||
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<BoneData> getBones () {
|
||||
return bones;
|
||||
|
||||
@ -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.
|
||||
* <p>
|
||||
* See <a href="https://esotericsoftware.com/spine-physics-constraints">Physics constraints</a> in the Spine User Guide. */
|
||||
public class PhysicsConstraint extends Constraint<PhysicsConstraintData, PhysicsConstraintPose> {
|
||||
public class PhysicsConstraint extends Constraint<PhysicsConstraint, PhysicsConstraintData, PhysicsConstraintPose> {
|
||||
BonePose bone;
|
||||
|
||||
boolean reset = true;
|
||||
@ -52,10 +52,10 @@ public class PhysicsConstraint extends Constraint<PhysicsConstraintData, Physics
|
||||
bone = skeleton.bones.get(data.bone.index).constrained;
|
||||
}
|
||||
|
||||
/** Copy constructor. */
|
||||
public PhysicsConstraint (PhysicsConstraint constraint, Skeleton skeleton) {
|
||||
this(constraint.data, skeleton);
|
||||
pose.set(constraint.pose);
|
||||
public PhysicsConstraint copy (Skeleton skeleton) {
|
||||
var copy = new PhysicsConstraint(data, skeleton);
|
||||
copy.pose.set(pose);
|
||||
return copy;
|
||||
}
|
||||
|
||||
public void reset (Skeleton skeleton) {
|
||||
@ -255,7 +255,19 @@ public class PhysicsConstraint extends Constraint<PhysicsConstraintData, Physics
|
||||
bone.updateLocalTransform(skeleton);
|
||||
}
|
||||
|
||||
public void sort () {
|
||||
void sort (Skeleton skeleton) {
|
||||
Bone bone = this.bone.bone;
|
||||
skeleton.sortBone(bone);
|
||||
|
||||
skeleton.resetCache(bone);
|
||||
skeleton.updateCache.add(this);
|
||||
|
||||
skeleton.sortReset(bone.children);
|
||||
bone.sorted = true;
|
||||
}
|
||||
|
||||
boolean isSourceActive () {
|
||||
return bone.bone.active;
|
||||
}
|
||||
|
||||
/** The bone constrained by this physics constraint. */
|
||||
|
||||
@ -32,7 +32,7 @@ package com.esotericsoftware.spine;
|
||||
/** Stores the setup pose for a {@link PhysicsConstraint}.
|
||||
* <p>
|
||||
* See <a href="https://esotericsoftware.com/spine-physics-constraints">Physics constraints</a> in the Spine User Guide. */
|
||||
public class PhysicsConstraintData extends PosedData<PhysicsConstraintPose> {
|
||||
public class PhysicsConstraintData extends ConstraintData<PhysicsConstraint, PhysicsConstraintPose> {
|
||||
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<PhysicsConstraintPose> {
|
||||
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;
|
||||
|
||||
@ -1,7 +1,11 @@
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
abstract public class Posed<D extends PosedData<P>, P extends Pose, A extends P> {
|
||||
abstract public class Posed< //
|
||||
D extends PosedData<P>, //
|
||||
P extends Pose, //
|
||||
A extends P> {
|
||||
|
||||
final D data;
|
||||
final P pose;
|
||||
final A constrained;
|
||||
@ -13,7 +17,6 @@ abstract public class Posed<D extends PosedData<P>, P extends Pose, A extends P>
|
||||
this.pose = pose;
|
||||
this.constrained = constrained;
|
||||
applied = (A)pose;
|
||||
setupPose();
|
||||
}
|
||||
|
||||
public void setupPose () {
|
||||
|
||||
@ -1,11 +1,17 @@
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
abstract public class PosedActive<D extends PosedData<P>, P extends Pose, A extends P> extends Posed<D, P, A> {
|
||||
abstract public class PosedActive< //
|
||||
D extends PosedData<P>, //
|
||||
P extends Pose, //
|
||||
A extends P> //
|
||||
extends Posed<D, P, A> {
|
||||
|
||||
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
|
||||
|
||||
@ -35,16 +35,6 @@ abstract public class PosedData<P extends Pose> {
|
||||
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;
|
||||
|
||||
@ -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<Bone> bones;
|
||||
final Array<Slot> slots;
|
||||
Array<Slot> drawOrder;
|
||||
final Array<Slider> sliders;
|
||||
final Array<IkConstraint> ikConstraints;
|
||||
final Array<TransformConstraint> transformConstraints;
|
||||
final Array<PathConstraint> pathConstraints;
|
||||
final Array<PhysicsConstraint> physicsConstraints;
|
||||
final Array<Constraint> constraints;
|
||||
final Array<PhysicsConstraint> physics;
|
||||
final Array updateCache = new Array();
|
||||
final Array<Posed> 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<BonePose> 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<Bone> bones) {
|
||||
void sortReset (Array<Bone> 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 <a href="https://esotericsoftware.com/spine-runtime-skeletons#World-transforms">World transforms</a> 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<Slider> getSliders () {
|
||||
return sliders;
|
||||
/** The skeleton's constraints. */
|
||||
public Array<Constraint> 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<IkConstraint> 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<TransformConstraint> 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<PathConstraint> 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<PhysicsConstraint> 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 extends Constraint> T findConstraint (String constraintName, Class<T> 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);
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
@ -44,11 +44,7 @@ public class SkeletonData {
|
||||
@Null Skin defaultSkin;
|
||||
final Array<EventData> events = new Array();
|
||||
final Array<Animation> animations = new Array();
|
||||
final Array<SliderData> sliders = new Array();
|
||||
final Array<IkConstraintData> ikConstraints = new Array();
|
||||
final Array<TransformConstraintData> transformConstraints = new Array();
|
||||
final Array<PathConstraintData> pathConstraints = new Array();
|
||||
final Array<PhysicsConstraintData> physicsConstraints = new Array();
|
||||
final Array<ConstraintData> 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<SliderData> getSliders () {
|
||||
return sliders;
|
||||
/** The skeleton's constraints. */
|
||||
public Array<ConstraintData> 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 extends ConstraintData> T findConstraint (String constraintName, Class<T> 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<IkConstraintData> 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<TransformConstraintData> 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<PathConstraintData> 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<PhysicsConstraintData> 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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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.
|
||||
* <p>
|
||||
* 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();
|
||||
|
||||
@ -45,7 +45,7 @@ public class Skin {
|
||||
final String name;
|
||||
final OrderedSet<SkinEntry> attachments = new OrderedSet();
|
||||
final Array<BoneData> bones = new Array(0);
|
||||
final Array<PosedData> constraints = new Array(0);
|
||||
final Array<ConstraintData> 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<PosedData> getConstraints () {
|
||||
public Array<ConstraintData> getConstraints () {
|
||||
return constraints;
|
||||
}
|
||||
|
||||
|
||||
@ -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}.
|
||||
* <p>
|
||||
* See <a href="https://esotericsoftware.com/spine-physics-constraints">Physics constraints</a> in the Spine User Guide. */
|
||||
public class Slider extends Constraint<SliderData, SliderPose> {
|
||||
public class Slider extends Constraint<Slider, SliderData, SliderPose> {
|
||||
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<SliderData, SliderPose> {
|
||||
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()]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,13 +32,17 @@ package com.esotericsoftware.spine;
|
||||
/** Stores the setup pose for a {@link PhysicsConstraint}.
|
||||
* <p>
|
||||
* See <a href="https://esotericsoftware.com/spine-physics-constraints">Physics constraints</a> in the Spine User Guide. */
|
||||
public class SliderData extends PosedData<SliderPose> {
|
||||
public class SliderData extends ConstraintData<Slider, SliderPose> {
|
||||
Animation animation;
|
||||
|
||||
public SliderData (String name) {
|
||||
super(name, new SliderPose());
|
||||
}
|
||||
|
||||
public Slider create (Skeleton skeleton) {
|
||||
return new Slider(this);
|
||||
}
|
||||
|
||||
public Animation getAnimation () {
|
||||
return animation;
|
||||
}
|
||||
|
||||
@ -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<SlotData, SlotPose, SlotPose> {
|
||||
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<SlotData, SlotPose, SlotPose> {
|
||||
}
|
||||
|
||||
/** 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<SlotData, SlotPose, SlotPose> {
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -40,7 +40,7 @@ import com.esotericsoftware.spine.TransformConstraintData.ToProperty;
|
||||
* bones to match that of the source bone.
|
||||
* <p>
|
||||
* See <a href="https://esotericsoftware.com/spine-transform-constraints">Transform constraints</a> in the Spine User Guide. */
|
||||
public class TransformConstraint extends Constraint<TransformConstraintData, TransformConstraintPose> {
|
||||
public class TransformConstraint extends Constraint<TransformConstraint, TransformConstraintData, TransformConstraintPose> {
|
||||
final Array<BonePose> bones;
|
||||
Bone source;
|
||||
|
||||
@ -55,10 +55,10 @@ public class TransformConstraint extends Constraint<TransformConstraintData, Tra
|
||||
source = skeleton.bones.get(data.source.index);
|
||||
}
|
||||
|
||||
/** Copy constructor. */
|
||||
public TransformConstraint (TransformConstraint constraint, Skeleton skeleton) {
|
||||
this(constraint.data, skeleton);
|
||||
pose.set(constraint.pose);
|
||||
public TransformConstraint copy (Skeleton skeleton) {
|
||||
var copy = new TransformConstraint(data, skeleton);
|
||||
copy.pose.set(pose);
|
||||
return copy;
|
||||
}
|
||||
|
||||
/** Applies the constraint to the constrained bones. */
|
||||
@ -101,7 +101,36 @@ public class TransformConstraint extends Constraint<TransformConstraintData, Tra
|
||||
}
|
||||
}
|
||||
|
||||
public void sort () {
|
||||
void sort (Skeleton skeleton) {
|
||||
skeleton.sortBone(source);
|
||||
|
||||
Object[] bones = this.bones.items;
|
||||
int boneCount = this.bones.size;
|
||||
if (data.localSource) {
|
||||
for (int i = 0; i < boneCount; i++) {
|
||||
Bone child = ((BonePose)bones[i]).bone;
|
||||
skeleton.resetCache(child);
|
||||
skeleton.sortBone(child.parent);
|
||||
skeleton.sortBone(child);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < boneCount; i++) {
|
||||
Bone bone = ((BonePose)bones[i]).bone;
|
||||
skeleton.resetCache(bone);
|
||||
skeleton.sortBone(bone);
|
||||
}
|
||||
}
|
||||
|
||||
skeleton.updateCache.add(this);
|
||||
|
||||
for (int i = 0; i < boneCount; i++)
|
||||
skeleton.sortReset(((BonePose)bones[i]).bone.children);
|
||||
for (int i = 0; i < boneCount; i++)
|
||||
((BonePose)bones[i]).bone.sorted = true;
|
||||
}
|
||||
|
||||
boolean isSourceActive () {
|
||||
return source.active;
|
||||
}
|
||||
|
||||
/** The bones that will be modified by this transform constraint. */
|
||||
|
||||
@ -36,7 +36,7 @@ import com.badlogic.gdx.utils.Array;
|
||||
/** Stores the setup pose for a {@link TransformConstraint}.
|
||||
* <p>
|
||||
* See <a href="https://esotericsoftware.com/spine-transform-constraints">Transform constraints</a> in the Spine User Guide. */
|
||||
public class TransformConstraintData extends PosedData<TransformConstraintPose> {
|
||||
public class TransformConstraintData extends ConstraintData<TransformConstraint, TransformConstraintPose> {
|
||||
final Array<BoneData> bones = new Array();
|
||||
BoneData source;
|
||||
float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY;
|
||||
@ -47,6 +47,10 @@ public class TransformConstraintData extends PosedData<TransformConstraintPose>
|
||||
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<BoneData> getBones () {
|
||||
return bones;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user