diff --git a/spine-csharp/spine-csharp_xna.csproj b/spine-csharp/spine-csharp_xna.csproj index 514a4cd93..85f5f33ca 100644 --- a/spine-csharp/spine-csharp_xna.csproj +++ b/spine-csharp/spine-csharp_xna.csproj @@ -105,6 +105,8 @@ + + diff --git a/spine-csharp/src/Animation.cs b/spine-csharp/src/Animation.cs index 39d66ba03..b11df2ac2 100644 --- a/spine-csharp/src/Animation.cs +++ b/spine-csharp/src/Animation.cs @@ -98,6 +98,22 @@ namespace Spine { } } + /// After the first and before the last entry. + internal static int binarySearch (float[] values, float target) { + int low = 0; + int high = values.Length - 2; + if (high == 0) return 1; + int current = (int)((uint)high >> 1); + while (true) { + if (values[(current + 1)] <= target) + low = current + 1; + else + high = current; + if (low == high) return (low + 1); + 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; @@ -107,78 +123,51 @@ namespace Spine { public interface Timeline { /// Sets the value(s) for the specified time. - void Apply (Skeleton skeleton, float lastTime, float time, List firedEvents, float alpha); + /// May be null to not collect fired events. + void Apply (Skeleton skeleton, float lastTime, float time, List events, 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; + protected const float LINEAR = 0, STEPPED = 1, BEZIER = 2; + protected const int BEZIER_SEGMENTS = 10, BEZIER_SIZE = BEZIER_SEGMENTS * 2 - 1; - private float[] curves; // dfx, dfy, ddfx, ddfy, dddfx, dddfy, ... - public int FrameCount { get { return curves.Length / 6 + 1; } } + private float[] curves; // type, x, y, ... + public int FrameCount { get { return curves.Length / BEZIER_SIZE + 1; } } public CurveTimeline (int frameCount) { - curves = new float[(frameCount - 1) * 6]; + curves = new float[(frameCount - 1) * BEZIER_SIZE]; } abstract public void Apply (Skeleton skeleton, float lastTime, float time, List firedEvents, float alpha); public void SetLinear (int frameIndex) { - curves[frameIndex * 6] = LINEAR; + curves[frameIndex * BEZIER_SIZE] = LINEAR; } public void SetStepped (int frameIndex) { - curves[frameIndex * 6] = STEPPED; + curves[frameIndex * BEZIER_SIZE] = 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; - } + float subdiv1 = 1f / BEZIER_SEGMENTS, subdiv2 = subdiv1 * subdiv1, subdiv3 = subdiv2 * subdiv1; + float pre1 = 3 * subdiv1, pre2 = 3 * subdiv2, pre4 = 6 * subdiv2, pre5 = 6 * subdiv3; + float tmp1x = -cx1 * 2 + cx2, tmp1y = -cy1 * 2 + cy2, tmp2x = (cx1 - cx2) * 3 + 1, tmp2y = (cy1 - cy2) * 3 + 1; + float dfx = cx1 * pre1 + tmp1x * pre2 + tmp2x * subdiv3, dfy = cy1 * pre1 + tmp1y * pre2 + tmp2y * subdiv3; + float ddfx = tmp1x * pre4 + tmp2x * pre5, ddfy = tmp1y * pre4 + tmp2y * pre5; + float dddfx = tmp2x * pre5, dddfy = tmp2y * pre5; - public float GetCurvePercent (int frameIndex, float percent) { - int curveIndex = frameIndex * 6; + int i = frameIndex * BEZIER_SIZE; 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]; + curves[i++] = BEZIER; + 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--; + for (int n = i + BEZIER_SIZE - 1; i < n; i += 2) { + curves[i] = x; + curves[i + 1] = y; dfx += ddfx; dfy += ddfy; ddfx += dddfx; @@ -186,13 +175,38 @@ namespace Spine { x += dfx; y += dfy; } + } + + public float GetCurvePercent (int frameIndex, float percent) { + float[] curves = this.curves; + int i = frameIndex * BEZIER_SIZE; + float type = curves[i]; + if (type == LINEAR) return percent; + if (type == STEPPED) return 0; + i++; + float x = 0; + for (int start = i, n = i + BEZIER_SIZE - 1; i < n; i += 2) { + x = curves[i]; + if (x >= percent) { + float prevX, prevY; + if (i == start) { + prevX = 0; + prevY = 0; + } else { + prevX = curves[i - 2]; + prevY = curves[i - 1]; + } + return prevY + (curves[i + 1] - prevY) * (percent - prevX) / (x - prevX); + } + } + float y = curves[i - 1]; 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; + protected const int LAST_FRAME_TIME = -2; + protected const int FRAME_VALUE = 1; internal int boneIndex; internal float[] frames; @@ -235,7 +249,7 @@ namespace Spine { 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)); + percent = GetCurvePercent((frameIndex >> 1) - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); amount = frames[frameIndex + FRAME_VALUE] - lastFrameValue; while (amount > 180) @@ -252,9 +266,9 @@ namespace Spine { } public class TranslateTimeline : CurveTimeline { - static protected int LAST_FRAME_TIME = -3; - static protected int FRAME_X = 1; - static protected int FRAME_Y = 2; + protected const int LAST_FRAME_TIME = -3; + protected const int FRAME_X = 1; + protected const int FRAME_Y = 2; internal int boneIndex; internal float[] frames; @@ -330,11 +344,11 @@ namespace Spine { } 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; + protected const int LAST_FRAME_TIME = -5; + protected const int FRAME_R = 1; + protected const int FRAME_G = 2; + protected const int FRAME_B = 3; + protected const int FRAME_A = 4; internal int slotIndex; internal float[] frames; @@ -423,13 +437,14 @@ namespace Spine { public void Apply (Skeleton skeleton, float lastTime, float time, List firedEvents, float alpha) { float[] frames = this.frames; - if (time < frames[0]) return; // Time is before first frame. + if (time < frames[0]) { + if (lastTime > time) Apply(skeleton, lastTime, int.MaxValue, null, 0); + return; + } else if (lastTime > time) // + lastTime = -1; - 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; + int frameIndex = time >= frames[frames.Length - 1] ? frames.Length - 1 : Animation.binarySearch(frames, time) - 1; + if (frames[frameIndex] <= lastTime) return; String attachmentName = attachmentNames[frameIndex]; skeleton.slots[slotIndex].Attachment = @@ -473,7 +488,7 @@ namespace Spine { if (lastTime < frames[0]) frameIndex = 0; else { - frameIndex = Animation.binarySearch(frames, lastTime, 1); + frameIndex = Animation.binarySearch(frames, lastTime); float frame = frames[frameIndex]; while (frameIndex > 0) { // Fire multiple events with the same frame. if (frames[frameIndex - 1] != frame) break; @@ -513,7 +528,7 @@ namespace Spine { if (time >= frames[frames.Length - 1]) // Time is after last frame. frameIndex = frames.Length - 1; else - frameIndex = Animation.binarySearch(frames, time, 1) - 1; + frameIndex = Animation.binarySearch(frames, time) - 1; List drawOrder = skeleton.drawOrder; List slots = skeleton.slots; @@ -583,7 +598,7 @@ namespace Spine { } // Interpolate between the previous frame and the current frame. - int frameIndex = Animation.binarySearch(frames, time, 1); + int frameIndex = Animation.binarySearch(frames, time); float frameTime = frames[frameIndex]; float percent = 1 - (time - frameTime) / (frames[frameIndex - 1] - frameTime); percent = GetCurvePercent(frameIndex - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); @@ -604,4 +619,57 @@ namespace Spine { } } } + + public class IkConstraintTimeline : CurveTimeline { + private const int PREV_FRAME_TIME = -3; + private const int FRAME_MIX = 1; + private const int FRAME_BEND_DIRECTION = 2; + + internal int ikConstraintIndex; + internal float[] frames; + + public int IkConstraintIndex { get { return ikConstraintIndex; } set { ikConstraintIndex = value; } } + public float[] Frames { get { return frames; } set { frames = value; } } // time, mix, bendDirection, ... + + public IkConstraintTimeline (int frameCount) + : base(frameCount) { + frames = new float[frameCount * 3]; + } + + public float[] getFrames () { + return frames; + } + + /** Sets the time, mix and bend direction of the specified keyframe. */ + public void setFrame (int frameIndex, float time, float mix, int bendDirection) { + frameIndex *= 3; + frames[frameIndex] = time; + frames[frameIndex + 1] = mix; + frames[frameIndex + 2] = bendDirection; + } + + override public void Apply (Skeleton skeleton, float lastTime, float time, List firedEvents, float alpha) { + float[] frames = this.frames; + if (time < frames[0]) return; // Time is before first frame. + + IkConstraint ikConstraint = skeleton.ikConstraints[ikConstraintIndex]; + + if (time >= frames[frames.Length - 3]) { // Time is after last frame. + ikConstraint.mix += (frames[frames.Length - 2] - ikConstraint.mix) * alpha; + ikConstraint.bendDirection = (int)frames[frames.Length - 1]; + return; + } + + // Interpolate between the previous frame and the current frame. + int frameIndex = Animation.binarySearch(frames, time, 3); + float prevFrameMix = frames[frameIndex - 2]; + float frameTime = frames[frameIndex]; + float percent = 1 - (time - frameTime) / (frames[frameIndex + PREV_FRAME_TIME] - frameTime); + percent = GetCurvePercent(frameIndex / 3 - 1, percent < 0 ? 0 : (percent > 1 ? 1 : percent)); + + float mix = prevFrameMix + (frames[frameIndex + FRAME_MIX] - prevFrameMix) * percent; + ikConstraint.mix += (mix - ikConstraint.mix) * alpha; + ikConstraint.bendDirection = (int)frames[frameIndex + FRAME_BEND_DIRECTION]; + } + } } diff --git a/spine-csharp/src/Bone.cs b/spine-csharp/src/Bone.cs index 7a9fb556a..bc63853fb 100644 --- a/spine-csharp/src/Bone.cs +++ b/spine-csharp/src/Bone.cs @@ -36,15 +36,19 @@ namespace Spine { internal BoneData data; internal Bone parent; - internal float x, y, rotation, scaleX, scaleY; + internal float x, y, rotation, rotationIK, scaleX, scaleY; internal float m00, m01, m10, m11; internal float worldX, worldY, worldRotation, worldScaleX, worldScaleY; + internal bool flipX, flipY; public BoneData Data { get { return data; } } public Bone Parent { get { return parent; } } public float X { get { return x; } set { x = value; } } public float Y { get { return y; } set { y = value; } } + /// The forward kinetics rotation. public float Rotation { get { return rotation; } set { rotation = value; } } + /// The inverse kinetics rotation, as calculated by any IK constraints. + public float RotationIK { get { return rotationIK; } set { rotationIK = value; } } public float ScaleX { get { return scaleX; } set { scaleX = value; } } public float ScaleY { get { return scaleY; } set { scaleY = value; } } @@ -67,8 +71,9 @@ namespace Spine { } /// Computes the world SRT using the parent bone and the local SRT. - public void UpdateWorldTransform (bool flipX, bool flipY) { + public void UpdateWorldTransform () { Bone parent = this.parent; + float x = this.x, y = this.y; if (parent != null) { worldX = x * parent.m00 + y * parent.m01 + parent.worldX; worldY = x * parent.m10 + y * parent.m11 + parent.worldY; @@ -79,28 +84,30 @@ namespace Spine { worldScaleX = scaleX; worldScaleY = scaleY; } - worldRotation = data.inheritRotation ? parent.worldRotation + rotation : rotation; + worldRotation = data.inheritRotation ? parent.worldRotation + rotationIK : rotationIK; } else { worldX = flipX ? -x : x; worldY = flipY != yDown ? -y : y; worldScaleX = scaleX; worldScaleY = scaleY; - worldRotation = rotation; + worldRotation = rotationIK; } 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; + m00 = -cos * worldScaleX; + m01 = sin * worldScaleY; + } else { + m00 = cos * worldScaleX; + m01 = -sin * worldScaleY; } if (flipY != yDown) { - m10 = -m10; - m11 = -m11; + m10 = -sin * worldScaleX; + m11 = -cos * worldScaleY; + } else { + m10 = sin * worldScaleX; + m11 = cos * worldScaleY; } } @@ -109,10 +116,28 @@ namespace Spine { x = data.x; y = data.y; rotation = data.rotation; + rotationIK = rotation; scaleX = data.scaleX; scaleY = data.scaleY; } + public void worldToLocal (float worldX, float worldY, out float localX, out float localY) { + float dx = worldX - this.worldX, dy = worldY - this.worldY; + float m00 = this.m00, m10 = this.m10, m01 = this.m01, m11 = this.m11; + if (flipX != (flipY != yDown)) { + m00 *= -1; + m11 *= -1; + } + float invDet = 1 / (m00 * m11 - m01 * m10); + localX = (dx * m00 * invDet - dy * m01 * invDet); + localY = (dy * m11 * invDet - dx * m10 * invDet); + } + + public void localToWorld (float localX, float localY, out float worldX, out float worldY) { + worldX = localX * m00 + localY * m01 + this.worldX; + worldY = localX * m10 + localY * m11 + this.worldY; + } + override public String ToString () { return data.name; } diff --git a/spine-csharp/src/EventData.cs b/spine-csharp/src/EventData.cs index 832d3de83..4f5d745ff 100644 --- a/spine-csharp/src/EventData.cs +++ b/spine-csharp/src/EventData.cs @@ -32,14 +32,16 @@ using System; namespace Spine { public class EventData { - public String Name { get; private set; } + internal String name; + + public String Name { get { return name; } } public int Int { get; set; } public float Float { get; set; } public String String { get; set; } public EventData (String name) { if (name == null) throw new ArgumentNullException("name cannot be null."); - Name = name; + this.name = name; } override public String ToString () { diff --git a/spine-csharp/src/IkConstraint.cs b/spine-csharp/src/IkConstraint.cs new file mode 100644 index 000000000..6b27c4a03 --- /dev/null +++ b/spine-csharp/src/IkConstraint.cs @@ -0,0 +1,148 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using System.Collections.Generic; + +namespace Spine { + public class IkConstraint { + private const float radDeg = 180 / (float)Math.PI; + + internal IkConstraintData data; + internal List bones = new List(); + internal Bone target; + internal int bendDirection = 1; + internal float mix = 1; + + public IkConstraintData Data { get { return data; } } + public List Bones { get { return bones; } } + public Bone Target { get { return target; } set { target = value; } } + public int BendDirection { get { return bendDirection; } set { bendDirection = value; } } + public float Mix { get { return mix; } set { mix = value; } } + + public IkConstraint (IkConstraintData data, Skeleton skeleton) { + this.data = data; + mix = data.mix; + bendDirection = data.bendDirection; + + bones = new List(data.bones.Count); + if (skeleton != null) { + foreach (BoneData boneData in data.bones) + bones.Add(skeleton.FindBone(boneData.name)); + target = skeleton.FindBone(data.target.name); + } + } + + public void apply () { + Bone target = this.target; + List bones = this.bones; + switch (bones.Count) { + case 1: + apply(bones[0], target.worldX, target.worldY, mix); + break; + case 2: + apply(bones[0], bones[1], target.worldX, target.worldY, bendDirection, mix); + break; + } + } + + override public String ToString () { + return data.name; + } + + /// Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified + /// in the world coordinate system. + static public void apply (Bone bone, float targetX, float targetY, float alpha) { + float parentRotation = (!bone.data.inheritRotation || bone.parent == null) ? 0 : bone.parent.worldRotation; + float rotation = bone.rotation; + float rotationIK = (float)Math.Atan2(targetY - bone.worldY, targetX - bone.worldX) * radDeg - parentRotation; + bone.rotationIK = rotation + (rotationIK - rotation) * alpha; + } + + /// Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as + /// possible. The target is specified in the world coordinate system. + /// Any descendant bone of the parent. + static public void apply (Bone parent, Bone child, float targetX, float targetY, int bendDirection, float alpha) { + float childRotation = child.rotation, parentRotation = parent.rotation; + if (alpha == 0) { + child.rotationIK = childRotation; + parent.rotationIK = parentRotation; + return; + } + float positionX, positionY; + Bone parentParent = parent.parent; + if (parentParent != null) { + parentParent.worldToLocal(targetX, targetY, out positionX, out positionY); + targetX = (positionX - parent.x) * parentParent.worldScaleX; + targetY = (positionY - parent.y) * parentParent.worldScaleY; + } else { + targetX -= parent.x; + targetY -= parent.y; + } + if (child.parent == parent) { + positionX = child.x; + positionY = child.y; + } else { + child.parent.localToWorld(child.x, child.y, out positionX, out positionY); + parent.worldToLocal(positionX, positionY, out positionX, out positionY); + } + float childX = positionX * parent.worldScaleX, childY = positionY * parent.worldScaleY; + float offset = (float)Math.Atan2(childY, childX); + float len1 = (float)Math.Sqrt(childX * childX + childY * childY), len2 = child.data.length * child.worldScaleX; + // Based on code by Ryan Juckett with permission: Copyright (c) 2008-2009 Ryan Juckett, http://www.ryanjuckett.com/ + float cosDenom = 2 * len1 * len2; + if (cosDenom < 0.0001f) { + child.rotationIK = childRotation + ((float)Math.Atan2(targetY, targetX) * radDeg - parentRotation - childRotation) + * alpha; + return; + } + float cos = (targetX * targetX + targetY * targetY - len1 * len1 - len2 * len2) / cosDenom; + if (cos < -1) + cos = -1; + else if (cos > 1) + cos = 1; + float childAngle = (float)Math.Acos(cos) * bendDirection; + float adjacent = len1 + len2 * cos, opposite = len2 * (float)Math.Sin(childAngle); + float parentAngle = (float)Math.Atan2(targetY * adjacent - targetX * opposite, targetX * adjacent + targetY * opposite); + float rotation = (parentAngle - offset) * radDeg - parentRotation; + if (rotation > 180) + rotation -= 360; + else if (rotation < -180) // + rotation += 360; + parent.rotationIK = parentRotation + rotation * alpha; + rotation = (childAngle + offset) * radDeg - childRotation; + if (rotation > 180) + rotation -= 360; + else if (rotation < -180) // + rotation += 360; + child.rotationIK = childRotation + (rotation + parent.worldRotation - child.parent.worldRotation) * alpha; + } + } +} diff --git a/spine-csharp/src/IkConstraintData.cs b/spine-csharp/src/IkConstraintData.cs new file mode 100644 index 000000000..9919a61e9 --- /dev/null +++ b/spine-csharp/src/IkConstraintData.cs @@ -0,0 +1,57 @@ +/****************************************************************************** + * Spine Runtimes Software License + * Version 2.1 + * + * Copyright (c) 2013, Esoteric Software + * All rights reserved. + * + * You are granted a perpetual, non-exclusive, non-sublicensable and + * non-transferable license to install, execute and perform the Spine Runtimes + * Software (the "Software") solely for internal use. Without the written + * permission of Esoteric Software (typically granted by licensing Spine), you + * may not (a) modify, translate, adapt or otherwise create derivative works, + * improvements of the Software or develop new applications using the Software + * or (b) remove, delete, alter or obscure any trademarks or any copyright, + * trademark, patent or other intellectual property or proprietary rights + * notices on or in the Software, including any copy thereof. Redistributions + * in binary or source form must include this license and terms. + * + * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO + * EVENT SHALL ESOTERIC SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + *****************************************************************************/ + +using System; +using System.Collections.Generic; + +namespace Spine { + public class IkConstraintData { + internal String name; + internal List bones = new List(); + internal BoneData target; + internal int bendDirection = 1; + internal float mix = 1; + + public String Name { get { return name; } } + public List Bones { get { return bones; } } + public BoneData Target { get { return target; } set { target = value; } } + public int BendDirection { get { return bendDirection; } set { bendDirection = value; } } + public float Mix { get { return mix; } set { mix = value; } } + + public IkConstraintData (String name) { + if (name == null) throw new ArgumentNullException("name cannot be null."); + this.name = name; + } + + override public String ToString () { + return name; + } + } +} diff --git a/spine-csharp/src/Skeleton.cs b/spine-csharp/src/Skeleton.cs index 07cb95413..699cd6a33 100644 --- a/spine-csharp/src/Skeleton.cs +++ b/spine-csharp/src/Skeleton.cs @@ -37,6 +37,8 @@ namespace Spine { internal List bones; internal List slots; internal List drawOrder; + internal List ikConstraints = new List(); + private List> updateBonesCache = new List>(); internal Skin skin; internal float r = 1, g = 1, b = 1, a = 1; internal float time; @@ -47,17 +49,38 @@ namespace Spine { public List Bones { get { return bones; } } public List Slots { get { return slots; } } public List DrawOrder { get { return drawOrder; } } + public List IkConstraints { get { return ikConstraints; } set { ikConstraints = value; } } public Skin Skin { get { return skin; } set { skin = value; } } public float R { get { return r; } set { r = value; } } public float G { get { return g; } set { g = value; } } public float B { get { return b; } set { b = value; } } public float A { get { return a; } set { a = value; } } public float Time { get { return time; } set { time = value; } } - public bool FlipX { get { return flipX; } set { flipX = value; } } - public bool FlipY { get { return flipY; } set { flipY = value; } } public float X { get { return x; } set { x = value; } } public float Y { get { return y; } set { y = value; } } + public bool FlipX { + get { return flipX; } + set { + if (flipX == value) return; + flipX = value; + List bones = this.bones; + for (int i = 0, n = bones.Count; i < n; i++) + bones[i].flipX = value; + } + } + + public bool FlipY { + get { return flipY; } + set { + if (flipY == value) return; + flipY = value; + List bones = this.bones; + for (int i = 0, n = bones.Count; i < n; i++) + bones[i].flipY = value; + } + } + public Bone RootBone { get { return bones.Count == 0 ? null : bones[0]; @@ -82,15 +105,73 @@ namespace Spine { slots.Add(slot); drawOrder.Add(slot); } + + ikConstraints = new List(data.ikConstraints.Count); + foreach (IkConstraintData ikConstraintData in data.ikConstraints) + ikConstraints.Add(new IkConstraint(ikConstraintData, this)); + + UpdateCache(); } - /// Updates the world transform for each bone. + /// Caches information about bones and IK constraints. Must be called if bones or IK constraints are added or + /// removed. + public void UpdateCache () { + List> updateBonesCache = this.updateBonesCache; + List ikConstraints = this.ikConstraints; + int ikConstraintsCount = ikConstraints.Count; + + int arrayCount = ikConstraintsCount + 1; + if (updateBonesCache.Count > arrayCount) updateBonesCache.RemoveRange(arrayCount, updateBonesCache.Count - arrayCount); + for (int i = 0, n = updateBonesCache.Count; i < n; i++) + updateBonesCache[i].Clear(); + while (updateBonesCache.Count < arrayCount) + updateBonesCache.Add(new List()); + + List nonIkBones = updateBonesCache[0]; + + for (int i = 0, n = bones.Count; i < n; i++) { + Bone bone = bones[i]; + Bone current = bone; + do { + for (int ii = 0; ii < ikConstraintsCount; ii++) { + IkConstraint ikConstraint = ikConstraints[ii]; + Bone parent = ikConstraint.bones[0]; + Bone child = ikConstraint.bones[ikConstraint.bones.Count - 1]; + while (true) { + if (current == child) { + updateBonesCache[ii].Add(bone); + updateBonesCache[ii + 1].Add(bone); + goto outer; + } + if (child == parent) break; + child = child.parent; + } + } + current = current.parent; + } while (current != null); + nonIkBones.Add(bone); + outer: {} + } + } + + /// Updates the world transform for each bone and applies IK constraints. public void UpdateWorldTransform () { - bool flipX = this.flipX; - bool flipY = this.flipY; List bones = this.bones; - for (int i = 0, n = bones.Count; i < n; i++) - bones[i].UpdateWorldTransform(flipX, flipY); + for (int ii = 0, nn = bones.Count; ii < nn; ii++) { + Bone bone = bones[ii]; + bone.rotationIK = bone.rotation; + } + List> updateBonesCache = this.updateBonesCache; + List ikConstraints = this.ikConstraints; + int i = 0, last = updateBonesCache.Count - 1; + while (true) { + List updateBones = updateBonesCache[i]; + for (int ii = 0, nn = updateBones.Count; ii < nn; ii++) + updateBones[ii].UpdateWorldTransform(); + if (i == last) break; + ikConstraints[i].apply(); + i++; + } } /// Sets the bones and slots to their setup pose values. @@ -103,6 +184,13 @@ namespace Spine { List bones = this.bones; for (int i = 0, n = bones.Count; i < n; i++) bones[i].SetToSetupPose(); + + List ikConstraints = this.ikConstraints; + for (int i = 0, n = ikConstraints.Count; i < n; i++) { + IkConstraint ikConstraint = ikConstraints[i]; + ikConstraint.bendDirection = ikConstraint.data.bendDirection; + ikConstraint.mix = ikConstraint.data.mix; + } } public void SetSlotsToSetupPose () { @@ -218,6 +306,17 @@ namespace Spine { throw new Exception("Slot not found: " + slotName); } + /** @return May be null. */ + public IkConstraint FindIkConstraint (String ikConstraintName) { + if (ikConstraintName == null) throw new ArgumentNullException("ikConstraintName cannot be null."); + List ikConstraints = this.ikConstraints; + for (int i = 0, n = ikConstraints.Count; i < n; i++) { + IkConstraint ikConstraint = ikConstraints[i]; + if (ikConstraint.data.name == ikConstraintName) return ikConstraint; + } + return null; + } + public void Update (float delta) { time += delta; } diff --git a/spine-csharp/src/SkeletonData.cs b/spine-csharp/src/SkeletonData.cs index 60a5d537a..edc5d648b 100644 --- a/spine-csharp/src/SkeletonData.cs +++ b/spine-csharp/src/SkeletonData.cs @@ -40,6 +40,9 @@ namespace Spine { internal Skin defaultSkin; internal List events = new List(); internal List animations = new List(); + internal List ikConstraints = new List(); + internal float width, height; + internal String version, hash; public String Name { get { return name; } set { name = value; } } public List Bones { get { return bones; } } // Ordered parents first. @@ -49,15 +52,15 @@ namespace Spine { public Skin DefaultSkin { get { return defaultSkin; } set { defaultSkin = value; } } public List Events { get { return events; } set { events = value; } } public List Animations { get { return animations; } set { animations = value; } } + public List IkConstraints { get { return ikConstraints; } set { ikConstraints = value; } } + public float Width { get { return width; } set { width = value; } } + public float Height { get { return height; } set { height = value; } } + /// The Spine version used to export this data. + public String Version { get { return version; } set { version = value; } } + public String Hash { get { return hash; } set { hash = value; } } // --- Bones. - public void AddBone (BoneData bone) { - if (bone == null) throw new ArgumentNullException("bone cannot be null."); - bones.Add(bone); - } - - /// May be null. public BoneData FindBone (String boneName) { if (boneName == null) throw new ArgumentNullException("boneName cannot be null."); @@ -80,11 +83,6 @@ namespace Spine { // --- Slots. - public void AddSlot (SlotData slot) { - if (slot == null) throw new ArgumentNullException("slot cannot be null."); - slots.Add(slot); - } - /// May be null. public SlotData FindSlot (String slotName) { if (slotName == null) throw new ArgumentNullException("slotName cannot be null."); @@ -106,12 +104,7 @@ namespace Spine { } // --- Skins. - - public void AddSkin (Skin skin) { - if (skin == null) throw new ArgumentNullException("skin cannot be null."); - skins.Add(skin); - } - + /// May be null. public Skin FindSkin (String skinName) { if (skinName == null) throw new ArgumentNullException("skinName cannot be null."); @@ -122,33 +115,36 @@ namespace Spine { // --- Events. - public void AddEvent (EventData eventData) { - if (eventData == null) throw new ArgumentNullException("eventData cannot be null."); - events.Add(eventData); - } - /// May be null. public EventData FindEvent (String eventDataName) { if (eventDataName == null) throw new ArgumentNullException("eventDataName cannot be null."); foreach (EventData eventData in events) - if (eventData.Name == eventDataName) return eventData; + if (eventData.name == eventDataName) return eventData; return null; } // --- Animations. - - public void AddAnimation (Animation animation) { - if (animation == null) throw new ArgumentNullException("animation cannot be null."); - animations.Add(animation); - } - + /// May be null. public Animation FindAnimation (String animationName) { if (animationName == null) throw new ArgumentNullException("animationName cannot be null."); List animations = this.animations; for (int i = 0, n = animations.Count; i < n; i++) { Animation animation = animations[i]; - if (animation.Name == animationName) return animation; + if (animation.name == animationName) return animation; + } + return null; + } + + // --- IK + + /// May be null. + public IkConstraintData FindIkConstraint (String ikConstraintName) { + if (ikConstraintName == null) throw new ArgumentNullException("ikConstraintName cannot be null."); + List ikConstraints = this.ikConstraints; + for (int i = 0, n = ikConstraints.Count; i < n; i++) { + IkConstraintData ikConstraint = ikConstraints[i]; + if (ikConstraint.name == ikConstraintName) return ikConstraint; } return null; } diff --git a/spine-csharp/src/SkeletonJson.cs b/spine-csharp/src/SkeletonJson.cs index 11c951419..e97102c3d 100644 --- a/spine-csharp/src/SkeletonJson.cs +++ b/spine-csharp/src/SkeletonJson.cs @@ -90,6 +90,15 @@ namespace Spine { var root = Json.Deserialize(reader) as Dictionary; if (root == null) throw new Exception("Invalid JSON."); + // Skeleton. + var skeletonMap = (Dictionary)root["skeleton"]; + if (skeletonMap != null) { + skeletonData.version = (String)skeletonMap["spine"]; + skeletonData.hash = (String)skeletonMap["hash"]; + skeletonData.width = GetFloat(skeletonMap, "width", 0); + skeletonData.height = GetFloat(skeletonMap, "width", 1); + } + // Bones. foreach (Dictionary boneMap in (List)root["bones"]) { BoneData parent = null; @@ -107,7 +116,27 @@ namespace Spine { boneData.scaleY = GetFloat(boneMap, "scaleY", 1); boneData.inheritScale = GetBoolean(boneMap, "inheritScale", true); boneData.inheritRotation = GetBoolean(boneMap, "inheritRotation", true); - skeletonData.AddBone(boneData); + skeletonData.bones.Add(boneData); + } + + // IK constraints. + foreach (Dictionary ikMap in (List)root["ik"]) { + IkConstraintData ikConstraintData = new IkConstraintData((String)ikMap["name"]); + + foreach (String boneName in (List)ikMap["bones"]) { + BoneData bone = skeletonData.FindBone(boneName); + if (bone == null) throw new Exception("IK bone not found: " + boneName); + ikConstraintData.bones.Add(bone); + } + + String targetName = (String)ikMap["target"]; + ikConstraintData.target = skeletonData.FindBone(targetName); + if (ikConstraintData.target == null) throw new Exception("Target bone not found: " + targetName); + + ikConstraintData.bendDirection = GetBoolean(ikMap, "bendPositive", true) ? 1 : -1; + ikConstraintData.mix = GetFloat(ikMap, "mix", 1); + + skeletonData.ikConstraints.Add(ikConstraintData); } // Slots. @@ -134,7 +163,7 @@ namespace Spine { if (slotMap.ContainsKey("additive")) slotData.additiveBlending = (bool)slotMap["additive"]; - skeletonData.AddSlot(slotData); + skeletonData.slots.Add(slotData); } } @@ -149,7 +178,7 @@ namespace Spine { if (attachment != null) skin.AddAttachment(slotIndex, attachmentEntry.Key, attachment); } } - skeletonData.AddSkin(skin); + skeletonData.skins.Add(skin); if (skin.name == "default") skeletonData.defaultSkin = skin; } @@ -163,7 +192,7 @@ namespace Spine { eventData.Int = GetInt(entryMap, "int", 0); eventData.Float = GetFloat(entryMap, "float", 0); eventData.String = GetString(entryMap, "string", null); - skeletonData.AddEvent(eventData); + skeletonData.events.Add(eventData); } } @@ -443,6 +472,26 @@ namespace Spine { } } + if (map.ContainsKey("ik")) { + foreach (KeyValuePair ikMap in (Dictionary)map["ik"]) { + IkConstraintData ikConstraint = skeletonData.FindIkConstraint(ikMap.Key); + var values = (List)ikMap.Value; + var timeline = new IkConstraintTimeline(values.Count); + timeline.ikConstraintIndex = skeletonData.ikConstraints.IndexOf(ikConstraint); + int frameIndex = 0; + foreach (Dictionary valueMap in values) { + float time = (float)valueMap["time"]; + float mix = valueMap.ContainsKey("mix") ? (float)valueMap["mix"] : 1; + bool bendPositive = valueMap.ContainsKey("bendPositive") ? (bool)valueMap["bendPositive"] : true; + timeline.setFrame(frameIndex, time, mix, bendPositive ? 1 : -1); + ReadCurve(timeline, frameIndex, valueMap); + frameIndex++; + } + timelines.Add(timeline); + duration = Math.Max(duration, timeline.frames[timeline.FrameCount * 3 - 3]); + } + } + if (map.ContainsKey("ffd")) { foreach (KeyValuePair ffdMap in (Dictionary)map["ffd"]) { Skin skin = skeletonData.FindSkin(ffdMap.Key); @@ -553,7 +602,7 @@ namespace Spine { } timelines.TrimExcess(); - skeletonData.AddAnimation(new Animation(name, timelines, duration)); + skeletonData.animations.Add(new Animation(name, timelines, duration)); } private void ReadCurve (CurveTimeline timeline, int frameIndex, Dictionary valueMap) { diff --git a/spine-xna/example/data/raptor.atlas b/spine-xna/example/data/raptor.atlas new file mode 100644 index 000000000..56ba9d776 --- /dev/null +++ b/spine-xna/example/data/raptor.atlas @@ -0,0 +1,104 @@ + +raptor.png +size: 1014,480 +format: RGBA8888 +filter: Linear,Linear +repeat: none +stirrup + rotate: false + xy: 657, 57 + size: 50, 45 + orig: 50, 45 + offset: 0, 0 + index: -1 +velo_arm_back + rotate: false + xy: 881, 204 + size: 82, 86 + orig: 82, 86 + offset: 0, 0 + index: -1 +velo_body + rotate: false + xy: 2, 195 + size: 610, 285 + orig: 610, 285 + offset: 0, 0 + index: -1 +velo_front_arm + rotate: false + xy: 798, 188 + size: 81, 102 + orig: 81, 102 + offset: 0, 0 + index: -1 +velo_front_leg + rotate: true + xy: 2, 2 + size: 191, 257 + orig: 191, 257 + offset: 0, 0 + index: -1 +velo_hindleg_back + rotate: false + xy: 614, 265 + size: 169, 215 + orig: 169, 215 + offset: 0, 0 + index: -1 +velo_horn + rotate: false + xy: 614, 183 + size: 182, 80 + orig: 182, 80 + offset: 0, 0 + index: -1 +velo_horn_back + rotate: false + xy: 581, 104 + size: 176, 77 + orig: 176, 77 + offset: 0, 0 + index: -1 +velo_jaw + rotate: false + xy: 426, 50 + size: 153, 143 + orig: 153, 143 + offset: 0, 0 + index: -1 +velo_saddle_noshadow + rotate: false + xy: 261, 5 + size: 163, 188 + orig: 163, 188 + offset: 0, 0 + index: -1 +velo_saddle_strap_front + rotate: false + xy: 950, 385 + size: 57, 95 + orig: 57, 95 + offset: 0, 0 + index: -1 +velo_saddle_strap_rear + rotate: true + xy: 581, 48 + size: 54, 74 + orig: 54, 74 + offset: 0, 0 + index: -1 +velo_saddle_w_shadow + rotate: false + xy: 785, 292 + size: 163, 188 + orig: 163, 188 + offset: 0, 0 + index: -1 +velo_tongue + rotate: true + xy: 950, 297 + size: 86, 64 + orig: 86, 64 + offset: 0, 0 + index: -1 diff --git a/spine-xna/example/data/raptor.json b/spine-xna/example/data/raptor.json new file mode 100644 index 000000000..f41d56113 --- /dev/null +++ b/spine-xna/example/data/raptor.json @@ -0,0 +1 @@ +{"skeleton":{"spine":"Dev","hash":"2OoNdoqifc292lPt91atLy82Mjk","width":1078.39,"height":1006.05},"bones":[{"name":"root"},{"name":"front_foot_goal","parent":"root","x":-45.79,"y":-28.67,"rotation":-0.94,"color":"ff0000ff"},{"name":"hip","parent":"root","x":-136.78,"y":415.47,"rotation":3.15,"color":"fbff00ff"},{"name":"rear_foot_goal","parent":"root","x":33.43,"y":30.81,"color":"ff0000ff"},{"name":"front_leg1","parent":"hip","length":251.74,"x":27.36,"y":-28.27,"rotation":-51.5,"color":"15ff00ff"},{"name":"front_leg_goal","parent":"front_foot_goal","x":-106.06,"y":115.58,"color":"ff0000ff"},{"name":"rear_leg1","parent":"hip","length":226.27,"x":55.19,"y":-71.25,"rotation":-54.76,"color":"e07800ff"},{"name":"rear_leg_goal","parent":"rear_foot_goal","x":-127.51,"y":75.99,"color":"ff0000ff"},{"name":"rear_strap_goal","parent":"hip","x":-114.9,"y":-80.05,"color":"ff0700ff"},{"name":"tail1","parent":"hip","length":162.53,"x":-20.86,"y":6.87,"rotation":162.92,"color":"eaff00ff"},{"name":"torso1","parent":"hip","length":126.25,"x":30.03,"y":-0.4,"rotation":-4.97,"color":"eaff00ff"},{"name":"front_leg2","parent":"front_leg1","length":208.54,"x":251.03,"y":0.16,"rotation":261.93,"color":"15ff00ff"},{"name":"rear_leg2","parent":"rear_leg1","length":172.58,"x":226.32,"y":0.23,"rotation":-92.25,"color":"e07800ff"},{"name":"saddle","parent":"torso1","length":50.91,"x":4.56,"y":71.86,"rotation":91.8,"color":"ff7300ff"},{"name":"tail2","parent":"tail1","length":130.02,"x":162.53,"y":-0.82,"rotation":30.3,"color":"eaff00ff"},{"name":"torso2","parent":"torso1","length":121.2,"x":126.25,"y":-0.37,"rotation":39.84,"color":"eaff00ff"},{"name":"front_arm1","parent":"torso2","length":109.99,"x":46.37,"y":-84.61,"rotation":224.54,"color":"15ff00ff"},{"name":"front_leg3","parent":"front_leg2","length":118.18,"x":208.5,"y":-1.63,"rotation":85.46,"color":"15ff00ff"},{"name":"neck","parent":"torso2","length":70.59,"x":121.19,"y":0.34,"rotation":41.37,"color":"eaff00ff"},{"name":"rear_arm1","parent":"torso2","length":109.56,"x":57.05,"y":-95.38,"rotation":-124.71,"color":"e07800ff"},{"name":"rear_leg3","parent":"rear_leg2","length":103.05,"x":172.31,"y":2.21,"rotation":82.81,"color":"e07800ff"},{"name":"saddle_strap_front1","parent":"saddle","length":97.27,"x":-27.36,"y":-73.38,"rotation":-148.11,"color":"ff7300ff"},{"name":"saddle_strap_rear1","parent":"saddle","length":38.62,"x":-33.34,"y":87.32,"rotation":151.13,"color":"ff7300ff"},{"name":"tail3","parent":"tail2","length":141.06,"x":130.02,"y":0.1,"rotation":6.88,"color":"eaff00ff"},{"name":"front_arm2","parent":"front_arm1","length":86.33,"x":109.99,"y":0.2,"rotation":105.23,"color":"15ff00ff"},{"name":"front_foot1","parent":"front_leg3","length":57.79,"x":118.19,"y":-0.79,"scaleX":1.126,"rotation":54.46,"color":"15ff00ff"},{"name":"head","parent":"neck","length":105.5,"x":70.59,"y":0.03,"rotation":9.82,"color":"eaff00ff"},{"name":"rear_arm2","parent":"rear_arm1","length":85.8,"x":109.56,"rotation":123.56,"color":"e07800ff"},{"name":"rear_foot1","parent":"rear_leg3","length":84.51,"x":102.37,"y":-0.02,"rotation":75.43,"color":"e07800ff"},{"name":"saddle_strap_front2","parent":"saddle_strap_front1","length":102.74,"x":97.29,"y":0.3,"rotation":-11.13,"color":"ff7300ff"},{"name":"saddle_strap_rear2","parent":"saddle_strap_rear1","length":54.36,"x":38.63,"y":-0.02,"color":"ff7300ff"},{"name":"stirrup","parent":"saddle_strap_front1","length":47.24,"x":98.88,"y":30.48,"rotation":118.16,"color":"ff7300ff"},{"name":"tail4","parent":"tail3","length":126.25,"x":141.05,"y":0.64,"rotation":-18.86,"color":"eaff00ff"},{"name":"front_foot2","parent":"front_foot1","length":56.19,"x":57.78,"y":-0.02,"scaleX":0.73,"scaleY":0.823,"rotation":-0.46,"inheritRotation":false,"color":"15ff00ff"},{"name":"front_hand","parent":"front_arm2","length":47.55,"x":86.33,"y":0.06,"rotation":-56.83,"color":"15ff00ff"},{"name":"horn_front","parent":"head","length":87.48,"x":82.09,"y":-221.36,"rotation":49.36,"color":"15ff00ff"},{"name":"horn_rear","parent":"head","length":73.78,"x":99.27,"y":-226.79,"rotation":44.31,"color":"e07800ff"},{"name":"jaw","parent":"head","length":203.76,"x":29.36,"y":-40.15,"rotation":-140.14,"inheritScale":false,"color":"ffff00ff"},{"name":"rear_foot2","parent":"rear_foot1","length":102.31,"x":84.49,"y":-0.34,"rotation":-6.13,"inheritRotation":false,"color":"e07800ff"},{"name":"rear_hand","parent":"rear_arm2","length":45.8,"x":85.8,"y":0.1,"rotation":-76.28,"color":"e07800ff"},{"name":"saddle_strap_rear3","parent":"saddle_strap_rear2","length":44.04,"x":54.86,"y":0.19,"rotation":3.63,"color":"ff7300ff"},{"name":"tail5","parent":"tail4","length":91.06,"x":126.25,"y":-0.47,"rotation":-22.34,"color":"eaff00ff"},{"name":"tongue1","parent":"head","length":55.11,"x":20.81,"y":-104.75,"rotation":-129.04,"color":"ffff00ff"},{"name":"front_foot3","parent":"front_foot2","length":129.88,"x":49.71,"y":20.65,"scaleX":1.154,"rotation":-3.16,"inheritRotation":false,"color":"15ff00ff"},{"name":"tongue2","parent":"tongue1","length":44.66,"x":55.59,"y":0.93,"rotation":8.93,"color":"fff200ff"},{"name":"tongue3","parent":"tongue2","length":43.64,"x":44.26,"y":-0.2,"rotation":12.86,"color":"fff200ff"}],"ik":[{"name":"front_leg_goal","bones":["front_leg1","front_leg2"],"target":"front_leg_goal","bendPositive":false},{"name":"rear_leg_goal","bones":["rear_leg1","rear_leg2"],"target":"rear_leg_goal","bendPositive":false},{"name":"front_foot_goal","bones":["front_leg3","front_foot1"],"target":"front_foot_goal"},{"name":"rear_foot_goal","bones":["rear_leg3","rear_foot1"],"target":"rear_foot_goal"},{"name":"rear_strap_goal","bones":["saddle_strap_rear2","saddle_strap_rear3"],"target":"rear_strap_goal","bendPositive":false}],"slots":[{"name":"velo_horn_back","bone":"horn_rear","attachment":"velo_horn_back"},{"name":"velo_tongue","bone":"root","attachment":"velo_tongue"},{"name":"velo_hindleg_back","bone":"rear_leg1","attachment":"velo_hindleg_back"},{"name":"velo_arm_back","bone":"root","attachment":"velo_arm_back"},{"name":"velo_body","bone":"torso1","attachment":"velo_body"},{"name":"velo_saddle_strap_front","bone":"saddle_strap_front1","attachment":"velo_saddle_strap_front"},{"name":"velo_saddle_strap_rear","bone":"saddle_strap_rear1","attachment":"velo_saddle_strap_rear"},{"name":"velo_saddle_w_shadow","bone":"saddle","attachment":"velo_saddle_w_shadow"},{"name":"velo_saddle_noshadow","bone":"saddle"},{"name":"velo_front_leg","bone":"front_leg1","attachment":"velo_front_leg"},{"name":"velo_front_arm","bone":"root","attachment":"velo_front_arm"},{"name":"velo_jaw","bone":"jaw","attachment":"velo_jaw"},{"name":"velo_horn","bone":"horn_front","attachment":"velo_horn"},{"name":"stirrup","bone":"stirrup"}],"skins":{"default":{"stirrup":{"stirrup":{"x":37.67,"y":0.28,"rotation":-56.87,"width":99,"height":89}},"velo_arm_back":{"velo_arm_back":{"type":"skinnedmesh","uvs":[0.38711,0.29362,0.31382,0.46513,0.29242,0.51521,0.32475,0.4931,0.57587,0.32138,0.63254,0.28263,0.71632,0.34507,0.94948,0.51888,1,0.65257,1,0.90624,0.95462,0.99934,0.88957,0.83204,0.80294,0.99998,0.75236,0.75696,0.6654,0.713,0.62288,0.63242,0.58194,0.65031,0.22478,0.80641,0.07791,0.73315,0.07825,0.66549,0.07984,0.34306,0,0.29728,0,0,0.32334,0,0.94947,0.60129],"triangles":[6,14,15,5,6,15,5,15,4,6,7,14,24,7,8,24,14,7,13,14,24,11,13,24,11,24,8,11,8,9,10,11,9,12,13,11,15,16,4,18,19,2,16,3,4,17,18,2,17,2,3,17,3,16,20,21,22,23,20,22,0,20,23,1,20,0,1,19,20,2,19,1],"vertices":[2,19,36.95,33.31,0.91666,27,68.53,41.05,0.08333,2,19,66.02,20.35,0.76813,27,41.41,24.39,0.23186,2,19,74.51,16.57,0.64468,27,33.49,19.53,0.35531,3,19,70.89,21.97,0.27669,27,39.99,19.46,0.67508,39,-29.67,-39.91,0.04822,3,19,42.77,63.89,0.11483,27,90.47,18.95,0.60854,39,-17.2,9,0.27661,2,27,101.86,18.83,0.45955,39,-14.38,20.04,0.54044,2,27,106.47,2.08,0.0625,39,2.98,20.56,0.9375,1,39,51.32,21.98,1,1,39,72.39,9.61,1,1,39,100.37,-23.87,1,1,39,104.96,-40.9,1,1,39,78.37,-25.61,1,1,39,86.05,-56.84,1,1,39,52.92,-30.04,1,2,27,62.24,-43.92,0.0625,39,37.19,-33.33,0.9375,2,27,64.89,-28.65,0.3125,39,22.98,-27.14,0.6875,2,27,57.69,-27.17,0.30612,39,19.83,-33.78,0.69387,2,19,124.19,3.83,0.19395,27,-5.09,-14.23,0.80604,2,19,110.77,-19.65,0.3125,27,-16.88,10.1,0.6875,2,19,99.14,-19.2,0.51613,27,-9.93,19.44,0.48386,2,19,43.73,-17.03,0.9375,27,23.17,63.92,0.0625,1,19,35.41,-29.77,1,1,19,-15.68,-28.02,1,1,19,-13.87,24.65,1,1,39,60.41,11.1,1],"hull":24,"edges":[42,44,42,40,36,34,30,28,28,26,26,24,22,20,16,48,48,14,44,46,36,4,6,4,6,34,40,38,38,36,4,2,2,0,38,2,10,30,34,32,32,30,10,8,8,6,32,8,14,12,12,10,12,28,14,16,16,18,20,18,24,22,46,0],"width":163,"height":172}},"velo_body":{"velo_body":{"type":"skinnedmesh","uvs":[0.91962,0.11974,1,0.22194,1,0.42847,0.88179,0.38589,0.874,0.47986,0.84783,0.51728,0.82504,0.54984,0.82403,0.61606,0.82305,0.67972,0.74042,0.86709,0.61596,0.93097,0.49649,0.90968,0.41186,0.71379,0.36955,0.70086,0.32823,0.68824,0.27515,0.71028,0.22568,0.73082,0.15952,0.70337,0.09227,0.67546,0.06029,0.63165,0.02855,0.58817,0,0.49874,0.05045,0.53494,0.08267,0.54507,0.11815,0.55623,0.17913,0.52568,0.22867,0.50087,0.27523,0.44458,0.32026,0.39015,0.37517,0.35747,0.43476,0.32201,0.4893,0.35534,0.56021,0.39867,0.61587,0.40674,0.67769,0.4157,0.69094,0.31314,0.69362,0.14742,0.79219,0.08354,0.51541,0.74573,0.62393,0.75425,0.70856,0.7287,0.76132,0.63288,0.7566,0.49454,0.80613,0.27517,0.65885,0.59037,0.53929,0.54937,0.42632,0.52207,0.3246,0.55241,0.22715,0.618,0.10574,0.61341,0.03969,0.56109,0.77916,0.39461,0.37556,0.53721,0.27743,0.58416,0.16958,0.61582,0.07259,0.58715,0.87545,0.31683,0.85488,0.21417,0.81012,0.17403,0.83214,0.25662,0.83823,0.32214,0.84622,0.41719,0.59954,0.57003,0.49074,0.53763,0.76917,0.43888,0.75912,0.56845,0.871,0.3701,0.85431,0.43545,0.89558,0.32412],"triangles":[12,52,46,12,63,38,38,62,39,11,12,38,39,11,38,10,11,39,49,55,24,50,21,22,23,50,22,55,23,24,20,21,50,20,50,55,19,20,55,19,55,49,18,19,49,55,50,23,54,24,25,49,24,54,54,18,49,17,18,54,54,25,48,48,17,54,27,53,26,47,53,27,48,25,26,53,48,26,15,48,53,14,15,53,16,48,15,16,17,48,52,28,29,28,47,27,29,46,52,28,52,47,13,14,47,53,47,14,52,13,47,13,52,12,30,31,46,30,46,29,63,46,31,32,63,31,45,63,32,45,32,33,12,46,63,38,63,45,58,37,0,43,36,37,57,58,0,68,57,0,59,58,57,58,43,37,43,58,59,35,36,43,68,56,57,59,57,56,60,59,56,43,59,60,0,1,68,66,60,56,66,56,68,3,66,68,51,35,43,51,43,60,61,51,60,66,61,60,67,61,66,68,1,2,3,68,2,3,67,66,4,67,3,67,51,61,4,51,67,4,5,64,51,4,64,51,34,35,64,34,51,42,34,64,5,42,64,6,42,5,65,42,6,44,62,34,42,44,34,65,44,42,7,65,6,41,65,7,44,65,41,8,41,7,40,44,41,40,41,8,39,44,40,62,45,33,62,33,34,38,45,62,39,62,44,9,40,8,39,40,9,10,39,9],"vertices":[1,26,144.03,-181.57,1,1,26,89.4,-281.62,1,1,26,-28.24,-285.93,1,1,26,-14.58,-194.68,1,5,10,363.21,87.73,0.02179,15,238.39,-84.13,0.20397,18,32.1,-140.85,0.18915,26,-61.96,-132.26,0.41197,37,129.57,6.39,0.1731,5,10,332.7,63.71,0.06905,15,199.57,-83.03,0.29424,18,3.69,-114.37,0.2194,26,-85.43,-101.32,0.30859,37,127.34,-26.64,0.1087,5,10,307.08,43.5,0.11018,15,166.95,-82.13,0.37282,18,-20.18,-92.14,0.24572,26,-105.18,-75.34,0.21862,37,123.08,-64.79,0.05264,5,10,307.75,5.7,0.18146,15,143.25,-111.59,0.56512,18,-57.43,-98.57,0.12044,26,-142.98,-75.33,0.10715,37,154.85,-83.49,0.0258,2,10,308.7,-30.55,0.25,15,120.75,-140.04,0.75,2,10,213.94,-142.7,0.75,15,-23.83,-165.45,0.25,3,10,64.45,-187.34,0.31139,9,-158.45,158.33,0.10379,2,84.16,-190.98,0.5848,1,2,-61.47,-178.84,1,1,2,-166.91,-67.95,1,6,10,-246.26,-74,0.04136,9,170.4,123.13,0.2858,14,66.71,104.77,0.57052,23,-53.08,110.21,0.10163,32,-220.11,35.3,5.1E-4,41,-331.4,-106.89,1.5E-4,6,10,-297.45,-69.74,0.01855,9,221.11,131.31,0.14592,14,115.07,87.47,0.47026,23,-6.58,88.39,0.30085,32,-168.92,31,0.06162,41,-282.82,-90.19,0.00276,6,10,-359.24,-85.1,0.0065,9,277.38,161.09,0.05488,14,178.73,86.41,0.32208,23,56.68,81.29,0.4306,32,-107.13,46.31,0.16903,41,-232.44,-51.26,0.01688,6,10,-416.83,-99.41,0.00166,9,329.83,188.85,0.01461,14,238.06,85.41,0.16842,23,115.65,74.66,0.43221,32,-49.53,60.58,0.31675,41,-185.49,-14.98,0.06633,6,10,-498.22,-88.19,7.7E-4,9,411.52,197.55,0.00629,14,313.81,53.61,0.09141,23,188.04,35.82,0.31822,32,31.84,49.3,0.37311,41,-106.46,7.49,0.21017,6,10,-580.94,-76.79,4.3E-4,9,494.56,206.4,0.00213,14,390.81,21.3,0.04419,23,261.62,-3.66,0.20981,32,114.55,37.83,0.37148,41,-26.15,30.34,0.37194,6,10,-621.23,-53.98,4.2E-4,9,539.16,193.96,7.7E-4,14,423.87,-11.11,0.02138,23,291.46,-39.06,0.12153,32,154.83,14.99,0.33319,41,19.91,25.67,0.52268,6,10,-661.22,-31.34,4.8E-4,9,583.41,181.62,3.7E-4,14,456.68,-43.27,0.01083,23,321.06,-74.2,0.0674,32,194.79,-7.66,0.29737,41,65.62,21.04,0.62353,6,10,-698.76,17.64,5.0E-4,9,631.64,143.1,2.5E-4,14,480.34,-100.28,0.00773,23,339.2,-133.2,0.05082,32,232.3,-56.69,0.28595,41,119.7,-8.69,0.65471,6,10,-636.21,0.4,4.7E-4,9,566.79,144.78,3.6E-4,14,424.34,-67.52,0.01083,23,286.57,-95.27,0.0674,32,169.77,-39.4,0.29821,41,55.51,-18.08,0.62269,6,10,-596.68,-3.21,4.1E-4,9,527.55,138.78,7.5E-4,14,387.08,-53.84,0.0214,23,250.77,-78.11,0.12153,32,130.24,-35.75,0.33437,41,17.87,-30.67,0.5215,6,10,-553.14,-7.2,3.6E-4,9,484.33,132.17,0.00206,14,346.04,-38.78,0.04428,23,211.34,-59.22,0.20983,32,86.7,-31.72,0.37245,41,-23.59,-44.54,0.37098,6,10,-479.88,14.24,5.1E-4,9,418.38,93.72,0.00606,14,269.72,-40.64,0.09174,23,135.19,-53.82,0.3183,32,13.42,-53.11,0.37365,41,-82.03,-93.66,0.20971,6,10,-420.35,31.66,9.1E-4,9,364.8,62.48,0.01396,14,207.71,-42.14,0.16936,23,73.33,-49.43,0.43245,32,-46.11,-70.49,0.31692,41,-129.51,-133.56,0.06637,6,10,-365.43,66.79,0.00309,9,319.95,15.15,0.05251,14,145.6,-61.95,0.32632,23,9.61,-63.26,0.43168,32,-101.06,-105.58,0.16945,41,-165.65,-187.83,0.01692,6,10,-312.31,100.78,0.00731,9,276.58,-30.61,0.13928,14,85.52,-81.11,0.48508,23,-52.01,-76.62,0.30338,32,-154.2,-139.52,0.06214,41,-200.6,-240.31,0.00279,6,10,-242.48,124.41,0.00974,9,214.5,-70.36,0.27055,14,11.97,-85.98,0.61489,23,-125.69,-74.48,0.10409,32,-224.04,-163.1,5.4E-4,41,-255.01,-290.05,1.5E-4,6,10,-166.71,150.07,0.02469,9,147.14,-113.5,0.57033,14,-67.84,-91.26,0.38714,23,-205.65,-72.16,0.01755,32,-299.83,-188.7,2.0E-4,41,-314.05,-344.03,5.0E-5,2,10,-113.14,135.84,0.24192,9,91.72,-112.59,0.75807,2,10,-42.12,116.77,0.14515,9,18.2,-111.17,0.85484,1,10,44.2,107.1,1,2,10,140.09,96.35,0.22579,15,72.59,65.41,0.7742,4,10,137.69,169.35,0.05644,15,117.5,123,0.24355,18,78.3,94.48,0.2125,26,23.7,91.74,0.4875,2,18,171.15,111.98,0.25,26,118.17,93.15,0.75,1,26,158.96,-25.58,1,1,2,-40.63,-86.01,1,3,10,67.34,-86.66,0.33215,9,-137.02,59.92,0.08303,2,92.54,-90.61,0.5848,2,10,170.13,-66.29,0.75,15,-8.53,-78.72,0.25,2,10,231.74,-8.12,0.4,15,76.03,-73.52,0.6,5,10,222.04,70.41,0.16894,15,118.9,-7,0.5373,18,-6.58,-3.99,0.17075,26,-76.73,9.18,0.08551,37,45.05,-108.02,0.03748,1,26,50.43,-46.56,1,1,15,-9.88,20.65,1,2,10,-53.22,20.53,0.2,9,5.8,-15.09,0.8,6,10,-180.71,32.22,0.0849,9,132.35,4.24,0.55723,14,-23.98,19.01,0.34911,23,-151.51,33.44,0.0085,32,-285.75,-70.86,1.8E-4,41,-348.66,-230.51,5.0E-5,6,10,-304.22,7.95,0.01243,9,246.39,57.53,0.13635,14,101.61,10.65,0.48532,23,-27.28,13.2,0.30559,32,-162.22,-46.69,0.05823,41,-245.36,-158.59,0.00205,6,10,-418.56,-35.1,0.0011,9,346.99,126.85,0.01192,14,223.17,22.83,0.16472,23,94.88,13.77,0.44132,32,-47.85,-3.72,0.31958,41,-158.02,-73.16,0.06133,6,10,-566.47,-40.57,3.7E-4,9,489.24,167.77,0.00175,14,367.51,-9.96,0.04197,23,235.45,-32.57,0.20889,32,100.06,1.62,0.37632,41,-24.81,-8.63,0.37068,6,10,-648.5,-15.19,4.7E-4,9,574.96,162.88,3.8E-4,14,440.24,-55.6,0.01145,23,303.52,-84.91,0.07134,32,182.07,-23.8,0.30238,41,60.48,1.14,0.61394,3,15,174.99,22.22,0.2,18,54.82,-19.14,0.6,26,-18.8,-16.2,0.2,6,10,-242.34,20.11,0.02478,9,189.25,30.83,0.26443,14,38.68,14.84,0.61556,23,-89.52,23.34,0.09454,32,-224.1,-58.8,5.1E-4,41,-297.11,-194.62,1.4E-4,6,10,-359.57,-12.88,0.00439,9,295.08,91.08,0.04956,14,160.45,16.54,0.32578,23,31.85,13.48,0.44083,32,-106.86,-25.89,0.16548,41,-203.08,-117.24,0.01394,6,10,-488.69,-37.69,5.8E-4,9,414.43,146.25,0.00544,14,291.61,7.27,0.08857,23,161.53,-8.2,0.3197,32,22.27,-1.18,0.37813,41,-94.86,-42.56,0.20756,6,10,-607.64,-27.83,4.1E-4,9,532.26,165.32,7.2E-4,14,404.01,-32.87,0.02089,23,269.61,-58.84,0.12051,32,141.21,-11.13,0.334,41,17.98,-3.72,0.52343,1,26,26.4,-166.06,1,1,26,87.21,-106.12,1,1,26,108.19,-49.62,1,2,26,61.73,-82.13,0.50021,37,4.42,52.83,0.49978,2,26,22.84,-109.4,0.50021,37,51.52,46.73,0.49978,5,10,348.39,119.13,0.00694,15,247.12,-50.52,0.065,18,60.86,-121.4,0.06027,26,-30.3,-118,0.48738,37,96.58,17.22,0.38039,1,10,26.73,14.8,1,2,10,-107.97,25.67,0.24192,9,60.17,-6.91,0.75807,5,10,235.53,102.96,0.07484,15,150.1,9.35,0.34943,18,27.64,-12.34,0.40983,26,-44.43,-4.87,0.14928,37,34.03,-74.39,0.0166,5,10,227.15,28.49,0.29239,15,95.96,-42.46,0.5708,18,-47.23,-15.44,0.07952,26,-118.74,4.84,0.03982,37,84.85,-129.5,0.01745,2,26,5.19,-153.1,0.87618,37,90.96,71.21,0.12381,5,10,351.78,108.85,0.01127,15,243.13,-60.59,0.10548,18,51.21,-126.33,0.09782,26,-40.65,-121.21,0.46541,37,105.71,17.33,0.32,1,26,23.69,-185.21,1],"hull":38,"edges":[22,20,20,18,18,16,6,4,4,2,2,0,0,74,74,72,44,42,42,40,24,22,24,76,76,22,76,78,78,20,78,80,80,18,80,82,82,16,12,84,84,68,86,72,86,74,68,88,88,78,82,88,64,90,90,76,60,92,92,24,56,94,94,28,52,96,96,32,48,98,98,36,44,100,100,40,72,70,70,68,102,86,70,102,8,6,102,8,24,26,26,28,92,104,104,94,26,104,56,58,58,60,104,58,28,30,30,32,94,106,106,96,30,106,52,54,54,56,106,54,32,34,34,36,96,108,108,98,34,108,48,50,50,52,108,50,36,38,38,40,98,110,110,100,38,110,44,46,46,48,110,46,112,114,114,116,116,118,120,86,118,120,120,122,64,66,66,68,88,124,124,90,66,124,60,62,62,64,90,126,126,92,62,126,8,10,10,12,84,128,128,102,10,128,12,14,14,16,82,130,130,84,14,130,6,132,132,120,8,134,134,122,132,134,6,136,132,136,0,136,112,136],"width":1219,"height":570}},"velo_front_arm":{"velo_front_arm":{"type":"skinnedmesh","uvs":[0.39562,0.1396,0.3877,0.30212,0.3123,0.41784,0.27287,0.47835,0.33388,0.4507,0.54879,0.35328,0.64092,0.31152,0.73024,0.36529,1,0.5277,1,0.86606,0.93242,1,0.86176,0.80967,0.75576,0.99765,0.71748,1,0.70276,0.77442,0.62031,0.73448,0.58792,0.64519,0.53561,0.6582,0.13448,0.75798,0,0.69218,0.01846,0.56357,0.05498,0.30917,0,0.27863,0,0.12423,0,0,0.19596,0,0.40242,0,0.24536,0.1924,0.21678,0.0811],"triangles":[0,28,26,23,25,28,28,25,26,23,24,25,6,7,16,6,16,5,15,16,7,7,14,15,8,14,7,11,14,8,11,8,9,12,14,11,13,14,12,10,11,9,17,4,5,16,17,5,18,19,3,18,3,4,18,4,17,27,28,0,27,22,23,27,23,28,1,27,0,21,22,27,21,27,1,2,21,1,2,20,21,3,20,2,19,20,3],"vertices":[2,16,3.06,31.88,0.51075,15,66.56,-109.48,0.48924,1,16,35.87,35.62,1,2,16,60.94,27.12,0.8464,24,46.49,31.12,0.15359,3,16,74.05,22.67,0.34375,24,36.5,21.53,0.64062,34,-45.25,-29.96,0.01562,3,16,67,31.58,0.10937,24,47.66,23.68,0.78125,34,-40.93,-19.44,0.10937,3,16,42.17,62.99,0.01562,24,86.98,31.24,0.64062,34,-25.75,17.61,0.34375,2,24,103.83,34.49,0.34375,34,-19.24,33.49,0.65625,2,24,114.04,19.51,0.10937,34,-1.11,33.84,0.89062,2,24,144.85,-25.73,0.02083,34,53.62,34.88,0.97916,1,34,96.03,-19.16,1,1,34,104.2,-47.31,1,1,34,71.34,-23.98,1,1,34,81.39,-64.61,1,1,34,76.8,-68.81,1,2,24,83.18,-57.72,0.02083,34,46.65,-34.25,0.97916,2,24,73.13,-45.76,0.10937,34,31.14,-36.12,0.89062,2,24,73.98,-26.9,0.34375,34,15.82,-25.09,0.65625,3,16,103.67,70.28,0.01562,24,65.1,-26.69,0.64062,34,10.78,-32.41,0.34375,3,16,133.56,9.13,0.10937,24,-2.94,-25.03,0.78125,34,-27.84,-88.47,0.10937,3,16,123.67,-14.42,0.34375,24,-19.29,-5.39,0.64062,34,-53.23,-91.41,0.01562,2,16,97.41,-15.43,0.8464,24,-8.08,18.37,0.15359,1,16,45.46,-17.43,1,2,16,40.69,-27.17,0.45035,15,-1.69,-93.8,0.54964,2,16,-2.74,-29.63,0.44352,15,18.99,-72.93,0.55647,1,15,32.11,-48.45,1,1,15,57.56,-67.43,1,1,15,84.38,-87.42,1,2,16,16.44,5.21,0.7182,15,46.31,-101.86,0.28179,2,16,-4.51,5.32,0.48851,15,52.82,-81.94,0.51148],"hull":27,"edges":[38,36,32,30,30,28,28,26,24,26,24,22,22,20,20,18,18,16,44,42,38,6,38,40,40,42,6,4,4,2,40,4,8,6,36,8,32,12,42,2,52,0,0,2,16,14,14,12,30,14,36,34,34,32,12,10,10,8,34,10,48,50,50,52,0,54,54,44,54,42,44,46,46,48,50,56,56,54,46,56,56,52],"width":162,"height":203}},"velo_front_leg":{"velo_front_leg":{"type":"skinnedmesh","uvs":[0.55116,0.17817,0.6279,0.36027,0.6671,0.4533,0.64879,0.51527,0.53553,0.56893,0.32335,0.66946,0.28674,0.72086,0.32538,0.804,0.36258,0.80144,0.42056,0.79744,0.61015,0.78435,0.84813,0.84028,1,0.93854,0.62439,0.91738,0.72812,1,0.58574,1,0.36707,0.96667,0.26306,0.95082,0.16266,0.93552,0.03859,0.72237,0,0.66946,0.0374,0.62999,0.1647,0.49562,0.23731,0.4568,0.27019,0.43923,0.28063,0.43364,0.223,0.4057,0.12565,0.35851,0,0.29759,0,0.1524,0,0,0.32132,0,0.32222,0.22778,0.4493,0.38031,0.47664,0.44361,0.4615,0.47375,0.35106,0.53247,0.20091,0.65256,0.18527,0.72148,0.25222,0.86314,0.30941,0.88124,0.55694,0.89613,0.55857,0.89207,0.47493,0.85339,0.6059,0.91526,0.39705,0.89129,0.13229,0.09352,0.36997,0.45345,0.37163,0.43827,0.32515,0.39424,0.23759,0.34425,0.34065,0.47414],"triangles":[46,30,31,43,9,10,42,43,10,41,43,42,13,44,42,10,13,42,11,13,10,13,11,12,45,8,9,45,9,43,40,8,45,41,42,44,45,43,41,45,41,44,16,40,45,17,40,16,15,45,44,16,45,15,14,15,44,13,14,44,19,21,38,20,21,19,39,38,6,39,6,7,40,39,7,40,7,8,18,19,38,18,38,39,17,39,40,18,39,17,47,25,48,24,25,47,35,48,34,47,48,35,51,24,47,23,24,51,3,34,2,35,34,3,36,51,47,23,51,36,22,23,36,36,47,35,4,35,3,36,35,4,37,22,36,21,22,37,5,37,36,5,36,4,6,37,5,38,21,37,38,37,6,29,30,46,32,31,0,46,31,32,28,29,46,28,46,32,32,27,28,50,27,32,33,32,0,33,0,1,49,50,32,33,49,32,26,27,50,26,50,49,25,26,49,48,49,33,25,49,48,34,33,1,48,33,34,34,1,2],"vertices":[3,4,128.03,88.47,0.83908,11,-70.2,-134.13,0.01331,2,158.83,-71.91,0.1476,2,4,219.55,53.15,0.77988,11,-48.04,-38.58,0.22011,3,4,266.3,35.1,0.53531,11,-36.73,10.22,0.46443,25,127.25,245.46,2.4E-4,4,4,286.89,9.79,0.35076,11,-14.56,34.14,0.64667,25,125.69,212.88,0.0023,33,101.39,199.13,2.5E-4,4,4,281.54,-41.24,0.09169,11,36.71,36,0.90196,25,87.64,178.44,0.00513,33,58.29,171.29,0.00119,5,4,271.53,-136.86,0.05608,11,132.77,39.48,0.69232,17,34.99,78.76,0.22087,25,16.38,113.93,0.0224,33,-22.45,119.13,0.0083,5,4,283.51,-164.25,0.01987,11,158.21,55.17,0.50334,17,52.65,54.63,0.3617,25,7.01,85.54,0.08322,33,-36.28,92.63,0.03184,6,4,326.15,-179.3,0.00798,11,167.14,99.49,0.21327,17,97.55,49.25,0.35075,25,28.72,45.87,0.14107,33,-21.26,49.99,0.22311,43,-72.29,25.96,0.0638,6,4,333.96,-167.35,0.00242,11,154.22,105.55,0.07519,17,102.57,62.6,0.22995,25,42.51,49.55,0.2831,33,-7.06,51.39,0.2694,43,-58.17,28.03,0.13992,6,4,344.19,-149.68,4.9E-4,11,134.24,114.44,0.0176,17,109.72,83.39,0.11397,25,64.09,55.23,0.07976,33,15.12,53.51,0.36292,43,-36.09,31.19,0.42523,1,43,35.8,41.81,1,1,43,128.11,17.93,1,1,43,188.72,-29.42,1,1,43,44.86,-26.17,1,1,33,133.17,-49.83,1,1,33,78.78,-50.15,1,5,4,399.32,-220.02,2.2E-4,11,195.56,179.43,0.01703,17,179.46,27.52,0.2372,25,58.34,-33.93,0.2023,33,-4.91,-33.55,0.54324,5,4,370.41,-244.91,3.2E-4,11,225.9,152.49,0.02513,17,155.04,-5.13,0.35003,25,17.88,-32.5,0.29852,33,-44.62,-25.61,0.32598,5,4,340.37,-270.04,0.00251,11,254.98,126.27,0.10129,17,131.21,-36.2,0.54075,25,-21.24,-31.17,0.2082,33,-83.02,-17.97,0.14723,5,4,225.1,-238.94,0.01529,11,240.33,7.81,0.24036,17,11.94,-30.98,0.57881,25,-86.31,68.9,0.12023,33,-131.06,91.29,0.04528,5,4,194.64,-233.55,0.04819,11,239.26,-23.1,0.40427,17,-18.96,-32.37,0.48451,25,-105.4,93.25,0.04604,33,-145.97,118.4,0.01697,5,4,187.65,-209.73,0.09565,11,216.66,-33.35,0.57617,17,-30.97,-10.65,0.30651,25,-94.71,115.65,0.01788,33,-131.8,138.78,0.00376,4,4,163.85,-128.67,0.19533,11,139.75,-68.26,0.8011,25,-58.32,191.88,0.00327,33,-83.58,208.13,2.9E-4,4,4,165.74,-94.49,0.31921,11,105.59,-71.26,0.6795,25,-5.04,220.72,0.00117,33,-56.32,275.96,1.0E-4,4,4,166.39,-79.07,0.46205,11,90.23,-72.76,0.53752,25,5.55,230.48,3.9E-4,33,-40.61,286.16,2.0E-5,3,4,166.49,-74.17,0.53779,11,85.42,-73.28,0.46208,25,-19.99,230.7,1.2E-4,2,4,141.54,-82.46,0.73138,11,97.13,-96.82,0.26861,3,4,99.76,-97.08,0.81379,11,117.34,-136.23,0.13997,2,-2.56,-164.19,0.04623,3,4,45.01,-114.56,0.8186,11,142.41,-187.89,0.02098,2,-51.09,-135.29,0.1604,3,4,-16.2,-74.76,0.62389,11,113.82,-253.08,0.00952,2,-42.95,-58.38,0.36658,2,4,-74.73,-19.33,0.31468,2,-52.66,17.55,0.68531,2,4,1.67,76.75,0.25576,2,70.07,18.78,0.74423,1,4,93.54,4.13,1,2,4,185.14,-6.66,0.75461,11,15.98,-64.27,0.24538,2,4,217.11,-18.75,0.50845,11,23.47,-30.93,0.49154,3,4,225.63,-32.92,0.32512,11,36.3,-20.5,0.6744,25,51.57,221.95,4.7E-4,4,4,223,-84.73,0.20061,11,87.96,-15.86,0.79287,25,15.03,185.13,0.00581,33,-12.28,189.61,6.9E-4,5,4,235.61,-168.06,0.07777,11,168.69,8.29,0.54931,17,6.74,40.47,0.33413,25,-31.18,114.66,0.0321,33,-69.27,127.55,0.00667,5,4,259.63,-194.79,0.01921,11,191.79,35.8,0.30498,17,36,19.62,0.53642,25,-31.14,78.74,0.09568,33,-75.03,92.09,0.04369,5,4,332.55,-220.1,0.00292,11,206.64,111.53,0.10776,17,112.69,10.82,0.51915,25,6.25,11.23,0.23449,33,-49.03,19.43,0.13566,4,11,192.51,130.62,0.03213,17,130.6,26.41,0.33941,25,29.35,5.71,0.27333,33,-27.12,10.25,0.35511,1,33,67.46,3.16,1,1,43,19.07,-14.51,1,6,4,381.55,-150.4,3.0E-4,11,130.71,150.34,0.00811,17,145.36,89.53,0.04102,25,89.29,30.41,0.02558,33,36,24.95,0.37636,43,-13.89,3.64,0.54861,1,33,86.23,-6.55,1,4,11,164.9,153.55,0.02263,17,151.18,56,0.23908,25,65.44,5.55,0.19254,33,8.45,4.27,0.54574,2,4,-9.28,-17.5,0.59606,2,7.72,-30.85,0.40393,3,4,195.9,-53.81,0.42356,11,61.11,-47.06,0.57613,25,39.7,225.21,2.9E-4,3,4,190.1,-48.45,0.53227,11,56.61,-53.56,0.46765,25,39.83,233.12,6.0E-5,2,4,161.26,-48.26,0.79873,11,60.44,-82.13,0.20126,3,4,120.37,-58.54,0.8485,11,76.31,-121.18,0.14441,2,41.04,-161.4,0.00707,4,4,197.37,-69.23,0.33487,11,76.17,-43.46,0.66324,25,30.34,213.88,0.0017,33,-9.09,262.42,1.8E-4],"hull":32,"edges":[40,38,38,36,28,30,28,26,26,24,24,22,22,20,14,12,12,10,6,4,60,62,0,62,40,42,42,44,34,36,16,14,52,50,4,2,2,0,10,8,8,6,0,64,64,56,2,66,64,66,4,68,66,68,6,70,68,70,8,72,72,44,70,72,10,74,74,42,72,74,12,76,76,38,74,76,14,78,78,36,76,78,16,80,80,34,78,80,26,84,86,84,86,20,26,88,82,88,88,28,80,90,90,88,16,18,18,20,18,90,30,32,32,34,90,32,86,18,82,86,56,58,58,60,60,92,92,64,58,92,92,62,94,70,50,96,96,68,94,96,52,98,98,66,96,98,52,54,54,56,54,100,100,98,100,64,48,50,94,48,44,46,46,48,46,102,102,72,102,94],"width":382,"height":514}},"velo_hindleg_back":{"velo_hindleg_back":{"type":"skinnedmesh","uvs":[0.45041,0.09352,0.56933,0.23361,0.65294,0.47296,0.66353,0.50822,0.63174,0.54254,0.32383,0.69723,0.30068,0.73875,0.27934,0.77704,0.30417,0.83513,0.31058,0.85014,0.341,0.85046,0.45165,0.85163,0.59555,0.81881,0.91176,0.92548,1,1,0.56336,0.96426,0.48349,0.9826,0.29878,0.98027,0.22808,0.98389,0.15997,0.98737,0.15423,0.95546,0.13894,0.87047,0.07371,0.78726,0,0.75299,0,0.7049,0,0.671,0.11875,0.64652,0.16535,0.52659,0.28495,0.47397,0.2901,0.45773,0.29427,0.4446,0.20635,0.40396,0.06128,0.33691,0,0.25247,0,0,0.30793,0,0.27599,0.20261,0.40397,0.31121,0.48439,0.45963,0.48317,0.48383,0.47029,0.51062,0.22698,0.67328,0.17141,0.7242,0.17122,0.78241,0.22995,0.89469,0.24677,0.90829,0.28672,0.9146,0.46582,0.91414],"triangles":[16,47,15,15,12,13,15,13,14,15,47,12,47,10,11,17,46,47,47,46,10,18,46,17,17,47,16,18,45,46,47,11,12,22,23,24,43,42,7,43,22,42,21,22,43,44,43,7,44,7,8,44,8,9,21,43,44,45,44,9,46,45,9,20,21,44,20,45,19,44,45,20,45,18,19,46,9,10,41,27,28,26,27,41,41,28,40,5,41,40,5,40,4,24,25,26,42,26,41,24,26,42,6,41,5,42,41,6,28,29,40,40,39,4,7,42,6,24,42,22,40,29,39,36,34,35,36,35,0,33,34,36,37,36,0,37,0,1,32,33,36,31,32,36,31,36,37,30,31,37,38,37,1,30,37,38,38,1,2,39,30,38,39,38,2,29,30,39,39,2,3,4,39,3],"vertices":[1,6,53.94,69.15,1,1,6,126.23,67.31,1,2,6,226.42,31.13,0.9375,12,-30.87,-1.11,0.0625,2,6,240.84,25.33,0.7,12,-25.64,13.52,0.3,2,6,246.67,8.05,0.3,12,-8.61,20.02,0.7,3,6,240.81,-115.25,0.0625,12,114.8,19.01,0.875,20,9.48,59.16,0.0625,2,12,131.07,29.69,0.7,20,22.11,44.35,0.3,2,12,146.06,39.54,0.3,20,33.76,30.71,0.7,4,12,152.6,65.01,0.12438,20,59.85,27.41,0.74434,28,15.85,48.05,0.12104,38,-80.52,23.87,0.01022,4,12,154.28,71.59,0.0519,20,66.59,26.56,0.74749,28,16.72,41.31,0.15401,38,-77.54,17.76,0.04658,4,12,145.73,77.3,0.02193,20,71.19,35.76,0.63296,28,26.78,39.17,0.1288,38,-67.32,18.96,0.21628,3,20,87.93,69.21,0.0625,28,63.37,31.39,0.675,38,-30.17,23.3,0.26249,2,28,113.82,35.72,0.1038,38,16.23,43.56,0.89619,1,38,128.14,12.02,1,1,38,161.85,-15.81,1,2,28,90.98,-23.36,0.0138,38,13.52,-19.72,0.98619,2,28,62.97,-25.81,0.7,38,-12.23,-31.02,0.3,3,20,115.12,-1.33,0.08333,28,1.93,-12.66,0.83333,38,-74.26,-38.1,0.08333,2,20,106.11,-23.53,0.3,28,-21.8,-9.52,0.7,2,20,97.43,-44.9,0.7,28,-44.67,-6.51,0.3,2,20,84.26,-40.69,0.9375,28,-43.9,7.29,0.0625,1,20,49.18,-29.46,1,2,12,206.75,5.37,0.13333,20,7.44,-33.77,0.86666,2,12,219.64,-20.52,0.36111,20,-16.64,-49.8,0.63888,2,12,208.4,-37.82,0.72083,20,-35.22,-40.82,0.27916,2,12,200.49,-50.02,0.91666,20,-48.31,-34.48,0.08333,1,12,161.1,-36.97,1,2,6,150.1,-116.76,0.08333,12,119.88,-71.55,0.91666,2,6,154.99,-70.71,0.42846,12,73.68,-68.47,0.57153,2,6,150.3,-65.27,0.35604,12,68.42,-73.36,0.64395,2,6,146.51,-60.87,0.59147,12,64.17,-77.32,0.40852,2,6,115.12,-75.08,0.8446,12,79.61,-108.13,0.15539,1,6,63.33,-98.53,1,1,6,21.78,-94.55,1,1,6,-66.69,-32.04,1,1,6,-6.62,52.97,1,1,6,58.14,-6,1,1,6,121.17,2.44,1,2,6,188.87,-12.1,0.96,12,13.79,-36.92,0.04,2,6,197.11,-18.42,0.7,12,19.79,-28.44,0.3,2,6,203.98,-28.61,0.3,12,29.69,-21.17,0.7,3,6,213.53,-136.06,0.04,12,136.67,-7.42,0.91999,20,-14.02,34.16,0.04,2,12,164.32,0.66,0.7,20,-2.53,7.73,0.3,2,12,177.97,21.57,0.25,20,19.92,-3.19,0.75,3,12,187.55,72.78,0.04,20,71.93,-6.29,0.91999,28,-13.72,27.87,0.04,2,20,79.66,-3.72,0.7,28,-9.28,21.04,0.3,3,20,87.98,7.25,0.3,28,3.42,15.76,0.66,38,-81.96,-10.7,0.04,3,20,114.16,61.85,0.04,28,62.84,4.15,0.7,38,-21.95,-2.66,0.26],"hull":36,"edges":[66,68,66,64,56,54,54,52,52,50,46,44,44,42,34,32,32,30,30,28,28,26,26,24,24,22,10,8,8,6,6,4,4,2,2,0,68,70,0,70,46,48,48,50,14,12,12,10,60,58,58,56,42,40,40,38,18,16,16,14,22,20,20,18,38,36,36,34,60,62,62,64,0,72,72,64,68,72,2,74,74,62,72,74,4,76,76,60,74,76,6,78,78,58,76,78,8,80,80,56,78,80,10,82,82,52,80,82,12,84,84,48,82,84,14,86,86,44,84,86,16,88,88,40,86,88,18,90,90,38,88,90,20,92,92,36,90,92,92,94,94,22,94,32,30,24,94,24],"width":338,"height":429}},"velo_horn":{"velo_horn":{"x":156.2,"y":74.1,"rotation":-137.26,"width":363,"height":159}},"velo_horn_back":{"velo_horn_back":{"x":121.42,"y":83.01,"rotation":-132.21,"width":351,"height":153}},"velo_jaw":{"velo_jaw":{"type":"skinnedmesh","uvs":[0.40984,0.22169,0.42214,0.3988,0.67894,0.53819,0.7589,0.62838,0.99999,0.4726,1,0.53491,0.87731,0.77925,0.63281,0.94487,0.39908,0.96947,0.19456,0.89404,0.21609,0.6497,0,0.46111,0,0,0.26069,0,0.19456,0.29385,0.31758,0.50047],"triangles":[14,13,0,10,11,15,15,14,1,2,7,8,8,9,10,15,2,8,15,8,10,7,3,6,7,2,3,2,15,1,6,3,5,5,3,4,14,0,1,11,14,15,11,12,14,14,12,13],"vertices":[1,37,28.6,68.85,1,1,37,69.65,38.95,1,1,37,150.72,72.88,1,1,37,186.16,74.79,1,1,37,199.76,159.69,1,1,37,213.35,148.16,1,1,37,242.43,74.42,1,1,37,230.31,-13.08,1,1,37,189.56,-71.99,1,1,37,132.76,-105.6,1,1,37,83.71,-55.39,1,2,26,-18.31,12.1,0.67732,37,-0.04,-70.76,0.32267,1,26,113.44,16.95,1,1,26,116.36,-62.48,1,1,37,1.86,5.43,1,1,37,71.19,-4.17,1],"hull":14,"edges":[22,24,22,20,20,18,18,16,16,14,14,12,12,10,10,8,8,6,6,4,4,2,2,0,24,26,0,26,24,28,28,30,30,20,22,28,28,0,30,2],"width":305,"height":286}},"velo_saddle_noshadow":{"velo_saddle_noshadow":{"x":80.83,"y":10.63,"rotation":-88.64,"width":326,"height":375}},"velo_saddle_strap_front":{"velo_saddle_strap_front":{"x":128.83,"y":-4.71,"rotation":61.29,"width":114,"height":189}},"velo_saddle_strap_rear":{"velo_saddle_strap_rear":{"type":"skinnedmesh","uvs":[0.85499,0.06802,1,0.13237,1,0.20266,0.95981,0.26524,0.88583,0.38045,0.80684,0.46413,0.74038,0.53453,0.81676,0.5895,0.51961,1,0.4516,1,0.01739,0.8407,0,0.80889,0.24645,0.36639,0.3792,0.39151,0.42457,0.32099,0.49229,0.21571,0.57673,0.10986,0.66437,0,0.70168,0,0.56028,0.46321,0.68822,0.29772,0.76845,0.18722,0.61529,0.39206],"triangles":[19,14,22,13,14,19,19,22,6,13,10,11,9,13,19,8,9,19,6,8,19,13,11,12,9,10,13,7,8,6,22,15,20,14,15,22,5,20,4,22,20,5,15,16,20,20,21,4,6,22,5,21,18,0,16,17,18,21,16,18,0,1,2,3,21,0,2,3,0,20,16,21,4,21,3],"vertices":[1,22,3.9,-3.27,1,1,22,4.25,15.05,1,1,22,13.24,20.28,1,2,22,23.42,21.2,0.7,30,-15.2,21.22,0.3,3,22,41.11,22.87,0.3,30,2.48,22.89,0.6375,40,-33.83,24.96,0.0625,3,22,52.07,21.72,0.0625,30,13.43,21.74,0.6375,40,-22.97,23.11,0.3,2,30,18.39,20.76,0.25,40,-18.09,21.82,0.75,1,40,-18.76,33.09,1,1,40,49.92,31.57,1,1,40,53.21,25,1,1,40,53.11,-27.48,1,1,40,49.74,-31.27,1,1,40,-20.73,-36.76,1,1,40,-23.82,-22.28,1,3,22,53.48,-24.61,0.0625,30,14.84,-24.59,0.575,40,-24.51,-23.21,0.3625,3,22,41.44,-26.12,0.3,30,2.81,-26.09,0.6375,40,-36.62,-23.95,0.0625,2,22,24.38,-26.12,0.7,30,-14.24,-26.1,0.3,1,22,5.57,-26.12,1,1,22,3.54,-22.64,1,1,40,-23.08,-0.04,1,3,22,41.66,-1.72,0.3,30,3.03,-1.7,0.66,40,-34.85,0.38,0.04,2,22,23.85,-2.46,0.7,30,-14.77,-2.44,0.3,3,22,52.58,-1.52,0.04,30,13.95,-1.5,0.62,40,-23.94,-0.11,0.34],"hull":19,"edges":[26,24,24,22,22,20,20,18,16,18,16,14,14,12,4,2,34,36,12,38,38,26,8,40,40,30,2,0,0,36,30,32,32,34,0,42,42,40,32,42,4,6,6,8,42,6,26,28,28,30,38,44,44,40,28,44,8,10,10,12,44,10],"width":108,"height":148}},"velo_saddle_w_shadow":{"velo_saddle_w_shadow":{"x":80.83,"y":10.63,"rotation":-88.64,"width":326,"height":375}},"velo_tongue":{"velo_tongue":{"type":"skinnedmesh","uvs":[0.35242,0.2156,0.4794,0.44245,0.62071,0.61176,0.80562,0.75373,1,0.90297,1,1,0.8971,1,0.72054,0.92254,0.50668,0.82872,0.30401,0.70725,0.10537,0.57888,0,0.50622,0,0,0.26224,0],"triangles":[8,7,6,6,4,5,4,6,3,6,7,3,7,8,3,8,2,3,9,10,1,8,9,2,9,1,2,1,10,0,10,11,0,0,12,13,0,11,12],"vertices":[2,42,3.63,27.04,0.6875,44,-47.26,33.87,0.3125,3,42,39.09,19.45,0.3125,44,-13.41,20.86,0.625,45,-51.54,33.37,0.0625,3,42,71.56,19.02,0.0625,44,18.58,15.39,0.625,45,-21.56,20.92,0.3125,2,44,55.03,16.85,0.3125,45,14.29,14.23,0.6875,2,44,93.34,18.39,0.08333,45,51.98,7.21,0.91666,1,45,56.09,-4.5,1,2,44,85.06,-1.49,0.08333,45,39.48,-10.33,0.91666,2,44,54.22,-9.18,0.3125,45,7.71,-10.96,0.6875,3,42,75.14,-14.72,0.0625,44,16.87,-18.5,0.625,45,-30.77,-11.73,0.3125,3,42,38.8,-25.8,0.3125,44,-20.74,-23.8,0.625,45,-68.62,-8.53,0.0625,2,42,2.4,-35.77,0.6875,44,-58.25,-27.99,0.3125,2,42,-17.28,-40.62,0.91666,44,-78.45,-29.71,0.08333,1,42,-59.91,8.18,1,2,42,-26.13,37.69,0.91666,44,-75.02,49.02,0.08333],"hull":14,"edges":[22,24,10,12,10,8,24,26,16,4,18,16,2,4,18,2,22,20,0,26,20,0,0,2,12,14,14,16,4,6,6,8,14,6,20,18],"width":171,"height":128}}}},"animations":{"attack":{"bones":{"rear_arm1":{"rotate":[{"time":0,"angle":-31.17},{"time":0.3333,"angle":49.35},{"time":1,"angle":-17.92},{"time":1.4333,"angle":-31.17}]},"rear_arm2":{"rotate":[{"time":0,"angle":-4.84},{"time":0.3333,"angle":-81.73},{"time":1,"angle":-11.47},{"time":1.4333,"angle":-41.6}]},"rear_hand":{"rotate":[{"time":0,"angle":-25.84},{"time":0.3333,"angle":36.57},{"time":1,"angle":-24.32},{"time":1.4333,"angle":0}]},"tail2":{"rotate":[{"time":0,"angle":-12.58},{"time":0.3333,"angle":-34.38},{"time":0.5,"angle":3.7},{"time":0.6,"angle":10.57},{"time":1.0333,"angle":-7.07},{"time":1.3333,"angle":-16.78},{"time":1.4333,"angle":-12.58}]},"tail3":{"rotate":[{"time":0,"angle":-12.58},{"time":0.3333,"angle":-34.38},{"time":0.5,"angle":3.7},{"time":0.6,"angle":10.57},{"time":0.9333,"angle":6.12},{"time":1.0333,"angle":-7.07},{"time":1.3333,"angle":-16.78},{"time":1.4333,"angle":-12.58}]},"tail4":{"rotate":[{"time":0,"angle":-12.58},{"time":0.3333,"angle":-34.38},{"time":0.5,"angle":3.7},{"time":0.6,"angle":-12.83},{"time":1.0333,"angle":33.51},{"time":1.3333,"angle":0.68},{"time":1.4333,"angle":-12.58}]},"tail5":{"rotate":[{"time":0,"angle":-12.58},{"time":0.3333,"angle":-34.38},{"time":0.5,"angle":3.7},{"time":0.6,"angle":-12.83},{"time":1.0333,"angle":14.86},{"time":1.3333,"angle":-17.96},{"time":1.4333,"angle":-12.58}]},"torso2":{"rotate":[{"time":0,"angle":0},{"time":0.3333,"angle":13.38},{"time":0.5,"angle":-11.64},{"time":1.0333,"angle":10.25,"curve":"stepped"},{"time":1.3333,"angle":10.25},{"time":1.4333,"angle":0}],"scale":[{"time":0.3333,"x":1,"y":1}]},"neck":{"rotate":[{"time":0,"angle":-12.4},{"time":0.3333,"angle":13.38},{"time":0.5333,"angle":-21.32},{"time":1.0333,"angle":-32.76,"curve":"stepped"},{"time":1.3333,"angle":-32.76},{"time":1.4333,"angle":-12.4}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.3333,"x":0,"y":0},{"time":0.5333,"x":52.94,"y":-11.36},{"time":0.8,"x":0,"y":0,"curve":"stepped"},{"time":1.4333,"x":0,"y":0}]},"head":{"rotate":[{"time":0,"angle":-12.4},{"time":0.3333,"angle":-23.09},{"time":0.5333,"angle":-14.19},{"time":0.7,"angle":63.83},{"time":1.0333,"angle":31.61},{"time":1.3333,"angle":12.74},{"time":1.4333,"angle":-12.4}]},"jaw":{"rotate":[{"time":0,"angle":5.7},{"time":0.5,"angle":-10.5},{"time":0.5666,"angle":16.93},{"time":1.4333,"angle":-3.9}]},"tongue1":{"rotate":[{"time":0,"angle":0},{"time":0.3333,"angle":-27.63},{"time":1.4333,"angle":0}]},"tongue2":{"rotate":[{"time":0,"angle":-4.73},{"time":0.3333,"angle":27.19},{"time":1.4333,"angle":-4.73}]},"tongue3":{"rotate":[{"time":0,"angle":-4.73},{"time":0.3333,"angle":27.19},{"time":1.4333,"angle":-4.73}]},"front_foot_goal":{"rotate":[{"time":0,"angle":-41.82},{"time":0.3333,"angle":-68.69},{"time":0.7666,"angle":-54.82},{"time":1.4333,"angle":-41.82}],"translate":[{"time":0,"x":-355.05,"y":29.5,"curve":"stepped"},{"time":1.4333,"x":-355.05,"y":29.5}]},"hip":{"rotate":[{"time":0,"angle":30.52},{"time":0.3333,"angle":3.37},{"time":1.0333,"angle":15.45,"curve":"stepped"},{"time":1.2,"angle":15.45},{"time":1.4333,"angle":30.52}],"translate":[{"time":0,"x":-259.84,"y":46.63},{"time":0.3333,"x":-48.81,"y":-13.04},{"time":0.5,"x":11.29,"y":-76.83},{"time":0.6333,"x":-19.31,"y":-53.65},{"time":1.0333,"x":-114.92,"y":7.75},{"time":1.2,"x":-163.39,"y":30.83},{"time":1.4333,"x":-259.84,"y":46.63}]},"front_leg1":{"rotate":[{"time":0,"angle":-42.15},{"time":0.1666,"angle":-60.58},{"time":0.2,"angle":-41.23},{"time":0.2666,"angle":-52.43},{"time":0.3333,"angle":-42.62},{"time":0.3666,"angle":-46.04},{"time":0.4,"angle":-47.24},{"time":0.5,"angle":-60.67},{"time":0.5333,"angle":-59.31},{"time":0.6333,"angle":-55.23},{"time":0.6666,"angle":-54.94},{"time":0.7,"angle":-54.66},{"time":0.7666,"angle":-54.17},{"time":0.8666,"angle":-52.95},{"time":0.9,"angle":-52.59},{"time":0.9333,"angle":-50.4},{"time":1,"angle":-51.69},{"time":1.0333,"angle":-48.5},{"time":1.1333,"angle":-46.17},{"time":1.2,"angle":-42.81},{"time":1.3,"angle":-42.24},{"time":1.3333,"angle":-42.12},{"time":1.4333,"angle":-53.97}],"translate":[{"time":0,"x":27.36,"y":-5.17,"curve":"stepped"},{"time":1.4333,"x":27.36,"y":-5.17}]},"rear_leg1":{"rotate":[{"time":0,"angle":-21.37},{"time":0.1666,"angle":7.44},{"time":0.2,"angle":8.7},{"time":0.2666,"angle":11.07},{"time":0.3333,"angle":30.05},{"time":0.3666,"angle":37.77},{"time":0.4,"angle":12.69},{"time":0.5,"angle":21.48},{"time":0.5333,"angle":21.71},{"time":0.6333,"angle":21.14},{"time":0.6666,"angle":38.54},{"time":0.7,"angle":11.98},{"time":0.7666,"angle":12.95},{"time":0.8666,"angle":6.06},{"time":0.9,"angle":3.61},{"time":0.9333,"angle":5.65},{"time":1,"angle":14.71},{"time":1.0333,"angle":1.62},{"time":1.1333,"angle":6.03},{"time":1.2,"angle":18.26},{"time":1.3,"angle":-15.18},{"time":1.3333,"angle":-16.33},{"time":1.4333,"angle":2.13}]},"rear_strap_goal":{"translate":[{"time":0,"x":-16.13,"y":0.02,"curve":"stepped"},{"time":1.4333,"x":-16.13,"y":0.02}]},"front_leg2":{"rotate":[{"time":0,"angle":-354.16},{"time":0.1666,"angle":-341.37},{"time":0.2,"angle":-359.33},{"time":0.2666,"angle":-347.98},{"time":0.3333,"angle":-355.66},{"time":0.3666,"angle":-355.77},{"time":0.4,"angle":-352.04},{"time":0.5,"angle":-353.32},{"time":0.5333,"angle":-354.81},{"time":0.6333,"angle":-358.77},{"time":0.6666,"angle":-358.35},{"time":0.7,"angle":-357.89},{"time":0.7666,"angle":-356.83},{"time":0.8666,"angle":-355.58},{"time":0.9,"angle":-355.06},{"time":0.9333,"angle":-356.24},{"time":1,"angle":-353.23},{"time":1.0333,"angle":-355.14},{"time":1.1333,"angle":-353.34},{"time":1.2,"angle":-353.4},{"time":1.3,"angle":-354.75},{"time":1.3333,"angle":-354.87},{"time":1.4333,"angle":-347.84}]},"rear_leg2":{"rotate":[{"time":0,"angle":29.39},{"time":0.1666,"angle":-17.46},{"time":0.2,"angle":-19.58},{"time":0.2666,"angle":-9.32},{"time":0.3333,"angle":-22.84},{"time":0.3666,"angle":-21.27},{"time":0.4,"angle":-2.17},{"time":0.5,"angle":-37.09},{"time":0.5333,"angle":-34.05},{"time":0.6333,"angle":-24.28},{"time":0.6666,"angle":-24.04},{"time":0.7,"angle":-9.85},{"time":0.7666,"angle":-10},{"time":0.8666,"angle":2.48},{"time":0.9,"angle":7.09},{"time":0.9333,"angle":10.04},{"time":1,"angle":4.65},{"time":1.0333,"angle":20.13},{"time":1.1333,"angle":-10.21},{"time":1.2,"angle":-7.77},{"time":1.3,"angle":13.8},{"time":1.3333,"angle":17.08},{"time":1.4333,"angle":-10.74}]},"front_leg3":{"rotate":[{"time":0,"angle":-33.13},{"time":0.1666,"angle":-32.61},{"time":0.2,"angle":-28.82},{"time":0.2666,"angle":-26.08},{"time":0.3333,"angle":-30.95},{"time":0.3666,"angle":-26.98},{"time":0.4,"angle":-21.77},{"time":0.5,"angle":-12.96},{"time":0.5333,"angle":-12.35},{"time":0.6333,"angle":-11.05},{"time":0.6666,"angle":-11.23},{"time":0.7,"angle":-11.51},{"time":0.7666,"angle":-12.12},{"time":0.8666,"angle":-14.29},{"time":0.9,"angle":-15.07},{"time":0.9333,"angle":-19.19},{"time":1,"angle":-17.52},{"time":1.0333,"angle":-23.85},{"time":1.1333,"angle":-20.83},{"time":1.2,"angle":-22.81},{"time":1.3,"angle":-26.51},{"time":1.3333,"angle":-28.03},{"time":1.4333,"angle":-46.22}]},"front_foot1":{"rotate":[{"time":0,"angle":20.78},{"time":0.1666,"angle":20.8},{"time":0.2,"angle":20.89},{"time":0.2666,"angle":20.78},{"time":0.3333,"angle":20.77},{"time":0.3666,"angle":20.84},{"time":0.4,"angle":20.77},{"time":0.5,"angle":20.82},{"time":0.5333,"angle":20.84},{"time":0.6333,"angle":20.85},{"time":0.6666,"angle":20.82},{"time":0.7,"angle":20.87},{"time":0.7666,"angle":20.92},{"time":0.9,"angle":20.87},{"time":0.9333,"angle":20.85},{"time":1,"angle":20.81},{"time":1.0333,"angle":20.83},{"time":1.2,"angle":20.77},{"time":1.3,"angle":20.79},{"time":1.3333,"angle":20.79},{"time":1.4333,"angle":21.04}]},"rear_foot1":{"rotate":[{"time":0,"angle":-34.45},{"time":0.1666,"angle":12.48},{"time":0.2,"angle":-33.81},{"time":0.2666,"angle":3.92},{"time":0.3333,"angle":-34.08},{"time":0.3666,"angle":-34.75},{"time":0.4,"angle":-3.14},{"time":0.5,"angle":-33.8},{"time":0.5333,"angle":-33.78},{"time":0.6333,"angle":-33.84},{"time":0.6666,"angle":-34.94},{"time":0.7,"angle":-3.1},{"time":0.7666,"angle":-33.82},{"time":0.8666,"angle":-33.86},{"time":0.9,"angle":-33.85},{"time":0.9333,"angle":-3.2},{"time":1,"angle":-34.48},{"time":1.0333,"angle":-3.36},{"time":1.1333,"angle":-33.82},{"time":1.2,"angle":16.28},{"time":1.3,"angle":-33.98},{"time":1.3333,"angle":-34.07},{"time":1.4333,"angle":22.21}]},"saddle_strap_rear2":{"rotate":[{"time":0,"angle":6.92},{"time":0.1666,"angle":6.79},{"time":0.2,"angle":19.96},{"time":0.2666,"angle":6.76},{"time":0.3333,"angle":19.51},{"time":0.3666,"angle":21.67},{"time":0.5,"angle":14.99},{"time":0.5333,"angle":14.58},{"time":0.6333,"angle":13.71},{"time":0.6666,"angle":13.4},{"time":0.7,"angle":12.9},{"time":0.7666,"angle":12.54},{"time":0.8666,"angle":11.7},{"time":0.9,"angle":11.41},{"time":1,"angle":10.54},{"time":1.0333,"angle":15.04},{"time":1.1333,"angle":9.43},{"time":1.2,"angle":8.86},{"time":1.3,"angle":8.01},{"time":1.3333,"angle":7.72},{"time":1.4333,"angle":6.92}],"translate":[{"time":0,"x":10.87,"y":1.11},{"time":0.5333,"x":20.01,"y":5.71},{"time":1.4333,"x":10.87,"y":1.11}]},"front_foot2":{"rotate":[{"time":0,"angle":2.35,"curve":"stepped"},{"time":1.4333,"angle":2.35}]},"rear_foot2":{"rotate":[{"time":0,"angle":-1.17},{"time":0.2,"angle":23.38},{"time":0.3666,"angle":2.64},{"time":1,"angle":3.58},{"time":1.1333,"angle":-10.84},{"time":1.3,"angle":1.15}]},"saddle_strap_rear3":{"rotate":[{"time":0,"angle":-3.42},{"time":0.2,"angle":-55.82},{"time":0.3333,"angle":-73.67},{"time":0.3666,"angle":-64.68},{"time":0.5,"angle":-3.42,"curve":"stepped"},{"time":1.4333,"angle":-3.42}]},"front_foot3":{"rotate":[{"time":0,"angle":-6.65,"curve":"stepped"},{"time":1.4333,"angle":-6.65}]},"rear_leg3":{"rotate":[{"time":0,"angle":-37.64},{"time":0.1666,"angle":-37.19},{"time":0.2,"angle":-8.97},{"time":0.2666,"angle":-27.11},{"time":0.3333,"angle":-25.52},{"time":0.3666,"angle":-41.88},{"time":0.4,"angle":-20.2},{"time":0.5,"angle":2.84},{"time":0.5333,"angle":0.59},{"time":0.6333,"angle":-5.45},{"time":0.6666,"angle":-45},{"time":0.7,"angle":-18.15},{"time":0.7666,"angle":-6.49},{"time":0.8666,"angle":-8.11},{"time":0.9,"angle":-8.94},{"time":0.9333,"angle":-35.98},{"time":1,"angle":-38.62},{"time":1.0333,"angle":-43.8},{"time":1.1333,"angle":-13.27},{"time":1.2,"angle":-34.58},{"time":1.3,"angle":-19.59},{"time":1.3333,"angle":-23.88},{"time":1.4333,"angle":-45.21}]},"rear_foot_goal":{"rotate":[{"time":0,"angle":-34.12},{"time":0.2,"angle":-56.49},{"time":0.6666,"angle":-33.52},{"time":0.9,"angle":-20.2},{"time":1,"angle":-39.38},{"time":1.3,"angle":-34.12}],"translate":[{"time":0,"x":-137.61,"y":-14.59},{"time":0.2,"x":-78.13,"y":22.13},{"time":0.3666,"x":33.81,"y":-16.34,"curve":"stepped"},{"time":1,"x":33.81,"y":-16.34},{"time":1.1333,"x":-67.64,"y":18.64},{"time":1.3,"x":-137.61,"y":-14.59}]},"front_leg_goal":{"translate":[{"time":0,"x":-4.83,"y":-26.3,"curve":"stepped"},{"time":1.4333,"x":-4.83,"y":-26.3}]},"rear_leg_goal":{"translate":[{"time":0,"x":-46.75,"y":-44.29}]},"torso1":{"rotate":[{"time":0,"angle":2.11},{"time":0.3333,"angle":11.62},{"time":0.5,"angle":-4.57},{"time":1.4333,"angle":2.11}]},"saddle":{"rotate":[{"time":0,"angle":-6.43,"curve":"stepped"},{"time":1.4333,"angle":-6.43}]},"front_arm1":{"rotate":[{"time":0,"angle":-48.58},{"time":0.3333,"angle":-371.75},{"time":0.9,"angle":-385.85},{"time":1.1333,"angle":-386.33},{"time":1.4333,"angle":-48.58}]},"front_arm2":{"rotate":[{"time":0,"angle":-23.48},{"time":0.3333,"angle":-45.53},{"time":0.7666,"angle":14.16},{"time":1.1333,"angle":-44.33},{"time":1.4333,"angle":-23.48}]},"tail1":{"rotate":[{"time":0,"angle":3.36},{"time":0.6,"angle":-6.68},{"time":1.4333,"angle":3.36}]},"front_hand":{"rotate":[{"time":0,"angle":11.5},{"time":0.3333,"angle":19.4},{"time":0.7666,"angle":-47.28},{"time":0.9,"angle":-18.77},{"time":1.1333,"angle":9.29},{"time":1.4333,"angle":11.5}]},"root":{"translate":[{"time":0,"x":173.04,"y":0}]}}},"walk":{"bones":{"root":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"front_foot_goal":{"rotate":[{"time":0,"angle":0},{"time":0.2666,"angle":-51.26},{"time":0.4,"angle":-65.17},{"time":0.5333,"angle":-76.28},{"time":0.8,"angle":-76.52},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":343.28,"y":36.5},{"time":0.2666,"x":86.5,"y":36.99},{"time":0.5333,"x":-173.36,"y":37.42},{"time":0.6,"x":-68.15,"y":141.15},{"time":0.7333,"x":91.78,"y":238.01},{"time":0.8,"x":155.89,"y":190.91},{"time":0.9666,"x":303.28,"y":94.4},{"time":1.0666,"x":343.28,"y":36.5}]},"hip":{"rotate":[{"time":0,"angle":-4.78},{"time":0.0666,"angle":-3.99},{"time":0.2666,"angle":-12.49},{"time":0.5333,"angle":-4.78},{"time":0.6,"angle":-3.99},{"time":0.8,"angle":-12.49},{"time":1.0666,"angle":-4.78}],"translate":[{"time":0,"x":161.93,"y":4.89,"curve":[0.27,0.37,0.62,0.4]},{"time":0.0666,"x":165.04,"y":-5.99,"curve":[0.244,0,0.757,1]},{"time":0.2666,"x":178.8,"y":136.52,"curve":[0.25,0,0.841,0.8]},{"time":0.5333,"x":161.93,"y":4.89,"curve":[0.27,0.37,0.62,0.4]},{"time":0.6,"x":165.04,"y":-5.99,"curve":[0.244,0,0.757,1]},{"time":0.8,"x":178.8,"y":136.52,"curve":[0.25,0,0.858,0.82]},{"time":1.0666,"x":161.93,"y":4.89}]},"rear_foot_goal":{"rotate":[{"time":0,"angle":-62.73},{"time":0.2666,"angle":-107.17},{"time":0.4666,"angle":-40.51},{"time":0.8,"angle":-97.15},{"time":1.0666,"angle":-62.73}],"translate":[{"time":0,"x":-266.69,"y":-15.46},{"time":0.1333,"x":-87.88,"y":124.85},{"time":0.2666,"x":88.35,"y":134.06},{"time":0.3666,"x":198.39,"y":90.64},{"time":0.4666,"x":308.19,"y":-26.42},{"time":0.6,"x":167.06,"y":-26.42},{"time":1.0666,"x":-266.69,"y":-15.46}]},"front_leg1":{"rotate":[{"time":0,"angle":27.07,"curve":"stepped"},{"time":1.0666,"angle":27.07}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.5333,"x":0,"y":0},{"time":0.7333,"x":-2.85,"y":15.32},{"time":1.0666,"x":0,"y":0}]},"front_leg_goal":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":-18.04,"y":-2.88},{"time":0.5333,"x":-41.17,"y":-105.11},{"time":0.7333,"x":-1.52,"y":-94.28},{"time":0.8,"x":-24.29,"y":-116.41},{"time":1,"x":-41.88,"y":-93.3},{"time":1.0666,"x":-18.04,"y":-2.88}]},"rear_leg1":{"rotate":[{"time":0,"angle":-45.71,"curve":"stepped"},{"time":1.0666,"angle":-45.71}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"rear_leg_goal":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":-2.05,"y":15.12},{"time":0.2666,"x":17.49,"y":-150.43},{"time":0.4666,"x":-40.21,"y":-81.76},{"time":0.5333,"x":-31.68,"y":-82.43},{"time":0.8,"x":2.65,"y":-169.21},{"time":0.9333,"x":-16.76,"y":-98.31},{"time":1.0666,"x":-2.05,"y":15.12}]},"rear_strap_goal":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":-7.05,"y":-5.85},{"time":0.5333,"x":-7.83,"y":-10.39},{"time":1.0666,"x":-7.03,"y":-6.4}]},"tail1":{"rotate":[{"time":0,"angle":1.3},{"time":0.0666,"angle":4.13},{"time":0.3333,"angle":-5.77},{"time":0.6333,"angle":4.13},{"time":0.9,"angle":-5.77},{"time":1.0666,"angle":1.3}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.0666,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"torso1":{"rotate":[{"time":0,"angle":7.21},{"time":0.2666,"angle":4.19},{"time":0.5333,"angle":7.21},{"time":0.8,"angle":4.19},{"time":1.0666,"angle":7.21}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"front_leg2":{"rotate":[{"time":0,"angle":-347.28,"curve":"stepped"},{"time":1.0666,"angle":-347.28}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"rear_leg2":{"rotate":[{"time":0,"angle":9.92,"curve":"stepped"},{"time":1.0666,"angle":9.92}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"saddle":{"rotate":[{"time":0,"angle":-2.51},{"time":0.2666,"angle":-4.17},{"time":0.5333,"angle":-3.85},{"time":0.8,"angle":-3.09},{"time":1.0666,"angle":-2.51}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.2666,"x":0,"y":0,"curve":[0.149,0.28,0.75,1]},{"time":0.3333,"x":-0.03,"y":5.91,"curve":[0.421,0,0.85,0.78]},{"time":0.5333,"x":0,"y":0},{"time":0.6,"x":-0.2,"y":-2.35},{"time":0.8,"x":0,"y":0,"curve":[0.149,0.28,0.75,1]},{"time":0.8666,"x":-0.03,"y":5.91,"curve":[0.421,0,0.85,0.78]},{"time":1.0666,"x":0,"y":0}]},"tail2":{"rotate":[{"time":0,"angle":-6.57},{"time":0.0666,"angle":-1.96},{"time":0.3333,"angle":-18.09},{"time":0.6333,"angle":-1.96},{"time":0.9,"angle":-18.09},{"time":1.0666,"angle":-6.57}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.0666,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}],"scale":[{"time":0,"x":1.024,"y":1},{"time":0.0666,"x":1.072,"y":1},{"time":0.3333,"x":0.947,"y":1},{"time":0.6333,"x":1.072,"y":1},{"time":0.9,"x":0.903,"y":1},{"time":1.0666,"x":1.024,"y":1}]},"torso2":{"rotate":[{"time":0,"angle":4.99},{"time":0.2666,"angle":5.91,"curve":[0.25,0,0.75,1]},{"time":0.5333,"angle":4.4},{"time":0.8,"angle":1.87,"curve":[0.25,0,0.75,1]},{"time":1.0666,"angle":4.99}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"front_arm1":{"rotate":[{"time":0,"angle":0},{"time":0.5,"angle":-367.82},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":20.64,"y":-7.55},{"time":0.5,"x":-2.86,"y":3.32},{"time":0.8,"x":24.09,"y":-1.47},{"time":0.9333,"x":21.73,"y":-3.7},{"time":1.0666,"x":20.64,"y":-7.55}]},"front_leg3":{"rotate":[{"time":0,"angle":1.14,"curve":"stepped"},{"time":1.0666,"angle":1.14}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"neck":{"rotate":[{"time":0,"angle":6.5},{"time":0.2666,"angle":12.71},{"time":0.5333,"angle":6.5},{"time":0.8,"angle":13.61},{"time":1.0666,"angle":6.5}],"translate":[{"time":0,"x":21.17,"y":-41.2},{"time":0.2666,"x":10.55,"y":-103.39,"curve":[0.204,0.01,0.861,0.86]},{"time":0.5333,"x":21.17,"y":-41.2},{"time":0.8,"x":10.55,"y":-103.39,"curve":[0.204,0.01,0.861,0.86]},{"time":1.0666,"x":21.17,"y":-41.2}]},"rear_arm1":{"rotate":[{"time":0,"angle":0},{"time":0.5,"angle":13.71},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0},{"time":0.5,"x":11.12,"y":-13.38},{"time":1.0666,"x":0,"y":0}]},"rear_leg3":{"rotate":[{"time":0,"angle":-23.18,"curve":"stepped"},{"time":1.0666,"angle":-23.18}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"saddle_strap_front1":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"saddle_strap_rear1":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"tail3":{"rotate":[{"time":0,"angle":-14.83},{"time":0.0666,"angle":-24.31},{"time":0.3333,"angle":8.86},{"time":0.6333,"angle":-24.31},{"time":0.9,"angle":8.86},{"time":1.0666,"angle":-14.83}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.0666,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}],"scale":[{"time":0,"x":0.995,"y":1},{"time":0.0666,"x":1,"y":1},{"time":0.3333,"x":0.947,"y":1},{"time":1.0666,"x":0.995,"y":1}]},"front_arm2":{"rotate":[{"time":0,"angle":0},{"time":0.5,"angle":22.44},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"front_foot1":{"rotate":[{"time":0,"angle":-41.33,"curve":"stepped"},{"time":1.0666,"angle":-41.33}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"head":{"rotate":[{"time":0,"angle":-2.3},{"time":0.1333,"angle":-7.93,"curve":[0.25,0,0.75,1]},{"time":0.4,"angle":-1.06},{"time":0.5333,"angle":-2.3},{"time":0.6666,"angle":-7.93,"curve":[0.25,0,0.75,1]},{"time":0.9333,"angle":-1.06},{"time":1.0666,"angle":-2.3}],"translate":[{"time":0,"x":-3.88,"y":-32.87,"curve":"stepped"},{"time":1.0666,"x":-3.88,"y":-32.87}]},"rear_arm2":{"rotate":[{"time":0,"angle":0},{"time":0.5,"angle":-30.2},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"rear_foot1":{"rotate":[{"time":0,"angle":2.07,"curve":"stepped"},{"time":1.0666,"angle":2.07}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"saddle_strap_front2":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"saddle_strap_rear2":{"rotate":[{"time":0,"angle":-6.55},{"time":0.2666,"angle":0.54},{"time":0.4,"angle":-1.23},{"time":0.4666,"angle":-3.26},{"time":0.5333,"angle":-5.37},{"time":0.6666,"angle":-4.13},{"time":0.7333,"angle":-3.17},{"time":0.9,"angle":-2.01},{"time":1,"angle":-4.65},{"time":1.0333,"angle":15.71},{"time":1.0666,"angle":-6.55}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"stirrup":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"tail4":{"rotate":[{"time":0,"angle":16.99},{"time":0.0666,"angle":7.36},{"time":0.3333,"angle":41.06},{"time":0.6333,"angle":7.36},{"time":0.9,"angle":41.06},{"time":1.0666,"angle":16.99}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.0666,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}],"scale":[{"time":0,"x":0.995,"y":1},{"time":0.0666,"x":1,"y":1},{"time":0.3333,"x":0.947,"y":1},{"time":1.0666,"x":0.995,"y":1}]},"front_foot2":{"rotate":[{"time":0,"angle":44.18},{"time":0.0666,"angle":19.05},{"time":0.4,"angle":19.22},{"time":0.5333,"angle":15.45},{"time":0.6666,"angle":-67.33},{"time":0.7333,"angle":-65.23},{"time":1,"angle":42.33},{"time":1.0666,"angle":44.18}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"front_hand":{"rotate":[{"time":0,"angle":9.49},{"time":0.5,"angle":-48.6},{"time":1.0666,"angle":9.49}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"horn_front":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0},{"time":0.2,"x":-0.91,"y":-8.94},{"time":0.5333,"x":0,"y":0},{"time":0.7333,"x":-0.91,"y":-8.94},{"time":1.0666,"x":0,"y":0}]},"horn_rear":{"rotate":[{"time":0,"angle":0,"curve":"stepped"},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0},{"time":0.2,"x":2.05,"y":18.03},{"time":0.5333,"x":0,"y":0},{"time":0.7333,"x":2.05,"y":18.03},{"time":1.0666,"x":0,"y":0}]},"jaw":{"rotate":[{"time":0,"angle":25.56},{"time":0.2,"angle":21.27},{"time":0.3333,"angle":21.35},{"time":0.6666,"angle":15.6},{"time":0.8666,"angle":22.96},{"time":1.0666,"angle":25.56}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"rear_foot2":{"rotate":[{"time":0,"angle":0},{"time":0.1333,"angle":-82.37},{"time":0.2666,"angle":-110.3},{"time":0.4666,"angle":24.69},{"time":0.5333,"angle":2.1},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"rear_hand":{"rotate":[{"time":0,"angle":-28.89},{"time":0.5,"angle":12.19},{"time":1.0666,"angle":-28.89}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"saddle_strap_rear3":{"rotate":[{"time":0,"angle":-3.42,"curve":"stepped"},{"time":0.2666,"angle":-3.42,"curve":"stepped"},{"time":0.4666,"angle":-3.42,"curve":"stepped"},{"time":0.5333,"angle":-3.42,"curve":"stepped"},{"time":0.6666,"angle":-3.42,"curve":"stepped"},{"time":1,"angle":-3.42},{"time":1.0333,"angle":-38.58},{"time":1.0666,"angle":-3.42}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"tail5":{"rotate":[{"time":0,"angle":-15.7},{"time":0.0666,"angle":-38.39},{"time":0.3333,"angle":41.03},{"time":0.6333,"angle":-38.39},{"time":0.9,"angle":41.03},{"time":1.0666,"angle":-15.7}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":0.0666,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}],"scale":[{"time":0,"x":0.995,"y":1},{"time":0.0666,"x":1,"y":1},{"time":0.3333,"x":0.947,"y":1},{"time":1.0666,"x":0.995,"y":1}]},"tongue1":{"rotate":[{"time":0,"angle":0},{"time":0.3333,"angle":7.55},{"time":0.6666,"angle":-1.68},{"time":0.9333,"angle":8.11},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"front_foot3":{"rotate":[{"time":0,"angle":27.59},{"time":0.0666,"angle":-9.81},{"time":0.1333,"angle":-3.94},{"time":0.2666,"angle":-3.81},{"time":0.5333,"angle":-9.85},{"time":0.6,"angle":-21.2},{"time":0.6666,"angle":-73.63},{"time":0.7333,"angle":-102.81},{"time":0.8333,"angle":-41.3},{"time":1,"angle":27.59},{"time":1.0666,"angle":27.59}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"tongue2":{"rotate":[{"time":0,"angle":0},{"time":0.3333,"angle":7.55},{"time":0.6666,"angle":-1.68},{"time":0.9333,"angle":8.11},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]},"tongue3":{"rotate":[{"time":0,"angle":0},{"time":0.3333,"angle":7.55},{"time":0.6666,"angle":-1.68},{"time":0.9333,"angle":8.11},{"time":1.0666,"angle":0}],"translate":[{"time":0,"x":0,"y":0,"curve":"stepped"},{"time":1.0666,"x":0,"y":0}]}},"ffd":{"default":{"velo_body":{"velo_body":[{"time":0,"curve":"stepped"},{"time":0.0333,"curve":"stepped"},{"time":0.0666,"curve":"stepped"},{"time":0.1333,"curve":"stepped"},{"time":0.2666,"curve":"stepped"},{"time":0.5333,"curve":"stepped"},{"time":0.6,"curve":"stepped"},{"time":0.7333,"curve":"stepped"},{"time":0.8,"curve":"stepped"},{"time":1.0666}]},"velo_front_leg":{"velo_front_leg":[{"time":0,"curve":"stepped"},{"time":0.2666,"curve":"stepped"},{"time":0.5333,"curve":"stepped"},{"time":0.6,"curve":"stepped"},{"time":0.7333,"curve":"stepped"},{"time":0.8,"curve":"stepped"},{"time":0.8333,"curve":"stepped"},{"time":0.9,"curve":"stepped"},{"time":0.9666,"curve":"stepped"},{"time":1.0666}]}}}}}} \ No newline at end of file diff --git a/spine-xna/example/data/raptor.png b/spine-xna/example/data/raptor.png new file mode 100644 index 000000000..9b9f7c80d Binary files /dev/null and b/spine-xna/example/data/raptor.png differ diff --git a/spine-xna/example/spine-xna-example.csproj b/spine-xna/example/spine-xna-example.csproj index 9c95a3bd3..6edc700f4 100644 --- a/spine-xna/example/spine-xna-example.csproj +++ b/spine-xna/example/spine-xna-example.csproj @@ -117,6 +117,7 @@ + PreserveNewest @@ -163,6 +164,8 @@ + + PreserveNewest diff --git a/spine-xna/example/src/ExampleGame.cs b/spine-xna/example/src/ExampleGame.cs index 9fa8ae3dd..fdb3bbc4b 100644 --- a/spine-xna/example/src/ExampleGame.cs +++ b/spine-xna/example/src/ExampleGame.cs @@ -50,9 +50,9 @@ namespace Spine { SkeletonBounds bounds = new SkeletonBounds(); #if WINDOWS_STOREAPP - private string assetsFolder = @"Assets\"; + private string assetsFolder = @"Assets\"; #else - private string assetsFolder = "data/"; + private string assetsFolder = "data/"; #endif public Example () { @@ -75,11 +75,13 @@ namespace Spine { skeletonRenderer.PremultipliedAlpha = true; // String name = "spineboy"; - String name = "goblins-ffd"; + // String name = "goblins-ffd"; + String name = "raptor"; - Atlas atlas = new Atlas(assetsFolder + name + ".atlas", new XnaTextureLoader(GraphicsDevice)); + Atlas atlas = new Atlas(assetsFolder + name + ".atlas", new XnaTextureLoader(GraphicsDevice)); SkeletonJson json = new SkeletonJson(atlas); if (name == "spineboy") json.Scale = 0.6f; + if (name == "raptor") json.Scale = 0.5f; skeleton = new Skeleton(json.ReadSkeletonData(assetsFolder + name + ".json")); if (name == "goblins-ffd") skeleton.SetSkin("goblin"); @@ -138,13 +140,15 @@ namespace Spine { bounds.Update(skeleton, true); MouseState mouse = Mouse.GetState(); - headSlot.G = 1; - headSlot.B = 1; - if (bounds.AabbContainsPoint(mouse.X, mouse.Y)) { - BoundingBoxAttachment hit = bounds.ContainsPoint(mouse.X, mouse.Y); - if (hit != null) { - headSlot.G = 0; - headSlot.B = 0; + if (headSlot != null) { + headSlot.G = 1; + headSlot.B = 1; + if (bounds.AabbContainsPoint(mouse.X, mouse.Y)) { + BoundingBoxAttachment hit = bounds.ContainsPoint(mouse.X, mouse.Y); + if (hit != null) { + headSlot.G = 0; + headSlot.B = 0; + } } } @@ -152,25 +156,25 @@ namespace Spine { } public void Start (AnimationState state, int trackIndex) { -#if !WINDOWS_STOREAPP +#if !WINDOWS_STOREAPP Console.WriteLine(trackIndex + " " + state.GetCurrent(trackIndex) + ": start"); #endif } public void End (AnimationState state, int trackIndex) { -#if !WINDOWS_STOREAPP +#if !WINDOWS_STOREAPP Console.WriteLine(trackIndex + " " + state.GetCurrent(trackIndex) + ": end"); #endif } public void Complete (AnimationState state, int trackIndex, int loopCount) { -#if !WINDOWS_STOREAPP +#if !WINDOWS_STOREAPP Console.WriteLine(trackIndex + " " + state.GetCurrent(trackIndex) + ": complete " + loopCount); #endif } public void Event (AnimationState state, int trackIndex, Event e) { -#if !WINDOWS_STOREAPP +#if !WINDOWS_STOREAPP Console.WriteLine(trackIndex + " " + state.GetCurrent(trackIndex) + ": event " + e); #endif }