mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +08:00
Committed spine-c into spine-unity.
Screw it, it's easier for Unity people.
This commit is contained in:
parent
803a8ab045
commit
4a4098ed45
415
spine-unity/Assets/Plugins/Spine/spine-csharp/Animation.cs
Normal file
415
spine-unity/Assets/Plugins/Spine/spine-csharp/Animation.cs
Normal file
@ -0,0 +1,415 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 {
|
||||||
|
public String Name { get; private set; }
|
||||||
|
public List<Timeline> Timelines { get; set; }
|
||||||
|
public float Duration { get; set; }
|
||||||
|
|
||||||
|
public Animation (String name, List<Timeline> timelines, float duration) {
|
||||||
|
if (name == null) throw new ArgumentNullException("name cannot be null.");
|
||||||
|
if (timelines == null) throw new ArgumentNullException("timelines cannot be null.");
|
||||||
|
Name = name;
|
||||||
|
Timelines = timelines;
|
||||||
|
Duration = duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Poses the skeleton at the specified time for this animation. */
|
||||||
|
public void Apply (Skeleton skeleton, float time, bool loop) {
|
||||||
|
if (skeleton == null) throw new ArgumentNullException("skeleton cannot be null.");
|
||||||
|
|
||||||
|
if (loop && Duration != 0) time %= Duration;
|
||||||
|
|
||||||
|
List<Timeline> timelines = Timelines;
|
||||||
|
for (int i = 0, n = timelines.Count; i < n; i++)
|
||||||
|
timelines[i].Apply(skeleton, time, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Poses the skeleton at the specified time for this animation mixed with the current pose.
|
||||||
|
* @param alpha The amount of this animation that affects the current pose. */
|
||||||
|
public void Mix (Skeleton skeleton, float time, bool loop, float alpha) {
|
||||||
|
if (skeleton == null) throw new ArgumentNullException("skeleton cannot be null.");
|
||||||
|
|
||||||
|
if (loop && Duration != 0) time %= Duration;
|
||||||
|
|
||||||
|
List<Timeline> timelines = Timelines;
|
||||||
|
for (int i = 0, n = timelines.Count; i < n; i++)
|
||||||
|
timelines[i].Apply(skeleton, time, alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param target 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 time, 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 time, 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;
|
||||||
|
|
||||||
|
public int BoneIndex { get; set; }
|
||||||
|
public float[] Frames { get; private set; } // 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 time, float alpha) {
|
||||||
|
float[] frames = 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;
|
||||||
|
|
||||||
|
public int BoneIndex { get; set; }
|
||||||
|
public float[] Frames { get; private set; } // 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 time, float alpha) {
|
||||||
|
float[] frames = 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 time, float alpha) {
|
||||||
|
float[] frames = 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;
|
||||||
|
|
||||||
|
public int SlotIndex { get; set; }
|
||||||
|
public float[] Frames { get; private set; } // 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 time, float alpha) {
|
||||||
|
float[] frames = Frames;
|
||||||
|
if (time < frames[0]) return; // Time is before first frame.
|
||||||
|
|
||||||
|
Slot slot = skeleton.Slots[SlotIndex];
|
||||||
|
|
||||||
|
if (time >= frames[frames.Length - 5]) { // Time is after last frame.
|
||||||
|
int i = frames.Length - 1;
|
||||||
|
slot.R = frames[i - 3];
|
||||||
|
slot.G = frames[i - 2];
|
||||||
|
slot.B = frames[i - 1];
|
||||||
|
slot.A = frames[i];
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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));
|
||||||
|
|
||||||
|
float r = lastFrameR + (frames[frameIndex + FRAME_R] - lastFrameR) * percent;
|
||||||
|
float g = lastFrameG + (frames[frameIndex + FRAME_G] - lastFrameG) * percent;
|
||||||
|
float b = lastFrameB + (frames[frameIndex + FRAME_B] - lastFrameB) * percent;
|
||||||
|
float 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 {
|
||||||
|
public int SlotIndex { get; set; }
|
||||||
|
public float[] Frames { get; private set; } // time, ...
|
||||||
|
public String[] AttachmentNames { get; private set; }
|
||||||
|
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 time, float alpha) {
|
||||||
|
float[] frames = 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
101
spine-unity/Assets/Plugins/Spine/spine-csharp/AnimationState.cs
Normal file
101
spine-unity/Assets/Plugins/Spine/spine-csharp/AnimationState.cs
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 AnimationState {
|
||||||
|
public AnimationStateData Data { get; private set; }
|
||||||
|
public Animation Animation { get; private set; }
|
||||||
|
public float Time { get; set; }
|
||||||
|
public bool Loop { get; set; }
|
||||||
|
private Animation previous;
|
||||||
|
float previousTime;
|
||||||
|
bool previousLoop;
|
||||||
|
float mixTime, mixDuration;
|
||||||
|
|
||||||
|
public AnimationState (AnimationStateData data) {
|
||||||
|
if (data == null) throw new ArgumentNullException("data cannot be null.");
|
||||||
|
Data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Update (float delta) {
|
||||||
|
Time += delta;
|
||||||
|
previousTime += delta;
|
||||||
|
mixTime += delta;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Apply (Skeleton skeleton) {
|
||||||
|
if (Animation == null) return;
|
||||||
|
if (previous != null) {
|
||||||
|
previous.Apply(skeleton, previousTime, previousLoop);
|
||||||
|
float alpha = mixTime / mixDuration;
|
||||||
|
if (alpha >= 1) {
|
||||||
|
alpha = 1;
|
||||||
|
previous = null;
|
||||||
|
}
|
||||||
|
Animation.Mix(skeleton, Time, Loop, alpha);
|
||||||
|
} else
|
||||||
|
Animation.Apply(skeleton, Time, Loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAnimation (String animationName, bool loop) {
|
||||||
|
Animation animation = Data.SkeletonData.FindAnimation(animationName);
|
||||||
|
if (animation == null) throw new ArgumentException("Animation not found: " + animationName);
|
||||||
|
SetAnimation(animation, loop);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetAnimation (Animation animation, bool loop) {
|
||||||
|
previous = null;
|
||||||
|
if (animation != null && Animation != null) {
|
||||||
|
mixDuration = Data.GetMix(Animation, animation);
|
||||||
|
if (mixDuration > 0) {
|
||||||
|
mixTime = 0;
|
||||||
|
previous = Animation;
|
||||||
|
previousTime = Time;
|
||||||
|
previousLoop = Loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Animation = animation;
|
||||||
|
Loop = loop;
|
||||||
|
Time = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearAnimation () {
|
||||||
|
previous = null;
|
||||||
|
Animation = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns true if no animation is set or if the current time is greater than the animation duration, regardless of looping. */
|
||||||
|
public bool isComplete () {
|
||||||
|
return Animation == null || Time >= Animation.Duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
override public String ToString () {
|
||||||
|
return (Animation != null && Animation.Name != null) ? Animation.Name : base.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,61 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 {
|
||||||
|
public SkeletonData SkeletonData { get; private set; }
|
||||||
|
private Dictionary<KeyValuePair<Animation, Animation>, float> animationToMixTime = new Dictionary<KeyValuePair<Animation, Animation>, float>();
|
||||||
|
|
||||||
|
public AnimationStateData (SkeletonData skeletonData) {
|
||||||
|
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<Animation, Animation> key = new KeyValuePair<Animation, Animation>(from, to);
|
||||||
|
animationToMixTime.Remove(key);
|
||||||
|
animationToMixTime.Add(key, duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public float GetMix (Animation from, Animation to) {
|
||||||
|
KeyValuePair<Animation, Animation> key = new KeyValuePair<Animation, Animation>(from, to);
|
||||||
|
float duration;
|
||||||
|
animationToMixTime.TryGetValue(key, out duration);
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
229
spine-unity/Assets/Plugins/Spine/spine-csharp/Atlas.cs
Normal file
229
spine-unity/Assets/Plugins/Spine/spine-csharp/Atlas.cs
Normal file
@ -0,0 +1,229 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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;
|
||||||
|
|
||||||
|
namespace Spine {
|
||||||
|
public class Atlas {
|
||||||
|
List<AtlasPage> pages = new List<AtlasPage>();
|
||||||
|
List<AtlasRegion> regions = new List<AtlasRegion>();
|
||||||
|
TextureLoader textureLoader;
|
||||||
|
|
||||||
|
public Atlas (String path, TextureLoader textureLoader) {
|
||||||
|
using (StreamReader reader = new StreamReader(path)) {
|
||||||
|
try {
|
||||||
|
Load(reader, Path.GetDirectoryName(path), textureLoader);
|
||||||
|
} catch (Exception ex) {
|
||||||
|
throw new Exception("Error reading atlas file: " + path, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Atlas (TextReader reader, String dir, TextureLoader textureLoader) {
|
||||||
|
Load(reader, dir, textureLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
page.format = (Format)Enum.Parse(typeof(Format), readValue(reader), false);
|
||||||
|
|
||||||
|
readTuple(reader, tuple);
|
||||||
|
page.minFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[0]);
|
||||||
|
page.magFilter = (TextureFilter)Enum.Parse(typeof(TextureFilter), tuple[1]);
|
||||||
|
|
||||||
|
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;
|
||||||
|
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 (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) {
|
||||||
|
if (i == 0) throw new Exception("Invalid line: " + line);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
tuple[i] = line.Substring(lastMatch, comma - lastMatch).Trim();
|
||||||
|
lastMatch = comma + 1;
|
||||||
|
}
|
||||||
|
tuple[i] = line.Substring(lastMatch).Trim();
|
||||||
|
return i + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 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.
|
||||||
|
* @return 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 () {
|
||||||
|
for (int i = 0, n = pages.Count; i < n; i++)
|
||||||
|
textureLoader.Unload(pages[i].texture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 texture;
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,49 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 Attachment NewAttachment (Skin skin, AttachmentType type, String name) {
|
||||||
|
switch (type) {
|
||||||
|
case AttachmentType.region:
|
||||||
|
AtlasRegion region = atlas.FindRegion(name);
|
||||||
|
if (region == null) throw new Exception("Region not found in atlas: " + name + " (" + type + ")");
|
||||||
|
RegionAttachment attachment = new RegionAttachment(name);
|
||||||
|
attachment.Region = region;
|
||||||
|
return attachment;
|
||||||
|
}
|
||||||
|
throw new Exception("Unknown attachment type: " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,41 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 {
|
||||||
|
/** @return May be null to not load any attachment. */
|
||||||
|
Attachment NewAttachment (Skin skin, AttachmentType type, String name);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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, regionSequence
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,130 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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;
|
||||||
|
|
||||||
|
public float X { get; set; }
|
||||||
|
public float Y { get; set; }
|
||||||
|
public float ScaleX { get; set; }
|
||||||
|
public float ScaleY { get; set; }
|
||||||
|
public float Rotation { get; set; }
|
||||||
|
public float Width { get; set; }
|
||||||
|
public float Height { get; set; }
|
||||||
|
|
||||||
|
public float[] Offset { get; private set; }
|
||||||
|
public float[] Vertices { get; private set; }
|
||||||
|
public AtlasRegion Region { get; set; }
|
||||||
|
|
||||||
|
public RegionAttachment (string name)
|
||||||
|
: base(name) {
|
||||||
|
Offset = new float[8];
|
||||||
|
Vertices = new float[8];
|
||||||
|
ScaleX = 1;
|
||||||
|
ScaleY = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateOffset () {
|
||||||
|
float width = Width;
|
||||||
|
float height = Height;
|
||||||
|
float localX2 = width / 2;
|
||||||
|
float localY2 = height / 2;
|
||||||
|
float localX = -localX2;
|
||||||
|
float localY = -localY2;
|
||||||
|
AtlasRegion region = Region;
|
||||||
|
if (region != null) {
|
||||||
|
if (region.rotate) {
|
||||||
|
localX += region.offsetX / region.originalWidth * height;
|
||||||
|
localY += region.offsetY / region.originalHeight * width;
|
||||||
|
localX2 -= (region.originalWidth - region.offsetX - region.height) / region.originalWidth * width;
|
||||||
|
localY2 -= (region.originalHeight - region.offsetY - region.width) / region.originalHeight * height;
|
||||||
|
} else {
|
||||||
|
localX += region.offsetX / region.originalWidth * width;
|
||||||
|
localY += region.offsetY / region.originalHeight * height;
|
||||||
|
localX2 -= (region.originalWidth - region.offsetX - region.width) / region.originalWidth * width;
|
||||||
|
localY2 -= (region.originalHeight - region.offsetY - region.height) / region.originalHeight * height;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
float scaleX = ScaleX;
|
||||||
|
float scaleY = ScaleY;
|
||||||
|
localX *= scaleX;
|
||||||
|
localY *= scaleY;
|
||||||
|
localX2 *= scaleX;
|
||||||
|
localY2 *= scaleY;
|
||||||
|
float radians = Rotation * (float)Math.PI / 180;
|
||||||
|
float cos = (float)Math.Cos(radians);
|
||||||
|
float sin = (float)Math.Sin(radians);
|
||||||
|
float x = X;
|
||||||
|
float y = 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 = 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 UpdateVertices (Bone bone) {
|
||||||
|
float x = bone.WorldX;
|
||||||
|
float y = bone.WorldY;
|
||||||
|
float m00 = bone.M00;
|
||||||
|
float m01 = bone.M01;
|
||||||
|
float m10 = bone.M10;
|
||||||
|
float m11 = bone.M11;
|
||||||
|
float[] vertices = Vertices;
|
||||||
|
float[] offset = Offset;
|
||||||
|
vertices[X1] = offset[X1] * m00 + offset[Y1] * m01 + x;
|
||||||
|
vertices[Y1] = offset[X1] * m10 + offset[Y1] * m11 + y;
|
||||||
|
vertices[X2] = offset[X2] * m00 + offset[Y2] * m01 + x;
|
||||||
|
vertices[Y2] = offset[X2] * m10 + offset[Y2] * m11 + y;
|
||||||
|
vertices[X3] = offset[X3] * m00 + offset[Y3] * m01 + x;
|
||||||
|
vertices[Y3] = offset[X3] * m10 + offset[Y3] * m11 + y;
|
||||||
|
vertices[X4] = offset[X4] * m00 + offset[Y4] * m01 + x;
|
||||||
|
vertices[Y4] = offset[X4] * m10 + offset[Y4] * m11 + y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
108
spine-unity/Assets/Plugins/Spine/spine-csharp/Bone.cs
Normal file
108
spine-unity/Assets/Plugins/Spine/spine-csharp/Bone.cs
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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;
|
||||||
|
|
||||||
|
public BoneData Data { get; private set; }
|
||||||
|
public Bone Parent { get; private set; }
|
||||||
|
public float X { get; set; }
|
||||||
|
public float Y { get; set; }
|
||||||
|
public float Rotation { get; set; }
|
||||||
|
public float ScaleX { get; set; }
|
||||||
|
public float ScaleY { get; set; }
|
||||||
|
|
||||||
|
public float M00 { get; private set; }
|
||||||
|
public float M01 { get; private set; }
|
||||||
|
public float M10 { get; private set; }
|
||||||
|
public float M11 { get; private set; }
|
||||||
|
public float WorldX { get; private set; }
|
||||||
|
public float WorldY { get; private set; }
|
||||||
|
public float WorldRotation { get; private set; }
|
||||||
|
public float WorldScaleX { get; private set; }
|
||||||
|
public float WorldScaleY { get; private set; }
|
||||||
|
|
||||||
|
/** @param parent May be null. */
|
||||||
|
public Bone (BoneData data, Bone parent) {
|
||||||
|
if (data == null) throw new ArgumentNullException("data cannot be null.");
|
||||||
|
Data = data;
|
||||||
|
Parent = parent;
|
||||||
|
SetToBindPose();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Computes the world SRT using the parent bone and the local SRT. */
|
||||||
|
public void UpdateWorldTransform (bool flipX, bool flipY) {
|
||||||
|
Bone parent = Parent;
|
||||||
|
if (parent != null) {
|
||||||
|
WorldX = X * parent.M00 + Y * parent.M01 + parent.WorldX;
|
||||||
|
WorldY = X * parent.M10 + Y * parent.M11 + parent.WorldY;
|
||||||
|
WorldScaleX = parent.WorldScaleX * ScaleX;
|
||||||
|
WorldScaleY = parent.WorldScaleY * ScaleY;
|
||||||
|
WorldRotation = parent.WorldRotation + Rotation;
|
||||||
|
} else {
|
||||||
|
WorldX = X;
|
||||||
|
WorldY = 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) {
|
||||||
|
M10 = -M10;
|
||||||
|
M11 = -M11;
|
||||||
|
}
|
||||||
|
if (yDown) {
|
||||||
|
M10 = -M10;
|
||||||
|
M11 = -M11;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetToBindPose () {
|
||||||
|
BoneData data = Data;
|
||||||
|
X = data.X;
|
||||||
|
Y = data.Y;
|
||||||
|
Rotation = data.Rotation;
|
||||||
|
ScaleX = data.ScaleX;
|
||||||
|
ScaleY = data.ScaleY;
|
||||||
|
}
|
||||||
|
|
||||||
|
override public String ToString () {
|
||||||
|
return Data.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
53
spine-unity/Assets/Plugins/Spine/spine-csharp/BoneData.cs
Normal file
53
spine-unity/Assets/Plugins/Spine/spine-csharp/BoneData.cs
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 {
|
||||||
|
/** May be null. */
|
||||||
|
public BoneData Parent { get; private set; }
|
||||||
|
public String Name { get; private set; }
|
||||||
|
public float Length { get; set; }
|
||||||
|
public float X { get; set; }
|
||||||
|
public float Y { get; set; }
|
||||||
|
public float Rotation { get; set; }
|
||||||
|
public float ScaleX { get; set; }
|
||||||
|
public float ScaleY { get; set; }
|
||||||
|
|
||||||
|
/** @param parent May be null. */
|
||||||
|
public BoneData (String name, BoneData parent) {
|
||||||
|
if (name == null) throw new ArgumentNullException("name cannot be null.");
|
||||||
|
Name = name;
|
||||||
|
Parent = parent;
|
||||||
|
ScaleX = 1;
|
||||||
|
ScaleY = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
override public String ToString () {
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
542
spine-unity/Assets/Plugins/Spine/spine-csharp/Json.cs
Normal file
542
spine-unity/Assets/Plugins/Spine/spine-csharp/Json.cs
Normal file
@ -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<string,object>;
|
||||||
|
//
|
||||||
|
// Debug.Log("deserialized: " + dict.GetType());
|
||||||
|
// Debug.Log("dict['array'][0]: " + ((List<object>) 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);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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.
|
||||||
|
/// </summary>
|
||||||
|
public static class Json {
|
||||||
|
/// <summary>
|
||||||
|
/// Parses the string json into a value
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="json">A JSON string.</param>
|
||||||
|
/// <returns>An List<object>, a Dictionary<string, object>, a float, an integer,a string, null, true, or false</returns>
|
||||||
|
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<string, object> ParseObject() {
|
||||||
|
Dictionary<string, object> table = new Dictionary<string, object>();
|
||||||
|
|
||||||
|
// 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<object> ParseArray() {
|
||||||
|
List<object> array = new List<object>();
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Converts a IDictionary / IList object or a simple type (string, int, etc.) into a JSON string
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="json">A Dictionary<string, object> / List<object></param>
|
||||||
|
/// <returns>A JSON encoded string, or null if object 'json' is not serializable</returns>
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
196
spine-unity/Assets/Plugins/Spine/spine-csharp/Skeleton.cs
Normal file
196
spine-unity/Assets/Plugins/Spine/spine-csharp/Skeleton.cs
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 {
|
||||||
|
public SkeletonData Data { get; private set; }
|
||||||
|
public List<Bone> Bones { get; private set; }
|
||||||
|
public List<Slot> Slots { get; private set; }
|
||||||
|
public List<Slot> DrawOrder { get; private set; }
|
||||||
|
public Skin Skin { get; set; }
|
||||||
|
public float R { get; set; }
|
||||||
|
public float G { get; set; }
|
||||||
|
public float B { get; set; }
|
||||||
|
public float A { get; set; }
|
||||||
|
public float Time { get; set; }
|
||||||
|
public bool FlipX { get; set; }
|
||||||
|
public bool FlipY { get; set; }
|
||||||
|
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.");
|
||||||
|
Data = data;
|
||||||
|
|
||||||
|
Bones = new List<Bone>(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<Slot>(Data.Slots.Count);
|
||||||
|
DrawOrder = new List<Slot>(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);
|
||||||
|
}
|
||||||
|
|
||||||
|
R = 1;
|
||||||
|
G = 1;
|
||||||
|
B = 1;
|
||||||
|
A = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Updates the world transform for each bone. */
|
||||||
|
public void UpdateWorldTransform () {
|
||||||
|
bool flipX = FlipX;
|
||||||
|
bool flipY = FlipY;
|
||||||
|
List<Bone> bones = Bones;
|
||||||
|
for (int i = 0, n = bones.Count; i < n; i++)
|
||||||
|
bones[i].UpdateWorldTransform(flipX, flipY);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the bones and slots to their bind pose values. */
|
||||||
|
public void SetToBindPose () {
|
||||||
|
SetBonesToBindPose();
|
||||||
|
SetSlotsToBindPose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetBonesToBindPose () {
|
||||||
|
List<Bone> bones = this.Bones;
|
||||||
|
for (int i = 0, n = bones.Count; i < n; i++)
|
||||||
|
bones[i].SetToBindPose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetSlotsToBindPose () {
|
||||||
|
List<Slot> slots = this.Slots;
|
||||||
|
for (int i = 0, n = slots.Count; i < n; i++)
|
||||||
|
slots[i].SetToBindPose(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public Bone FindBone (String boneName) {
|
||||||
|
if (boneName == null) throw new ArgumentNullException("boneName cannot be null.");
|
||||||
|
List<Bone> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return -1 if the bone was not found. */
|
||||||
|
public int FindBoneIndex (String boneName) {
|
||||||
|
if (boneName == null) throw new ArgumentNullException("boneName cannot be null.");
|
||||||
|
List<Bone> bones = this.Bones;
|
||||||
|
for (int i = 0, n = bones.Count; i < n; i++)
|
||||||
|
if (bones[i].Data.Name == boneName) return i;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public Slot FindSlot (String slotName) {
|
||||||
|
if (slotName == null) throw new ArgumentNullException("slotName cannot be null.");
|
||||||
|
List<Slot> 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return -1 if the bone was not found. */
|
||||||
|
public int FindSlotIndex (String slotName) {
|
||||||
|
if (slotName == null) throw new ArgumentNullException("slotName cannot be null.");
|
||||||
|
List<Slot> 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(Skin) */
|
||||||
|
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.
|
||||||
|
* @param newSkin May be null. */
|
||||||
|
public void SetSkin (Skin newSkin) {
|
||||||
|
if (Skin != null && newSkin != null) newSkin.AttachAll(this, Skin);
|
||||||
|
Skin = newSkin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public Attachment GetAttachment (String slotName, String attachmentName) {
|
||||||
|
return GetAttachment(Data.FindSlotIndex(slotName), attachmentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @param attachmentName May be null. */
|
||||||
|
public void SetAttachment (String slotName, String attachmentName) {
|
||||||
|
if (slotName == null) throw new ArgumentNullException("slotName cannot be null.");
|
||||||
|
List<Slot> slots = 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 ArgumentNullException("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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
135
spine-unity/Assets/Plugins/Spine/spine-csharp/SkeletonData.cs
Normal file
135
spine-unity/Assets/Plugins/Spine/spine-csharp/SkeletonData.cs
Normal file
@ -0,0 +1,135 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 {
|
||||||
|
public String Name { get; set; }
|
||||||
|
public List<BoneData> Bones { get; private set; } // Ordered parents first.
|
||||||
|
public List<SlotData> Slots { get; private set; } // Bind pose draw order.
|
||||||
|
public List<Skin> Skins { get; private set; }
|
||||||
|
/** May be null. */
|
||||||
|
public Skin DefaultSkin;
|
||||||
|
public List<Animation> Animations { get; private set; }
|
||||||
|
|
||||||
|
public SkeletonData () {
|
||||||
|
Bones = new List<BoneData>();
|
||||||
|
Slots = new List<SlotData>();
|
||||||
|
Skins = new List<Skin>();
|
||||||
|
Animations = new List<Animation>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Bones.
|
||||||
|
|
||||||
|
public void AddBone (BoneData bone) {
|
||||||
|
if (bone == null) throw new ArgumentNullException("bone cannot be null.");
|
||||||
|
Bones.Add(bone);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public BoneData FindBone (String boneName) {
|
||||||
|
if (boneName == null) throw new ArgumentNullException("boneName cannot be null.");
|
||||||
|
for (int i = 0, n = Bones.Count; i < n; i++) {
|
||||||
|
BoneData bone = Bones[i];
|
||||||
|
if (bone.Name == boneName) return bone;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return -1 if the bone was not found. */
|
||||||
|
public int FindBoneIndex (String boneName) {
|
||||||
|
if (boneName == null) throw new ArgumentNullException("boneName cannot be null.");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public SlotData FindSlot (String slotName) {
|
||||||
|
if (slotName == null) throw new ArgumentNullException("slotName cannot be null.");
|
||||||
|
for (int i = 0, n = Slots.Count; i < n; i++) {
|
||||||
|
SlotData slot = Slots[i];
|
||||||
|
if (slot.Name == slotName) return slot;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return -1 if the bone was not found. */
|
||||||
|
public int FindSlotIndex (String slotName) {
|
||||||
|
if (slotName == null) throw new ArgumentNullException("slotName cannot be null.");
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- Animations.
|
||||||
|
|
||||||
|
public void AddAnimation (Animation animation) {
|
||||||
|
if (animation == null) throw new ArgumentNullException("animation cannot be null.");
|
||||||
|
Animations.Add(animation);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public Animation FindAnimation (String animationName) {
|
||||||
|
if (animationName == null) throw new ArgumentNullException("animationName cannot be null.");
|
||||||
|
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 != null ? Name : base.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
302
spine-unity/Assets/Plugins/Spine/spine-csharp/SkeletonJson.cs
Normal file
302
spine-unity/Assets/Plugins/Spine/spine-csharp/SkeletonJson.cs
Normal file
@ -0,0 +1,302 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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;
|
||||||
|
|
||||||
|
namespace Spine {
|
||||||
|
public class SkeletonJson {
|
||||||
|
static public String TIMELINE_SCALE = "scale";
|
||||||
|
static public String TIMELINE_ROTATE = "rotate";
|
||||||
|
static public String TIMELINE_TRANSLATE = "translate";
|
||||||
|
static public String TIMELINE_ATTACHMENT = "attachment";
|
||||||
|
static public String TIMELINE_COLOR = "color";
|
||||||
|
|
||||||
|
static public String ATTACHMENT_REGION = "region";
|
||||||
|
static public String ATTACHMENT_REGION_SEQUENCE = "regionSequence";
|
||||||
|
|
||||||
|
private AttachmentLoader attachmentLoader;
|
||||||
|
public float Scale { get; set; }
|
||||||
|
|
||||||
|
public SkeletonJson (Atlas atlas) {
|
||||||
|
this.attachmentLoader = new AtlasAttachmentLoader(atlas);
|
||||||
|
Scale = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkeletonJson (AttachmentLoader attachmentLoader) {
|
||||||
|
if (attachmentLoader == null) throw new ArgumentNullException("attachmentLoader cannot be null.");
|
||||||
|
this.attachmentLoader = attachmentLoader;
|
||||||
|
Scale = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkeletonData ReadSkeletonData (String path) {
|
||||||
|
using (StreamReader reader = new StreamReader(path)) {
|
||||||
|
SkeletonData skeletonData = ReadSkeletonData(reader);
|
||||||
|
skeletonData.Name = Path.GetFileNameWithoutExtension(path);
|
||||||
|
return skeletonData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SkeletonData ReadSkeletonData (TextReader reader) {
|
||||||
|
if (reader == null) throw new ArgumentNullException("reader cannot be null.");
|
||||||
|
|
||||||
|
SkeletonData skeletonData = new SkeletonData();
|
||||||
|
|
||||||
|
var root = Json.Deserialize(reader) as Dictionary<String, Object>;
|
||||||
|
if (root == null) throw new Exception("Invalid JSON.");
|
||||||
|
|
||||||
|
// Bones.
|
||||||
|
foreach (Dictionary<String, Object> boneMap in (List<Object>)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"]);
|
||||||
|
}
|
||||||
|
BoneData 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);
|
||||||
|
skeletonData.AddBone(boneData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Slots.
|
||||||
|
if (root.ContainsKey("slots")) {
|
||||||
|
var slots = (List<Object>)root["slots"];
|
||||||
|
foreach (Dictionary<String, Object> slotMap in (List<Object>)slots) {
|
||||||
|
String slotName = (String)slotMap["name"];
|
||||||
|
String boneName = (String)slotMap["bone"];
|
||||||
|
BoneData boneData = skeletonData.FindBone(boneName);
|
||||||
|
if (boneData == null)
|
||||||
|
throw new Exception("Slot bone not found: " + boneName);
|
||||||
|
SlotData slotData = new SlotData(slotName, boneData);
|
||||||
|
|
||||||
|
if (slotMap.ContainsKey("color")) {
|
||||||
|
String 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"];
|
||||||
|
|
||||||
|
skeletonData.AddSlot(slotData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skins.
|
||||||
|
if (root.ContainsKey("skins")) {
|
||||||
|
var skinMap = (Dictionary<String, Object>)root["skins"];
|
||||||
|
foreach (KeyValuePair<String, Object> entry in skinMap) {
|
||||||
|
Skin skin = new Skin(entry.Key);
|
||||||
|
foreach (KeyValuePair<String, Object> slotEntry in (Dictionary<String, Object>)entry.Value) {
|
||||||
|
int slotIndex = skeletonData.FindSlotIndex(slotEntry.Key);
|
||||||
|
foreach (KeyValuePair<String, Object> attachmentEntry in ((Dictionary<String, Object>)slotEntry.Value)) {
|
||||||
|
Attachment attachment = ReadAttachment(skin, attachmentEntry.Key, (Dictionary<String, Object>)attachmentEntry.Value);
|
||||||
|
skin.AddAttachment(slotIndex, attachmentEntry.Key, attachment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
skeletonData.AddSkin(skin);
|
||||||
|
if (skin.Name == "default")
|
||||||
|
skeletonData.DefaultSkin = skin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Animations.
|
||||||
|
if (root.ContainsKey("animations")) {
|
||||||
|
var animationMap = (Dictionary<String, Object>)root["animations"];
|
||||||
|
foreach (KeyValuePair<String, Object> entry in animationMap)
|
||||||
|
ReadAnimation(entry.Key, (Dictionary<String, Object>)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<String, Object> map) {
|
||||||
|
if (map.ContainsKey("name"))
|
||||||
|
name = (String)map["name"];
|
||||||
|
|
||||||
|
AttachmentType type = AttachmentType.region;
|
||||||
|
if (map.ContainsKey("type"))
|
||||||
|
type = (AttachmentType)Enum.Parse(typeof(AttachmentType), (String)map["type"], false);
|
||||||
|
Attachment attachment = attachmentLoader.NewAttachment(skin, type, name);
|
||||||
|
|
||||||
|
if (attachment is RegionAttachment) {
|
||||||
|
RegionAttachment regionAttachment = (RegionAttachment)attachment;
|
||||||
|
regionAttachment.X = GetFloat(map, "x", 0) * Scale;
|
||||||
|
regionAttachment.Y = GetFloat(map, "y", 0) * Scale;
|
||||||
|
regionAttachment.ScaleX = GetFloat(map, "scaleX", 1);
|
||||||
|
regionAttachment.ScaleY = GetFloat(map, "scaleY", 1);
|
||||||
|
regionAttachment.Rotation = GetFloat(map, "rotation", 0);
|
||||||
|
regionAttachment.Width = GetFloat(map, "width", 32) * Scale;
|
||||||
|
regionAttachment.Height = GetFloat(map, "height", 32) * Scale;
|
||||||
|
regionAttachment.UpdateOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
return attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
private float GetFloat (Dictionary<String, Object> map, String name, float defaultValue) {
|
||||||
|
if (!map.ContainsKey(name))
|
||||||
|
return (float)defaultValue;
|
||||||
|
return (float)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<String, Object> map, SkeletonData skeletonData) {
|
||||||
|
var timelines = new List<Timeline>();
|
||||||
|
float duration = 0;
|
||||||
|
|
||||||
|
if (map.ContainsKey("bones")) {
|
||||||
|
var bonesMap = (Dictionary<String, Object>)map["bones"];
|
||||||
|
foreach (KeyValuePair<String, Object> entry in bonesMap) {
|
||||||
|
String boneName = entry.Key;
|
||||||
|
int boneIndex = skeletonData.FindBoneIndex(boneName);
|
||||||
|
if (boneIndex == -1)
|
||||||
|
throw new Exception("Bone not found: " + boneName);
|
||||||
|
|
||||||
|
var timelineMap = (Dictionary<String, Object>)entry.Value;
|
||||||
|
foreach (KeyValuePair<String, Object> timelineEntry in timelineMap) {
|
||||||
|
var values = (List<Object>)timelineEntry.Value;
|
||||||
|
String timelineName = (String)timelineEntry.Key;
|
||||||
|
if (timelineName.Equals(TIMELINE_ROTATE)) {
|
||||||
|
RotateTimeline timeline = new RotateTimeline(values.Count);
|
||||||
|
timeline.BoneIndex = boneIndex;
|
||||||
|
|
||||||
|
int frameIndex = 0;
|
||||||
|
foreach (Dictionary<String, Object> 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(TIMELINE_TRANSLATE) || timelineName.Equals(TIMELINE_SCALE)) {
|
||||||
|
TranslateTimeline timeline;
|
||||||
|
float timelineScale = 1;
|
||||||
|
if (timelineName.Equals(TIMELINE_SCALE))
|
||||||
|
timeline = new ScaleTimeline(values.Count);
|
||||||
|
else {
|
||||||
|
timeline = new TranslateTimeline(values.Count);
|
||||||
|
timelineScale = Scale;
|
||||||
|
}
|
||||||
|
timeline.BoneIndex = boneIndex;
|
||||||
|
|
||||||
|
int frameIndex = 0;
|
||||||
|
foreach (Dictionary<String, Object> 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("slots")) {
|
||||||
|
var slotsMap = (Dictionary<String, Object>)map["slots"];
|
||||||
|
foreach (KeyValuePair<String, Object> entry in slotsMap) {
|
||||||
|
String slotName = entry.Key;
|
||||||
|
int slotIndex = skeletonData.FindSlotIndex(slotName);
|
||||||
|
var timelineMap = (Dictionary<String, Object>)entry.Value;
|
||||||
|
|
||||||
|
foreach (KeyValuePair<String, Object> timelineEntry in timelineMap) {
|
||||||
|
var values = (List<Object>)timelineEntry.Value;
|
||||||
|
String timelineName = (String)timelineEntry.Key;
|
||||||
|
if (timelineName.Equals(TIMELINE_COLOR)) {
|
||||||
|
ColorTimeline timeline = new ColorTimeline(values.Count);
|
||||||
|
timeline.SlotIndex = slotIndex;
|
||||||
|
|
||||||
|
int frameIndex = 0;
|
||||||
|
foreach (Dictionary<String, Object> 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(TIMELINE_ATTACHMENT)) {
|
||||||
|
AttachmentTimeline timeline = new AttachmentTimeline(values.Count);
|
||||||
|
timeline.SlotIndex = slotIndex;
|
||||||
|
|
||||||
|
int frameIndex = 0;
|
||||||
|
foreach (Dictionary<String, Object> 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 + ")");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
timelines.TrimExcess();
|
||||||
|
skeletonData.AddAnimation(new Animation(name, timelines, duration));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReadCurve (CurveTimeline timeline, int frameIndex, Dictionary<String, Object> valueMap) {
|
||||||
|
if (!valueMap.ContainsKey("curve"))
|
||||||
|
return;
|
||||||
|
Object curveObject = valueMap["curve"];
|
||||||
|
if (curveObject.Equals("stepped"))
|
||||||
|
timeline.SetStepped(frameIndex);
|
||||||
|
else if (curveObject is List<Object>) {
|
||||||
|
List<Object> curve = (List<Object>)curveObject;
|
||||||
|
timeline.SetCurve(frameIndex, (float)curve[0], (float)curve[1], (float)curve[2], (float)curve[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
80
spine-unity/Assets/Plugins/Spine/spine-csharp/Skin.cs
Normal file
80
spine-unity/Assets/Plugins/Spine/spine-csharp/Skin.cs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 {
|
||||||
|
public String Name { get; private set; }
|
||||||
|
private Dictionary<KeyValuePair<int, String>, Attachment> attachments = new Dictionary<KeyValuePair<int, String>, Attachment>();
|
||||||
|
|
||||||
|
public Skin (String name) {
|
||||||
|
if (name == null) throw new ArgumentNullException("name cannot be null.");
|
||||||
|
Name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddAttachment (int slotIndex, String name, Attachment attachment) {
|
||||||
|
if (attachment == null) throw new ArgumentNullException("attachment cannot be null.");
|
||||||
|
attachments.Add(new KeyValuePair<int, String>(slotIndex, name), attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @return May be null. */
|
||||||
|
public Attachment GetAttachment (int slotIndex, String name) {
|
||||||
|
Attachment attachment;
|
||||||
|
attachments.TryGetValue(new KeyValuePair<int, String>(slotIndex, name), out attachment);
|
||||||
|
return attachment;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FindNamesForSlot (int slotIndex, List<String> names) {
|
||||||
|
if (names == null) throw new ArgumentNullException("names cannot be null.");
|
||||||
|
foreach (KeyValuePair<int, String> key in attachments.Keys)
|
||||||
|
if (key.Key == slotIndex) names.Add(key.Value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void FindAttachmentsForSlot (int slotIndex, List<Attachment> attachments) {
|
||||||
|
if (attachments == null) throw new ArgumentNullException("attachments cannot be null.");
|
||||||
|
foreach (KeyValuePair<KeyValuePair<int, String>, 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<KeyValuePair<int, String>, 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
86
spine-unity/Assets/Plugins/Spine/spine-csharp/Slot.cs
Normal file
86
spine-unity/Assets/Plugins/Spine/spine-csharp/Slot.cs
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 {
|
||||||
|
public SlotData Data { get; private set; }
|
||||||
|
public Bone Bone { get; private set; }
|
||||||
|
public Skeleton Skeleton { get; private set; }
|
||||||
|
public float R { get; set; }
|
||||||
|
public float G { get; set; }
|
||||||
|
public float B { get; set; }
|
||||||
|
public float A { get; set; }
|
||||||
|
|
||||||
|
/** May be null. */
|
||||||
|
private Attachment attachment;
|
||||||
|
public Attachment Attachment {
|
||||||
|
get {
|
||||||
|
return attachment;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
attachment = value;
|
||||||
|
attachmentTime = Skeleton.Time;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private float attachmentTime;
|
||||||
|
public float AttachmentTime {
|
||||||
|
get {
|
||||||
|
return Skeleton.Time - attachmentTime;
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
attachmentTime = Skeleton.Time - 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.");
|
||||||
|
Data = data;
|
||||||
|
Skeleton = skeleton;
|
||||||
|
Bone = bone;
|
||||||
|
SetToBindPose();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void SetToBindPose (int slotIndex) {
|
||||||
|
R = Data.R;
|
||||||
|
G = Data.G;
|
||||||
|
B = Data.B;
|
||||||
|
A = Data.A;
|
||||||
|
Attachment = Data.AttachmentName == null ? null : Skeleton.GetAttachment(slotIndex, Data.AttachmentName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetToBindPose () {
|
||||||
|
SetToBindPose(Skeleton.Data.Slots.IndexOf(Data));
|
||||||
|
}
|
||||||
|
|
||||||
|
override public String ToString () {
|
||||||
|
return Data.Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
54
spine-unity/Assets/Plugins/Spine/spine-csharp/SlotData.cs
Normal file
54
spine-unity/Assets/Plugins/Spine/spine-csharp/SlotData.cs
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (c) 2013, Esoteric Software
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER OR CONTRIBUTORS 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 {
|
||||||
|
public String Name { get; private set; }
|
||||||
|
public BoneData BoneData { get; private set; }
|
||||||
|
public float R { get; set; }
|
||||||
|
public float G { get; set; }
|
||||||
|
public float B { get; set; }
|
||||||
|
public float A { get; set; }
|
||||||
|
/** @param attachmentName May be null. */
|
||||||
|
public String AttachmentName { get; set; }
|
||||||
|
|
||||||
|
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.");
|
||||||
|
Name = name;
|
||||||
|
BoneData = boneData;
|
||||||
|
R = 1;
|
||||||
|
G = 1;
|
||||||
|
B = 1;
|
||||||
|
A = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
override public String ToString () {
|
||||||
|
return Name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user