From 217aa60c4f533feca8028242606633c6be0c0d92 Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Sat, 13 Aug 2016 08:38:41 +0200 Subject: [PATCH] Finished "applied transform" for arbitrary constraint order. --- .../src/com/esotericsoftware/spine/Bone.java | 121 +++++++++--------- .../esotericsoftware/spine/IkConstraint.java | 8 +- .../spine/PathConstraint.java | 1 + .../com/esotericsoftware/spine/Skeleton.java | 18 ++- .../spine/TransformConstraint.java | 7 + 5 files changed, 87 insertions(+), 68 deletions(-) diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java index bfd736954..8a47c74b8 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java @@ -45,7 +45,7 @@ public class Bone implements Updatable { final Array children = new Array(); float x, y, rotation, scaleX, scaleY, shearX, shearY; float ax, ay, arotation, ascaleX, ascaleY, ashearX, ashearY; - boolean appliedValid; // BOZO! - Use everywhere. + boolean appliedValid; float a, b, worldX; float c, d, worldY; @@ -99,6 +99,7 @@ public class Bone implements Updatable { ascaleY = scaleY; ashearX = shearX; ashearY = shearY; + appliedValid = true; float rotationY = rotation + 90 + shearY; float la = cosDeg(rotation + shearX) * scaleX, lb = cosDeg(rotationY) * scaleY; @@ -162,71 +163,71 @@ public class Bone implements Updatable { b = cos(r) * s; d = sin(r) * s; } else if (data.inheritScale) { // No rotation inheritance. - float psx = (float)Math.sqrt(pa * pa + pc * pc), psy, pr; - if (psx > 0.0001f) { - float det = pa * pd - pb * pc; - psy = det / psx; - rotationY = atan2(pa * pb + pc * pd, det) * radDeg + 90; - pr = atan2(pc, pa) * radDeg; - } else { - psx = 0; - psy = (float)Math.sqrt(pb * pb + pd * pd); - rotationY = 90; - pr = 90 - atan2(pd, pb) * radDeg; - } + // float psx = (float)Math.sqrt(pa * pa + pc * pc), psy, pr; + // if (psx > 0.0001f) { + // float det = pa * pd - pb * pc; + // psy = det / psx; + // rotationY = atan2(pa * pb + pc * pd, det) * radDeg + 90; + // pr = atan2(pc, pa) * radDeg; + // } else { + // psx = 0; + // psy = (float)Math.sqrt(pb * pb + pd * pd); + // rotationY = 90; + // pr = 90 - atan2(pd, pb) * radDeg; + // } + // + // float blend; + // if (pr < -90) + // blend = 1 + (pr + 90) / 90; + // else if (pr < 0) + // blend = -pr / 90; + // else if (pr < 90) + // blend = pr / 90; + // else + // blend = 1f - (pr - 90) / 90; + // + // pa = lerp(psx, Math.abs(psy) * Math.signum(psx), blend); + // psy = lerp(psy, Math.abs(psx) * Math.signum(psy), blend); + // pb = cosDeg(rotationY) * psy; + // pc = 0; + // pd = sinDeg(rotationY) * psy; + // + // a = pa * la + pb * lc; + // b = pa * lb + pb * ld; + // c = pc * la + pd * lc; + // d = pc * lb + pd * ld; - float blend; - if (pr < -90) - blend = 1 + (pr + 90) / 90; - else if (pr < 0) - blend = -pr / 90; - else if (pr < 90) - blend = pr / 90; - else - blend = 1f - (pr - 90) / 90; - - pa = lerp(psx, Math.abs(psy) * Math.signum(psx), blend); - psy = lerp(psy, Math.abs(psx) * Math.signum(psy), blend); - pb = cosDeg(rotationY) * psy; + pa = 1; + pb = 0; pc = 0; - pd = sinDeg(rotationY) * psy; + pd = 1; + do { + float cos = cosDeg(parent.arotation), sin = sinDeg(parent.arotation); + float psx = parent.ascaleX, psy = parent.ascaleY; + float za = cos * psx, zb = sin * psy, zc = sin * psx, zd = cos * psy; + float temp = pa * za + pb * zc; + pb = pb * zd - pa * zb; + pa = temp; + temp = pc * za + pd * zc; + pd = pd * zd - pc * zb; + pc = temp; + if (psx >= 0) // BOZO! - Why? Should always do this? Fix in new code? + sin = -sin; + temp = pa * cos + pb * sin; + pb = pb * cos - pa * sin; + pa = temp; + temp = pc * cos + pd * sin; + pd = pd * cos - pc * sin; + pc = temp; + + if (!parent.data.inheritScale) break; + parent = parent.parent; + } while (parent != null); a = pa * la + pb * lc; b = pa * lb + pb * ld; c = pc * la + pd * lc; d = pc * lb + pd * ld; - -// pa = 1; -// pb = 0; -// pc = 0; -// pd = 1; -// do { -// float cos = cosDeg(parent.arotation), sin = sinDeg(parent.arotation); -// float psx = parent.ascaleX, psy = parent.ascaleY; -// float za = cos * psx, zb = sin * psy, zc = sin * psx, zd = cos * psy; -// float temp = pa * za + pb * zc; -// pb = pb * zd - pa * zb; -// pa = temp; -// temp = pc * za + pd * zc; -// pd = pd * zd - pc * zb; -// pc = temp; -// -// if (psx >= 0) // BOZO! - Why? Should always do this? Fix in new code? -// sin = -sin; -// temp = pa * cos + pb * sin; -// pb = pb * cos - pa * sin; -// pa = temp; -// temp = pc * cos + pd * sin; -// pd = pd * cos - pc * sin; -// pc = temp; -// -// if (!parent.data.inheritScale) break; -// parent = parent.parent; -// } while (parent != null); -// a = pa * la + pb * lc; -// b = pa * lb + pb * ld; -// c = pc * la + pd * lc; -// d = pc * lb + pd * ld; } else { a = la; b = lb; @@ -411,6 +412,7 @@ public class Bone implements Updatable { this.b = cos * b - sin * d; this.c = sin * a + cos * c; this.d = sin * b + cos * d; + appliedValid = false; } /** Computes the individual applied transform values from the world transform. This can be useful to perform processing using @@ -418,6 +420,7 @@ public class Bone implements Updatable { *

* Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. */ public void updateAppliedTransform () { + appliedValid = true; Bone parent = this.parent; if (parent == null) { ax = worldX; diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java index e8074b252..40dc12c99 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java @@ -128,6 +128,7 @@ public class IkConstraint implements Constraint { /** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world * coordinate system. */ static public void apply (Bone bone, float targetX, float targetY, float alpha) { + if (!bone.appliedValid) bone.updateAppliedTransform(); Bone p = bone.parent; float id = 1 / (p.a * p.d - p.b * p.c); float x = targetX - p.worldX, y = targetY - p.worldY; @@ -149,11 +150,8 @@ public class IkConstraint implements Constraint { child.updateWorldTransform(); return; } - - // BOZO! - Only when each bone needs it. - // child.updateLocalTransform(); - // parent.updateLocalTransform(); - + if (!parent.appliedValid) parent.updateAppliedTransform(); + if (!child.appliedValid) child.updateAppliedTransform(); float px = parent.ax, py = parent.ay, psx = parent.ascaleX, psy = parent.ascaleY, csx = child.ascaleX; int os1, os2, s2; if (psx < 0) { 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 6f048a133..2dff74a6a 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/PathConstraint.java @@ -137,6 +137,7 @@ public class PathConstraint implements Constraint { bone.c = sin * a + cos * c; bone.d = sin * b + cos * d; } + bone.appliedValid = false; } } 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 e2055c45e..8c5aae6d4 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java @@ -60,7 +60,10 @@ public class Skeleton { float x, y; final Comparator constraintComparator = new Comparator() { - public int compare (Constraint o1,Constraint o2){return o1.getOrder()-o2.getOrder();}}; + public int compare (Constraint o1, Constraint o2) { + return o1.getOrder() - o2.getOrder(); + } + }; public Skeleton (SkeletonData data) { if (data == null) throw new IllegalArgumentException("data cannot be null."); @@ -152,11 +155,11 @@ public class Skeleton { public void updateCache () { Array updateCache = this.updateCache; updateCache.clear(); - + Array bones = this.bones; for (int i = 0, n = bones.size; i < n; i++) bones.get(i).sorted = false; - + Array constraints = sortedConstraints; constraints.addAll(ikConstraints); constraints.addAll(transformConstraints); @@ -172,9 +175,16 @@ public class Skeleton { sortPathConstraint((PathConstraint)constraint); } constraints.clear(); - + for (int i = 0, n = bones.size; i < n; i++) sortBone(bones.get(i)); + + // BOZO +// for (int i = 0, n = updateCache.size; i < n; i++) { +// Updatable item = updateCache.get(i); +// if (item instanceof Constraint) System.out.print(item + ", "); +// } +// System.out.println(); } private void sortIkConstraint (IkConstraint constraint) { 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 fbe56d777..935c1cf4c 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java @@ -53,6 +53,7 @@ public class TransformConstraint implements Constraint { Array bones = this.bones; for (int i = 0, n = bones.size; i < n; i++) { Bone bone = bones.get(i); + boolean modified = false; if (rotateMix != 0) { float a = bone.a, b = bone.b, c = bone.c, d = bone.d; @@ -66,6 +67,7 @@ public class TransformConstraint implements Constraint { bone.b = cos * b - sin * d; bone.c = sin * a + cos * c; bone.d = sin * b + cos * d; + modified = true; } if (translateMix != 0) { @@ -73,6 +75,7 @@ public class TransformConstraint implements Constraint { target.localToWorld(temp.set(data.offsetX, data.offsetY)); bone.worldX += (temp.x - bone.worldX) * translateMix; bone.worldY += (temp.y - bone.worldY) * translateMix; + modified = true; } if (scaleMix > 0) { @@ -86,6 +89,7 @@ public class TransformConstraint implements Constraint { s = bs > 0.00001f ? (bs + (ts - bs + data.offsetScaleY) * scaleMix) / bs : 0; bone.b *= s; bone.d *= s; + modified = true; } if (shearMix > 0) { @@ -99,7 +103,10 @@ public class TransformConstraint implements Constraint { float s = (float)Math.sqrt(b * b + d * d); bone.b = cos(r) * s; bone.d = sin(r) * s; + modified = true; } + + if (modified) bone.appliedValid = false; } }