From a62e4466dd5d26235bd71159108fa00be7526f30 Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Wed, 11 Jul 2018 04:44:56 +0200 Subject: [PATCH 01/15] Added stretchy IK. --- .../com/esotericsoftware/spine/Animation.java | 43 +++++++++++++----- .../esotericsoftware/spine/IkConstraint.java | 45 ++++++++++++++----- .../spine/IkConstraintData.java | 11 +++++ .../com/esotericsoftware/spine/Skeleton.java | 1 + .../spine/SkeletonBinary.java | 3 +- .../esotericsoftware/spine/SkeletonJson.java | 3 +- 6 files changed, 81 insertions(+), 25 deletions(-) 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 d4a2ca6dd..6fa9f2d8c 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Animation.java @@ -37,6 +37,7 @@ import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.FloatArray; + import com.esotericsoftware.spine.attachments.Attachment; import com.esotericsoftware.spine.attachments.VertexAttachment; @@ -1294,11 +1295,12 @@ public class Animation { } } - /** Changes an IK constraint's {@link IkConstraint#getMix()} and {@link IkConstraint#getBendDirection()}. */ + /** Changes an IK constraint's {@link IkConstraint#getMix()}, {@link IkConstraint#getBendDirection()}, and + * {@link IkConstraint#getStretch()}. */ static public class IkConstraintTimeline extends CurveTimeline { - static public final int ENTRIES = 3; - static private final int PREV_TIME = -3, PREV_MIX = -2, PREV_BEND_DIRECTION = -1; - static private final int MIX = 1, BEND_DIRECTION = 2; + static public final int ENTRIES = 4; + static private final int PREV_TIME = -4, PREV_MIX = -3, PREV_BEND_DIRECTION = -2, PREV_STRETCH = -1; + static private final int MIX = 1, BEND_DIRECTION = 2, STRETCH = 3; int ikConstraintIndex; private final float[] frames; // time, mix, bendDirection, ... @@ -1328,11 +1330,12 @@ public class Animation { } /** Sets the time in seconds, mix, and bend direction for the specified key frame. */ - public void setFrame (int frameIndex, float time, float mix, int bendDirection) { + public void setFrame (int frameIndex, float time, float mix, int bendDirection, boolean stretch) { frameIndex *= ENTRIES; frames[frameIndex] = time; frames[frameIndex + MIX] = mix; frames[frameIndex + BEND_DIRECTION] = bendDirection; + frames[frameIndex + STRETCH] = stretch ? 1 : 0; } public void apply (Skeleton skeleton, float lastTime, float time, Array events, float alpha, MixBlend blend, @@ -1345,10 +1348,12 @@ public class Animation { case setup: constraint.mix = constraint.data.mix; constraint.bendDirection = constraint.data.bendDirection; + constraint.stretch = constraint.data.stretch; return; case first: constraint.mix += (constraint.data.mix - constraint.mix) * alpha; constraint.bendDirection = constraint.data.bendDirection; + constraint.stretch = constraint.data.stretch; } return; } @@ -1356,11 +1361,19 @@ public class Animation { if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame. if (blend == setup) { constraint.mix = constraint.data.mix + (frames[frames.length + PREV_MIX] - constraint.data.mix) * alpha; - constraint.bendDirection = direction == out ? constraint.data.bendDirection - : (int)frames[frames.length + PREV_BEND_DIRECTION]; + if (direction == out) { + constraint.bendDirection = constraint.data.bendDirection; + constraint.stretch = constraint.data.stretch; + } else { + constraint.bendDirection = (int)frames[frames.length + PREV_BEND_DIRECTION]; + constraint.stretch = frames[frames.length + PREV_STRETCH] != 0; + } } else { constraint.mix += (frames[frames.length + PREV_MIX] - constraint.mix) * alpha; - if (direction == in) constraint.bendDirection = (int)frames[frames.length + PREV_BEND_DIRECTION]; + if (direction == in) { + constraint.bendDirection = (int)frames[frames.length + PREV_BEND_DIRECTION]; + constraint.stretch = frames[frames.length + PREV_STRETCH] != 0; + } } return; } @@ -1373,11 +1386,19 @@ public class Animation { if (blend == setup) { constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha; - constraint.bendDirection = direction == out ? constraint.data.bendDirection - : (int)frames[frame + PREV_BEND_DIRECTION]; + if (direction == out) { + constraint.bendDirection = constraint.data.bendDirection; + constraint.stretch = constraint.data.stretch; + } else { + constraint.bendDirection = (int)frames[frame + PREV_BEND_DIRECTION]; + constraint.stretch = frames[frame + PREV_STRETCH] != 0; + } } else { constraint.mix += (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha; - if (direction == in) constraint.bendDirection = (int)frames[frame + PREV_BEND_DIRECTION]; + if (direction == in) { + constraint.bendDirection = (int)frames[frame + PREV_BEND_DIRECTION]; + constraint.stretch = frames[frame + PREV_STRETCH] != 0; + } } } } 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 d6128a332..0a7f8aa36 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java @@ -42,8 +42,9 @@ public class IkConstraint implements Constraint { final IkConstraintData data; final Array bones; Bone target; - float mix = 1; int bendDirection; + boolean stretch; + float mix = 1; public IkConstraint (IkConstraintData data, Skeleton skeleton) { if (data == null) throw new IllegalArgumentException("data cannot be null."); @@ -51,6 +52,7 @@ public class IkConstraint implements Constraint { this.data = data; mix = data.mix; bendDirection = data.bendDirection; + stretch = data.stretch; bones = new Array(data.bones.size); for (BoneData boneData : data.bones) @@ -69,6 +71,7 @@ public class IkConstraint implements Constraint { target = skeleton.bones.get(constraint.target.data.index); mix = constraint.mix; bendDirection = constraint.bendDirection; + stretch = constraint.stretch; } /** Applies the constraint to the constrained bones. */ @@ -81,10 +84,10 @@ public class IkConstraint implements Constraint { Array bones = this.bones; switch (bones.size) { case 1: - apply(bones.first(), target.worldX, target.worldY, mix); + apply(bones.first(), target.worldX, target.worldY, stretch, mix); break; case 2: - apply(bones.first(), bones.get(1), target.worldX, target.worldY, bendDirection, mix); + apply(bones.first(), bones.get(1), target.worldX, target.worldY, bendDirection, stretch, mix); break; } } @@ -125,6 +128,16 @@ public class IkConstraint implements Constraint { this.bendDirection = bendDirection; } + /** When true, if the target is out of range, the parent bone is scaled on the X axis to reach it. If the parent bone has local + * nonuniform scale, stretching is not applied. */ + public boolean getStretch () { + return stretch; + } + + public void setStretch (boolean stretch) { + this.stretch = stretch; + } + /** The IK constraint's setup pose data. */ public IkConstraintData getData () { return data; @@ -135,7 +148,7 @@ public class IkConstraint implements Constraint { } /** Applies 1 bone IK. The target is specified in the world coordinate system. */ - static public void apply (Bone bone, float targetX, float targetY, float alpha) { + static public void apply (Bone bone, float targetX, float targetY, boolean stretch, float alpha) { if (!bone.appliedValid) bone.updateAppliedTransform(); Bone p = bone.parent; float id = 1 / (p.a * p.d - p.b * p.c); @@ -146,20 +159,25 @@ public class IkConstraint implements Constraint { if (rotationIK > 180) rotationIK -= 360; else if (rotationIK < -180) rotationIK += 360; - bone.updateWorldTransform(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, bone.ascaleX, bone.ascaleY, bone.ashearX, + float sx = bone.ascaleX; + if (stretch) { + float dd = (float)Math.sqrt(tx * tx + ty * ty); + if (dd > bone.data.length * sx) sx *= (dd / (bone.data.length * sx) - 1) * alpha + 1; + } + bone.updateWorldTransform(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, bone.ascaleY, bone.ashearX, bone.ashearY); } /** Applies 2 bone IK. The target is specified in the world coordinate system. * @param child A direct descendant of the parent bone. */ - static public void apply (Bone parent, Bone child, float targetX, float targetY, int bendDir, float alpha) { + static public void apply (Bone parent, Bone child, float targetX, float targetY, int bendDir, boolean stretch, float alpha) { if (alpha == 0) { child.updateWorldTransform(); return; } 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; + float px = parent.ax, py = parent.ay, psx = parent.ascaleX, sx = psx, psy = parent.ascaleY, csx = child.ascaleX; int os1, os2, s2; if (psx < 0) { psx = -psx; @@ -195,7 +213,7 @@ public class IkConstraint implements Constraint { c = pp.c; d = pp.d; float id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY; - float tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py; + float tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py, dd = tx * tx + ty * ty; x = cwx - pp.worldX; y = cwy - pp.worldY; float dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; @@ -203,10 +221,13 @@ public class IkConstraint implements Constraint { outer: if (u) { l2 *= psx; - float cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); + float cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2); if (cos < -1) cos = -1; - else if (cos > 1) cos = 1; + else if (cos > 1) { + cos = 1; + if (stretch) sx *= ((float)Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1; + } a2 = (float)Math.acos(cos) * bendDir; a = l1 + l2 * cos; b = l2 * sin(a2); @@ -214,7 +235,7 @@ public class IkConstraint implements Constraint { } else { a = psx * l2; b = psy * l2; - float aa = a * a, bb = b * b, dd = tx * tx + ty * ty, ta = atan2(ty, tx); + float aa = a * a, bb = b * b, ta = atan2(ty, tx); c = bb * l1 * l1 + aa * dd - aa * bb; float c1 = -2 * bb * l1, c2 = bb - aa; d = c1 * c1 - 4 * c2 * c; @@ -266,7 +287,7 @@ public class IkConstraint implements Constraint { if (a1 > 180) a1 -= 360; else if (a1 < -180) a1 += 360; - parent.updateWorldTransform(px, py, rotation + a1 * alpha, parent.ascaleX, parent.ascaleY, 0, 0); + parent.updateWorldTransform(px, py, rotation + a1 * alpha, sx, parent.ascaleY, 0, 0); rotation = child.arotation; a2 = ((a2 + os) * radDeg - child.ashearX) * s2 + os2 - rotation; if (a2 > 180) diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java index 75b3e49d6..81bceb23b 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraintData.java @@ -41,6 +41,7 @@ public class IkConstraintData { final Array bones = new Array(); BoneData target; int bendDirection = 1; + boolean stretch; float mix = 1; public IkConstraintData (String name) { @@ -86,6 +87,16 @@ public class IkConstraintData { this.bendDirection = bendDirection; } + /** When true, if the target is out of range, the parent bone is scaled on the X axis to reach it. If the parent bone has local + * nonuniform scale, stretching is not applied. */ + public boolean getStretch () { + return stretch; + } + + public void setStretch (boolean stretch) { + this.stretch = stretch; + } + /** A percentage (0-1) that controls the mix between the constrained and unconstrained rotations. */ public float getMix () { return mix; 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 e267fa1a2..1e3168037 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java @@ -395,6 +395,7 @@ public class Skeleton { for (int i = 0, n = ikConstraints.size; i < n; i++) { IkConstraint constraint = ikConstraints.get(i); constraint.bendDirection = constraint.data.bendDirection; + constraint.stretch = constraint.data.stretch; constraint.mix = constraint.data.mix; } 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 81884693a..1d5e0959b 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonBinary.java @@ -232,6 +232,7 @@ public class SkeletonBinary { data.target = skeletonData.bones.get(input.readInt(true)); data.mix = input.readFloat(); data.bendDirection = input.readByte(); + data.stretch = input.readBoolean(); skeletonData.ikConstraints.add(data); } @@ -660,7 +661,7 @@ public class SkeletonBinary { IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount); timeline.ikConstraintIndex = index; for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) { - timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte()); + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean()); if (frameIndex < frameCount - 1) readCurve(input, frameIndex, timeline); } timelines.add(timeline); 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 904ce4752..3120595b6 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonJson.java @@ -186,6 +186,7 @@ public class SkeletonJson { if (data.target == null) throw new SerializationException("IK target bone not found: " + targetName); data.bendDirection = constraintMap.getBoolean("bendPositive", true) ? 1 : -1; + data.stretch = constraintMap.getBoolean("stretch", false); data.mix = constraintMap.getFloat("mix", 1); skeletonData.ikConstraints.add(data); @@ -568,7 +569,7 @@ public class SkeletonJson { int frameIndex = 0; for (JsonValue valueMap = constraintMap.child; valueMap != null; valueMap = valueMap.next) { timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getFloat("mix", 1), - valueMap.getBoolean("bendPositive", true) ? 1 : -1); + valueMap.getBoolean("bendPositive", true) ? 1 : -1, valueMap.getBoolean("stretch", false)); readCurve(valueMap, timeline, frameIndex); frameIndex++; } From ae2f77112024dea53f3e5c2d9f28afed5f0fc252 Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Wed, 11 Jul 2018 04:56:26 +0200 Subject: [PATCH 02/15] Be nicer about zero length bones for stretchy IK. --- .../src/com/esotericsoftware/spine/IkConstraint.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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 0a7f8aa36..77623cbad 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/IkConstraint.java @@ -161,8 +161,8 @@ public class IkConstraint implements Constraint { else if (rotationIK < -180) rotationIK += 360; float sx = bone.ascaleX; if (stretch) { - float dd = (float)Math.sqrt(tx * tx + ty * ty); - if (dd > bone.data.length * sx) sx *= (dd / (bone.data.length * sx) - 1) * alpha + 1; + float b = bone.data.length * sx, dd = (float)Math.sqrt(tx * tx + ty * ty); + if (dd > b && b > 0.0001f) sx *= (dd / b - 1) * alpha + 1; } bone.updateWorldTransform(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, bone.ascaleY, bone.ashearX, bone.ashearY); @@ -226,7 +226,7 @@ public class IkConstraint implements Constraint { cos = -1; else if (cos > 1) { cos = 1; - if (stretch) sx *= ((float)Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1; + if (stretch && l1 + l2 > 0.0001f) sx *= ((float)Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1; } a2 = (float)Math.acos(cos) * bendDir; a = l1 + l2 * cos; From 0f7c01c469c9b2f67c40ef843b90bb0559a312bb Mon Sep 17 00:00:00 2001 From: pharan Date: Thu, 12 Jul 2018 18:03:08 +0800 Subject: [PATCH 03/15] [csharp] Changed skeleton flipX/Y to scaleX/Y. (see https://github.com/EsotericSoftware/spine-runtimes/commit/d9a6b9151bdce0654cb263accfb0366a0a91d08b) --- spine-csharp/src/Bone.cs | 56 ++++++++++-------------------------- spine-csharp/src/Skeleton.cs | 12 ++++++-- 2 files changed, 24 insertions(+), 44 deletions(-) diff --git a/spine-csharp/src/Bone.cs b/spine-csharp/src/Bone.cs index 3357ec3c0..21b471894 100644 --- a/spine-csharp/src/Bone.cs +++ b/spine-csharp/src/Bone.cs @@ -53,10 +53,6 @@ namespace Spine { internal float a, b, worldX; internal float c, d, worldY; -// internal float worldSignX, worldSignY; -// public float WorldSignX { get { return worldSignX; } } -// public float WorldSignY { get { return worldSignY; } } - internal bool sorted; public BoneData Data { get { return data; } } @@ -152,27 +148,13 @@ namespace Spine { Bone parent = this.parent; if (parent == null) { // Root bone. - float rotationY = rotation + 90 + shearY; - float la = MathUtils.CosDeg(rotation + shearX) * scaleX; - float lb = MathUtils.CosDeg(rotationY) * scaleY; - float lc = MathUtils.SinDeg(rotation + shearX) * scaleX; - float ld = MathUtils.SinDeg(rotationY) * scaleY; - if (skeleton.flipX) { - x = -x; - la = -la; - lb = -lb; - } - if (skeleton.flipY != yDown) { - y = -y; - lc = -lc; - ld = -ld; - } - a = la; - b = lb; - c = lc; - d = ld; - worldX = x + skeleton.x; - worldY = y + skeleton.y; + float rotationY = rotation + 90 + shearY, sx = skeleton.scaleX, sy = skeleton.scaleY; + a = MathUtils.CosDeg(rotation + shearX) * scaleX * sx; + b = MathUtils.CosDeg(rotationY) * scaleY * sy; + c = MathUtils.SinDeg(rotation + shearX) * scaleX * sx; + d = MathUtils.SinDeg(rotationY) * scaleY * sy; + worldX = x * sx + skeleton.x; + worldY = y * sy + skeleton.y; return; } @@ -228,8 +210,8 @@ namespace Spine { case TransformMode.NoScale: case TransformMode.NoScaleOrReflection: { float cos = MathUtils.CosDeg(rotation), sin = MathUtils.SinDeg(rotation); - float za = pa * cos + pb * sin; - float zc = pc * cos + pd * sin; + float za = (pa * cos + pb * sin) / skeleton.scaleX; + float zc = (pc * cos + pd * sin) / skeleton.scaleY; float s = (float)Math.Sqrt(za * za + zc * zc); if (s > 0.00001f) s = 1 / s; za *= s; @@ -242,26 +224,18 @@ namespace Spine { float lb = MathUtils.CosDeg(90 + shearY) * scaleY; float lc = MathUtils.SinDeg(shearX) * scaleX; float ld = MathUtils.SinDeg(90 + shearY) * scaleY; - if (data.transformMode != TransformMode.NoScaleOrReflection? pa * pd - pb* pc< 0 : skeleton.flipX != skeleton.flipY) { - zb = -zb; - zd = -zd; - } a = za * la + zb * lc; b = za * lb + zb * ld; c = zc * la + zd * lc; - d = zc * lb + zd * ld; - return; + d = zc * lb + zd * ld; + break; } } - if (skeleton.flipX) { - a = -a; - b = -b; - } - if (skeleton.flipY != Bone.yDown) { - c = -c; - d = -d; - } + a *= skeleton.scaleX; + b *= skeleton.scaleX; + c *= skeleton.scaleY; + d *= skeleton.scaleY; } public void SetToSetupPose () { diff --git a/spine-csharp/src/Skeleton.cs b/spine-csharp/src/Skeleton.cs index ed4897ae6..f774e0490 100644 --- a/spine-csharp/src/Skeleton.cs +++ b/spine-csharp/src/Skeleton.cs @@ -45,7 +45,7 @@ namespace Spine { internal Skin skin; internal float r = 1, g = 1, b = 1, a = 1; internal float time; - internal bool flipX, flipY; + internal float scaleX, scaleY; internal float x, y; public SkeletonData Data { get { return data; } } @@ -64,8 +64,14 @@ namespace Spine { public float Time { get { return time; } set { time = value; } } public float X { get { return x; } set { x = value; } } public float Y { get { return y; } set { y = value; } } - public bool FlipX { get { return flipX; } set { flipX = value; } } - public bool FlipY { get { return flipY; } set { flipY = value; } } + public float ScaleX { get { return scaleX; } set { scaleX = value; } } + public float ScaleY { get { return scaleY; } set { scaleY = value; } } + + [Obsolete("Use ScaleX instead. FlipX is when ScaleX is negative.")] + public bool FlipX { get { return scaleX < 0; } set { scaleX = value ? -1f : 1f; } } + + [Obsolete("Use ScaleY instead. FlipY is when ScaleY is negative.")] + public bool FlipY { get { return scaleY < 0; } set { scaleY = value ? -1f : 1f; } } public Bone RootBone { get { return bones.Count == 0 ? null : bones.Items[0]; } From d336712ccc7e2b7bd52dc0aa763389577e11a1be Mon Sep 17 00:00:00 2001 From: pharan Date: Thu, 12 Jul 2018 18:05:56 +0800 Subject: [PATCH 04/15] [unity] Changed skeleton flipX/Y to scaleX/Y. --- .../Editor/spine-unity/Editor/SkeletonDebugWindow.cs | 6 +++--- .../Spine/Runtime/spine-unity/Components/BoneFollower.cs | 7 +------ .../Spine/Runtime/spine-unity/Components/PointFollower.cs | 2 +- .../Runtime/spine-unity/Components/SkeletonRenderer.cs | 4 ++-- .../Runtime/spine-unity/Mesh Generation/SpineMesh.cs | 8 ++++---- .../spine-unity/Modules/Ragdoll/SkeletonRagdoll.cs | 4 ++-- .../spine-unity/Modules/Ragdoll/SkeletonRagdoll2D.cs | 4 ++-- .../Modules/SkeletonGraphic/BoneFollowerGraphic.cs | 2 +- .../Modules/SkeletonGraphic/SkeletonGraphic.cs | 8 ++++---- .../spine-unity/SkeletonUtility/SkeletonUtility.cs | 4 ++-- .../spine-unity/SkeletonUtility/SkeletonUtilityBone.cs | 2 +- 11 files changed, 23 insertions(+), 28 deletions(-) diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDebugWindow.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDebugWindow.cs index cee6ecf9f..9373f93ad 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDebugWindow.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDebugWindow.cs @@ -229,9 +229,9 @@ namespace Spine.Unity.Editor { // Flip EditorGUILayout.BeginHorizontal(GUILayout.MaxWidth(160f)); - EditorGUILayout.LabelField("Flip", GUILayout.MaxWidth(EditorGUIUtility.labelWidth - 20f)); - skeleton.FlipX = EditorGUILayout.ToggleLeft(".FlipX", skeleton.FlipX, GUILayout.MaxWidth(70f)); - skeleton.FlipY = EditorGUILayout.ToggleLeft(".FlipY", skeleton.FlipY, GUILayout.MaxWidth(70f)); + EditorGUILayout.LabelField("Scale", GUILayout.MaxWidth(EditorGUIUtility.labelWidth - 20f)); + skeleton.ScaleX = EditorGUILayout.DelayedFloatField(".ScaleX", skeleton.ScaleX, GUILayout.MaxWidth(70f)); + skeleton.ScaleY = EditorGUILayout.DelayedFloatField(".ScaleY", skeleton.ScaleY, GUILayout.MaxWidth(70f)); GUILayout.EndHorizontal(); // Color diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/BoneFollower.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/BoneFollower.cs index 6ce6f147c..c462b262c 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/BoneFollower.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/BoneFollower.cs @@ -164,19 +164,14 @@ namespace Spine.Unity { if (followBoneRotation) { Vector3 worldRotation = skeletonTransform.rotation.eulerAngles; if (followLocalScale && bone.scaleX < 0) boneWorldRotation += 180f; - #if UNITY_5_6_OR_NEWER thisTransform.SetPositionAndRotation(targetWorldPosition, Quaternion.Euler(worldRotation.x, worldRotation.y, worldRotation.z + boneWorldRotation)); - #else - thisTransform.position = targetWorldPosition; - thisTransform.rotation = Quaternion.Euler(worldRotation.x, worldRotation.y, worldRotation.z + bone.WorldRotationX); - #endif } else { thisTransform.position = targetWorldPosition; } } Vector3 localScale = followLocalScale ? new Vector3(bone.scaleX, bone.scaleY, 1f) : new Vector3(1f, 1f, 1f); - if (followSkeletonFlip) localScale.y *= bone.skeleton.flipX ^ bone.skeleton.flipY ? -1f : 1f; + if (followSkeletonFlip) localScale.y *= Mathf.Sign(bone.skeleton.scaleX * bone.skeleton.scaleY); thisTransform.localScale = localScale; } } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/PointFollower.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/PointFollower.cs index f3702beb5..e75309356 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/PointFollower.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/PointFollower.cs @@ -145,7 +145,7 @@ namespace Spine.Unity { if (followSkeletonFlip) { Vector3 localScale = thisTransform.localScale; - localScale.y = Mathf.Abs(localScale.y) * (bone.skeleton.flipX ^ bone.skeleton.flipY ? -1f : 1f); + localScale.y = Mathf.Abs(localScale.y) * Mathf.Sign(bone.skeleton.scaleX * bone.skeleton.scaleY); thisTransform.localScale = localScale; } } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs index 21907bb7f..e4e25d464 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs @@ -207,8 +207,8 @@ namespace Spine.Unity { rendererBuffers.Initialize(); skeleton = new Skeleton(skeletonData) { - flipX = initialFlipX, - flipY = initialFlipY + scaleX = initialFlipX ? -1 : 1, + scaleY = initialFlipY ? -1 : 1 }; if (!string.IsNullOrEmpty(initialSkinName) && !string.Equals(initialSkinName, "default", System.StringComparison.Ordinal)) diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/SpineMesh.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/SpineMesh.cs index 9d4b12032..9b76040c5 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/SpineMesh.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/SpineMesh.cs @@ -308,10 +308,10 @@ namespace Spine.Unity { #if SPINE_TRIANGLECHECK var clippingAttachment = attachment as ClippingAttachment; if (clippingAttachment != null) { - clippingEndSlot = clippingAttachment.endSlot; - clippingAttachmentSource = i; - current.hasClipping = true; - skeletonHasClipping = true; + clippingEndSlot = clippingAttachment.endSlot; + clippingAttachmentSource = i; + current.hasClipping = true; + skeletonHasClipping = true; } #endif noRender = true; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Ragdoll/SkeletonRagdoll.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Ragdoll/SkeletonRagdoll.cs index d43fb19ac..da7248f36 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Ragdoll/SkeletonRagdoll.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Ragdoll/SkeletonRagdoll.cs @@ -313,8 +313,8 @@ namespace Spine.Unity.Modules { } void UpdateSpineSkeleton (ISkeletonAnimation skeletonRenderer) { - bool flipX = skeleton.flipX; - bool flipY = skeleton.flipY; + bool flipX = skeleton.ScaleX < 0; + bool flipY = skeleton.ScaleY < 0; bool flipXOR = flipX ^ flipY; bool flipOR = flipX || flipY; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Ragdoll/SkeletonRagdoll2D.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Ragdoll/SkeletonRagdoll2D.cs index 0e9c0aba2..f66015a74 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Ragdoll/SkeletonRagdoll2D.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Ragdoll/SkeletonRagdoll2D.cs @@ -311,8 +311,8 @@ namespace Spine.Unity.Modules { /// Performed every skeleton animation update to translate Unity Transforms positions into Spine bone transforms. void UpdateSpineSkeleton (ISkeletonAnimation animatedSkeleton) { - bool flipX = skeleton.flipX; - bool flipY = skeleton.flipY; + bool flipX = skeleton.ScaleX < 0; + bool flipY = skeleton.ScaleY < 0; bool flipXOR = flipX ^ flipY; bool flipOR = flipX || flipY; var startingBone = this.StartingBone; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonGraphic/BoneFollowerGraphic.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonGraphic/BoneFollowerGraphic.cs index f399e9bc2..e833c4453 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonGraphic/BoneFollowerGraphic.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonGraphic/BoneFollowerGraphic.cs @@ -123,7 +123,7 @@ namespace Spine.Unity { } Vector3 localScale = followLocalScale ? new Vector3(bone.scaleX, bone.scaleY, 1f) : new Vector3(1f, 1f, 1f); - if (followSkeletonFlip) localScale.y *= bone.skeleton.flipX ^ bone.skeleton.flipY ? -1f : 1f; + if (followSkeletonFlip) localScale.y *= Mathf.Sign(bone.skeleton.scaleX * bone.skeleton.scaleY); thisTransform.localScale = localScale; } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs index 43519c3d2..d76021a58 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/SkeletonGraphic/SkeletonGraphic.cs @@ -82,8 +82,8 @@ namespace Spine.Unity { // Only provide visual feedback to inspector changes in Unity Editor Edit mode. if (!Application.isPlaying) { - skeleton.flipX = this.initialFlipX; - skeleton.flipY = this.initialFlipY; + skeleton.scaleX = this.initialFlipX ? -1 : 1; + skeleton.scaleY = this.initialFlipY ? -1 : 1; skeleton.SetToSetupPose(); if (!string.IsNullOrEmpty(startingAnimation)) @@ -233,8 +233,8 @@ namespace Spine.Unity { } this.skeleton = new Skeleton(skeletonData) { - flipX = this.initialFlipX, - flipY = this.initialFlipY + scaleX = this.initialFlipX ? -1 : 1, + scaleY = this.initialFlipY ? -1 : 1 }; meshBuffers = new DoubleBuffered(); diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtility.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtility.cs index a46959fbc..d48234ffd 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtility.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtility.cs @@ -123,10 +123,10 @@ namespace Spine.Unity { var skeleton = skeletonRenderer.skeleton; if (boneRoot != null && skeleton != null) { Vector3 flipScale = Vector3.one; - if (skeleton.FlipX) + if (skeleton.scaleX < 0) flipScale.x = -1; - if (skeleton.FlipY) + if (skeleton.scaleY < 0) flipScale.y = -1; boneRoot.localScale = flipScale; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs index 1cec0264b..771045010 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonUtility/SkeletonUtilityBone.cs @@ -119,7 +119,7 @@ namespace Spine.Unity { } var thisTransform = cachedTransform; - float skeletonFlipRotation = (skeleton.flipX ^ skeleton.flipY) ? -1f : 1f; + float skeletonFlipRotation = Mathf.Sign(skeleton.scaleX * skeleton.scaleY); if (mode == Mode.Follow) { switch (phase) { case UpdatePhase.Local: From 6187e2b89e0ef4502660649b6087ae259def7267 Mon Sep 17 00:00:00 2001 From: pharan Date: Thu, 12 Jul 2018 18:08:05 +0800 Subject: [PATCH 05/15] [unity] Rearrange SpineEditorUtilities classes. --- .../spine-unity/Editor/SkeletonBaker.cs | 49 +- .../Editor/SkeletonDataAssetInspector.cs | 16 +- .../Editor/SpineEditorUtilities.cs | 1142 ++++++++--------- 3 files changed, 609 insertions(+), 598 deletions(-) diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonBaker.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonBaker.cs index 286149297..671fb99cb 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonBaker.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonBaker.cs @@ -80,7 +80,7 @@ namespace Spine.Unity.Editor { } string dataPath = AssetDatabase.GetAssetPath(skeletonDataAsset); - string controllerPath = dataPath.Replace(SpineEditorUtilities.SkeletonDataSuffix, "_Controller").Replace(".asset", ".controller"); + string controllerPath = dataPath.Replace(SpineEditorUtilities.AssetUtility.SkeletonDataSuffix, "_Controller").Replace(".asset", ".controller"); UnityEditor.Animations.AnimatorController controller; if (skeletonDataAsset.controller != null) { controller = (UnityEditor.Animations.AnimatorController)skeletonDataAsset.controller; @@ -1406,6 +1406,53 @@ namespace Spine.Unity.Editor { #endregion #endregion + #region Region Baking + public static GameObject BakeRegion (SpineAtlasAsset atlasAsset, AtlasRegion region, bool autoSave = true) { + atlasAsset.GetAtlas(); // Initializes atlasAsset. + + string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); + string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); + string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); + string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeName(region.name) + ".prefab").Replace("\\", "/"); + + GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject)); + GameObject root; + Mesh mesh; + bool isNewPrefab = false; + + if (!Directory.Exists(bakedDirPath)) + Directory.CreateDirectory(bakedDirPath); + + if (prefab == null) { + root = new GameObject("temp", typeof(MeshFilter), typeof(MeshRenderer)); + prefab = PrefabUtility.CreatePrefab(bakedPrefabPath, root); + isNewPrefab = true; + Object.DestroyImmediate(root); + } + + mesh = (Mesh)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(Mesh)); + + Material mat = null; + mesh = atlasAsset.GenerateMesh(region.name, mesh, out mat); + if (isNewPrefab) { + AssetDatabase.AddObjectToAsset(mesh, prefab); + prefab.GetComponent().sharedMesh = mesh; + } + + EditorUtility.SetDirty(mesh); + EditorUtility.SetDirty(prefab); + + if (autoSave) { + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + } + + prefab.GetComponent().sharedMaterial = mat; + + return prefab; + } + #endregion + static string GetPath (BoneData b) { return GetPathRecurse(b).Substring(1); } diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDataAssetInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDataAssetInspector.cs index 693aa25d6..a71cbfbeb 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDataAssetInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDataAssetInspector.cs @@ -28,7 +28,7 @@ * POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ -#define SPINE_SKELETON_ANIMATOR +#define SPINE_SKELETON_MECANIM using System; using System.Reflection; @@ -55,7 +55,7 @@ namespace Spine.Unity.Editor { SerializedProperty spriteCollection; #endif - #if SPINE_SKELETON_ANIMATOR + #if SPINE_SKELETON_MECANIM static bool isMecanimExpanded = false; SerializedProperty controller; #endif @@ -100,7 +100,7 @@ namespace Spine.Unity.Editor { duration = serializedObject.FindProperty("duration"); defaultMix = serializedObject.FindProperty("defaultMix"); - #if SPINE_SKELETON_ANIMATOR + #if SPINE_SKELETON_MECANIM controller = serializedObject.FindProperty("controller"); #endif @@ -494,7 +494,7 @@ namespace Spine.Unity.Editor { } void DrawUnityTools () { - #if SPINE_SKELETON_ANIMATOR + #if SPINE_SKELETON_MECANIM using (new SpineInspectorUtility.BoxScope()) { isMecanimExpanded = EditorGUILayout.Foldout(isMecanimExpanded, SpineInspectorUtility.TempContent("SkeletonAnimator", SpineInspectorUtility.UnityIcon())); if (isMecanimExpanded) { @@ -569,7 +569,7 @@ namespace Spine.Unity.Editor { } else { List missingPaths = null; if (atlasAssets.arraySize > 0) { - missingPaths = SpineEditorUtilities.GetRequiredAtlasRegions(AssetDatabase.GetAssetPath(skeletonJSON.objectReferenceValue)); + missingPaths = SpineEditorUtilities.AssetUtility.GetRequiredAtlasRegions(AssetDatabase.GetAssetPath(skeletonJSON.objectReferenceValue)); foreach (var atlas in atlasList) { for (int i = 0; i < missingPaths.Count; i++) { @@ -587,8 +587,8 @@ namespace Spine.Unity.Editor { } if (missingPaths != null) { - foreach (string str in missingPaths) - warnings.Add("Missing Region: '" + str + "'"); + foreach (string missingRegion in missingPaths) + warnings.Add(string.Format("Missing Region: '{0}'", missingRegion)); } } @@ -599,7 +599,7 @@ namespace Spine.Unity.Editor { } void DoReimport () { - SpineEditorUtilities.ImportSpineContent(new [] { AssetDatabase.GetAssetPath(skeletonJSON.objectReferenceValue) }, true); + SpineEditorUtilities.AssetUtility.ImportSpineContent(new [] { AssetDatabase.GetAssetPath(skeletonJSON.objectReferenceValue) }, true); preview.Clear(); InitializeEditor(); EditorUtility.SetDirty(targetSkeletonDataAsset); diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs index 66804c332..50940a132 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs @@ -622,639 +622,603 @@ namespace Spine.Unity.Editor { if (AssetDatabaseAvailabilityDetector.IsAssetDatabaseAvailable()) { string[] combinedAssets = assetsImportedInWrongState.ToArray(); assetsImportedInWrongState.Clear(); - ImportSpineContent(combinedAssets); + AssetUtility.ImportSpineContent(combinedAssets); } } - public static void ImportSpineContent (string[] imported, bool reimport = false) { - var atlasPaths = new List(); - var imagePaths = new List(); - var skeletonPaths = new List(); - - foreach (string str in imported) { - string extension = Path.GetExtension(str).ToLower(); - switch (extension) { - case ".txt": - if (str.EndsWith(".atlas.txt", System.StringComparison.Ordinal)) - atlasPaths.Add(str); - break; - case ".png": - case ".jpg": - imagePaths.Add(str); - break; - case ".json": - var jsonAsset = (TextAsset)AssetDatabase.LoadAssetAtPath(str, typeof(TextAsset)); - if (jsonAsset != null && SkeletonDataFileValidator.IsSpineData(jsonAsset)) - skeletonPaths.Add(str); - break; - case ".bytes": - if (str.ToLower().EndsWith(".skel.bytes", System.StringComparison.Ordinal)) { - if (SkeletonDataFileValidator.IsSpineData((TextAsset)AssetDatabase.LoadAssetAtPath(str, typeof(TextAsset)))) - skeletonPaths.Add(str); - } - break; - } - } - - // Import atlases first. - var atlases = new List(); - foreach (string ap in atlasPaths) { - TextAsset atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(ap, typeof(TextAsset)); - AtlasAssetBase atlas = IngestSpineAtlas(atlasText); - atlases.Add(atlas); - } - - // Import skeletons and match them with atlases. - bool abortSkeletonImport = false; - foreach (string sp in skeletonPaths) { - if (!reimport && SkeletonDataFileValidator.CheckForValidSkeletonData(sp)) { - ReloadSkeletonData(sp); - continue; - } - - string dir = Path.GetDirectoryName(sp); - - #if SPINE_TK2D - IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, null); - #else - var localAtlases = FindAtlasesAtPath(dir); - var requiredPaths = GetRequiredAtlasRegions(sp); - var atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases); - if (atlasMatch != null || requiredPaths.Count == 0) { - IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasMatch); - } else { - bool resolved = false; - while (!resolved) { - - string filename = Path.GetFileNameWithoutExtension(sp); - int result = EditorUtility.DisplayDialogComplex( - string.Format("AtlasAsset for \"{0}\"", filename), - string.Format("Could not automatically set the AtlasAsset for \"{0}\". You may set it manually.", filename), - "Choose AtlasAssets...", "Skip this", "Stop importing all" - ); - - switch (result) { - case -1: - //Debug.Log("Select Atlas"); - AtlasAssetBase selectedAtlas = GetAtlasDialog(Path.GetDirectoryName(sp)); - if (selectedAtlas != null) { - localAtlases.Clear(); - localAtlases.Add(selectedAtlas); - atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases); - if (atlasMatch != null) { - resolved = true; - IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasMatch); - } - } - break; - case 0: // Choose AtlasAssets... - var atlasList = MultiAtlasDialog(requiredPaths, Path.GetDirectoryName(sp), Path.GetFileNameWithoutExtension(sp)); - if (atlasList != null) - IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasList.ToArray()); - - resolved = true; - break; - case 1: // Skip - Debug.Log("Skipped importing: " + Path.GetFileName(sp)); - resolved = true; - break; - case 2: // Stop importing all - abortSkeletonImport = true; - resolved = true; - break; - } - } - } - - if (abortSkeletonImport) - break; - #endif - } - // Any post processing of images - } - - static void ReloadSkeletonData (string skeletonJSONPath) { - string dir = Path.GetDirectoryName(skeletonJSONPath); - TextAsset textAsset = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonJSONPath, typeof(TextAsset)); - DirectoryInfo dirInfo = new DirectoryInfo(dir); - FileInfo[] files = dirInfo.GetFiles("*.asset"); - - foreach (var f in files) { - string localPath = dir + "/" + f.Name; - var obj = AssetDatabase.LoadAssetAtPath(localPath, typeof(Object)); - var skeletonDataAsset = obj as SkeletonDataAsset; - if (skeletonDataAsset != null) { - if (skeletonDataAsset.skeletonJSON == textAsset) { - if (Selection.activeObject == skeletonDataAsset) - Selection.activeObject = null; - - Debug.LogFormat("Changes to '{0}' detected. Clearing SkeletonDataAsset: {1}", skeletonJSONPath, localPath); - skeletonDataAsset.Clear(); - - string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(skeletonDataAsset)); - string lastHash = EditorPrefs.GetString(guid + "_hash"); - - // For some weird reason sometimes Unity loses the internal Object pointer, - // and as a result, all comparisons with null returns true. - // But the C# wrapper is still alive, so we can "restore" the object - // by reloading it from its Instance ID. - AtlasAssetBase[] skeletonDataAtlasAssets = skeletonDataAsset.atlasAssets; - if (skeletonDataAtlasAssets != null) { - for (int i = 0; i < skeletonDataAtlasAssets.Length; i++) { - if (!ReferenceEquals(null, skeletonDataAtlasAssets[i]) && - skeletonDataAtlasAssets[i].Equals(null) && - skeletonDataAtlasAssets[i].GetInstanceID() != 0 - ) { - skeletonDataAtlasAssets[i] = EditorUtility.InstanceIDToObject(skeletonDataAtlasAssets[i].GetInstanceID()) as AtlasAssetBase; - } - } - } - - SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(true); - string currentHash = skeletonData != null ? skeletonData.Hash : null; - - #if SPINE_SKELETONMECANIM - if (currentHash == null || lastHash != currentHash) - UpdateMecanimClips(skeletonDataAsset); - #endif - - // if (currentHash == null || lastHash != currentHash) - // Do any upkeep on synchronized assets - - if (currentHash != null) - EditorPrefs.SetString(guid + "_hash", currentHash); - } - } - } - } #endregion - #region Match SkeletonData with Atlases - static readonly AttachmentType[] AtlasTypes = { AttachmentType.Region, AttachmentType.Linkedmesh, AttachmentType.Mesh }; + public static class AssetUtility { - static List MultiAtlasDialog (List requiredPaths, string initialDirectory, string filename = "") { - List atlasAssets = new List(); - bool resolved = false; - string lastAtlasPath = initialDirectory; - while (!resolved) { + #region Match SkeletonData with Atlases + static readonly AttachmentType[] AtlasTypes = { AttachmentType.Region, AttachmentType.Linkedmesh, AttachmentType.Mesh }; - // Build dialog box message. - var missingRegions = new List(requiredPaths); - var dialogText = new StringBuilder(); - { - dialogText.AppendLine(string.Format("SkeletonDataAsset for \"{0}\"", filename)); - dialogText.AppendLine("has missing regions."); - dialogText.AppendLine(); - dialogText.AppendLine("Current Atlases:"); - - if (atlasAssets.Count == 0) - dialogText.AppendLine("\t--none--"); - - for (int i = 0; i < atlasAssets.Count; i++) - dialogText.AppendLine("\t" + atlasAssets[i].name); - - dialogText.AppendLine(); - dialogText.AppendLine("Missing Regions:"); - - foreach (var atlasAsset in atlasAssets) { - var atlas = atlasAsset.GetAtlas(); - for (int i = 0; i < missingRegions.Count; i++) { - if (atlas.FindRegion(missingRegions[i]) != null) { - missingRegions.RemoveAt(i); - i--; - } - } - } - - int n = missingRegions.Count; - if (n == 0) break; - - const int MaxListLength = 15; - for (int i = 0; (i < n && i < MaxListLength); i++) - dialogText.AppendLine("\t" + missingRegions[i]); - - if (n > MaxListLength) dialogText.AppendLine(string.Format("\t... {0} more...", n - MaxListLength)); - } - - // Show dialog box. - int result = EditorUtility.DisplayDialogComplex( - "SkeletonDataAsset has missing Atlas.", - dialogText.ToString(), - "Browse...", "Import anyway", "Cancel" - ); - - switch (result) { - case 0: // Browse... - AtlasAssetBase selectedAtlasAsset = GetAtlasDialog(lastAtlasPath); - if (selectedAtlasAsset != null) { - var atlas = selectedAtlasAsset.GetAtlas(); - bool hasValidRegion = false; - foreach (string str in missingRegions) { - if (atlas.FindRegion(str) != null) { - hasValidRegion = true; - break; - } - } - atlasAssets.Add(selectedAtlasAsset); - } - break; - case 1: // Import anyway - resolved = true; - break; - case 2: // Cancel - atlasAssets = null; - resolved = true; - break; - } + static void AddRequiredAtlasRegionsFromBinary (string skeletonDataPath, List requiredPaths) { + SkeletonBinary binary = new SkeletonBinary(new AtlasRequirementLoader(requiredPaths)); + TextAsset data = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonDataPath, typeof(TextAsset)); + MemoryStream input = new MemoryStream(data.bytes); + binary.ReadSkeletonData(input); + binary = null; } - return atlasAssets; - } + public static List GetRequiredAtlasRegions (string skeletonDataPath) { + List requiredPaths = new List(); - static AtlasAssetBase GetAtlasDialog (string dirPath) { - string path = EditorUtility.OpenFilePanel("Select AtlasAsset...", dirPath, "asset"); - if (path == "") return null; // Canceled or closed by user. + if (skeletonDataPath.Contains(".skel")) { + AddRequiredAtlasRegionsFromBinary(skeletonDataPath, requiredPaths); + return requiredPaths; + } - int subLen = Application.dataPath.Length - 6; - string assetRelativePath = path.Substring(subLen, path.Length - subLen).Replace("\\", "/"); + TextAsset spineJson = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonDataPath, typeof(TextAsset)); - Object obj = AssetDatabase.LoadAssetAtPath(assetRelativePath, typeof(AtlasAssetBase)); + StringReader reader = new StringReader(spineJson.text); + var root = Json.Deserialize(reader) as Dictionary; - if (obj == null || obj.GetType() != typeof(AtlasAssetBase)) - return null; + if (!root.ContainsKey("skins")) + return requiredPaths; - return (AtlasAssetBase)obj; - } + foreach (var skin in (Dictionary)root["skins"]) { + foreach (var slot in (Dictionary)skin.Value) { - static void AddRequiredAtlasRegionsFromBinary (string skeletonDataPath, List requiredPaths) { - SkeletonBinary binary = new SkeletonBinary(new AtlasRequirementLoader(requiredPaths)); - TextAsset data = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonDataPath, typeof(TextAsset)); - MemoryStream input = new MemoryStream(data.bytes); - binary.ReadSkeletonData(input); - binary = null; - } + foreach (var attachment in ((Dictionary)slot.Value)) { + var data = ((Dictionary)attachment.Value); - public static List GetRequiredAtlasRegions (string skeletonDataPath) { - List requiredPaths = new List(); + // Ignore non-atlas-requiring types. + if (data.ContainsKey("type")) { + AttachmentType attachmentType; + string typeString = (string)data["type"]; + try { + attachmentType = (AttachmentType)System.Enum.Parse(typeof(AttachmentType), typeString, true); + } catch (System.ArgumentException e) { + // For more info, visit: http://esotericsoftware.com/forum/Spine-editor-and-runtime-version-management-6534 + Debug.LogWarning(string.Format("Unidentified Attachment type: \"{0}\". Skeleton may have been exported from an incompatible Spine version.", typeString)); + throw e; + } + + if (!AtlasTypes.Contains(attachmentType)) + continue; + } + + if (data.ContainsKey("path")) + requiredPaths.Add((string)data["path"]); + else if (data.ContainsKey("name")) + requiredPaths.Add((string)data["name"]); + //else + // requiredPaths.Add(attachmentEntry.Key); + } + } + } - if (skeletonDataPath.Contains(".skel")) { - AddRequiredAtlasRegionsFromBinary(skeletonDataPath, requiredPaths); return requiredPaths; } - TextAsset spineJson = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonDataPath, typeof(TextAsset)); + static AtlasAssetBase GetMatchingAtlas (List requiredPaths, List atlasAssets) { + AtlasAssetBase atlasAssetMatch = null; - StringReader reader = new StringReader(spineJson.text); - var root = Json.Deserialize(reader) as Dictionary; - - if (!root.ContainsKey("skins")) - return requiredPaths; - - foreach (KeyValuePair entry in (Dictionary)root["skins"]) { - foreach (KeyValuePair slotEntry in (Dictionary)entry.Value) { - - foreach (KeyValuePair attachmentEntry in ((Dictionary)slotEntry.Value)) { - var data = ((Dictionary)attachmentEntry.Value); - - // Ignore non-atlas-requiring types. - if (data.ContainsKey("type")) { - AttachmentType attachmentType; - string typeString = (string)data["type"]; - try { - attachmentType = (AttachmentType)System.Enum.Parse(typeof(AttachmentType), typeString, true); - } catch (System.ArgumentException e) { - // For more info, visit: http://esotericsoftware.com/forum/Spine-editor-and-runtime-version-management-6534 - Debug.LogWarning(string.Format("Unidentified Attachment type: \"{0}\". Skeleton may have been exported from an incompatible Spine version.", typeString)); - throw e; - } - - if (!AtlasTypes.Contains(attachmentType)) - continue; + foreach (AtlasAssetBase a in atlasAssets) { + Atlas atlas = a.GetAtlas(); + bool failed = false; + foreach (string regionPath in requiredPaths) { + if (atlas.FindRegion(regionPath) == null) { + failed = true; + break; } - - if (data.ContainsKey("path")) - requiredPaths.Add((string)data["path"]); - else if (data.ContainsKey("name")) - requiredPaths.Add((string)data["name"]); - else - requiredPaths.Add(attachmentEntry.Key); } - } - } - return requiredPaths; - } - - static AtlasAssetBase GetMatchingAtlas (List requiredPaths, List atlasAssets) { - AtlasAssetBase atlasAssetMatch = null; - - foreach (AtlasAssetBase a in atlasAssets) { - Atlas atlas = a.GetAtlas(); - bool failed = false; - foreach (string regionPath in requiredPaths) { - if (atlas.FindRegion(regionPath) == null) { - failed = true; + if (!failed) { + atlasAssetMatch = a; break; } } - if (!failed) { - atlasAssetMatch = a; - break; + return atlasAssetMatch; + } + + public class AtlasRequirementLoader : AttachmentLoader { + List requirementList; + + public AtlasRequirementLoader (List requirementList) { + this.requirementList = requirementList; + } + + public RegionAttachment NewRegionAttachment (Skin skin, string name, string path) { + requirementList.Add(path); + return new RegionAttachment(name); + } + + public MeshAttachment NewMeshAttachment (Skin skin, string name, string path) { + requirementList.Add(path); + return new MeshAttachment(name); + } + + public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, string name) { + return new BoundingBoxAttachment(name); + } + + public PathAttachment NewPathAttachment (Skin skin, string name) { + return new PathAttachment(name); + } + + public PointAttachment NewPointAttachment (Skin skin, string name) { + return new PointAttachment(name); + } + + public ClippingAttachment NewClippingAttachment (Skin skin, string name) { + return new ClippingAttachment(name); } } + #endregion - return atlasAssetMatch; - } + public static void ImportSpineContent (string[] imported, bool reimport = false) { + var atlasPaths = new List(); + var imagePaths = new List(); + var skeletonPaths = new List(); - public class AtlasRequirementLoader : AttachmentLoader { - List requirementList; + foreach (string str in imported) { + string extension = Path.GetExtension(str).ToLower(); + switch (extension) { + case ".txt": + if (str.EndsWith(".atlas.txt", System.StringComparison.Ordinal)) + atlasPaths.Add(str); + break; + case ".png": + case ".jpg": + imagePaths.Add(str); + break; + case ".json": + var jsonAsset = (TextAsset)AssetDatabase.LoadAssetAtPath(str, typeof(TextAsset)); + if (jsonAsset != null && SkeletonDataFileValidator.IsSpineData(jsonAsset)) + skeletonPaths.Add(str); + break; + case ".bytes": + if (str.ToLower().EndsWith(".skel.bytes", System.StringComparison.Ordinal)) { + if (SkeletonDataFileValidator.IsSpineData((TextAsset)AssetDatabase.LoadAssetAtPath(str, typeof(TextAsset)))) + skeletonPaths.Add(str); + } + break; + } + } - public AtlasRequirementLoader (List requirementList) { - this.requirementList = requirementList; - } + // Import atlases first. + var atlases = new List(); + foreach (string ap in atlasPaths) { + TextAsset atlasText = (TextAsset)AssetDatabase.LoadAssetAtPath(ap, typeof(TextAsset)); + AtlasAssetBase atlas = IngestSpineAtlas(atlasText); + atlases.Add(atlas); + } - public RegionAttachment NewRegionAttachment (Skin skin, string name, string path) { - requirementList.Add(path); - return new RegionAttachment(name); - } - - public MeshAttachment NewMeshAttachment (Skin skin, string name, string path) { - requirementList.Add(path); - return new MeshAttachment(name); - } - - public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, string name) { - return new BoundingBoxAttachment(name); - } - - public PathAttachment NewPathAttachment (Skin skin, string name) { - return new PathAttachment(name); - } - - public PointAttachment NewPointAttachment (Skin skin, string name) { - return new PointAttachment(name); - } - - public ClippingAttachment NewClippingAttachment (Skin skin, string name) { - return new ClippingAttachment(name); - } - } - #endregion - - #region Import Atlases - static List FindAtlasesAtPath (string path) { - List arr = new List(); - DirectoryInfo dir = new DirectoryInfo(path); - FileInfo[] assetInfoArr = dir.GetFiles("*.asset"); - - int subLen = Application.dataPath.Length - 6; - foreach (var f in assetInfoArr) { - string assetRelativePath = f.FullName.Substring(subLen, f.FullName.Length - subLen).Replace("\\", "/"); - Object obj = AssetDatabase.LoadAssetAtPath(assetRelativePath, typeof(AtlasAssetBase)); - if (obj != null) - arr.Add(obj as AtlasAssetBase); - } - - return arr; - } - - static AtlasAssetBase IngestSpineAtlas (TextAsset atlasText) { - if (atlasText == null) { - Debug.LogWarning("Atlas source cannot be null!"); - return null; - } - - string primaryName = Path.GetFileNameWithoutExtension(atlasText.name).Replace(".atlas", ""); - string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(atlasText)); - - string atlasPath = assetPath + "/" + primaryName + "_Atlas.asset"; - - SpineAtlasAsset atlasAsset = (SpineAtlasAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(SpineAtlasAsset)); - - List vestigialMaterials = new List(); - - if (atlasAsset == null) - atlasAsset = SpineAtlasAsset.CreateInstance(); - else { - foreach (Material m in atlasAsset.materials) - vestigialMaterials.Add(m); - } - - protectFromStackGarbageCollection.Add(atlasAsset); - atlasAsset.atlasFile = atlasText; - - //strip CR - string atlasStr = atlasText.text; - atlasStr = atlasStr.Replace("\r", ""); - - string[] atlasLines = atlasStr.Split('\n'); - List pageFiles = new List(); - for (int i = 0; i < atlasLines.Length - 1; i++) { - if (atlasLines[i].Trim().Length == 0) - pageFiles.Add(atlasLines[i + 1].Trim()); - } - - var populatingMaterials = new List(pageFiles.Count);//atlasAsset.materials = new Material[pageFiles.Count]; - - for (int i = 0; i < pageFiles.Count; i++) { - string texturePath = assetPath + "/" + pageFiles[i]; - Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D)); - - if (setTextureImporterSettings) { - TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath); - if (texImporter == null) { - Debug.LogWarning(string.Format("{0} ::: Texture asset \"{1}\" not found. Skipping. Please check your atlas file for renamed files.", atlasAsset.name, texturePath)); + // Import skeletons and match them with atlases. + bool abortSkeletonImport = false; + foreach (string sp in skeletonPaths) { + if (!reimport && SkeletonDataFileValidator.CheckForValidSkeletonData(sp)) { + ReloadSkeletonData(sp); continue; } - texImporter.textureCompression = TextureImporterCompression.Uncompressed; - texImporter.alphaSource = TextureImporterAlphaSource.FromInput; - texImporter.mipmapEnabled = false; - texImporter.alphaIsTransparency = false; // Prevent the texture importer from applying bleed to the transparent parts for PMA. - texImporter.spriteImportMode = SpriteImportMode.None; - texImporter.maxTextureSize = 2048; + string dir = Path.GetDirectoryName(sp); - EditorUtility.SetDirty(texImporter); - AssetDatabase.ImportAsset(texturePath); - AssetDatabase.SaveAssets(); - } + #if SPINE_TK2D + IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, null); + #else + var localAtlases = FindAtlasesAtPath(dir); + var requiredPaths = GetRequiredAtlasRegions(sp); + var atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases); + if (atlasMatch != null || requiredPaths.Count == 0) { + IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasMatch); + } else { + bool resolved = false; + while (!resolved) { - string pageName = Path.GetFileNameWithoutExtension(pageFiles[i]); + string filename = Path.GetFileNameWithoutExtension(sp); + int result = EditorUtility.DisplayDialogComplex( + string.Format("AtlasAsset for \"{0}\"", filename), + string.Format("Could not automatically set the AtlasAsset for \"{0}\". You may set it manually.", filename), + "Choose AtlasAssets...", "Skip this", "Stop importing all" + ); - //because this looks silly - if (pageName == primaryName && pageFiles.Count == 1) - pageName = "Material"; + switch (result) { + case -1: + //Debug.Log("Select Atlas"); + AtlasAssetBase selectedAtlas = AssetEditorGUI.GetAtlasDialog(Path.GetDirectoryName(sp)); + if (selectedAtlas != null) { + localAtlases.Clear(); + localAtlases.Add(selectedAtlas); + atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases); + if (atlasMatch != null) { + resolved = true; + IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasMatch); + } + } + break; + case 0: // Choose AtlasAssets... + var atlasList = AssetEditorGUI.MultiAtlasDialog(requiredPaths, Path.GetDirectoryName(sp), Path.GetFileNameWithoutExtension(sp)); + if (atlasList != null) + IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasList.ToArray()); - string materialPath = assetPath + "/" + primaryName + "_" + pageName + ".mat"; - Material mat = (Material)AssetDatabase.LoadAssetAtPath(materialPath, typeof(Material)); - - if (mat == null) { - mat = new Material(Shader.Find(defaultShader)); - AssetDatabase.CreateAsset(mat, materialPath); - } else { - vestigialMaterials.Remove(mat); - } - - mat.mainTexture = texture; - EditorUtility.SetDirty(mat); - AssetDatabase.SaveAssets(); - - populatingMaterials.Add(mat); //atlasAsset.materials[i] = mat; - } - - atlasAsset.materials = populatingMaterials.ToArray(); - - for (int i = 0; i < vestigialMaterials.Count; i++) - AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(vestigialMaterials[i])); - - if (AssetDatabase.GetAssetPath(atlasAsset) == "") - AssetDatabase.CreateAsset(atlasAsset, atlasPath); - else - atlasAsset.Clear(); - - EditorUtility.SetDirty(atlasAsset); - AssetDatabase.SaveAssets(); - - if (pageFiles.Count != atlasAsset.materials.Length) - Debug.LogWarning(string.Format("{0} ::: Not all atlas pages were imported. If you rename your image files, please make sure you also edit the filenames specified in the atlas file.", atlasAsset.name)); - else - Debug.Log(string.Format("{0} ::: Imported with {1} material", atlasAsset.name, atlasAsset.materials.Length)); - - // Iterate regions and bake marked. - Atlas atlas = atlasAsset.GetAtlas(); - FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic); - List regions = (List)field.GetValue(atlas); - string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); - string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); - string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); - - bool hasBakedRegions = false; - for (int i = 0; i < regions.Count; i++) { - AtlasRegion region = regions[i]; - string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeName(region.name) + ".prefab").Replace("\\", "/"); - GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject)); - if (prefab != null) { - BakeRegion(atlasAsset, region, false); - hasBakedRegions = true; - } - } - - if (hasBakedRegions) { - AssetDatabase.SaveAssets(); - AssetDatabase.Refresh(); - } - - protectFromStackGarbageCollection.Remove(atlasAsset); - return (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(AtlasAssetBase)); - } - #endregion - - #region Bake Atlas Region - public static GameObject BakeRegion (SpineAtlasAsset atlasAsset, AtlasRegion region, bool autoSave = true) { - Atlas atlas = atlasAsset.GetAtlas(); - string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); - string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); - string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); - string bakedPrefabPath = Path.Combine(bakedDirPath, GetPathSafeName(region.name) + ".prefab").Replace("\\", "/"); - - GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject)); - GameObject root; - Mesh mesh; - bool isNewPrefab = false; - - if (!Directory.Exists(bakedDirPath)) - Directory.CreateDirectory(bakedDirPath); - - if (prefab == null) { - root = new GameObject("temp", typeof(MeshFilter), typeof(MeshRenderer)); - prefab = PrefabUtility.CreatePrefab(bakedPrefabPath, root); - isNewPrefab = true; - Object.DestroyImmediate(root); - } - - mesh = (Mesh)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(Mesh)); - - Material mat = null; - mesh = atlasAsset.GenerateMesh(region.name, mesh, out mat); - if (isNewPrefab) { - AssetDatabase.AddObjectToAsset(mesh, prefab); - prefab.GetComponent().sharedMesh = mesh; - } - - EditorUtility.SetDirty(mesh); - EditorUtility.SetDirty(prefab); - - if (autoSave) { - AssetDatabase.SaveAssets(); - AssetDatabase.Refresh(); - } - - prefab.GetComponent().sharedMaterial = mat; - - return prefab; - } - #endregion - - #region Import SkeletonData (json or binary) - public const string SkeletonDataSuffix = "_SkeletonData"; - static SkeletonDataAsset IngestSpineProject (TextAsset spineJson, params AtlasAssetBase[] atlasAssets) { - string primaryName = Path.GetFileNameWithoutExtension(spineJson.name); - string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson)); - string filePath = assetPath + "/" + primaryName + SkeletonDataSuffix + ".asset"; - - #if SPINE_TK2D - if (spineJson != null) { - SkeletonDataAsset skeletonDataAsset = (SkeletonDataAsset)AssetDatabase.LoadAssetAtPath(filePath, typeof(SkeletonDataAsset)); - if (skeletonDataAsset == null) { - skeletonDataAsset = SkeletonDataAsset.CreateInstance(); - skeletonDataAsset.skeletonJSON = spineJson; - skeletonDataAsset.fromAnimation = new string[0]; - skeletonDataAsset.toAnimation = new string[0]; - skeletonDataAsset.duration = new float[0]; - skeletonDataAsset.defaultMix = defaultMix; - skeletonDataAsset.scale = defaultScale; - - AssetDatabase.CreateAsset(skeletonDataAsset, filePath); - AssetDatabase.SaveAssets(); - } else { - skeletonDataAsset.Clear(); - skeletonDataAsset.GetSkeletonData(true); - } - - return skeletonDataAsset; - } else { - EditorUtility.DisplayDialog("Error!", "Tried to ingest null Spine data.", "OK"); - return null; - } - - #else - if (spineJson != null && atlasAssets != null) { - SkeletonDataAsset skeletonDataAsset = (SkeletonDataAsset)AssetDatabase.LoadAssetAtPath(filePath, typeof(SkeletonDataAsset)); - if (skeletonDataAsset == null) { - skeletonDataAsset = ScriptableObject.CreateInstance(); { - skeletonDataAsset.atlasAssets = atlasAssets; - skeletonDataAsset.skeletonJSON = spineJson; - skeletonDataAsset.defaultMix = defaultMix; - skeletonDataAsset.scale = defaultScale; + resolved = true; + break; + case 1: // Skip + Debug.Log("Skipped importing: " + Path.GetFileName(sp)); + resolved = true; + break; + case 2: // Stop importing all + abortSkeletonImport = true; + resolved = true; + break; + } + } } - AssetDatabase.CreateAsset(skeletonDataAsset, filePath); - AssetDatabase.SaveAssets(); - } else { - skeletonDataAsset.atlasAssets = atlasAssets; - skeletonDataAsset.Clear(); - skeletonDataAsset.GetSkeletonData(true); + if (abortSkeletonImport) + break; + #endif + } + // Any post processing of images + } + + static void ReloadSkeletonData (string skeletonJSONPath) { + string dir = Path.GetDirectoryName(skeletonJSONPath); + TextAsset textAsset = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonJSONPath, typeof(TextAsset)); + DirectoryInfo dirInfo = new DirectoryInfo(dir); + FileInfo[] files = dirInfo.GetFiles("*.asset"); + + foreach (var f in files) { + string localPath = dir + "/" + f.Name; + var obj = AssetDatabase.LoadAssetAtPath(localPath, typeof(Object)); + var skeletonDataAsset = obj as SkeletonDataAsset; + if (skeletonDataAsset != null) { + if (skeletonDataAsset.skeletonJSON == textAsset) { + if (Selection.activeObject == skeletonDataAsset) + Selection.activeObject = null; + + Debug.LogFormat("Changes to '{0}' detected. Clearing SkeletonDataAsset: {1}", skeletonJSONPath, localPath); + skeletonDataAsset.Clear(); + + string guid = AssetDatabase.AssetPathToGUID(AssetDatabase.GetAssetPath(skeletonDataAsset)); + string lastHash = EditorPrefs.GetString(guid + "_hash"); + + // For some weird reason sometimes Unity loses the internal Object pointer, + // and as a result, all comparisons with null returns true. + // But the C# wrapper is still alive, so we can "restore" the object + // by reloading it from its Instance ID. + AtlasAssetBase[] skeletonDataAtlasAssets = skeletonDataAsset.atlasAssets; + if (skeletonDataAtlasAssets != null) { + for (int i = 0; i < skeletonDataAtlasAssets.Length; i++) { + if (!ReferenceEquals(null, skeletonDataAtlasAssets[i]) && + skeletonDataAtlasAssets[i].Equals(null) && + skeletonDataAtlasAssets[i].GetInstanceID() != 0 + ) { + skeletonDataAtlasAssets[i] = EditorUtility.InstanceIDToObject(skeletonDataAtlasAssets[i].GetInstanceID()) as AtlasAssetBase; + } + } + } + + SkeletonData skeletonData = skeletonDataAsset.GetSkeletonData(true); + string currentHash = skeletonData != null ? skeletonData.Hash : null; + + #if SPINE_SKELETONMECANIM + if (currentHash == null || lastHash != currentHash) + UpdateMecanimClips(skeletonDataAsset); + #endif + + // if (currentHash == null || lastHash != currentHash) + // Do any upkeep on synchronized assets + + if (currentHash != null) + EditorPrefs.SetString(guid + "_hash", currentHash); + } + } + } + } + + #region Import Atlases + static List FindAtlasesAtPath (string path) { + List arr = new List(); + DirectoryInfo dir = new DirectoryInfo(path); + FileInfo[] assetInfoArr = dir.GetFiles("*.asset"); + + int subLen = Application.dataPath.Length - 6; + foreach (var f in assetInfoArr) { + string assetRelativePath = f.FullName.Substring(subLen, f.FullName.Length - subLen).Replace("\\", "/"); + Object obj = AssetDatabase.LoadAssetAtPath(assetRelativePath, typeof(AtlasAssetBase)); + if (obj != null) + arr.Add(obj as AtlasAssetBase); } - return skeletonDataAsset; - } else { - EditorUtility.DisplayDialog("Error!", "Must specify both Spine JSON and AtlasAsset array", "OK"); - return null; + return arr; + } + + static AtlasAssetBase IngestSpineAtlas (TextAsset atlasText) { + if (atlasText == null) { + Debug.LogWarning("Atlas source cannot be null!"); + return null; + } + + string primaryName = Path.GetFileNameWithoutExtension(atlasText.name).Replace(".atlas", ""); + string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(atlasText)); + + string atlasPath = assetPath + "/" + primaryName + "_Atlas.asset"; + + SpineAtlasAsset atlasAsset = (SpineAtlasAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(SpineAtlasAsset)); + + List vestigialMaterials = new List(); + + if (atlasAsset == null) + atlasAsset = SpineAtlasAsset.CreateInstance(); + else { + foreach (Material m in atlasAsset.materials) + vestigialMaterials.Add(m); + } + + protectFromStackGarbageCollection.Add(atlasAsset); + atlasAsset.atlasFile = atlasText; + + //strip CR + string atlasStr = atlasText.text; + atlasStr = atlasStr.Replace("\r", ""); + + string[] atlasLines = atlasStr.Split('\n'); + List pageFiles = new List(); + for (int i = 0; i < atlasLines.Length - 1; i++) { + if (atlasLines[i].Trim().Length == 0) + pageFiles.Add(atlasLines[i + 1].Trim()); + } + + var populatingMaterials = new List(pageFiles.Count);//atlasAsset.materials = new Material[pageFiles.Count]; + + for (int i = 0; i < pageFiles.Count; i++) { + string texturePath = assetPath + "/" + pageFiles[i]; + Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D)); + + if (setTextureImporterSettings) { + TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath); + if (texImporter == null) { + Debug.LogWarning(string.Format("{0} ::: Texture asset \"{1}\" not found. Skipping. Please check your atlas file for renamed files.", atlasAsset.name, texturePath)); + continue; + } + + texImporter.textureCompression = TextureImporterCompression.Uncompressed; + texImporter.alphaSource = TextureImporterAlphaSource.FromInput; + texImporter.mipmapEnabled = false; + texImporter.alphaIsTransparency = false; // Prevent the texture importer from applying bleed to the transparent parts for PMA. + texImporter.spriteImportMode = SpriteImportMode.None; + texImporter.maxTextureSize = 2048; + + EditorUtility.SetDirty(texImporter); + AssetDatabase.ImportAsset(texturePath); + AssetDatabase.SaveAssets(); + } + + string pageName = Path.GetFileNameWithoutExtension(pageFiles[i]); + + //because this looks silly + if (pageName == primaryName && pageFiles.Count == 1) + pageName = "Material"; + + string materialPath = assetPath + "/" + primaryName + "_" + pageName + ".mat"; + Material mat = (Material)AssetDatabase.LoadAssetAtPath(materialPath, typeof(Material)); + + if (mat == null) { + mat = new Material(Shader.Find(defaultShader)); + AssetDatabase.CreateAsset(mat, materialPath); + } else { + vestigialMaterials.Remove(mat); + } + + mat.mainTexture = texture; + EditorUtility.SetDirty(mat); + AssetDatabase.SaveAssets(); + + populatingMaterials.Add(mat); //atlasAsset.materials[i] = mat; + } + + atlasAsset.materials = populatingMaterials.ToArray(); + + for (int i = 0; i < vestigialMaterials.Count; i++) + AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(vestigialMaterials[i])); + + if (AssetDatabase.GetAssetPath(atlasAsset) == "") + AssetDatabase.CreateAsset(atlasAsset, atlasPath); + else + atlasAsset.Clear(); + + EditorUtility.SetDirty(atlasAsset); + AssetDatabase.SaveAssets(); + + if (pageFiles.Count != atlasAsset.materials.Length) + Debug.LogWarning(string.Format("{0} ::: Not all atlas pages were imported. If you rename your image files, please make sure you also edit the filenames specified in the atlas file.", atlasAsset.name)); + else + Debug.Log(string.Format("{0} ::: Imported with {1} material", atlasAsset.name, atlasAsset.materials.Length)); + + // Iterate regions and bake marked. + Atlas atlas = atlasAsset.GetAtlas(); + FieldInfo field = typeof(Atlas).GetField("regions", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.NonPublic); + List regions = (List)field.GetValue(atlas); + string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); + string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); + string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); + + bool hasBakedRegions = false; + for (int i = 0; i < regions.Count; i++) { + AtlasRegion region = regions[i]; + string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeName(region.name) + ".prefab").Replace("\\", "/"); + GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject)); + if (prefab != null) { + SkeletonBaker.BakeRegion(atlasAsset, region, false); + hasBakedRegions = true; + } + } + + if (hasBakedRegions) { + AssetDatabase.SaveAssets(); + AssetDatabase.Refresh(); + } + + protectFromStackGarbageCollection.Remove(atlasAsset); + return (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(AtlasAssetBase)); + } + #endregion + + #region Import SkeletonData (json or binary) + public const string SkeletonDataSuffix = "_SkeletonData"; + static SkeletonDataAsset IngestSpineProject (TextAsset spineJson, params AtlasAssetBase[] atlasAssets) { + string primaryName = Path.GetFileNameWithoutExtension(spineJson.name); + string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson)); + string filePath = assetPath + "/" + primaryName + SkeletonDataSuffix + ".asset"; + + #if SPINE_TK2D + if (spineJson != null) { + SkeletonDataAsset skeletonDataAsset = (SkeletonDataAsset)AssetDatabase.LoadAssetAtPath(filePath, typeof(SkeletonDataAsset)); + if (skeletonDataAsset == null) { + skeletonDataAsset = SkeletonDataAsset.CreateInstance(); + skeletonDataAsset.skeletonJSON = spineJson; + skeletonDataAsset.fromAnimation = new string[0]; + skeletonDataAsset.toAnimation = new string[0]; + skeletonDataAsset.duration = new float[0]; + skeletonDataAsset.defaultMix = defaultMix; + skeletonDataAsset.scale = defaultScale; + + AssetDatabase.CreateAsset(skeletonDataAsset, filePath); + AssetDatabase.SaveAssets(); + } else { + skeletonDataAsset.Clear(); + skeletonDataAsset.GetSkeletonData(true); + } + + return skeletonDataAsset; + } else { + EditorUtility.DisplayDialog("Error!", "Tried to ingest null Spine data.", "OK"); + return null; + } + + #else + if (spineJson != null && atlasAssets != null) { + SkeletonDataAsset skeletonDataAsset = (SkeletonDataAsset)AssetDatabase.LoadAssetAtPath(filePath, typeof(SkeletonDataAsset)); + if (skeletonDataAsset == null) { + skeletonDataAsset = ScriptableObject.CreateInstance(); + { + skeletonDataAsset.atlasAssets = atlasAssets; + skeletonDataAsset.skeletonJSON = spineJson; + skeletonDataAsset.defaultMix = defaultMix; + skeletonDataAsset.scale = defaultScale; + } + + AssetDatabase.CreateAsset(skeletonDataAsset, filePath); + AssetDatabase.SaveAssets(); + } else { + skeletonDataAsset.atlasAssets = atlasAssets; + skeletonDataAsset.Clear(); + skeletonDataAsset.GetSkeletonData(true); + } + + return skeletonDataAsset; + } else { + EditorUtility.DisplayDialog("Error!", "Must specify both Spine JSON and AtlasAsset array", "OK"); + return null; + } + #endif + } + #endregion + } + + public static class AssetEditorGUI { + public static List MultiAtlasDialog (List requiredPaths, string initialDirectory, string filename = "") { + List atlasAssets = new List(); + bool resolved = false; + string lastAtlasPath = initialDirectory; + while (!resolved) { + + // Build dialog box message. + var missingRegions = new List(requiredPaths); + var dialogText = new StringBuilder(); + { + dialogText.AppendLine(string.Format("SkeletonDataAsset for \"{0}\"", filename)); + dialogText.AppendLine("has missing regions."); + dialogText.AppendLine(); + dialogText.AppendLine("Current Atlases:"); + + if (atlasAssets.Count == 0) + dialogText.AppendLine("\t--none--"); + + for (int i = 0; i < atlasAssets.Count; i++) + dialogText.AppendLine("\t" + atlasAssets[i].name); + + dialogText.AppendLine(); + dialogText.AppendLine("Missing Regions:"); + + foreach (var atlasAsset in atlasAssets) { + var atlas = atlasAsset.GetAtlas(); + for (int i = 0; i < missingRegions.Count; i++) { + if (atlas.FindRegion(missingRegions[i]) != null) { + missingRegions.RemoveAt(i); + i--; + } + } + } + + int n = missingRegions.Count; + if (n == 0) + break; + + const int MaxListLength = 15; + for (int i = 0; (i < n && i < MaxListLength); i++) + dialogText.AppendLine("\t" + missingRegions[i]); + + if (n > MaxListLength) + dialogText.AppendLine(string.Format("\t... {0} more...", n - MaxListLength)); + } + + // Show dialog box. + int result = EditorUtility.DisplayDialogComplex( + "SkeletonDataAsset has missing Atlas.", + dialogText.ToString(), + "Browse...", "Import anyway", "Cancel" + ); + + switch (result) { + case 0: // Browse... + AtlasAssetBase selectedAtlasAsset = GetAtlasDialog(lastAtlasPath); + if (selectedAtlasAsset != null) { + var atlas = selectedAtlasAsset.GetAtlas(); + bool hasValidRegion = false; + foreach (string str in missingRegions) { + if (atlas.FindRegion(str) != null) { + hasValidRegion = true; + break; + } + } + atlasAssets.Add(selectedAtlasAsset); + } + break; + case 1: // Import anyway + resolved = true; + break; + case 2: // Cancel + atlasAssets = null; + resolved = true; + break; + } + } + + return atlasAssets; + } + + public static AtlasAssetBase GetAtlasDialog (string dirPath) { + string path = EditorUtility.OpenFilePanel("Select AtlasAsset...", dirPath, "asset"); + if (path == "") + return null; // Canceled or closed by user. + + int subLen = Application.dataPath.Length - 6; + string assetRelativePath = path.Substring(subLen, path.Length - subLen).Replace("\\", "/"); + + Object obj = AssetDatabase.LoadAssetAtPath(assetRelativePath, typeof(AtlasAssetBase)); + + if (obj == null || obj.GetType() != typeof(AtlasAssetBase)) + return null; + + return (AtlasAssetBase)obj; } - #endif } - #endregion #region SkeletonDataFileValidator internal static class SkeletonDataFileValidator { @@ -1363,9 +1327,9 @@ namespace Spine.Unity.Editor { bool pmaVertexColors = false; bool tintBlack = false; - foreach (var atlasAsset in skeletonDataAsset.atlasAssets) { + foreach (SpineAtlasAsset atlasAsset in skeletonDataAsset.atlasAssets) { if (!pmaVertexColors) { - foreach (Material m in atlasAsset.Materials) { + foreach (Material m in atlasAsset.materials) { if (m.shader.name.Contains(PMAShaderQuery)) { pmaVertexColors = true; break; @@ -1374,7 +1338,7 @@ namespace Spine.Unity.Editor { } if (!tintBlack) { - foreach (Material m in atlasAsset.Materials) { + foreach (Material m in atlasAsset.materials) { if (m.shader.name.Contains(TintBlackShaderQuery)) { tintBlack = true; break; From 9f031f8999cc0693a2f97befefdf0eff78dd6f9f Mon Sep 17 00:00:00 2001 From: pharan Date: Thu, 12 Jul 2018 18:08:21 +0800 Subject: [PATCH 06/15] [unity] Minor formatting. --- .../Assets/Spine/Runtime/spine-unity/SkeletonExtensions.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonExtensions.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonExtensions.cs index 06c2f57f0..6044c6d55 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonExtensions.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonExtensions.cs @@ -194,9 +194,8 @@ namespace Spine.Unity { public static Material GetMaterial (this Attachment a) { object rendererObject = null; var renderableAttachment = a as IHasRendererObject; - if (renderableAttachment != null) { - rendererObject = renderableAttachment.RendererObject; - } + if (renderableAttachment != null) + rendererObject = renderableAttachment.RendererObject; if (rendererObject == null) return null; From a070b0fd9fb2b917f010adc2e71f87832a6d84b5 Mon Sep 17 00:00:00 2001 From: pharan Date: Thu, 12 Jul 2018 18:57:49 +0800 Subject: [PATCH 07/15] [unity] Improved editor warnings and dialogs for asset import. --- .../Editor/SpineAtlasAssetInspector.cs | 11 ++- .../Editor/SpineEditorUtilities.cs | 91 ++++++++++--------- 2 files changed, 58 insertions(+), 44 deletions(-) diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAtlasAssetInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAtlasAssetInspector.cs index 798392f86..76d46a502 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAtlasAssetInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAtlasAssetInspector.cs @@ -285,7 +285,16 @@ namespace Spine.Unity.Editor { } } - EditorGUILayout.LabelField(new GUIContent(regions[i].name, SpineEditorUtilities.Icons.image)); + string regionName = regions[i].name; + Texture2D icon = SpineEditorUtilities.Icons.image; + if (regionName.EndsWith(" ")) { + regionName = string.Format("'{0}'", regions[i].name); + icon = SpineEditorUtilities.Icons.warning; + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(regionName, icon, "Region name ends with whitespace. This may cause errors. Please check your source image filenames.")); + } else { + EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(regionName, icon)); + } + } EditorGUI.indentLevel = baseIndent; } diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs index 50940a132..ea3153842 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs @@ -629,18 +629,12 @@ namespace Spine.Unity.Editor { #endregion public static class AssetUtility { + public const string SkeletonDataSuffix = "_SkeletonData"; + public const string AtlasSuffix = "_Atlas"; #region Match SkeletonData with Atlases static readonly AttachmentType[] AtlasTypes = { AttachmentType.Region, AttachmentType.Linkedmesh, AttachmentType.Mesh }; - static void AddRequiredAtlasRegionsFromBinary (string skeletonDataPath, List requiredPaths) { - SkeletonBinary binary = new SkeletonBinary(new AtlasRequirementLoader(requiredPaths)); - TextAsset data = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonDataPath, typeof(TextAsset)); - MemoryStream input = new MemoryStream(data.bytes); - binary.ReadSkeletonData(input); - binary = null; - } - public static List GetRequiredAtlasRegions (string skeletonDataPath) { List requiredPaths = new List(); @@ -684,7 +678,7 @@ namespace Spine.Unity.Editor { else if (data.ContainsKey("name")) requiredPaths.Add((string)data["name"]); //else - // requiredPaths.Add(attachmentEntry.Key); + // requiredPaths.Add(attachment.Key); } } } @@ -692,6 +686,14 @@ namespace Spine.Unity.Editor { return requiredPaths; } + static void AddRequiredAtlasRegionsFromBinary (string skeletonDataPath, List requiredPaths) { + SkeletonBinary binary = new SkeletonBinary(new AtlasRequirementLoader(requiredPaths)); + TextAsset data = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonDataPath, typeof(TextAsset)); + MemoryStream input = new MemoryStream(data.bytes); + binary.ReadSkeletonData(input); + binary = null; + } + static AtlasAssetBase GetMatchingAtlas (List requiredPaths, List atlasAssets) { AtlasAssetBase atlasAssetMatch = null; @@ -789,56 +791,57 @@ namespace Spine.Unity.Editor { // Import skeletons and match them with atlases. bool abortSkeletonImport = false; - foreach (string sp in skeletonPaths) { - if (!reimport && SkeletonDataFileValidator.CheckForValidSkeletonData(sp)) { - ReloadSkeletonData(sp); + foreach (string skeletonPath in skeletonPaths) { + if (!reimport && SkeletonDataFileValidator.CheckForValidSkeletonData(skeletonPath)) { + ReloadSkeletonData(skeletonPath); continue; } - string dir = Path.GetDirectoryName(sp); + string dir = Path.GetDirectoryName(skeletonPath); #if SPINE_TK2D IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, null); #else var localAtlases = FindAtlasesAtPath(dir); - var requiredPaths = GetRequiredAtlasRegions(sp); + var requiredPaths = GetRequiredAtlasRegions(skeletonPath); var atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases); if (atlasMatch != null || requiredPaths.Count == 0) { - IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasMatch); + IngestSpineProject(AssetDatabase.LoadAssetAtPath(skeletonPath, typeof(TextAsset)) as TextAsset, atlasMatch); } else { bool resolved = false; while (!resolved) { - string filename = Path.GetFileNameWithoutExtension(sp); + string filename = Path.GetFileNameWithoutExtension(skeletonPath); int result = EditorUtility.DisplayDialogComplex( string.Format("AtlasAsset for \"{0}\"", filename), - string.Format("Could not automatically set the AtlasAsset for \"{0}\". You may set it manually.", filename), - "Choose AtlasAssets...", "Skip this", "Stop importing all" + string.Format("Could not automatically set the AtlasAsset for \"{0}\".\n\n (You may resolve this manually later.)", filename), + "Resolve atlases...", "Import without atlases", "Stop importing" ); switch (result) { case -1: //Debug.Log("Select Atlas"); - AtlasAssetBase selectedAtlas = AssetEditorGUI.GetAtlasDialog(Path.GetDirectoryName(sp)); + AtlasAssetBase selectedAtlas = AssetEditorGUI.BrowseAtlasDialog(Path.GetDirectoryName(skeletonPath)); if (selectedAtlas != null) { localAtlases.Clear(); localAtlases.Add(selectedAtlas); atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases); if (atlasMatch != null) { resolved = true; - IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasMatch); + IngestSpineProject(AssetDatabase.LoadAssetAtPath(skeletonPath, typeof(TextAsset)) as TextAsset, atlasMatch); } } break; - case 0: // Choose AtlasAssets... - var atlasList = AssetEditorGUI.MultiAtlasDialog(requiredPaths, Path.GetDirectoryName(sp), Path.GetFileNameWithoutExtension(sp)); + case 0: // Resolve AtlasAssets... + var atlasList = AssetEditorGUI.MultiAtlasDialog(requiredPaths, Path.GetDirectoryName(skeletonPath), Path.GetFileNameWithoutExtension(skeletonPath)); if (atlasList != null) - IngestSpineProject(AssetDatabase.LoadAssetAtPath(sp, typeof(TextAsset)) as TextAsset, atlasList.ToArray()); + IngestSpineProject(AssetDatabase.LoadAssetAtPath(skeletonPath, typeof(TextAsset)) as TextAsset, atlasList.ToArray()); resolved = true; break; - case 1: // Skip - Debug.Log("Skipped importing: " + Path.GetFileName(sp)); + case 1: // Import without atlas + Debug.LogWarning("Imported with missing atlases. Skeleton will not render: " + Path.GetFileName(skeletonPath)); + IngestSpineProject(AssetDatabase.LoadAssetAtPath(skeletonPath, typeof(TextAsset)) as TextAsset, new AtlasAssetBase[] {} ); resolved = true; break; case 2: // Stop importing all @@ -937,7 +940,7 @@ namespace Spine.Unity.Editor { string primaryName = Path.GetFileNameWithoutExtension(atlasText.name).Replace(".atlas", ""); string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(atlasText)); - string atlasPath = assetPath + "/" + primaryName + "_Atlas.asset"; + string atlasPath = assetPath + "/" + primaryName + AtlasSuffix + ".asset"; SpineAtlasAsset atlasAsset = (SpineAtlasAsset)AssetDatabase.LoadAssetAtPath(atlasPath, typeof(SpineAtlasAsset)); @@ -1026,9 +1029,9 @@ namespace Spine.Unity.Editor { AssetDatabase.SaveAssets(); if (pageFiles.Count != atlasAsset.materials.Length) - Debug.LogWarning(string.Format("{0} ::: Not all atlas pages were imported. If you rename your image files, please make sure you also edit the filenames specified in the atlas file.", atlasAsset.name)); + Debug.LogWarning(string.Format("{0} :: Not all atlas pages were imported. If you rename your image files, please make sure you also edit the filenames specified in the atlas file.", atlasAsset.name)); else - Debug.Log(string.Format("{0} ::: Imported with {1} material", atlasAsset.name, atlasAsset.materials.Length)); + Debug.Log(string.Format("{0} :: Imported with {1} material", atlasAsset.name, atlasAsset.materials.Length)); // Iterate regions and bake marked. Atlas atlas = atlasAsset.GetAtlas(); @@ -1060,7 +1063,6 @@ namespace Spine.Unity.Editor { #endregion #region Import SkeletonData (json or binary) - public const string SkeletonDataSuffix = "_SkeletonData"; static SkeletonDataAsset IngestSpineProject (TextAsset spineJson, params AtlasAssetBase[] atlasAssets) { string primaryName = Path.GetFileNameWithoutExtension(spineJson.name); string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson)); @@ -1162,7 +1164,7 @@ namespace Spine.Unity.Editor { const int MaxListLength = 15; for (int i = 0; (i < n && i < MaxListLength); i++) - dialogText.AppendLine("\t" + missingRegions[i]); + dialogText.AppendLine(string.Format("\t {0}", missingRegions[i])); if (n > MaxListLength) dialogText.AppendLine(string.Format("\t... {0} more...", n - MaxListLength)); @@ -1172,22 +1174,24 @@ namespace Spine.Unity.Editor { int result = EditorUtility.DisplayDialogComplex( "SkeletonDataAsset has missing Atlas.", dialogText.ToString(), - "Browse...", "Import anyway", "Cancel" + "Browse Atlas...", "Import anyway", "Cancel import" ); switch (result) { case 0: // Browse... - AtlasAssetBase selectedAtlasAsset = GetAtlasDialog(lastAtlasPath); + AtlasAssetBase selectedAtlasAsset = BrowseAtlasDialog(lastAtlasPath); if (selectedAtlasAsset != null) { - var atlas = selectedAtlasAsset.GetAtlas(); - bool hasValidRegion = false; - foreach (string str in missingRegions) { - if (atlas.FindRegion(str) != null) { - hasValidRegion = true; - break; + if (!atlasAssets.Contains(selectedAtlasAsset)) { + var atlas = selectedAtlasAsset.GetAtlas(); + bool hasValidRegion = false; + foreach (string str in missingRegions) { + if (atlas.FindRegion(str) != null) { + hasValidRegion = true; + break; + } } + atlasAssets.Add(selectedAtlasAsset); } - atlasAssets.Add(selectedAtlasAsset); } break; case 1: // Import anyway @@ -1203,7 +1207,7 @@ namespace Spine.Unity.Editor { return atlasAssets; } - public static AtlasAssetBase GetAtlasDialog (string dirPath) { + public static AtlasAssetBase BrowseAtlasDialog (string dirPath) { string path = EditorUtility.OpenFilePanel("Select AtlasAsset...", dirPath, "asset"); if (path == "") return null; // Canceled or closed by user. @@ -1211,10 +1215,11 @@ namespace Spine.Unity.Editor { int subLen = Application.dataPath.Length - 6; string assetRelativePath = path.Substring(subLen, path.Length - subLen).Replace("\\", "/"); - Object obj = AssetDatabase.LoadAssetAtPath(assetRelativePath, typeof(AtlasAssetBase)); - - if (obj == null || obj.GetType() != typeof(AtlasAssetBase)) + var obj = AssetDatabase.LoadAssetAtPath(assetRelativePath, typeof(AtlasAssetBase)); + if (obj == null || !(obj is AtlasAssetBase)) { + Debug.Log("Chosen asset was not of type AtlasAssetBase"); return null; + } return (AtlasAssetBase)obj; } From dd888a356ed429e47a1e3b15ba3d01ab8ab3c749 Mon Sep 17 00:00:00 2001 From: pharan Date: Thu, 12 Jul 2018 21:17:10 +0800 Subject: [PATCH 08/15] [unity] Reorganize SpineEditorUtilities. --- .../Editor/AnimationReferenceAssetEditor.cs | 2 +- .../spine-unity/Editor/SkeletonBaker.cs | 13 +- .../Editor/SkeletonDataAssetInspector.cs | 8 +- .../Editor/SpineAtlasAssetInspector.cs | 8 +- .../Editor/SpineEditorUtilities.cs | 1383 +++++++++-------- .../Editor/SkeletonGraphicInspector.cs | 2 +- 6 files changed, 712 insertions(+), 704 deletions(-) diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/AnimationReferenceAssetEditor.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/AnimationReferenceAssetEditor.cs index 596efbb42..15991bbcb 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/AnimationReferenceAssetEditor.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/AnimationReferenceAssetEditor.cs @@ -111,7 +111,7 @@ namespace Spine.Unity.Editor { EditorGUILayout.HelpBox(string.Format("Animation named {0} was not found for this Skeleton.", animationNameProperty.stringValue), MessageType.Warning); } else { using (new SpineInspectorUtility.BoxScope()) { - if (!string.Equals(SpineEditorUtilities.GetPathSafeName(animationName), ThisAnimationReferenceAsset.name, System.StringComparison.OrdinalIgnoreCase)) + if (!string.Equals(SpineEditorUtilities.AssetUtility.GetPathSafeName(animationName), ThisAnimationReferenceAsset.name, System.StringComparison.OrdinalIgnoreCase)) EditorGUILayout.HelpBox("Animation name value does not match this asset's name. Inspectors using this asset may be misleading.", MessageType.None); EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(animationName, SpineEditorUtilities.Icons.animation)); diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonBaker.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonBaker.cs index 671fb99cb..bbed3b657 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonBaker.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonBaker.cs @@ -30,7 +30,7 @@ // Contributed by: Mitch Thompson -#define SPINE_SKELETON_ANIMATOR +#define SPINE_SKELETONMECANIM using UnityEngine; using UnityEditor; @@ -71,7 +71,14 @@ namespace Spine.Unity.Editor { public static class SkeletonBaker { #region SkeletonAnimator's Mecanim Clips - #if SPINE_SKELETON_ANIMATOR + #if SPINE_SKELETONMECANIM + public static void UpdateMecanimClips (SkeletonDataAsset skeletonDataAsset) { + if (skeletonDataAsset.controller == null) + return; + + SkeletonBaker.GenerateMecanimAnimationClips(skeletonDataAsset); + } + public static void GenerateMecanimAnimationClips (SkeletonDataAsset skeletonDataAsset) { var data = skeletonDataAsset.GetSkeletonData(true); if (data == null) { @@ -1413,7 +1420,7 @@ namespace Spine.Unity.Editor { string atlasAssetPath = AssetDatabase.GetAssetPath(atlasAsset); string atlasAssetDirPath = Path.GetDirectoryName(atlasAssetPath); string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); - string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeName(region.name) + ".prefab").Replace("\\", "/"); + string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.AssetUtility.GetPathSafeName(region.name) + ".prefab").Replace("\\", "/"); GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject)); GameObject root; diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDataAssetInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDataAssetInspector.cs index a71cbfbeb..d27348f48 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDataAssetInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SkeletonDataAssetInspector.cs @@ -238,7 +238,7 @@ namespace Spine.Unity.Editor { FieldInfo nameField = typeof(AnimationReferenceAsset).GetField("animationName", BindingFlags.NonPublic | BindingFlags.Instance); FieldInfo skeletonDataAssetField = typeof(AnimationReferenceAsset).GetField("skeletonDataAsset", BindingFlags.NonPublic | BindingFlags.Instance); foreach (var animation in targetSkeletonData.Animations) { - string assetPath = string.Format("{0}/{1}.asset", dataPath, SpineEditorUtilities.GetPathSafeName(animation.Name)); + string assetPath = string.Format("{0}/{1}.asset", dataPath, SpineEditorUtilities.AssetUtility.GetPathSafeName(animation.Name)); AnimationReferenceAsset existingAsset = AssetDatabase.LoadAssetAtPath(assetPath); if (existingAsset == null) { AnimationReferenceAsset newAsset = ScriptableObject.CreateInstance(); @@ -538,8 +538,8 @@ namespace Spine.Unity.Editor { warnings.Add("Missing Skeleton JSON"); } else { var fieldValue = (TextAsset)skeletonJSON.objectReferenceValue; - if (!SpineEditorUtilities.SkeletonDataFileValidator.IsSpineData(fieldValue)) { - warnings.Add("Skeleton data file is not a valid JSON or binary file."); + if (!SpineEditorUtilities.AssetUtility.IsSpineData(fieldValue)) { + warnings.Add("Skeleton data file is not a valid Spine JSON or binary file."); } else { #if SPINE_TK2D bool searchForSpineAtlasAssets = true; @@ -769,7 +769,7 @@ namespace Spine.Unity.Editor { if (previewGameObject == null) { try { - previewGameObject = SpineEditorUtilities.InstantiateSkeletonAnimation(skeletonDataAsset, skinName).gameObject; + previewGameObject = SpineEditorUtilities.EditorInstantiation.InstantiateSkeletonAnimation(skeletonDataAsset, skinName).gameObject; if (previewGameObject != null) { previewGameObject.hideFlags = HideFlags.HideAndDontSave; diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAtlasAssetInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAtlasAssetInspector.cs index 76d46a502..de693f737 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAtlasAssetInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAtlasAssetInspector.cs @@ -93,7 +93,7 @@ namespace Spine.Unity.Editor { string bakedDirPath = Path.Combine(atlasAssetDirPath, atlasAsset.name); for (int i = 0; i < regions.Count; i++) { AtlasRegion region = regions[i]; - string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeRegionName(region) + ".prefab").Replace("\\", "/"); + string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.AssetUtility.GetPathSafeRegionName(region) + ".prefab").Replace("\\", "/"); GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject)); baked.Add(prefab != null); bakedObjects.Add(prefab); @@ -134,12 +134,12 @@ namespace Spine.Unity.Editor { } EditorGUILayout.Space(); - if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Set Mipmap Bias to " + SpineEditorUtilities.DEFAULT_MIPMAPBIAS))) { + if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent("Set Mipmap Bias to " + SpineEditorUtilities.Preferences.DEFAULT_MIPMAPBIAS))) { foreach (var m in atlasAsset.materials) { var texture = m.mainTexture; - texture.mipMapBias = SpineEditorUtilities.DEFAULT_MIPMAPBIAS; + texture.mipMapBias = SpineEditorUtilities.Preferences.DEFAULT_MIPMAPBIAS; } - Debug.Log("Texture mipmap bias set to " + SpineEditorUtilities.DEFAULT_MIPMAPBIAS); + Debug.Log("Texture mipmap bias set to " + SpineEditorUtilities.Preferences.DEFAULT_MIPMAPBIAS); } EditorGUILayout.Space(); diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs index ea3153842..37d9efb8d 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs @@ -157,65 +157,27 @@ namespace Spine.Unity.Editor { public static string editorGUIPath = ""; public static bool initialized; - /// HACK: This list keeps the asset reference temporarily during importing. - /// - /// In cases of very large projects/sufficient RAM pressure, when AssetDatabase.SaveAssets is called, - /// Unity can mistakenly unload assets whose references are only on the stack. - /// This leads to MissingReferenceException and other errors. - static readonly List protectFromStackGarbageCollection = new List(); - static HashSet assetsImportedInWrongState = new HashSet(); + // Preferences entry point + [PreferenceItem("Spine")] + static void PreferencesGUI () { + Preferences.HandlePreferencesGUI(); + } - #if SPINE_TK2D - const float DEFAULT_DEFAULT_SCALE = 1f; - #else - const float DEFAULT_DEFAULT_SCALE = 0.01f; - #endif - const string DEFAULT_SCALE_KEY = "SPINE_DEFAULT_SCALE"; - public static float defaultScale = DEFAULT_DEFAULT_SCALE; + // Auto-import entry point + static void OnPostprocessAllAssets (string[] imported, string[] deleted, string[] moved, string[] movedFromAssetPaths) { + if (imported.Length == 0) + return; - const float DEFAULT_DEFAULT_MIX = 0.2f; - const string DEFAULT_MIX_KEY = "SPINE_DEFAULT_MIX"; - public static float defaultMix = DEFAULT_DEFAULT_MIX; - - const string DEFAULT_DEFAULT_SHADER = "Spine/Skeleton"; - const string DEFAULT_SHADER_KEY = "SPINE_DEFAULT_SHADER"; - public static string defaultShader = DEFAULT_DEFAULT_SHADER; - - const float DEFAULT_DEFAULT_ZSPACING = 0f; - const string DEFAULT_ZSPACING_KEY = "SPINE_DEFAULT_ZSPACING"; - public static float defaultZSpacing = DEFAULT_DEFAULT_ZSPACING; - - const bool DEFAULT_SHOW_HIERARCHY_ICONS = true; - const string SHOW_HIERARCHY_ICONS_KEY = "SPINE_SHOW_HIERARCHY_ICONS"; - public static bool showHierarchyIcons = DEFAULT_SHOW_HIERARCHY_ICONS; - - const bool DEFAULT_SET_TEXTUREIMPORTER_SETTINGS = true; - const string SET_TEXTUREIMPORTER_SETTINGS_KEY = "SPINE_SET_TEXTUREIMPORTER_SETTINGS"; - public static bool setTextureImporterSettings = DEFAULT_SET_TEXTUREIMPORTER_SETTINGS; - - internal const float DEFAULT_MIPMAPBIAS = -0.5f; - - public const float DEFAULT_SCENE_ICONS_SCALE = 1f; - public const string SCENE_ICONS_SCALE_KEY = "SPINE_SCENE_ICONS_SCALE"; + AssetUtility.HandleOnPostprocessAllAssets(imported); + } #region Initialization static SpineEditorUtilities () { Initialize(); } - static void LoadPreferences () { - defaultMix = EditorPrefs.GetFloat(DEFAULT_MIX_KEY, DEFAULT_DEFAULT_MIX); - defaultScale = EditorPrefs.GetFloat(DEFAULT_SCALE_KEY, DEFAULT_DEFAULT_SCALE); - defaultZSpacing = EditorPrefs.GetFloat(DEFAULT_ZSPACING_KEY, DEFAULT_DEFAULT_ZSPACING); - defaultShader = EditorPrefs.GetString(DEFAULT_SHADER_KEY, DEFAULT_DEFAULT_SHADER); - showHierarchyIcons = EditorPrefs.GetBool(SHOW_HIERARCHY_ICONS_KEY, DEFAULT_SHOW_HIERARCHY_ICONS); - setTextureImporterSettings = EditorPrefs.GetBool(SET_TEXTUREIMPORTER_SETTINGS_KEY, DEFAULT_SET_TEXTUREIMPORTER_SETTINGS); - SpineHandles.handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, DEFAULT_SCENE_ICONS_SCALE); - preferencesLoaded = true; - } - static void Initialize () { - LoadPreferences(); + Preferences.Load(); DirectoryInfo rootDir = new DirectoryInfo(Application.dataPath); FileInfo[] files = rootDir.GetFiles("SpineEditorUtilities.cs", SearchOption.AllDirectories); @@ -225,20 +187,21 @@ namespace Spine.Unity.Editor { Icons.Initialize(); // Drag and Drop - SceneView.onSceneGUIDelegate -= SceneViewDragAndDrop; - SceneView.onSceneGUIDelegate += SceneViewDragAndDrop; - EditorApplication.hierarchyWindowItemOnGUI -= SpineEditorHierarchyHandler.HierarchyDragAndDrop; - EditorApplication.hierarchyWindowItemOnGUI += SpineEditorHierarchyHandler.HierarchyDragAndDrop; + SceneView.onSceneGUIDelegate -= DragAndDropInstantiation.SceneViewDragAndDrop; + SceneView.onSceneGUIDelegate += DragAndDropInstantiation.SceneViewDragAndDrop; + + EditorApplication.hierarchyWindowItemOnGUI -= HierarchyHandler.HandleDragAndDrop; + EditorApplication.hierarchyWindowItemOnGUI += HierarchyHandler.HandleDragAndDrop; // Hierarchy Icons #if UNITY_2017_2_OR_NEWER - EditorApplication.playModeStateChanged -= SpineEditorHierarchyHandler.HierarchyIconsOnPlaymodeStateChanged; - EditorApplication.playModeStateChanged += SpineEditorHierarchyHandler.HierarchyIconsOnPlaymodeStateChanged; - SpineEditorHierarchyHandler.HierarchyIconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode); + EditorApplication.playModeStateChanged -= HierarchyHandler.IconsOnPlaymodeStateChanged; + EditorApplication.playModeStateChanged += HierarchyHandler.IconsOnPlaymodeStateChanged; + HierarchyHandler.IconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode); #else - EditorApplication.playmodeStateChanged -= SpineEditorHierarchyHandler.HierarchyIconsOnPlaymodeStateChanged; - EditorApplication.playmodeStateChanged += SpineEditorHierarchyHandler.HierarchyIconsOnPlaymodeStateChanged; - SpineEditorHierarchyHandler.HierarchyIconsOnPlaymodeStateChanged(); + EditorApplication.playmodeStateChanged -= HierarchyHandler.IconsOnPlaymodeStateChanged; + EditorApplication.playmodeStateChanged += HierarchyHandler.IconsOnPlaymodeStateChanged; + HierarchyHandler.IconsOnPlaymodeStateChanged(); #endif initialized = true; @@ -250,388 +213,168 @@ namespace Spine.Unity.Editor { } #endregion - #region Spine Preferences and Defaults - static bool preferencesLoaded = false; - - [PreferenceItem("Spine")] - static void PreferencesGUI () { - if (!preferencesLoaded) - LoadPreferences(); - - EditorGUI.BeginChangeCheck(); - showHierarchyIcons = EditorGUILayout.Toggle(new GUIContent("Show Hierarchy Icons", "Show relevant icons on GameObjects with Spine Components on them. Disable this if you have large, complex scenes."), showHierarchyIcons); - if (EditorGUI.EndChangeCheck()) { - EditorPrefs.SetBool(SHOW_HIERARCHY_ICONS_KEY, showHierarchyIcons); - #if UNITY_2017_2_OR_NEWER - SpineEditorHierarchyHandler.HierarchyIconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode); - #else - SpineEditorHierarchyHandler.HierarchyIconsOnPlaymodeStateChanged(); - #endif - } - - EditorGUILayout.Separator(); - - EditorGUILayout.LabelField("Auto-Import Settings", EditorStyles.boldLabel); - - EditorGUI.BeginChangeCheck(); - defaultMix = EditorGUILayout.FloatField("Default Mix", defaultMix); - if (EditorGUI.EndChangeCheck()) - EditorPrefs.SetFloat(DEFAULT_MIX_KEY, defaultMix); - - EditorGUI.BeginChangeCheck(); - defaultScale = EditorGUILayout.FloatField("Default SkeletonData Scale", defaultScale); - if (EditorGUI.EndChangeCheck()) - EditorPrefs.SetFloat(DEFAULT_SCALE_KEY, defaultScale); - - EditorGUI.BeginChangeCheck(); - var shader = (EditorGUILayout.ObjectField("Default Shader", Shader.Find(defaultShader), typeof(Shader), false) as Shader); - defaultShader = shader != null ? shader.name : DEFAULT_DEFAULT_SHADER; - if (EditorGUI.EndChangeCheck()) - EditorPrefs.SetString(DEFAULT_SHADER_KEY, defaultShader); - - EditorGUI.BeginChangeCheck(); - setTextureImporterSettings = EditorGUILayout.Toggle(new GUIContent("Apply Atlas Texture Settings", "Apply the recommended settings for Texture Importers."), showHierarchyIcons); - if (EditorGUI.EndChangeCheck()) { - EditorPrefs.SetBool(SET_TEXTUREIMPORTER_SETTINGS_KEY, showHierarchyIcons); - } - - EditorGUILayout.Space(); - - EditorGUILayout.LabelField("Editor Instantiation", EditorStyles.boldLabel); - EditorGUI.BeginChangeCheck(); - defaultZSpacing = EditorGUILayout.Slider("Default Slot Z-Spacing", defaultZSpacing, -0.1f, 0f); - if (EditorGUI.EndChangeCheck()) - EditorPrefs.SetFloat(DEFAULT_ZSPACING_KEY, defaultZSpacing); - - - EditorGUILayout.Space(); - EditorGUILayout.LabelField("Handles and Gizmos", EditorStyles.boldLabel); - EditorGUI.BeginChangeCheck(); - SpineHandles.handleScale = EditorGUILayout.Slider("Editor Bone Scale", SpineHandles.handleScale, 0.01f, 2f); - SpineHandles.handleScale = Mathf.Max(0.01f, SpineHandles.handleScale); - if (EditorGUI.EndChangeCheck()) { - EditorPrefs.SetFloat(SCENE_ICONS_SCALE_KEY, SpineHandles.handleScale); - SceneView.RepaintAll(); - } - - - GUILayout.Space(20); - EditorGUILayout.LabelField("3rd Party Settings", EditorStyles.boldLabel); - using (new GUILayout.HorizontalScope()) { - EditorGUILayout.PrefixLabel("Define TK2D"); - if (GUILayout.Button("Enable", GUILayout.Width(64))) - SpineTK2DEditorUtility.EnableTK2D(); - if (GUILayout.Button("Disable", GUILayout.Width(64))) - SpineTK2DEditorUtility.DisableTK2D(); - } - } - #endregion - - #region Drag and Drop Instantiation - public delegate Component InstantiateDelegate (SkeletonDataAsset skeletonDataAsset); - - public struct SpawnMenuData { - public Vector3 spawnPoint; - public SkeletonDataAsset skeletonDataAsset; - public InstantiateDelegate instantiateDelegate; - public bool isUI; - } - - public class SkeletonComponentSpawnType { - public string menuLabel; - public InstantiateDelegate instantiateDelegate; - public bool isUI; - } - - internal static readonly List additionalSpawnTypes = new List(); - - static void SceneViewDragAndDrop (SceneView sceneview) { - var current = UnityEngine.Event.current; - var references = DragAndDrop.objectReferences; - if (current.type == EventType.Layout) return; - - // Allow drag and drop of one SkeletonDataAsset. - if (references.Length == 1) { - var skeletonDataAsset = references[0] as SkeletonDataAsset; - if (skeletonDataAsset != null) { - var mousePos = current.mousePosition; - - bool invalidSkeletonData = skeletonDataAsset.GetSkeletonData(true) == null; - if (invalidSkeletonData) { - DragAndDrop.visualMode = DragAndDropVisualMode.Rejected; - Handles.BeginGUI(); - GUI.Label(new Rect(mousePos + new Vector2(20f, 20f), new Vector2(400f, 40f)), new GUIContent(string.Format("{0} is invalid.\nCannot create new Spine GameObject.", skeletonDataAsset.name), SpineEditorUtilities.Icons.warning)); - Handles.EndGUI(); - return; - } else { - DragAndDrop.visualMode = DragAndDropVisualMode.Copy; - Handles.BeginGUI(); - GUI.Label(new Rect(mousePos + new Vector2(20f, 20f), new Vector2(400f, 20f)), new GUIContent(string.Format("Create Spine GameObject ({0})", skeletonDataAsset.skeletonJSON.name), SpineEditorUtilities.Icons.skeletonDataAssetIcon)); - Handles.EndGUI(); - - if (current.type == EventType.DragPerform) { - RectTransform rectTransform = (Selection.activeGameObject == null) ? null : Selection.activeGameObject.GetComponent(); - Plane plane = (rectTransform == null) ? new Plane(Vector3.back, Vector3.zero) : new Plane(-rectTransform.forward, rectTransform.position); - Vector3 spawnPoint = MousePointToWorldPoint2D(mousePos, sceneview.camera, plane); - ShowInstantiateContextMenu(skeletonDataAsset, spawnPoint); - DragAndDrop.AcceptDrag(); - current.Use(); - } - } - } - } - } - - public static void ShowInstantiateContextMenu (SkeletonDataAsset skeletonDataAsset, Vector3 spawnPoint) { - var menu = new GenericMenu(); - - // SkeletonAnimation - menu.AddItem(new GUIContent("SkeletonAnimation"), false, HandleSkeletonComponentDrop, new SpawnMenuData { - skeletonDataAsset = skeletonDataAsset, - spawnPoint = spawnPoint, - instantiateDelegate = (data) => InstantiateSkeletonAnimation(data), - isUI = false - }); - - // SkeletonGraphic - var skeletonGraphicInspectorType = System.Type.GetType("Spine.Unity.Editor.SkeletonGraphicInspector"); - if (skeletonGraphicInspectorType != null) { - var graphicInstantiateDelegate = skeletonGraphicInspectorType.GetMethod("SpawnSkeletonGraphicFromDrop", BindingFlags.Static | BindingFlags.Public); - if (graphicInstantiateDelegate != null) - menu.AddItem(new GUIContent("SkeletonGraphic (UI)"), false, HandleSkeletonComponentDrop, new SpawnMenuData { - skeletonDataAsset = skeletonDataAsset, - spawnPoint = spawnPoint, - instantiateDelegate = System.Delegate.CreateDelegate(typeof(InstantiateDelegate), graphicInstantiateDelegate) as InstantiateDelegate, - isUI = true - }); - } - - #if SPINE_SKELETONMECANIM - menu.AddSeparator(""); - // SkeletonMecanim - menu.AddItem(new GUIContent("SkeletonMecanim"), false, HandleSkeletonComponentDrop, new SpawnMenuData { - skeletonDataAsset = skeletonDataAsset, - spawnPoint = spawnPoint, - instantiateDelegate = (data) => InstantiateSkeletonMecanim(data) - }); - #endif - - menu.ShowAsContext(); - } - - public static void HandleSkeletonComponentDrop (object spawnMenuData) { - var data = (SpawnMenuData)spawnMenuData; - - if (data.skeletonDataAsset.GetSkeletonData(true) == null) { - EditorUtility.DisplayDialog("Invalid SkeletonDataAsset", "Unable to create Spine GameObject.\n\nPlease check your SkeletonDataAsset.", "Ok"); - return; - } - - bool isUI = data.isUI; - - Component newSkeletonComponent = data.instantiateDelegate.Invoke(data.skeletonDataAsset); - GameObject newGameObject = newSkeletonComponent.gameObject; - Transform newTransform = newGameObject.transform; - - var activeGameObject = Selection.activeGameObject; - if (isUI && activeGameObject != null) - newTransform.SetParent(activeGameObject.transform, false); - - newTransform.position = isUI ? data.spawnPoint : RoundVector(data.spawnPoint, 2); - - if (isUI && (activeGameObject == null || activeGameObject.GetComponent() == null)) - Debug.Log("Created a UI Skeleton GameObject not under a RectTransform. It may not be visible until you parent it to a canvas."); - - if (!isUI && activeGameObject != null && activeGameObject.transform.localScale != Vector3.one) - Debug.Log("New Spine GameObject was parented to a scaled Transform. It may not be the intended size."); - - Selection.activeGameObject = newGameObject; - //EditorGUIUtility.PingObject(newGameObject); // Doesn't work when setting activeGameObject. - Undo.RegisterCreatedObjectUndo(newGameObject, "Create Spine GameObject"); - } - - /// - /// Rounds off vector components to a number of decimal digits. - /// - public static Vector3 RoundVector (Vector3 vector, int digits) { - vector.x = (float)System.Math.Round(vector.x, digits); - vector.y = (float)System.Math.Round(vector.y, digits); - vector.z = (float)System.Math.Round(vector.z, digits); - return vector; - } - - /// - /// Converts a mouse point to a world point on a plane. - /// - static Vector3 MousePointToWorldPoint2D (Vector2 mousePosition, Camera camera, Plane plane) { - var screenPos = new Vector3(mousePosition.x, camera.pixelHeight - mousePosition.y, 0f); - var ray = camera.ScreenPointToRay(screenPos); - float distance; - bool hit = plane.Raycast(ray, out distance); - return ray.GetPoint(distance); - } - #endregion - - #region Hierarchy - static class SpineEditorHierarchyHandler { - static Dictionary skeletonRendererTable = new Dictionary(); - static Dictionary skeletonUtilityBoneTable = new Dictionary(); - static Dictionary boundingBoxFollowerTable = new Dictionary(); - - #if UNITY_2017_2_OR_NEWER - internal static void HierarchyIconsOnPlaymodeStateChanged (PlayModeStateChange stateChange) { + public static class Preferences { + #if SPINE_TK2D + const float DEFAULT_DEFAULT_SCALE = 1f; #else - internal static void HierarchyIconsOnPlaymodeStateChanged () { + const float DEFAULT_DEFAULT_SCALE = 0.01f; #endif - skeletonRendererTable.Clear(); - skeletonUtilityBoneTable.Clear(); - boundingBoxFollowerTable.Clear(); + const string DEFAULT_SCALE_KEY = "SPINE_DEFAULT_SCALE"; + public static float defaultScale = DEFAULT_DEFAULT_SCALE; - #if UNITY_2018 - EditorApplication.hierarchyChanged -= HierarchyIconsOnChanged; - #else - EditorApplication.hierarchyWindowChanged -= HierarchyIconsOnChanged; - #endif - EditorApplication.hierarchyWindowItemOnGUI -= HierarchyIconsOnGUI; + const float DEFAULT_DEFAULT_MIX = 0.2f; + const string DEFAULT_MIX_KEY = "SPINE_DEFAULT_MIX"; + public static float defaultMix = DEFAULT_DEFAULT_MIX; - if (!Application.isPlaying && showHierarchyIcons) { - #if UNITY_2018 - EditorApplication.hierarchyChanged += HierarchyIconsOnChanged; + const string DEFAULT_DEFAULT_SHADER = "Spine/Skeleton"; + const string DEFAULT_SHADER_KEY = "SPINE_DEFAULT_SHADER"; + public static string defaultShader = DEFAULT_DEFAULT_SHADER; + + const float DEFAULT_DEFAULT_ZSPACING = 0f; + const string DEFAULT_ZSPACING_KEY = "SPINE_DEFAULT_ZSPACING"; + public static float defaultZSpacing = DEFAULT_DEFAULT_ZSPACING; + + const bool DEFAULT_SHOW_HIERARCHY_ICONS = true; + const string SHOW_HIERARCHY_ICONS_KEY = "SPINE_SHOW_HIERARCHY_ICONS"; + public static bool showHierarchyIcons = DEFAULT_SHOW_HIERARCHY_ICONS; + + const bool DEFAULT_SET_TEXTUREIMPORTER_SETTINGS = true; + const string SET_TEXTUREIMPORTER_SETTINGS_KEY = "SPINE_SET_TEXTUREIMPORTER_SETTINGS"; + public static bool setTextureImporterSettings = DEFAULT_SET_TEXTUREIMPORTER_SETTINGS; + + internal const float DEFAULT_MIPMAPBIAS = -0.5f; + + public const float DEFAULT_SCENE_ICONS_SCALE = 1f; + public const string SCENE_ICONS_SCALE_KEY = "SPINE_SCENE_ICONS_SCALE"; + + static bool preferencesLoaded = false; + + public static void Load () { + defaultMix = EditorPrefs.GetFloat(DEFAULT_MIX_KEY, DEFAULT_DEFAULT_MIX); + defaultScale = EditorPrefs.GetFloat(DEFAULT_SCALE_KEY, DEFAULT_DEFAULT_SCALE); + defaultZSpacing = EditorPrefs.GetFloat(DEFAULT_ZSPACING_KEY, DEFAULT_DEFAULT_ZSPACING); + defaultShader = EditorPrefs.GetString(DEFAULT_SHADER_KEY, DEFAULT_DEFAULT_SHADER); + showHierarchyIcons = EditorPrefs.GetBool(SHOW_HIERARCHY_ICONS_KEY, DEFAULT_SHOW_HIERARCHY_ICONS); + setTextureImporterSettings = EditorPrefs.GetBool(SET_TEXTUREIMPORTER_SETTINGS_KEY, DEFAULT_SET_TEXTUREIMPORTER_SETTINGS); + SpineHandles.handleScale = EditorPrefs.GetFloat(SCENE_ICONS_SCALE_KEY, DEFAULT_SCENE_ICONS_SCALE); + preferencesLoaded = true; + } + + public static void HandlePreferencesGUI () { + if (!preferencesLoaded) + Load(); + + EditorGUI.BeginChangeCheck(); + showHierarchyIcons = EditorGUILayout.Toggle(new GUIContent("Show Hierarchy Icons", "Show relevant icons on GameObjects with Spine Components on them. Disable this if you have large, complex scenes."), showHierarchyIcons); + if (EditorGUI.EndChangeCheck()) { + EditorPrefs.SetBool(SHOW_HIERARCHY_ICONS_KEY, showHierarchyIcons); + #if UNITY_2017_2_OR_NEWER + SpineEditorHierarchyHandler.HierarchyIconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode); #else - EditorApplication.hierarchyWindowChanged += HierarchyIconsOnChanged; + HierarchyHandler.IconsOnPlaymodeStateChanged(); #endif - EditorApplication.hierarchyWindowItemOnGUI += HierarchyIconsOnGUI; - HierarchyIconsOnChanged(); - } - } - - internal static void HierarchyIconsOnChanged () { - skeletonRendererTable.Clear(); - skeletonUtilityBoneTable.Clear(); - boundingBoxFollowerTable.Clear(); - - SkeletonRenderer[] arr = Object.FindObjectsOfType(); - foreach (SkeletonRenderer r in arr) - skeletonRendererTable[r.gameObject.GetInstanceID()] = r.gameObject; - - SkeletonUtilityBone[] boneArr = Object.FindObjectsOfType(); - foreach (SkeletonUtilityBone b in boneArr) - skeletonUtilityBoneTable[b.gameObject.GetInstanceID()] = b; - - BoundingBoxFollower[] bbfArr = Object.FindObjectsOfType(); - foreach (BoundingBoxFollower bbf in bbfArr) - boundingBoxFollowerTable[bbf.gameObject.GetInstanceID()] = bbf; - } - - internal static void HierarchyIconsOnGUI (int instanceId, Rect selectionRect) { - Rect r = new Rect(selectionRect); - if (skeletonRendererTable.ContainsKey(instanceId)) { - r.x = r.width - 15; - r.width = 15; - GUI.Label(r, Icons.spine); - } else if (skeletonUtilityBoneTable.ContainsKey(instanceId)) { - r.x -= 26; - if (skeletonUtilityBoneTable[instanceId] != null) { - if (skeletonUtilityBoneTable[instanceId].transform.childCount == 0) - r.x += 13; - r.y += 2; - r.width = 13; - r.height = 13; - if (skeletonUtilityBoneTable[instanceId].mode == SkeletonUtilityBone.Mode.Follow) - GUI.DrawTexture(r, Icons.bone); - else - GUI.DrawTexture(r, Icons.poseBones); - } - } else if (boundingBoxFollowerTable.ContainsKey(instanceId)) { - r.x -= 26; - if (boundingBoxFollowerTable[instanceId] != null) { - if (boundingBoxFollowerTable[instanceId].transform.childCount == 0) - r.x += 13; - r.y += 2; - r.width = 13; - r.height = 13; - GUI.DrawTexture(r, Icons.boundingBox); - } - } - } - - internal static void HierarchyDragAndDrop (int instanceId, Rect selectionRect) { - // HACK: Uses EditorApplication.hierarchyWindowItemOnGUI. - // Only works when there is at least one item in the scene. - var current = UnityEngine.Event.current; - var eventType = current.type; - bool isDraggingEvent = eventType == EventType.DragUpdated; - bool isDropEvent = eventType == EventType.DragPerform; - if (isDraggingEvent || isDropEvent) { - var mouseOverWindow = EditorWindow.mouseOverWindow; - if (mouseOverWindow != null) { - - // One, existing, valid SkeletonDataAsset - var references = DragAndDrop.objectReferences; - if (references.Length == 1) { - var skeletonDataAsset = references[0] as SkeletonDataAsset; - if (skeletonDataAsset != null && skeletonDataAsset.GetSkeletonData(true) != null) { - - // Allow drag-and-dropping anywhere in the Hierarchy Window. - // HACK: string-compare because we can't get its type via reflection. - const string HierarchyWindow = "UnityEditor.SceneHierarchyWindow"; - if (HierarchyWindow.Equals(mouseOverWindow.GetType().ToString(), System.StringComparison.Ordinal)) { - if (isDraggingEvent) { - DragAndDrop.visualMode = DragAndDropVisualMode.Copy; - current.Use(); - } else if (isDropEvent) { - ShowInstantiateContextMenu(skeletonDataAsset, Vector3.zero); - DragAndDrop.AcceptDrag(); - current.Use(); - return; - } - } - - } - } - } } + EditorGUILayout.Separator(); + + EditorGUILayout.LabelField("Auto-Import Settings", EditorStyles.boldLabel); + + EditorGUI.BeginChangeCheck(); + defaultMix = EditorGUILayout.FloatField("Default Mix", defaultMix); + if (EditorGUI.EndChangeCheck()) + EditorPrefs.SetFloat(DEFAULT_MIX_KEY, defaultMix); + + EditorGUI.BeginChangeCheck(); + defaultScale = EditorGUILayout.FloatField("Default SkeletonData Scale", defaultScale); + if (EditorGUI.EndChangeCheck()) + EditorPrefs.SetFloat(DEFAULT_SCALE_KEY, defaultScale); + + EditorGUI.BeginChangeCheck(); + var shader = (EditorGUILayout.ObjectField("Default Shader", Shader.Find(defaultShader), typeof(Shader), false) as Shader); + defaultShader = shader != null ? shader.name : DEFAULT_DEFAULT_SHADER; + if (EditorGUI.EndChangeCheck()) + EditorPrefs.SetString(DEFAULT_SHADER_KEY, defaultShader); + + EditorGUI.BeginChangeCheck(); + setTextureImporterSettings = EditorGUILayout.Toggle(new GUIContent("Apply Atlas Texture Settings", "Apply the recommended settings for Texture Importers."), showHierarchyIcons); + if (EditorGUI.EndChangeCheck()) { + EditorPrefs.SetBool(SET_TEXTUREIMPORTER_SETTINGS_KEY, showHierarchyIcons); + } + + EditorGUILayout.Space(); + + EditorGUILayout.LabelField("Editor Instantiation", EditorStyles.boldLabel); + EditorGUI.BeginChangeCheck(); + defaultZSpacing = EditorGUILayout.Slider("Default Slot Z-Spacing", defaultZSpacing, -0.1f, 0f); + if (EditorGUI.EndChangeCheck()) + EditorPrefs.SetFloat(DEFAULT_ZSPACING_KEY, defaultZSpacing); + + + EditorGUILayout.Space(); + EditorGUILayout.LabelField("Handles and Gizmos", EditorStyles.boldLabel); + EditorGUI.BeginChangeCheck(); + SpineHandles.handleScale = EditorGUILayout.Slider("Editor Bone Scale", SpineHandles.handleScale, 0.01f, 2f); + SpineHandles.handleScale = Mathf.Max(0.01f, SpineHandles.handleScale); + if (EditorGUI.EndChangeCheck()) { + EditorPrefs.SetFloat(SCENE_ICONS_SCALE_KEY, SpineHandles.handleScale); + SceneView.RepaintAll(); + } + + + GUILayout.Space(20); + EditorGUILayout.LabelField("3rd Party Settings", EditorStyles.boldLabel); + using (new GUILayout.HorizontalScope()) { + EditorGUILayout.PrefixLabel("Define TK2D"); + if (GUILayout.Button("Enable", GUILayout.Width(64))) + SpineTK2DEditorUtility.EnableTK2D(); + if (GUILayout.Button("Disable", GUILayout.Width(64))) + SpineTK2DEditorUtility.DisableTK2D(); + } } } - #endregion - - #region Auto-Import Entry Point - static void OnPostprocessAllAssets (string[] imported, string[] deleted, string[] moved, string[] movedFromAssetPaths) { - if (imported.Length == 0) - return; - - // In case user used "Assets -> Reimport All", during the import process, - // asset database is not initialized until some point. During that period, - // all attempts to load any assets using API (i.e. AssetDatabase.LoadAssetAtPath) - // will return null, and as result, assets won't be loaded even if they actually exists, - // which may lead to numerous importing errors. - // This situation also happens if Library folder is deleted from the project, which is a pretty - // common case, since when using version control systems, the Library folder must be excluded. - // - // So to avoid this, in case asset database is not available, we delay loading the assets - // until next time. - // - // Unity *always* reimports some internal assets after the process is done, so this method - // is always called once again in a state when asset database is available. - // - // Checking whether AssetDatabase is initialized is done by attempting to load - // a known "marker" asset that should always be available. Failing to load this asset - // means that AssetDatabase is not initialized. - assetsImportedInWrongState.UnionWith(imported); - if (AssetDatabaseAvailabilityDetector.IsAssetDatabaseAvailable()) { - string[] combinedAssets = assetsImportedInWrongState.ToArray(); - assetsImportedInWrongState.Clear(); - AssetUtility.ImportSpineContent(combinedAssets); - } - } - - #endregion public static class AssetUtility { public const string SkeletonDataSuffix = "_SkeletonData"; public const string AtlasSuffix = "_Atlas"; + static readonly int[][] compatibleBinaryVersions = { new[] { 3, 7, 0 } }; + static readonly int[][] compatibleJsonVersions = { new[] { 3, 7, 0 }, new[] { 3, 6, 0 }, new[] { 3, 5, 0 } }; + //static bool isFixVersionRequired = false; + + /// HACK: This list keeps the asset reference temporarily during importing. + /// + /// In cases of very large projects/sufficient RAM pressure, when AssetDatabase.SaveAssets is called, + /// Unity can mistakenly unload assets whose references are only on the stack. + /// This leads to MissingReferenceException and other errors. + public static readonly List protectFromStackGarbageCollection = new List(); + public static HashSet assetsImportedInWrongState = new HashSet(); + + public static void HandleOnPostprocessAllAssets (string[] imported) { + // In case user used "Assets -> Reimport All", during the import process, + // asset database is not initialized until some point. During that period, + // all attempts to load any assets using API (i.e. AssetDatabase.LoadAssetAtPath) + // will return null, and as result, assets won't be loaded even if they actually exists, + // which may lead to numerous importing errors. + // This situation also happens if Library folder is deleted from the project, which is a pretty + // common case, since when using version control systems, the Library folder must be excluded. + // + // So to avoid this, in case asset database is not available, we delay loading the assets + // until next time. + // + // Unity *always* reimports some internal assets after the process is done, so this method + // is always called once again in a state when asset database is available. + // + // Checking whether AssetDatabase is initialized is done by attempting to load + // a known "marker" asset that should always be available. Failing to load this asset + // means that AssetDatabase is not initialized. + AssetUtility.assetsImportedInWrongState.UnionWith(imported); + if (AssetDatabaseAvailabilityDetector.IsAssetDatabaseAvailable()) { + string[] combinedAssets = AssetUtility.assetsImportedInWrongState.ToArray(); + AssetUtility.assetsImportedInWrongState.Clear(); + AssetUtility.ImportSpineContent(combinedAssets); + } + } + #region Match SkeletonData with Atlases static readonly AttachmentType[] AtlasTypes = { AttachmentType.Region, AttachmentType.Linkedmesh, AttachmentType.Mesh }; @@ -686,7 +429,7 @@ namespace Spine.Unity.Editor { return requiredPaths; } - static void AddRequiredAtlasRegionsFromBinary (string skeletonDataPath, List requiredPaths) { + internal static void AddRequiredAtlasRegionsFromBinary (string skeletonDataPath, List requiredPaths) { SkeletonBinary binary = new SkeletonBinary(new AtlasRequirementLoader(requiredPaths)); TextAsset data = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonDataPath, typeof(TextAsset)); MemoryStream input = new MemoryStream(data.bytes); @@ -694,7 +437,7 @@ namespace Spine.Unity.Editor { binary = null; } - static AtlasAssetBase GetMatchingAtlas (List requiredPaths, List atlasAssets) { + internal static AtlasAssetBase GetMatchingAtlas (List requiredPaths, List atlasAssets) { AtlasAssetBase atlasAssetMatch = null; foreach (AtlasAssetBase a in atlasAssets) { @@ -769,12 +512,12 @@ namespace Spine.Unity.Editor { break; case ".json": var jsonAsset = (TextAsset)AssetDatabase.LoadAssetAtPath(str, typeof(TextAsset)); - if (jsonAsset != null && SkeletonDataFileValidator.IsSpineData(jsonAsset)) + if (jsonAsset != null && IsSpineData(jsonAsset)) skeletonPaths.Add(str); break; case ".bytes": if (str.ToLower().EndsWith(".skel.bytes", System.StringComparison.Ordinal)) { - if (SkeletonDataFileValidator.IsSpineData((TextAsset)AssetDatabase.LoadAssetAtPath(str, typeof(TextAsset)))) + if (IsSpineData((TextAsset)AssetDatabase.LoadAssetAtPath(str, typeof(TextAsset)))) skeletonPaths.Add(str); } break; @@ -792,7 +535,7 @@ namespace Spine.Unity.Editor { // Import skeletons and match them with atlases. bool abortSkeletonImport = false; foreach (string skeletonPath in skeletonPaths) { - if (!reimport && SkeletonDataFileValidator.CheckForValidSkeletonData(skeletonPath)) { + if (!reimport && CheckForValidSkeletonData(skeletonPath)) { ReloadSkeletonData(skeletonPath); continue; } @@ -808,48 +551,7 @@ namespace Spine.Unity.Editor { if (atlasMatch != null || requiredPaths.Count == 0) { IngestSpineProject(AssetDatabase.LoadAssetAtPath(skeletonPath, typeof(TextAsset)) as TextAsset, atlasMatch); } else { - bool resolved = false; - while (!resolved) { - - string filename = Path.GetFileNameWithoutExtension(skeletonPath); - int result = EditorUtility.DisplayDialogComplex( - string.Format("AtlasAsset for \"{0}\"", filename), - string.Format("Could not automatically set the AtlasAsset for \"{0}\".\n\n (You may resolve this manually later.)", filename), - "Resolve atlases...", "Import without atlases", "Stop importing" - ); - - switch (result) { - case -1: - //Debug.Log("Select Atlas"); - AtlasAssetBase selectedAtlas = AssetEditorGUI.BrowseAtlasDialog(Path.GetDirectoryName(skeletonPath)); - if (selectedAtlas != null) { - localAtlases.Clear(); - localAtlases.Add(selectedAtlas); - atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases); - if (atlasMatch != null) { - resolved = true; - IngestSpineProject(AssetDatabase.LoadAssetAtPath(skeletonPath, typeof(TextAsset)) as TextAsset, atlasMatch); - } - } - break; - case 0: // Resolve AtlasAssets... - var atlasList = AssetEditorGUI.MultiAtlasDialog(requiredPaths, Path.GetDirectoryName(skeletonPath), Path.GetFileNameWithoutExtension(skeletonPath)); - if (atlasList != null) - IngestSpineProject(AssetDatabase.LoadAssetAtPath(skeletonPath, typeof(TextAsset)) as TextAsset, atlasList.ToArray()); - - resolved = true; - break; - case 1: // Import without atlas - Debug.LogWarning("Imported with missing atlases. Skeleton will not render: " + Path.GetFileName(skeletonPath)); - IngestSpineProject(AssetDatabase.LoadAssetAtPath(skeletonPath, typeof(TextAsset)) as TextAsset, new AtlasAssetBase[] {} ); - resolved = true; - break; - case 2: // Stop importing all - abortSkeletonImport = true; - resolved = true; - break; - } - } + SkeletonImportDialog(skeletonPath, localAtlases, requiredPaths, ref abortSkeletonImport); } if (abortSkeletonImport) @@ -901,7 +603,7 @@ namespace Spine.Unity.Editor { #if SPINE_SKELETONMECANIM if (currentHash == null || lastHash != currentHash) - UpdateMecanimClips(skeletonDataAsset); + SkeletonBaker.UpdateMecanimClips(skeletonDataAsset); #endif // if (currentHash == null || lastHash != currentHash) @@ -973,7 +675,7 @@ namespace Spine.Unity.Editor { string texturePath = assetPath + "/" + pageFiles[i]; Texture2D texture = (Texture2D)AssetDatabase.LoadAssetAtPath(texturePath, typeof(Texture2D)); - if (setTextureImporterSettings) { + if (SpineEditorUtilities.Preferences.setTextureImporterSettings) { TextureImporter texImporter = (TextureImporter)TextureImporter.GetAtPath(texturePath); if (texImporter == null) { Debug.LogWarning(string.Format("{0} ::: Texture asset \"{1}\" not found. Skipping. Please check your atlas file for renamed files.", atlasAsset.name, texturePath)); @@ -1002,7 +704,7 @@ namespace Spine.Unity.Editor { Material mat = (Material)AssetDatabase.LoadAssetAtPath(materialPath, typeof(Material)); if (mat == null) { - mat = new Material(Shader.Find(defaultShader)); + mat = new Material(Shader.Find(SpineEditorUtilities.Preferences.defaultShader)); AssetDatabase.CreateAsset(mat, materialPath); } else { vestigialMaterials.Remove(mat); @@ -1044,7 +746,7 @@ namespace Spine.Unity.Editor { bool hasBakedRegions = false; for (int i = 0; i < regions.Count; i++) { AtlasRegion region = regions[i]; - string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.GetPathSafeName(region.name) + ".prefab").Replace("\\", "/"); + string bakedPrefabPath = Path.Combine(bakedDirPath, SpineEditorUtilities.AssetUtility.GetPathSafeName(region.name) + ".prefab").Replace("\\", "/"); GameObject prefab = (GameObject)AssetDatabase.LoadAssetAtPath(bakedPrefabPath, typeof(GameObject)); if (prefab != null) { SkeletonBaker.BakeRegion(atlasAsset, region, false); @@ -1063,7 +765,7 @@ namespace Spine.Unity.Editor { #endregion #region Import SkeletonData (json or binary) - static SkeletonDataAsset IngestSpineProject (TextAsset spineJson, params AtlasAssetBase[] atlasAssets) { + internal static SkeletonDataAsset IngestSpineProject (TextAsset spineJson, params AtlasAssetBase[] atlasAssets) { string primaryName = Path.GetFileNameWithoutExtension(spineJson.name); string assetPath = Path.GetDirectoryName(AssetDatabase.GetAssetPath(spineJson)); string filePath = assetPath + "/" + primaryName + SkeletonDataSuffix + ".asset"; @@ -1101,8 +803,8 @@ namespace Spine.Unity.Editor { { skeletonDataAsset.atlasAssets = atlasAssets; skeletonDataAsset.skeletonJSON = spineJson; - skeletonDataAsset.defaultMix = defaultMix; - skeletonDataAsset.scale = defaultScale; + skeletonDataAsset.defaultMix = SpineEditorUtilities.Preferences.defaultMix; + skeletonDataAsset.scale = SpineEditorUtilities.Preferences.defaultScale; } AssetDatabase.CreateAsset(skeletonDataAsset, filePath); @@ -1121,9 +823,142 @@ namespace Spine.Unity.Editor { #endif } #endregion - } - public static class AssetEditorGUI { + #region Spine Skeleton Data File Validation + public static bool CheckForValidSkeletonData (string skeletonJSONPath) { + string dir = Path.GetDirectoryName(skeletonJSONPath); + TextAsset textAsset = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonJSONPath, typeof(TextAsset)); + DirectoryInfo dirInfo = new DirectoryInfo(dir); + FileInfo[] files = dirInfo.GetFiles("*.asset"); + + foreach (var path in files) { + string localPath = dir + "/" + path.Name; + var obj = AssetDatabase.LoadAssetAtPath(localPath, typeof(Object)); + var skeletonDataAsset = obj as SkeletonDataAsset; + if (skeletonDataAsset != null && skeletonDataAsset.skeletonJSON == textAsset) + return true; + } + + return false; + } + + public static bool IsSpineData (TextAsset asset) { + if (asset == null) + return false; + + bool isSpineData = false; + string rawVersion = null; + + int[][] compatibleVersions; + if (asset.name.Contains(".skel")) { + try { + rawVersion = SkeletonBinary.GetVersionString(new MemoryStream(asset.bytes)); + isSpineData = !(string.IsNullOrEmpty(rawVersion)); + compatibleVersions = compatibleBinaryVersions; + } catch (System.Exception e) { + Debug.LogErrorFormat("Failed to read '{0}'. It is likely not a binary Spine SkeletonData file.\n{1}", asset.name, e); + return false; + } + } else { + object obj = Json.Deserialize(new StringReader(asset.text)); + if (obj == null) { + Debug.LogErrorFormat("'{0}' is not valid JSON.", asset.name); + return false; + } + + var root = obj as Dictionary; + if (root == null) { + Debug.LogError("Parser returned an incorrect type."); + return false; + } + + isSpineData = root.ContainsKey("skeleton"); + if (isSpineData) { + var skeletonInfo = (Dictionary)root["skeleton"]; + object jv; + skeletonInfo.TryGetValue("spine", out jv); + rawVersion = jv as string; + } + + compatibleVersions = compatibleJsonVersions; + } + + // Version warning + if (isSpineData) { + string primaryRuntimeVersionDebugString = compatibleVersions[0][0] + "." + compatibleVersions[0][1]; + + if (string.IsNullOrEmpty(rawVersion)) { + Debug.LogWarningFormat("Skeleton '{0}' has no version information. It may be incompatible with your runtime version: spine-unity v{1}", asset.name, primaryRuntimeVersionDebugString); + } else { + string[] versionSplit = rawVersion.Split('.'); + bool match = false; + foreach (var version in compatibleVersions) { + bool primaryMatch = version[0] == int.Parse(versionSplit[0]); + bool secondaryMatch = version[1] == int.Parse(versionSplit[1]); + + // if (isFixVersionRequired) secondaryMatch &= version[2] <= int.Parse(jsonVersionSplit[2]); + + if (primaryMatch && secondaryMatch) { + match = true; + break; + } + } + + if (!match) + Debug.LogWarningFormat("Skeleton '{0}' (exported with Spine {1}) may be incompatible with your runtime version: spine-unity v{2}", asset.name, rawVersion, primaryRuntimeVersionDebugString); + } + } + + return isSpineData; + } + #endregion + + #region Dialogs + public static void SkeletonImportDialog (string skeletonPath, List localAtlases, List requiredPaths, ref bool abortSkeletonImport) { + bool resolved = false; + while (!resolved) { + + string filename = Path.GetFileNameWithoutExtension(skeletonPath); + int result = EditorUtility.DisplayDialogComplex( + string.Format("AtlasAsset for \"{0}\"", filename), + string.Format("Could not automatically set the AtlasAsset for \"{0}\".\n\n (You may resolve this manually later.)", filename), + "Resolve atlases...", "Import without atlases", "Stop importing" + ); + + switch (result) { + case -1: + //Debug.Log("Select Atlas"); + AtlasAssetBase selectedAtlas = BrowseAtlasDialog(Path.GetDirectoryName(skeletonPath)); + if (selectedAtlas != null) { + localAtlases.Clear(); + localAtlases.Add(selectedAtlas); + var atlasMatch = AssetUtility.GetMatchingAtlas(requiredPaths, localAtlases); + if (atlasMatch != null) { + resolved = true; + AssetUtility.IngestSpineProject(AssetDatabase.LoadAssetAtPath(skeletonPath, typeof(TextAsset)) as TextAsset, atlasMatch); + } + } + break; + case 0: // Resolve AtlasAssets... + var atlasList = MultiAtlasDialog(requiredPaths, Path.GetDirectoryName(skeletonPath), Path.GetFileNameWithoutExtension(skeletonPath)); + if (atlasList != null) + AssetUtility.IngestSpineProject(AssetDatabase.LoadAssetAtPath(skeletonPath, typeof(TextAsset)) as TextAsset, atlasList.ToArray()); + + resolved = true; + break; + case 1: // Import without atlas + Debug.LogWarning("Imported with missing atlases. Skeleton will not render: " + Path.GetFileName(skeletonPath)); + AssetUtility.IngestSpineProject(AssetDatabase.LoadAssetAtPath(skeletonPath, typeof(TextAsset)) as TextAsset, new AtlasAssetBase[] { }); + resolved = true; + break; + case 2: // Stop importing all + abortSkeletonImport = true; + resolved = true; + break; + } + } + } + public static List MultiAtlasDialog (List requiredPaths, string initialDirectory, string filename = "") { List atlasAssets = new List(); bool resolved = false; @@ -1223,251 +1058,425 @@ namespace Spine.Unity.Editor { return (AtlasAssetBase)obj; } + #endregion + + public static string GetPathSafeName (string name) { + foreach (char c in System.IO.Path.GetInvalidFileNameChars()) { // Doesn't handle more obscure file name limitations. + name = name.Replace(c, '_'); + } + return name; + } } - #region SkeletonDataFileValidator - internal static class SkeletonDataFileValidator { - static readonly int[][] compatibleBinaryVersions = { new[] { 3, 7, 0 } }; - static readonly int[][] compatibleJsonVersions = { new[] { 3, 7, 0 }, new[] { 3, 6, 0 }, new[] { 3, 5, 0 } }; - //static bool isFixVersionRequired = false; + public static class EditorInstantiation { + public delegate Component InstantiateDelegate (SkeletonDataAsset skeletonDataAsset); - public static bool CheckForValidSkeletonData (string skeletonJSONPath) { - string dir = Path.GetDirectoryName(skeletonJSONPath); - TextAsset textAsset = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonJSONPath, typeof(TextAsset)); - DirectoryInfo dirInfo = new DirectoryInfo(dir); - FileInfo[] files = dirInfo.GetFiles("*.asset"); - - foreach (var path in files) { - string localPath = dir + "/" + path.Name; - var obj = AssetDatabase.LoadAssetAtPath(localPath, typeof(Object)); - var skeletonDataAsset = obj as SkeletonDataAsset; - if (skeletonDataAsset != null && skeletonDataAsset.skeletonJSON == textAsset) - return true; - } - - return false; + public class SkeletonComponentSpawnType { + public string menuLabel; + public InstantiateDelegate instantiateDelegate; + public bool isUI; } - public static bool IsSpineData (TextAsset asset) { - if (asset == null) - return false; + internal static readonly List additionalSpawnTypes = new List(); - bool isSpineData = false; - string rawVersion = null; + public static void IngestAdvancedRenderSettings (SkeletonRenderer skeletonRenderer) { + const string PMAShaderQuery = "Spine/Skeleton"; + const string TintBlackShaderQuery = "Tint Black"; - int[][] compatibleVersions; - if (asset.name.Contains(".skel")) { - try { - rawVersion = SkeletonBinary.GetVersionString(new MemoryStream(asset.bytes)); - isSpineData = !(string.IsNullOrEmpty(rawVersion)); - compatibleVersions = compatibleBinaryVersions; - } catch (System.Exception e) { - Debug.LogErrorFormat("Failed to read '{0}'. It is likely not a binary Spine SkeletonData file.\n{1}", asset.name, e); - return false; - } - } else { - object obj = Json.Deserialize(new StringReader(asset.text)); - if (obj == null) { - Debug.LogErrorFormat("'{0}' is not valid JSON.", asset.name); - return false; - } + if (skeletonRenderer == null) + return; + var skeletonDataAsset = skeletonRenderer.skeletonDataAsset; + if (skeletonDataAsset == null) + return; - var root = obj as Dictionary; - if (root == null) { - Debug.LogError("Parser returned an incorrect type."); - return false; - } - - isSpineData = root.ContainsKey("skeleton"); - if (isSpineData) { - var skeletonInfo = (Dictionary)root["skeleton"]; - object jv; - skeletonInfo.TryGetValue("spine", out jv); - rawVersion = jv as string; - } - - compatibleVersions = compatibleJsonVersions; - } - - // Version warning - if (isSpineData) { - string primaryRuntimeVersionDebugString = compatibleVersions[0][0] + "." + compatibleVersions[0][1]; - - if (string.IsNullOrEmpty(rawVersion)) { - Debug.LogWarningFormat("Skeleton '{0}' has no version information. It may be incompatible with your runtime version: spine-unity v{1}", asset.name, primaryRuntimeVersionDebugString); - } else { - string[] versionSplit = rawVersion.Split('.'); - bool match = false; - foreach (var version in compatibleVersions) { - bool primaryMatch = version[0] == int.Parse(versionSplit[0]); - bool secondaryMatch = version[1] == int.Parse(versionSplit[1]); - - // if (isFixVersionRequired) secondaryMatch &= version[2] <= int.Parse(jsonVersionSplit[2]); - - if (primaryMatch && secondaryMatch) { - match = true; + bool pmaVertexColors = false; + bool tintBlack = false; + foreach (SpineAtlasAsset atlasAsset in skeletonDataAsset.atlasAssets) { + if (!pmaVertexColors) { + foreach (Material m in atlasAsset.materials) { + if (m.shader.name.Contains(PMAShaderQuery)) { + pmaVertexColors = true; break; } } - - if (!match) - Debug.LogWarningFormat("Skeleton '{0}' (exported with Spine {1}) may be incompatible with your runtime version: spine-unity v{2}", asset.name, rawVersion, primaryRuntimeVersionDebugString); } - } - return isSpineData; - } - } - - #endregion - - #region SkeletonAnimation Menu - public static void IngestAdvancedRenderSettings (SkeletonRenderer skeletonRenderer) { - const string PMAShaderQuery = "Spine/Skeleton"; - const string TintBlackShaderQuery = "Tint Black"; - - if (skeletonRenderer == null) return; - var skeletonDataAsset = skeletonRenderer.skeletonDataAsset; - if (skeletonDataAsset == null) return; - - bool pmaVertexColors = false; - bool tintBlack = false; - foreach (SpineAtlasAsset atlasAsset in skeletonDataAsset.atlasAssets) { - if (!pmaVertexColors) { - foreach (Material m in atlasAsset.materials) { - if (m.shader.name.Contains(PMAShaderQuery)) { - pmaVertexColors = true; - break; + if (!tintBlack) { + foreach (Material m in atlasAsset.materials) { + if (m.shader.name.Contains(TintBlackShaderQuery)) { + tintBlack = true; + break; + } } } } - if (!tintBlack) { - foreach (Material m in atlasAsset.materials) { - if (m.shader.name.Contains(TintBlackShaderQuery)) { - tintBlack = true; - break; + skeletonRenderer.pmaVertexColors = pmaVertexColors; + skeletonRenderer.tintBlack = tintBlack; + } + + public static SkeletonAnimation InstantiateSkeletonAnimation (SkeletonDataAsset skeletonDataAsset, string skinName, bool destroyInvalid = true) { + var skeletonData = skeletonDataAsset.GetSkeletonData(true); + var skin = skeletonData != null ? skeletonData.FindSkin(skinName) : null; + return InstantiateSkeletonAnimation(skeletonDataAsset, skin, destroyInvalid); + } + + public static SkeletonAnimation InstantiateSkeletonAnimation (SkeletonDataAsset skeletonDataAsset, Skin skin = null, bool destroyInvalid = true) { + SkeletonData data = skeletonDataAsset.GetSkeletonData(true); + + if (data == null) { + for (int i = 0; i < skeletonDataAsset.atlasAssets.Length; i++) { + string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAssets[i]); + skeletonDataAsset.atlasAssets[i] = (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAssetBase)); + } + data = skeletonDataAsset.GetSkeletonData(false); + } + + if (data == null) { + Debug.LogWarning("InstantiateSkeletonAnimation tried to instantiate a skeleton from an invalid SkeletonDataAsset."); + return null; + } + + string spineGameObjectName = string.Format("Spine GameObject ({0})", skeletonDataAsset.name.Replace("_SkeletonData", "")); + GameObject go = new GameObject(spineGameObjectName, typeof(MeshFilter), typeof(MeshRenderer), typeof(SkeletonAnimation)); + SkeletonAnimation newSkeletonAnimation = go.GetComponent(); + newSkeletonAnimation.skeletonDataAsset = skeletonDataAsset; + IngestAdvancedRenderSettings(newSkeletonAnimation); + + try { + newSkeletonAnimation.Initialize(false); + } catch (System.Exception e) { + if (destroyInvalid) { + Debug.LogWarning("Editor-instantiated SkeletonAnimation threw an Exception. Destroying GameObject to prevent orphaned GameObject."); + GameObject.DestroyImmediate(go); + } + throw e; + } + + // Set Defaults + bool noSkins = data.DefaultSkin == null && (data.Skins == null || data.Skins.Count == 0); // Support attachmentless/skinless SkeletonData. + skin = skin ?? data.DefaultSkin ?? (noSkins ? null : data.Skins.Items[0]); + if (skin != null) { + newSkeletonAnimation.initialSkinName = skin.Name; + newSkeletonAnimation.skeleton.SetSkin(skin); + } + + newSkeletonAnimation.zSpacing = SpineEditorUtilities.Preferences.defaultZSpacing; + + newSkeletonAnimation.skeleton.Update(0); + newSkeletonAnimation.state.Update(0); + newSkeletonAnimation.state.Apply(newSkeletonAnimation.skeleton); + newSkeletonAnimation.skeleton.UpdateWorldTransform(); + + return newSkeletonAnimation; + } + + #region SkeletonMecanim + #if SPINE_SKELETONMECANIM + public static SkeletonMecanim InstantiateSkeletonMecanim (SkeletonDataAsset skeletonDataAsset, string skinName) { + return InstantiateSkeletonMecanim(skeletonDataAsset, skeletonDataAsset.GetSkeletonData(true).FindSkin(skinName)); + } + + public static SkeletonMecanim InstantiateSkeletonMecanim (SkeletonDataAsset skeletonDataAsset, Skin skin = null) { + string spineGameObjectName = string.Format("Spine Mecanim GameObject ({0})", skeletonDataAsset.name.Replace("_SkeletonData", "")); + GameObject go = new GameObject(spineGameObjectName, typeof(MeshFilter), typeof(MeshRenderer), typeof(Animator), typeof(SkeletonMecanim)); + + if (skeletonDataAsset.controller == null) { + SkeletonBaker.GenerateMecanimAnimationClips(skeletonDataAsset); + Debug.Log(string.Format("Mecanim controller was automatically generated and assigned for {0}", skeletonDataAsset.name)); + } + + go.GetComponent().runtimeAnimatorController = skeletonDataAsset.controller; + + SkeletonMecanim anim = go.GetComponent(); + anim.skeletonDataAsset = skeletonDataAsset; + IngestAdvancedRenderSettings(anim); + + SkeletonData data = skeletonDataAsset.GetSkeletonData(true); + if (data == null) { + for (int i = 0; i < skeletonDataAsset.atlasAssets.Length; i++) { + string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAssets[i]); + skeletonDataAsset.atlasAssets[i] = (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAssetBase)); + } + data = skeletonDataAsset.GetSkeletonData(true); + } + + // Set defaults + skin = skin ?? data.DefaultSkin ?? data.Skins.Items[0]; + anim.zSpacing = SpineEditorUtilities.Preferences.defaultZSpacing; + + anim.Initialize(false); + anim.skeleton.SetSkin(skin); + anim.initialSkinName = skin.Name; + + anim.skeleton.Update(0); + anim.skeleton.UpdateWorldTransform(); + anim.LateUpdate(); + + return anim; + } + #endif + #endregion + } + + public static class DragAndDropInstantiation { + public struct SpawnMenuData { + public Vector3 spawnPoint; + public SkeletonDataAsset skeletonDataAsset; + public EditorInstantiation.InstantiateDelegate instantiateDelegate; + public bool isUI; + } + + public static void SceneViewDragAndDrop (SceneView sceneview) { + var current = UnityEngine.Event.current; + var references = DragAndDrop.objectReferences; + if (current.type == EventType.Layout) + return; + + // Allow drag and drop of one SkeletonDataAsset. + if (references.Length == 1) { + var skeletonDataAsset = references[0] as SkeletonDataAsset; + if (skeletonDataAsset != null) { + var mousePos = current.mousePosition; + + bool invalidSkeletonData = skeletonDataAsset.GetSkeletonData(true) == null; + if (invalidSkeletonData) { + DragAndDrop.visualMode = DragAndDropVisualMode.Rejected; + Handles.BeginGUI(); + GUI.Label(new Rect(mousePos + new Vector2(20f, 20f), new Vector2(400f, 40f)), new GUIContent(string.Format("{0} is invalid.\nCannot create new Spine GameObject.", skeletonDataAsset.name), SpineEditorUtilities.Icons.warning)); + Handles.EndGUI(); + return; + } else { + DragAndDrop.visualMode = DragAndDropVisualMode.Copy; + Handles.BeginGUI(); + GUI.Label(new Rect(mousePos + new Vector2(20f, 20f), new Vector2(400f, 20f)), new GUIContent(string.Format("Create Spine GameObject ({0})", skeletonDataAsset.skeletonJSON.name), SpineEditorUtilities.Icons.skeletonDataAssetIcon)); + Handles.EndGUI(); + + if (current.type == EventType.DragPerform) { + RectTransform rectTransform = (Selection.activeGameObject == null) ? null : Selection.activeGameObject.GetComponent(); + Plane plane = (rectTransform == null) ? new Plane(Vector3.back, Vector3.zero) : new Plane(-rectTransform.forward, rectTransform.position); + Vector3 spawnPoint = MousePointToWorldPoint2D(mousePos, sceneview.camera, plane); + ShowInstantiateContextMenu(skeletonDataAsset, spawnPoint); + DragAndDrop.AcceptDrag(); + current.Use(); + } } } } } - skeletonRenderer.pmaVertexColors = pmaVertexColors; - skeletonRenderer.tintBlack = tintBlack; - } + public static void ShowInstantiateContextMenu (SkeletonDataAsset skeletonDataAsset, Vector3 spawnPoint) { + var menu = new GenericMenu(); - public static SkeletonAnimation InstantiateSkeletonAnimation (SkeletonDataAsset skeletonDataAsset, string skinName, bool destroyInvalid = true) { - var skeletonData = skeletonDataAsset.GetSkeletonData(true); - var skin = skeletonData != null ? skeletonData.FindSkin(skinName) : null; - return InstantiateSkeletonAnimation(skeletonDataAsset, skin, destroyInvalid); - } + // SkeletonAnimation + menu.AddItem(new GUIContent("SkeletonAnimation"), false, HandleSkeletonComponentDrop, new SpawnMenuData { + skeletonDataAsset = skeletonDataAsset, + spawnPoint = spawnPoint, + instantiateDelegate = (data) => EditorInstantiation.InstantiateSkeletonAnimation(data), + isUI = false + }); - public static SkeletonAnimation InstantiateSkeletonAnimation (SkeletonDataAsset skeletonDataAsset, Skin skin = null, bool destroyInvalid = true) { - SkeletonData data = skeletonDataAsset.GetSkeletonData(true); - - if (data == null) { - for (int i = 0; i < skeletonDataAsset.atlasAssets.Length; i++) { - string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAssets[i]); - skeletonDataAsset.atlasAssets[i] = (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAssetBase)); + // SkeletonGraphic + var skeletonGraphicInspectorType = System.Type.GetType("Spine.Unity.Editor.SkeletonGraphicInspector"); + if (skeletonGraphicInspectorType != null) { + var graphicInstantiateDelegate = skeletonGraphicInspectorType.GetMethod("SpawnSkeletonGraphicFromDrop", BindingFlags.Static | BindingFlags.Public); + if (graphicInstantiateDelegate != null) + menu.AddItem(new GUIContent("SkeletonGraphic (UI)"), false, HandleSkeletonComponentDrop, new SpawnMenuData { + skeletonDataAsset = skeletonDataAsset, + spawnPoint = spawnPoint, + instantiateDelegate = System.Delegate.CreateDelegate(typeof(EditorInstantiation.InstantiateDelegate), graphicInstantiateDelegate) as EditorInstantiation.InstantiateDelegate, + isUI = true + }); } - data = skeletonDataAsset.GetSkeletonData(false); + + #if SPINE_SKELETONMECANIM + menu.AddSeparator(""); + // SkeletonMecanim + menu.AddItem(new GUIContent("SkeletonMecanim"), false, HandleSkeletonComponentDrop, new SpawnMenuData { + skeletonDataAsset = skeletonDataAsset, + spawnPoint = spawnPoint, + instantiateDelegate = (data) => EditorInstantiation.InstantiateSkeletonMecanim(data) + }); + #endif + + menu.ShowAsContext(); } - if (data == null) { - Debug.LogWarning("InstantiateSkeletonAnimation tried to instantiate a skeleton from an invalid SkeletonDataAsset."); - return null; - } + public static void HandleSkeletonComponentDrop (object spawnMenuData) { + var data = (SpawnMenuData)spawnMenuData; - string spineGameObjectName = string.Format("Spine GameObject ({0})", skeletonDataAsset.name.Replace("_SkeletonData", "")); - GameObject go = new GameObject(spineGameObjectName, typeof(MeshFilter), typeof(MeshRenderer), typeof(SkeletonAnimation)); - SkeletonAnimation newSkeletonAnimation = go.GetComponent(); - newSkeletonAnimation.skeletonDataAsset = skeletonDataAsset; - IngestAdvancedRenderSettings(newSkeletonAnimation); - - try { - newSkeletonAnimation.Initialize(false); - } catch (System.Exception e) { - if (destroyInvalid) { - Debug.LogWarning("Editor-instantiated SkeletonAnimation threw an Exception. Destroying GameObject to prevent orphaned GameObject."); - GameObject.DestroyImmediate(go); + if (data.skeletonDataAsset.GetSkeletonData(true) == null) { + EditorUtility.DisplayDialog("Invalid SkeletonDataAsset", "Unable to create Spine GameObject.\n\nPlease check your SkeletonDataAsset.", "Ok"); + return; } - throw e; + + bool isUI = data.isUI; + + Component newSkeletonComponent = data.instantiateDelegate.Invoke(data.skeletonDataAsset); + GameObject newGameObject = newSkeletonComponent.gameObject; + Transform newTransform = newGameObject.transform; + + var activeGameObject = Selection.activeGameObject; + if (isUI && activeGameObject != null) + newTransform.SetParent(activeGameObject.transform, false); + + newTransform.position = isUI ? data.spawnPoint : RoundVector(data.spawnPoint, 2); + + if (isUI && (activeGameObject == null || activeGameObject.GetComponent() == null)) + Debug.Log("Created a UI Skeleton GameObject not under a RectTransform. It may not be visible until you parent it to a canvas."); + + if (!isUI && activeGameObject != null && activeGameObject.transform.localScale != Vector3.one) + Debug.Log("New Spine GameObject was parented to a scaled Transform. It may not be the intended size."); + + Selection.activeGameObject = newGameObject; + //EditorGUIUtility.PingObject(newGameObject); // Doesn't work when setting activeGameObject. + Undo.RegisterCreatedObjectUndo(newGameObject, "Create Spine GameObject"); } - // Set Defaults - bool noSkins = data.DefaultSkin == null && (data.Skins == null || data.Skins.Count == 0); // Support attachmentless/skinless SkeletonData. - skin = skin ?? data.DefaultSkin ?? (noSkins ? null : data.Skins.Items[0]); - if (skin != null) { - newSkeletonAnimation.initialSkinName = skin.Name; - newSkeletonAnimation.skeleton.SetSkin(skin); + /// + /// Rounds off vector components to a number of decimal digits. + /// + public static Vector3 RoundVector (Vector3 vector, int digits) { + vector.x = (float)System.Math.Round(vector.x, digits); + vector.y = (float)System.Math.Round(vector.y, digits); + vector.z = (float)System.Math.Round(vector.z, digits); + return vector; } - newSkeletonAnimation.zSpacing = defaultZSpacing; - - newSkeletonAnimation.skeleton.Update(0); - newSkeletonAnimation.state.Update(0); - newSkeletonAnimation.state.Apply(newSkeletonAnimation.skeleton); - newSkeletonAnimation.skeleton.UpdateWorldTransform(); - - return newSkeletonAnimation; - } - #endregion - - #region SkeletonMecanim - #if SPINE_SKELETONMECANIM - static void UpdateMecanimClips (SkeletonDataAsset skeletonDataAsset) { - if (skeletonDataAsset.controller == null) - return; - - SkeletonBaker.GenerateMecanimAnimationClips(skeletonDataAsset); - } - - public static SkeletonMecanim InstantiateSkeletonMecanim (SkeletonDataAsset skeletonDataAsset, string skinName) { - return InstantiateSkeletonMecanim(skeletonDataAsset, skeletonDataAsset.GetSkeletonData(true).FindSkin(skinName)); - } - - public static SkeletonMecanim InstantiateSkeletonMecanim (SkeletonDataAsset skeletonDataAsset, Skin skin = null) { - string spineGameObjectName = string.Format("Spine Mecanim GameObject ({0})", skeletonDataAsset.name.Replace("_SkeletonData", "")); - GameObject go = new GameObject(spineGameObjectName, typeof(MeshFilter), typeof(MeshRenderer), typeof(Animator), typeof(SkeletonMecanim)); - - if (skeletonDataAsset.controller == null) { - SkeletonBaker.GenerateMecanimAnimationClips(skeletonDataAsset); - Debug.Log(string.Format("Mecanim controller was automatically generated and assigned for {0}", skeletonDataAsset.name)); + /// + /// Converts a mouse point to a world point on a plane. + /// + static Vector3 MousePointToWorldPoint2D (Vector2 mousePosition, Camera camera, Plane plane) { + var screenPos = new Vector3(mousePosition.x, camera.pixelHeight - mousePosition.y, 0f); + var ray = camera.ScreenPointToRay(screenPos); + float distance; + bool hit = plane.Raycast(ray, out distance); + return ray.GetPoint(distance); } + } - go.GetComponent().runtimeAnimatorController = skeletonDataAsset.controller; + static class HierarchyHandler { + static Dictionary skeletonRendererTable = new Dictionary(); + static Dictionary skeletonUtilityBoneTable = new Dictionary(); + static Dictionary boundingBoxFollowerTable = new Dictionary(); - SkeletonMecanim anim = go.GetComponent(); - anim.skeletonDataAsset = skeletonDataAsset; - IngestAdvancedRenderSettings(anim); + #if UNITY_2017_2_OR_NEWER + internal static void IconsOnPlaymodeStateChanged (PlayModeStateChange stateChange) { + #else + internal static void IconsOnPlaymodeStateChanged () { + #endif + skeletonRendererTable.Clear(); + skeletonUtilityBoneTable.Clear(); + boundingBoxFollowerTable.Clear(); - SkeletonData data = skeletonDataAsset.GetSkeletonData(true); - if (data == null) { - for (int i = 0; i < skeletonDataAsset.atlasAssets.Length; i++) { - string reloadAtlasPath = AssetDatabase.GetAssetPath(skeletonDataAsset.atlasAssets[i]); - skeletonDataAsset.atlasAssets[i] = (AtlasAssetBase)AssetDatabase.LoadAssetAtPath(reloadAtlasPath, typeof(AtlasAssetBase)); + #if UNITY_2018 + EditorApplication.hierarchyChanged -= IconsOnChanged; + #else + EditorApplication.hierarchyWindowChanged -= IconsOnChanged; + #endif + EditorApplication.hierarchyWindowItemOnGUI -= IconsOnGUI; + + if (!Application.isPlaying && Preferences.showHierarchyIcons) { + #if UNITY_2018 + EditorApplication.hierarchyChanged += IconsOnChanged; + #else + EditorApplication.hierarchyWindowChanged += IconsOnChanged; + #endif + EditorApplication.hierarchyWindowItemOnGUI += IconsOnGUI; + IconsOnChanged(); } - data = skeletonDataAsset.GetSkeletonData(true); } - // Set defaults - skin = skin ?? data.DefaultSkin ?? data.Skins.Items[0]; - anim.zSpacing = defaultZSpacing; + internal static void IconsOnChanged () { + skeletonRendererTable.Clear(); + skeletonUtilityBoneTable.Clear(); + boundingBoxFollowerTable.Clear(); - anim.Initialize(false); - anim.skeleton.SetSkin(skin); - anim.initialSkinName = skin.Name; + SkeletonRenderer[] arr = Object.FindObjectsOfType(); + foreach (SkeletonRenderer r in arr) + skeletonRendererTable[r.gameObject.GetInstanceID()] = r.gameObject; - anim.skeleton.Update(0); - anim.skeleton.UpdateWorldTransform(); - anim.LateUpdate(); + SkeletonUtilityBone[] boneArr = Object.FindObjectsOfType(); + foreach (SkeletonUtilityBone b in boneArr) + skeletonUtilityBoneTable[b.gameObject.GetInstanceID()] = b; - return anim; + BoundingBoxFollower[] bbfArr = Object.FindObjectsOfType(); + foreach (BoundingBoxFollower bbf in bbfArr) + boundingBoxFollowerTable[bbf.gameObject.GetInstanceID()] = bbf; + } + + internal static void IconsOnGUI (int instanceId, Rect selectionRect) { + Rect r = new Rect(selectionRect); + if (skeletonRendererTable.ContainsKey(instanceId)) { + r.x = r.width - 15; + r.width = 15; + GUI.Label(r, Icons.spine); + } else if (skeletonUtilityBoneTable.ContainsKey(instanceId)) { + r.x -= 26; + if (skeletonUtilityBoneTable[instanceId] != null) { + if (skeletonUtilityBoneTable[instanceId].transform.childCount == 0) + r.x += 13; + r.y += 2; + r.width = 13; + r.height = 13; + if (skeletonUtilityBoneTable[instanceId].mode == SkeletonUtilityBone.Mode.Follow) + GUI.DrawTexture(r, Icons.bone); + else + GUI.DrawTexture(r, Icons.poseBones); + } + } else if (boundingBoxFollowerTable.ContainsKey(instanceId)) { + r.x -= 26; + if (boundingBoxFollowerTable[instanceId] != null) { + if (boundingBoxFollowerTable[instanceId].transform.childCount == 0) + r.x += 13; + r.y += 2; + r.width = 13; + r.height = 13; + GUI.DrawTexture(r, Icons.boundingBox); + } + } + } + + internal static void HandleDragAndDrop (int instanceId, Rect selectionRect) { + // HACK: Uses EditorApplication.hierarchyWindowItemOnGUI. + // Only works when there is at least one item in the scene. + var current = UnityEngine.Event.current; + var eventType = current.type; + bool isDraggingEvent = eventType == EventType.DragUpdated; + bool isDropEvent = eventType == EventType.DragPerform; + if (isDraggingEvent || isDropEvent) { + var mouseOverWindow = EditorWindow.mouseOverWindow; + if (mouseOverWindow != null) { + + // One, existing, valid SkeletonDataAsset + var references = UnityEditor.DragAndDrop.objectReferences; + if (references.Length == 1) { + var skeletonDataAsset = references[0] as SkeletonDataAsset; + if (skeletonDataAsset != null && skeletonDataAsset.GetSkeletonData(true) != null) { + + // Allow drag-and-dropping anywhere in the Hierarchy Window. + // HACK: string-compare because we can't get its type via reflection. + const string HierarchyWindow = "UnityEditor.SceneHierarchyWindow"; + if (HierarchyWindow.Equals(mouseOverWindow.GetType().ToString(), System.StringComparison.Ordinal)) { + if (isDraggingEvent) { + UnityEditor.DragAndDrop.visualMode = DragAndDropVisualMode.Copy; + current.Use(); + } else if (isDropEvent) { + DragAndDropInstantiation.ShowInstantiateContextMenu(skeletonDataAsset, Vector3.zero); + UnityEditor.DragAndDrop.AcceptDrag(); + current.Use(); + return; + } + } + + } + } + } + } + + } } -#endif - #endregion - #region SpineTK2DEditorUtility internal static class SpineTK2DEditorUtility { const string SPINE_TK2D_DEFINE = "SPINE_TK2D"; @@ -1530,14 +1539,6 @@ namespace Spine.Unity.Editor { } } } - #endregion - - public static string GetPathSafeName (string name) { - foreach (char c in System.IO.Path.GetInvalidFileNameChars()) { // Doesn't handle more obscure file name limitations. - name = name.Replace(c, '_'); - } - return name; - } } public static class SpineHandles { diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs index bf6bda947..12ab21d20 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Modules/SkeletonGraphic/Editor/SkeletonGraphicInspector.cs @@ -193,7 +193,7 @@ namespace Spine.Unity.Editor { } skin = skin ?? data.DefaultSkin ?? data.Skins.Items[0]; - graphic.MeshGenerator.settings.zSpacing = SpineEditorUtilities.defaultZSpacing; + graphic.MeshGenerator.settings.zSpacing = SpineEditorUtilities.Preferences.defaultZSpacing; graphic.Initialize(false); if (skin != null) graphic.Skeleton.SetSkin(skin); From 6da58244f6f694e6539ed0e13104d18caf48e12f Mon Sep 17 00:00:00 2001 From: pharan Date: Fri, 13 Jul 2018 22:55:49 +0800 Subject: [PATCH 09/15] [unity] Add shadow to Skeleton Fill shader. --- .../Shaders/Spine-Skeleton-Fill.shader | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader index 161b03b59..1c5ab61fe 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader @@ -1,4 +1,4 @@ -// - Unlit + no shadow +// - Unlit // - Premultiplied Alpha Blending (Optional straight alpha input) // - Double-sided, no depth @@ -59,6 +59,46 @@ Shader "Spine/Skeleton Fill" { } ENDCG } + + Pass { + Name "Caster" + Tags { "LightMode"="ShadowCaster" } + Offset 1, 1 + ZWrite On + ZTest LEqual + + Fog { Mode Off } + Cull Off + Lighting Off + + CGPROGRAM + #pragma vertex vert + #pragma fragment frag + #pragma multi_compile_shadowcaster + #pragma fragmentoption ARB_precision_hint_fastest + #include "UnityCG.cginc" + sampler2D _MainTex; + fixed _Cutoff; + + struct VertexOutput { + V2F_SHADOW_CASTER; + float2 uv : TEXCOORD1; + }; + + VertexOutput vert (appdata_base v) { + VertexOutput o; + o.uv = v.texcoord; + TRANSFER_SHADOW_CASTER(o) + return o; + } + + float4 frag (VertexOutput i) : COLOR { + fixed4 texcol = tex2D(_MainTex, i.uv); + clip(texcol.a - _Cutoff); + SHADOW_CASTER_FRAGMENT(i) + } + ENDCG + } } FallBack "Diffuse" -} \ No newline at end of file +} From c4f013b99e62a4f986c068979fc17e0bcb83358d Mon Sep 17 00:00:00 2001 From: pharan Date: Fri, 13 Jul 2018 22:57:33 +0800 Subject: [PATCH 10/15] [unity] Add cutoff property to Fill shader. --- .../spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader | 1 + 1 file changed, 1 insertion(+) diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader index 1c5ab61fe..f331ada19 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader @@ -7,6 +7,7 @@ Shader "Spine/Skeleton Fill" { _FillColor ("FillColor", Color) = (1,1,1,1) _FillPhase ("FillPhase", Range(0, 1)) = 0 [NoScaleOffset] _MainTex ("MainTex", 2D) = "white" {} + _Cutoff ("Shadow alpha cutoff", Range(0,1)) = 0.1 [Toggle(_STRAIGHT_ALPHA_INPUT)] _StraightAlphaInput("Straight Alpha Texture", Int) = 0 } SubShader { From e4eff734975602451fbff4e90d2e939f5832b12d Mon Sep 17 00:00:00 2001 From: pharan Date: Fri, 13 Jul 2018 23:44:06 +0800 Subject: [PATCH 11/15] [unity] Update Spine Examples --- .../Other Examples/Animation Tester.meta | 9 ++ .../Animation Tester/Animation Tester.unity | Bin 0 -> 39608 bytes .../Animation Tester.unity.meta | 8 ++ .../SpineAnimationTesterTool.cs | 117 ++++++++++++++++++ .../SpineAnimationTesterTool.cs.meta | 12 ++ .../Other Examples/Mix and Match Equip.unity | Bin 55199 -> 54816 bytes .../StateMachine SkeletonAnimation.meta | 9 ++ .../AnimationState with Mecanim.unity | Bin 0 -> 18800 bytes .../AnimationState with Mecanim.unity.meta | 8 ++ .../Hero.controller | Bin 0 -> 14208 bytes .../Hero.controller.meta | 9 ++ .../Scripts/AnimationStateMecanimState.cs | 62 ++++++++++ .../AnimationStateMecanimState.cs.meta | 12 ++ .../AnimationStateWithMecanimExample.cs | 82 ++++++++++++ .../AnimationStateWithMecanimExample.cs.meta | 12 ++ .../Scripts/FootSoldierExample.cs | 4 +- .../BasicPlatformerController.cs | 2 +- .../SpineBeginnerTwo.cs | 4 +- .../SpineboyBeginnerView.cs | 4 +- .../SpineboyTargetController.cs | 2 +- .../SkeletonAnimationMulti.cs | 4 +- .../{Spine.meta => Spine Skeletons.meta} | 0 .../{Spine => Spine Skeletons}/Dragon.meta | 0 .../Dragon/dragon.atlas.txt | 0 .../Dragon/dragon.atlas.txt.meta | 0 .../Dragon/dragon.json | 0 .../Dragon/dragon.json.meta | 0 .../Dragon/dragon.png | Bin .../Dragon/dragon.png.meta | 0 .../Dragon/dragon2.png | Bin .../Dragon/dragon2.png.meta | 0 .../Dragon/dragon_Atlas.asset | Bin .../Dragon/dragon_Atlas.asset.meta | 0 .../Dragon/dragon_SkeletonData.asset | 0 .../Dragon/dragon_SkeletonData.asset.meta | 0 .../Dragon/dragon_dragon.mat | Bin .../Dragon/dragon_dragon.mat.meta | 0 .../Dragon/dragon_dragon2.mat | Bin .../Dragon/dragon_dragon2.mat.meta | 0 .../Dragon/license.txt | 0 .../Dragon/license.txt.meta | 0 .../{Spine => Spine Skeletons}/Eyes.meta | 0 .../Eyes/eyes.atlas.txt | 0 .../Eyes/eyes.atlas.txt.meta | 0 .../{Spine => Spine Skeletons}/Eyes/eyes.json | 0 .../Eyes/eyes.json.meta | 0 .../{Spine => Spine Skeletons}/Eyes/eyes.png | Bin .../Eyes/eyes.png.meta | 0 .../Eyes/eyes_Atlas.asset | Bin .../Eyes/eyes_Atlas.asset.meta | 0 .../Eyes/eyes_Material.mat | Bin .../Eyes/eyes_Material.mat.meta | 0 .../Eyes/eyes_SkeletonData.asset | 0 .../Eyes/eyes_SkeletonData.asset.meta | 0 .../FootSoldier.meta | 0 .../FootSoldier/Equipment.meta | 0 .../FootSoldier/Equipment/Equipment.atlas.txt | 0 .../Equipment/Equipment.atlas.txt.meta | 0 .../FootSoldier/Equipment/Equipment.png | Bin .../FootSoldier/Equipment/Equipment.png.meta | 0 .../Equipment/Equipment_Atlas.asset | Bin .../Equipment/Equipment_Atlas.asset.meta | 0 .../Equipment/Equipment_Material.mat | Bin .../Equipment/Equipment_Material.mat.meta | 0 .../FootSoldier/FS_White.atlas.txt | 0 .../FootSoldier/FS_White.atlas.txt.meta | 0 .../FootSoldier/FS_White.png | Bin .../FootSoldier/FS_White.png.meta | 0 .../FootSoldier/FS_White_Atlas.asset | Bin .../FootSoldier/FS_White_Atlas.asset.meta | 0 .../FootSoldier/FS_White_Material.mat | Bin .../FootSoldier/FS_White_Material.mat.meta | 0 .../FootSoldier/FootSoldier.json | 0 .../FootSoldier/FootSoldier.json.meta | 0 .../FootSoldier_SkeletonData.asset | 0 .../FootSoldier_SkeletonData.asset.meta | 0 .../FootSoldier/license.txt | 0 .../FootSoldier/license.txt.meta | 0 .../{Spine => Spine Skeletons}/Gauge.meta | 0 .../Gauge/Gauge.atlas.txt | 0 .../Gauge/Gauge.atlas.txt.meta | 0 .../Gauge/Gauge.json | 0 .../Gauge/Gauge.json.meta | 0 .../Gauge/Gauge.png | Bin .../Gauge/Gauge.png.meta | 0 .../Gauge/Gauge_Atlas.asset | Bin .../Gauge/Gauge_Atlas.asset.meta | 0 .../Gauge/Gauge_Material.mat | Bin .../Gauge/Gauge_Material.mat.meta | 0 .../Gauge/Gauge_SkeletonData.asset | 0 .../Gauge/Gauge_SkeletonData.asset.meta | 0 .../Gauge/ReferenceAssets.meta | 0 .../Gauge/ReferenceAssets/Fill.asset | 0 .../Gauge/ReferenceAssets/Fill.asset.meta | 0 .../{Spine => Spine Skeletons}/Goblins.meta | 0 .../Goblins/dagger.png | Bin .../Goblins/dagger.png.meta | 0 .../Goblins/goblins.atlas.txt | 0 .../Goblins/goblins.atlas.txt.meta | 0 .../Goblins/goblins.json | 0 .../Goblins/goblins.json.meta | 0 .../Goblins/goblins.png | Bin .../Goblins/goblins.png.meta | 0 .../Goblins/goblins_Atlas.asset | Bin .../Goblins/goblins_Atlas.asset.meta | 0 .../Goblins/goblins_Material.mat | Bin .../Goblins/goblins_Material.mat.meta | 0 .../Goblins/goblins_SkeletonData.asset | 0 .../Goblins/goblins_SkeletonData.asset.meta | 0 .../{Spine => Spine Skeletons}/Hero.meta | 0 .../Hero/ReferenceAssets.meta | 0 .../Hero/ReferenceAssets/attack.asset | 0 .../Hero/ReferenceAssets/attack.asset.meta | 0 .../ReferenceAssets/crouch-from fall.asset | 0 .../crouch-from fall.asset.meta | 0 .../Hero/ReferenceAssets/crouch.asset | 0 .../Hero/ReferenceAssets/crouch.asset.meta | 0 .../Hero/ReferenceAssets/fall.asset | 0 .../Hero/ReferenceAssets/fall.asset.meta | 0 .../Hero/ReferenceAssets/head-turn.asset | 0 .../Hero/ReferenceAssets/head-turn.asset.meta | 0 .../Hero/ReferenceAssets/idle-from fall.asset | 0 .../ReferenceAssets/idle-from fall.asset.meta | 0 .../Hero/ReferenceAssets/idle.asset | 0 .../Hero/ReferenceAssets/idle.asset.meta | 0 .../Hero/ReferenceAssets/jump.asset | 0 .../Hero/ReferenceAssets/jump.asset.meta | 0 .../Hero/ReferenceAssets/run-from fall.asset | 0 .../ReferenceAssets/run-from fall.asset.meta | 0 .../Hero/ReferenceAssets/run.asset | 0 .../Hero/ReferenceAssets/run.asset.meta | 0 .../Hero/ReferenceAssets/walk.asset | 0 .../Hero/ReferenceAssets/walk.asset.meta | 0 .../Hero/hero-pro.atlas.txt | 0 .../Hero/hero-pro.atlas.txt.meta | 0 .../Hero/hero-pro.json | 0 .../Hero/hero-pro.json.meta | 0 .../Hero/hero-pro.png | Bin .../Hero/hero-pro.png.meta | 0 .../Hero/hero-pro_Atlas.asset | Bin .../Hero/hero-pro_Atlas.asset.meta | 0 .../Hero/hero-pro_Material.mat | Bin 4252 -> 4332 bytes .../Hero/hero-pro_Material.mat.meta | 0 .../Hero/hero-pro_SkeletonData.asset | Bin 0 -> 4360 bytes .../Hero/hero-pro_SkeletonData.asset.meta | 0 .../Hero/license.txt | 0 .../Hero/license.txt.meta | 0 .../Raggedy Spineboy.meta | 0 .../Raggedy Spineboy.atlas.txt | 0 .../Raggedy Spineboy.atlas.txt.meta | 0 .../Raggedy Spineboy/Raggedy Spineboy.png | Bin .../Raggedy Spineboy.png.meta | 0 .../Raggedy Spineboy_Atlas.asset | Bin .../Raggedy Spineboy_Atlas.asset.meta | 0 .../Raggedy Spineboy_Material.mat | Bin .../Raggedy Spineboy_Material.mat.meta | 0 .../Raggedy Spineboy_SkeletonData.asset | 0 .../Raggedy Spineboy_SkeletonData.asset.meta | 0 .../Raggedy Spineboy/raggedy spineboy.json | 0 .../raggedy spineboy.json.meta | 0 .../{Spine => Spine Skeletons}/Raptor.meta | 0 .../Raptor/ReferenceAssets.meta | 0 .../Raptor/ReferenceAssets/Jump.asset | 0 .../Raptor/ReferenceAssets/Jump.asset.meta | 0 .../Raptor/ReferenceAssets/gungrab.asset | 0 .../Raptor/ReferenceAssets/gungrab.asset.meta | 0 .../Raptor/ReferenceAssets/gunkeep.asset | 0 .../Raptor/ReferenceAssets/gunkeep.asset.meta | 0 .../Raptor/ReferenceAssets/walk.asset | 0 .../Raptor/ReferenceAssets/walk.asset.meta | 0 .../Raptor/raptor.atlas.txt | 0 .../Raptor/raptor.atlas.txt.meta | 0 .../Raptor/raptor.json | 0 .../Raptor/raptor.json.meta | 0 .../Raptor/raptor.png | Bin .../Raptor/raptor.png.meta | 0 .../Raptor/raptor_Atlas.asset | Bin .../Raptor/raptor_Atlas.asset.meta | 0 .../Raptor/raptor_Material.mat | Bin .../Raptor/raptor_Material.mat.meta | 0 .../Raptor/raptor_SkeletonData.asset | 0 .../Raptor/raptor_SkeletonData.asset.meta | 0 .../Runtime Template Material.mat | 0 .../Runtime Template Material.mat.meta | 0 .../Spineunitygirl.meta | 0 .../Spineunitygirl/Doi.atlas.txt | 0 .../Spineunitygirl/Doi.atlas.txt.meta | 0 .../Spineunitygirl/Doi.json | 0 .../Spineunitygirl/Doi.json.meta | 0 .../Spineunitygirl/Doi.png | Bin .../Spineunitygirl/Doi.png.meta | 0 .../Spineunitygirl/Doi_Atlas.asset | Bin .../Spineunitygirl/Doi_Atlas.asset.meta | 0 .../Spineunitygirl/Doi_Material.mat | Bin .../Spineunitygirl/Doi_Material.mat.meta | 0 .../Spineunitygirl/Doi_SkeletonData.asset | 0 .../Doi_SkeletonData.asset.meta | 0 .../Spineunitygirl/ReferenceAssets.meta | 0 .../ReferenceAssets/blink.asset | 0 .../ReferenceAssets/blink.asset.meta | 0 .../Spineunitygirl/ReferenceAssets/main.asset | 0 .../ReferenceAssets/main.asset.meta | 0 .../Strechyman.meta | 0 .../stretchyman-diffuse-pma.atlas.txt | 0 .../stretchyman-diffuse-pma.atlas.txt.meta | 0 .../Strechyman/stretchyman-diffuse-pma.png | Bin .../stretchyman-diffuse-pma.png.meta | 0 .../stretchyman-diffuse-pma_Atlas.asset | Bin .../stretchyman-diffuse-pma_Atlas.asset.meta | 0 .../stretchyman-diffuse-pma_Material.mat | Bin .../stretchyman-diffuse-pma_Material.mat.meta | 0 .../Strechyman/stretchyman-emission.png | Bin .../Strechyman/stretchyman-emission.png.meta | 0 .../Strechyman/stretchyman-normals.png | Bin .../Strechyman/stretchyman-normals.png.meta | 0 .../Strechyman/stretchyman.json | 0 .../Strechyman/stretchyman.json.meta | 0 .../Strechyman/stretchyman_SkeletonData.asset | 0 .../stretchyman_SkeletonData.asset.meta | 0 .../spineboy-pro.meta | 0 .../spineboy-pro/spineboy-pro.atlas.txt | 0 .../spineboy-pro/spineboy-pro.atlas.txt.meta | 0 .../spineboy-pro/spineboy-pro.json | 0 .../spineboy-pro/spineboy-pro.json.meta | 0 .../spineboy-pro/spineboy-pro.png | Bin .../spineboy-pro/spineboy-pro.png.meta | 0 .../spineboy-pro/spineboy-pro_Atlas.asset | Bin .../spineboy-pro_Atlas.asset.meta | 0 .../spineboy-pro/spineboy-pro_Material.mat | Bin .../spineboy-pro_Material.mat.meta | 0 .../spineboy-pro_SkeletonData.asset | 0 .../spineboy-pro_SkeletonData.asset.meta | 0 .../spineboy-unity.meta | 0 .../spineboy-unity/Equips.meta | 0 .../spineboy-unity/Equips/goggles-normal.png | Bin .../Equips/goggles-normal.png.meta | 0 .../Equips/goggles-tactical.png | Bin .../Equips/goggles-tactical.png.meta | 0 .../spineboy-unity/Equips/gun-freeze.png | Bin .../spineboy-unity/Equips/gun-freeze.png.meta | 0 .../spineboy-unity/Equips/gun-normal.png | Bin .../spineboy-unity/Equips/gun-normal.png.meta | 0 .../spineboy-unity/ReferenceAssets.meta | 0 .../ReferenceAssets/death.asset | 0 .../ReferenceAssets/death.asset.meta | 0 .../ReferenceAssets/diagonal.asset | 0 .../ReferenceAssets/diagonal.asset.meta | 0 .../ReferenceAssets/footstep.asset | 0 .../ReferenceAssets/footstep.asset.meta | 0 .../ReferenceAssets/frozen.asset | 0 .../ReferenceAssets/frozen.asset.meta | 0 .../ReferenceAssets/gun toss.asset | 0 .../ReferenceAssets/gun toss.asset.meta | 0 .../ReferenceAssets/hit old.asset | 0 .../ReferenceAssets/hit old.asset.meta | 0 .../spineboy-unity/ReferenceAssets/hit.asset | 0 .../ReferenceAssets/hit.asset.meta | 0 .../spineboy-unity/ReferenceAssets/idle.asset | 0 .../ReferenceAssets/idle.asset.meta | 0 .../ReferenceAssets/idlebag.asset | 0 .../ReferenceAssets/idlebag.asset.meta | 0 .../ReferenceAssets/jump old.asset | 0 .../ReferenceAssets/jump old.asset.meta | 0 .../ReferenceAssets/jump rm.asset | 0 .../ReferenceAssets/jump rm.asset.meta | 0 .../spineboy-unity/ReferenceAssets/jump.asset | 0 .../ReferenceAssets/jump.asset.meta | 0 .../spineboy-unity/ReferenceAssets/pole.asset | 0 .../ReferenceAssets/pole.asset.meta | 0 .../ReferenceAssets/run rm.asset | 0 .../ReferenceAssets/run rm.asset.meta | 0 .../spineboy-unity/ReferenceAssets/run.asset | 0 .../ReferenceAssets/run.asset.meta | 0 .../ReferenceAssets/shoot.asset | 0 .../ReferenceAssets/shoot.asset.meta | 0 .../ReferenceAssets/walk rm.asset | 0 .../ReferenceAssets/walk rm.asset.meta | 0 .../spineboy-unity/ReferenceAssets/walk.asset | 0 .../ReferenceAssets/walk.asset.meta | 0 .../spineboy-unity/spineboy-unity.json | 0 .../spineboy-unity/spineboy-unity.json.meta | 0 .../spineboy-unity_SkeletonData.asset | 0 .../spineboy-unity_SkeletonData.asset.meta | 0 .../spineboy-unity/spineboy.atlas.txt | 0 .../spineboy-unity/spineboy.atlas.txt.meta | 0 .../spineboy-unity/spineboy.png | Bin .../spineboy-unity/spineboy.png.meta | 0 .../spineboy-unity/spineboy_Atlas.asset | Bin .../spineboy-unity/spineboy_Atlas.asset.meta | 0 .../spineboy-unity/spineboy_Material Fill.mat | 0 .../spineboy_Material Fill.mat.meta | 0 .../spineboy-unity/spineboy_Material.mat | Bin .../spineboy-unity/spineboy_Material.mat.meta | 0 .../{Spine => Spine Skeletons}/square32.png | Bin .../square32.png.meta | 0 .../Spine/Hero/hero-pro_SkeletonData.asset | 34 ----- 296 files changed, 350 insertions(+), 44 deletions(-) create mode 100644 spine-unity/Assets/Spine Examples/Other Examples/Animation Tester.meta create mode 100644 spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/Animation Tester.unity create mode 100644 spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/Animation Tester.unity.meta create mode 100644 spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/SpineAnimationTesterTool.cs create mode 100644 spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/SpineAnimationTesterTool.cs.meta create mode 100644 spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation.meta create mode 100644 spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/AnimationState with Mecanim.unity create mode 100644 spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/AnimationState with Mecanim.unity.meta create mode 100644 spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/Hero.controller create mode 100644 spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/Hero.controller.meta create mode 100644 spine-unity/Assets/Spine Examples/Scripts/AnimationStateMecanimState.cs create mode 100644 spine-unity/Assets/Spine Examples/Scripts/AnimationStateMecanimState.cs.meta create mode 100644 spine-unity/Assets/Spine Examples/Scripts/AnimationStateWithMecanimExample.cs create mode 100644 spine-unity/Assets/Spine Examples/Scripts/AnimationStateWithMecanimExample.cs.meta rename spine-unity/Assets/Spine Examples/{Spine.meta => Spine Skeletons.meta} (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon.atlas.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon.atlas.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon.json (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon.json.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon2.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon2.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon_Atlas.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon_Atlas.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon_SkeletonData.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon_SkeletonData.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon_dragon.mat (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon_dragon.mat.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon_dragon2.mat (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/dragon_dragon2.mat.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/license.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Dragon/license.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Eyes.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Eyes/eyes.atlas.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Eyes/eyes.atlas.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Eyes/eyes.json (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Eyes/eyes.json.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Eyes/eyes.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Eyes/eyes.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Eyes/eyes_Atlas.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Eyes/eyes_Atlas.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Eyes/eyes_Material.mat (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Eyes/eyes_Material.mat.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Eyes/eyes_SkeletonData.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Eyes/eyes_SkeletonData.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/Equipment.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/Equipment/Equipment.atlas.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/Equipment/Equipment.atlas.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/Equipment/Equipment.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/Equipment/Equipment.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/Equipment/Equipment_Atlas.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/Equipment/Equipment_Atlas.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/Equipment/Equipment_Material.mat (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/Equipment/Equipment_Material.mat.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/FS_White.atlas.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/FS_White.atlas.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/FS_White.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/FS_White.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/FS_White_Atlas.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/FS_White_Atlas.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/FS_White_Material.mat (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/FS_White_Material.mat.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/FootSoldier.json (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/FootSoldier.json.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/FootSoldier_SkeletonData.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/FootSoldier_SkeletonData.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/license.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/FootSoldier/license.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge/Gauge.atlas.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge/Gauge.atlas.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge/Gauge.json (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge/Gauge.json.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge/Gauge.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge/Gauge.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge/Gauge_Atlas.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge/Gauge_Atlas.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge/Gauge_Material.mat (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge/Gauge_Material.mat.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge/Gauge_SkeletonData.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge/Gauge_SkeletonData.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge/ReferenceAssets.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge/ReferenceAssets/Fill.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Gauge/ReferenceAssets/Fill.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Goblins.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Goblins/dagger.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Goblins/dagger.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Goblins/goblins.atlas.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Goblins/goblins.atlas.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Goblins/goblins.json (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Goblins/goblins.json.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Goblins/goblins.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Goblins/goblins.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Goblins/goblins_Atlas.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Goblins/goblins_Atlas.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Goblins/goblins_Material.mat (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Goblins/goblins_Material.mat.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Goblins/goblins_SkeletonData.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Goblins/goblins_SkeletonData.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/attack.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/attack.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/crouch-from fall.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/crouch-from fall.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/crouch.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/crouch.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/fall.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/fall.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/head-turn.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/head-turn.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/idle-from fall.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/idle-from fall.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/idle.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/idle.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/jump.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/jump.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/run-from fall.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/run-from fall.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/run.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/run.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/walk.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/ReferenceAssets/walk.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/hero-pro.atlas.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/hero-pro.atlas.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/hero-pro.json (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/hero-pro.json.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/hero-pro.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/hero-pro.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/hero-pro_Atlas.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/hero-pro_Atlas.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/hero-pro_Material.mat (92%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/hero-pro_Material.mat.meta (100%) create mode 100644 spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro_SkeletonData.asset rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/hero-pro_SkeletonData.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/license.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Hero/license.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raggedy Spineboy.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raggedy Spineboy/Raggedy Spineboy.atlas.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raggedy Spineboy/Raggedy Spineboy.atlas.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raggedy Spineboy/Raggedy Spineboy.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raggedy Spineboy/Raggedy Spineboy.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raggedy Spineboy/Raggedy Spineboy_Atlas.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raggedy Spineboy/Raggedy Spineboy_Atlas.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raggedy Spineboy/Raggedy Spineboy_Material.mat (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raggedy Spineboy/Raggedy Spineboy_Material.mat.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raggedy Spineboy/Raggedy Spineboy_SkeletonData.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raggedy Spineboy/Raggedy Spineboy_SkeletonData.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raggedy Spineboy/raggedy spineboy.json (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raggedy Spineboy/raggedy spineboy.json.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/ReferenceAssets.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/ReferenceAssets/Jump.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/ReferenceAssets/Jump.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/ReferenceAssets/gungrab.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/ReferenceAssets/gungrab.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/ReferenceAssets/gunkeep.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/ReferenceAssets/gunkeep.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/ReferenceAssets/walk.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/ReferenceAssets/walk.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/raptor.atlas.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/raptor.atlas.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/raptor.json (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/raptor.json.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/raptor.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/raptor.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/raptor_Atlas.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/raptor_Atlas.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/raptor_Material.mat (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/raptor_Material.mat.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/raptor_SkeletonData.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Raptor/raptor_SkeletonData.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Runtime Template Material.mat (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Runtime Template Material.mat.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/Doi.atlas.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/Doi.atlas.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/Doi.json (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/Doi.json.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/Doi.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/Doi.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/Doi_Atlas.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/Doi_Atlas.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/Doi_Material.mat (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/Doi_Material.mat.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/Doi_SkeletonData.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/Doi_SkeletonData.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/ReferenceAssets.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/ReferenceAssets/blink.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/ReferenceAssets/blink.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/ReferenceAssets/main.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Spineunitygirl/ReferenceAssets/main.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman-diffuse-pma.atlas.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman-diffuse-pma.atlas.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman-diffuse-pma.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman-diffuse-pma.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman-diffuse-pma_Atlas.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman-diffuse-pma_Atlas.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman-diffuse-pma_Material.mat (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman-diffuse-pma_Material.mat.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman-emission.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman-emission.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman-normals.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman-normals.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman.json (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman.json.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman_SkeletonData.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/Strechyman/stretchyman_SkeletonData.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-pro.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-pro/spineboy-pro.atlas.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-pro/spineboy-pro.atlas.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-pro/spineboy-pro.json (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-pro/spineboy-pro.json.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-pro/spineboy-pro.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-pro/spineboy-pro.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-pro/spineboy-pro_Atlas.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-pro/spineboy-pro_Atlas.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-pro/spineboy-pro_Material.mat (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-pro/spineboy-pro_Material.mat.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-pro/spineboy-pro_SkeletonData.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-pro/spineboy-pro_SkeletonData.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/Equips.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/Equips/goggles-normal.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/Equips/goggles-normal.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/Equips/goggles-tactical.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/Equips/goggles-tactical.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/Equips/gun-freeze.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/Equips/gun-freeze.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/Equips/gun-normal.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/Equips/gun-normal.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/death.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/death.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/diagonal.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/diagonal.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/footstep.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/footstep.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/frozen.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/frozen.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/gun toss.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/gun toss.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/hit old.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/hit old.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/hit.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/hit.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/idle.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/idle.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/idlebag.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/idlebag.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/jump old.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/jump old.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/jump rm.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/jump rm.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/jump.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/jump.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/pole.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/pole.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/run rm.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/run rm.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/run.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/run.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/shoot.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/shoot.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/walk rm.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/walk rm.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/walk.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/ReferenceAssets/walk.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/spineboy-unity.json (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/spineboy-unity.json.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/spineboy-unity_SkeletonData.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/spineboy-unity_SkeletonData.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/spineboy.atlas.txt (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/spineboy.atlas.txt.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/spineboy.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/spineboy.png.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/spineboy_Atlas.asset (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/spineboy_Atlas.asset.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/spineboy_Material Fill.mat (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/spineboy_Material Fill.mat.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/spineboy_Material.mat (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/spineboy-unity/spineboy_Material.mat.meta (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/square32.png (100%) rename spine-unity/Assets/Spine Examples/{Spine => Spine Skeletons}/square32.png.meta (100%) delete mode 100644 spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro_SkeletonData.asset diff --git a/spine-unity/Assets/Spine Examples/Other Examples/Animation Tester.meta b/spine-unity/Assets/Spine Examples/Other Examples/Animation Tester.meta new file mode 100644 index 000000000..8e1382599 --- /dev/null +++ b/spine-unity/Assets/Spine Examples/Other Examples/Animation Tester.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 173cd2c662ebd674f994bff2385cfbf6 +folderAsset: yes +timeCreated: 1529972040 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/Animation Tester.unity b/spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/Animation Tester.unity new file mode 100644 index 0000000000000000000000000000000000000000..7c5ca0bce5b42e1b2fc3efd93be7552ec48c35fc GIT binary patch literal 39608 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 literal 0 HcmV?d00001 diff --git a/spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/Animation Tester.unity.meta b/spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/Animation Tester.unity.meta new file mode 100644 index 000000000..43460e8bd --- /dev/null +++ b/spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/Animation Tester.unity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b804088948820194cbda76af39c08174 +timeCreated: 1529972058 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/SpineAnimationTesterTool.cs b/spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/SpineAnimationTesterTool.cs new file mode 100644 index 000000000..37cf5f8ba --- /dev/null +++ b/spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/SpineAnimationTesterTool.cs @@ -0,0 +1,117 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +using Spine; +using Spine.Unity; + +using System.Text; + +namespace Spine.Unity.Examples { + public class SpineAnimationTesterTool : MonoBehaviour, IHasSkeletonDataAsset, IHasSkeletonComponent { + + public SkeletonAnimation skeletonAnimation; + public SkeletonDataAsset SkeletonDataAsset { get { return skeletonAnimation.SkeletonDataAsset; } } + public ISkeletonComponent SkeletonComponent { get { return skeletonAnimation; } } + + public bool useOverrideMixDuration; + public float overrideMixDuration = 0.2f; + + [System.Serializable] + public struct AnimationControl { + [SpineAnimation] + public string animationName; + public bool loop; + public KeyCode key; + + [Space] + public bool useCustomMixDuration; + public float mixDuration; + //public bool useChainToControl; + //public int chainToControl; + } + [System.Serializable] + public class ControlledTrack { + public List controls = new List(); + } + + [Space] + public List trackControls = new List(); + + [Header("UI")] + public UnityEngine.UI.Text boundAnimationsText; + public UnityEngine.UI.Text skeletonNameText; + + void OnValidate () { + // Fill in the SkeletonData asset name + if (skeletonNameText != null) { + if (skeletonAnimation != null && skeletonAnimation.skeletonDataAsset != null) { + skeletonNameText.text = SkeletonDataAsset.name.Replace("_SkeletonData", ""); + } + } + + // Fill in the control list. + if (boundAnimationsText != null) { + var boundAnimationsStringBuilder = new StringBuilder(); + boundAnimationsStringBuilder.AppendLine("Animation Controls:"); + + for (int trackIndex = 0; trackIndex < trackControls.Count; trackIndex++) { + + if (trackIndex > 0) + boundAnimationsStringBuilder.AppendLine(); + + boundAnimationsStringBuilder.AppendFormat("---- Track {0} ---- \n", trackIndex); + foreach (var ba in trackControls[trackIndex].controls) { + string animationName = ba.animationName; + if (string.IsNullOrEmpty(animationName)) + animationName = "SetEmptyAnimation"; + + boundAnimationsStringBuilder.AppendFormat("[{0}] {1}\n", ba.key.ToString(), animationName); + } + + } + + boundAnimationsText.text = boundAnimationsStringBuilder.ToString(); + + } + + } + + void Start () { + if (useOverrideMixDuration) { + skeletonAnimation.AnimationState.Data.DefaultMix = overrideMixDuration; + } + } + + void Update () { + var animationState = skeletonAnimation.AnimationState; + + // For each track + for (int trackIndex = 0; trackIndex < trackControls.Count; trackIndex++) { + + // For each control in the track + foreach (var control in trackControls[trackIndex].controls) { + + // Check each control, and play the appropriate animation. + if (Input.GetKeyDown(control.key)) { + if (!string.IsNullOrEmpty(control.animationName)) { + var trackEntry = animationState.SetAnimation(trackIndex, control.animationName, control.loop); + if (control.useCustomMixDuration) + trackEntry.MixDuration = control.mixDuration; + + } else { + float mix = control.useCustomMixDuration ? control.mixDuration : animationState.Data.DefaultMix; + animationState.SetEmptyAnimation(trackIndex, mix); + } + + // Don't parse more than one animation per track. + break; + } + } + } + + } + + } +} + diff --git a/spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/SpineAnimationTesterTool.cs.meta b/spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/SpineAnimationTesterTool.cs.meta new file mode 100644 index 000000000..b5c006260 --- /dev/null +++ b/spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/SpineAnimationTesterTool.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: b99b2d8e59226fa4db070f241259fd98 +timeCreated: 1529972356 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/Spine Examples/Other Examples/Mix and Match Equip.unity b/spine-unity/Assets/Spine Examples/Other Examples/Mix and Match Equip.unity index 4df601543b330328cb8c4c567777a05c0c09af77..f36bb07456d315f65c0e53a2c8e16cac38e09406 100644 GIT binary patch literal 54816 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 F{{W?Z3%mdT literal 55199 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 L$|Tn$WxDp?#|q`> literal 0 HcmV?d00001 diff --git a/spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/AnimationState with Mecanim.unity.meta b/spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/AnimationState with Mecanim.unity.meta new file mode 100644 index 000000000..20063753f --- /dev/null +++ b/spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/AnimationState with Mecanim.unity.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: afd3c9ec31200bc49b169c22f00b010b +timeCreated: 1531300871 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/Hero.controller b/spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/Hero.controller new file mode 100644 index 0000000000000000000000000000000000000000..ae8ec504c3ffe5971121effcb546d88c08295032 GIT binary patch literal 14208 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 literal 0 HcmV?d00001 diff --git a/spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/Hero.controller.meta b/spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/Hero.controller.meta new file mode 100644 index 000000000..7c90a3d5b --- /dev/null +++ b/spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/Hero.controller.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: cec34498f2eb26b488452ec274c54439 +timeCreated: 1531292741 +licenseType: Free +NativeFormatImporter: + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/Spine Examples/Scripts/AnimationStateMecanimState.cs b/spine-unity/Assets/Spine Examples/Scripts/AnimationStateMecanimState.cs new file mode 100644 index 000000000..46afe77f5 --- /dev/null +++ b/spine-unity/Assets/Spine Examples/Scripts/AnimationStateMecanimState.cs @@ -0,0 +1,62 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +using Spine; +using Spine.Unity; + +public class AnimationStateMecanimState : StateMachineBehaviour { + + #region Inspector + public AnimationReferenceAsset animation; + + [System.Serializable] + public struct AnimationTransition { + public AnimationReferenceAsset from; + public AnimationReferenceAsset transition; + } + + [UnityEngine.Serialization.FormerlySerializedAs("transitions")] + public List fromTransitions = new List(); + #endregion + + Spine.AnimationState state; + + public void Initialize (Animator animator) { + if (state == null) { + var animationStateComponent = (animator.GetComponent(typeof(IAnimationStateComponent))) as IAnimationStateComponent; + state = animationStateComponent.AnimationState; + } + } + + override public void OnStateEnter (Animator animator, AnimatorStateInfo stateInfo, int layerIndex) { + if (state == null) { + Initialize(animator); + } + + float timeScale = stateInfo.speed; + var current = state.GetCurrent(layerIndex); + + bool transitionPlayed = false; + if (current != null && fromTransitions.Count > 0) { + foreach (var t in fromTransitions) { + if (t.from.Animation == current.Animation) { + var transitionEntry = state.SetAnimation(layerIndex, t.transition.Animation, false); + transitionEntry.TimeScale = timeScale; + transitionPlayed = true; + break; + } + } + } + + TrackEntry trackEntry; + if (transitionPlayed) { + trackEntry = state.AddAnimation(layerIndex, animation.Animation, stateInfo.loop, 0); + } else { + trackEntry = state.SetAnimation(layerIndex, animation.Animation, stateInfo.loop); + } + trackEntry.TimeScale = timeScale; + + } + +} diff --git a/spine-unity/Assets/Spine Examples/Scripts/AnimationStateMecanimState.cs.meta b/spine-unity/Assets/Spine Examples/Scripts/AnimationStateMecanimState.cs.meta new file mode 100644 index 000000000..b205d8341 --- /dev/null +++ b/spine-unity/Assets/Spine Examples/Scripts/AnimationStateMecanimState.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 536bdde8dc7bbb641b17da9221d6562f +timeCreated: 1531293563 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/Spine Examples/Scripts/AnimationStateWithMecanimExample.cs b/spine-unity/Assets/Spine Examples/Scripts/AnimationStateWithMecanimExample.cs new file mode 100644 index 000000000..9121fdeb8 --- /dev/null +++ b/spine-unity/Assets/Spine Examples/Scripts/AnimationStateWithMecanimExample.cs @@ -0,0 +1,82 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +using Spine; +using Spine.Unity; + +namespace Spine.Unity.Examples { + public class AnimationStateWithMecanimExample : MonoBehaviour { + + SkeletonAnimation skeletonAnimation; + Animator logicAnimator; + + [Header("Controls")] + public KeyCode walkButton = KeyCode.LeftShift; + public KeyCode jumpButton = KeyCode.Space; + + [Header("Animator Properties")] + public string horizontalSpeedProperty = "Speed"; + public string verticalSpeedProperty = "VerticalSpeed"; + public string groundedProperty = "Grounded"; + + [Header("Fake Physics")] + public float jumpDuration = 1.5f; + public Vector2 speed; + public bool isGrounded; + + void Awake () { + skeletonAnimation = GetComponent(); + logicAnimator = GetComponent(); + + isGrounded = true; + } + + void Update () { + float x = Input.GetAxisRaw("Horizontal"); + if (Input.GetKey(walkButton)) { + x *= 0.4f; + } + + speed.x = x; + + // Flip skeleton. + if (x != 0) { + skeletonAnimation.Skeleton.ScaleX = x > 0 ? 1f : -1f; + } + + if (Input.GetKeyDown(jumpButton)) { + if (isGrounded) + StartCoroutine(FakeJump()); + } + + logicAnimator.SetFloat(horizontalSpeedProperty, Mathf.Abs(speed.x)); + logicAnimator.SetFloat(verticalSpeedProperty, speed.y); + logicAnimator.SetBool(groundedProperty, isGrounded); + + } + + IEnumerator FakeJump () { + // Rise + isGrounded = false; + speed.y = 10f; + float durationLeft = jumpDuration * 0.5f; + while (durationLeft > 0) { + durationLeft -= Time.deltaTime; + if (!Input.GetKey(jumpButton)) break; + yield return null; + } + + // Fall + speed.y = -10f; + float fallDuration = (jumpDuration * 0.5f) - durationLeft; + yield return new WaitForSeconds(fallDuration); + + // Land + speed.y = 0f; + isGrounded = true; + yield return null; + } + } + +} diff --git a/spine-unity/Assets/Spine Examples/Scripts/AnimationStateWithMecanimExample.cs.meta b/spine-unity/Assets/Spine Examples/Scripts/AnimationStateWithMecanimExample.cs.meta new file mode 100644 index 000000000..6f5b125ab --- /dev/null +++ b/spine-unity/Assets/Spine Examples/Scripts/AnimationStateWithMecanimExample.cs.meta @@ -0,0 +1,12 @@ +fileFormatVersion: 2 +guid: 782062825deffd64ba7e7e9f978788e5 +timeCreated: 1531300740 +licenseType: Free +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/Spine Examples/Scripts/FootSoldierExample.cs b/spine-unity/Assets/Spine Examples/Scripts/FootSoldierExample.cs index 08cf1a6a7..971d96213 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/FootSoldierExample.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/FootSoldierExample.cs @@ -80,11 +80,11 @@ namespace Spine.Unity.Examples { } else { if (Input.GetKey(rightKey)) { skeletonAnimation.AnimationName = moveAnimation; - skeletonAnimation.Skeleton.FlipX = false; + skeletonAnimation.Skeleton.ScaleX = 1; transform.Translate(moveSpeed * Time.deltaTime, 0, 0); } else if(Input.GetKey(leftKey)) { skeletonAnimation.AnimationName = moveAnimation; - skeletonAnimation.Skeleton.FlipX = true; + skeletonAnimation.Skeleton.ScaleX = -1; transform.Translate(-moveSpeed * Time.deltaTime, 0, 0); } else { skeletonAnimation.AnimationName = idleAnimation; diff --git a/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/BasicPlatformerController.cs b/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/BasicPlatformerController.cs index 3166055a4..67f8a0dbf 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/BasicPlatformerController.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/BasicPlatformerController.cs @@ -183,7 +183,7 @@ namespace Spine.Unity.Examples { // Face intended direction. if (input.x != 0) - skeletonAnimation.Skeleton.FlipX = input.x < 0; + skeletonAnimation.Skeleton.ScaleX = Mathf.Sign(input.x); // Effects diff --git a/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/SpineBeginnerTwo.cs b/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/SpineBeginnerTwo.cs index 0de31c2f8..7a4b15015 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/SpineBeginnerTwo.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/SpineBeginnerTwo.cs @@ -93,11 +93,11 @@ namespace Spine.Unity.Examples { spineAnimationState.AddAnimation(0, idleAnimationName, true, 0); yield return new WaitForSeconds(1f); - skeleton.FlipX = true; // skeleton allows you to flip the skeleton. + skeleton.ScaleX = -1; // skeleton allows you to flip the skeleton. spineAnimationState.SetAnimation(0, idleTurnAnimationName, false); spineAnimationState.AddAnimation(0, idleAnimationName, true, 0); yield return new WaitForSeconds(0.5f); - skeleton.FlipX = false; + skeleton.ScaleX = 1; spineAnimationState.SetAnimation(0, idleTurnAnimationName, false); spineAnimationState.AddAnimation(0, idleAnimationName, true, 0); yield return new WaitForSeconds(0.5f); diff --git a/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/SpineboyBeginnerView.cs b/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/SpineboyBeginnerView.cs index 041725cbc..7e8b46353 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/SpineboyBeginnerView.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/SpineboyBeginnerView.cs @@ -69,7 +69,7 @@ namespace Spine.Unity.Examples { if (skeletonAnimation == null) return; if (model == null) return; - if (skeletonAnimation.skeleton.FlipX != model.facingLeft) { // Detect changes in model.facingLeft + if ((skeletonAnimation.skeleton.ScaleX < 0) != model.facingLeft) { // Detect changes in model.facingLeft Turn(model.facingLeft); } @@ -134,7 +134,7 @@ namespace Spine.Unity.Examples { } public void Turn (bool facingLeft) { - skeletonAnimation.Skeleton.FlipX = facingLeft; + skeletonAnimation.Skeleton.ScaleX = facingLeft ? -1f : 1f; // Maybe play a transient turning animation too, then call ChangeStableAnimation. } #endregion diff --git a/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/SpineboyTargetController.cs b/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/SpineboyTargetController.cs index 63242c16f..8e2871915 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/SpineboyTargetController.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Getting Started Scripts/SpineboyTargetController.cs @@ -23,7 +23,7 @@ namespace Spine.Unity.Examples { var mousePosition = Input.mousePosition; var worldMousePosition = camera.ScreenToWorldPoint(mousePosition); var skeletonSpacePoint = skeletonAnimation.transform.InverseTransformPoint(worldMousePosition); - if (skeletonAnimation.Skeleton.FlipX) skeletonSpacePoint.x *= -1; + //if (skeletonAnimation.Skeleton.FlipX) skeletonSpacePoint.x *= -1; bone.SetPosition(skeletonSpacePoint); } } diff --git a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonAnimationMulti/SkeletonAnimationMulti.cs b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonAnimationMulti/SkeletonAnimationMulti.cs index d071f565c..dd0e80d8e 100644 --- a/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonAnimationMulti/SkeletonAnimationMulti.cs +++ b/spine-unity/Assets/Spine Examples/Scripts/Sample Components/SkeletonAnimationMulti/SkeletonAnimationMulti.cs @@ -69,8 +69,8 @@ namespace Spine.Unity { sa.initialFlipX = this.initialFlipX; sa.initialFlipY = this.initialFlipY; var skeleton = sa.skeleton; - skeleton.FlipX = this.initialFlipX; - skeleton.FlipY = this.initialFlipY; + skeleton.ScaleX = this.initialFlipX ? 1 : -1; + skeleton.ScaleY = this.initialFlipY ? 1 : -1; sa.Initialize(false); skeletonAnimations.Add(sa); diff --git a/spine-unity/Assets/Spine Examples/Spine.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon.atlas.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon.atlas.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon.atlas.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon.atlas.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon.atlas.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon.atlas.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon.atlas.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon.atlas.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon.json b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon.json similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon.json rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon.json diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon.json.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon.json.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon.json.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon.json.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon.png diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon2.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon2.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon2.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon2.png diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon2.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon2.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon2.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon2.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_Atlas.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_Atlas.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_Atlas.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_Atlas.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_Atlas.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_Atlas.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_Atlas.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_Atlas.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_SkeletonData.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_SkeletonData.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_SkeletonData.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_SkeletonData.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_SkeletonData.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_SkeletonData.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_SkeletonData.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_SkeletonData.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_dragon.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_dragon.mat similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_dragon.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_dragon.mat diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_dragon.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_dragon.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_dragon.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_dragon.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_dragon2.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_dragon2.mat similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_dragon2.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_dragon2.mat diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_dragon2.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_dragon2.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/dragon_dragon2.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/dragon_dragon2.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/license.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/license.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/license.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/license.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/Dragon/license.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/license.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Dragon/license.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Dragon/license.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Eyes.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Eyes.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Eyes/eyes.atlas.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes.atlas.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Eyes/eyes.atlas.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes.atlas.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/Eyes/eyes.atlas.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes.atlas.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Eyes/eyes.atlas.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes.atlas.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Eyes/eyes.json b/spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes.json similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Eyes/eyes.json rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes.json diff --git a/spine-unity/Assets/Spine Examples/Spine/Eyes/eyes.json.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes.json.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Eyes/eyes.json.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes.json.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Eyes/eyes.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Eyes/eyes.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes.png diff --git a/spine-unity/Assets/Spine Examples/Spine/Eyes/eyes.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Eyes/eyes.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Eyes/eyes_Atlas.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes_Atlas.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Eyes/eyes_Atlas.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes_Atlas.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Eyes/eyes_Atlas.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes_Atlas.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Eyes/eyes_Atlas.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes_Atlas.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Eyes/eyes_Material.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes_Material.mat similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Eyes/eyes_Material.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes_Material.mat diff --git a/spine-unity/Assets/Spine Examples/Spine/Eyes/eyes_Material.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes_Material.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Eyes/eyes_Material.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes_Material.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Eyes/eyes_SkeletonData.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes_SkeletonData.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Eyes/eyes_SkeletonData.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes_SkeletonData.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Eyes/eyes_SkeletonData.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes_SkeletonData.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Eyes/eyes_SkeletonData.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Eyes/eyes_SkeletonData.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment.atlas.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment.atlas.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment.atlas.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment.atlas.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment.atlas.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment.atlas.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment.atlas.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment.atlas.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment.png diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment_Atlas.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment_Atlas.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment_Atlas.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment_Atlas.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment_Atlas.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment_Atlas.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment_Atlas.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment_Atlas.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment_Material.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment_Material.mat similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment_Material.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment_Material.mat diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment_Material.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment_Material.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/Equipment/Equipment_Material.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/Equipment/Equipment_Material.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White.atlas.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White.atlas.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White.atlas.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White.atlas.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White.atlas.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White.atlas.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White.atlas.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White.atlas.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White.png diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White_Atlas.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White_Atlas.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White_Atlas.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White_Atlas.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White_Atlas.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White_Atlas.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White_Atlas.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White_Atlas.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White_Material.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White_Material.mat similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White_Material.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White_Material.mat diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White_Material.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White_Material.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/FS_White_Material.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FS_White_Material.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/FootSoldier.json b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FootSoldier.json similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/FootSoldier.json rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FootSoldier.json diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/FootSoldier.json.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FootSoldier.json.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/FootSoldier.json.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FootSoldier.json.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/FootSoldier_SkeletonData.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FootSoldier_SkeletonData.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/FootSoldier_SkeletonData.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FootSoldier_SkeletonData.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/FootSoldier_SkeletonData.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FootSoldier_SkeletonData.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/FootSoldier_SkeletonData.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/FootSoldier_SkeletonData.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/license.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/license.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/license.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/license.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/FootSoldier/license.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/license.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/FootSoldier/license.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/FootSoldier/license.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge.atlas.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge.atlas.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge.atlas.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge.atlas.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge.atlas.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge.atlas.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge.atlas.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge.atlas.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge.json b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge.json similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge.json rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge.json diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge.json.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge.json.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge.json.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge.json.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge.png diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge_Atlas.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge_Atlas.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge_Atlas.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge_Atlas.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge_Atlas.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge_Atlas.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge_Atlas.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge_Atlas.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge_Material.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge_Material.mat similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge_Material.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge_Material.mat diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge_Material.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge_Material.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge_Material.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge_Material.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge_SkeletonData.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge_SkeletonData.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge_SkeletonData.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge_SkeletonData.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge_SkeletonData.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge_SkeletonData.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge/Gauge_SkeletonData.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/Gauge_SkeletonData.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge/ReferenceAssets.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/ReferenceAssets.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge/ReferenceAssets.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/ReferenceAssets.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge/ReferenceAssets/Fill.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/ReferenceAssets/Fill.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge/ReferenceAssets/Fill.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/ReferenceAssets/Fill.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Gauge/ReferenceAssets/Fill.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/ReferenceAssets/Fill.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Gauge/ReferenceAssets/Fill.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Gauge/ReferenceAssets/Fill.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Goblins.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Goblins.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Goblins/dagger.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/dagger.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Goblins/dagger.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/dagger.png diff --git a/spine-unity/Assets/Spine Examples/Spine/Goblins/dagger.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/dagger.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Goblins/dagger.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/dagger.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Goblins/goblins.atlas.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins.atlas.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Goblins/goblins.atlas.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins.atlas.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/Goblins/goblins.atlas.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins.atlas.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Goblins/goblins.atlas.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins.atlas.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Goblins/goblins.json b/spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins.json similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Goblins/goblins.json rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins.json diff --git a/spine-unity/Assets/Spine Examples/Spine/Goblins/goblins.json.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins.json.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Goblins/goblins.json.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins.json.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Goblins/goblins.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Goblins/goblins.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins.png diff --git a/spine-unity/Assets/Spine Examples/Spine/Goblins/goblins.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Goblins/goblins.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Goblins/goblins_Atlas.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins_Atlas.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Goblins/goblins_Atlas.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins_Atlas.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Goblins/goblins_Atlas.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins_Atlas.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Goblins/goblins_Atlas.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins_Atlas.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Goblins/goblins_Material.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins_Material.mat similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Goblins/goblins_Material.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins_Material.mat diff --git a/spine-unity/Assets/Spine Examples/Spine/Goblins/goblins_Material.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins_Material.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Goblins/goblins_Material.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins_Material.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Goblins/goblins_SkeletonData.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins_SkeletonData.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Goblins/goblins_SkeletonData.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins_SkeletonData.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Goblins/goblins_SkeletonData.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins_SkeletonData.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Goblins/goblins_SkeletonData.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Goblins/goblins_SkeletonData.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/attack.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/attack.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/attack.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/attack.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/attack.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/attack.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/attack.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/attack.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/crouch-from fall.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/crouch-from fall.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/crouch-from fall.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/crouch-from fall.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/crouch-from fall.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/crouch-from fall.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/crouch-from fall.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/crouch-from fall.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/crouch.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/crouch.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/crouch.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/crouch.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/crouch.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/crouch.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/crouch.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/crouch.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/fall.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/fall.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/fall.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/fall.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/fall.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/fall.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/fall.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/fall.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/head-turn.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/head-turn.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/head-turn.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/head-turn.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/head-turn.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/head-turn.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/head-turn.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/head-turn.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/idle-from fall.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/idle-from fall.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/idle-from fall.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/idle-from fall.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/idle-from fall.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/idle-from fall.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/idle-from fall.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/idle-from fall.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/idle.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/idle.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/idle.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/idle.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/idle.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/idle.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/idle.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/idle.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/jump.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/jump.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/jump.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/jump.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/jump.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/jump.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/jump.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/jump.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/run-from fall.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/run-from fall.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/run-from fall.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/run-from fall.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/run-from fall.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/run-from fall.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/run-from fall.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/run-from fall.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/run.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/run.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/run.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/run.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/run.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/run.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/run.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/run.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/walk.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/walk.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/walk.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/walk.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/walk.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/walk.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/ReferenceAssets/walk.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/ReferenceAssets/walk.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro.atlas.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.atlas.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro.atlas.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.atlas.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro.atlas.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.atlas.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro.atlas.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.atlas.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro.json b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.json similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro.json rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.json diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro.json.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.json.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro.json.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.json.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.png diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro_Atlas.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro_Atlas.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro_Atlas.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro_Atlas.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro_Atlas.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro_Atlas.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro_Atlas.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro_Atlas.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro_Material.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro_Material.mat similarity index 92% rename from spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro_Material.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro_Material.mat index c0db3163eb26f7caa063b49424061a50e8e0c476..993985b66316f5b19a43c23532def7a0b35fd3dc 100644 GIT binary patch delta 161 zcmbQE_(qX~fq}D?fkEKSMvf3p#WxHHzyxB3Oey8G_U!kZRkqjPWk&S&&9$8D>>12J z8FnC!cP=f-PfKGsd*+NS7l`kcnUfQckyxAxa^XXN00rWx~jf@_1CLcHA%I|xceei z69f;D8K^{>8@4nwp4=qAMn^{t1He^S=6ub*oZs@|?1ndW)l)KED?a?lzy7wQZRA32 z)zFupr*kcEdxpXx;|=k*iujNiRik}!L$0U9zlV3}z>mJddY1f5fX4(G_Kcky^8MtD?bQpgRt zhB%KxhwGV44G4|pp$nX`bIp3ahU75sNHFhIaGHUPMB|^PnC8)Wr-$5-4$ONKI?O+J z)$o50+>l|!vKD>DIUhBxTz`Saf9Wrb@FuhwKXbe&Z~I4$bs>+(xt<(W9%mh) zPaco6p1v9Kc$^L7s>I{m5ON*o1@sx`M%1+OeByVYto(d#j_^T5#(bv18bhwn!$tJT zdB$iw4_8q?Lg9I6Mxm9Thb@X}9z75EdkJ5W?rzWB(bk*y9Jg)2vkJw$Q)rd`W9@m{ z+PephZqv)5VS2V%%odB5SJY!xW<#>eELyEn>@jUCcz47a@RT#~3Cp%Tr_g!$z<%j- zo&Ibg-*0-DMm*;!8n6)$>zb<9J1{JzUsu2X-~b&eel?v#5>&kUyI7+%=M?tqhC)$HI^?b;K5N$I;Y@6UavZSz~# uEfwl{8?7b?-m^)ce6MY>{+Ay$F;@6p-{U%^o}9$m99M2Ho Date: Fri, 13 Jul 2018 23:45:20 +0800 Subject: [PATCH 12/15] [unity] Update Timeline code. --- .../SpineAnimationStateMixerBehaviour.cs | 5 +++-- .../SpineAnimationStateTrack.cs | 7 ++++++- .../SpineSkeletonFlipMixerBehaviour.cs | 16 ++++++++-------- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs index 2b593e1fb..a4994157c 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineAnimationState/SpineAnimationStateMixerBehaviour.cs @@ -40,6 +40,7 @@ namespace Spine.Unity.Playables { public class SpineAnimationStateMixerBehaviour : PlayableBehaviour { float[] lastInputWeights; + public int trackIndex; // NOTE: This function is called at runtime and edit time. Keep that in mind when setting the values of properties. public override void ProcessFrame (Playable playable, FrameData info, object playerData) { @@ -80,10 +81,10 @@ namespace Spine.Unity.Playables { if (clipData.animationReference == null) { float mixDuration = clipData.customDuration ? clipData.mixDuration : state.Data.DefaultMix; - state.SetEmptyAnimation(0, mixDuration); + state.SetEmptyAnimation(trackIndex, mixDuration); } else { if (clipData.animationReference.Animation != null) { - Spine.TrackEntry trackEntry = state.SetAnimation(0, clipData.animationReference.Animation, clipData.loop); + Spine.TrackEntry trackEntry = state.SetAnimation(trackIndex, clipData.animationReference.Animation, clipData.loop); //trackEntry.TrackTime = (float)inputPlayable.GetTime(); // More accurate time-start? trackEntry.EventThreshold = clipData.eventThreshold; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineAnimationState/SpineAnimationStateTrack.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineAnimationState/SpineAnimationStateTrack.cs index 3bce9be06..4c51e7d4e 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineAnimationState/SpineAnimationStateTrack.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineAnimationState/SpineAnimationStateTrack.cs @@ -38,8 +38,13 @@ namespace Spine.Unity.Playables { [TrackClipType(typeof(SpineAnimationStateClip))] [TrackBindingType(typeof(SkeletonAnimation))] public class SpineAnimationStateTrack : TrackAsset { + public int trackIndex = 0; + public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount) { - return ScriptPlayable.Create (graph, inputCount); + var scriptPlayable = ScriptPlayable.Create(graph, inputCount); + var mixerBehaviour = scriptPlayable.GetBehaviour(); + mixerBehaviour.trackIndex = this.trackIndex; + return scriptPlayable; } } } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineSkeletonFlip/SpineSkeletonFlipMixerBehaviour.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineSkeletonFlip/SpineSkeletonFlipMixerBehaviour.cs index 2330aae56..1ce745d12 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineSkeletonFlip/SpineSkeletonFlipMixerBehaviour.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Timeline/SpineSkeletonFlip/SpineSkeletonFlipMixerBehaviour.cs @@ -52,8 +52,8 @@ namespace Spine.Unity.Playables { var skeleton = playableHandle.Skeleton; if (!m_FirstFrameHappened) { - defaultFlipX = skeleton.flipX; - defaultFlipY = skeleton.flipY; + defaultFlipX = skeleton.FlipX; + defaultFlipY = skeleton.FlipY; m_FirstFrameHappened = true; } @@ -71,8 +71,8 @@ namespace Spine.Unity.Playables { totalWeight += inputWeight; if (inputWeight > greatestWeight) { - skeleton.flipX = input.flipX; - skeleton.flipY = input.flipY; + skeleton.FlipX = input.flipX; + skeleton.FlipY = input.flipY; greatestWeight = inputWeight; } @@ -81,8 +81,8 @@ namespace Spine.Unity.Playables { } if (currentInputs != 1 && 1f - totalWeight > greatestWeight) { - skeleton.flipX = defaultFlipX; - skeleton.flipY = defaultFlipY; + skeleton.FlipX = defaultFlipX; + skeleton.FlipY = defaultFlipY; } } @@ -93,8 +93,8 @@ namespace Spine.Unity.Playables { return; var skeleton = playableHandle.Skeleton; - skeleton.flipX = defaultFlipX; - skeleton.flipY = defaultFlipY; + skeleton.FlipX = defaultFlipX; + skeleton.FlipY = defaultFlipY; } } From 98907dd70377c047e1d2e682101b39f01a5655fc Mon Sep 17 00:00:00 2001 From: NathanSweet Date: Mon, 16 Jul 2018 03:59:15 +0200 Subject: [PATCH 13/15] [libgdx] Javadoc typo. --- .../src/com/esotericsoftware/spine/SkeletonRenderer.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java index a231e8167..19a9de0db 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/SkeletonRenderer.java @@ -67,7 +67,7 @@ public class SkeletonRenderer { * skeleton is rendered without two color tinting and any mesh attachments will throw an exception. *

* This method may change the batch's {@link Batch#setBlendFunctionSeparate(int, int, int, int) blending function}. The - * previous blend function is not restore, since that could result in unnecessary flushes, depending on what is rendered + * previous blend function is not restored, since that could result in unnecessary flushes, depending on what is rendered * next. */ public void draw (Batch batch, Skeleton skeleton) { if (batch instanceof PolygonSpriteBatch) { @@ -144,7 +144,7 @@ public class SkeletonRenderer { /** Renders the specified skeleton, including meshes, but without two color tinting. *

* This method may change the batch's {@link Batch#setBlendFunctionSeparate(int, int, int, int) blending function}. The - * previous blend function is not restore, since that could result in unnecessary flushes, depending on what is rendered + * previous blend function is not restored, since that could result in unnecessary flushes, depending on what is rendered * next. */ @SuppressWarnings("null") public void draw (PolygonSpriteBatch batch, Skeleton skeleton) { @@ -266,7 +266,7 @@ public class SkeletonRenderer { /** Renders the specified skeleton, including meshes and two color tinting. *

* This method may change the batch's {@link Batch#setBlendFunctionSeparate(int, int, int, int) blending function}. The - * previous blend function is not restore, since that could result in unnecessary flushes, depending on what is rendered + * previous blend function is not restored, since that could result in unnecessary flushes, depending on what is rendered * next. */ @SuppressWarnings("null") public void draw (TwoColorPolygonBatch batch, Skeleton skeleton) { From 043c51130b65a6daebaed940f18a070b7f7882f0 Mon Sep 17 00:00:00 2001 From: pharan Date: Tue, 17 Jul 2018 05:39:54 +0800 Subject: [PATCH 14/15] [unity] Fix typo for 2017.2 and up. --- .../Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs index 37d9efb8d..d7ab79121 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineEditorUtilities.cs @@ -269,7 +269,7 @@ namespace Spine.Unity.Editor { if (EditorGUI.EndChangeCheck()) { EditorPrefs.SetBool(SHOW_HIERARCHY_ICONS_KEY, showHierarchyIcons); #if UNITY_2017_2_OR_NEWER - SpineEditorHierarchyHandler.HierarchyIconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode); + HierarchyHandler.IconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode); #else HierarchyHandler.IconsOnPlaymodeStateChanged(); #endif From 6e83e6aed1fdc8c72693eace5c107f5fc3cdb2ef Mon Sep 17 00:00:00 2001 From: badlogic Date: Wed, 18 Jul 2018 12:04:11 +0200 Subject: [PATCH 15/15] [c][cpp][sfml][cocos2d-x] Skip rendering of skeleton/slot/attachment early if alpha is 0. See #1145 --- spine-cocos2dx/src/spine/SkeletonRenderer.cpp | 23 +++++++++++++++ spine-sfml/c/src/spine/spine-sfml.cpp | 28 +++++++++++++++++-- spine-sfml/cpp/src/spine/spine-sfml.cpp | 27 ++++++++++++++++-- 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp index 8fac0f5ed..20d822eb4 100644 --- a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp +++ b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp @@ -266,6 +266,11 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t SkeletonTwoColorBatch* twoColorBatch = SkeletonTwoColorBatch::getInstance(); bool isTwoColorTint = this->isTwoColorTint(); + // Early exit if the skeleton is invisible + if (getDisplayedOpacity() == 0 || _skeleton->color.a == 0){ + return; + } + if (_effect) _effect->begin(_effect, _skeleton); Color4F nodeColor; @@ -301,6 +306,12 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t continue; } + // Early exit if slot is invisible + if (slot->color.a == 0) { + spSkeletonClipping_clipEnd(_clipper, slot); + continue; + } + cocos2d::TrianglesCommand::Triangles triangles; TwoColorTriangles trianglesTwoColor; @@ -309,6 +320,12 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t spRegionAttachment* attachment = (spRegionAttachment*)slot->attachment; attachmentVertices = getAttachmentVertices(attachment); + // Early exit if attachment is invisible + if (attachment->color.a == 0) { + spSkeletonClipping_clipEnd(_clipper, slot); + continue; + } + if (!isTwoColorTint) { triangles.indices = attachmentVertices->_triangles->indices; triangles.indexCount = attachmentVertices->_triangles->indexCount; @@ -338,6 +355,12 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t spMeshAttachment* attachment = (spMeshAttachment*)slot->attachment; attachmentVertices = getAttachmentVertices(attachment); + // Early exit if attachment is invisible + if (attachment->color.a == 0) { + spSkeletonClipping_clipEnd(_clipper, slot); + continue; + } + if (!isTwoColorTint) { triangles.indices = attachmentVertices->_triangles->indices; triangles.indexCount = attachmentVertices->_triangles->indexCount; diff --git a/spine-sfml/c/src/spine/spine-sfml.cpp b/spine-sfml/c/src/spine/spine-sfml.cpp index c3304d77e..e48fc0856 100644 --- a/spine-sfml/c/src/spine/spine-sfml.cpp +++ b/spine-sfml/c/src/spine/spine-sfml.cpp @@ -116,6 +116,9 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const { states.texture = 0; unsigned short quadIndices[6] = { 0, 1, 2, 2, 3, 0 }; + // Early out if skeleton is invisible + if (skeleton->color.a == 0) return; + if (vertexEffect != 0) vertexEffect->begin(vertexEffect, skeleton); sf::Vertex vertex; @@ -125,6 +128,12 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const { Attachment* attachment = slot->attachment; if (!attachment) continue; + // Early out if slot is invisible + if (slot->color.a == 0) { + spSkeletonClipping_clipEnd(clipper, slot); + continue; + } + float* vertices = worldVertices; int verticesCount = 0; float* uvs = 0; @@ -134,16 +143,31 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const { if (attachment->type == ATTACHMENT_REGION) { RegionAttachment* regionAttachment = (RegionAttachment*)attachment; + attachmentColor = ®ionAttachment->color; + + // Early out if slot is invisible + if (attachmentColor->a == 0) { + spSkeletonClipping_clipEnd(clipper, slot); + continue; + } + spRegionAttachment_computeWorldVertices(regionAttachment, slot->bone, vertices, 0, 2); verticesCount = 4; uvs = regionAttachment->uvs; indices = quadIndices; indicesCount = 6; texture = (Texture*)((AtlasRegion*)regionAttachment->rendererObject)->page->rendererObject; - attachmentColor = ®ionAttachment->color; } else if (attachment->type == ATTACHMENT_MESH) { MeshAttachment* mesh = (MeshAttachment*)attachment; + attachmentColor = &mesh->color; + + // Early out if slot is invisible + if (attachmentColor->a == 0) { + spSkeletonClipping_clipEnd(clipper, slot); + continue; + } + if (mesh->super.worldVerticesLength > SPINE_MESH_VERTEX_COUNT_MAX) continue; texture = (Texture*)((AtlasRegion*)mesh->rendererObject)->page->rendererObject; spVertexAttachment_computeWorldVertices(SUPER(mesh), slot, 0, mesh->super.worldVerticesLength, worldVertices, 0, 2); @@ -151,7 +175,7 @@ void SkeletonDrawable::draw (RenderTarget& target, RenderStates states) const { uvs = mesh->uvs; indices = mesh->triangles; indicesCount = mesh->trianglesCount; - attachmentColor = &mesh->color; + } else if (attachment->type == SP_ATTACHMENT_CLIPPING) { spClippingAttachment* clip = (spClippingAttachment*)slot->attachment; spSkeletonClipping_clipStart(clipper, slot, clip); diff --git a/spine-sfml/cpp/src/spine/spine-sfml.cpp b/spine-sfml/cpp/src/spine/spine-sfml.cpp index 1aca8c9f7..4359c64d7 100644 --- a/spine-sfml/cpp/src/spine/spine-sfml.cpp +++ b/spine-sfml/cpp/src/spine/spine-sfml.cpp @@ -91,6 +91,9 @@ void SkeletonDrawable::draw(RenderTarget &target, RenderStates states) const { vertexArray->clear(); states.texture = NULL; + // Early out if the skeleton alpha is 0 + if (skeleton->getColor().a == 0) return; + if (vertexEffect != NULL) vertexEffect->begin(*skeleton); sf::Vertex vertex; @@ -100,6 +103,12 @@ void SkeletonDrawable::draw(RenderTarget &target, RenderStates states) const { Attachment *attachment = slot.getAttachment(); if (!attachment) continue; + // Early out if the slot color is 0 + if (slot.getColor().a == 0) { + clipper.clipEnd(slot); + continue; + } + Vector *vertices = &worldVertices; int verticesCount = 0; Vector *uvs = NULL; @@ -109,6 +118,14 @@ void SkeletonDrawable::draw(RenderTarget &target, RenderStates states) const { if (attachment->getRTTI().isExactly(RegionAttachment::rtti)) { RegionAttachment *regionAttachment = (RegionAttachment *) attachment; + attachmentColor = ®ionAttachment->getColor(); + + // Early out if the attachment color is 0 + if (attachmentColor->a == 0) { + clipper.clipEnd(slot); + continue; + } + worldVertices.setSize(8, 0); regionAttachment->computeWorldVertices(slot.getBone(), worldVertices, 0, 2); verticesCount = 4; @@ -116,10 +133,17 @@ void SkeletonDrawable::draw(RenderTarget &target, RenderStates states) const { indices = &quadIndices; indicesCount = 6; texture = (Texture *) ((AtlasRegion *) regionAttachment->getRendererObject())->page->rendererObject; - attachmentColor = ®ionAttachment->getColor(); } else if (attachment->getRTTI().isExactly(MeshAttachment::rtti)) { MeshAttachment *mesh = (MeshAttachment *) attachment; + attachmentColor = &mesh->getColor(); + + // Early out if the attachment color is 0 + if (attachmentColor->a == 0) { + clipper.clipEnd(slot); + continue; + } + worldVertices.setSize(mesh->getWorldVerticesLength(), 0); texture = (Texture *) ((AtlasRegion *) mesh->getRendererObject())->page->rendererObject; mesh->computeWorldVertices(slot, 0, mesh->getWorldVerticesLength(), worldVertices, 0, 2); @@ -127,7 +151,6 @@ void SkeletonDrawable::draw(RenderTarget &target, RenderStates states) const { uvs = &mesh->getUVs(); indices = &mesh->getTriangles(); indicesCount = mesh->getTriangles().size(); - attachmentColor = &mesh->getColor(); } else if (attachment->getRTTI().isExactly(ClippingAttachment::rtti)) { ClippingAttachment *clip = (ClippingAttachment *) slot.getAttachment(); clipper.clipStart(slot, clip);