diff --git a/.gitignore b/.gitignore index 9706c2ee9..77a302a74 100644 --- a/.gitignore +++ b/.gitignore @@ -1,16 +1,26 @@ -spine-c/Debug/* -spine-cpp/Debug/* -spine-sfml/Debug/* -spine-sfml/SFML -spine-libgdx/bin/* -spine-libgdx/libs/* -target +target *Debug.win32 *.sdf *.opensdf *.suo *.ipch +*.userprefs +*.pidb +*.cachefile +*.swp +*.user +.DS_Store + +spine-c/Debug/* + +spine-cpp/Debug/* + +spine-sfml/Debug/* +spine-sfml/SFML + +spine-libgdx/bin/* +spine-libgdx/libs/* spine-cocos2dx/2/cocos2dx/ !spine-cocos2dx/2/cocos2dx/Place cocos2dx here.txt @@ -21,8 +31,6 @@ spine-cocos2dx/3.0/example/proj.win32/Debug spine-cocos2dx/3.1/cocos2dx/ !spine-cocos2dx/3.1/cocos2dx/Place cocos2dx here.txt spine-cocos2dx/3.1/example/proj.win32/Debug -*.swp -.DS_Store xcuserdata spine-cocos2d-iphone/libs/* @@ -30,8 +38,6 @@ spine-cocos2d-iphone/libs/* !spine-cocos2d-iphone/libs/CocosDenshion/Place CocosDenshion here.txt !spine-cocos2d-iphone/libs/kazmath/Place kazmath here.txt -*.user -forums spine-csharp/bin spine-csharp/obj @@ -50,22 +56,18 @@ spine-xna/obj spine-xna/example/bin spine-xna/example/obj -spine-unity/Assets/Spine/spine-csharp -spine-unity/Assets/Spine/spine-csharp.meta -!spine-unity/Assets/Spine/spine-csharp/Place spine-csharp here.txt +spine-unity/Assets/spine-csharp* +!spine-unity/Assets/spine-csharp/Place spine-csharp src here.* spine-unity/ProjectSettings spine-unity/Temp spine-unity/Library spine-unity/*.sln -*.userprefs -*.pidb -*.cachefile Assembly-*.csproj Assembly-*.pidb AssetStoreTools* -spine-tk2d/Assets/Spine/spine-csharp -!spine-tk2d/Assets/Spine/spine-csharp/Place spine-csharp here.txt +spine-tk2d/Assets/Spine/spine-csharp* +!spine-tk2d/Assets/Spine/spine-csharp/Place spine-csharp src here.* spine-tk2d/ProjectSettings spine-tk2d/Temp spine-tk2d/Library diff --git a/spine-tk2d/Assets/Spine/spine-csharp.meta b/spine-tk2d/Assets/spine-csharp.meta similarity index 63% rename from spine-tk2d/Assets/Spine/spine-csharp.meta rename to spine-tk2d/Assets/spine-csharp.meta index ef59cc982..6b09776f5 100644 --- a/spine-tk2d/Assets/Spine/spine-csharp.meta +++ b/spine-tk2d/Assets/spine-csharp.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: afc6035066a4eb4478f706aa211ca644 +guid: fd5a58479265f7248ae0e2c97c958b7e folderAsset: yes DefaultImporter: userData: diff --git a/spine-tk2d/Assets/spine-csharp/Animation.cs b/spine-tk2d/Assets/spine-csharp/Animation.cs new file mode 100644 index 000000000..19d892ca5 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Animation.cs @@ -0,0 +1,607 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using System.Collections.Generic; + +namespace Spine { + public class Animation { + internal List timelines; + internal float duration; + internal String name; + + public String Name { get { return name; } } + public List Timelines { get { return timelines; } set { timelines = value; } } + public float Duration { get { return duration; } set { duration = value; } } + + public Animation (String name, List timelines, float duration) { + if (name == null) throw new ArgumentNullException("name cannot be null."); + if (timelines == null) throw new ArgumentNullException("timelines cannot be null."); + this.name = name; + this.timelines = timelines; + this.duration = duration; + } + + /// Poses the skeleton at the specified time for this animation. + /// The last time the animation was applied. + /// Any triggered events are added. + public void Apply (Skeleton skeleton, float lastTime, float time, bool loop, List events) { + if (skeleton == null) throw new ArgumentNullException("skeleton cannot be null."); + + if (loop && duration != 0) { + time %= duration; + lastTime %= duration; + } + + List timelines = this.timelines; + for (int i = 0, n = timelines.Count; i < n; i++) + timelines[i].Apply(skeleton, lastTime, time, events, 1); + } + + /// Poses the skeleton at the specified time for this animation mixed with the current pose. + /// The last time the animation was applied. + /// Any triggered events are added. + /// The amount of this animation that affects the current pose. + public void Mix (Skeleton skeleton, float lastTime, float time, bool loop, List events, float alpha) { + if (skeleton == null) throw new ArgumentNullException("skeleton cannot be null."); + + if (loop && duration != 0) { + time %= duration; + lastTime %= duration; + } + + List timelines = this.timelines; + for (int i = 0, n = timelines.Count; i < n; i++) + timelines[i].Apply(skeleton, lastTime, time, events, alpha); + } + + /// After the first and before the last entry. + internal static int binarySearch (float[] values, float target, int step) { + int low = 0; + int high = values.Length / step - 2; + if (high == 0) return step; + int current = (int)((uint)high >> 1); + while (true) { + if (values[(current + 1) * step] <= target) + low = current + 1; + else + high = current; + if (low == high) return (low + 1) * step; + current = (int)((uint)(low + high) >> 1); + } + } + + internal static int linearSearch (float[] values, float target, int step) { + for (int i = 0, last = values.Length - step; i <= last; i += step) + if (values[i] > target) return i; + return -1; + } + } + + public interface Timeline { + /// Sets the value(s) for the specified time. + void Apply (Skeleton skeleton, float lastTime, float time, List firedEvents, float alpha); + } + + /// Base class for frames that use an interpolation bezier curve. + abstract public class CurveTimeline : Timeline { + static protected float LINEAR = 0; + static protected float STEPPED = -1; + static protected int BEZIER_SEGMENTS = 10; + + private float[] curves; // dfx, dfy, ddfx, ddfy, dddfx, dddfy, ... + public int FrameCount { get { return curves.Length / 6 + 1; } } + + public CurveTimeline (int frameCount) { + curves = new float[(frameCount - 1) * 6]; + } + + abstract public void Apply (Skeleton skeleton, float lastTime, float time, List firedEvents, float alpha); + + public void SetLinear (int frameIndex) { + curves[frameIndex * 6] = LINEAR; + } + + public void SetStepped (int frameIndex) { + curves[frameIndex * 6] = STEPPED; + } + + /// Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. + /// cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of + /// the difference between the keyframe's values. + public void SetCurve (int frameIndex, float cx1, float cy1, float cx2, float cy2) { + float subdiv_step = 1f / BEZIER_SEGMENTS; + float subdiv_step2 = subdiv_step * subdiv_step; + float subdiv_step3 = subdiv_step2 * subdiv_step; + float pre1 = 3 * subdiv_step; + float pre2 = 3 * subdiv_step2; + float pre4 = 6 * subdiv_step2; + float pre5 = 6 * subdiv_step3; + float tmp1x = -cx1 * 2 + cx2; + float tmp1y = -cy1 * 2 + cy2; + float tmp2x = (cx1 - cx2) * 3 + 1; + float tmp2y = (cy1 - cy2) * 3 + 1; + int i = frameIndex * 6; + float[] curves = this.curves; + curves[i] = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv_step3; + curves[i + 1] = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv_step3; + curves[i + 2] = tmp1x * pre4 + tmp2x * pre5; + curves[i + 3] = tmp1y * pre4 + tmp2y * pre5; + curves[i + 4] = tmp2x * pre5; + curves[i + 5] = tmp2y * pre5; + } + + public float GetCurvePercent (int frameIndex, float percent) { + int curveIndex = frameIndex * 6; + float[] curves = this.curves; + float dfx = curves[curveIndex]; + if (dfx == LINEAR) return percent; + if (dfx == STEPPED) return 0; + float dfy = curves[curveIndex + 1]; + float ddfx = curves[curveIndex + 2]; + float ddfy = curves[curveIndex + 3]; + float dddfx = curves[curveIndex + 4]; + float dddfy = curves[curveIndex + 5]; + float x = dfx, y = dfy; + int i = BEZIER_SEGMENTS - 2; + while (true) { + if (x >= percent) { + float lastX = x - dfx; + float lastY = y - dfy; + return lastY + (y - lastY) * (percent - lastX) / (x - lastX); + } + if (i == 0) break; + i--; + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + x += dfx; + y += dfy; + } + return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1. + } + } + + public class RotateTimeline : CurveTimeline { + static protected int LAST_FRAME_TIME = -2; + static protected int FRAME_VALUE = 1; + + internal int boneIndex; + internal float[] frames; + + public int BoneIndex { get { return boneIndex; } set { boneIndex = value; } } + public float[] Frames { get { return frames; } set { frames = value; } } // time, value, ... + + public RotateTimeline (int frameCount) + : base(frameCount) { + frames = new float[frameCount * 2]; + } + + /// Sets the time and value of the specified keyframe. + public void SetFrame (int frameIndex, float time, float angle) { + frameIndex *= 2; + frames[frameIndex] = time; + frames[frameIndex + 1] = angle; + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, List firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + Bone bone = skeleton.bones[boneIndex]; + + float amount; + + if (time >= frames[frames.Length - 2]) { // Time is after last frame. + amount = bone.data.rotation + frames[frames.Length - 1] - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + return; + } + + // Interpolate between the last frame and the current frame. + int frameIndex = Animation.binarySearch(frames, time, 2); + float lastFrameValue = frames[frameIndex - 1]; + float frameTime = frames[frameIndex]; + float percent = 1 - (time - frameTime) / (frames[frameIndex + LAST_FRAME_TIME] - frameTime); + percent = GetCurvePercent(frameIndex / 2 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); + + amount = frames[frameIndex + FRAME_VALUE] - lastFrameValue; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + amount = bone.data.rotation + (lastFrameValue + amount * percent) - bone.rotation; + while (amount > 180) + amount -= 360; + while (amount < -180) + amount += 360; + bone.rotation += amount * alpha; + } + } + + public class TranslateTimeline : CurveTimeline { + static protected int LAST_FRAME_TIME = -3; + static protected int FRAME_X = 1; + static protected int FRAME_Y = 2; + + internal int boneIndex; + internal float[] frames; + + public int BoneIndex { get { return boneIndex; } set { boneIndex = value; } } + public float[] Frames { get { return frames; } set { frames = value; } } // time, value, value, ... + + public TranslateTimeline (int frameCount) + : base(frameCount) { + frames = new float[frameCount * 3]; + } + + /// Sets the time and value of the specified keyframe. + public void SetFrame (int frameIndex, float time, float x, float y) { + frameIndex *= 3; + frames[frameIndex] = time; + frames[frameIndex + 1] = x; + frames[frameIndex + 2] = y; + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, List firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + Bone bone = skeleton.bones[boneIndex]; + + if (time >= frames[frames.Length - 3]) { // Time is after last frame. + bone.x += (bone.data.x + frames[frames.Length - 2] - bone.x) * alpha; + bone.y += (bone.data.y + frames[frames.Length - 1] - bone.y) * alpha; + return; + } + + // Interpolate between the last frame and the current frame. + int frameIndex = Animation.binarySearch(frames, time, 3); + float lastFrameX = frames[frameIndex - 2]; + float lastFrameY = frames[frameIndex - 1]; + float frameTime = frames[frameIndex]; + float percent = 1 - (time - frameTime) / (frames[frameIndex + LAST_FRAME_TIME] - frameTime); + percent = GetCurvePercent(frameIndex / 3 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); + + bone.x += (bone.data.x + lastFrameX + (frames[frameIndex + FRAME_X] - lastFrameX) * percent - bone.x) * alpha; + bone.y += (bone.data.y + lastFrameY + (frames[frameIndex + FRAME_Y] - lastFrameY) * percent - bone.y) * alpha; + } + } + + public class ScaleTimeline : TranslateTimeline { + public ScaleTimeline (int frameCount) + : base(frameCount) { + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, List firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + Bone bone = skeleton.bones[boneIndex]; + if (time >= frames[frames.Length - 3]) { // Time is after last frame. + bone.scaleX += (bone.data.scaleX - 1 + frames[frames.Length - 2] - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY - 1 + frames[frames.Length - 1] - bone.scaleY) * alpha; + return; + } + + // Interpolate between the last frame and the current frame. + int frameIndex = Animation.binarySearch(frames, time, 3); + float lastFrameX = frames[frameIndex - 2]; + float lastFrameY = frames[frameIndex - 1]; + float frameTime = frames[frameIndex]; + float percent = 1 - (time - frameTime) / (frames[frameIndex + LAST_FRAME_TIME] - frameTime); + percent = GetCurvePercent(frameIndex / 3 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); + + bone.scaleX += (bone.data.scaleX - 1 + lastFrameX + (frames[frameIndex + FRAME_X] - lastFrameX) * percent - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY - 1 + lastFrameY + (frames[frameIndex + FRAME_Y] - lastFrameY) * percent - bone.scaleY) * alpha; + } + } + + public class ColorTimeline : CurveTimeline { + static protected int LAST_FRAME_TIME = -5; + static protected int FRAME_R = 1; + static protected int FRAME_G = 2; + static protected int FRAME_B = 3; + static protected int FRAME_A = 4; + + internal int slotIndex; + internal float[] frames; + + public int SlotIndex { get { return slotIndex; } set { slotIndex = value; } } + public float[] Frames { get { return frames; } set { frames = value; } } // time, r, g, b, a, ... + + public ColorTimeline (int frameCount) + : base(frameCount) { + frames = new float[frameCount * 5]; + } + + /// Sets the time and value of the specified keyframe. + public void setFrame (int frameIndex, float time, float r, float g, float b, float a) { + frameIndex *= 5; + frames[frameIndex] = time; + frames[frameIndex + 1] = r; + frames[frameIndex + 2] = g; + frames[frameIndex + 3] = b; + frames[frameIndex + 4] = a; + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, List firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + Slot slot = skeleton.slots[slotIndex]; + + float r, g, b, a; + if (time >= frames[frames.Length - 5]) { + // Time is after last frame. + int i = frames.Length - 1; + r = frames[i - 3]; + g = frames[i - 2]; + b = frames[i - 1]; + a = frames[i]; + } else { + // Interpolate between the last frame and the current frame. + int frameIndex = Animation.binarySearch(frames, time, 5); + float lastFrameR = frames[frameIndex - 4]; + float lastFrameG = frames[frameIndex - 3]; + float lastFrameB = frames[frameIndex - 2]; + float lastFrameA = frames[frameIndex - 1]; + float frameTime = frames[frameIndex]; + float percent = 1 - (time - frameTime) / (frames[frameIndex + LAST_FRAME_TIME] - frameTime); + percent = GetCurvePercent(frameIndex / 5 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); + + r = lastFrameR + (frames[frameIndex + FRAME_R] - lastFrameR) * percent; + g = lastFrameG + (frames[frameIndex + FRAME_G] - lastFrameG) * percent; + b = lastFrameB + (frames[frameIndex + FRAME_B] - lastFrameB) * percent; + a = lastFrameA + (frames[frameIndex + FRAME_A] - lastFrameA) * percent; + } + if (alpha < 1) { + slot.r += (r - slot.r) * alpha; + slot.g += (g - slot.g) * alpha; + slot.b += (b - slot.b) * alpha; + slot.a += (a - slot.a) * alpha; + } else { + slot.r = r; + slot.g = g; + slot.b = b; + slot.a = a; + } + } + } + + public class AttachmentTimeline : Timeline { + internal int slotIndex; + internal float[] frames; + private String[] attachmentNames; + + public int SlotIndex { get { return slotIndex; } set { slotIndex = value; } } + public float[] Frames { get { return frames; } set { frames = value; } } // time, ... + public String[] AttachmentNames { get { return attachmentNames; } set { attachmentNames = value; } } + public int FrameCount { get { return frames.Length; } } + + public AttachmentTimeline (int frameCount) { + frames = new float[frameCount]; + attachmentNames = new String[frameCount]; + } + + /// Sets the time and value of the specified keyframe. + public void setFrame (int frameIndex, float time, String attachmentName) { + frames[frameIndex] = time; + attachmentNames[frameIndex] = attachmentName; + } + + public void Apply (Skeleton skeleton, float lastTime, float time, List firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + int frameIndex; + if (time >= frames[frames.Length - 1]) // Time is after last frame. + frameIndex = frames.Length - 1; + else + frameIndex = Animation.binarySearch(frames, time, 1) - 1; + + String attachmentName = attachmentNames[frameIndex]; + skeleton.slots[slotIndex].Attachment = + attachmentName == null ? null : skeleton.GetAttachment(slotIndex, attachmentName); + } + } + + public class EventTimeline : Timeline { + internal float[] frames; + private Event[] events; + + public float[] Frames { get { return frames; } set { frames = value; } } // time, ... + public Event[] Events { get { return events; } set { events = value; } } + public int FrameCount { get { return frames.Length; } } + + public EventTimeline (int frameCount) { + frames = new float[frameCount]; + events = new Event[frameCount]; + } + + /// Sets the time and value of the specified keyframe. + public void setFrame (int frameIndex, float time, Event e) { + frames[frameIndex] = time; + events[frameIndex] = e; + } + + /// Fires events for frames > lastTime and <= time. + public void Apply (Skeleton skeleton, float lastTime, float time, List firedEvents, float alpha) { + if (firedEvents == null) return; + float[] frames = this.frames; + int frameCount = frames.Length; + + if (lastTime > time) { // Fire events after last time for looped animations. + Apply(skeleton, lastTime, int.MaxValue, firedEvents, alpha); + lastTime = -1f; + } else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame. + return; + if (time < frames[0]) return; // Time is before first frame. + + int frameIndex; + if (lastTime < frames[0]) + frameIndex = 0; + else { + frameIndex = Animation.binarySearch(frames, lastTime, 1); + float frame = frames[frameIndex]; + while (frameIndex > 0) { // Fire multiple events with the same frame. + if (frames[frameIndex - 1] != frame) break; + frameIndex--; + } + } + for (; frameIndex < frameCount && time >= frames[frameIndex]; frameIndex++) + firedEvents.Add(events[frameIndex]); + } + } + + public class DrawOrderTimeline : Timeline { + internal float[] frames; + private int[][] drawOrders; + + public float[] Frames { get { return frames; } set { frames = value; } } // time, ... + public int[][] DrawOrders { get { return drawOrders; } set { drawOrders = value; } } + public int FrameCount { get { return frames.Length; } } + + public DrawOrderTimeline (int frameCount) { + frames = new float[frameCount]; + drawOrders = new int[frameCount][]; + } + + /// Sets the time and value of the specified keyframe. + /// May be null to use bind pose draw order. + public void setFrame (int frameIndex, float time, int[] drawOrder) { + frames[frameIndex] = time; + drawOrders[frameIndex] = drawOrder; + } + + public void Apply (Skeleton skeleton, float lastTime, float time, List firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + int frameIndex; + if (time >= frames[frames.Length - 1]) // Time is after last frame. + frameIndex = frames.Length - 1; + else + frameIndex = Animation.binarySearch(frames, time, 1) - 1; + + List drawOrder = skeleton.drawOrder; + List slots = skeleton.slots; + int[] drawOrderToSetupIndex = drawOrders[frameIndex]; + if (drawOrderToSetupIndex == null) { + drawOrder.Clear(); + drawOrder.AddRange(slots); + } else { + for (int i = 0, n = drawOrderToSetupIndex.Length; i < n; i++) + drawOrder[i] = slots[drawOrderToSetupIndex[i]]; + } + } + } + + public class FFDTimeline : CurveTimeline { + internal int slotIndex; + internal float[] frames; + private float[][] frameVertices; + internal Attachment attachment; + + public int SlotIndex { get { return slotIndex; } set { slotIndex = value; } } + public float[] Frames { get { return frames; } set { frames = value; } } // time, ... + public float[][] Vertices { get { return frameVertices; } set { frameVertices = value; } } + public Attachment Attachment { get { return attachment; } set { attachment = value; } } + + public FFDTimeline (int frameCount) + : base(frameCount) { + frames = new float[frameCount]; + frameVertices = new float[frameCount][]; + } + + /// Sets the time and value of the specified keyframe. + public void setFrame (int frameIndex, float time, float[] vertices) { + frames[frameIndex] = time; + frameVertices[frameIndex] = vertices; + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, List firedEvents, float alpha) { + Slot slot = skeleton.slots[slotIndex]; + if (slot.attachment != attachment) return; + + float[] frames = this.frames; + if (time < frames[0]) { + slot.attachmentVerticesCount = 0; + return; // Time is before first frame. + } + + float[][] frameVertices = this.frameVertices; + int vertexCount = frameVertices[0].Length; + + float[] vertices = slot.attachmentVertices; + if (vertices.Length < vertexCount) { + vertices = new float[vertexCount]; + slot.attachmentVertices = vertices; + } + slot.attachmentVerticesCount = vertexCount; + + if (time >= frames[frames.Length - 1]) { // Time is after last frame. + float[] lastVertices = frameVertices[frames.Length - 1]; + if (alpha < 1) { + for (int i = 0; i < vertexCount; i++) + vertices[i] += (lastVertices[i] - vertices[i]) * alpha; + } else + Array.Copy(lastVertices, 0, vertices, 0, vertexCount); + return; + } + + // Interpolate between the previous frame and the current frame. + int frameIndex = Animation.binarySearch(frames, time, 1); + float frameTime = frames[frameIndex]; + float percent = 1 - (time - frameTime) / (frames[frameIndex - 1] - frameTime); + percent = GetCurvePercent(frameIndex - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); + + float[] prevVertices = frameVertices[frameIndex - 1]; + float[] nextVertices = frameVertices[frameIndex]; + + if (alpha < 1) { + for (int i = 0; i < vertexCount; i++) { + float prev = prevVertices[i]; + vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha; + } + } else { + for (int i = 0; i < vertexCount; i++) { + float prev = prevVertices[i]; + vertices[i] = prev + (nextVertices[i] - prev) * percent; + } + } + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/Animation.cs.meta b/spine-tk2d/Assets/spine-csharp/Animation.cs.meta new file mode 100644 index 000000000..a9b3555d5 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Animation.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ec9879cdddeea4a458e534aad1c97aef +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/AnimationState.cs b/spine-tk2d/Assets/spine-csharp/AnimationState.cs new file mode 100644 index 000000000..91711afc3 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/AnimationState.cs @@ -0,0 +1,297 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Text; + +namespace Spine { + public class AnimationState { + private AnimationStateData data; + private List tracks = new List(); + private List events = new List(); + private float timeScale = 1; + + public AnimationStateData Data { get { return data; } } + public float TimeScale { get { return timeScale; } set { timeScale = value; } } + + public delegate void StartEndDelegate(AnimationState state, int trackIndex); + public event StartEndDelegate Start; + public event StartEndDelegate End; + + public delegate void EventDelegate(AnimationState state, int trackIndex, Event e); + public event EventDelegate Event; + + public delegate void CompleteDelegate(AnimationState state, int trackIndex, int loopCount); + public event CompleteDelegate Complete; + + public AnimationState (AnimationStateData data) { + if (data == null) throw new ArgumentNullException("data cannot be null."); + this.data = data; + } + + public void Update (float delta) { + delta *= timeScale; + for (int i = 0; i < tracks.Count; i++) { + TrackEntry current = tracks[i]; + if (current == null) continue; + + float trackDelta = delta * current.timeScale; + float time = current.time + trackDelta; + float endTime = current.endTime; + + current.time = time; + if (current.previous != null) { + current.previous.time += trackDelta; + current.mixTime += trackDelta; + } + + // Check if completed the animation or a loop iteration. + if (current.loop ? (current.lastTime % endTime > time % endTime) : (current.lastTime < endTime && time >= endTime)) { + int count = (int)(time / endTime); + current.OnComplete(this, i, count); + if (Complete != null) Complete(this, i, count); + } + + TrackEntry next = current.next; + if (next != null) { + next.time = current.lastTime - next.delay; + if (next.time >= 0) SetCurrent(i, next); + } else { + // End non-looping animation when it reaches its end time and there is no next entry. + if (!current.loop && current.lastTime >= current.endTime) ClearTrack(i); + } + } + } + + public void Apply (Skeleton skeleton) { + List events = this.events; + + for (int i = 0; i < tracks.Count; i++) { + TrackEntry current = tracks[i]; + if (current == null) continue; + + events.Clear(); + + float time = current.time; + bool loop = current.loop; + if (!loop && time > current.endTime) time = current.endTime; + + TrackEntry previous = current.previous; + if (previous == null) { + if (current.mix == 1) + current.animation.Apply(skeleton, current.lastTime, time, loop, events); + else + current.animation.Mix(skeleton, current.lastTime, time, loop, events, current.mix); + } else { + float previousTime = previous.time; + if (!previous.loop && previousTime > previous.endTime) previousTime = previous.endTime; + previous.animation.Apply(skeleton, previousTime, previousTime, previous.loop, null); + + float alpha = current.mixTime / current.mixDuration * current.mix; + if (alpha >= 1) { + alpha = 1; + current.previous = null; + } + current.animation.Mix(skeleton, current.lastTime, time, loop, events, alpha); + } + + for (int ii = 0, nn = events.Count; ii < nn; ii++) { + Event e = events[ii]; + current.OnEvent(this, i, e); + if (Event != null) Event(this, i, e); + } + + current.lastTime = current.time; + } + } + + public void ClearTracks () { + for (int i = 0, n = tracks.Count; i < n; i++) + ClearTrack(i); + tracks.Clear(); + } + + public void ClearTrack (int trackIndex) { + if (trackIndex >= tracks.Count) return; + TrackEntry current = tracks[trackIndex]; + if (current == null) return; + + current.OnEnd(this, trackIndex); + if (End != null) End(this, trackIndex); + + tracks[trackIndex] = null; + } + + private TrackEntry ExpandToIndex (int index) { + if (index < tracks.Count) return tracks[index]; + while (index >= tracks.Count) + tracks.Add(null); + return null; + } + + private void SetCurrent (int index, TrackEntry entry) { + TrackEntry current = ExpandToIndex(index); + if (current != null) { + TrackEntry previous = current.previous; + current.previous = null; + + current.OnEnd(this, index); + if (End != null) End(this, index); + + entry.mixDuration = data.GetMix(current.animation, entry.animation); + if (entry.mixDuration > 0) { + entry.mixTime = 0; + // If a mix is in progress, mix from the closest animation. + if (previous != null && current.mixTime / current.mixDuration < 0.5f) + entry.previous = previous; + else + entry.previous = current; + } + } + + tracks[index] = entry; + + entry.OnStart(this, index); + if (Start != null) Start(this, index); + } + + public TrackEntry SetAnimation (int trackIndex, String animationName, bool loop) { + Animation animation = data.skeletonData.FindAnimation(animationName); + if (animation == null) throw new ArgumentException("Animation not found: " + animationName); + return SetAnimation(trackIndex, animation, loop); + } + + /// Set the current animation. Any queued animations are cleared. + public TrackEntry SetAnimation (int trackIndex, Animation animation, bool loop) { + TrackEntry entry = new TrackEntry(); + entry.animation = animation; + entry.loop = loop; + entry.time = 0; + entry.endTime = animation.Duration; + SetCurrent(trackIndex, entry); + return entry; + } + + public TrackEntry AddAnimation (int trackIndex, String animationName, bool loop, float delay) { + Animation animation = data.skeletonData.FindAnimation(animationName); + if (animation == null) throw new ArgumentException("Animation not found: " + animationName); + return AddAnimation(trackIndex, animation, loop, delay); + } + + /// Adds an animation to be played delay seconds after the current or last queued animation. + /// May be <= 0 to use duration of previous animation minus any mix duration plus the negative delay. + public TrackEntry AddAnimation (int trackIndex, Animation animation, bool loop, float delay) { + TrackEntry entry = new TrackEntry(); + entry.animation = animation; + entry.loop = loop; + entry.time = 0; + entry.endTime = animation.Duration; + + TrackEntry last = ExpandToIndex(trackIndex); + if (last != null) { + while (last.next != null) + last = last.next; + last.next = entry; + } else + tracks[trackIndex] = entry; + + if (delay <= 0) { + if (last != null) + delay += last.endTime - data.GetMix(last.animation, animation); + else + delay = 0; + } + entry.delay = delay; + + return entry; + } + + /// May be null. + public TrackEntry GetCurrent (int trackIndex) { + if (trackIndex >= tracks.Count) return null; + return tracks[trackIndex]; + } + + override public String ToString () { + StringBuilder buffer = new StringBuilder(); + for (int i = 0, n = tracks.Count; i < n; i++) { + TrackEntry entry = tracks[i]; + if (entry == null) continue; + if (buffer.Length > 0) buffer.Append(", "); + buffer.Append(entry.ToString()); + } + if (buffer.Length == 0) return ""; + return buffer.ToString(); + } + } + + public class TrackEntry { + internal TrackEntry next, previous; + internal Animation animation; + internal bool loop; + internal float delay, time, lastTime = -1, endTime, timeScale = 1; + internal float mixTime, mixDuration, mix = 1; + + public Animation Animation { get { return animation; } } + public float Delay { get { return delay; } set { delay = value; } } + public float Time { get { return time; } set { time = value; } } + public float LastTime { get { return lastTime; } set { lastTime = value; } } + public float EndTime { get { return endTime; } set { endTime = value; } } + public float TimeScale { get { return timeScale; } set { timeScale = value; } } + public float Mix { get { return mix; } set { mix = value; } } + public bool Loop { get { return loop; } set { loop = value; } } + + public event AnimationState.StartEndDelegate Start; + public event AnimationState.StartEndDelegate End; + public event AnimationState.EventDelegate Event; + public event AnimationState.CompleteDelegate Complete; + + internal void OnStart (AnimationState state, int index) { + if (Start != null) Start(state, index); + } + + internal void OnEnd (AnimationState state, int index) { + if (End != null) End(state, index); + } + + internal void OnEvent (AnimationState state, int index, Event e) { + if (Event != null) Event(state, index, e); + } + + internal void OnComplete (AnimationState state, int index, int loopCount) { + if (Complete != null) Complete(state, index, loopCount); + } + + override public String ToString () { + return animation == null ? "" : animation.name; + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/AnimationState.cs.meta b/spine-tk2d/Assets/spine-csharp/AnimationState.cs.meta new file mode 100644 index 000000000..0b7112deb --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/AnimationState.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: ee7e4f6e66f00dc46b287376544a4321 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/AnimationStateData.cs b/spine-tk2d/Assets/spine-csharp/AnimationStateData.cs new file mode 100644 index 000000000..f2fa86630 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/AnimationStateData.cs @@ -0,0 +1,70 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using System.Collections.Generic; + +namespace Spine { + public class AnimationStateData { + internal SkeletonData skeletonData; + private Dictionary, float> animationToMixTime = new Dictionary, float>(); + internal float defaultMix; + + public SkeletonData SkeletonData { get { return skeletonData; } } + public float DefaultMix { get { return defaultMix; } set { defaultMix = value; } } + + public AnimationStateData (SkeletonData skeletonData) { + this.skeletonData = skeletonData; + } + + public void SetMix (String fromName, String toName, float duration) { + Animation from = skeletonData.FindAnimation(fromName); + if (from == null) throw new ArgumentException("Animation not found: " + fromName); + Animation to = skeletonData.FindAnimation(toName); + if (to == null) throw new ArgumentException("Animation not found: " + toName); + SetMix(from, to, duration); + } + + public void SetMix (Animation from, Animation to, float duration) { + if (from == null) throw new ArgumentNullException("from cannot be null."); + if (to == null) throw new ArgumentNullException("to cannot be null."); + KeyValuePair key = new KeyValuePair(from, to); + animationToMixTime.Remove(key); + animationToMixTime.Add(key, duration); + } + + public float GetMix (Animation from, Animation to) { + KeyValuePair key = new KeyValuePair(from, to); + float duration; + if (animationToMixTime.TryGetValue(key, out duration)) return duration; + return defaultMix; + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/AnimationStateData.cs.meta b/spine-tk2d/Assets/spine-csharp/AnimationStateData.cs.meta new file mode 100644 index 000000000..05ee6f929 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/AnimationStateData.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9e47e500598d679418fa687193b876ff +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/Atlas.cs b/spine-tk2d/Assets/spine-csharp/Atlas.cs new file mode 100644 index 000000000..3242b9d04 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Atlas.cs @@ -0,0 +1,288 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using System.Collections.Generic; +using System.IO; +using System.Reflection; + +#if WINDOWS_STOREAPP +using System.Threading.Tasks; +using Windows.Storage; +#endif + +namespace Spine { + public class Atlas { + List pages = new List(); + List regions = new List(); + TextureLoader textureLoader; + +#if WINDOWS_STOREAPP + private async Task ReadFile(string path, TextureLoader textureLoader) { + var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; + var file = await folder.GetFileAsync(path).AsTask().ConfigureAwait(false); + using (var reader = new StreamReader(await file.OpenStreamForReadAsync().ConfigureAwait(false))) { + try { + Load(reader, Path.GetDirectoryName(path), textureLoader); + } catch (Exception ex) { + throw new Exception("Error reading atlas file: " + path, ex); + } + } + } + + public Atlas(String path, TextureLoader textureLoader) { + this.ReadFile(path, textureLoader).Wait(); + } +#else + public Atlas (String path, TextureLoader textureLoader) { + +#if WINDOWS_PHONE + Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path); + using (StreamReader reader = new StreamReader(stream)) + { +#else + using (StreamReader reader = new StreamReader(path)) { +#endif + try { + Load(reader, Path.GetDirectoryName(path), textureLoader); + } catch (Exception ex) { + throw new Exception("Error reading atlas file: " + path, ex); + } + } + } +#endif + + public Atlas (TextReader reader, String dir, TextureLoader textureLoader) { + Load(reader, dir, textureLoader); + } + + public Atlas (List pages, List regions) { + this.pages = pages; + this.regions = regions; + this.textureLoader = null; + } + + private void Load (TextReader reader, String imagesDir, TextureLoader textureLoader) { + if (textureLoader == null) throw new ArgumentNullException("textureLoader cannot be null."); + this.textureLoader = textureLoader; + + String[] tuple = new String[4]; + AtlasPage page = null; + while (true) { + String line = reader.ReadLine(); + if (line == null) break; + if (line.Trim().Length == 0) + page = null; + else if (page == null) { + page = new AtlasPage(); + page.name = line; + + if (readTuple(reader, tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker. + page.width = int.Parse(tuple[0]); + page.height = int.Parse(tuple[1]); + readTuple(reader, tuple); + } + page.format = (Format)Enum.Parse(typeof(Format), tuple[0], false); + + readTuple(reader, tuple); + page.minFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[0], false); + page.magFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[1], false); + + String direction = readValue(reader); + page.uWrap = TextureWrap.ClampToEdge; + page.vWrap = TextureWrap.ClampToEdge; + if (direction == "x") + page.uWrap = TextureWrap.Repeat; + else if (direction == "y") + page.vWrap = TextureWrap.Repeat; + else if (direction == "xy") + page.uWrap = page.vWrap = TextureWrap.Repeat; + + textureLoader.Load(page, Path.Combine(imagesDir, line)); + + pages.Add(page); + + } else { + AtlasRegion region = new AtlasRegion(); + region.name = line; + region.page = page; + + region.rotate = Boolean.Parse(readValue(reader)); + + readTuple(reader, tuple); + int x = int.Parse(tuple[0]); + int y = int.Parse(tuple[1]); + + readTuple(reader, tuple); + int width = int.Parse(tuple[0]); + int height = int.Parse(tuple[1]); + + region.u = x / (float)page.width; + region.v = y / (float)page.height; + if (region.rotate) { + region.u2 = (x + height) / (float)page.width; + region.v2 = (y + width) / (float)page.height; + } else { + region.u2 = (x + width) / (float)page.width; + region.v2 = (y + height) / (float)page.height; + } + region.x = x; + region.y = y; + region.width = Math.Abs(width); + region.height = Math.Abs(height); + + if (readTuple(reader, tuple) == 4) { // split is optional + region.splits = new int[] {int.Parse(tuple[0]), int.Parse(tuple[1]), + int.Parse(tuple[2]), int.Parse(tuple[3])}; + + if (readTuple(reader, tuple) == 4) { // pad is optional, but only present with splits + region.pads = new int[] {int.Parse(tuple[0]), int.Parse(tuple[1]), + int.Parse(tuple[2]), int.Parse(tuple[3])}; + + readTuple(reader, tuple); + } + } + + region.originalWidth = int.Parse(tuple[0]); + region.originalHeight = int.Parse(tuple[1]); + + readTuple(reader, tuple); + region.offsetX = int.Parse(tuple[0]); + region.offsetY = int.Parse(tuple[1]); + + region.index = int.Parse(readValue(reader)); + + regions.Add(region); + } + } + } + + static String readValue (TextReader reader) { + String line = reader.ReadLine(); + int colon = line.IndexOf(':'); + if (colon == -1) throw new Exception("Invalid line: " + line); + return line.Substring(colon + 1).Trim(); + } + + /// Returns the number of tuple values read (1, 2 or 4). + static int readTuple (TextReader reader, String[] tuple) { + String line = reader.ReadLine(); + int colon = line.IndexOf(':'); + if (colon == -1) throw new Exception("Invalid line: " + line); + int i = 0, lastMatch = colon + 1; + for (; i < 3; i++) { + int comma = line.IndexOf(',', lastMatch); + if (comma == -1) break; + tuple[i] = line.Substring(lastMatch, comma - lastMatch).Trim(); + lastMatch = comma + 1; + } + tuple[i] = line.Substring(lastMatch).Trim(); + return i + 1; + } + + public void FlipV () { + for (int i = 0, n = regions.Count; i < n; i++) { + AtlasRegion region = regions[i]; + region.v = 1 - region.v; + region.v2 = 1 - region.v2; + } + } + + /// Returns the first region found with the specified name. This method uses string comparison to find the region, so the result + /// should be cached rather than calling this method multiple times. + /// The region, or null. + public AtlasRegion FindRegion (String name) { + for (int i = 0, n = regions.Count; i < n; i++) + if (regions[i].name == name) return regions[i]; + return null; + } + + public void Dispose () { + if (textureLoader == null) return; + for (int i = 0, n = pages.Count; i < n; i++) + textureLoader.Unload(pages[i].rendererObject); + } + } + + public enum Format { + Alpha, + Intensity, + LuminanceAlpha, + RGB565, + RGBA4444, + RGB888, + RGBA8888 + } + + public enum TextureFilter { + Nearest, + Linear, + MipMap, + MipMapNearestNearest, + MipMapLinearNearest, + MipMapNearestLinear, + MipMapLinearLinear + } + + public enum TextureWrap { + MirroredRepeat, + ClampToEdge, + Repeat + } + + public class AtlasPage { + public String name; + public Format format; + public TextureFilter minFilter; + public TextureFilter magFilter; + public TextureWrap uWrap; + public TextureWrap vWrap; + public Object rendererObject; + public int width, height; + } + + public class AtlasRegion { + public AtlasPage page; + public String name; + public int x, y, width, height; + public float u, v, u2, v2; + public float offsetX, offsetY; + public int originalWidth, originalHeight; + public int index; + public bool rotate; + public int[] splits; + public int[] pads; + } + + public interface TextureLoader { + void Load (AtlasPage page, String path); + void Unload (Object texture); + } +} diff --git a/spine-tk2d/Assets/spine-csharp/Atlas.cs.meta b/spine-tk2d/Assets/spine-csharp/Atlas.cs.meta new file mode 100644 index 000000000..ae62b4f35 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Atlas.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 4c4b7be3b4d96e3428f47ad190a53166 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/Spine.meta b/spine-tk2d/Assets/spine-csharp/Attachments.meta similarity index 63% rename from spine-tk2d/Assets/Spine.meta rename to spine-tk2d/Assets/spine-csharp/Attachments.meta index 661958cff..0967bf553 100644 --- a/spine-tk2d/Assets/Spine.meta +++ b/spine-tk2d/Assets/spine-csharp/Attachments.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 1fdd5b9e3e0974d40b1b149ec5a15662 +guid: 8767a0c4c9e00124c9dc9393d2e3ee2f folderAsset: yes DefaultImporter: userData: diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/AtlasAttachmentLoader.cs b/spine-tk2d/Assets/spine-csharp/Attachments/AtlasAttachmentLoader.cs new file mode 100644 index 000000000..37fdbb9fd --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/AtlasAttachmentLoader.cs @@ -0,0 +1,99 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; + +namespace Spine { + public class AtlasAttachmentLoader : AttachmentLoader { + private Atlas atlas; + + public AtlasAttachmentLoader (Atlas atlas) { + if (atlas == null) throw new ArgumentNullException("atlas cannot be null."); + this.atlas = atlas; + } + + public RegionAttachment NewRegionAttachment (Skin skin, String name, String path) { + AtlasRegion region = atlas.FindRegion(path); + if (region == null) throw new Exception("Region not found in atlas: " + path + " (region attachment: " + name + ")"); + RegionAttachment attachment = new RegionAttachment(name); + attachment.RendererObject = region; + attachment.SetUVs(region.u, region.v, region.u2, region.v2, region.rotate); + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + return attachment; + } + + public MeshAttachment NewMeshAttachment (Skin skin, String name, String path) { + AtlasRegion region = atlas.FindRegion(path); + if (region == null) throw new Exception("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); + MeshAttachment attachment = new MeshAttachment(name); + attachment.RendererObject = region; + attachment.RegionU = region.u; + attachment.RegionV = region.v; + attachment.RegionU2 = region.u2; + attachment.RegionV2 = region.v2; + attachment.RegionRotate = region.rotate; + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + return attachment; + } + + public SkinnedMeshAttachment NewSkinnedMeshAttachment (Skin skin, String name, String path) { + AtlasRegion region = atlas.FindRegion(path); + if (region == null) throw new Exception("Region not found in atlas: " + path + " (skinned mesh attachment: " + name + ")"); + SkinnedMeshAttachment attachment = new SkinnedMeshAttachment(name); + attachment.RendererObject = region; + attachment.RegionU = region.u; + attachment.RegionV = region.v; + attachment.RegionU2 = region.u2; + attachment.RegionV2 = region.v2; + attachment.RegionRotate = region.rotate; + attachment.regionOffsetX = region.offsetX; + attachment.regionOffsetY = region.offsetY; + attachment.regionWidth = region.width; + attachment.regionHeight = region.height; + attachment.regionOriginalWidth = region.originalWidth; + attachment.regionOriginalHeight = region.originalHeight; + return attachment; + } + + public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name) { + return new BoundingBoxAttachment(name); + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/AtlasAttachmentLoader.cs.meta b/spine-tk2d/Assets/spine-csharp/Attachments/AtlasAttachmentLoader.cs.meta new file mode 100644 index 000000000..e25cabdf5 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/AtlasAttachmentLoader.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6252babf561d6d849b41131b206ad656 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/Attachment.cs b/spine-tk2d/Assets/spine-csharp/Attachments/Attachment.cs new file mode 100644 index 000000000..f54bf4976 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/Attachment.cs @@ -0,0 +1,46 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; + +namespace Spine { + abstract public class Attachment { + public String Name { get; private set; } + + public Attachment (String name) { + if (name == null) throw new ArgumentNullException("name cannot be null."); + Name = name; + } + + override public String ToString () { + return Name; + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/Attachment.cs.meta b/spine-tk2d/Assets/spine-csharp/Attachments/Attachment.cs.meta new file mode 100644 index 000000000..0088c702d --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/Attachment.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f010b1c38c4bb4c44ae56ae6511c6ca4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/AttachmentLoader.cs b/spine-tk2d/Assets/spine-csharp/Attachments/AttachmentLoader.cs new file mode 100644 index 000000000..8630f4b54 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/AttachmentLoader.cs @@ -0,0 +1,47 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; + +namespace Spine { + public interface AttachmentLoader { + /// May be null to not load any attachment. + RegionAttachment NewRegionAttachment (Skin skin, String name, String path); + + /// May be null to not load any attachment. + MeshAttachment NewMeshAttachment (Skin skin, String name, String path); + + /// May be null to not load any attachment. + SkinnedMeshAttachment NewSkinnedMeshAttachment (Skin skin, String name, String path); + + /// May be null to not load any attachment. + BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name); + } +} diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/AttachmentLoader.cs.meta b/spine-tk2d/Assets/spine-csharp/Attachments/AttachmentLoader.cs.meta new file mode 100644 index 000000000..703331650 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/AttachmentLoader.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f673addf75a62d347808c6d58014358a +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/AttachmentType.cs b/spine-tk2d/Assets/spine-csharp/Attachments/AttachmentType.cs new file mode 100644 index 000000000..3ae01ae58 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/AttachmentType.cs @@ -0,0 +1,35 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +namespace Spine { + public enum AttachmentType { + region, boundingbox, mesh, skinnedmesh + } +} diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/AttachmentType.cs.meta b/spine-tk2d/Assets/spine-csharp/Attachments/AttachmentType.cs.meta new file mode 100644 index 000000000..001a7159e --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/AttachmentType.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b545bbd6837590d4c86aff0dad223ddc +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/BoundingBoxAttachment.cs b/spine-tk2d/Assets/spine-csharp/Attachments/BoundingBoxAttachment.cs new file mode 100644 index 000000000..838dbeb55 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/BoundingBoxAttachment.cs @@ -0,0 +1,61 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; + +namespace Spine { + /// Attachment that has a polygon for bounds checking. + public class BoundingBoxAttachment : Attachment { + internal float[] vertices; + + public float[] Vertices { get { return vertices; } set { vertices = value; } } + + public BoundingBoxAttachment (string name) + : base(name) { + } + + /// Must have at least the same length as this attachment's vertices. + public void ComputeWorldVertices (float x, float y, Bone bone, float[] worldVertices) { + x += bone.worldX; + y += bone.worldY; + float m00 = bone.m00; + float m01 = bone.m01; + float m10 = bone.m10; + float m11 = bone.m11; + float[] vertices = this.vertices; + for (int i = 0, n = vertices.Length; i < n; i += 2) { + float px = vertices[i]; + float py = vertices[i + 1]; + worldVertices[i] = px * m00 + py * m01 + x; + worldVertices[i + 1] = px * m10 + py * m11 + y; + } + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/BoundingBoxAttachment.cs.meta b/spine-tk2d/Assets/spine-csharp/Attachments/BoundingBoxAttachment.cs.meta new file mode 100644 index 000000000..dd046b31e --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/BoundingBoxAttachment.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e18e23c38b80c2d42b12a5962b96827c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/MeshAttachment.cs b/spine-tk2d/Assets/spine-csharp/Attachments/MeshAttachment.cs new file mode 100644 index 000000000..033afab1b --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/MeshAttachment.cs @@ -0,0 +1,109 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; + +namespace Spine { + /// Attachment that displays a texture region. + public class MeshAttachment : Attachment { + internal float[] vertices, uvs, regionUVs; + internal int[] triangles; + internal float regionOffsetX, regionOffsetY, regionWidth, regionHeight, regionOriginalWidth, regionOriginalHeight; + internal float r = 1, g = 1, b = 1, a = 1; + + public int HullLength { get; set; } + public float[] Vertices { get { return vertices; } set { vertices = value; } } + public float[] RegionUVs { get { return regionUVs; } set { regionUVs = value; } } + public float[] UVs { get { return uvs; } set { uvs = value; } } + public int[] Triangles { get { return triangles; } set { triangles = value; } } + + public float R { get { return r; } set { r = value; } } + public float G { get { return g; } set { g = value; } } + public float B { get { return b; } set { b = value; } } + public float A { get { return a; } set { a = value; } } + + public String Path { get; set; } + public Object RendererObject { get; set; } + public float RegionU { get; set; } + public float RegionV { get; set; } + public float RegionU2 { get; set; } + public float RegionV2 { get; set; } + public bool RegionRotate { get; set; } + public float RegionOffsetX { get { return regionOffsetX; } set { regionOffsetX = value; } } + public float RegionOffsetY { get { return regionOffsetY; } set { regionOffsetY = value; } } // Pixels stripped from the bottom left, unrotated. + public float RegionWidth { get { return regionWidth; } set { regionWidth = value; } } + public float RegionHeight { get { return regionHeight; } set { regionHeight = value; } } // Unrotated, stripped size. + public float RegionOriginalWidth { get { return regionOriginalWidth; } set { regionOriginalWidth = value; } } + public float RegionOriginalHeight { get { return regionOriginalHeight; } set { regionOriginalHeight = value; } } // Unrotated, unstripped size. + + // Nonessential. + public int[] Edges { get; set; } + public float Width { get; set; } + public float Height { get; set; } + + public MeshAttachment (string name) + : base(name) { + } + + public void UpdateUVs () { + float u = RegionU, v = RegionV, width = RegionU2 - RegionU, height = RegionV2 - RegionV; + float[] regionUVs = this.regionUVs; + if (this.uvs == null || this.uvs.Length != regionUVs.Length) this.uvs = new float[regionUVs.Length]; + float[] uvs = this.uvs; + if (RegionRotate) { + for (int i = 0, n = uvs.Length; i < n; i += 2) { + uvs[i] = u + regionUVs[i + 1] * width; + uvs[i + 1] = v + height - regionUVs[i] * height; + } + } else { + for (int i = 0, n = uvs.Length; i < n; i += 2) { + uvs[i] = u + regionUVs[i] * width; + uvs[i + 1] = v + regionUVs[i + 1] * height; + } + } + } + + public void ComputeWorldVertices (float x, float y, Slot slot, float[] worldVertices) { + Bone bone = slot.bone; + x += bone.worldX; + y += bone.worldY; + float m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11; + float[] vertices = this.vertices; + int verticesCount = vertices.Length; + if (slot.attachmentVerticesCount == verticesCount) vertices = slot.AttachmentVertices; + for (int i = 0; i < verticesCount; i += 2) { + float vx = vertices[i]; + float vy = vertices[i + 1]; + worldVertices[i] = vx * m00 + vy * m01 + x; + worldVertices[i + 1] = vx * m10 + vy * m11 + y; + } + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/MeshAttachment.cs.meta b/spine-tk2d/Assets/spine-csharp/Attachments/MeshAttachment.cs.meta new file mode 100644 index 000000000..e7b43258b --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/MeshAttachment.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3b7d667dfd7029341b3c8b2fe76244d8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/RegionAttachment.cs b/spine-tk2d/Assets/spine-csharp/Attachments/RegionAttachment.cs new file mode 100644 index 000000000..511cb4103 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/RegionAttachment.cs @@ -0,0 +1,152 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; + +namespace Spine { + /// Attachment that displays a texture region. + public class RegionAttachment : Attachment { + public const int X1 = 0; + public const int Y1 = 1; + public const int X2 = 2; + public const int Y2 = 3; + public const int X3 = 4; + public const int Y3 = 5; + public const int X4 = 6; + public const int Y4 = 7; + + internal float x, y, rotation, scaleX = 1, scaleY = 1, width, height; + internal float regionOffsetX, regionOffsetY, regionWidth, regionHeight, regionOriginalWidth, regionOriginalHeight; + internal float[] offset = new float[8], uvs = new float[8]; + internal float r = 1, g = 1, b = 1, a = 1; + + public float X { get { return x; } set { x = value; } } + public float Y { get { return y; } set { y = value; } } + public float Rotation { get { return rotation; } set { rotation = value; } } + public float ScaleX { get { return scaleX; } set { scaleX = value; } } + public float ScaleY { get { return scaleY; } set { scaleY = value; } } + public float Width { get { return width; } set { width = value; } } + public float Height { get { return height; } set { height = value; } } + + public float R { get { return r; } set { r = value; } } + public float G { get { return g; } set { g = value; } } + public float B { get { return b; } set { b = value; } } + public float A { get { return a; } set { a = value; } } + + public String Path { get; set; } + public Object RendererObject { get; set; } + public float RegionOffsetX { get { return regionOffsetX; } set { regionOffsetX = value; } } + public float RegionOffsetY { get { return regionOffsetY; } set { regionOffsetY = value; } } // Pixels stripped from the bottom left, unrotated. + public float RegionWidth { get { return regionWidth; } set { regionWidth = value; } } + public float RegionHeight { get { return regionHeight; } set { regionHeight = value; } } // Unrotated, stripped size. + public float RegionOriginalWidth { get { return regionOriginalWidth; } set { regionOriginalWidth = value; } } + public float RegionOriginalHeight { get { return regionOriginalHeight; } set { regionOriginalHeight = value; } } // Unrotated, unstripped size. + + public float[] Offset { get { return offset; } } + public float[] UVs { get { return uvs; } } + + public RegionAttachment (string name) + : base(name) { + } + + public void SetUVs (float u, float v, float u2, float v2, bool rotate) { + float[] uvs = this.uvs; + if (rotate) { + uvs[X2] = u; + uvs[Y2] = v2; + uvs[X3] = u; + uvs[Y3] = v; + uvs[X4] = u2; + uvs[Y4] = v; + uvs[X1] = u2; + uvs[Y1] = v2; + } else { + uvs[X1] = u; + uvs[Y1] = v2; + uvs[X2] = u; + uvs[Y2] = v; + uvs[X3] = u2; + uvs[Y3] = v; + uvs[X4] = u2; + uvs[Y4] = v2; + } + } + + public void UpdateOffset () { + float width = this.width; + float height = this.height; + float scaleX = this.scaleX; + float scaleY = this.scaleY; + float regionScaleX = width / regionOriginalWidth * scaleX; + float regionScaleY = height / regionOriginalHeight * scaleY; + float localX = -width / 2 * scaleX + regionOffsetX * regionScaleX; + float localY = -height / 2 * scaleY + regionOffsetY * regionScaleY; + float localX2 = localX + regionWidth * regionScaleX; + float localY2 = localY + regionHeight * regionScaleY; + float radians = rotation * (float)Math.PI / 180; + float cos = (float)Math.Cos(radians); + float sin = (float)Math.Sin(radians); + float x = this.x; + float y = this.y; + float localXCos = localX * cos + x; + float localXSin = localX * sin; + float localYCos = localY * cos + y; + float localYSin = localY * sin; + float localX2Cos = localX2 * cos + x; + float localX2Sin = localX2 * sin; + float localY2Cos = localY2 * cos + y; + float localY2Sin = localY2 * sin; + float[] offset = this.offset; + offset[X1] = localXCos - localYSin; + offset[Y1] = localYCos + localXSin; + offset[X2] = localXCos - localY2Sin; + offset[Y2] = localY2Cos + localXSin; + offset[X3] = localX2Cos - localY2Sin; + offset[Y3] = localY2Cos + localX2Sin; + offset[X4] = localX2Cos - localYSin; + offset[Y4] = localYCos + localX2Sin; + } + + public void ComputeWorldVertices (float x, float y, Bone bone, float[] worldVertices) { + x += bone.worldX; + y += bone.worldY; + float m00 = bone.m00, m01 = bone.m01, m10 = bone.m10, m11 = bone.m11; + float[] offset = this.offset; + worldVertices[X1] = offset[X1] * m00 + offset[Y1] * m01 + x; + worldVertices[Y1] = offset[X1] * m10 + offset[Y1] * m11 + y; + worldVertices[X2] = offset[X2] * m00 + offset[Y2] * m01 + x; + worldVertices[Y2] = offset[X2] * m10 + offset[Y2] * m11 + y; + worldVertices[X3] = offset[X3] * m00 + offset[Y3] * m01 + x; + worldVertices[Y3] = offset[X3] * m10 + offset[Y3] * m11 + y; + worldVertices[X4] = offset[X4] * m00 + offset[Y4] * m01 + x; + worldVertices[Y4] = offset[X4] * m10 + offset[Y4] * m11 + y; + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/RegionAttachment.cs.meta b/spine-tk2d/Assets/spine-csharp/Attachments/RegionAttachment.cs.meta new file mode 100644 index 000000000..ef97bba21 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/RegionAttachment.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b740c1a2a0c9a644b872b7188988f9f9 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/SkinnedMeshAttachment.cs b/spine-tk2d/Assets/spine-csharp/Attachments/SkinnedMeshAttachment.cs new file mode 100644 index 000000000..ebd662827 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/SkinnedMeshAttachment.cs @@ -0,0 +1,130 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using System.Collections.Generic; + +namespace Spine { + /// Attachment that displays a texture region. + public class SkinnedMeshAttachment : Attachment { + internal int[] bones; + internal float[] weights, uvs, regionUVs; + internal int[] triangles; + internal float regionOffsetX, regionOffsetY, regionWidth, regionHeight, regionOriginalWidth, regionOriginalHeight; + internal float r = 1, g = 1, b = 1, a = 1; + + public int HullLength { get; set; } + public int[] Bones { get { return bones; } set { bones = value; } } + public float[] Weights { get { return weights; } set { weights = value; } } + public float[] RegionUVs { get { return regionUVs; } set { regionUVs = value; } } + public float[] UVs { get { return uvs; } set { uvs = value; } } + public int[] Triangles { get { return triangles; } set { triangles = value; } } + + public float R { get { return r; } set { r = value; } } + public float G { get { return g; } set { g = value; } } + public float B { get { return b; } set { b = value; } } + public float A { get { return a; } set { a = value; } } + + public String Path { get; set; } + public Object RendererObject { get; set; } + public float RegionU { get; set; } + public float RegionV { get; set; } + public float RegionU2 { get; set; } + public float RegionV2 { get; set; } + public bool RegionRotate { get; set; } + public float RegionOffsetX { get { return regionOffsetX; } set { regionOffsetX = value; } } + public float RegionOffsetY { get { return regionOffsetY; } set { regionOffsetY = value; } } // Pixels stripped from the bottom left, unrotated. + public float RegionWidth { get { return regionWidth; } set { regionWidth = value; } } + public float RegionHeight { get { return regionHeight; } set { regionHeight = value; } } // Unrotated, stripped size. + public float RegionOriginalWidth { get { return regionOriginalWidth; } set { regionOriginalWidth = value; } } + public float RegionOriginalHeight { get { return regionOriginalHeight; } set { regionOriginalHeight = value; } } // Unrotated, unstripped size. + + // Nonessential. + public int[] Edges { get; set; } + public float Width { get; set; } + public float Height { get; set; } + + public SkinnedMeshAttachment (string name) + : base(name) { + } + + public void UpdateUVs () { + float u = RegionU, v = RegionV, width = RegionU2 - RegionU, height = RegionV2 - RegionV; + float[] regionUVs = this.regionUVs; + if (this.uvs == null || this.uvs.Length != regionUVs.Length) this.uvs = new float[regionUVs.Length]; + float[] uvs = this.uvs; + if (RegionRotate) { + for (int i = 0, n = uvs.Length; i < n; i += 2) { + uvs[i] = u + regionUVs[i + 1] * width; + uvs[i + 1] = v + height - regionUVs[i] * height; + } + } else { + for (int i = 0, n = uvs.Length; i < n; i += 2) { + uvs[i] = u + regionUVs[i] * width; + uvs[i + 1] = v + regionUVs[i + 1] * height; + } + } + } + + public void ComputeWorldVertices (float x, float y, Slot slot, float[] worldVertices) { + List skeletonBones = slot.skeleton.bones; + float[] weights = this.weights; + int[] bones = this.bones; + if (slot.attachmentVerticesCount == 0) { + for (int w = 0, v = 0, b = 0, n = bones.Length; v < n; w += 2) { + float wx = 0, wy = 0; + int nn = bones[v++] + v; + for (; v < nn; v++, b += 3) { + Bone bone = (Bone)skeletonBones[bones[v]]; + float vx = weights[b], vy = weights[b + 1], weight = weights[b + 2]; + wx += (vx * bone.M00 + vy * bone.M01 + bone.worldX) * weight; + wy += (vx * bone.M10 + vy * bone.M11 + bone.worldY) * weight; + } + worldVertices[w] = wx + x; + worldVertices[w + 1] = wy + y; + } + } else { + float[] ffd = slot.AttachmentVertices; + for (int w = 0, v = 0, b = 0, f = 0, n = bones.Length; v < n; w += 2) { + float wx = 0, wy = 0; + int nn = bones[v++] + v; + for (; v < nn; v++, b += 3, f += 2) { + Bone bone = (Bone)skeletonBones[bones[v]]; + float vx = weights[b] + ffd[f], vy = weights[b + 1] + ffd[f + 1], weight = weights[b + 2]; + wx += (vx * bone.M00 + vy * bone.M01 + bone.worldX) * weight; + wy += (vx * bone.M10 + vy * bone.M11 + bone.worldY) * weight; + } + worldVertices[w] = wx + x; + worldVertices[w + 1] = wy + y; + } + } + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/Attachments/SkinnedMeshAttachment.cs.meta b/spine-tk2d/Assets/spine-csharp/Attachments/SkinnedMeshAttachment.cs.meta new file mode 100644 index 000000000..88872ea08 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Attachments/SkinnedMeshAttachment.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: a129c2350d647e64a9175e61db44c741 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/Bone.cs b/spine-tk2d/Assets/spine-csharp/Bone.cs new file mode 100644 index 000000000..7a9fb556a --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Bone.cs @@ -0,0 +1,120 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; + +namespace Spine { + public class Bone { + static public bool yDown; + + internal BoneData data; + internal Bone parent; + internal float x, y, rotation, scaleX, scaleY; + internal float m00, m01, m10, m11; + internal float worldX, worldY, worldRotation, worldScaleX, worldScaleY; + + public BoneData Data { get { return data; } } + public Bone Parent { get { return parent; } } + public float X { get { return x; } set { x = value; } } + public float Y { get { return y; } set { y = value; } } + public float Rotation { get { return rotation; } set { rotation = value; } } + public float ScaleX { get { return scaleX; } set { scaleX = value; } } + public float ScaleY { get { return scaleY; } set { scaleY = value; } } + + public float M00 { get { return m00; } } + public float M01 { get { return m01; } } + public float M10 { get { return m10; } } + public float M11 { get { return m11; } } + public float WorldX { get { return worldX; } } + public float WorldY { get { return worldY; } } + public float WorldRotation { get { return worldRotation; } } + public float WorldScaleX { get { return worldScaleX; } } + public float WorldScaleY { get { return worldScaleY; } } + + /// May be null. + public Bone (BoneData data, Bone parent) { + if (data == null) throw new ArgumentNullException("data cannot be null."); + this.data = data; + this.parent = parent; + SetToSetupPose(); + } + + /// Computes the world SRT using the parent bone and the local SRT. + public void UpdateWorldTransform (bool flipX, bool flipY) { + Bone parent = this.parent; + if (parent != null) { + worldX = x * parent.m00 + y * parent.m01 + parent.worldX; + worldY = x * parent.m10 + y * parent.m11 + parent.worldY; + if (data.inheritScale) { + worldScaleX = parent.worldScaleX * scaleX; + worldScaleY = parent.worldScaleY * scaleY; + } else { + worldScaleX = scaleX; + worldScaleY = scaleY; + } + worldRotation = data.inheritRotation ? parent.worldRotation + rotation : rotation; + } else { + worldX = flipX ? -x : x; + worldY = flipY != yDown ? -y : y; + worldScaleX = scaleX; + worldScaleY = scaleY; + worldRotation = rotation; + } + float radians = worldRotation * (float)Math.PI / 180; + float cos = (float)Math.Cos(radians); + float sin = (float)Math.Sin(radians); + m00 = cos * worldScaleX; + m10 = sin * worldScaleX; + m01 = -sin * worldScaleY; + m11 = cos * worldScaleY; + if (flipX) { + m00 = -m00; + m01 = -m01; + } + if (flipY != yDown) { + m10 = -m10; + m11 = -m11; + } + } + + public void SetToSetupPose () { + BoneData data = this.data; + x = data.x; + y = data.y; + rotation = data.rotation; + scaleX = data.scaleX; + scaleY = data.scaleY; + } + + override public String ToString () { + return data.name; + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/Bone.cs.meta b/spine-tk2d/Assets/spine-csharp/Bone.cs.meta new file mode 100644 index 000000000..b1c2ba2de --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Bone.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e5d58f928336539469e2127ed8ef0589 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/BoneData.cs b/spine-tk2d/Assets/spine-csharp/BoneData.cs new file mode 100644 index 000000000..5d19b266e --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/BoneData.cs @@ -0,0 +1,63 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; + +namespace Spine { + public class BoneData { + internal BoneData parent; + internal String name; + internal float length, x, y, rotation, scaleX = 1, scaleY = 1; + internal bool inheritScale = true, inheritRotation = true; + + /// May be null. + public BoneData Parent { get { return parent; } } + public String Name { get { return name; } } + public float Length { get { return length; } set { length = value; } } + public float X { get { return x; } set { x = value; } } + public float Y { get { return y; } set { y = value; } } + public float Rotation { get { return rotation; } set { rotation = value; } } + public float ScaleX { get { return scaleX; } set { scaleX = value; } } + public float ScaleY { get { return scaleY; } set { scaleY = value; } } + public bool InheritScale { get { return inheritScale; } set { inheritScale = value; } } + public bool InheritRotation { get { return inheritRotation; } set { inheritRotation = value; } } + + /// May be null. + public BoneData (String name, BoneData parent) { + if (name == null) throw new ArgumentNullException("name cannot be null."); + this.name = name; + this.parent = parent; + } + + override public String ToString () { + return name; + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/BoneData.cs.meta b/spine-tk2d/Assets/spine-csharp/BoneData.cs.meta new file mode 100644 index 000000000..49deb00d6 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/BoneData.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7598e79bf893b604e83072b903a2ea6f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/Event.cs b/spine-tk2d/Assets/spine-csharp/Event.cs new file mode 100644 index 000000000..36514e7c0 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Event.cs @@ -0,0 +1,48 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; + +namespace Spine { + public class Event { + public EventData Data { get; private set; } + public int Int { get; set; } + public float Float { get; set; } + public String String { get; set; } + + public Event (EventData data) { + Data = data; + } + + override public String ToString () { + return Data.Name; + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/Event.cs.meta b/spine-tk2d/Assets/spine-csharp/Event.cs.meta new file mode 100644 index 000000000..20ef24ca8 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Event.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bb7f87705d8bbd9448a04a798638cd04 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/EventData.cs b/spine-tk2d/Assets/spine-csharp/EventData.cs new file mode 100644 index 000000000..832d3de83 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/EventData.cs @@ -0,0 +1,49 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; + +namespace Spine { + public class EventData { + public String Name { get; private set; } + public int Int { get; set; } + public float Float { get; set; } + public String String { get; set; } + + public EventData (String name) { + if (name == null) throw new ArgumentNullException("name cannot be null."); + Name = name; + } + + override public String ToString () { + return Name; + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/EventData.cs.meta b/spine-tk2d/Assets/spine-csharp/EventData.cs.meta new file mode 100644 index 000000000..a494bdb5f --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/EventData.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: e97f9d2627906294d8a17bd9551c810c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/Json.cs b/spine-tk2d/Assets/spine-csharp/Json.cs new file mode 100644 index 000000000..376dd7ef7 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Json.cs @@ -0,0 +1,542 @@ +/* + * Copyright (c) 2012 Calvin Rien + * + * Based on the JSON parser by Patrick van Bergen + * http://techblog.procurios.nl/k/618/news/view/14605/14863/How-do-I-write-my-own-parser-for-JSON.html + * + * Simplified it so that it doesn't throw exceptions + * and can be used in Unity iPhone with maximum code stripping. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +using System; +using System.Collections; +using System.Collections.Generic; +using System.IO; +using System.Text; +using System.Globalization; + +namespace Spine +{ + // Example usage: + // + // using UnityEngine; + // using System.Collections; + // using System.Collections.Generic; + // using MiniJSON; + // + // public class MiniJSONTest : MonoBehaviour { + // void Start () { + // var jsonString = "{ \"array\": [1.44,2,3], " + + // "\"object\": {\"key1\":\"value1\", \"key2\":256}, " + + // "\"string\": \"The quick brown fox \\\"jumps\\\" over the lazy dog \", " + + // "\"unicode\": \"\\u3041 Men\u00fa sesi\u00f3n\", " + + // "\"int\": 65536, " + + // "\"float\": 3.1415926, " + + // "\"bool\": true, " + + // "\"null\": null }"; + // + // var dict = Json.Deserialize(jsonString) as Dictionary; + // + // Debug.Log("deserialized: " + dict.GetType()); + // Debug.Log("dict['array'][0]: " + ((List) dict["array"])[0]); + // Debug.Log("dict['string']: " + (string) dict["string"]); + // Debug.Log("dict['float']: " + (float) dict["float"]); + // Debug.Log("dict['int']: " + (long) dict["int"]); // ints come out as longs + // Debug.Log("dict['unicode']: " + (string) dict["unicode"]); + // + // var str = Json.Serialize(dict); + // + // Debug.Log("serialized: " + str); + // } + // } + + /// + /// This class encodes and decodes JSON strings. + /// Spec. details, see http://www.json.org/ + /// + /// JSON uses Arrays and Objects. These correspond here to the datatypes IList and IDictionary. + /// All numbers are parsed to floats. + /// + public static class Json { + /// + /// Parses the string json into a value + /// + /// A JSON string. + /// An List<object>, a Dictionary<string, object>, a float, an integer,a string, null, true, or false + public static object Deserialize (TextReader json) { + if (json == null) { + return null; + } + return Parser.Parse(json); + } + + sealed class Parser : IDisposable { + const string WHITE_SPACE = " \t\n\r"; + const string WORD_BREAK = " \t\n\r{}[],:\""; + + enum TOKEN { + NONE, + CURLY_OPEN, + CURLY_CLOSE, + SQUARED_OPEN, + SQUARED_CLOSE, + COLON, + COMMA, + STRING, + NUMBER, + TRUE, + FALSE, + NULL + }; + + TextReader json; + + Parser(TextReader reader) { + json = reader; + } + + public static object Parse (TextReader reader) { + using (var instance = new Parser(reader)) { + return instance.ParseValue(); + } + } + + public void Dispose() { + json.Dispose(); + json = null; + } + + Dictionary ParseObject() { + Dictionary table = new Dictionary(); + + // ditch opening brace + json.Read(); + + // { + while (true) { + switch (NextToken) { + case TOKEN.NONE: + return null; + case TOKEN.COMMA: + continue; + case TOKEN.CURLY_CLOSE: + return table; + default: + // name + string name = ParseString(); + if (name == null) { + return null; + } + + // : + if (NextToken != TOKEN.COLON) { + return null; + } + // ditch the colon + json.Read(); + + // value + table[name] = ParseValue(); + break; + } + } + } + + List ParseArray() { + List array = new List(); + + // ditch opening bracket + json.Read(); + + // [ + var parsing = true; + while (parsing) { + TOKEN nextToken = NextToken; + + switch (nextToken) { + case TOKEN.NONE: + return null; + case TOKEN.COMMA: + continue; + case TOKEN.SQUARED_CLOSE: + parsing = false; + break; + default: + object value = ParseByToken(nextToken); + + array.Add(value); + break; + } + } + + return array; + } + + object ParseValue() { + TOKEN nextToken = NextToken; + return ParseByToken(nextToken); + } + + object ParseByToken(TOKEN token) { + switch (token) { + case TOKEN.STRING: + return ParseString(); + case TOKEN.NUMBER: + return ParseNumber(); + case TOKEN.CURLY_OPEN: + return ParseObject(); + case TOKEN.SQUARED_OPEN: + return ParseArray(); + case TOKEN.TRUE: + return true; + case TOKEN.FALSE: + return false; + case TOKEN.NULL: + return null; + default: + return null; + } + } + + string ParseString() { + StringBuilder s = new StringBuilder(); + char c; + + // ditch opening quote + json.Read(); + + bool parsing = true; + while (parsing) { + + if (json.Peek() == -1) { + parsing = false; + break; + } + + c = NextChar; + switch (c) { + case '"': + parsing = false; + break; + case '\\': + if (json.Peek() == -1) { + parsing = false; + break; + } + + c = NextChar; + switch (c) { + case '"': + case '\\': + case '/': + s.Append(c); + break; + case 'b': + s.Append('\b'); + break; + case 'f': + s.Append('\f'); + break; + case 'n': + s.Append('\n'); + break; + case 'r': + s.Append('\r'); + break; + case 't': + s.Append('\t'); + break; + case 'u': + var hex = new StringBuilder(); + + for (int i=0; i< 4; i++) { + hex.Append(NextChar); + } + + s.Append((char) Convert.ToInt32(hex.ToString(), 16)); + break; + } + break; + default: + s.Append(c); + break; + } + } + + return s.ToString(); + } + + object ParseNumber() { + string number = NextWord; + float parsedFloat; + float.TryParse(number, NumberStyles.Float, CultureInfo.InvariantCulture, out parsedFloat); + return parsedFloat; + } + + void EatWhitespace() { + while (WHITE_SPACE.IndexOf(PeekChar) != -1) { + json.Read(); + + if (json.Peek() == -1) { + break; + } + } + } + + char PeekChar { + get { + return Convert.ToChar(json.Peek()); + } + } + + char NextChar { + get { + return Convert.ToChar(json.Read()); + } + } + + string NextWord { + get { + StringBuilder word = new StringBuilder(); + + while (WORD_BREAK.IndexOf(PeekChar) == -1) { + word.Append(NextChar); + + if (json.Peek() == -1) { + break; + } + } + + return word.ToString(); + } + } + + TOKEN NextToken { + get { + EatWhitespace(); + + if (json.Peek() == -1) { + return TOKEN.NONE; + } + + char c = PeekChar; + switch (c) { + case '{': + return TOKEN.CURLY_OPEN; + case '}': + json.Read(); + return TOKEN.CURLY_CLOSE; + case '[': + return TOKEN.SQUARED_OPEN; + case ']': + json.Read(); + return TOKEN.SQUARED_CLOSE; + case ',': + json.Read(); + return TOKEN.COMMA; + case '"': + return TOKEN.STRING; + case ':': + return TOKEN.COLON; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + return TOKEN.NUMBER; + } + + string word = NextWord; + + switch (word) { + case "false": + return TOKEN.FALSE; + case "true": + return TOKEN.TRUE; + case "null": + return TOKEN.NULL; + } + + return TOKEN.NONE; + } + } + } + + /// + /// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string + /// + /// A Dictionary<string, object> / List<object> + /// A JSON encoded string, or null if object 'json' is not serializable + public static string Serialize(object obj) { + return Serializer.Serialize(obj); + } + + sealed class Serializer { + StringBuilder builder; + + Serializer() { + builder = new StringBuilder(); + } + + public static string Serialize(object obj) { + var instance = new Serializer(); + + instance.SerializeValue(obj); + + return instance.builder.ToString(); + } + + void SerializeValue(object value) { + IList asList; + IDictionary asDict; + string asStr; + + if (value == null) { + builder.Append("null"); + } + else if ((asStr = value as string) != null) { + SerializeString(asStr); + } + else if (value is bool) { + builder.Append(value.ToString().ToLower()); + } + else if ((asList = value as IList) != null) { + SerializeArray(asList); + } + else if ((asDict = value as IDictionary) != null) { + SerializeObject(asDict); + } + else if (value is char) { + SerializeString(value.ToString()); + } + else { + SerializeOther(value); + } + } + + void SerializeObject(IDictionary obj) { + bool first = true; + + builder.Append('{'); + + foreach (object e in obj.Keys) { + if (!first) { + builder.Append(','); + } + + SerializeString(e.ToString()); + builder.Append(':'); + + SerializeValue(obj[e]); + + first = false; + } + + builder.Append('}'); + } + + void SerializeArray(IList anArray) { + builder.Append('['); + + bool first = true; + + foreach (object obj in anArray) { + if (!first) { + builder.Append(','); + } + + SerializeValue(obj); + + first = false; + } + + builder.Append(']'); + } + + void SerializeString(string str) { + builder.Append('\"'); + + char[] charArray = str.ToCharArray(); + foreach (var c in charArray) { + switch (c) { + case '"': + builder.Append("\\\""); + break; + case '\\': + builder.Append("\\\\"); + break; + case '\b': + builder.Append("\\b"); + break; + case '\f': + builder.Append("\\f"); + break; + case '\n': + builder.Append("\\n"); + break; + case '\r': + builder.Append("\\r"); + break; + case '\t': + builder.Append("\\t"); + break; + default: + int codepoint = Convert.ToInt32(c); + if ((codepoint >= 32) && (codepoint <= 126)) { + builder.Append(c); + } + else { + builder.Append("\\u" + Convert.ToString(codepoint, 16).PadLeft(4, '0')); + } + break; + } + } + + builder.Append('\"'); + } + + void SerializeOther(object value) { + if (value is float + || value is int + || value is uint + || value is long + || value is float + || value is sbyte + || value is byte + || value is short + || value is ushort + || value is ulong + || value is decimal) { + builder.Append(value.ToString()); + } + else { + SerializeString(value.ToString()); + } + } + } + } +} \ No newline at end of file diff --git a/spine-tk2d/Assets/spine-csharp/Json.cs.meta b/spine-tk2d/Assets/spine-csharp/Json.cs.meta new file mode 100644 index 000000000..cf36906ec --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Json.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7dc7846bb73779846ad441bc908d11e2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/Place spine-csharp src here.txt b/spine-tk2d/Assets/spine-csharp/Place spine-csharp src here.txt new file mode 100644 index 000000000..e69de29bb diff --git a/spine-tk2d/Assets/spine-csharp/Place spine-csharp src here.txt.meta b/spine-tk2d/Assets/spine-csharp/Place spine-csharp src here.txt.meta new file mode 100644 index 000000000..f9ee3e6ef --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Place spine-csharp src here.txt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 796664cab7a50f94d92f55ed41f7f5b1 +TextScriptImporter: + userData: diff --git a/spine-tk2d/Assets/spine-csharp/Skeleton.cs b/spine-tk2d/Assets/spine-csharp/Skeleton.cs new file mode 100644 index 000000000..f8e54bedd --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Skeleton.cs @@ -0,0 +1,222 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using System.Collections.Generic; + +namespace Spine { + public class Skeleton { + internal SkeletonData data; + internal List bones; + internal List slots; + internal List drawOrder; + internal Skin skin; + internal float r = 1, g = 1, b = 1, a = 1; + internal float time; + internal bool flipX, flipY; + internal float x, y; + + public SkeletonData Data { get { return data; } } + public List Bones { get { return bones; } } + public List Slots { get { return slots; } } + public List DrawOrder { get { return drawOrder; } } + public Skin Skin { get { return skin; } set { skin = value; } } + public float R { get { return r; } set { r = value; } } + public float G { get { return g; } set { g = value; } } + public float B { get { return b; } set { b = value; } } + public float A { get { return a; } set { a = value; } } + public float Time { get { return time; } set { time = value; } } + public bool FlipX { get { return flipX; } set { flipX = value; } } + public bool FlipY { get { return flipY; } set { flipY = value; } } + public float X { get { return x; } set { x = value; } } + public float Y { get { return y; } set { y = value; } } + + public Bone RootBone { + get { + return bones.Count == 0 ? null : bones[0]; + } + } + + public Skeleton (SkeletonData data) { + if (data == null) throw new ArgumentNullException("data cannot be null."); + this.data = data; + + bones = new List(data.bones.Count); + foreach (BoneData boneData in data.bones) { + Bone parent = boneData.parent == null ? null : bones[data.bones.IndexOf(boneData.parent)]; + bones.Add(new Bone(boneData, parent)); + } + + slots = new List(data.slots.Count); + drawOrder = new List(data.slots.Count); + foreach (SlotData slotData in data.slots) { + Bone bone = bones[data.bones.IndexOf(slotData.boneData)]; + Slot slot = new Slot(slotData, this, bone); + slots.Add(slot); + drawOrder.Add(slot); + } + } + + /// Updates the world transform for each bone. + public void UpdateWorldTransform () { + bool flipX = this.flipX; + bool flipY = this.flipY; + List bones = this.bones; + for (int i = 0, n = bones.Count; i < n; i++) + bones[i].UpdateWorldTransform(flipX, flipY); + } + + /// Sets the bones and slots to their setup pose values. + public void SetToSetupPose () { + SetBonesToSetupPose(); + SetSlotsToSetupPose(); + } + + public void SetBonesToSetupPose () { + List bones = this.bones; + for (int i = 0, n = bones.Count; i < n; i++) + bones[i].SetToSetupPose(); + } + + public void SetSlotsToSetupPose () { + List slots = this.slots; + drawOrder.Clear(); + drawOrder.AddRange(slots); + for (int i = 0, n = slots.Count; i < n; i++) + slots[i].SetToSetupPose(i); + } + + /// May be null. + public Bone FindBone (String boneName) { + if (boneName == null) throw new ArgumentNullException("boneName cannot be null."); + List bones = this.bones; + for (int i = 0, n = bones.Count; i < n; i++) { + Bone bone = bones[i]; + if (bone.data.name == boneName) return bone; + } + return null; + } + + /// -1 if the bone was not found. + public int FindBoneIndex (String boneName) { + if (boneName == null) throw new ArgumentNullException("boneName cannot be null."); + List bones = this.bones; + for (int i = 0, n = bones.Count; i < n; i++) + if (bones[i].data.name == boneName) return i; + return -1; + } + + /// May be null. + public Slot FindSlot (String slotName) { + if (slotName == null) throw new ArgumentNullException("slotName cannot be null."); + List slots = this.slots; + for (int i = 0, n = slots.Count; i < n; i++) { + Slot slot = slots[i]; + if (slot.data.name == slotName) return slot; + } + return null; + } + + /// -1 if the bone was not found. + public int FindSlotIndex (String slotName) { + if (slotName == null) throw new ArgumentNullException("slotName cannot be null."); + List slots = this.slots; + for (int i = 0, n = slots.Count; i < n; i++) + if (slots[i].data.name.Equals(slotName)) return i; + return -1; + } + + /// Sets a skin by name (see SetSkin). + public void SetSkin (String skinName) { + Skin skin = data.FindSkin(skinName); + if (skin == null) throw new ArgumentException("Skin not found: " + skinName); + SetSkin(skin); + } + + /// Sets the skin used to look up attachments not found in the {@link SkeletonData#getDefaultSkin() default skin}. Attachments + /// from the new skin are attached if the corresponding attachment from the old skin was attached. If there was no old skin, each slot's + /// setup mode attachment is attached from the new skin. + /// May be null. + public void SetSkin (Skin newSkin) { + if (skin == null) { + List slots = this.slots; + for (int i = 0, n = slots.Count; i < n; i++) { + Slot slot = slots[i]; + String name = slot.data.attachmentName; + if (name != null) { + Attachment attachment = newSkin.GetAttachment(i, name); + if (attachment != null) slot.Attachment = attachment; + } + } + } else if (newSkin != null) // + newSkin.AttachAll(this, skin); + skin = newSkin; + } + + /// May be null. + public Attachment GetAttachment (String slotName, String attachmentName) { + return GetAttachment(data.FindSlotIndex(slotName), attachmentName); + } + + /// May be null. + public Attachment GetAttachment (int slotIndex, String attachmentName) { + if (attachmentName == null) throw new ArgumentNullException("attachmentName cannot be null."); + if (skin != null) { + Attachment attachment = skin.GetAttachment(slotIndex, attachmentName); + if (attachment != null) return attachment; + } + if (data.defaultSkin != null) return data.defaultSkin.GetAttachment(slotIndex, attachmentName); + return null; + } + + /// May be null. + public void SetAttachment (String slotName, String attachmentName) { + if (slotName == null) throw new ArgumentNullException("slotName cannot be null."); + List slots = this.slots; + for (int i = 0, n = slots.Count; i < n; i++) { + Slot slot = slots[i]; + if (slot.data.name == slotName) { + Attachment attachment = null; + if (attachmentName != null) { + attachment = GetAttachment(i, attachmentName); + if (attachment == null) throw new Exception("Attachment not found: " + attachmentName + ", for slot: " + slotName); + } + slot.Attachment = attachment; + return; + } + } + throw new Exception("Slot not found: " + slotName); + } + + public void Update (float delta) { + time += delta; + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/Skeleton.cs.meta b/spine-tk2d/Assets/spine-csharp/Skeleton.cs.meta new file mode 100644 index 000000000..351da26b3 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Skeleton.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f55a047e931c73b449e1df43c1a6010b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/SkeletonBounds.cs b/spine-tk2d/Assets/spine-csharp/SkeletonBounds.cs new file mode 100644 index 000000000..3e434a8f4 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/SkeletonBounds.cs @@ -0,0 +1,216 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using System.Collections.Generic; + +namespace Spine { + public class SkeletonBounds { + private List polygonPool = new List(); + private float minX, minY, maxX, maxY; + + public List BoundingBoxes { get; private set; } + public List Polygons { get; private set; } + public float MinX { get { return minX; } set { minX = value; } } + public float MinY { get { return minY; } set { minY = value; } } + public float MaxX { get { return maxX; } set { maxX = value; } } + public float MaxY { get { return maxY; } set { maxY = value; } } + public float Width { get { return maxX - minX; } } + public float Height { get { return maxY - minY; } } + + public SkeletonBounds () { + BoundingBoxes = new List(); + Polygons = new List(); + } + + public void Update (Skeleton skeleton, bool updateAabb) { + List boundingBoxes = BoundingBoxes; + List polygons = Polygons; + List slots = skeleton.slots; + int slotCount = slots.Count; + float x = skeleton.x, y = skeleton.y; + + boundingBoxes.Clear(); + foreach (Polygon polygon in polygons) + polygonPool.Add(polygon); + polygons.Clear(); + + for (int i = 0; i < slotCount; i++) { + Slot slot = slots[i]; + BoundingBoxAttachment boundingBox = slot.attachment as BoundingBoxAttachment; + if (boundingBox == null) continue; + boundingBoxes.Add(boundingBox); + + Polygon polygon = null; + int poolCount = polygonPool.Count; + if (poolCount > 0) { + polygon = polygonPool[poolCount - 1]; + polygonPool.RemoveAt(poolCount - 1); + } else + polygon = new Polygon(); + polygons.Add(polygon); + + int count = boundingBox.Vertices.Length; + polygon.Count = count; + if (polygon.Vertices.Length < count) polygon.Vertices = new float[count]; + boundingBox.ComputeWorldVertices(x, y, slot.bone, polygon.Vertices); + } + + if (updateAabb) aabbCompute(); + } + + private void aabbCompute () { + float minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue; + List polygons = Polygons; + for (int i = 0, n = polygons.Count; i < n; i++) { + Polygon polygon = polygons[i]; + float[] vertices = polygon.Vertices; + for (int ii = 0, nn = polygon.Count; ii < nn; ii += 2) { + float x = vertices[ii]; + float y = vertices[ii + 1]; + minX = Math.Min(minX, x); + minY = Math.Min(minY, y); + maxX = Math.Max(maxX, x); + maxY = Math.Max(maxY, y); + } + } + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + + + /// Returns true if the axis aligned bounding box contains the point. + public bool AabbContainsPoint (float x, float y) { + return x >= minX && x <= maxX && y >= minY && y <= maxY; + } + + /// Returns true if the axis aligned bounding box intersects the line segment. + public bool AabbIntersectsSegment (float x1, float y1, float x2, float y2) { + float minX = this.minX; + float minY = this.minY; + float maxX = this.maxX; + float maxY = this.maxY; + if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) + return false; + float m = (y2 - y1) / (x2 - x1); + float y = m * (minX - x1) + y1; + if (y > minY && y < maxY) return true; + y = m * (maxX - x1) + y1; + if (y > minY && y < maxY) return true; + float x = (minY - y1) / m + x1; + if (x > minX && x < maxX) return true; + x = (maxY - y1) / m + x1; + if (x > minX && x < maxX) return true; + return false; + } + + /// Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. + public bool AabbIntersectsSkeleton (SkeletonBounds bounds) { + return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY; + } + + /// Returns true if the polygon contains the point. + public bool ContainsPoint (Polygon polygon, float x, float y) { + float[] vertices = polygon.Vertices; + int nn = polygon.Count; + + int prevIndex = nn - 2; + bool inside = false; + for (int ii = 0; ii < nn; ii += 2) { + float vertexY = vertices[ii + 1]; + float prevY = vertices[prevIndex + 1]; + if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { + float vertexX = vertices[ii]; + if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; + } + prevIndex = ii; + } + return inside; + } + + /// Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more + /// efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. + public BoundingBoxAttachment ContainsPoint (float x, float y) { + List polygons = Polygons; + for (int i = 0, n = polygons.Count; i < n; i++) + if (ContainsPoint(polygons[i], x, y)) return BoundingBoxes[i]; + return null; + } + + /// Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually + /// more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true. + public BoundingBoxAttachment IntersectsSegment (float x1, float y1, float x2, float y2) { + List polygons = Polygons; + for (int i = 0, n = polygons.Count; i < n; i++) + if (IntersectsSegment(polygons[i], x1, y1, x2, y2)) return BoundingBoxes[i]; + return null; + } + + /// Returns true if the polygon contains the line segment. + public bool IntersectsSegment (Polygon polygon, float x1, float y1, float x2, float y2) { + float[] vertices = polygon.Vertices; + int nn = polygon.Count; + + float width12 = x1 - x2, height12 = y1 - y2; + float det1 = x1 * y2 - y1 * x2; + float x3 = vertices[nn - 2], y3 = vertices[nn - 1]; + for (int ii = 0; ii < nn; ii += 2) { + float x4 = vertices[ii], y4 = vertices[ii + 1]; + float det2 = x3 * y4 - y3 * x4; + float width34 = x3 - x4, height34 = y3 - y4; + float det3 = width12 * height34 - height12 * width34; + float x = (det1 * width34 - width12 * det2) / det3; + if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { + float y = (det1 * height34 - height12 * det2) / det3; + if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true; + } + x3 = x4; + y3 = y4; + } + return false; + } + + public Polygon getPolygon (BoundingBoxAttachment attachment) { + int index = BoundingBoxes.IndexOf(attachment); + return index == -1 ? null : Polygons[index]; + } + } + + public class Polygon { + public float[] Vertices { get; set; } + public int Count { get; set; } + + public Polygon () { + Vertices = new float[16]; + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/SkeletonBounds.cs.meta b/spine-tk2d/Assets/spine-csharp/SkeletonBounds.cs.meta new file mode 100644 index 000000000..50d4e2c7f --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/SkeletonBounds.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 723d7c54f1b15fa42b184c5ef4a3b18e +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/SkeletonData.cs b/spine-tk2d/Assets/spine-csharp/SkeletonData.cs new file mode 100644 index 000000000..60a5d537a --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/SkeletonData.cs @@ -0,0 +1,162 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using System.Collections.Generic; + +namespace Spine { + public class SkeletonData { + internal String name; + internal List bones = new List(); + internal List slots = new List(); + internal List skins = new List(); + internal Skin defaultSkin; + internal List events = new List(); + internal List animations = new List(); + + public String Name { get { return name; } set { name = value; } } + public List Bones { get { return bones; } } // Ordered parents first. + public List Slots { get { return slots; } } // Setup pose draw order. + public List Skins { get { return skins; } set { skins = value; } } + /// May be null. + public Skin DefaultSkin { get { return defaultSkin; } set { defaultSkin = value; } } + public List Events { get { return events; } set { events = value; } } + public List Animations { get { return animations; } set { animations = value; } } + + // --- Bones. + + public void AddBone (BoneData bone) { + if (bone == null) throw new ArgumentNullException("bone cannot be null."); + bones.Add(bone); + } + + + /// May be null. + public BoneData FindBone (String boneName) { + if (boneName == null) throw new ArgumentNullException("boneName cannot be null."); + List bones = this.bones; + for (int i = 0, n = bones.Count; i < n; i++) { + BoneData bone = bones[i]; + if (bone.name == boneName) return bone; + } + return null; + } + + /// -1 if the bone was not found. + public int FindBoneIndex (String boneName) { + if (boneName == null) throw new ArgumentNullException("boneName cannot be null."); + List bones = this.bones; + for (int i = 0, n = bones.Count; i < n; i++) + if (bones[i].name == boneName) return i; + return -1; + } + + // --- Slots. + + public void AddSlot (SlotData slot) { + if (slot == null) throw new ArgumentNullException("slot cannot be null."); + slots.Add(slot); + } + + /// May be null. + public SlotData FindSlot (String slotName) { + if (slotName == null) throw new ArgumentNullException("slotName cannot be null."); + List slots = this.slots; + for (int i = 0, n = slots.Count; i < n; i++) { + SlotData slot = slots[i]; + if (slot.name == slotName) return slot; + } + return null; + } + + /// -1 if the bone was not found. + public int FindSlotIndex (String slotName) { + if (slotName == null) throw new ArgumentNullException("slotName cannot be null."); + List slots = this.slots; + for (int i = 0, n = slots.Count; i < n; i++) + if (slots[i].name == slotName) return i; + return -1; + } + + // --- Skins. + + public void AddSkin (Skin skin) { + if (skin == null) throw new ArgumentNullException("skin cannot be null."); + skins.Add(skin); + } + + /// May be null. + public Skin FindSkin (String skinName) { + if (skinName == null) throw new ArgumentNullException("skinName cannot be null."); + foreach (Skin skin in skins) + if (skin.name == skinName) return skin; + return null; + } + + // --- Events. + + public void AddEvent (EventData eventData) { + if (eventData == null) throw new ArgumentNullException("eventData cannot be null."); + events.Add(eventData); + } + + /// May be null. + public EventData FindEvent (String eventDataName) { + if (eventDataName == null) throw new ArgumentNullException("eventDataName cannot be null."); + foreach (EventData eventData in events) + if (eventData.Name == eventDataName) return eventData; + return null; + } + + // --- Animations. + + public void AddAnimation (Animation animation) { + if (animation == null) throw new ArgumentNullException("animation cannot be null."); + animations.Add(animation); + } + + /// May be null. + public Animation FindAnimation (String animationName) { + if (animationName == null) throw new ArgumentNullException("animationName cannot be null."); + List animations = this.animations; + for (int i = 0, n = animations.Count; i < n; i++) { + Animation animation = animations[i]; + if (animation.Name == animationName) return animation; + } + return null; + } + + // --- + + override public String ToString () { + return name ?? base.ToString(); + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/SkeletonData.cs.meta b/spine-tk2d/Assets/spine-csharp/SkeletonData.cs.meta new file mode 100644 index 000000000..6439d6099 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/SkeletonData.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: faa288c5c9e63b9458b1e6ba0dce560d +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/SkeletonJson.cs b/spine-tk2d/Assets/spine-csharp/SkeletonJson.cs new file mode 100644 index 000000000..e7b2a0db5 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/SkeletonJson.cs @@ -0,0 +1,571 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using System.IO; +using System.Collections.Generic; + +#if WINDOWS_STOREAPP +using System.Threading.Tasks; +using Windows.Storage; +#endif + +namespace Spine { + public class SkeletonJson { + private AttachmentLoader attachmentLoader; + public float Scale { get; set; } + + public SkeletonJson (Atlas atlas) + : this(new AtlasAttachmentLoader(atlas)) { + } + + public SkeletonJson (AttachmentLoader attachmentLoader) { + if (attachmentLoader == null) throw new ArgumentNullException("attachmentLoader cannot be null."); + this.attachmentLoader = attachmentLoader; + Scale = 1; + } + +#if WINDOWS_STOREAPP + private async Task ReadFile(string path) { + var folder = Windows.ApplicationModel.Package.Current.InstalledLocation; + var file = await folder.GetFileAsync(path).AsTask().ConfigureAwait(false); + using (var reader = new StreamReader(await file.OpenStreamForReadAsync().ConfigureAwait(false))) { + SkeletonData skeletonData = ReadSkeletonData(reader); + skeletonData.Name = Path.GetFileNameWithoutExtension(path); + return skeletonData; + } + } + + public SkeletonData ReadSkeletonData (String path) { + return this.ReadFile(path).Result; + } +#else + public SkeletonData ReadSkeletonData (String path) { +#if WINDOWS_PHONE + Stream stream = Microsoft.Xna.Framework.TitleContainer.OpenStream(path); + using (StreamReader reader = new StreamReader(stream)) + { +#else + using (StreamReader reader = new StreamReader(path)) { +#endif + SkeletonData skeletonData = ReadSkeletonData(reader); + skeletonData.name = Path.GetFileNameWithoutExtension(path); + return skeletonData; + } + } +#endif + + public SkeletonData ReadSkeletonData (TextReader reader) { + if (reader == null) throw new ArgumentNullException("reader cannot be null."); + + var skeletonData = new SkeletonData(); + + var root = Json.Deserialize(reader) as Dictionary; + if (root == null) throw new Exception("Invalid JSON."); + + // Bones. + foreach (Dictionary boneMap in (List)root["bones"]) { + BoneData parent = null; + if (boneMap.ContainsKey("parent")) { + parent = skeletonData.FindBone((String)boneMap["parent"]); + if (parent == null) + throw new Exception("Parent bone not found: " + boneMap["parent"]); + } + var boneData = new BoneData((String)boneMap["name"], parent); + boneData.length = GetFloat(boneMap, "length", 0) * Scale; + boneData.x = GetFloat(boneMap, "x", 0) * Scale; + boneData.y = GetFloat(boneMap, "y", 0) * Scale; + boneData.rotation = GetFloat(boneMap, "rotation", 0); + boneData.scaleX = GetFloat(boneMap, "scaleX", 1); + boneData.scaleY = GetFloat(boneMap, "scaleY", 1); + boneData.inheritScale = GetBoolean(boneMap, "inheritScale", true); + boneData.inheritRotation = GetBoolean(boneMap, "inheritRotation", true); + skeletonData.AddBone(boneData); + } + + // Slots. + if (root.ContainsKey("slots")) { + foreach (Dictionary slotMap in (List)root["slots"]) { + var slotName = (String)slotMap["name"]; + var boneName = (String)slotMap["bone"]; + BoneData boneData = skeletonData.FindBone(boneName); + if (boneData == null) + throw new Exception("Slot bone not found: " + boneName); + var slotData = new SlotData(slotName, boneData); + + if (slotMap.ContainsKey("color")) { + var color = (String)slotMap["color"]; + slotData.r = ToColor(color, 0); + slotData.g = ToColor(color, 1); + slotData.b = ToColor(color, 2); + slotData.a = ToColor(color, 3); + } + + if (slotMap.ContainsKey("attachment")) + slotData.attachmentName = (String)slotMap["attachment"]; + + if (slotMap.ContainsKey("additive")) + slotData.additiveBlending = (bool)slotMap["additive"]; + + skeletonData.AddSlot(slotData); + } + } + + // Skins. + if (root.ContainsKey("skins")) { + foreach (KeyValuePair entry in (Dictionary)root["skins"]) { + var skin = new Skin(entry.Key); + foreach (KeyValuePair slotEntry in (Dictionary)entry.Value) { + int slotIndex = skeletonData.FindSlotIndex(slotEntry.Key); + foreach (KeyValuePair attachmentEntry in ((Dictionary)slotEntry.Value)) { + Attachment attachment = ReadAttachment(skin, attachmentEntry.Key, (Dictionary)attachmentEntry.Value); + if (attachment != null) skin.AddAttachment(slotIndex, attachmentEntry.Key, attachment); + } + } + skeletonData.AddSkin(skin); + if (skin.name == "default") + skeletonData.defaultSkin = skin; + } + } + + // Events. + if (root.ContainsKey("events")) { + foreach (KeyValuePair entry in (Dictionary)root["events"]) { + var entryMap = (Dictionary)entry.Value; + var eventData = new EventData(entry.Key); + eventData.Int = GetInt(entryMap, "int", 0); + eventData.Float = GetFloat(entryMap, "float", 0); + eventData.String = GetString(entryMap, "string", null); + skeletonData.AddEvent(eventData); + } + } + + // Animations. + if (root.ContainsKey("animations")) { + foreach (KeyValuePair entry in (Dictionary)root["animations"]) + ReadAnimation(entry.Key, (Dictionary)entry.Value, skeletonData); + } + + skeletonData.bones.TrimExcess(); + skeletonData.slots.TrimExcess(); + skeletonData.skins.TrimExcess(); + skeletonData.animations.TrimExcess(); + return skeletonData; + } + + private Attachment ReadAttachment (Skin skin, String name, Dictionary map) { + if (map.ContainsKey("name")) + name = (String)map["name"]; + + var type = AttachmentType.region; + if (map.ContainsKey("type")) + type = (AttachmentType)Enum.Parse(typeof(AttachmentType), (String)map["type"], false); + + String path = name; + if (map.ContainsKey("path")) + path = (String)map["path"]; + + switch (type) { + case AttachmentType.region: + RegionAttachment region = attachmentLoader.NewRegionAttachment(skin, name, path); + if (region == null) return null; + region.Path = path; + region.x = GetFloat(map, "x", 0) * Scale; + region.y = GetFloat(map, "y", 0) * Scale; + region.scaleX = GetFloat(map, "scaleX", 1); + region.scaleY = GetFloat(map, "scaleY", 1); + region.rotation = GetFloat(map, "rotation", 0); + region.width = GetFloat(map, "width", 32) * Scale; + region.height = GetFloat(map, "height", 32) * Scale; + region.UpdateOffset(); + + if (map.ContainsKey("color")) { + var color = (String)map["color"]; + region.r = ToColor(color, 0); + region.g = ToColor(color, 1); + region.b = ToColor(color, 2); + region.a = ToColor(color, 3); + } + + return region; + case AttachmentType.mesh: { + MeshAttachment mesh = attachmentLoader.NewMeshAttachment(skin, name, path); + if (mesh == null) return null; + + mesh.Path = path; + mesh.vertices = GetFloatArray(map, "vertices", Scale); + mesh.triangles = GetIntArray(map, "triangles"); + mesh.regionUVs = GetFloatArray(map, "uvs", 1); + mesh.UpdateUVs(); + + if (map.ContainsKey("color")) { + var color = (String)map["color"]; + mesh.r = ToColor(color, 0); + mesh.g = ToColor(color, 1); + mesh.b = ToColor(color, 2); + mesh.a = ToColor(color, 3); + } + + mesh.HullLength = GetInt(map, "hull", 0) * 2; + if (map.ContainsKey("edges")) mesh.Edges = GetIntArray(map, "edges"); + mesh.Width = GetInt(map, "width", 0) * Scale; + mesh.Height = GetInt(map, "height", 0) * Scale; + + return mesh; + } + case AttachmentType.skinnedmesh: { + SkinnedMeshAttachment mesh = attachmentLoader.NewSkinnedMeshAttachment(skin, name, path); + if (mesh == null) return null; + + mesh.Path = path; + float[] uvs = GetFloatArray(map, "uvs", 1); + float[] vertices = GetFloatArray(map, "vertices", 1); + var weights = new List(uvs.Length * 3 * 3); + var bones = new List(uvs.Length * 3); + float scale = Scale; + for (int i = 0, n = vertices.Length; i < n; ) { + int boneCount = (int)vertices[i++]; + bones.Add(boneCount); + for (int nn = i + boneCount * 4; i < nn; ) { + bones.Add((int)vertices[i]); + weights.Add(vertices[i + 1] * scale); + weights.Add(vertices[i + 2] * scale); + weights.Add(vertices[i + 3]); + i += 4; + } + } + mesh.bones = bones.ToArray(); + mesh.weights = weights.ToArray(); + mesh.triangles = GetIntArray(map, "triangles"); + mesh.regionUVs = uvs; + mesh.UpdateUVs(); + + if (map.ContainsKey("color")) { + var color = (String)map["color"]; + mesh.r = ToColor(color, 0); + mesh.g = ToColor(color, 1); + mesh.b = ToColor(color, 2); + mesh.a = ToColor(color, 3); + } + + mesh.HullLength = GetInt(map, "hull", 0) * 2; + if (map.ContainsKey("edges")) mesh.Edges = GetIntArray(map, "edges"); + mesh.Width = GetInt(map, "width", 0) * Scale; + mesh.Height = GetInt(map, "height", 0) * Scale; + + return mesh; + } + case AttachmentType.boundingbox: + BoundingBoxAttachment box = attachmentLoader.NewBoundingBoxAttachment(skin, name); + if (box == null) return null; + box.vertices = GetFloatArray(map, "vertices", Scale); + return box; + } + return null; + } + + private float[] GetFloatArray (Dictionary map, String name, float scale) { + var list = (List)map[name]; + var values = new float[list.Count]; + if (scale == 1) { + for (int i = 0, n = list.Count; i < n; i++) + values[i] = (float)list[i]; + } else { + for (int i = 0, n = list.Count; i < n; i++) + values[i] = (float)list[i] * scale; + } + return values; + } + + private int[] GetIntArray (Dictionary map, String name) { + var list = (List)map[name]; + var values = new int[list.Count]; + for (int i = 0, n = list.Count; i < n; i++) + values[i] = (int)(float)list[i]; + return values; + } + + private float GetFloat (Dictionary map, String name, float defaultValue) { + if (!map.ContainsKey(name)) + return defaultValue; + return (float)map[name]; + } + + private int GetInt (Dictionary map, String name, int defaultValue) { + if (!map.ContainsKey(name)) + return defaultValue; + return (int)(float)map[name]; + } + + private bool GetBoolean (Dictionary map, String name, bool defaultValue) { + if (!map.ContainsKey(name)) + return defaultValue; + return (bool)map[name]; + } + + private String GetString (Dictionary map, String name, String defaultValue) { + if (!map.ContainsKey(name)) + return defaultValue; + return (String)map[name]; + } + + public static float ToColor (String hexString, int colorIndex) { + if (hexString.Length != 8) + throw new ArgumentException("Color hexidecimal length must be 8, recieved: " + hexString); + return Convert.ToInt32(hexString.Substring(colorIndex * 2, 2), 16) / (float)255; + } + + private void ReadAnimation (String name, Dictionary map, SkeletonData skeletonData) { + var timelines = new List(); + float duration = 0; + float scale = Scale; + + if (map.ContainsKey("slots")) { + foreach (KeyValuePair entry in (Dictionary)map["slots"]) { + String slotName = entry.Key; + int slotIndex = skeletonData.FindSlotIndex(slotName); + var timelineMap = (Dictionary)entry.Value; + + foreach (KeyValuePair timelineEntry in timelineMap) { + var values = (List)timelineEntry.Value; + var timelineName = (String)timelineEntry.Key; + if (timelineName.Equals("color")) { + var timeline = new ColorTimeline(values.Count); + timeline.slotIndex = slotIndex; + + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float time = (float)valueMap["time"]; + String c = (String)valueMap["color"]; + timeline.setFrame(frameIndex, time, ToColor(c, 0), ToColor(c, 1), ToColor(c, 2), ToColor(c, 3)); + ReadCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[timeline.FrameCount * 5 - 5]); + + } else if (timelineName.Equals("attachment")) { + var timeline = new AttachmentTimeline(values.Count); + timeline.slotIndex = slotIndex; + + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float time = (float)valueMap["time"]; + timeline.setFrame(frameIndex++, time, (String)valueMap["name"]); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]); + + } else + throw new Exception("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"); + } + } + } + + if (map.ContainsKey("bones")) { + foreach (KeyValuePair entry in (Dictionary)map["bones"]) { + String boneName = entry.Key; + int boneIndex = skeletonData.FindBoneIndex(boneName); + if (boneIndex == -1) + throw new Exception("Bone not found: " + boneName); + + var timelineMap = (Dictionary)entry.Value; + foreach (KeyValuePair timelineEntry in timelineMap) { + var values = (List)timelineEntry.Value; + var timelineName = (String)timelineEntry.Key; + if (timelineName.Equals("rotate")) { + var timeline = new RotateTimeline(values.Count); + timeline.boneIndex = boneIndex; + + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float time = (float)valueMap["time"]; + timeline.SetFrame(frameIndex, time, (float)valueMap["angle"]); + ReadCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[timeline.FrameCount * 2 - 2]); + + } else if (timelineName.Equals("translate") || timelineName.Equals("scale")) { + TranslateTimeline timeline; + float timelineScale = 1; + if (timelineName.Equals("scale")) + timeline = new ScaleTimeline(values.Count); + else { + timeline = new TranslateTimeline(values.Count); + timelineScale = scale; + } + timeline.boneIndex = boneIndex; + + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float time = (float)valueMap["time"]; + float x = valueMap.ContainsKey("x") ? (float)valueMap["x"] : 0; + float y = valueMap.ContainsKey("y") ? (float)valueMap["y"] : 0; + timeline.SetFrame(frameIndex, time, (float)x * timelineScale, (float)y * timelineScale); + ReadCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[timeline.FrameCount * 3 - 3]); + + } else + throw new Exception("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"); + } + } + } + + if (map.ContainsKey("ffd")) { + foreach (KeyValuePair ffdMap in (Dictionary)map["ffd"]) { + Skin skin = skeletonData.FindSkin(ffdMap.Key); + foreach (KeyValuePair slotMap in (Dictionary)ffdMap.Value) { + int slotIndex = skeletonData.FindSlotIndex(slotMap.Key); + foreach (KeyValuePair meshMap in (Dictionary)slotMap.Value) { + var values = (List)meshMap.Value; + var timeline = new FFDTimeline(values.Count); + Attachment attachment = skin.GetAttachment(slotIndex, meshMap.Key); + if (attachment == null) throw new Exception("FFD attachment not found: " + meshMap.Key); + timeline.slotIndex = slotIndex; + timeline.attachment = attachment; + + int vertexCount; + if (attachment is MeshAttachment) + vertexCount = ((MeshAttachment)attachment).vertices.Length; + else + vertexCount = ((SkinnedMeshAttachment)attachment).Weights.Length / 3 * 2; + + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float[] vertices; + if (!valueMap.ContainsKey("vertices")) { + if (attachment is MeshAttachment) + vertices = ((MeshAttachment)attachment).vertices; + else + vertices = new float[vertexCount]; + } else { + var verticesValue = (List)valueMap["vertices"]; + vertices = new float[vertexCount]; + int start = GetInt(valueMap, "offset", 0); + if (scale == 1) { + for (int i = 0, n = verticesValue.Count; i < n; i++) + vertices[i + start] = (float)verticesValue[i]; + } else { + for (int i = 0, n = verticesValue.Count; i < n; i++) + vertices[i + start] = (float)verticesValue[i] * scale; + } + if (attachment is MeshAttachment) { + float[] meshVertices = ((MeshAttachment)attachment).vertices; + for (int i = 0, n = vertices.Length; i < n; i++) + vertices[i] += meshVertices[i]; + } + } + + timeline.setFrame(frameIndex, (float)valueMap["time"], vertices); + ReadCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]); + } + } + } + } + + if (map.ContainsKey("draworder")) { + var values = (List)map["draworder"]; + var timeline = new DrawOrderTimeline(values.Count); + int slotCount = skeletonData.slots.Count; + int frameIndex = 0; + foreach (Dictionary drawOrderMap in values) { + int[] drawOrder = null; + if (drawOrderMap.ContainsKey("offsets")) { + drawOrder = new int[slotCount]; + for (int i = slotCount - 1; i >= 0; i--) + drawOrder[i] = -1; + var offsets = (List)drawOrderMap["offsets"]; + int[] unchanged = new int[slotCount - offsets.Count]; + int originalIndex = 0, unchangedIndex = 0; + foreach (Dictionary offsetMap in offsets) { + int slotIndex = skeletonData.FindSlotIndex((String)offsetMap["slot"]); + if (slotIndex == -1) throw new Exception("Slot not found: " + offsetMap["slot"]); + // Collect unchanged items. + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + // Set changed items. + drawOrder[originalIndex + (int)(float)offsetMap["offset"]] = originalIndex++; + } + // Collect remaining unchanged items. + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + // Fill in unchanged items. + for (int i = slotCount - 1; i >= 0; i--) + if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex]; + } + timeline.setFrame(frameIndex++, (float)drawOrderMap["time"], drawOrder); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]); + } + + if (map.ContainsKey("events")) { + var eventsMap = (List)map["events"]; + var timeline = new EventTimeline(eventsMap.Count); + int frameIndex = 0; + foreach (Dictionary eventMap in eventsMap) { + EventData eventData = skeletonData.FindEvent((String)eventMap["name"]); + if (eventData == null) throw new Exception("Event not found: " + eventMap["name"]); + var e = new Event(eventData); + e.Int = GetInt(eventMap, "int", eventData.Int); + e.Float = GetFloat(eventMap, "float", eventData.Float); + e.String = GetString(eventMap, "string", eventData.String); + timeline.setFrame(frameIndex++, (float)eventMap["time"], e); + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]); + } + + timelines.TrimExcess(); + skeletonData.AddAnimation(new Animation(name, timelines, duration)); + } + + private void ReadCurve (CurveTimeline timeline, int frameIndex, Dictionary valueMap) { + if (!valueMap.ContainsKey("curve")) + return; + Object curveObject = valueMap["curve"]; + if (curveObject.Equals("stepped")) + timeline.SetStepped(frameIndex); + else if (curveObject is List) { + var curve = (List)curveObject; + timeline.SetCurve(frameIndex, (float)curve[0], (float)curve[1], (float)curve[2], (float)curve[3]); + } + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/SkeletonJson.cs.meta b/spine-tk2d/Assets/spine-csharp/SkeletonJson.cs.meta new file mode 100644 index 000000000..ae829588d --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/SkeletonJson.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 38d0de320809b7942ac6c25a1805cdd0 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/Skin.cs b/spine-tk2d/Assets/spine-csharp/Skin.cs new file mode 100644 index 000000000..e8e68d3dc --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Skin.cs @@ -0,0 +1,101 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using System.Collections.Generic; + +namespace Spine { + /// Stores attachments by slot index and attachment name. + public class Skin { + internal String name; + private Dictionary, Attachment> attachments = + new Dictionary, Attachment>(AttachmentComparer.Instance); + + public String Name { get { return name; } } + + public Skin (String name) { + if (name == null) throw new ArgumentNullException("name cannot be null."); + this.name = name; + } + + public void AddAttachment (int slotIndex, String name, Attachment attachment) { + if (attachment == null) throw new ArgumentNullException("attachment cannot be null."); + attachments[new KeyValuePair(slotIndex, name)] = attachment; + } + + /// May be null. + public Attachment GetAttachment (int slotIndex, String name) { + Attachment attachment; + attachments.TryGetValue(new KeyValuePair(slotIndex, name), out attachment); + return attachment; + } + + public void FindNamesForSlot (int slotIndex, List names) { + if (names == null) throw new ArgumentNullException("names cannot be null."); + foreach (KeyValuePair key in attachments.Keys) + if (key.Key == slotIndex) names.Add(key.Value); + } + + public void FindAttachmentsForSlot (int slotIndex, List attachments) { + if (attachments == null) throw new ArgumentNullException("attachments cannot be null."); + foreach (KeyValuePair, Attachment> entry in this.attachments) + if (entry.Key.Key == slotIndex) attachments.Add(entry.Value); + } + + override public String ToString () { + return name; + } + + /// Attach all attachments from this skin if the corresponding attachment from the old skin is currently attached. + internal void AttachAll (Skeleton skeleton, Skin oldSkin) { + foreach (KeyValuePair, Attachment> entry in oldSkin.attachments) { + int slotIndex = entry.Key.Key; + Slot slot = skeleton.slots[slotIndex]; + if (slot.attachment == entry.Value) { + Attachment attachment = GetAttachment(slotIndex, entry.Key.Value); + if (attachment != null) slot.Attachment = attachment; + } + } + } + + // Avoids boxing in the dictionary. + private class AttachmentComparer : IEqualityComparer> { + internal static readonly AttachmentComparer Instance = new AttachmentComparer(); + + bool IEqualityComparer>.Equals (KeyValuePair o1, KeyValuePair o2) { + return o1.Key == o2.Key && o1.Value == o2.Value; + } + + int IEqualityComparer>.GetHashCode (KeyValuePair o) { + return o.Key; + } + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/Skin.cs.meta b/spine-tk2d/Assets/spine-csharp/Skin.cs.meta new file mode 100644 index 000000000..0f1358825 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Skin.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 230bfc023e782464ea1b4227d7ea271f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/Slot.cs b/spine-tk2d/Assets/spine-csharp/Slot.cs new file mode 100644 index 000000000..e7a323aff --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Slot.cs @@ -0,0 +1,103 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; + +namespace Spine { + public class Slot { + internal SlotData data; + internal Bone bone; + internal Skeleton skeleton; + internal float r, g, b, a; + internal float attachmentTime; + internal Attachment attachment; + internal float[] attachmentVertices = new float[0]; + internal int attachmentVerticesCount; + + public SlotData Data { get { return data; } } + public Bone Bone { get { return bone; } } + public Skeleton Skeleton { get { return skeleton; } } + public float R { get { return r; } set { r = value; } } + public float G { get { return g; } set { g = value; } } + public float B { get { return b; } set { b = value; } } + public float A { get { return a; } set { a = value; } } + + /// May be null. + public Attachment Attachment { + get { + return attachment; + } + set { + attachment = value; + attachmentTime = skeleton.time; + attachmentVerticesCount = 0; + } + } + + public float AttachmentTime { + get { + return skeleton.time - attachmentTime; + } + set { + attachmentTime = skeleton.time - value; + } + } + + public float[] AttachmentVertices { get { return attachmentVertices; } set { attachmentVertices = value; } } + public int AttachmentVerticesCount { get { return attachmentVerticesCount; } set { attachmentVerticesCount = value; } } + + public Slot (SlotData data, Skeleton skeleton, Bone bone) { + if (data == null) throw new ArgumentNullException("data cannot be null."); + if (skeleton == null) throw new ArgumentNullException("skeleton cannot be null."); + if (bone == null) throw new ArgumentNullException("bone cannot be null."); + this.data = data; + this.skeleton = skeleton; + this.bone = bone; + SetToSetupPose(); + } + + internal void SetToSetupPose (int slotIndex) { + r = data.r; + g = data.g; + b = data.b; + a = data.a; + Attachment = data.attachmentName == null ? null : skeleton.GetAttachment(slotIndex, data.attachmentName); + attachmentVerticesCount = 0; + } + + public void SetToSetupPose () { + SetToSetupPose(skeleton.data.slots.IndexOf(data)); + } + + override public String ToString () { + return data.name; + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/Slot.cs.meta b/spine-tk2d/Assets/spine-csharp/Slot.cs.meta new file mode 100644 index 000000000..fb5446c0a --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/Slot.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: f1a78d8441206284a8372ea7e10ea850 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-tk2d/Assets/spine-csharp/SlotData.cs b/spine-tk2d/Assets/spine-csharp/SlotData.cs new file mode 100644 index 000000000..dd74f4ff1 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/SlotData.cs @@ -0,0 +1,62 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; + +namespace Spine { + public class SlotData { + internal String name; + internal BoneData boneData; + internal float r = 1, g = 1, b = 1, a = 1; + internal String attachmentName; + internal bool additiveBlending; + + public String Name { get { return name; } } + public BoneData BoneData { get { return boneData; } } + public float R { get { return r; } set { r = value; } } + public float G { get { return g; } set { g = value; } } + public float B { get { return b; } set { b = value; } } + public float A { get { return a; } set { a = value; } } + /// May be null. + public String AttachmentName { get { return attachmentName; } set { attachmentName = value; } } + public bool AdditiveBlending { get { return additiveBlending; } set { additiveBlending = value; } } + + public SlotData (String name, BoneData boneData) { + if (name == null) throw new ArgumentNullException("name cannot be null."); + if (boneData == null) throw new ArgumentNullException("boneData cannot be null."); + this.name = name; + this.boneData = boneData; + } + + override public String ToString () { + return name; + } + } +} diff --git a/spine-tk2d/Assets/spine-csharp/SlotData.cs.meta b/spine-tk2d/Assets/spine-csharp/SlotData.cs.meta new file mode 100644 index 000000000..375779a39 --- /dev/null +++ b/spine-tk2d/Assets/spine-csharp/SlotData.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 11956e64fafe7904a89594662753e219 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/spine-unity/Assets/Spine.meta b/spine-tk2d/Assets/spine-tk2d.meta similarity index 63% rename from spine-unity/Assets/Spine.meta rename to spine-tk2d/Assets/spine-tk2d.meta index bf187b4b2..f7c809bbc 100644 --- a/spine-unity/Assets/Spine.meta +++ b/spine-tk2d/Assets/spine-tk2d.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 460170723785f0448822b8dcc876fe7f +guid: ca05969319ad1e94694474804763fecc folderAsset: yes DefaultImporter: userData: diff --git a/spine-tk2d/Assets/Spine/BoneComponent.cs b/spine-tk2d/Assets/spine-tk2d/BoneComponent.cs similarity index 100% rename from spine-tk2d/Assets/Spine/BoneComponent.cs rename to spine-tk2d/Assets/spine-tk2d/BoneComponent.cs diff --git a/spine-tk2d/Assets/Spine/BoneComponent.cs.meta b/spine-tk2d/Assets/spine-tk2d/BoneComponent.cs.meta similarity index 100% rename from spine-tk2d/Assets/Spine/BoneComponent.cs.meta rename to spine-tk2d/Assets/spine-tk2d/BoneComponent.cs.meta diff --git a/spine-tk2d/Assets/Spine/Editor.meta b/spine-tk2d/Assets/spine-tk2d/Editor.meta similarity index 100% rename from spine-tk2d/Assets/Spine/Editor.meta rename to spine-tk2d/Assets/spine-tk2d/Editor.meta diff --git a/spine-tk2d/Assets/Spine/Editor/BoneComponentInspector.cs b/spine-tk2d/Assets/spine-tk2d/Editor/BoneComponentInspector.cs similarity index 100% rename from spine-tk2d/Assets/Spine/Editor/BoneComponentInspector.cs rename to spine-tk2d/Assets/spine-tk2d/Editor/BoneComponentInspector.cs diff --git a/spine-tk2d/Assets/Spine/Editor/BoneComponentInspector.cs.meta b/spine-tk2d/Assets/spine-tk2d/Editor/BoneComponentInspector.cs.meta similarity index 100% rename from spine-tk2d/Assets/Spine/Editor/BoneComponentInspector.cs.meta rename to spine-tk2d/Assets/spine-tk2d/Editor/BoneComponentInspector.cs.meta diff --git a/spine-tk2d/Assets/Spine/Editor/Menus.cs b/spine-tk2d/Assets/spine-tk2d/Editor/Menus.cs similarity index 100% rename from spine-tk2d/Assets/Spine/Editor/Menus.cs rename to spine-tk2d/Assets/spine-tk2d/Editor/Menus.cs diff --git a/spine-tk2d/Assets/Spine/Editor/Menus.cs.meta b/spine-tk2d/Assets/spine-tk2d/Editor/Menus.cs.meta similarity index 100% rename from spine-tk2d/Assets/Spine/Editor/Menus.cs.meta rename to spine-tk2d/Assets/spine-tk2d/Editor/Menus.cs.meta diff --git a/spine-tk2d/Assets/Spine/Editor/SkeletonAnimationInspector.cs b/spine-tk2d/Assets/spine-tk2d/Editor/SkeletonAnimationInspector.cs similarity index 100% rename from spine-tk2d/Assets/Spine/Editor/SkeletonAnimationInspector.cs rename to spine-tk2d/Assets/spine-tk2d/Editor/SkeletonAnimationInspector.cs diff --git a/spine-tk2d/Assets/Spine/Editor/SkeletonAnimationInspector.cs.meta b/spine-tk2d/Assets/spine-tk2d/Editor/SkeletonAnimationInspector.cs.meta similarity index 100% rename from spine-tk2d/Assets/Spine/Editor/SkeletonAnimationInspector.cs.meta rename to spine-tk2d/Assets/spine-tk2d/Editor/SkeletonAnimationInspector.cs.meta diff --git a/spine-tk2d/Assets/Spine/Editor/SkeletonDataAssetInspector.cs b/spine-tk2d/Assets/spine-tk2d/Editor/SkeletonDataAssetInspector.cs similarity index 100% rename from spine-tk2d/Assets/Spine/Editor/SkeletonDataAssetInspector.cs rename to spine-tk2d/Assets/spine-tk2d/Editor/SkeletonDataAssetInspector.cs diff --git a/spine-tk2d/Assets/Spine/Editor/SkeletonDataAssetInspector.cs.meta b/spine-tk2d/Assets/spine-tk2d/Editor/SkeletonDataAssetInspector.cs.meta similarity index 100% rename from spine-tk2d/Assets/Spine/Editor/SkeletonDataAssetInspector.cs.meta rename to spine-tk2d/Assets/spine-tk2d/Editor/SkeletonDataAssetInspector.cs.meta diff --git a/spine-tk2d/Assets/Spine/Editor/SkeletonRendererInspector.cs b/spine-tk2d/Assets/spine-tk2d/Editor/SkeletonRendererInspector.cs similarity index 100% rename from spine-tk2d/Assets/Spine/Editor/SkeletonRendererInspector.cs rename to spine-tk2d/Assets/spine-tk2d/Editor/SkeletonRendererInspector.cs diff --git a/spine-tk2d/Assets/Spine/Editor/SkeletonRendererInspector.cs.meta b/spine-tk2d/Assets/spine-tk2d/Editor/SkeletonRendererInspector.cs.meta similarity index 100% rename from spine-tk2d/Assets/Spine/Editor/SkeletonRendererInspector.cs.meta rename to spine-tk2d/Assets/spine-tk2d/Editor/SkeletonRendererInspector.cs.meta diff --git a/spine-tk2d/Assets/Spine/Shaders.meta b/spine-tk2d/Assets/spine-tk2d/Shaders.meta similarity index 100% rename from spine-tk2d/Assets/Spine/Shaders.meta rename to spine-tk2d/Assets/spine-tk2d/Shaders.meta diff --git a/spine-tk2d/Assets/Spine/Shaders/Skeleton.shader b/spine-tk2d/Assets/spine-tk2d/Shaders/Skeleton.shader similarity index 100% rename from spine-tk2d/Assets/Spine/Shaders/Skeleton.shader rename to spine-tk2d/Assets/spine-tk2d/Shaders/Skeleton.shader diff --git a/spine-tk2d/Assets/Spine/Shaders/Skeleton.shader.meta b/spine-tk2d/Assets/spine-tk2d/Shaders/Skeleton.shader.meta similarity index 100% rename from spine-tk2d/Assets/Spine/Shaders/Skeleton.shader.meta rename to spine-tk2d/Assets/spine-tk2d/Shaders/Skeleton.shader.meta diff --git a/spine-tk2d/Assets/Spine/Shaders/SkeletonLit.shader b/spine-tk2d/Assets/spine-tk2d/Shaders/SkeletonLit.shader similarity index 100% rename from spine-tk2d/Assets/Spine/Shaders/SkeletonLit.shader rename to spine-tk2d/Assets/spine-tk2d/Shaders/SkeletonLit.shader diff --git a/spine-tk2d/Assets/Spine/Shaders/SkeletonLit.shader.meta b/spine-tk2d/Assets/spine-tk2d/Shaders/SkeletonLit.shader.meta similarity index 100% rename from spine-tk2d/Assets/Spine/Shaders/SkeletonLit.shader.meta rename to spine-tk2d/Assets/spine-tk2d/Shaders/SkeletonLit.shader.meta diff --git a/spine-tk2d/Assets/Spine/SkeletonAnimation.cs b/spine-tk2d/Assets/spine-tk2d/SkeletonAnimation.cs similarity index 100% rename from spine-tk2d/Assets/Spine/SkeletonAnimation.cs rename to spine-tk2d/Assets/spine-tk2d/SkeletonAnimation.cs diff --git a/spine-tk2d/Assets/Spine/SkeletonAnimation.cs.meta b/spine-tk2d/Assets/spine-tk2d/SkeletonAnimation.cs.meta similarity index 100% rename from spine-tk2d/Assets/Spine/SkeletonAnimation.cs.meta rename to spine-tk2d/Assets/spine-tk2d/SkeletonAnimation.cs.meta diff --git a/spine-tk2d/Assets/Spine/SkeletonDataAsset.cs b/spine-tk2d/Assets/spine-tk2d/SkeletonDataAsset.cs similarity index 100% rename from spine-tk2d/Assets/Spine/SkeletonDataAsset.cs rename to spine-tk2d/Assets/spine-tk2d/SkeletonDataAsset.cs diff --git a/spine-tk2d/Assets/Spine/SkeletonDataAsset.cs.meta b/spine-tk2d/Assets/spine-tk2d/SkeletonDataAsset.cs.meta similarity index 100% rename from spine-tk2d/Assets/Spine/SkeletonDataAsset.cs.meta rename to spine-tk2d/Assets/spine-tk2d/SkeletonDataAsset.cs.meta diff --git a/spine-tk2d/Assets/Spine/SkeletonRenderer.cs b/spine-tk2d/Assets/spine-tk2d/SkeletonRenderer.cs similarity index 100% rename from spine-tk2d/Assets/Spine/SkeletonRenderer.cs rename to spine-tk2d/Assets/spine-tk2d/SkeletonRenderer.cs diff --git a/spine-tk2d/Assets/Spine/SkeletonRenderer.cs.meta b/spine-tk2d/Assets/spine-tk2d/SkeletonRenderer.cs.meta similarity index 100% rename from spine-tk2d/Assets/Spine/SkeletonRenderer.cs.meta rename to spine-tk2d/Assets/spine-tk2d/SkeletonRenderer.cs.meta diff --git a/spine-tk2d/Assets/Spine/SpriteCollectionAttachmentLoader.cs b/spine-tk2d/Assets/spine-tk2d/SpriteCollectionAttachmentLoader.cs similarity index 100% rename from spine-tk2d/Assets/Spine/SpriteCollectionAttachmentLoader.cs rename to spine-tk2d/Assets/spine-tk2d/SpriteCollectionAttachmentLoader.cs diff --git a/spine-tk2d/Assets/Spine/SpriteCollectionAttachmentLoader.cs.meta b/spine-tk2d/Assets/spine-tk2d/SpriteCollectionAttachmentLoader.cs.meta similarity index 100% rename from spine-tk2d/Assets/Spine/SpriteCollectionAttachmentLoader.cs.meta rename to spine-tk2d/Assets/spine-tk2d/SpriteCollectionAttachmentLoader.cs.meta diff --git a/spine-tk2d/README.md b/spine-tk2d/README.md index 6003b0147..4db76b876 100644 --- a/spine-tk2d/README.md +++ b/spine-tk2d/README.md @@ -7,10 +7,15 @@ A Spine skeleton is a GameObject and can be used throughout Unity like any other ## Setup 1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip). -1. Copy the contents of `spine-csharp/src` to `spine-tk2d/Assets/Spine/spine-csharp`. +1. Copy the contents of `spine-csharp/src` to `spine-tk2d/Assets/spine-csharp`. 1. Open the `spine-tk2d/Assets/examples/spineboy/spineboy.unity` scene file using Unity 4.2+. -1. Import 2D Toolkit into the project. +1. Import 2D Toolkit into the example project. +To use spine-tk2d in your own Unity project: + +1. Copy the contents of `spine-csharp/src` to `Assets/spine-csharp` in your project. +1. Copy the `spine-tk2d/Assets/spine-tk2d` to `Assets/spine-tk2d` in your project. +1. Import 2D Toolkit into your project. ## Examples diff --git a/spine-unity/Assets/spine-unity.meta b/spine-unity/Assets/spine-unity.meta new file mode 100644 index 000000000..f89227fa1 --- /dev/null +++ b/spine-unity/Assets/spine-unity.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 29a3535756b284a428d35dcd4327185e +folderAsset: yes +DefaultImporter: + userData: diff --git a/spine-unity/Assets/Spine/AtlasAsset.cs b/spine-unity/Assets/spine-unity/AtlasAsset.cs similarity index 100% rename from spine-unity/Assets/Spine/AtlasAsset.cs rename to spine-unity/Assets/spine-unity/AtlasAsset.cs diff --git a/spine-unity/Assets/Spine/AtlasAsset.cs.meta b/spine-unity/Assets/spine-unity/AtlasAsset.cs.meta similarity index 100% rename from spine-unity/Assets/Spine/AtlasAsset.cs.meta rename to spine-unity/Assets/spine-unity/AtlasAsset.cs.meta diff --git a/spine-unity/Assets/Spine/BoneComponent.cs b/spine-unity/Assets/spine-unity/BoneComponent.cs similarity index 100% rename from spine-unity/Assets/Spine/BoneComponent.cs rename to spine-unity/Assets/spine-unity/BoneComponent.cs diff --git a/spine-unity/Assets/Spine/BoneComponent.cs.meta b/spine-unity/Assets/spine-unity/BoneComponent.cs.meta similarity index 100% rename from spine-unity/Assets/Spine/BoneComponent.cs.meta rename to spine-unity/Assets/spine-unity/BoneComponent.cs.meta diff --git a/spine-unity/Assets/Spine/Editor.meta b/spine-unity/Assets/spine-unity/Editor.meta similarity index 100% rename from spine-unity/Assets/Spine/Editor.meta rename to spine-unity/Assets/spine-unity/Editor.meta diff --git a/spine-unity/Assets/Spine/Editor/AtlasAssetInspector.cs b/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs similarity index 100% rename from spine-unity/Assets/Spine/Editor/AtlasAssetInspector.cs rename to spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs diff --git a/spine-unity/Assets/Spine/Editor/AtlasAssetInspector.cs.meta b/spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs.meta similarity index 100% rename from spine-unity/Assets/Spine/Editor/AtlasAssetInspector.cs.meta rename to spine-unity/Assets/spine-unity/Editor/AtlasAssetInspector.cs.meta diff --git a/spine-unity/Assets/Spine/Editor/BoneComponentInspector.cs b/spine-unity/Assets/spine-unity/Editor/BoneComponentInspector.cs similarity index 100% rename from spine-unity/Assets/Spine/Editor/BoneComponentInspector.cs rename to spine-unity/Assets/spine-unity/Editor/BoneComponentInspector.cs diff --git a/spine-unity/Assets/Spine/Editor/BoneComponentInspector.cs.meta b/spine-unity/Assets/spine-unity/Editor/BoneComponentInspector.cs.meta similarity index 100% rename from spine-unity/Assets/Spine/Editor/BoneComponentInspector.cs.meta rename to spine-unity/Assets/spine-unity/Editor/BoneComponentInspector.cs.meta diff --git a/spine-unity/Assets/Spine/Editor/Menus.cs b/spine-unity/Assets/spine-unity/Editor/Menus.cs similarity index 100% rename from spine-unity/Assets/Spine/Editor/Menus.cs rename to spine-unity/Assets/spine-unity/Editor/Menus.cs diff --git a/spine-unity/Assets/Spine/Editor/Menus.cs.meta b/spine-unity/Assets/spine-unity/Editor/Menus.cs.meta similarity index 100% rename from spine-unity/Assets/Spine/Editor/Menus.cs.meta rename to spine-unity/Assets/spine-unity/Editor/Menus.cs.meta diff --git a/spine-unity/Assets/Spine/Editor/SkeletonAnimationInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs similarity index 100% rename from spine-unity/Assets/Spine/Editor/SkeletonAnimationInspector.cs rename to spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs diff --git a/spine-unity/Assets/Spine/Editor/SkeletonAnimationInspector.cs.meta b/spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs.meta similarity index 100% rename from spine-unity/Assets/Spine/Editor/SkeletonAnimationInspector.cs.meta rename to spine-unity/Assets/spine-unity/Editor/SkeletonAnimationInspector.cs.meta diff --git a/spine-unity/Assets/Spine/Editor/SkeletonDataAssetInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs similarity index 100% rename from spine-unity/Assets/Spine/Editor/SkeletonDataAssetInspector.cs rename to spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs diff --git a/spine-unity/Assets/Spine/Editor/SkeletonDataAssetInspector.cs.meta b/spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs.meta similarity index 100% rename from spine-unity/Assets/Spine/Editor/SkeletonDataAssetInspector.cs.meta rename to spine-unity/Assets/spine-unity/Editor/SkeletonDataAssetInspector.cs.meta diff --git a/spine-unity/Assets/Spine/Editor/SkeletonRendererInspector.cs b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs similarity index 100% rename from spine-unity/Assets/Spine/Editor/SkeletonRendererInspector.cs rename to spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs diff --git a/spine-unity/Assets/Spine/Editor/SkeletonRendererInspector.cs.meta b/spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs.meta similarity index 100% rename from spine-unity/Assets/Spine/Editor/SkeletonRendererInspector.cs.meta rename to spine-unity/Assets/spine-unity/Editor/SkeletonRendererInspector.cs.meta diff --git a/spine-unity/Assets/Spine/Shaders.meta b/spine-unity/Assets/spine-unity/Shaders.meta similarity index 100% rename from spine-unity/Assets/Spine/Shaders.meta rename to spine-unity/Assets/spine-unity/Shaders.meta diff --git a/spine-unity/Assets/Spine/Shaders/Skeleton.shader b/spine-unity/Assets/spine-unity/Shaders/Skeleton.shader similarity index 100% rename from spine-unity/Assets/Spine/Shaders/Skeleton.shader rename to spine-unity/Assets/spine-unity/Shaders/Skeleton.shader diff --git a/spine-unity/Assets/Spine/Shaders/Skeleton.shader.meta b/spine-unity/Assets/spine-unity/Shaders/Skeleton.shader.meta similarity index 100% rename from spine-unity/Assets/Spine/Shaders/Skeleton.shader.meta rename to spine-unity/Assets/spine-unity/Shaders/Skeleton.shader.meta diff --git a/spine-unity/Assets/Spine/Shaders/SkeletonLit.shader b/spine-unity/Assets/spine-unity/Shaders/SkeletonLit.shader similarity index 100% rename from spine-unity/Assets/Spine/Shaders/SkeletonLit.shader rename to spine-unity/Assets/spine-unity/Shaders/SkeletonLit.shader diff --git a/spine-unity/Assets/Spine/Shaders/SkeletonLit.shader.meta b/spine-unity/Assets/spine-unity/Shaders/SkeletonLit.shader.meta similarity index 100% rename from spine-unity/Assets/Spine/Shaders/SkeletonLit.shader.meta rename to spine-unity/Assets/spine-unity/Shaders/SkeletonLit.shader.meta diff --git a/spine-unity/Assets/Spine/SkeletonAnimation.cs b/spine-unity/Assets/spine-unity/SkeletonAnimation.cs similarity index 100% rename from spine-unity/Assets/Spine/SkeletonAnimation.cs rename to spine-unity/Assets/spine-unity/SkeletonAnimation.cs diff --git a/spine-unity/Assets/Spine/SkeletonAnimation.cs.meta b/spine-unity/Assets/spine-unity/SkeletonAnimation.cs.meta similarity index 100% rename from spine-unity/Assets/Spine/SkeletonAnimation.cs.meta rename to spine-unity/Assets/spine-unity/SkeletonAnimation.cs.meta diff --git a/spine-unity/Assets/Spine/SkeletonDataAsset.cs b/spine-unity/Assets/spine-unity/SkeletonDataAsset.cs similarity index 100% rename from spine-unity/Assets/Spine/SkeletonDataAsset.cs rename to spine-unity/Assets/spine-unity/SkeletonDataAsset.cs diff --git a/spine-unity/Assets/Spine/SkeletonDataAsset.cs.meta b/spine-unity/Assets/spine-unity/SkeletonDataAsset.cs.meta similarity index 100% rename from spine-unity/Assets/Spine/SkeletonDataAsset.cs.meta rename to spine-unity/Assets/spine-unity/SkeletonDataAsset.cs.meta diff --git a/spine-unity/Assets/Spine/SkeletonRenderer.cs b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs similarity index 100% rename from spine-unity/Assets/Spine/SkeletonRenderer.cs rename to spine-unity/Assets/spine-unity/SkeletonRenderer.cs diff --git a/spine-unity/Assets/Spine/SkeletonRenderer.cs.meta b/spine-unity/Assets/spine-unity/SkeletonRenderer.cs.meta similarity index 100% rename from spine-unity/Assets/Spine/SkeletonRenderer.cs.meta rename to spine-unity/Assets/spine-unity/SkeletonRenderer.cs.meta diff --git a/spine-unity/README.md b/spine-unity/README.md index e9cc6e81d..31325cb12 100644 --- a/spine-unity/README.md +++ b/spine-unity/README.md @@ -6,10 +6,17 @@ A Spine skeleton is a GameObject and can be used throughout Unity like any other ## Setup +To run the examples: + 1. Download the Spine Runtimes source using [git](https://help.github.com/articles/set-up-git) or by downloading it [as a zip](https://github.com/EsotericSoftware/spine-runtimes/archive/master.zip). -1. Copy the contents of `spine-csharp/src` to `spine-unity/Assets/Spine/spine-csharp`. +1. Copy the contents of `spine-csharp/src` to `spine-unity/Assets/spine-csharp`. 1. Open an example scene file from `spine-unity/Assets/examples/` using Unity 4.2+. +To use spine-unity in your own Unity project: + +1. Copy the contents of `spine-csharp/src` to `Assets/spine-csharp` in your project. +1. Copy the `spine-unity/Assets/spine-unity` to `Assets/spine-unity` in your project. + ## Examples * **spineboy** This shows the spineboy skeleton. First an animation is played that shows the draw order changing and events firing, then spineboy jumps and walks. Click spineboy to jump again. Notice the walk and jump animations are mixed and transition smoothly. The white cube on spineboy's right hand is a separate GameObject that is positioned using a `BoneComponent`. This example uses images that are split across two atlas pages. This demonstrates a multi-page atlas, but of course has a high number of draw calls.