diff --git a/.gitignore b/.gitignore index 13d206e55..c34459ead 100644 --- a/.gitignore +++ b/.gitignore @@ -102,3 +102,5 @@ spine-starling/spine-starling-example/lib/.spine-starling.swc.stamp spine-turbulenz/spine-js/spine.js spine-threejs/spine-js/spine.js + +spine-ts/.vscode/* diff --git a/spine-libgdx/spine-libgdx/.settings/org.eclipse.jdt.core.prefs b/spine-libgdx/spine-libgdx/.settings/org.eclipse.jdt.core.prefs index b1afb4ec3..13db62da1 100644 --- a/spine-libgdx/spine-libgdx/.settings/org.eclipse.jdt.core.prefs +++ b/spine-libgdx/spine-libgdx/.settings/org.eclipse.jdt.core.prefs @@ -33,7 +33,7 @@ org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=disabled org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning -org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning +org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning @@ -84,6 +84,7 @@ org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=enabled +org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore org.eclipse.jdt.core.compiler.problem.unusedImport=warning org.eclipse.jdt.core.compiler.problem.unusedLabel=warning org.eclipse.jdt.core.compiler.problem.unusedLocal=warning diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java index 43afb22c8..8183a362e 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java @@ -721,35 +721,33 @@ public class Animation { // BOZO - Test. if (alpha == 1) { - // Absolute. + // Vertex positions or deform offsets, no alpha. for (int i = 0; i < vertexCount; i++) { float prev = prevVertices[i]; vertices[i] = prev + (nextVertices[i] - prev) * percent; } - } else { - if (setupPose) { - VertexAttachment vertexAttachment = (VertexAttachment)slotAttachment; - if (vertexAttachment.getBones() == null) { - // Vertex positions. - float[] setupVertices = vertexAttachment.getVertices(); - for (int i = 0; i < vertexCount; i++) { - float prev = prevVertices[i], setup = setupVertices[i]; - vertices[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha; - } - } else { - // Deform offsets. - for (int i = 0; i < vertexCount; i++) { - float prev = prevVertices[i]; - vertices[i] = (prev + (nextVertices[i] - prev) * percent) * alpha; - } + } else if (setupPose) { + VertexAttachment vertexAttachment = (VertexAttachment)slotAttachment; + if (vertexAttachment.getBones() == null) { + // Unweighted vertex positions, with alpha. + float[] setupVertices = vertexAttachment.getVertices(); + for (int i = 0; i < vertexCount; i++) { + float prev = prevVertices[i], setup = setupVertices[i]; + vertices[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha; } } else { - // Additive. + // Weighted deform offsets, with alpha. for (int i = 0; i < vertexCount; i++) { float prev = prevVertices[i]; - vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha; + vertices[i] = (prev + (nextVertices[i] - prev) * percent) * alpha; } } + } else { + // Vertex positions or deform offsets, with alpha. + for (int i = 0; i < vertexCount; i++) { + float prev = prevVertices[i]; + vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha; + } } } } @@ -918,6 +916,8 @@ public class Animation { float[] frames = this.frames; if (time < frames[0]) return; // Time is before first frame. + // BOZO - Finish timelines handling setupPose and mixingOut from here down. + IkConstraint constraint = skeleton.ikConstraints.get(ikConstraintIndex); if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. 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 d628415e0..20ed4dc58 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java @@ -37,6 +37,7 @@ import static com.badlogic.gdx.math.Matrix3.*; import com.badlogic.gdx.math.Matrix3; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Array; +import com.esotericsoftware.spine.BoneData.TransformMode; public class Bone implements Updatable { final BoneData data; @@ -100,12 +101,13 @@ public class Bone implements Updatable { ashearY = shearY; appliedValid = true; - float rotationY = rotation + 90 + shearY; - float la = cosDeg(rotation + shearX) * scaleX, lb = cosDeg(rotationY) * scaleY; - float lc = sinDeg(rotation + shearX) * scaleX, ld = sinDeg(rotationY) * scaleY; - Bone parent = this.parent; if (parent == null) { // Root bone. + float rotationY = rotation + 90 + shearY; + float la = cosDeg(rotation + shearX) * scaleX; + float lb = cosDeg(rotationY) * scaleY; + float lc = sinDeg(rotation + shearX) * scaleX; + float ld = sinDeg(rotationY) * scaleY; Skeleton skeleton = this.skeleton; if (skeleton.flipX) { x = -x; @@ -130,28 +132,99 @@ public class Bone implements Updatable { worldX = pa * x + pb * y + parent.worldX; worldY = pc * x + pd * y + parent.worldY; - if (data.inheritRotation && data.inheritScale) { + switch (data.transformMode) { + case normal: { + float rotationY = rotation + 90 + shearY; + float la = cosDeg(rotation + shearX) * scaleX; + float lb = cosDeg(rotationY) * scaleY; + float lc = sinDeg(rotation + shearX) * scaleX; + float ld = sinDeg(rotationY) * scaleY; a = pa * la + pb * lc; b = pa * lb + pb * ld; c = pc * la + pd * lc; d = pc * lb + pd * ld; - } else { - if (data.inheritRotation) { // No scale inheritance. - float psx = (float)Math.sqrt(pa * pa + pc * pc); - float psy = (float)Math.sqrt(pb * pb + pd * pd); - if (psx > 0.0001f) { - pa /= psx; - pc /= psx; - } - if (psy > 0.0001f) { - pb /= psy; - pd /= psy; + return; + } + case onlyTranslation: { + float rotationY = rotation + 90 + shearY; + a = cosDeg(rotation + shearX) * scaleX; + b = cosDeg(rotationY) * scaleY; + c = sinDeg(rotation + shearX) * scaleX; + d = sinDeg(rotationY) * scaleY; + break; + } + case noRotation: { + if (false) { + // Summing parent rotations. + // 1) Negative parent scale causes bone to rotate. + float sum = 0; + Bone current = parent; + while (current != null) { + sum += current.arotation; + current = current.parent; } + rotation -= sum; + float rotationY = rotation + 90 + shearY; + float la = cosDeg(rotation + shearX) * scaleX; + float lb = cosDeg(rotationY) * scaleY; + float lc = sinDeg(rotation + shearX) * scaleX; + float ld = sinDeg(rotationY) * scaleY; a = pa * la + pb * lc; b = pa * lb + pb * ld; c = pc * la + pd * lc; d = pc * lb + pd * ld; - } else if (data.inheritScale) { // No rotation inheritance. + } else if (true) { + // Old way. + // 1) Immediate parent scale is applied in wrong direction. + // 2) Negative parent scale causes bone to rotate. + pa = 1; + pb = 0; + pc = 0; + pd = 1; + float rotationY, la, lb, lc, ld; + outer: + do { + if (!parent.appliedValid) parent.updateAppliedTransform(); + float pr = parent.arotation, psx = parent.ascaleX; + rotationY = pr + 90 + parent.ashearY; + la = cosDeg(pr + parent.shearX); + lb = cosDeg(rotationY); + lc = sinDeg(pr + parent.shearX); + ld = sinDeg(rotationY); + float temp = (pa * la + pb * lc) * psx; + pb = (pb * ld + pa * lb) * parent.ascaleY; + pa = temp; + temp = (pc * la + pd * lc) * psx; + pd = (pd * ld + pc * lb) * parent.ascaleY; + pc = temp; + + if (psx < 0) lc = -lc; + temp = pa * la - pb * lc; + pb = pb * ld - pa * lb; + pa = temp; + temp = pc * la - pd * lc; + pd = pd * ld - pc * lb; + pc = temp; + + switch (parent.data.transformMode) { + case noScale: + case noScaleOrReflection: + break outer; + } + parent = parent.parent; + } while (parent != null); + rotationY = rotation + 90 + shearY; + la = cosDeg(rotation + shearX) * scaleX; + lb = cosDeg(rotationY) * scaleY; + lc = sinDeg(rotation + shearX) * scaleX; + ld = sinDeg(rotationY) * scaleY; + a = pa * la + pb * lc; + b = pa * lb + pb * ld; + c = pc * la + pd * lc; + d = pc * lb + pd * ld; + } else { + // New way. + // 1) Negative scale can cause bone to flip. float psx = (float)Math.sqrt(pa * pa + pc * pc), psy, pr; if (psx > 0.0001f) { float det = pa * pd - pb * pc; @@ -173,24 +246,57 @@ public class Bone implements Updatable { blend = 1 - (pr - 90) / 90; pa = psx + (Math.abs(psy) * Math.signum(psx) - psx) * blend; pd = psy + (Math.abs(psx) * Math.signum(psy) - psy) * blend; - a = pa * la; - b = pa * lb; - c = pd * lc; - d = pd * ld; - } else { - a = la; - b = lb; - c = lc; - d = ld; + float rotationY = rotation + 90 + shearY; + a = pa * cosDeg(rotation + shearX) * scaleX; + b = pa * cosDeg(rotationY) * scaleY; + c = pd * sinDeg(rotation + shearX) * scaleX; + d = pd * sinDeg(rotationY) * scaleY; } - if (skeleton.flipX) { - a = -a; + break; + } + case noScale: + case noScaleOrReflection: { + float cos = cosDeg(rotation), sin = sinDeg(rotation); + float za = pa * cos + pb * sin, zb = za; + float zc = pc * cos + pd * sin, zd = zc; + float s = (float)Math.sqrt(za * za + zc * zc); + if (s > 0.00001f) s = 1 / s; + za *= s; + zc *= s; + s = (float)Math.sqrt(zb * zb + zd * zd); + if (s > 0.00001f) s = 1 / s; + zb *= s; + zd *= s; + float by = atan2(zd, zb), r = PI / 2 - (by - atan2(zc, za)); + if (r > PI) + r -= PI2; + else if (r < -PI) r += PI2; + r += by; + s = (float)Math.sqrt(zb * zb + zd * zd); + zb = cos(r) * s; + zd = sin(r) * s; + float la = cosDeg(shearX) * scaleX; + float lb = cosDeg(90 + shearY) * scaleY; + float lc = sinDeg(shearX) * scaleX; + float ld = sinDeg(90 + shearY) * scaleY; + a = za * la + zb * lc; + b = za * lb + zb * ld; + c = zc * la + zd * lc; + d = zc * lb + zd * ld; + if (data.transformMode != TransformMode.noScaleOrReflection ? pa * pd - pb * pc < 0 : skeleton.flipX != skeleton.flipY) { b = -b; - } - if (skeleton.flipY) { - c = -c; d = -d; } + return; + } + } + if (skeleton.flipX) { + a = -a; + b = -b; + } + if (skeleton.flipY) { + c = -c; + d = -d; } } diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BoneData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BoneData.java index 821403b95..12f412980 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BoneData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/BoneData.java @@ -39,7 +39,7 @@ public class BoneData { final BoneData parent; float length; float x, y, rotation, scaleX = 1, scaleY = 1, shearX, shearY; - boolean inheritRotation = true, inheritScale = true; + TransformMode transformMode = TransformMode.normal; // Nonessential. final Color color = new Color(0.61f, 0.61f, 0.61f, 1); @@ -157,20 +157,12 @@ public class BoneData { this.shearY = shearY; } - public boolean getInheritRotation () { - return inheritRotation; + public TransformMode getTransformMode () { + return transformMode; } - public void setInheritRotation (boolean inheritRotation) { - this.inheritRotation = inheritRotation; - } - - public boolean getInheritScale () { - return inheritScale; - } - - public void setInheritScale (boolean inheritScale) { - this.inheritScale = inheritScale; + public void setTransformMode (TransformMode transformMode) { + this.transformMode = transformMode; } public Color getColor () { @@ -180,4 +172,10 @@ public class BoneData { public String toString () { return name; } + + static public enum TransformMode { + normal, onlyTranslation, noRotation, noScale, noScaleOrReflection; + + static public final TransformMode[] values = TransformMode.values(); + } } 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 aa4ed70f0..53a34e91e 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java @@ -58,6 +58,7 @@ import com.esotericsoftware.spine.Animation.ShearTimeline; import com.esotericsoftware.spine.Animation.Timeline; import com.esotericsoftware.spine.Animation.TransformConstraintTimeline; import com.esotericsoftware.spine.Animation.TranslateTimeline; +import com.esotericsoftware.spine.BoneData.TransformMode; import com.esotericsoftware.spine.PathConstraintData.PositionMode; import com.esotericsoftware.spine.PathConstraintData.RotateMode; import com.esotericsoftware.spine.PathConstraintData.SpacingMode; @@ -186,8 +187,7 @@ public class SkeletonBinary { data.shearX = input.readFloat(); data.shearY = input.readFloat(); data.length = input.readFloat() * scale; - data.inheritRotation = input.readBoolean(); - data.inheritScale = input.readBoolean(); + data.transformMode = TransformMode.values[input.readInt(true)]; if (nonessential) Color.rgba8888ToColor(data.color, input.readInt()); skeletonData.bones.add(data); } 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 d920586ff..63bb5b6d2 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java @@ -56,6 +56,7 @@ import com.esotericsoftware.spine.Animation.ShearTimeline; import com.esotericsoftware.spine.Animation.Timeline; import com.esotericsoftware.spine.Animation.TransformConstraintTimeline; import com.esotericsoftware.spine.Animation.TranslateTimeline; +import com.esotericsoftware.spine.BoneData.TransformMode; import com.esotericsoftware.spine.PathConstraintData.PositionMode; import com.esotericsoftware.spine.PathConstraintData.RotateMode; import com.esotericsoftware.spine.PathConstraintData.SpacingMode; @@ -129,8 +130,7 @@ public class SkeletonJson { data.scaleY = boneMap.getFloat("scaleY", 1); data.shearX = boneMap.getFloat("shearX", 0); data.shearY = boneMap.getFloat("shearY", 0); - data.inheritRotation = boneMap.getBoolean("inheritRotation", true); - data.inheritScale = boneMap.getBoolean("inheritScale", true); + data.transformMode = TransformMode.valueOf(boneMap.getString("transform", TransformMode.normal.name())); String color = boneMap.getString("color", null); if (color != null) data.getColor().set(Color.valueOf(color)); 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 935c1cf4c..4e6e9a3fa 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/TransformConstraint.java @@ -79,14 +79,14 @@ public class TransformConstraint implements Constraint { } if (scaleMix > 0) { - float bs = (float)Math.sqrt(bone.a * bone.a + bone.c * bone.c); + float s = (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; + if (s > 0.00001f) s = (s + (ts - s + data.offsetScaleX) * scaleMix) / s; bone.a *= s; bone.c *= s; - bs = (float)Math.sqrt(bone.b * bone.b + bone.d * bone.d); + s = (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; + if (s > 0.00001f) s = (s + (ts - s + data.offsetScaleY) * scaleMix) / s; bone.b *= s; bone.d *= s; modified = true;