|
@@ -283,8 +283,150 @@ namespace Spine.Unity {
|
|
|
}
|
|
|
|
|
|
namespace Spine {
|
|
|
+ using System;
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
+ public struct BoneMatrix {
|
|
|
+ public float a, b, c, d, x, y;
|
|
|
+
|
|
|
+ /// <summary>Recursively calculates a worldspace bone matrix based on BoneData.</summary>
|
|
|
+ public static BoneMatrix CalculateSetupWorld (BoneData boneData) {
|
|
|
+ if (boneData == null)
|
|
|
+ return default(BoneMatrix);
|
|
|
+
|
|
|
+ // End condition: isRootBone
|
|
|
+ if (boneData.parent == null)
|
|
|
+ return GetInheritedInternal(boneData, default(BoneMatrix));
|
|
|
+
|
|
|
+ BoneMatrix result = CalculateSetupWorld(boneData.parent);
|
|
|
+ return GetInheritedInternal(boneData, result);
|
|
|
+ }
|
|
|
+
|
|
|
+ static BoneMatrix GetInheritedInternal (BoneData boneData, BoneMatrix parentMatrix) {
|
|
|
+ var parent = boneData.parent;
|
|
|
+ if (parent == null) return new BoneMatrix(boneData); // isRootBone
|
|
|
+
|
|
|
+ float pa = parentMatrix.a, pb = parentMatrix.b, pc = parentMatrix.c, pd = parentMatrix.d;
|
|
|
+ BoneMatrix result = default(BoneMatrix);
|
|
|
+ result.x = pa * boneData.x + pb * boneData.y + parentMatrix.x;
|
|
|
+ result.y = pc * boneData.x + pd * boneData.y + parentMatrix.y;
|
|
|
+
|
|
|
+ switch (boneData.transformMode) {
|
|
|
+ case TransformMode.Normal: {
|
|
|
+ float rotationY = boneData.rotation + 90 + boneData.shearY;
|
|
|
+ float la = MathUtils.CosDeg(boneData.rotation + boneData.shearX) * boneData.scaleX;
|
|
|
+ float lb = MathUtils.CosDeg(rotationY) * boneData.scaleY;
|
|
|
+ float lc = MathUtils.SinDeg(boneData.rotation + boneData.shearX) * boneData.scaleX;
|
|
|
+ float ld = MathUtils.SinDeg(rotationY) * boneData.scaleY;
|
|
|
+ result.a = pa * la + pb * lc;
|
|
|
+ result.b = pa * lb + pb * ld;
|
|
|
+ result.c = pc * la + pd * lc;
|
|
|
+ result.d = pc * lb + pd * ld;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case TransformMode.OnlyTranslation: {
|
|
|
+ float rotationY = boneData.rotation + 90 + boneData.shearY;
|
|
|
+ result.a = MathUtils.CosDeg(boneData.rotation + boneData.shearX) * boneData.scaleX;
|
|
|
+ result.b = MathUtils.CosDeg(rotationY) * boneData.scaleY;
|
|
|
+ result.c = MathUtils.SinDeg(boneData.rotation + boneData.shearX) * boneData.scaleX;
|
|
|
+ result.d = MathUtils.SinDeg(rotationY) * boneData.scaleY;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case TransformMode.NoRotationOrReflection: {
|
|
|
+ float s = pa * pa + pc * pc, prx;
|
|
|
+ if (s > 0.0001f) {
|
|
|
+ s = Math.Abs(pa * pd - pb * pc) / s;
|
|
|
+ pb = pc * s;
|
|
|
+ pd = pa * s;
|
|
|
+ prx = MathUtils.Atan2(pc, pa) * MathUtils.RadDeg;
|
|
|
+ } else {
|
|
|
+ pa = 0;
|
|
|
+ pc = 0;
|
|
|
+ prx = 90 - MathUtils.Atan2(pd, pb) * MathUtils.RadDeg;
|
|
|
+ }
|
|
|
+ float rx = boneData.rotation + boneData.shearX - prx;
|
|
|
+ float ry = boneData.rotation + boneData.shearY - prx + 90;
|
|
|
+ float la = MathUtils.CosDeg(rx) * boneData.scaleX;
|
|
|
+ float lb = MathUtils.CosDeg(ry) * boneData.scaleY;
|
|
|
+ float lc = MathUtils.SinDeg(rx) * boneData.scaleX;
|
|
|
+ float ld = MathUtils.SinDeg(ry) * boneData.scaleY;
|
|
|
+ result.a = pa * la - pb * lc;
|
|
|
+ result.b = pa * lb - pb * ld;
|
|
|
+ result.c = pc * la + pd * lc;
|
|
|
+ result.d = pc * lb + pd * ld;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ case TransformMode.NoScale:
|
|
|
+ case TransformMode.NoScaleOrReflection: {
|
|
|
+ float cos = MathUtils.CosDeg(boneData.rotation), sin = MathUtils.SinDeg(boneData.rotation);
|
|
|
+ float za = pa * cos + pb * sin;
|
|
|
+ float zc = pc * cos + pd * sin;
|
|
|
+ float s = (float)Math.Sqrt(za * za + zc * zc);
|
|
|
+ if (s > 0.00001f)
|
|
|
+ s = 1 / s;
|
|
|
+ za *= s;
|
|
|
+ zc *= s;
|
|
|
+ s = (float)Math.Sqrt(za * za + zc * zc);
|
|
|
+ float r = MathUtils.PI / 2 + MathUtils.Atan2(zc, za);
|
|
|
+ float zb = MathUtils.Cos(r) * s;
|
|
|
+ float zd = MathUtils.Sin(r) * s;
|
|
|
+ float la = MathUtils.CosDeg(boneData.shearX) * boneData.scaleX;
|
|
|
+ float lb = MathUtils.CosDeg(90 + boneData.shearY) * boneData.scaleY;
|
|
|
+ float lc = MathUtils.SinDeg(boneData.shearX) * boneData.scaleX;
|
|
|
+ float ld = MathUtils.SinDeg(90 + boneData.shearY) * boneData.scaleY;
|
|
|
+ if (boneData.transformMode != TransformMode.NoScaleOrReflection ? pa * pd - pb * pc < 0 : false) {
|
|
|
+ zb = -zb;
|
|
|
+ zd = -zd;
|
|
|
+ }
|
|
|
+ result.a = za * la + zb * lc;
|
|
|
+ result.b = za * lb + zb * ld;
|
|
|
+ result.c = zc * la + zd * lc;
|
|
|
+ result.d = zc * lb + zd * ld;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return result;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>Constructor for a local bone matrix based on Setup Pose BoneData.</summary>
|
|
|
+ public BoneMatrix (BoneData boneData) {
|
|
|
+ float rotationY = boneData.rotation + 90 + boneData.shearY;
|
|
|
+ float rotationX = boneData.rotation + boneData.shearX;
|
|
|
+
|
|
|
+ a = MathUtils.CosDeg(rotationX) * boneData.scaleX;
|
|
|
+ c = MathUtils.SinDeg(rotationX) * boneData.scaleX;
|
|
|
+ b = MathUtils.CosDeg(rotationY) * boneData.scaleY;
|
|
|
+ d = MathUtils.SinDeg(rotationY) * boneData.scaleY;
|
|
|
+ x = boneData.x;
|
|
|
+ y = boneData.y;
|
|
|
+ }
|
|
|
+
|
|
|
+ /// <summary>Constructor for a local bone matrix based on a bone instance's current pose.</summary>
|
|
|
+ public BoneMatrix (Bone bone) {
|
|
|
+ float rotationY = bone.rotation + 90 + bone.shearY;
|
|
|
+ float rotationX = bone.rotation + bone.shearX;
|
|
|
+
|
|
|
+ a = MathUtils.CosDeg(rotationX) * bone.scaleX;
|
|
|
+ c = MathUtils.SinDeg(rotationX) * bone.scaleX;
|
|
|
+ b = MathUtils.CosDeg(rotationY) * bone.scaleY;
|
|
|
+ d = MathUtils.SinDeg(rotationY) * bone.scaleY;
|
|
|
+ x = bone.x;
|
|
|
+ y = bone.y;
|
|
|
+ }
|
|
|
+
|
|
|
+ public BoneMatrix TransformMatrix (BoneMatrix local) {
|
|
|
+ return new BoneMatrix {
|
|
|
+ a = this.a * local.a + this.b * local.c,
|
|
|
+ b = this.a * local.b + this.b * local.d,
|
|
|
+ c = this.c * local.a + this.d * local.c,
|
|
|
+ d = this.c * local.b + this.d * local.d,
|
|
|
+ x = this.a * local.x + this.b * local.y + this.x,
|
|
|
+ y = this.c * local.x + this.d * local.y + this.y
|
|
|
+ };
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
public static class SkeletonExtensions {
|
|
|
public static bool IsWeighted (this VertexAttachment va) {
|
|
|
return va.bones != null && va.bones.Length > 0;
|