From 92d7ef32f4830a4061dd2f3eee992cf35c2e8877 Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Fri, 10 Jun 2016 03:21:54 +0200 Subject: [PATCH] Multiple constrained bones for transform constraints. --- .../spine/PathConstraint.java | 8 +- .../com/esotericsoftware/spine/Skeleton.java | 20 ++- .../spine/SkeletonBinary.java | 3 +- .../esotericsoftware/spine/SkeletonJson.java | 9 +- .../spine/TransformConstraint.java | 114 +++++++++--------- .../spine/TransformConstraintData.java | 14 +-- 6 files changed, 86 insertions(+), 82 deletions(-) diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java index 1d519d6b2..b9c4b1460 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java @@ -27,14 +27,14 @@ public class PathConstraint implements Updatable { if (data == null) throw new IllegalArgumentException("data cannot be null."); if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); this.data = data; - position = data.position; - spacing = data.spacing; - rotateMix = data.rotateMix; - translateMix = data.translateMix; bones = new Array(data.bones.size); for (BoneData boneData : data.bones) bones.add(skeleton.findBone(boneData.name)); target = skeleton.findSlot(data.target.name); + position = data.position; + spacing = data.spacing; + rotateMix = data.rotateMix; + translateMix = data.translateMix; } /** Copy constructor. */ diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java index af01157d9..4840ba15b 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java @@ -227,21 +227,17 @@ public class Skeleton { sortBone(constraint.target); - // BOZO! - Update transform constraints to support multiple constrained bones. - // Array constrained = constraint.bones; - // int boneCount = constrained.size; - // for (int ii = 0; ii < boneCount; ii++) - // sortBone(constrained.get(ii)); - sortBone(constraint.bone); + Array constrained = constraint.bones; + int boneCount = constrained.size; + for (int ii = 0; ii < boneCount; ii++) + sortBone(constrained.get(ii)); updateCache.add(constraint); - // for (int ii = 0; ii < boneCount; ii++) - // reset(constrained.get(ii).children); - sortReset(constraint.bone.children); // BOZO - Remove. - // for (int ii = 0; ii < boneCount; ii++) - // constrained.get(ii).sorted = true; - constraint.bone.sorted = true; // BOZO - Remove. + for (int ii = 0; ii < boneCount; ii++) + sortReset(constrained.get(ii).children); + for (int ii = 0; ii < boneCount; ii++) + constrained.get(ii).sorted = true; } for (int i = 0, n = bones.size; i < n; i++) diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java index 36e54b601..a24fe562f 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java @@ -217,7 +217,8 @@ public class SkeletonBinary { // Transform constraints. for (int i = 0, n = input.readInt(true); i < n; i++) { TransformConstraintData data = new TransformConstraintData(input.readString()); - data.bone = skeletonData.bones.get(input.readInt(true)); + for (int ii = 0, nn = input.readInt(true); ii < nn; ii++) + data.bones.add(skeletonData.bones.get(input.readInt(true))); data.target = skeletonData.bones.get(input.readInt(true)); data.offsetRotation = input.readFloat(); data.offsetX = input.readFloat() * scale; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java index b966f3cc7..5a49e17c3 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java @@ -179,9 +179,12 @@ public class SkeletonJson { for (JsonValue constraintMap = root.getChild("transform"); constraintMap != null; constraintMap = constraintMap.next) { TransformConstraintData data = new TransformConstraintData(constraintMap.getString("name")); - String boneName = constraintMap.getString("bone"); - data.bone = skeletonData.findBone(boneName); - if (data.bone == null) throw new SerializationException("Bone not found: " + boneName); + for (JsonValue boneMap = constraintMap.getChild("bones"); boneMap != null; boneMap = boneMap.next) { + String boneName = boneMap.asString(); + BoneData bone = skeletonData.findBone(boneName); + if (bone == null) throw new SerializationException("Path bone not found: " + boneName); + data.bones.add(bone); + } String targetName = constraintMap.getString("target"); data.target = skeletonData.findBone(targetName); diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java index bf484eb36..2b6be66cd 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java @@ -4,10 +4,12 @@ package com.esotericsoftware.spine; import static com.badlogic.gdx.math.MathUtils.*; import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.Array; public class TransformConstraint implements Updatable { final TransformConstraintData data; - Bone bone, target; + final Array bones; + Bone target; float rotateMix, translateMix, scaleMix, shearMix; final Vector2 temp = new Vector2(); @@ -19,7 +21,9 @@ public class TransformConstraint implements Updatable { translateMix = data.translateMix; scaleMix = data.scaleMix; shearMix = data.shearMix; - bone = skeleton.findBone(data.bone.name); + bones = new Array(data.bones.size); + for (BoneData boneData : data.bones) + bones.add(skeleton.findBone(boneData.name)); target = skeleton.findBone(data.target.name); } @@ -28,12 +32,14 @@ public class TransformConstraint implements Updatable { if (constraint == null) throw new IllegalArgumentException("constraint cannot be null."); if (skeleton == null) throw new IllegalArgumentException("skeleton cannot be null."); data = constraint.data; + bones = new Array(constraint.bones.size); + for (Bone bone : constraint.bones) + bones.add(skeleton.bones.get(bone.data.index)); + target = skeleton.bones.get(constraint.target.data.index); rotateMix = constraint.rotateMix; translateMix = constraint.translateMix; scaleMix = constraint.scaleMix; shearMix = constraint.shearMix; - bone = skeleton.bones.get(constraint.bone.data.index); - target = skeleton.bones.get(constraint.target.data.index); } public void apply () { @@ -41,64 +47,64 @@ public class TransformConstraint implements Updatable { } public void update () { - Bone bone = this.bone; + float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; Bone target = this.target; + float ta = target.a, tb = target.b, tc = target.c, td = target.d; + Array bones = this.bones; + for (int i = 0, n = bones.size; i < n; i++) { + Bone bone = bones.get(i); - if (rotateMix > 0) { - float a = bone.a, b = bone.b, c = bone.c, d = bone.d; - float r = atan2(target.c, target.a) - atan2(c, a) + data.offsetRotation * degRad; - if (r > PI) - r -= PI2; - else if (r < -PI) r += PI2; - r *= rotateMix; - float cos = cos(r), sin = sin(r); - bone.a = cos * a - sin * c; - bone.b = cos * b - sin * d; - bone.c = sin * a + cos * c; - bone.d = sin * b + cos * d; - } + if (rotateMix > 0) { + float a = bone.a, b = bone.b, c = bone.c, d = bone.d; + float r = atan2(tc, ta) - atan2(c, a) + data.offsetRotation * degRad; + if (r > PI) + r -= PI2; + else if (r < -PI) r += PI2; + r *= rotateMix; + float cos = cos(r), sin = sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } - if (scaleMix > 0) { - float bs = (float)Math.sqrt(bone.a * bone.a + bone.c * bone.c); - float ts = (float)Math.sqrt(target.a * target.a + target.c * target.c); - float s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleX) * scaleMix) / bs : 0; - bone.a *= s; - bone.c *= s; - bs = (float)Math.sqrt(bone.b * bone.b + bone.d * bone.d); - ts = (float)Math.sqrt(target.b * target.b + target.d * target.d); - s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleY) * scaleMix) / bs : 0; - bone.b *= s; - bone.d *= s; - } + if (translateMix > 0) { + Vector2 temp = this.temp; + target.localToWorld(temp.set(data.offsetX, data.offsetY)); + bone.worldX += (temp.x - bone.worldX) * translateMix; + bone.worldY += (temp.y - bone.worldY) * translateMix; + } - if (shearMix > 0) { - float b = bone.b, d = bone.d; - float by = atan2(d, b); - float r = atan2(target.d, target.b) - atan2(target.c, target.a) - (by - atan2(bone.c, bone.a)); - if (r > PI) - r -= PI2; - else if (r < -PI) r += PI2; - r = by + (r + data.offsetShearY * degRad) * shearMix; - float s = (float)Math.sqrt(b * b + d * d); - bone.b = cos(r) * s; - bone.d = sin(r) * s; - } + if (scaleMix > 0) { + float bs = (float)Math.sqrt(bone.a * bone.a + bone.c * bone.c); + float ts = (float)Math.sqrt(ta * ta + tc * tc); + float s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleX) * scaleMix) / bs : 0; + bone.a *= s; + bone.c *= s; + bs = (float)Math.sqrt(bone.b * bone.b + bone.d * bone.d); + ts = (float)Math.sqrt(tb * tb + td * td); + s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleY) * scaleMix) / bs : 0; + bone.b *= s; + bone.d *= s; + } - float translateMix = this.translateMix; - if (translateMix > 0) { - Vector2 temp = this.temp; - target.localToWorld(temp.set(data.offsetX, data.offsetY)); - bone.worldX += (temp.x - bone.worldX) * translateMix; - bone.worldY += (temp.y - bone.worldY) * translateMix; + if (shearMix > 0) { + float b = bone.b, d = bone.d; + float by = atan2(d, b); + float r = atan2(td, tb) - atan2(tc, ta) - (by - atan2(bone.c, bone.a)); + if (r > PI) + r -= PI2; + else if (r < -PI) r += PI2; + r = by + (r + data.offsetShearY * degRad) * shearMix; + float s = (float)Math.sqrt(b * b + d * d); + bone.b = cos(r) * s; + bone.d = sin(r) * s; + } } } - public Bone getBone () { - return bone; - } - - public void setBone (Bone bone) { - this.bone = bone; + public Array getBones () { + return bones; } public Bone getTarget () { diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java index 4a20acd5b..e20700526 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraintData.java @@ -1,9 +1,12 @@ package com.esotericsoftware.spine; +import com.badlogic.gdx.utils.Array; + public class TransformConstraintData { final String name; - BoneData bone, target; + final Array bones = new Array(); + BoneData target; float rotateMix, translateMix, scaleMix, shearMix; float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY; @@ -16,13 +19,8 @@ public class TransformConstraintData { return name; } - public BoneData getBone () { - return bone; - } - - public void setBone (BoneData bone) { - if (bone == null) throw new IllegalArgumentException("bone cannot be null."); - this.bone = bone; + public Array getBones () { + return bones; } public BoneData getTarget () {