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]; } diff --git a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/TestHarness.java b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/TestHarness.java index 8ace69cf3..06c485253 100644 --- a/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/TestHarness.java +++ b/spine-libgdx/spine-libgdx-tests/src/com/esotericsoftware/spine/TestHarness.java @@ -50,7 +50,7 @@ public class TestHarness extends ApplicationAdapter { skeleton = new Skeleton(skeletonData); skeleton.setPosition(320, 590); - skeleton.flipY = true; + skeleton.setScaleY(-1); AnimationStateData stateData = new AnimationStateData(skeletonData); state = new AnimationState(stateData); 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/Bone.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java index 54d397a3c..1994c6911 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Bone.java @@ -30,13 +30,12 @@ package com.esotericsoftware.spine; -import static com.esotericsoftware.spine.utils.SpineUtils.*; import static com.badlogic.gdx.math.Matrix3.*; +import static com.esotericsoftware.spine.utils.SpineUtils.*; import com.badlogic.gdx.math.Matrix3; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Array; -import com.esotericsoftware.spine.BoneData.TransformMode; /** Stores a bone's current pose. *

@@ -111,28 +110,14 @@ public class Bone implements Updatable { Bone parent = this.parent; if (parent == null) { // Root bone. - float rotationY = rotation + 90 + shearY; - float la = cosDeg(rotation + shearX) * scaleX; - float lb = cosDeg(rotationY) * scaleY; - float lc = sinDeg(rotation + shearX) * scaleX; - float ld = sinDeg(rotationY) * scaleY; Skeleton skeleton = this.skeleton; - if (skeleton.flipX) { - x = -x; - la = -la; - lb = -lb; - } - if (skeleton.flipY) { - 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 = cosDeg(rotation + shearX) * scaleX * sx; + b = cosDeg(rotationY) * scaleY * sy; + c = sinDeg(rotation + shearX) * scaleX * sx; + d = sinDeg(rotationY) * scaleY * sy; + worldX = x * sx + skeleton.x; + worldY = y * sy + skeleton.y; return; } @@ -188,8 +173,8 @@ public class Bone implements Updatable { case noScale: case noScaleOrReflection: { float cos = cosDeg(rotation), sin = 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; @@ -201,26 +186,18 @@ public class Bone implements Updatable { float la = cosDeg(shearX) * scaleX; float lb = cosDeg(90 + shearY) * scaleY; float lc = sinDeg(shearX) * scaleX; - float ld = sinDeg(90 + shearY) * scaleY; - if (data.transformMode != TransformMode.noScaleOrReflection ? pa * pd - pb * pc < 0 : skeleton.flipX != skeleton.flipY) { - zb = -zb; - zd = -zd; - } + float ld = sinDeg(90 + shearY) * scaleY; a = za * la + zb * lc; b = za * lb + zb * ld; c = zc * la + zd * lc; d = zc * lb + zd * ld; - return; + break; } } - if (skeleton.flipX) { - a = -a; - b = -b; - } - if (skeleton.flipY) { - c = -c; - d = -d; - } + a *= skeleton.scaleX; + b *= skeleton.scaleX; + c *= skeleton.scaleY; + d *= skeleton.scaleY; } /** Sets this bone's local transform to the setup pose. */ 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..77623cbad 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 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); } /** 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 && l1 + l2 > 0.0001f) 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 9bc28c918..1e3168037 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/Skeleton.java @@ -30,14 +30,14 @@ package com.esotericsoftware.spine; -import static com.esotericsoftware.spine.utils.SpineUtils.cosDeg; -import static com.esotericsoftware.spine.utils.SpineUtils.sinDeg; +import static com.esotericsoftware.spine.utils.SpineUtils.*; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.FloatArray; import com.badlogic.gdx.utils.ObjectMap.Entry; + import com.esotericsoftware.spine.Skin.Key; import com.esotericsoftware.spine.attachments.Attachment; import com.esotericsoftware.spine.attachments.MeshAttachment; @@ -61,7 +61,7 @@ public class Skeleton { Skin skin; final Color color; float time; - boolean flipX, flipY; + float scaleX = 1, scaleY = 1; float x, y; public Skeleton (SkeletonData data) { @@ -150,8 +150,8 @@ public class Skeleton { skin = skeleton.skin; color = new Color(skeleton.color); time = skeleton.time; - flipX = skeleton.flipX; - flipY = skeleton.flipY; + scaleX = skeleton.scaleX; + scaleY = skeleton.scaleY; updateCache(); } @@ -331,9 +331,9 @@ public class Skeleton { for (int i = 0, n = updateCache.size; i < n; i++) updateCache.get(i).update(); } - - /** Updates the world transform for each bone and applies all constraints. The - * root bone will be temporarily parented to the specified bone. + + /** Updates the world transform for each bone and applies all constraints. The root bone will be temporarily parented to the + * specified bone. *

* See World transforms in the Spine * Runtimes Guide. */ @@ -353,7 +353,7 @@ public class Skeleton { bone.ashearY = bone.shearY; bone.appliedValid = true; } - + // Apply the parent bone transform to the root bone. The root bone // always inherits scale, rotation and reflection. Bone rootBone = getRootBone(); @@ -366,20 +366,11 @@ public class Skeleton { float lb = cosDeg(rotationY) * rootBone.scaleY; float lc = sinDeg(rootBone.rotation + rootBone.shearX) * rootBone.scaleX; float ld = sinDeg(rotationY) * rootBone.scaleY; - rootBone.a = pa * la + pb * lc; - rootBone.b = pa * lb + pb * ld; - rootBone.c = pc * la + pd * lc; - rootBone.d = pc * lb + pd * ld; - - if (flipY) { - rootBone.a = -rootBone.a; - rootBone.b = -rootBone.b; - } - if (flipX) { - rootBone.c = -rootBone.c; - rootBone.d = -rootBone.d; - } - + rootBone.a = (pa * la + pb * lc) * scaleX; + rootBone.b = (pa * lb + pb * ld) * scaleX; + rootBone.c = (pc * la + pd * lc) * scaleY; + rootBone.d = (pc * lb + pd * ld) * scaleY; + // Update everything except root bone. Array updateCache = this.updateCache; for (int i = 0, n = updateCache.size; i < n; i++) { @@ -404,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; } @@ -685,29 +677,29 @@ public class Skeleton { this.color.set(color); } - /** If true, the entire skeleton is flipped over the Y axis. This affects all bones, even if the bone's transform mode - * disallows scale inheritance. */ - public boolean getFlipX () { - return flipX; + /** Scales the entire skeleton on the X axis. This affects all bones, even if the bone's transform mode disallows scale + * inheritance. */ + public float getScaleX () { + return scaleX; } - public void setFlipX (boolean flipX) { - this.flipX = flipX; + public void setScaleX (float scaleX) { + this.scaleX = scaleX; } - /** If true, the entire skeleton is flipped over the X axis. This affects all bones, even if the bone's transform mode - * disallows scale inheritance. */ - public boolean getFlipY () { - return flipY; + /** Scales the entire skeleton on the Y axis. This affects all bones, even if the bone's transform mode disallows scale + * inheritance. */ + public float getScaleY () { + return scaleY; } - public void setFlipY (boolean flipY) { - this.flipY = flipY; + public void setScaleY (float scaleY) { + this.scaleY = scaleY; } - public void setFlip (boolean flipX, boolean flipY) { - this.flipX = flipX; - this.flipY = flipY; + public void setScale (float scaleX, float scaleY) { + this.scaleX = scaleX; + this.scaleY = scaleY; } /** Sets the skeleton X position, which is added to the root bone worldX position. */ 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++; } 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) { diff --git a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonActorPool.java b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonActorPool.java index 4709802e5..a22286cb9 100644 --- a/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonActorPool.java +++ b/spine-libgdx/spine-libgdx/src/com/esotericsoftware/spine/utils/SkeletonActorPool.java @@ -70,7 +70,7 @@ public class SkeletonActorPool extends Pool { protected void reset (Skeleton skeleton) { skeleton.setColor(Color.WHITE); - skeleton.setFlip(false, false); + skeleton.setScale(1, 1); skeleton.setSkin((Skin)null); skeleton.setSkin(SkeletonActorPool.this.skeletonData.getDefaultSkin()); skeleton.setToSetupPose(); diff --git a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java index 1e4bc020d..f6cd0a632 100644 --- a/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java +++ b/spine-libgdx/spine-skeletonviewer/src/com/esotericsoftware/spine/SkeletonViewer.java @@ -192,11 +192,11 @@ public class SkeletonViewer extends ApplicationAdapter { String extension = skeletonFile.extension(); if (extension.equalsIgnoreCase("json") || extension.equalsIgnoreCase("txt")) { SkeletonJson json = new SkeletonJson(atlas); - json.setScale(ui.scaleSlider.getValue()); + json.setScale(ui.loadScaleSlider.getValue()); skeletonData = json.readSkeletonData(skeletonFile); } else { SkeletonBinary binary = new SkeletonBinary(atlas); - binary.setScale(ui.scaleSlider.getValue()); + binary.setScale(ui.loadScaleSlider.getValue()); skeletonData = binary.readSkeletonData(skeletonFile); if (skeletonData.getBones().size == 0) throw new Exception("No bones in skeleton data."); } @@ -311,7 +311,10 @@ public class SkeletonViewer extends ApplicationAdapter { renderer.setPremultipliedAlpha(ui.premultipliedCheckbox.isChecked()); batch.setPremultipliedAlpha(ui.premultipliedCheckbox.isChecked()); - skeleton.setFlip(ui.flipXCheckbox.isChecked(), ui.flipYCheckbox.isChecked()); + float scaleX = ui.xScaleSlider.getValue(), scaleY = ui.yScaleSlider.getValue(); + if (skeleton.scaleX == 0) skeleton.scaleX = 0.01f; + if (skeleton.scaleY == 0) skeleton.scaleY = 0.01f; + skeleton.setScale(scaleX, scaleY); delta = Math.min(delta, 0.032f) * ui.speedSlider.getValue(); skeleton.update(delta); @@ -412,16 +415,21 @@ public class SkeletonViewer extends ApplicationAdapter { TextButton openButton = new TextButton("Open", skin); TextButton minimizeButton = new TextButton("-", skin); - Slider scaleSlider = new Slider(0.1f, 3, 0.01f, false, skin); - Label scaleLabel = new Label("1.0", skin); - TextButton scaleResetButton = new TextButton("Reset", skin); + Slider loadScaleSlider = new Slider(0.1f, 3, 0.01f, false, skin); + Label loadScaleLabel = new Label("100%", skin); + TextButton loadScaleResetButton = new TextButton("Reset", skin); Slider zoomSlider = new Slider(0.01f, 10, 0.01f, false, skin); - Label zoomLabel = new Label("1.0", skin); + Label zoomLabel = new Label("100%", skin); TextButton zoomResetButton = new TextButton("Reset", skin); - CheckBox flipXCheckbox = new CheckBox("X", skin); - CheckBox flipYCheckbox = new CheckBox("Y", skin); + Slider xScaleSlider = new Slider(-2, 2, 0.01f, false, skin); + Label xScaleLabel = new Label("100%", skin); + TextButton xScaleResetButton = new TextButton("Reset", skin); + + Slider yScaleSlider = new Slider(-2, 2, 0.01f, false, skin); + Label yScaleLabel = new Label("100%", skin); + TextButton yScaleResetButton = new TextButton("Reset", skin); CheckBox debugBonesCheckbox = new CheckBox("Bones", skin); CheckBox debugRegionsCheckbox = new CheckBox("Regions", skin); @@ -448,17 +456,17 @@ public class SkeletonViewer extends ApplicationAdapter { CheckBox addCheckbox = new CheckBox("Add", skin); Slider alphaSlider = new Slider(0, 1, 0.01f, false, skin); - Label alphaLabel = new Label("1.0", skin); + Label alphaLabel = new Label("100%", skin); List animationList = new List(skin); ScrollPane animationScroll = new ScrollPane(animationList, skin, "bg"); Slider speedSlider = new Slider(0, 3, 0.01f, false, skin); - Label speedLabel = new Label("1.0", skin); + Label speedLabel = new Label("1.0x", skin); TextButton speedResetButton = new TextButton("Reset", skin); Slider mixSlider = new Slider(0, 4, 0.01f, false, skin); - Label mixLabel = new Label("0.3", skin); + Label mixLabel = new Label("0.3s", skin); Label statusLabel = new Label("", skin); WidgetGroup toasts = new WidgetGroup(); @@ -483,21 +491,27 @@ public class SkeletonViewer extends ApplicationAdapter { loopCheckbox.setChecked(true); - scaleSlider.setValue(1); - scaleSlider.setSnapToValues(new float[] {0.5f, 1, 1.5f, 2, 2.5f, 3, 3.5f}, 0.01f); + loadScaleSlider.setValue(1); + loadScaleSlider.setSnapToValues(new float[] {0.5f, 1, 1.5f, 2, 2.5f}, 0.09f); zoomSlider.setValue(1); - zoomSlider.setSnapToValues(new float[] {0.5f, 1, 1.5f, 2, 2.5f, 3, 3.5f}, 0.01f); + zoomSlider.setSnapToValues(new float[] {1, 2}, 0.30f); + + xScaleSlider.setValue(1); + xScaleSlider.setSnapToValues(new float[] {-1.5f, -1, -0.5f, 0.5f, 1, 1.5f}, 0.12f); + + yScaleSlider.setValue(1); + yScaleSlider.setSnapToValues(new float[] {-1.5f, -1, -0.5f, 0.5f, 1, 1.5f}, 0.12f); mixSlider.setValue(0.3f); - mixSlider.setSnapToValues(new float[] {1, 1.5f, 2, 2.5f, 3, 3.5f}, 0.1f); + mixSlider.setSnapToValues(new float[] {1, 1.5f, 2, 2.5f, 3, 3.5f}, 0.12f); speedSlider.setValue(1); - speedSlider.setSnapToValues(new float[] {0.5f, 0.75f, 1, 1.25f, 1.5f, 2, 2.5f}, 0.01f); + speedSlider.setSnapToValues(new float[] {0.5f, 0.75f, 1, 1.25f, 1.5f, 2, 2.5f}, 0.09f); alphaSlider.setValue(1); alphaSlider.setDisabled(true); - + addCheckbox.setDisabled(true); window.setMovable(false); @@ -519,12 +533,12 @@ public class SkeletonViewer extends ApplicationAdapter { root.defaults().space(6); root.columnDefaults(0).top().right().padTop(3); root.columnDefaults(1).left(); - root.add("Scale:"); + root.add("Load scale:"); { Table table = table(); - table.add(scaleLabel).width(29); - table.add(scaleSlider).growX(); - table.add(scaleResetButton); + table.add(loadScaleLabel).width(29); + table.add(loadScaleSlider).growX(); + table.add(loadScaleResetButton); root.add(table).fill().row(); } root.add("Zoom:"); @@ -535,8 +549,22 @@ public class SkeletonViewer extends ApplicationAdapter { table.add(zoomResetButton); root.add(table).fill().row(); } - root.add("Flip:"); - root.add(table(flipXCheckbox, flipYCheckbox)).row(); + root.add("Scale X:"); + { + Table table = table(); + table.add(xScaleLabel).width(29); + table.add(xScaleSlider).growX(); + table.add(xScaleResetButton).row(); + root.add(table).fill().row(); + } + root.add("Scale Y:"); + { + Table table = table(); + table.add(yScaleLabel).width(29); + table.add(yScaleSlider).growX(); + table.add(yScaleResetButton); + root.add(table).fill().row(); + } root.add("Debug:"); root.add(table(debugBonesCheckbox, debugRegionsCheckbox, debugBoundingBoxesCheckbox)).row(); root.add(); @@ -677,25 +705,25 @@ public class SkeletonViewer extends ApplicationAdapter { } }); - scaleSlider.addListener(new ChangeListener() { + loadScaleSlider.addListener(new ChangeListener() { public void changed (ChangeEvent event, Actor actor) { - scaleLabel.setText(Float.toString((int)(scaleSlider.getValue() * 100) / 100f)); - if (!scaleSlider.isDragging()) loadSkeleton(skeletonFile); + loadScaleLabel.setText(Integer.toString((int)(loadScaleSlider.getValue() * 100)) + "%"); + if (!loadScaleSlider.isDragging()) loadSkeleton(skeletonFile); } }); - scaleResetButton.addListener(new ChangeListener() { + loadScaleResetButton.addListener(new ChangeListener() { public void changed (ChangeEvent event, Actor actor) { resetCameraPosition(); - if (scaleSlider.getValue() == 1) + if (loadScaleSlider.getValue() == 1) loadSkeleton(skeletonFile); else - scaleSlider.setValue(1); + loadScaleSlider.setValue(1); } }); zoomSlider.addListener(new ChangeListener() { public void changed (ChangeEvent event, Actor actor) { - zoomLabel.setText(Float.toString((int)(zoomSlider.getValue() * 100) / 100f)); + zoomLabel.setText(Integer.toString((int)(zoomSlider.getValue() * 100)) + "%"); float newZoom = 1 / zoomSlider.getValue(); camera.position.x -= window.getWidth() / 2 * (newZoom - camera.zoom); camera.zoom = newZoom; @@ -710,9 +738,33 @@ public class SkeletonViewer extends ApplicationAdapter { } }); + xScaleSlider.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + if (xScaleSlider.getValue() == 0) xScaleSlider.setValue(0.01f); + xScaleLabel.setText(Integer.toString((int)(xScaleSlider.getValue() * 100)) + "%"); + } + }); + xScaleResetButton.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + xScaleSlider.setValue(1); + } + }); + + yScaleSlider.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + if (yScaleSlider.getValue() == 0) yScaleSlider.setValue(0.01f); + yScaleLabel.setText(Integer.toString((int)(yScaleSlider.getValue() * 100)) + "%"); + } + }); + yScaleResetButton.addListener(new ChangeListener() { + public void changed (ChangeEvent event, Actor actor) { + yScaleSlider.setValue(1); + } + }); + speedSlider.addListener(new ChangeListener() { public void changed (ChangeEvent event, Actor actor) { - speedLabel.setText(Float.toString((int)(speedSlider.getValue() * 100) / 100f)); + speedLabel.setText(Float.toString((int)(speedSlider.getValue() * 100) / 100f) + "x"); } }); speedResetButton.addListener(new ChangeListener() { @@ -723,7 +775,7 @@ public class SkeletonViewer extends ApplicationAdapter { alphaSlider.addListener(new ChangeListener() { public void changed (ChangeEvent event, Actor actor) { - alphaLabel.setText(Float.toString((int)(alphaSlider.getValue() * 100) / 100f)); + alphaLabel.setText(Integer.toString((int)(alphaSlider.getValue() * 100)) + "%"); int track = trackButtons.getCheckedIndex(); if (track > 0) { TrackEntry current = state.getCurrent(track); @@ -737,7 +789,7 @@ public class SkeletonViewer extends ApplicationAdapter { mixSlider.addListener(new ChangeListener() { public void changed (ChangeEvent event, Actor actor) { - mixLabel.setText(Float.toString((int)(mixSlider.getValue() * 100) / 100f)); + mixLabel.setText(Float.toString((int)(mixSlider.getValue() * 100) / 100f) + "s"); if (state != null) state.getData().setDefaultMix(mixSlider.getValue()); } }); @@ -878,8 +930,8 @@ public class SkeletonViewer extends ApplicationAdapter { speedSlider.addListener(savePrefsListener); speedResetButton.addListener(savePrefsListener); mixSlider.addListener(savePrefsListener); - scaleSlider.addListener(savePrefsListener); - scaleResetButton.addListener(savePrefsListener); + loadScaleSlider.addListener(savePrefsListener); + loadScaleResetButton.addListener(savePrefsListener); zoomSlider.addListener(savePrefsListener); zoomResetButton.addListener(savePrefsListener); animationList.addListener(savePrefsListener); @@ -942,7 +994,7 @@ public class SkeletonViewer extends ApplicationAdapter { prefs.putBoolean("add", addCheckbox.isChecked()); prefs.putFloat("speed", speedSlider.getValue()); prefs.putFloat("mix", mixSlider.getValue()); - prefs.putFloat("scale", scaleSlider.getValue()); + prefs.putFloat("scale", loadScaleSlider.getValue()); prefs.putFloat("zoom", zoomSlider.getValue()); prefs.putFloat("x", camera.position.x); prefs.putFloat("y", camera.position.y); @@ -978,7 +1030,7 @@ public class SkeletonViewer extends ApplicationAdapter { camera.position.x = prefs.getFloat("x", 0); camera.position.y = prefs.getFloat("y", 0); - scaleSlider.setValue(prefs.getFloat("scale", 1)); + loadScaleSlider.setValue(prefs.getFloat("scale", 1)); animationList.setSelected(prefs.getString("animationName", null)); skinList.setSelected(prefs.getString("skinName", null)); } catch (Exception ex) { diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpinePlugin.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpinePlugin.cpp index 4e8351326..18ae0d50e 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpinePlugin.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpinePlugin.cpp @@ -30,6 +30,8 @@ #include "SpinePluginPrivatePCH.h" +DEFINE_LOG_CATEGORY(SpineLog); + class FSpinePlugin : public SpinePlugin { virtual void StartupModule() override; virtual void ShutdownModule() override; diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonAnimationComponent.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonAnimationComponent.cpp index a575af97d..c01629bb3 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonAnimationComponent.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonAnimationComponent.cpp @@ -107,12 +107,14 @@ void USpineSkeletonAnimationComponent::CheckState () { if (Atlas && SkeletonData) { spSkeletonData* data = SkeletonData->GetSkeletonData(Atlas->GetAtlas(false), false); - skeleton = spSkeleton_create(data); - spAnimationStateData* stateData = SkeletonData->GetAnimationStateData(Atlas->GetAtlas(false)); - state = spAnimationState_create(stateData); - state->rendererObject = (void*)this; - state->listener = callback; - trackEntries.Empty(); + if (data) { + skeleton = spSkeleton_create(data); + spAnimationStateData* stateData = SkeletonData->GetAnimationStateData(Atlas->GetAtlas(false)); + state = spAnimationState_create(stateData); + state->rendererObject = (void*)this; + state->listener = callback; + trackEntries.Empty(); + } } lastAtlas = Atlas; diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp index 2c6d9ccfc..8ff4bf4dd 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Private/SpineSkeletonDataAsset.cpp @@ -33,6 +33,7 @@ #include #include #include +#include "Runtime/Core/Public/Misc/MessageDialog.h" #define LOCTEXT_NAMESPACE "Spine" @@ -103,10 +104,22 @@ spSkeletonData* USpineSkeletonDataAsset::GetSkeletonData (spAtlas* Atlas, bool F if (skeletonDataFileName.GetPlainNameString().Contains(TEXT(".json"))) { spSkeletonJson* json = spSkeletonJson_create(Atlas); this->skeletonData = spSkeletonJson_readSkeletonData(json, (const char*)rawData.GetData()); + if (!skeletonData) { +#if WITH_EDITORONLY_DATA + FMessageDialog::Debugf(FText::FromString(UTF8_TO_TCHAR(json->error))); +#endif + UE_LOG(SpineLog, Error, TEXT("Couldn't load skeleton data and atlas: %s"), UTF8_TO_TCHAR(json->error)); + } spSkeletonJson_dispose(json); } else { spSkeletonBinary* binary = spSkeletonBinary_create(Atlas); this->skeletonData = spSkeletonBinary_readSkeletonData(binary, (const unsigned char*)rawData.GetData(), (int)rawData.Num()); + if (!skeletonData) { +#if WITH_EDITORONLY_DATA + FMessageDialog::Debugf(FText::FromString(UTF8_TO_TCHAR(binary->error))); +#endif + UE_LOG(SpineLog, Error, TEXT("Couldn't load skeleton data and atlas: %s"), UTF8_TO_TCHAR(binary->error)); + } spSkeletonBinary_dispose(binary); } if (animationStateData) { diff --git a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpinePlugin.h b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpinePlugin.h index 6011f932d..0d16143f7 100644 --- a/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpinePlugin.h +++ b/spine-ue4/Plugins/SpinePlugin/Source/SpinePlugin/Public/SpinePlugin.h @@ -32,6 +32,8 @@ #include "ModuleManager.h" +DECLARE_LOG_CATEGORY_EXTERN(SpineLog, Log, All); + class SPINEPLUGIN_API SpinePlugin : public IModuleInterface { public: 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 000000000..7c5ca0bce Binary files /dev/null and b/spine-unity/Assets/Spine Examples/Other Examples/Animation Tester/Animation Tester.unity differ 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 4df601543..f36bb0745 100644 Binary files a/spine-unity/Assets/Spine Examples/Other Examples/Mix and Match Equip.unity and b/spine-unity/Assets/Spine Examples/Other Examples/Mix and Match Equip.unity differ diff --git a/spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation.meta b/spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation.meta new file mode 100644 index 000000000..0dc2b8f85 --- /dev/null +++ b/spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: 4766fcfd6167d2e46aad772ce3bc898c +folderAsset: yes +timeCreated: 1531292725 +licenseType: Free +DefaultImporter: + userData: + assetBundleName: + assetBundleVariant: diff --git a/spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/AnimationState with Mecanim.unity b/spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/AnimationState with Mecanim.unity new file mode 100644 index 000000000..aaf9462cd Binary files /dev/null and b/spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/AnimationState with Mecanim.unity differ 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 000000000..ae8ec504c Binary files /dev/null and b/spine-unity/Assets/Spine Examples/Other Examples/StateMachine SkeletonAnimation/Hero.controller differ 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 c0db3163e..993985b66 100644 Binary files a/spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro_Material.mat and b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro_Material.mat differ diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro_Material.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro_Material.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro_Material.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro_Material.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro_SkeletonData.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro_SkeletonData.asset new file mode 100644 index 000000000..68f84d5b1 Binary files /dev/null and b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro_SkeletonData.asset differ diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro_SkeletonData.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro_SkeletonData.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro_SkeletonData.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/hero-pro_SkeletonData.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/license.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/license.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/license.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/license.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/license.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/license.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Hero/license.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Hero/license.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy.atlas.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy.atlas.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy.atlas.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy.atlas.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy.atlas.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy.atlas.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy.atlas.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy.atlas.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy.png diff --git a/spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy_Atlas.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy_Atlas.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy_Atlas.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy_Atlas.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy_Atlas.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy_Atlas.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy_Atlas.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy_Atlas.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy_Material.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy_Material.mat similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy_Material.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy_Material.mat diff --git a/spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy_Material.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy_Material.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy_Material.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy_Material.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy_SkeletonData.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy_SkeletonData.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy_SkeletonData.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy_SkeletonData.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy_SkeletonData.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy_SkeletonData.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/Raggedy Spineboy_SkeletonData.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/Raggedy Spineboy_SkeletonData.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/raggedy spineboy.json b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/raggedy spineboy.json similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/raggedy spineboy.json rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/raggedy spineboy.json diff --git a/spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/raggedy spineboy.json.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/raggedy spineboy.json.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raggedy Spineboy/raggedy spineboy.json.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raggedy Spineboy/raggedy spineboy.json.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/Jump.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/Jump.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/Jump.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/Jump.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/Jump.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/Jump.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/Jump.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/Jump.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/gungrab.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/gungrab.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/gungrab.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/gungrab.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/gungrab.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/gungrab.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/gungrab.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/gungrab.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/gunkeep.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/gunkeep.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/gunkeep.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/gunkeep.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/gunkeep.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/gunkeep.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/gunkeep.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/gunkeep.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/walk.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/walk.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/walk.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/walk.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/walk.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/walk.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/ReferenceAssets/walk.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/ReferenceAssets/walk.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/raptor.atlas.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.atlas.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/raptor.atlas.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.atlas.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/raptor.atlas.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.atlas.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/raptor.atlas.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.atlas.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/raptor.json b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.json similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/raptor.json rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.json diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/raptor.json.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.json.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/raptor.json.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.json.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/raptor.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/raptor.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.png diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/raptor.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/raptor.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/raptor_Atlas.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor_Atlas.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/raptor_Atlas.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor_Atlas.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/raptor_Atlas.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor_Atlas.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/raptor_Atlas.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor_Atlas.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/raptor_Material.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor_Material.mat similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/raptor_Material.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor_Material.mat diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/raptor_Material.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor_Material.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/raptor_Material.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor_Material.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/raptor_SkeletonData.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor_SkeletonData.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/raptor_SkeletonData.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor_SkeletonData.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Raptor/raptor_SkeletonData.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor_SkeletonData.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Raptor/raptor_SkeletonData.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Raptor/raptor_SkeletonData.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Runtime Template Material.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/Runtime Template Material.mat similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Runtime Template Material.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Runtime Template Material.mat diff --git a/spine-unity/Assets/Spine Examples/Spine/Runtime Template Material.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Runtime Template Material.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Runtime Template Material.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Runtime Template Material.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi.atlas.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi.atlas.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi.atlas.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi.atlas.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi.atlas.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi.atlas.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi.atlas.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi.atlas.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi.json b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi.json similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi.json rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi.json diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi.json.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi.json.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi.json.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi.json.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi.png diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi_Atlas.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi_Atlas.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi_Atlas.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi_Atlas.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi_Atlas.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi_Atlas.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi_Atlas.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi_Atlas.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi_Material.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi_Material.mat similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi_Material.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi_Material.mat diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi_Material.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi_Material.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi_Material.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi_Material.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi_SkeletonData.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi_SkeletonData.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi_SkeletonData.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi_SkeletonData.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi_SkeletonData.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi_SkeletonData.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/Doi_SkeletonData.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/Doi_SkeletonData.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/ReferenceAssets.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/ReferenceAssets.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/ReferenceAssets.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/ReferenceAssets.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/ReferenceAssets/blink.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/ReferenceAssets/blink.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/ReferenceAssets/blink.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/ReferenceAssets/blink.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/ReferenceAssets/blink.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/ReferenceAssets/blink.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/ReferenceAssets/blink.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/ReferenceAssets/blink.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/ReferenceAssets/main.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/ReferenceAssets/main.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/ReferenceAssets/main.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/ReferenceAssets/main.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/ReferenceAssets/main.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/ReferenceAssets/main.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Spineunitygirl/ReferenceAssets/main.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Spineunitygirl/ReferenceAssets/main.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma.atlas.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma.atlas.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma.atlas.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma.atlas.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma.atlas.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma.atlas.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma.atlas.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma.atlas.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma.png diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma_Atlas.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma_Atlas.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma_Atlas.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma_Atlas.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma_Atlas.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma_Atlas.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma_Atlas.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma_Atlas.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma_Material.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma_Material.mat similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma_Material.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma_Material.mat diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma_Material.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma_Material.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-diffuse-pma_Material.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-diffuse-pma_Material.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-emission.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-emission.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-emission.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-emission.png diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-emission.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-emission.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-emission.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-emission.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-normals.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-normals.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-normals.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-normals.png diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-normals.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-normals.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman-normals.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman-normals.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman.json b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman.json similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman.json rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman.json diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman.json.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman.json.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman.json.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman.json.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman_SkeletonData.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman_SkeletonData.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman_SkeletonData.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman_SkeletonData.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman_SkeletonData.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman_SkeletonData.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/Strechyman/stretchyman_SkeletonData.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/Strechyman/stretchyman_SkeletonData.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-pro.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-pro.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro.atlas.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.atlas.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro.atlas.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.atlas.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro.atlas.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.atlas.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro.atlas.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.atlas.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro.json b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.json similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro.json rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.json diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro.json.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.json.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro.json.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.json.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.png diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro_Atlas.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro_Atlas.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro_Atlas.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro_Atlas.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro_Atlas.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro_Atlas.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro_Atlas.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro_Atlas.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro_Material.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro_Material.mat similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro_Material.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro_Material.mat diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro_Material.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro_Material.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro_Material.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro_Material.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro_SkeletonData.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro_SkeletonData.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro_SkeletonData.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro_SkeletonData.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro_SkeletonData.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro_SkeletonData.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-pro/spineboy-pro_SkeletonData.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-pro/spineboy-pro_SkeletonData.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/goggles-normal.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/goggles-normal.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/goggles-normal.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/goggles-normal.png diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/goggles-normal.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/goggles-normal.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/goggles-normal.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/goggles-normal.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/goggles-tactical.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/goggles-tactical.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/goggles-tactical.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/goggles-tactical.png diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/goggles-tactical.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/goggles-tactical.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/goggles-tactical.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/goggles-tactical.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/gun-freeze.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/gun-freeze.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/gun-freeze.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/gun-freeze.png diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/gun-freeze.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/gun-freeze.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/gun-freeze.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/gun-freeze.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/gun-normal.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/gun-normal.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/gun-normal.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/gun-normal.png diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/gun-normal.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/gun-normal.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/Equips/gun-normal.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/Equips/gun-normal.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/death.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/death.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/death.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/death.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/death.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/death.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/death.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/death.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/diagonal.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/diagonal.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/diagonal.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/diagonal.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/diagonal.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/diagonal.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/diagonal.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/diagonal.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/footstep.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/footstep.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/footstep.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/footstep.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/footstep.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/footstep.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/footstep.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/footstep.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/frozen.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/frozen.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/frozen.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/frozen.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/frozen.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/frozen.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/frozen.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/frozen.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/gun toss.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/gun toss.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/gun toss.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/gun toss.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/gun toss.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/gun toss.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/gun toss.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/gun toss.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/hit old.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/hit old.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/hit old.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/hit old.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/hit old.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/hit old.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/hit old.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/hit old.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/hit.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/hit.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/hit.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/hit.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/hit.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/hit.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/hit.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/hit.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/idle.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/idle.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/idle.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/idle.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/idle.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/idle.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/idle.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/idle.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/idlebag.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/idlebag.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/idlebag.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/idlebag.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/idlebag.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/idlebag.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/idlebag.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/idlebag.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/jump old.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/jump old.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/jump old.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/jump old.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/jump old.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/jump old.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/jump old.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/jump old.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/jump rm.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/jump rm.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/jump rm.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/jump rm.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/jump rm.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/jump rm.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/jump rm.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/jump rm.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/jump.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/jump.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/jump.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/jump.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/jump.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/jump.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/jump.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/jump.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/pole.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/pole.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/pole.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/pole.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/pole.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/pole.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/pole.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/pole.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/run rm.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/run rm.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/run rm.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/run rm.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/run rm.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/run rm.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/run rm.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/run rm.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/run.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/run.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/run.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/run.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/run.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/run.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/run.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/run.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/shoot.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/shoot.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/shoot.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/shoot.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/shoot.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/shoot.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/shoot.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/shoot.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/walk rm.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/walk rm.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/walk rm.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/walk rm.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/walk rm.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/walk rm.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/walk rm.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/walk rm.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/walk.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/walk.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/walk.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/walk.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/walk.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/walk.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/ReferenceAssets/walk.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/ReferenceAssets/walk.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy-unity.json b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy-unity.json similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy-unity.json rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy-unity.json diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy-unity.json.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy-unity.json.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy-unity.json.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy-unity.json.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy-unity_SkeletonData.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy-unity_SkeletonData.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy-unity_SkeletonData.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy-unity_SkeletonData.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy-unity_SkeletonData.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy-unity_SkeletonData.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy-unity_SkeletonData.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy-unity_SkeletonData.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy.atlas.txt b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy.atlas.txt similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy.atlas.txt rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy.atlas.txt diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy.atlas.txt.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy.atlas.txt.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy.atlas.txt.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy.atlas.txt.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy.png diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy_Atlas.asset b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy_Atlas.asset similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy_Atlas.asset rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy_Atlas.asset diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy_Atlas.asset.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy_Atlas.asset.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy_Atlas.asset.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy_Atlas.asset.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy_Material Fill.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy_Material Fill.mat similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy_Material Fill.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy_Material Fill.mat diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy_Material Fill.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy_Material Fill.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy_Material Fill.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy_Material Fill.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy_Material.mat b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy_Material.mat similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy_Material.mat rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy_Material.mat diff --git a/spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy_Material.mat.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy_Material.mat.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/spineboy-unity/spineboy_Material.mat.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/spineboy-unity/spineboy_Material.mat.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/square32.png b/spine-unity/Assets/Spine Examples/Spine Skeletons/square32.png similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/square32.png rename to spine-unity/Assets/Spine Examples/Spine Skeletons/square32.png diff --git a/spine-unity/Assets/Spine Examples/Spine/square32.png.meta b/spine-unity/Assets/Spine Examples/Spine Skeletons/square32.png.meta similarity index 100% rename from spine-unity/Assets/Spine Examples/Spine/square32.png.meta rename to spine-unity/Assets/Spine Examples/Spine Skeletons/square32.png.meta diff --git a/spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro_SkeletonData.asset b/spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro_SkeletonData.asset deleted file mode 100644 index 965ca4cb6..000000000 --- a/spine-unity/Assets/Spine Examples/Spine/Hero/hero-pro_SkeletonData.asset +++ /dev/null @@ -1,34 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!114 &11400000 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_PrefabParentObject: {fileID: 0} - m_PrefabInternal: {fileID: 0} - m_GameObject: {fileID: 0} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: f1b3b4b945939a54ea0b23d3396115fb, type: 3} - m_Name: hero-pro_SkeletonData - m_EditorClassIdentifier: - atlasAssets: - - {fileID: 11400000, guid: 8384ab388a4037649a1f64fb2e1a8e7f, type: 2} - scale: 0.01 - skeletonJSON: {fileID: 4900000, guid: 33cbc24302a26c1438b20d9253eee469, type: 3} - fromAnimation: - - fall - - run-from fall - - fall - - idle - toAnimation: - - run-from fall - - run - - crouch - - crouch - duration: - - 0.05 - - 0 - - 0 - - 0 - defaultMix: 0.1 - controller: {fileID: 0} 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 286149297..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) { @@ -80,7 +87,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 +1413,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.AssetUtility.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..d27348f48 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 @@ -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(); @@ -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) { @@ -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; @@ -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); @@ -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/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/Editor/spine-unity/Editor/SpineAtlasAssetInspector.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/SpineAtlasAssetInspector.cs index 798392f86..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(); @@ -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 66804c332..d7ab79121 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,1018 +213,618 @@ 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) { - #else - internal static void HierarchyIconsOnPlaymodeStateChanged () { - #endif - skeletonRendererTable.Clear(); - skeletonUtilityBoneTable.Clear(); - boundingBoxFollowerTable.Clear(); - - #if UNITY_2018 - EditorApplication.hierarchyChanged -= HierarchyIconsOnChanged; - #else - EditorApplication.hierarchyWindowChanged -= HierarchyIconsOnChanged; - #endif - EditorApplication.hierarchyWindowItemOnGUI -= HierarchyIconsOnGUI; - - if (!Application.isPlaying && showHierarchyIcons) { - #if UNITY_2018 - EditorApplication.hierarchyChanged += HierarchyIconsOnChanged; - #else - EditorApplication.hierarchyWindowChanged += HierarchyIconsOnChanged; - #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; - } - } - - } - } - } - } - - } - } - #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(); - 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 }; - - 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; - } - - 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; - } - - 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(); - - if (skeletonDataPath.Contains(".skel")) { - AddRequiredAtlasRegionsFromBinary(skeletonDataPath, requiredPaths); - return requiredPaths; - } - - TextAsset spineJson = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonDataPath, typeof(TextAsset)); - - 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; - } - - 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; - 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 - - #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)); - 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) { - 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"; - + public static class Preferences { #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; - } - + const float DEFAULT_DEFAULT_SCALE = 1f; #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; - } + const float DEFAULT_DEFAULT_SCALE = 0.01f; + #endif + const string DEFAULT_SCALE_KEY = "SPINE_DEFAULT_SCALE"; + public static float defaultScale = DEFAULT_DEFAULT_SCALE; - AssetDatabase.CreateAsset(skeletonDataAsset, filePath); - AssetDatabase.SaveAssets(); - } else { - skeletonDataAsset.atlasAssets = atlasAssets; - skeletonDataAsset.Clear(); - skeletonDataAsset.GetSkeletonData(true); + 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"; + + 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 + HierarchyHandler.IconsOnPlaymodeStateChanged(PlayModeStateChange.EnteredEditMode); + #else + HierarchyHandler.IconsOnPlaymodeStateChanged(); + #endif } - return skeletonDataAsset; - } else { - EditorUtility.DisplayDialog("Error!", "Must specify both Spine JSON and AtlasAsset array", "OK"); - return null; - } - #endif - } - #endregion + 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(); + } + } + } + + public static class AssetUtility { + public const string SkeletonDataSuffix = "_SkeletonData"; + public const string AtlasSuffix = "_Atlas"; - #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; + /// 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 }; + + public static List GetRequiredAtlasRegions (string skeletonDataPath) { + List requiredPaths = new List(); + + if (skeletonDataPath.Contains(".skel")) { + AddRequiredAtlasRegionsFromBinary(skeletonDataPath, requiredPaths); + return requiredPaths; + } + + TextAsset spineJson = (TextAsset)AssetDatabase.LoadAssetAtPath(skeletonDataPath, typeof(TextAsset)); + + StringReader reader = new StringReader(spineJson.text); + var root = Json.Deserialize(reader) as Dictionary; + + if (!root.ContainsKey("skins")) + return requiredPaths; + + foreach (var skin in (Dictionary)root["skins"]) { + foreach (var slot in (Dictionary)skin.Value) { + + foreach (var attachment in ((Dictionary)slot.Value)) { + var data = ((Dictionary)attachment.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; + } + + if (data.ContainsKey("path")) + requiredPaths.Add((string)data["path"]); + else if (data.ContainsKey("name")) + requiredPaths.Add((string)data["name"]); + //else + // requiredPaths.Add(attachment.Key); + } + } + } + + return 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); + binary.ReadSkeletonData(input); + binary = null; + } + + internal 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; + 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 + + 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 && IsSpineData(jsonAsset)) + skeletonPaths.Add(str); + break; + case ".bytes": + if (str.ToLower().EndsWith(".skel.bytes", System.StringComparison.Ordinal)) { + if (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 skeletonPath in skeletonPaths) { + if (!reimport && CheckForValidSkeletonData(skeletonPath)) { + ReloadSkeletonData(skeletonPath); + continue; + } + + 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(skeletonPath); + var atlasMatch = GetMatchingAtlas(requiredPaths, localAtlases); + if (atlasMatch != null || requiredPaths.Count == 0) { + IngestSpineProject(AssetDatabase.LoadAssetAtPath(skeletonPath, typeof(TextAsset)) as TextAsset, atlasMatch); + } else { + SkeletonImportDialog(skeletonPath, localAtlases, requiredPaths, ref abortSkeletonImport); + } + + 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) + SkeletonBaker.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 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 + AtlasSuffix + ".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 (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)); + 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(SpineEditorUtilities.Preferences.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.AssetUtility.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) + 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"; + + #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 = SpineEditorUtilities.Preferences.defaultMix; + skeletonDataAsset.scale = SpineEditorUtilities.Preferences.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 + + #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)); @@ -1348,157 +911,572 @@ namespace Spine.Unity.Editor { 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; + 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(string.Format("\t {0}", 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 Atlas...", "Import anyway", "Cancel import" + ); + + switch (result) { + case 0: // Browse... + AtlasAssetBase selectedAtlasAsset = BrowseAtlasDialog(lastAtlasPath); + if (selectedAtlasAsset != null) { + 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); + } + } + break; + case 1: // Import anyway + resolved = true; + break; + case 2: // Cancel + atlasAssets = null; + resolved = true; + break; + } + } + + return atlasAssets; + } + + public static AtlasAssetBase BrowseAtlasDialog (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("\\", "/"); + + 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; + } + #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; + } } - #endregion + public static class EditorInstantiation { + public delegate Component InstantiateDelegate (SkeletonDataAsset skeletonDataAsset); - #region SkeletonAnimation Menu - public static void IngestAdvancedRenderSettings (SkeletonRenderer skeletonRenderer) { - const string PMAShaderQuery = "Spine/Skeleton"; - const string TintBlackShaderQuery = "Tint Black"; + public class SkeletonComponentSpawnType { + public string menuLabel; + public InstantiateDelegate instantiateDelegate; + public bool isUI; + } - if (skeletonRenderer == null) return; - var skeletonDataAsset = skeletonRenderer.skeletonDataAsset; - if (skeletonDataAsset == null) return; + internal static readonly List additionalSpawnTypes = new List(); - bool pmaVertexColors = false; - bool tintBlack = false; - foreach (var atlasAsset in skeletonDataAsset.atlasAssets) { - if (!pmaVertexColors) { - foreach (Material m in atlasAsset.Materials) { - if (m.shader.name.Contains(PMAShaderQuery)) { - pmaVertexColors = true; - break; + 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"; @@ -1561,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); 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/AttachmentTools/AttachmentTools.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/AttachmentTools/AttachmentTools.cs index 7d0b2d0e1..601f06685 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/AttachmentTools/AttachmentTools.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/AttachmentTools/AttachmentTools.cs @@ -211,6 +211,8 @@ namespace Spine.Unity.Modules.AttachmentTools { internal const bool UseMipMaps = false; internal const float DefaultScale = 0.01f; + const int NonrenderingRegion = -1; + public static AtlasRegion ToAtlasRegion (this Texture2D t, Material materialPropertySource, float scale = DefaultScale) { return t.ToAtlasRegion(materialPropertySource.shader, scale, materialPropertySource); } @@ -395,7 +397,7 @@ namespace Spine.Unity.Modules.AttachmentTools { /// The List(Attachment) to populate with the newly created Attachment objects. /// /// May be null. If no Material property source is provided, no special - public static void GetRepackedAttachments (List sourceAttachments, List outputAttachments, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, string newAssetName = "Repacked Attachments", bool clearCache = false) { + public static void GetRepackedAttachments (List sourceAttachments, List outputAttachments, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, string newAssetName = "Repacked Attachments", bool clearCache = false, bool useOriginalNonrenderables = true) { if (sourceAttachments == null) throw new System.ArgumentNullException("sourceAttachments"); if (outputAttachments == null) throw new System.ArgumentNullException("outputAttachments"); @@ -411,9 +413,9 @@ namespace Spine.Unity.Modules.AttachmentTools { int newRegionIndex = 0; for (int i = 0, n = sourceAttachments.Count; i < n; i++) { var originalAttachment = sourceAttachments[i]; - var newAttachment = originalAttachment.GetClone(true); - if (IsRenderable(newAttachment)) { - + + if (IsRenderable(originalAttachment)) { + var newAttachment = originalAttachment.GetClone(true); var region = newAttachment.GetRegion(); int existingIndex; if (existingRegions.TryGetValue(region, out existingIndex)) { @@ -427,6 +429,9 @@ namespace Spine.Unity.Modules.AttachmentTools { } outputAttachments[i] = newAttachment; + } else { + outputAttachments[i] = useOriginalNonrenderables ? originalAttachment : originalAttachment.GetClone(true); + regionIndexes.Add(NonrenderingRegion); // Output attachments pairs with regionIndexes list 1:1. Pad with a sentinel if the attachment doesn't have a region. } } @@ -460,7 +465,8 @@ namespace Spine.Unity.Modules.AttachmentTools { // Map the cloned attachments to the repacked atlas. for (int i = 0, n = outputAttachments.Count; i < n; i++) { var a = outputAttachments[i]; - a.SetRegion(repackedRegions[regionIndexes[i]]); + if (IsRenderable(a)) + a.SetRegion(repackedRegions[regionIndexes[i]]); } // Clean up. @@ -474,14 +480,14 @@ namespace Spine.Unity.Modules.AttachmentTools { /// /// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas comprised of all the regions from the original skin. /// No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them. - public static Skin GetRepackedSkin (this Skin o, string newName, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps) { - return GetRepackedSkin(o, newName, materialPropertySource.shader, out outputMaterial, out outputTexture, maxAtlasSize, padding, textureFormat, mipmaps, materialPropertySource); + public static Skin GetRepackedSkin (this Skin o, string newName, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, bool useOriginalNonrenderables = true) { + return GetRepackedSkin(o, newName, materialPropertySource.shader, out outputMaterial, out outputTexture, maxAtlasSize, padding, textureFormat, mipmaps, materialPropertySource, useOriginalNonrenderables); } /// /// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas comprised of all the regions from the original skin. /// No Spine.Atlas object is created so there is no way to find AtlasRegions except through the Attachments using them. - public static Skin GetRepackedSkin (this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, Material materialPropertySource = null, bool clearCache = false) { + public static Skin GetRepackedSkin (this Skin o, string newName, Shader shader, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, Material materialPropertySource = null, bool clearCache = false, bool useOriginalNonrenderables = true) { if (o == null) throw new System.NullReferenceException("Skin was null"); var skinAttachments = o.Attachments; var newSkin = new Skin(newName); @@ -495,10 +501,13 @@ namespace Spine.Unity.Modules.AttachmentTools { var texturesToPack = new List(); var originalRegions = new List(); int newRegionIndex = 0; - foreach (var kvp in skinAttachments) { - var newAttachment = kvp.Value.GetClone(true); - if (IsRenderable(newAttachment)) { + foreach (var skinEntry in skinAttachments) { + var originalKey = skinEntry.Key; + var originalAttachment = skinEntry.Value; + Attachment newAttachment; + if (IsRenderable(originalAttachment)) { + newAttachment = originalAttachment.GetClone(true); var region = newAttachment.GetRegion(); int existingIndex; if (existingRegions.TryGetValue(region, out existingIndex)) { @@ -512,9 +521,10 @@ namespace Spine.Unity.Modules.AttachmentTools { } repackedAttachments.Add(newAttachment); - } - var key = kvp.Key; - newSkin.AddAttachment(key.slotIndex, key.name, newAttachment); + newSkin.AddAttachment(originalKey.slotIndex, originalKey.name, newAttachment); + } else { + newSkin.AddAttachment(originalKey.slotIndex, originalKey.name, useOriginalNonrenderables ? originalAttachment : originalAttachment.GetClone(true)); + } } // Fill a new texture with the collected attachment textures. @@ -546,7 +556,8 @@ namespace Spine.Unity.Modules.AttachmentTools { // Map the cloned attachments to the repacked atlas. for (int i = 0, n = repackedAttachments.Count; i < n; i++) { var a = repackedAttachments[i]; - a.SetRegion(repackedRegions[regionIndexes[i]]); + if (IsRenderable(a)) + a.SetRegion(repackedRegions[regionIndexes[i]]); } // Clean up. 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/Shaders/Spine-Skeleton-Fill.shader b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/Shaders/Spine-Skeleton-Fill.shader index 161b03b59..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 @@ -1,4 +1,4 @@ -// - Unlit + no shadow +// - Unlit // - Premultiplied Alpha Blending (Optional straight alpha input) // - Double-sided, no depth @@ -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 { @@ -59,6 +60,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 +} 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/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; } } 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; 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: