mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-09 16:48:43 +08:00
IK is complete for spine-libgdx when exporting from Spine 1.9.06+.
This commit is contained in:
parent
148715426f
commit
8a46d48e80
@ -42,10 +42,11 @@ public class Bone {
|
||||
float x, y;
|
||||
float rotation, rotationIK;
|
||||
float scaleX, scaleY;
|
||||
boolean flipX, flipY;
|
||||
|
||||
float m00, m01, worldX; // a b x
|
||||
float m10, m11, worldY; // c d y
|
||||
float worldRotation, worldCos, worldSin;
|
||||
float worldRotation;
|
||||
float worldScaleX, worldScaleY;
|
||||
|
||||
/** @param parent May be null. */
|
||||
@ -68,10 +69,12 @@ public class Bone {
|
||||
rotationIK = bone.rotationIK;
|
||||
scaleX = bone.scaleX;
|
||||
scaleY = bone.scaleY;
|
||||
flipX = bone.flipX;
|
||||
flipY = bone.flipY;
|
||||
}
|
||||
|
||||
/** Computes the world SRT using the parent bone and the local SRT. */
|
||||
public void updateWorldTransform (boolean flipX, boolean flipY) {
|
||||
public void updateWorldTransform () {
|
||||
Bone parent = this.parent;
|
||||
float x = this.x, y = this.y;
|
||||
if (parent != null) {
|
||||
@ -92,21 +95,21 @@ public class Bone {
|
||||
worldScaleY = scaleY;
|
||||
worldRotation = rotationIK;
|
||||
}
|
||||
float cos = MathUtils.cosDeg(worldRotation);
|
||||
float sin = MathUtils.sinDeg(worldRotation);
|
||||
worldCos = cos;
|
||||
worldSin = sin;
|
||||
m00 = cos * worldScaleX;
|
||||
m10 = sin * worldScaleX;
|
||||
m01 = -sin * worldScaleY;
|
||||
m11 = cos * worldScaleY;
|
||||
float cos = MathUtils.cosDeg(worldRotation) * worldScaleX;
|
||||
float sin = MathUtils.sinDeg(worldRotation) * worldScaleY;
|
||||
if (flipX) {
|
||||
m00 = -m00;
|
||||
m01 = -m01;
|
||||
m00 = -cos;
|
||||
m01 = sin;
|
||||
} else {
|
||||
m00 = cos;
|
||||
m01 = -sin;
|
||||
}
|
||||
if (flipY) {
|
||||
m10 = -m10;
|
||||
m11 = -m11;
|
||||
m10 = -sin;
|
||||
m11 = -cos;
|
||||
} else {
|
||||
m10 = sin;
|
||||
m11 = cos;
|
||||
}
|
||||
}
|
||||
|
||||
@ -221,14 +224,6 @@ public class Bone {
|
||||
return worldRotation;
|
||||
}
|
||||
|
||||
public float getWorldCos () {
|
||||
return worldCos;
|
||||
}
|
||||
|
||||
public float getWorldSin () {
|
||||
return worldSin;
|
||||
}
|
||||
|
||||
public float getWorldScaleX () {
|
||||
return worldScaleX;
|
||||
}
|
||||
@ -253,12 +248,15 @@ public class Bone {
|
||||
}
|
||||
|
||||
public Vector2 worldToLocal (Vector2 world) {
|
||||
float x = world.x - worldX;
|
||||
float y = world.y - worldY;
|
||||
float cos = worldCos;
|
||||
float sin = -worldSin;
|
||||
world.x = (x * cos - y * sin) / worldScaleX;
|
||||
world.y = (x * sin + y * cos) / worldScaleY;
|
||||
float x = world.x - worldX, y = world.y - worldY;
|
||||
float m00 = this.m00, m10 = this.m10, m01 = this.m01, m11 = this.m11;
|
||||
if (flipX != flipY) {
|
||||
m00 *= -1;
|
||||
m11 *= -1;
|
||||
}
|
||||
float invDet = 1 / (m00 * m11 - m01 * m10);
|
||||
world.x = (x * m00 * invDet - y * m01 * invDet);
|
||||
world.y = (y * m11 * invDet - x * m10 * invDet);
|
||||
return world;
|
||||
}
|
||||
|
||||
|
||||
@ -29,10 +29,10 @@ public class IkConstraint {
|
||||
}
|
||||
|
||||
/** Copy constructor. */
|
||||
public IkConstraint (IkConstraint ikConstraint) {
|
||||
public IkConstraint (IkConstraint ikConstraint, Array<Bone> bones, Bone target) {
|
||||
data = ikConstraint.data;
|
||||
bones = new Array(ikConstraint.bones);
|
||||
target = ikConstraint.target;
|
||||
this.bones = bones;
|
||||
this.target = target;
|
||||
mix = ikConstraint.mix;
|
||||
bendDirection = ikConstraint.bendDirection;
|
||||
}
|
||||
|
||||
@ -98,12 +98,19 @@ public class Skeleton {
|
||||
drawOrder.add(slots.get(skeleton.slots.indexOf(slot, true)));
|
||||
|
||||
ikConstraints = new Array(skeleton.ikConstraints.size);
|
||||
for (IkConstraint ikConstraint : skeleton.ikConstraints)
|
||||
ikConstraints.add(new IkConstraint(ikConstraint));
|
||||
for (IkConstraint ikConstraint : skeleton.ikConstraints) {
|
||||
Bone target = bones.get(skeleton.bones.indexOf(ikConstraint.target, true));
|
||||
Array<Bone> ikBones = new Array(ikConstraint.bones.size);
|
||||
for (Bone bone : ikConstraint.bones)
|
||||
ikBones.add(bones.get(skeleton.bones.indexOf(bone, true)));
|
||||
ikConstraints.add(new IkConstraint(ikConstraint, ikBones, target));
|
||||
}
|
||||
|
||||
skin = skeleton.skin;
|
||||
color = new Color(skeleton.color);
|
||||
time = skeleton.time;
|
||||
flipX = skeleton.flipX;
|
||||
flipY = skeleton.flipY;
|
||||
|
||||
updateCache();
|
||||
}
|
||||
@ -155,15 +162,13 @@ public class Skeleton {
|
||||
Bone bone = bones.get(i);
|
||||
bone.rotationIK = bone.rotation;
|
||||
}
|
||||
boolean flipX = this.flipX;
|
||||
boolean flipY = this.flipY;
|
||||
Array<Array<Bone>> updateBonesCache = this.updateBonesCache;
|
||||
Array<IkConstraint> ikConstraints = this.ikConstraints;
|
||||
int i = 0, last = updateBonesCache.size - 1;
|
||||
while (true) {
|
||||
Array<Bone> updateBones = updateBonesCache.get(i);
|
||||
for (int ii = 0, nn = updateBones.size; ii < nn; ii++)
|
||||
updateBones.get(ii).updateWorldTransform(flipX, flipY);
|
||||
updateBones.get(ii).updateWorldTransform();
|
||||
if (i == last) break;
|
||||
ikConstraints.get(i).apply();
|
||||
i++;
|
||||
@ -360,7 +365,11 @@ public class Skeleton {
|
||||
}
|
||||
|
||||
public void setFlipX (boolean flipX) {
|
||||
// if (this.flipX == flipX) return;
|
||||
this.flipX = flipX;
|
||||
Array<Bone> bones = this.bones;
|
||||
for (int i = 0, n = bones.size; i < n; i++)
|
||||
bones.get(i).flipX = flipX;
|
||||
}
|
||||
|
||||
public boolean getFlipY () {
|
||||
@ -368,7 +377,20 @@ public class Skeleton {
|
||||
}
|
||||
|
||||
public void setFlipY (boolean flipY) {
|
||||
if (this.flipY == flipY) return;
|
||||
this.flipY = flipY;
|
||||
Array<Bone> bones = this.bones;
|
||||
for (int i = 0, n = bones.size; i < n; i++)
|
||||
bones.get(i).flipY = flipY;
|
||||
}
|
||||
|
||||
public void setFlip (boolean flipX, boolean flipY) {
|
||||
Array<Bone> bones = this.bones;
|
||||
for (int i = 0, n = bones.size; i < n; i++) {
|
||||
Bone bone = bones.get(i);
|
||||
bone.flipX = flipX;
|
||||
bone.flipY = flipY;
|
||||
}
|
||||
}
|
||||
|
||||
public float getX () {
|
||||
|
||||
@ -107,6 +107,11 @@ public class SkeletonBinary {
|
||||
|
||||
DataInput input = new DataInput(file.read(512));
|
||||
try {
|
||||
skeletonData.version = input.readString();
|
||||
skeletonData.hash = input.readString();
|
||||
skeletonData.width = input.readFloat();
|
||||
skeletonData.height = input.readFloat();
|
||||
|
||||
boolean nonessential = input.readBoolean();
|
||||
// Bones.
|
||||
for (int i = 0, n = input.readInt(true); i < n; i++) {
|
||||
|
||||
@ -41,6 +41,8 @@ public class SkeletonData {
|
||||
final Array<EventData> events = new Array();
|
||||
final Array<Animation> animations = new Array();
|
||||
final Array<IkConstraintData> ikConstraints = new Array();
|
||||
float width, height;
|
||||
String version, hash;
|
||||
|
||||
// --- Bones.
|
||||
|
||||
@ -179,6 +181,39 @@ public class SkeletonData {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public float getWidth () {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth (float width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public float getHeight () {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight (float height) {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
/** Returns the Spine version used to export this data. */
|
||||
public String getVersion () {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion (String version) {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
public String getHash () {
|
||||
return hash;
|
||||
}
|
||||
|
||||
public void setHash (String hash) {
|
||||
this.hash = hash;
|
||||
}
|
||||
|
||||
public String toString () {
|
||||
return name != null ? name : super.toString();
|
||||
}
|
||||
|
||||
@ -90,6 +90,15 @@ public class SkeletonJson {
|
||||
|
||||
JsonValue root = new JsonReader().parse(file);
|
||||
|
||||
// Skeleton.
|
||||
JsonValue skeletonMap = root.get("skeleton");
|
||||
if (skeletonMap != null) {
|
||||
skeletonData.version = skeletonMap.getString("spine");
|
||||
skeletonData.hash = skeletonMap.getString("hash");
|
||||
skeletonData.width = skeletonMap.getFloat("width");
|
||||
skeletonData.height = skeletonMap.getFloat("height");
|
||||
}
|
||||
|
||||
// Bones.
|
||||
for (JsonValue boneMap = root.getChild("bones"); boneMap != null; boneMap = boneMap.next) {
|
||||
BoneData parent = null;
|
||||
@ -114,6 +123,27 @@ public class SkeletonJson {
|
||||
skeletonData.getBones().add(boneData);
|
||||
}
|
||||
|
||||
// IK.
|
||||
for (JsonValue ikMap = root.getChild("ik"); ikMap != null; ikMap = ikMap.next) {
|
||||
IkConstraintData ikConstraintData = new IkConstraintData(ikMap.getString("name"));
|
||||
|
||||
for (JsonValue boneMap = ikMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) {
|
||||
String boneName = boneMap.asString();
|
||||
BoneData bone = skeletonData.findBone(boneName);
|
||||
if (bone == null) throw new SerializationException("IK bone not found: " + boneName);
|
||||
ikConstraintData.getBones().add(bone);
|
||||
}
|
||||
|
||||
String targetName = ikMap.getString("target");
|
||||
ikConstraintData.setTarget(skeletonData.findBone(targetName));
|
||||
if (ikConstraintData.getTarget() == null) throw new SerializationException("Target bone not found: " + targetName);
|
||||
|
||||
ikConstraintData.setBendDirection(ikMap.getBoolean("bendPositive", true) ? 1 : -1);
|
||||
ikConstraintData.setMix(ikMap.getFloat("mix", 1));
|
||||
|
||||
skeletonData.getIkConstraints().add(ikConstraintData);
|
||||
}
|
||||
|
||||
// Slots.
|
||||
for (JsonValue slotMap = root.getChild("slots"); slotMap != null; slotMap = slotMap.next) {
|
||||
String slotName = slotMap.getString("name");
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user