mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-06 07:14:55 +08:00
[csharp] Ported 3.6-beta changes.
This commit is contained in:
parent
7ac7afac2c
commit
3736a5c3dc
@ -126,7 +126,8 @@ namespace Spine {
|
||||
Attachment, Color, Deform, //
|
||||
Event, DrawOrder, //
|
||||
IkConstraint, TransformConstraint, //
|
||||
PathConstraintPosition, PathConstraintSpacing, PathConstraintMix
|
||||
PathConstraintPosition, PathConstraintSpacing, PathConstraintMix, //
|
||||
TwoColor
|
||||
}
|
||||
|
||||
/// <summary>Base class for frames that use an interpolation bezier curve.</summary>
|
||||
@ -546,6 +547,136 @@ namespace Spine {
|
||||
}
|
||||
}
|
||||
|
||||
public class TwoColorTimeline : CurveTimeline {
|
||||
public const int ENTRIES = 8;
|
||||
protected const int PREV_TIME = -8, PREV_R = -7, PREV_G = -6, PREV_B = -5, PREV_A = -4;
|
||||
protected const int PREV_R2 = -3, PREV_G2 = -2, PREV_B2 = -1;
|
||||
protected const int R = 1, G = 2, B = 3, A = 4, R2 = 5, G2 = 6, B2 = 7;
|
||||
|
||||
internal float[] frames; // time, r, g, b, a, r2, g2, b2, ...
|
||||
public float[] Frames { get { return frames; } }
|
||||
|
||||
internal int slotIndex;
|
||||
public int SlotIndex {
|
||||
get { return slotIndex; }
|
||||
set {
|
||||
if (value < 0) throw new ArgumentOutOfRangeException("index must be >= 0.");
|
||||
slotIndex = value;
|
||||
}
|
||||
}
|
||||
|
||||
public TwoColorTimeline (int frameCount) :
|
||||
base(frameCount) {
|
||||
frames = new float[frameCount * ENTRIES];
|
||||
}
|
||||
|
||||
override public int PropertyId {
|
||||
get { return ((int)TimelineType.TwoColor << 24) + slotIndex; }
|
||||
}
|
||||
|
||||
/// <summary>Sets the time and value of the specified keyframe.</summary>
|
||||
public void SetFrame (int frameIndex, float time, float r, float g, float b, float a, float r2, float g2, float b2) {
|
||||
frameIndex *= ENTRIES;
|
||||
frames[frameIndex] = time;
|
||||
frames[frameIndex + R] = r;
|
||||
frames[frameIndex + G] = g;
|
||||
frames[frameIndex + B] = b;
|
||||
frames[frameIndex + A] = a;
|
||||
frames[frameIndex + R2] = r2;
|
||||
frames[frameIndex + G2] = g2;
|
||||
frames[frameIndex + B2] = b2;
|
||||
}
|
||||
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, bool setupPose, bool mixingOut) {
|
||||
Slot slot = skeleton.slots.Items[slotIndex];
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) { // Time is before first frame.
|
||||
if (setupPose) {
|
||||
// slot.color.set(slot.data.color);
|
||||
// slot.darkColor.set(slot.data.darkColor);
|
||||
var slotData = slot.data;
|
||||
slot.r = slotData.r;
|
||||
slot.g = slotData.g;
|
||||
slot.b = slotData.b;
|
||||
slot.a = slotData.a;
|
||||
slot.r2 = slotData.r2;
|
||||
slot.g2 = slotData.g2;
|
||||
slot.b2 = slotData.b2;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
float r, g, b, a, r2, g2, b2;
|
||||
if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame.
|
||||
int i = frames.Length;
|
||||
r = frames[i + PREV_R];
|
||||
g = frames[i + PREV_G];
|
||||
b = frames[i + PREV_B];
|
||||
a = frames[i + PREV_A];
|
||||
r2 = frames[i + PREV_R2];
|
||||
g2 = frames[i + PREV_G2];
|
||||
b2 = frames[i + PREV_B2];
|
||||
} else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
int frame = Animation.BinarySearch(frames, time, ENTRIES);
|
||||
r = frames[frame + PREV_R];
|
||||
g = frames[frame + PREV_G];
|
||||
b = frames[frame + PREV_B];
|
||||
a = frames[frame + PREV_A];
|
||||
r2 = frames[frame + PREV_R2];
|
||||
g2 = frames[frame + PREV_G2];
|
||||
b2 = frames[frame + PREV_B2];
|
||||
float frameTime = frames[frame];
|
||||
float percent = GetCurvePercent(frame / ENTRIES - 1,
|
||||
1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
r += (frames[frame + R] - r) * percent;
|
||||
g += (frames[frame + G] - g) * percent;
|
||||
b += (frames[frame + B] - b) * percent;
|
||||
a += (frames[frame + A] - a) * percent;
|
||||
r2 += (frames[frame + R2] - r2) * percent;
|
||||
g2 += (frames[frame + G2] - g2) * percent;
|
||||
b2 += (frames[frame + B2] - b2) * percent;
|
||||
}
|
||||
if (alpha == 1) {
|
||||
slot.r = r;
|
||||
slot.g = g;
|
||||
slot.b = b;
|
||||
slot.a = a;
|
||||
slot.r2 = r2;
|
||||
slot.g2 = g2;
|
||||
slot.b2 = b2;
|
||||
} else {
|
||||
float br, bg, bb, ba, br2, bg2, bb2;
|
||||
if (setupPose) {
|
||||
br = slot.data.r;
|
||||
bg = slot.data.g;
|
||||
bb = slot.data.b;
|
||||
ba = slot.data.a;
|
||||
br2 = slot.data.r2;
|
||||
bg2 = slot.data.g2;
|
||||
bb2 = slot.data.b2;
|
||||
} else {
|
||||
br = slot.r;
|
||||
bg = slot.g;
|
||||
bb = slot.b;
|
||||
ba = slot.a;
|
||||
br2 = slot.r2;
|
||||
bg2 = slot.g2;
|
||||
bb2 = slot.b2;
|
||||
}
|
||||
slot.r = br + ((r - br) * alpha);
|
||||
slot.g = bg + ((g - bg) * alpha);
|
||||
slot.b = bb + ((b - bb) * alpha);
|
||||
slot.a = ba + ((a - ba) * alpha);
|
||||
slot.r2 = br2 + ((r2 - br2) * alpha);
|
||||
slot.g2 = bg2 + ((g2 - bg2) * alpha);
|
||||
slot.b2 = bb2 + ((b2 - bb2) * alpha);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public class AttachmentTimeline : Timeline {
|
||||
internal int slotIndex;
|
||||
internal float[] frames;
|
||||
|
||||
@ -805,6 +805,11 @@ namespace Spine {
|
||||
/// <see cref="AnimationStateData"/> based on the animation before this animation (if any).
|
||||
///
|
||||
/// The mix duration must be set before <see cref="AnimationState.Update(float)"/> is next called.
|
||||
/// <para>
|
||||
/// When using <seealso cref="AnimationState.AddAnimation(int, Animation, bool, float)"/> with a
|
||||
/// <code>delay</code> <seealso cref="Delay"/> is set using the mix duration from the <see cref=" AnimationStateData"/>
|
||||
/// </para>
|
||||
///
|
||||
/// </summary>
|
||||
public float MixDuration { get { return mixDuration; } set { mixDuration = value; } }
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ namespace Spine {
|
||||
this.atlasArray = atlasArray;
|
||||
}
|
||||
|
||||
public RegionAttachment NewRegionAttachment (Skin skin, String name, String path) {
|
||||
public RegionAttachment NewRegionAttachment (Skin skin, string name, string path) {
|
||||
AtlasRegion region = FindRegion(path);
|
||||
if (region == null) throw new Exception("Region not found in atlas: " + path + " (region attachment: " + name + ")");
|
||||
RegionAttachment attachment = new RegionAttachment(name);
|
||||
@ -54,7 +54,7 @@ namespace Spine {
|
||||
return attachment;
|
||||
}
|
||||
|
||||
public MeshAttachment NewMeshAttachment (Skin skin, String name, String path) {
|
||||
public MeshAttachment NewMeshAttachment (Skin skin, string name, string path) {
|
||||
AtlasRegion region = FindRegion(path);
|
||||
if (region == null) throw new Exception("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
|
||||
MeshAttachment attachment = new MeshAttachment(name);
|
||||
@ -73,12 +73,16 @@ namespace Spine {
|
||||
return attachment;
|
||||
}
|
||||
|
||||
public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name) {
|
||||
public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, string name) {
|
||||
return new BoundingBoxAttachment(name);
|
||||
}
|
||||
|
||||
public PathAttachment NewPathAttachment (Skin skin, String name) {
|
||||
return new PathAttachment (name);
|
||||
public PathAttachment NewPathAttachment (Skin skin, string name) {
|
||||
return new PathAttachment(name);
|
||||
}
|
||||
|
||||
public PointAttachment NewPointAttachment (Skin skin, string name) {
|
||||
return new PointAttachment(name);
|
||||
}
|
||||
|
||||
public AtlasRegion FindRegion (string name) {
|
||||
|
||||
@ -33,15 +33,17 @@ using System;
|
||||
namespace Spine {
|
||||
public interface AttachmentLoader {
|
||||
/// <return>May be null to not load any attachment.</return>
|
||||
RegionAttachment NewRegionAttachment (Skin skin, String name, String path);
|
||||
RegionAttachment NewRegionAttachment (Skin skin, String name, string path);
|
||||
|
||||
/// <return>May be null to not load any attachment.</return>
|
||||
MeshAttachment NewMeshAttachment (Skin skin, String name, String path);
|
||||
MeshAttachment NewMeshAttachment (Skin skin, String name, string path);
|
||||
|
||||
/// <return>May be null to not load any attachment.</return>
|
||||
BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name);
|
||||
BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, string name);
|
||||
|
||||
/// <returns>May be null to not load any attachment</returns>
|
||||
PathAttachment NewPathAttachment (Skin skin, String name);
|
||||
PathAttachment NewPathAttachment (Skin skin, string name);
|
||||
|
||||
PointAttachment NewPointAttachment (Skin skin, string name);
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,6 +30,6 @@
|
||||
|
||||
namespace Spine {
|
||||
public enum AttachmentType {
|
||||
Region, Boundingbox, Mesh, Linkedmesh, Path
|
||||
Region, Boundingbox, Mesh, Linkedmesh, Path, Point
|
||||
}
|
||||
}
|
||||
|
||||
@ -43,6 +43,7 @@ namespace Spine {
|
||||
|
||||
public int HullLength { get { return hulllength; } set { hulllength = value; } }
|
||||
public float[] RegionUVs { get { return regionUVs; } set { regionUVs = value; } }
|
||||
/// <summary>The UV pair for each vertex, normalized within the entire texture. <seealso cref="MeshAttachment.UpdateUVs"/></summary>
|
||||
public float[] UVs { get { return uvs; } set { uvs = value; } }
|
||||
public int[] Triangles { get { return triangles; } set { triangles = value; } }
|
||||
|
||||
|
||||
61
spine-csharp/src/Attachments/PointAttachment.cs
Normal file
61
spine-csharp/src/Attachments/PointAttachment.cs
Normal file
@ -0,0 +1,61 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes Software License v2.5
|
||||
*
|
||||
* Copyright (c) 2013-2016, Esoteric Software
|
||||
* All rights reserved.
|
||||
*
|
||||
* You are granted a perpetual, non-exclusive, non-sublicensable, and
|
||||
* non-transferable license to use, install, execute, and perform the Spine
|
||||
* Runtimes software and derivative works solely for personal or internal
|
||||
* use. Without the written permission of Esoteric Software (see Section 2 of
|
||||
* the Spine Software License Agreement), you may not (a) modify, translate,
|
||||
* adapt, or develop new applications using the Spine Runtimes or otherwise
|
||||
* create derivative works or improvements of the Spine Runtimes 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 SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
|
||||
* USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
namespace Spine {
|
||||
/// <summary>
|
||||
/// An attachment which is a single point and a rotation. This can be used to spawn projectiles, particles, etc. A bone can be
|
||||
/// used in similar ways, but a PointAttachment is slightly less expensive to compute and can be hidden, shown, and placed in a
|
||||
/// skin.
|
||||
/// <p>
|
||||
/// See <a href="http://esotericsoftware.com/spine-point-attachments">Point Attachments</a> in the Spine User Guide.
|
||||
/// </summary>
|
||||
public class PointAttachment : Attachment {
|
||||
internal float x, y, rotation;
|
||||
public float X { get { return x; } set { x = value; } }
|
||||
public float Y { get { return y; } set { y = value; } }
|
||||
public float Rotation { get { return rotation; } set { rotation = value; } }
|
||||
|
||||
public PointAttachment (string name)
|
||||
: base(name) {
|
||||
}
|
||||
|
||||
public void ComputeWorldPosition (Bone bone, float x, float y, out float ox, out float oy) {
|
||||
bone.LocalToWorld(x, y, out ox, out oy);
|
||||
}
|
||||
|
||||
public float ComputeWorldRotation (Bone bone) {
|
||||
float cos = MathUtils.CosDeg(rotation), sin = MathUtils.SinDeg(rotation);
|
||||
float ix = cos * bone.a + sin * bone.b;
|
||||
float iy = cos * bone.c + sin * bone.d;
|
||||
return MathUtils.Atan2(iy, ix) * MathUtils.RadDeg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,7 +55,8 @@ namespace Spine {
|
||||
/// <param name="count">The number of world vertex values to output. Must be less than or equal to <see cref="WorldVerticesLength"/> - start.</param>
|
||||
/// <param name="worldVertices">The output world vertices. Must have a length greater than or equal to <paramref name="offset"/> + <paramref name="count"/>.</param>
|
||||
/// <param name="offset">The <paramref name="worldVertices"/> index to begin writing values.</param>
|
||||
public void ComputeWorldVertices (Slot slot, int start, int count, float[] worldVertices, int offset) {
|
||||
/// <param name="stride">The number of <paramref name="worldVertices"/> entries between the value pairs written.</param>
|
||||
public void ComputeWorldVertices (Slot slot, int start, int count, float[] worldVertices, int offset, int stride = 2) {
|
||||
count += offset;
|
||||
Skeleton skeleton = slot.Skeleton;
|
||||
var deformArray = slot.attachmentVertices;
|
||||
@ -66,7 +67,7 @@ namespace Spine {
|
||||
Bone bone = slot.bone;
|
||||
float x = bone.worldX, y = bone.worldY;
|
||||
float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
|
||||
for (int vv = start, w = offset; w < count; vv += 2, w += 2) {
|
||||
for (int vv = start, w = offset; w < count; vv += 2, w += stride) {
|
||||
float vx = vertices[vv], vy = vertices[vv + 1];
|
||||
worldVertices[w] = vx * a + vy * b + x;
|
||||
worldVertices[w + 1] = vx * c + vy * d + y;
|
||||
@ -81,7 +82,7 @@ namespace Spine {
|
||||
}
|
||||
Bone[] skeletonBones = skeleton.Bones.Items;
|
||||
if (deformArray.Count == 0) {
|
||||
for (int w = offset, b = skip * 3; w < count; w += 2) {
|
||||
for (int w = offset, b = skip * 3; w < count; w += stride) {
|
||||
float wx = 0, wy = 0;
|
||||
int n = bones[v++];
|
||||
n += v;
|
||||
@ -96,7 +97,7 @@ namespace Spine {
|
||||
}
|
||||
} else {
|
||||
float[] deform = deformArray.Items;
|
||||
for (int w = offset, b = skip * 3, f = skip << 1; w < count; w += 2) {
|
||||
for (int w = offset, b = skip * 3, f = skip << 1; w < count; w += stride) {
|
||||
float wx = 0, wy = 0;
|
||||
int n = bones[v++];
|
||||
n += v;
|
||||
|
||||
@ -31,6 +31,14 @@
|
||||
using System;
|
||||
|
||||
namespace Spine {
|
||||
/// <summary>
|
||||
/// Stores a bone's current pose.
|
||||
/// <para>
|
||||
/// A bone has a local transform which is used to compute its world transform. A bone also has an applied transform, which is a
|
||||
/// local transform that can be applied to compute the world transform. The local transform and applied transform may differ if a
|
||||
/// constraint or application code modifies the world transform after it was computed from the local transform.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public class Bone : IUpdatable {
|
||||
static public bool yDown;
|
||||
|
||||
@ -55,6 +63,7 @@ namespace Spine {
|
||||
public Skeleton Skeleton { get { return skeleton; } }
|
||||
public Bone Parent { get { return parent; } }
|
||||
public ExposedList<Bone> Children { get { return children; } }
|
||||
/// <summary>The local X translation.</summary>
|
||||
public float X { get { return x; } set { x = value; } }
|
||||
public float Y { get { return y; } set { y = value; } }
|
||||
public float Rotation { get { return rotation; } set { rotation = value; } }
|
||||
@ -240,34 +249,6 @@ namespace Spine {
|
||||
shearY = data.shearY;
|
||||
}
|
||||
|
||||
public float WorldToLocalRotationX {
|
||||
get {
|
||||
Bone parent = this.parent;
|
||||
if (parent == null) return arotation;
|
||||
float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, a = this.a, c = this.c;
|
||||
return MathUtils.Atan2(pa * c - pc * a, pd * a - pb * c) * MathUtils.RadDeg;
|
||||
}
|
||||
}
|
||||
|
||||
public float WorldToLocalRotationY {
|
||||
get {
|
||||
Bone parent = this.parent;
|
||||
if (parent == null) return arotation;
|
||||
float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, b = this.b, d = this.d;
|
||||
return MathUtils.Atan2(pa * d - pc * b, pd * b - pb * d) * MathUtils.RadDeg;
|
||||
}
|
||||
}
|
||||
|
||||
public void RotateWorld (float degrees) {
|
||||
float a = this.a, b = this.b, c = this.c, d = this.d;
|
||||
float cos = MathUtils.CosDeg(degrees), sin = MathUtils.SinDeg(degrees);
|
||||
this.a = cos * a - sin * c;
|
||||
this.b = cos * b - sin * d;
|
||||
this.c = sin * a + cos * c;
|
||||
this.d = sin * b + cos * d;
|
||||
appliedValid = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Computes the individual applied transform values from the world transform. This can be useful to perform processing using
|
||||
/// the applied transform after the world transform has been modified directly (eg, by a constraint)..
|
||||
@ -328,6 +309,44 @@ namespace Spine {
|
||||
worldY = localX * c + localY * d + this.worldY;
|
||||
}
|
||||
|
||||
public float WorldToLocalRotationX {
|
||||
get {
|
||||
Bone parent = this.parent;
|
||||
if (parent == null) return arotation;
|
||||
float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, a = this.a, c = this.c;
|
||||
return MathUtils.Atan2(pa * c - pc * a, pd * a - pb * c) * MathUtils.RadDeg;
|
||||
}
|
||||
}
|
||||
|
||||
public float WorldToLocalRotationY {
|
||||
get {
|
||||
Bone parent = this.parent;
|
||||
if (parent == null) return arotation;
|
||||
float pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d, b = this.b, d = this.d;
|
||||
return MathUtils.Atan2(pa * d - pc * b, pd * b - pb * d) * MathUtils.RadDeg;
|
||||
}
|
||||
}
|
||||
|
||||
public float WorldToLocalRotation (float worldRotation) {
|
||||
float sin = MathUtils.SinDeg(worldRotation), cos = MathUtils.CosDeg(worldRotation);
|
||||
return MathUtils.Atan2(a * sin - c * cos, d * cos - b * sin) * MathUtils.RadDeg;
|
||||
}
|
||||
|
||||
public float LocalToWorldRotation (float localRotation) {
|
||||
float sin = MathUtils.SinDeg(localRotation), cos = MathUtils.CosDeg(localRotation);
|
||||
return MathUtils.Atan2(cos * c + sin * d, cos * a + sin * b) * MathUtils.RadDeg;
|
||||
}
|
||||
|
||||
public void RotateWorld (float degrees) {
|
||||
float a = this.a, b = this.b, c = this.c, d = this.d;
|
||||
float cos = MathUtils.CosDeg(degrees), sin = MathUtils.SinDeg(degrees);
|
||||
this.a = cos * a - sin * c;
|
||||
this.b = cos * b - sin * d;
|
||||
this.c = sin * a + cos * c;
|
||||
this.d = sin * b + cos * d;
|
||||
appliedValid = false;
|
||||
}
|
||||
|
||||
override public String ToString () {
|
||||
return data.name;
|
||||
}
|
||||
|
||||
@ -91,10 +91,10 @@ namespace Spine {
|
||||
if (scale) lengths = this.lengths.Resize(boneCount);
|
||||
for (int i = 0, n = spacesCount - 1; i < n;) {
|
||||
Bone bone = bones[i];
|
||||
float length = bone.data.length, x = length * bone.a, y = length * bone.c;
|
||||
length = (float)Math.Sqrt(x * x + y * y);
|
||||
if (scale) lengths.Items[i] = length;
|
||||
spaces.Items[++i] = lengthSpacing ? Math.Max(0, length + spacing) : spacing;
|
||||
float setupLength = bone.data.length, x = setupLength * bone.a, y = setupLength * bone.c;
|
||||
float length = (float)Math.Sqrt(x * x + y * y);
|
||||
if (scale) lengths.Items[i] = setupLength;
|
||||
spaces.Items[++i] = (lengthSpacing ? Math.Max(0, setupLength + spacing) : spacing) * length / setupLength;
|
||||
}
|
||||
} else {
|
||||
for (int i = 1; i < spacesCount; i++)
|
||||
|
||||
@ -194,15 +194,15 @@ namespace Spine {
|
||||
|
||||
var constrained = constraint.bones;
|
||||
int boneCount = constrained.Count;
|
||||
for (int ii = 0; ii < boneCount; ii++)
|
||||
SortBone(constrained.Items[ii]);
|
||||
for (int i = 0; i < boneCount; i++)
|
||||
SortBone(constrained.Items[i]);
|
||||
|
||||
updateCache.Add(constraint);
|
||||
|
||||
for (int ii = 0; ii < boneCount; ii++)
|
||||
SortReset(constrained.Items[ii].children);
|
||||
for (int ii = 0; ii < boneCount; ii++)
|
||||
constrained.Items[ii].sorted = true;
|
||||
for (int i = 0; i < boneCount; i++)
|
||||
SortReset(constrained.Items[i].children);
|
||||
for (int i = 0; i < boneCount; i++)
|
||||
constrained.Items[i].sorted = true;
|
||||
}
|
||||
|
||||
private void SortTransformConstraint (TransformConstraint constraint) {
|
||||
@ -210,15 +210,25 @@ namespace Spine {
|
||||
|
||||
var constrained = constraint.bones;
|
||||
int boneCount = constrained.Count;
|
||||
for (int ii = 0; ii < boneCount; ii++)
|
||||
SortBone(constrained.Items[ii]);
|
||||
// for (int ii = 0; ii < boneCount; ii++)
|
||||
// SortBone(constrained.Items[ii]);
|
||||
if (constraint.data.local) {
|
||||
for (int i = 0; i < boneCount; i++) {
|
||||
Bone child = constrained.Items[constrained.Count - 1];
|
||||
SortBone(child.parent);
|
||||
if (!updateCache.Contains(child)) updateCacheReset.Add(child);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < boneCount; i++)
|
||||
SortBone(constrained.Items[i]);
|
||||
}
|
||||
|
||||
updateCache.Add(constraint);
|
||||
|
||||
for (int ii = 0; ii < boneCount; ii++)
|
||||
SortReset(constrained.Items[ii].children);
|
||||
for (int ii = 0; ii < boneCount; ii++)
|
||||
constrained.Items[ii].sorted = true;
|
||||
for (int i = 0; i < boneCount; i++)
|
||||
SortReset(constrained.Items[i].children);
|
||||
for (int i = 0; i < boneCount; i++)
|
||||
constrained.Items[i].sorted = true;
|
||||
}
|
||||
|
||||
private void SortPathConstraintAttachment (Skin skin, int slotIndex, Bone slotBone) {
|
||||
@ -475,5 +485,53 @@ namespace Spine {
|
||||
public void Update (float delta) {
|
||||
time += delta;
|
||||
}
|
||||
|
||||
/// <summary>Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose.</summary>
|
||||
/// <param name="x">The horizontal distance between the skeleton origin and the left side of the AABB.</param>
|
||||
/// <param name="y">The vertical distance between the skeleton origin and the bottom side of the AABB.</param>
|
||||
/// <param name="width">The width of the AABB</param>
|
||||
/// <param name="height">The height of the AABB.</param>
|
||||
/// <param name="vertexBuffer">Reference to hold a float[]. May be a null reference. This method will assign it a new float[] with the appropriate size as needed.</param>
|
||||
public void GetBounds (out float x, out float y, out float width, out float height, ref float[] vertexBuffer) {
|
||||
float[] temp = vertexBuffer;
|
||||
temp = temp ?? new float[8];
|
||||
var drawOrder = this.drawOrder;
|
||||
float minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue;
|
||||
for (int i = 0, n = drawOrder.Count; i < n; i++) {
|
||||
Slot slot = drawOrder.Items[i];
|
||||
int verticesLength = 0;
|
||||
float[] vertices = null;
|
||||
Attachment attachment = slot.attachment;
|
||||
var regionAttachment = attachment as RegionAttachment;
|
||||
if (regionAttachment != null) {
|
||||
verticesLength = 8;
|
||||
if (temp.Length < 8) temp = new float[8];
|
||||
regionAttachment.ComputeWorldVertices(slot.bone, temp);
|
||||
} else {
|
||||
var meshAttachment = attachment as MeshAttachment;
|
||||
if (meshAttachment != null) {
|
||||
MeshAttachment mesh = meshAttachment;
|
||||
verticesLength = mesh.WorldVerticesLength;
|
||||
if (temp.Length < verticesLength) temp = new float[verticesLength];
|
||||
mesh.ComputeWorldVertices(slot, 0, verticesLength, temp, 0);
|
||||
}
|
||||
}
|
||||
|
||||
if (vertices != null) {
|
||||
for (int ii = 0; ii < verticesLength; ii += 2) {
|
||||
float vx = vertices[ii], vy = vertices[ii + 1];
|
||||
minX = Math.Min(minX, vx);
|
||||
minY = Math.Min(minY, vy);
|
||||
maxX = Math.Max(maxX, vx);
|
||||
maxY = Math.Max(maxY, vy);
|
||||
}
|
||||
}
|
||||
}
|
||||
x = minX;
|
||||
y = minY;
|
||||
width = maxX - minX;
|
||||
height = maxY - minY;
|
||||
vertexBuffer = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -50,6 +50,7 @@ namespace Spine {
|
||||
|
||||
public const int SLOT_ATTACHMENT = 0;
|
||||
public const int SLOT_COLOR = 1;
|
||||
public const int SLOT_TWO_COLOR = 2;
|
||||
|
||||
public const int PATH_POSITION = 0;
|
||||
public const int PATH_SPACING = 1;
|
||||
@ -182,6 +183,15 @@ namespace Spine {
|
||||
slotData.g = ((color & 0x00ff0000) >> 16) / 255f;
|
||||
slotData.b = ((color & 0x0000ff00) >> 8) / 255f;
|
||||
slotData.a = ((color & 0x000000ff)) / 255f;
|
||||
|
||||
int darkColor = ReadInt(input);
|
||||
if (darkColor != -1) {
|
||||
slotData.hasSecondColor = true;
|
||||
slotData.r2 = ((darkColor & 0xff000000) >> 24) / 255f;
|
||||
slotData.g2 = ((darkColor & 0x00ff0000) >> 16) / 255f;
|
||||
slotData.b2 = ((darkColor & 0x0000ff00) >> 8) / 255f;
|
||||
}
|
||||
|
||||
slotData.attachmentName = ReadString(input);
|
||||
slotData.blendMode = (BlendMode)ReadVarint(input, true);
|
||||
skeletonData.slots.Add(slotData);
|
||||
@ -425,7 +435,7 @@ namespace Spine {
|
||||
float[] lengths = new float[vertexCount / 3];
|
||||
for (int i = 0, n = lengths.Length; i < n; i++)
|
||||
lengths[i] = ReadFloat(input) * scale;
|
||||
if (nonessential) ReadInt(input); //int color = nonessential ? ReadInt(input) : 0; // Avoid unused local warning.
|
||||
if (nonessential) ReadInt(input); //int color = nonessential ? ReadInt(input) : 0;
|
||||
|
||||
PathAttachment path = attachmentLoader.NewPathAttachment(skin, name);
|
||||
if (path == null) return null;
|
||||
@ -436,7 +446,21 @@ namespace Spine {
|
||||
path.bones = vertices.bones;
|
||||
path.lengths = lengths;
|
||||
return path;
|
||||
}
|
||||
}
|
||||
case AttachmentType.Point: {
|
||||
float rotation = ReadFloat(input);
|
||||
float x = ReadFloat(input);
|
||||
float y = ReadFloat(input);
|
||||
if (nonessential) ReadInt(input); //int color = nonessential ? ReadInt(input) : 0;
|
||||
|
||||
PointAttachment point = attachmentLoader.NewPointAttachment(skin, name);
|
||||
if (point == null) return null;
|
||||
point.x = x * scale;
|
||||
point.y = y * scale;
|
||||
point.rotation = rotation;
|
||||
//if (nonessential) point.color = color;
|
||||
return point;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -499,6 +523,15 @@ namespace Spine {
|
||||
int timelineType = input.ReadByte();
|
||||
int frameCount = ReadVarint(input, true);
|
||||
switch (timelineType) {
|
||||
case SLOT_ATTACHMENT: {
|
||||
AttachmentTimeline timeline = new AttachmentTimeline(frameCount);
|
||||
timeline.slotIndex = slotIndex;
|
||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
|
||||
timeline.SetFrame(frameIndex, ReadFloat(input), ReadString(input));
|
||||
timelines.Add(timeline);
|
||||
duration = Math.Max(duration, timeline.frames[frameCount - 1]);
|
||||
break;
|
||||
}
|
||||
case SLOT_COLOR: {
|
||||
ColorTimeline timeline = new ColorTimeline(frameCount);
|
||||
timeline.slotIndex = slotIndex;
|
||||
@ -516,13 +549,26 @@ namespace Spine {
|
||||
duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * ColorTimeline.ENTRIES]);
|
||||
break;
|
||||
}
|
||||
case SLOT_ATTACHMENT: {
|
||||
AttachmentTimeline timeline = new AttachmentTimeline(frameCount);
|
||||
case SLOT_TWO_COLOR: {
|
||||
TwoColorTimeline timeline = new TwoColorTimeline(frameCount);
|
||||
timeline.slotIndex = slotIndex;
|
||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
|
||||
timeline.SetFrame(frameIndex, ReadFloat(input), ReadString(input));
|
||||
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) {
|
||||
float time = ReadFloat(input);
|
||||
int color = ReadInt(input);
|
||||
float r = ((color & 0xff000000) >> 24) / 255f;
|
||||
float g = ((color & 0x00ff0000) >> 16) / 255f;
|
||||
float b = ((color & 0x0000ff00) >> 8) / 255f;
|
||||
float a = ((color & 0x000000ff)) / 255f;
|
||||
int color2 = ReadInt(input);
|
||||
float r2 = ((color2 & 0xff000000) >> 24) / 255f;
|
||||
float g2 = ((color2 & 0x00ff0000) >> 16) / 255f;
|
||||
float b2 = ((color2 & 0x0000ff00) >> 8) / 255f;
|
||||
|
||||
timeline.SetFrame(frameIndex, time, r, g, b, a, r2, g2, b2);
|
||||
if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline);
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
duration = Math.Max(duration, timeline.frames[frameCount - 1]);
|
||||
duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * TwoColorTimeline.ENTRIES]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -146,6 +146,14 @@ namespace Spine {
|
||||
data.b = ToColor(color, 2);
|
||||
data.a = ToColor(color, 3);
|
||||
}
|
||||
|
||||
if (slotMap.ContainsKey("dark")) {
|
||||
var color2 = (String)slotMap["dark"];
|
||||
data.r2 = ToColor(color2, 0);
|
||||
data.g2 = ToColor(color2, 1);
|
||||
data.b2 = ToColor(color2, 2);
|
||||
data.hasSecondColor = true;
|
||||
}
|
||||
|
||||
data.attachmentName = GetString(slotMap, "attachment", null);
|
||||
if (slotMap.ContainsKey("blend"))
|
||||
@ -394,6 +402,17 @@ namespace Spine {
|
||||
pathAttachment.lengths = GetFloatArray(map, "lengths", scale);
|
||||
return pathAttachment;
|
||||
}
|
||||
case AttachmentType.Point: {
|
||||
PointAttachment point = attachmentLoader.NewPointAttachment(skin, name);
|
||||
if (point == null) return null;
|
||||
point.x = GetFloat(map, "x", 0) * scale;
|
||||
point.y = GetFloat(map, "y", 0) * scale;
|
||||
point.rotation = GetFloat(map, "rotation", 0);
|
||||
|
||||
//string color = GetString(map, "color", null);
|
||||
//if (color != null) point.color = color;
|
||||
return point;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@ -441,7 +460,19 @@ namespace Spine {
|
||||
foreach (KeyValuePair<String, Object> timelineEntry in timelineMap) {
|
||||
var values = (List<Object>)timelineEntry.Value;
|
||||
var timelineName = (String)timelineEntry.Key;
|
||||
if (timelineName == "color") {
|
||||
if (timelineName == "attachment") {
|
||||
var timeline = new AttachmentTimeline(values.Count);
|
||||
timeline.slotIndex = slotIndex;
|
||||
|
||||
int frameIndex = 0;
|
||||
foreach (Dictionary<String, Object> valueMap in values) {
|
||||
float time = (float)valueMap["time"];
|
||||
timeline.SetFrame(frameIndex++, time, (String)valueMap["name"]);
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]);
|
||||
|
||||
} else if (timelineName == "color") {
|
||||
var timeline = new ColorTimeline(values.Count);
|
||||
timeline.slotIndex = slotIndex;
|
||||
|
||||
@ -456,17 +487,22 @@ namespace Spine {
|
||||
timelines.Add(timeline);
|
||||
duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * ColorTimeline.ENTRIES]);
|
||||
|
||||
} else if (timelineName == "attachment") {
|
||||
var timeline = new AttachmentTimeline(values.Count);
|
||||
} else if (timelineName == "twoColor") {
|
||||
var timeline = new TwoColorTimeline(values.Count);
|
||||
timeline.slotIndex = slotIndex;
|
||||
|
||||
int frameIndex = 0;
|
||||
foreach (Dictionary<String, Object> valueMap in values) {
|
||||
float time = (float)valueMap["time"];
|
||||
timeline.SetFrame(frameIndex++, time, (String)valueMap["name"]);
|
||||
String c = (String)valueMap["light"];
|
||||
String c2 = (String)valueMap["dark"];
|
||||
timeline.SetFrame(frameIndex, time, ToColor(c, 0), ToColor(c, 1), ToColor(c, 2), ToColor(c, 3),
|
||||
ToColor(c2, 0), ToColor(c2, 1), ToColor(c2, 2));
|
||||
ReadCurve(valueMap, timeline, frameIndex);
|
||||
frameIndex++;
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
duration = Math.Max(duration, timeline.frames[timeline.FrameCount - 1]);
|
||||
duration = Math.Max(duration, timeline.frames[(timeline.FrameCount - 1) * ColorTimeline.ENTRIES]);
|
||||
|
||||
} else
|
||||
throw new Exception("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")");
|
||||
|
||||
@ -35,6 +35,8 @@ namespace Spine {
|
||||
internal SlotData data;
|
||||
internal Bone bone;
|
||||
internal float r, g, b, a;
|
||||
internal float r2, g2, b2;
|
||||
internal bool hasSecondColor;
|
||||
internal Attachment attachment;
|
||||
internal float attachmentTime;
|
||||
internal ExposedList<float> attachmentVertices = new ExposedList<float>();
|
||||
@ -47,6 +49,11 @@ namespace Spine {
|
||||
public float B { get { return b; } set { b = value; } }
|
||||
public float A { get { return a; } set { a = value; } }
|
||||
|
||||
public float R2 { get { return r2; } set { r2 = value; } }
|
||||
public float G2 { get { return g2; } set { g2 = value; } }
|
||||
public float B2 { get { return b2; } set { b2 = value; } }
|
||||
public bool HasSecondColor { get { return hasSecondColor; } set { hasSecondColor = value; } }
|
||||
|
||||
/// <summary>May be null.</summary>
|
||||
public Attachment Attachment {
|
||||
get { return attachment; }
|
||||
|
||||
@ -33,19 +33,27 @@ using System;
|
||||
namespace Spine {
|
||||
public class SlotData {
|
||||
internal int index;
|
||||
internal String name;
|
||||
internal string name;
|
||||
internal BoneData boneData;
|
||||
internal float r = 1, g = 1, b = 1, a = 1;
|
||||
internal String attachmentName;
|
||||
internal float r2 = 0, g2 = 0, b2 = 0;
|
||||
internal bool hasSecondColor = false;
|
||||
internal string attachmentName;
|
||||
internal BlendMode blendMode;
|
||||
|
||||
public int Index { get { return index; } }
|
||||
public String Name { get { return name; } }
|
||||
public string Name { get { return name; } }
|
||||
public BoneData BoneData { get { return boneData; } }
|
||||
public float R { get { return r; } set { r = value; } }
|
||||
public float G { get { return g; } set { g = value; } }
|
||||
public float B { get { return b; } set { b = value; } }
|
||||
public float A { get { return a; } set { a = value; } }
|
||||
|
||||
public float R2 { get { return r2; } set { r2 = value; } }
|
||||
public float G2 { get { return g2; } set { g2 = value; } }
|
||||
public float B2 { get { return b2; } set { b2 = value; } }
|
||||
public bool HasSecondColor { get { return hasSecondColor; } set { hasSecondColor = value; } }
|
||||
|
||||
/// <summary>May be null.</summary>
|
||||
public String AttachmentName { get { return attachmentName; } set { attachmentName = value; } }
|
||||
public BlendMode BlendMode { get { return blendMode; } set { blendMode = value; } }
|
||||
|
||||
@ -67,15 +67,28 @@ namespace Spine {
|
||||
}
|
||||
|
||||
public void Update () {
|
||||
if (data.local) {
|
||||
if (data.relative)
|
||||
ApplyRelativeLocal();
|
||||
else
|
||||
ApplyAbsoluteLocal();
|
||||
} else {
|
||||
if (data.relative)
|
||||
ApplyRelativeWorld();
|
||||
else
|
||||
ApplyAbsoluteWorld();
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyAbsoluteWorld () {
|
||||
float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix;
|
||||
Bone target = this.target;
|
||||
float ta = target.a, tb = target.b, tc = target.c, td = target.d;
|
||||
float degRadReflect = (ta * td - tb * tc > 0) ? MathUtils.DegRad : -MathUtils.DegRad;
|
||||
float degRadReflect = ta * td - tb * tc > 0 ? MathUtils.DegRad : -MathUtils.DegRad;
|
||||
float offsetRotation = data.offsetRotation * degRadReflect, offsetShearY = data.offsetShearY * degRadReflect;
|
||||
var bones = this.bones;
|
||||
var bonesItems = bones.Items;
|
||||
for (int i = 0, n = bones.Count; i < n; i++) {
|
||||
Bone bone = bonesItems[i];
|
||||
Bone bone = bones.Items[i];
|
||||
bool modified = false;
|
||||
|
||||
if (rotateMix != 0) {
|
||||
@ -94,22 +107,20 @@ namespace Spine {
|
||||
}
|
||||
|
||||
if (translateMix != 0) {
|
||||
float tempx, tempy;
|
||||
target.LocalToWorld(data.offsetX, data.offsetY, out tempx, out tempy);
|
||||
bone.worldX += (tempx - bone.worldX) * translateMix;
|
||||
bone.worldY += (tempy - bone.worldY) * translateMix;
|
||||
float tx, ty; //Vector2 temp = this.temp;
|
||||
target.LocalToWorld(data.offsetX, data.offsetY, out tx, out ty); //target.localToWorld(temp.set(data.offsetX, data.offsetY));
|
||||
bone.worldX += (tx - bone.worldX) * translateMix;
|
||||
bone.worldY += (ty - bone.worldY) * translateMix;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (scaleMix > 0) {
|
||||
float s = (float)Math.Sqrt(bone.a * bone.a + bone.c * bone.c);
|
||||
float ts = (float)Math.Sqrt(ta * ta + tc * tc);
|
||||
if (s > 0.00001f) s = (s + (ts - s + data.offsetScaleX) * scaleMix) / s;
|
||||
if (s > 0.00001f) s = (s + ((float)Math.Sqrt(ta * ta + tc * tc) - s + data.offsetScaleX) * scaleMix) / s;
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
s = (float)Math.Sqrt(bone.b * bone.b + bone.d * bone.d);
|
||||
ts = (float)Math.Sqrt(tb * tb + td * td);
|
||||
if (s > 0.00001f) s = (s + (ts - s + data.offsetScaleY) * scaleMix) / s;
|
||||
if (s > 0.00001f) s = (s + ((float)Math.Sqrt(tb * tb + td * td) - s + data.offsetScaleY) * scaleMix) / s;
|
||||
bone.b *= s;
|
||||
bone.d *= s;
|
||||
modified = true;
|
||||
@ -133,6 +144,137 @@ namespace Spine {
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyRelativeWorld () {
|
||||
float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix;
|
||||
Bone target = this.target;
|
||||
float ta = target.a, tb = target.b, tc = target.c, td = target.d;
|
||||
float degRadReflect = ta * td - tb * tc > 0 ? MathUtils.DegRad : -MathUtils.DegRad;
|
||||
float offsetRotation = data.offsetRotation * degRadReflect, offsetShearY = data.offsetShearY * degRadReflect;
|
||||
var bones = this.bones;
|
||||
for (int i = 0, n = bones.Count; i < n; i++) {
|
||||
Bone bone = bones.Items[i];
|
||||
bool modified = false;
|
||||
|
||||
if (rotateMix != 0) {
|
||||
float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
|
||||
float r = MathUtils.Atan2(tc, ta) + offsetRotation;
|
||||
if (r > MathUtils.PI)
|
||||
r -= MathUtils.PI2;
|
||||
else if (r < -MathUtils.PI) r += MathUtils.PI2;
|
||||
r *= rotateMix;
|
||||
float cos = MathUtils.Cos(r), sin = MathUtils.Sin(r);
|
||||
bone.a = cos * a - sin * c;
|
||||
bone.b = cos * b - sin * d;
|
||||
bone.c = sin * a + cos * c;
|
||||
bone.d = sin * b + cos * d;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (translateMix != 0) {
|
||||
float tx, ty; //Vector2 temp = this.temp;
|
||||
target.LocalToWorld(data.offsetX, data.offsetY, out tx, out ty); //target.localToWorld(temp.set(data.offsetX, data.offsetY));
|
||||
bone.worldX += tx * translateMix;
|
||||
bone.worldY += ty * translateMix;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (scaleMix > 0) {
|
||||
float s = ((float)Math.Sqrt(ta * ta + tc * tc) - 1 + data.offsetScaleX) * scaleMix + 1;
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
s = ((float)Math.Sqrt(tb * tb + td * td) - 1 + data.offsetScaleY) * scaleMix + 1;
|
||||
bone.b *= s;
|
||||
bone.d *= s;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (shearMix > 0) {
|
||||
float r = MathUtils.Atan2(td, tb) - MathUtils.Atan2(tc, ta);
|
||||
if (r > MathUtils.PI)
|
||||
r -= MathUtils.PI2;
|
||||
else if (r < -MathUtils.PI) r += MathUtils.PI2;
|
||||
float b = bone.b, d = bone.d;
|
||||
r = MathUtils.Atan2(d, b) + (r - MathUtils.PI / 2 + offsetShearY) * shearMix;
|
||||
float s = (float)Math.Sqrt(b * b + d * d);
|
||||
bone.b = MathUtils.Cos(r) * s;
|
||||
bone.d = MathUtils.Sin(r) * s;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (modified) bone.appliedValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyAbsoluteLocal () {
|
||||
float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix;
|
||||
Bone target = this.target;
|
||||
if (!target.appliedValid) target.UpdateAppliedTransform();
|
||||
var bones = this.bones;
|
||||
for (int i = 0, n = bones.Count; i < n; i++) {
|
||||
Bone bone = bones.Items[i];
|
||||
if (!bone.appliedValid) bone.UpdateAppliedTransform();
|
||||
|
||||
float rotation = bone.arotation;
|
||||
if (rotateMix != 0) {
|
||||
float r = target.arotation - rotation + data.offsetRotation;
|
||||
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
|
||||
rotation += r * rotateMix;
|
||||
}
|
||||
|
||||
float x = bone.ax, y = bone.ay;
|
||||
if (translateMix != 0) {
|
||||
x += (target.ax - x + data.offsetX) * translateMix;
|
||||
y += (target.ay - y + data.offsetY) * translateMix;
|
||||
}
|
||||
|
||||
float scaleX = bone.ascaleX, scaleY = bone.ascaleY;
|
||||
if (scaleMix > 0) {
|
||||
if (scaleX > 0.00001f) scaleX = (scaleX + (target.ascaleX - scaleX + data.offsetScaleX) * scaleMix) / scaleX;
|
||||
if (scaleY > 0.00001f) scaleY = (scaleY + (target.ascaleY - scaleY + data.offsetScaleY) * scaleMix) / scaleY;
|
||||
}
|
||||
|
||||
float shearY = bone.ashearY;
|
||||
if (shearMix > 0) {
|
||||
float r = target.ashearY - shearY + data.offsetShearY;
|
||||
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
|
||||
bone.shearY += r * shearMix;
|
||||
}
|
||||
|
||||
bone.UpdateWorldTransform(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyRelativeLocal () {
|
||||
float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix;
|
||||
Bone target = this.target;
|
||||
if (!target.appliedValid) target.UpdateAppliedTransform();
|
||||
var bones = this.bones;
|
||||
for (int i = 0, n = bones.Count; i < n; i++) {
|
||||
Bone bone = bones.Items[i];
|
||||
if (!bone.appliedValid) bone.UpdateAppliedTransform();
|
||||
|
||||
float rotation = bone.arotation;
|
||||
if (rotateMix != 0) rotation += (target.arotation + data.offsetRotation) * rotateMix;
|
||||
|
||||
float x = bone.ax, y = bone.ay;
|
||||
if (translateMix != 0) {
|
||||
x += (target.ax + data.offsetX) * translateMix;
|
||||
y += (target.ay + data.offsetY) * translateMix;
|
||||
}
|
||||
|
||||
float scaleX = bone.ascaleX, scaleY = bone.ascaleY;
|
||||
if (scaleMix > 0) {
|
||||
if (scaleX > 0.00001f) scaleX *= ((target.ascaleX - 1 + data.offsetScaleX) * scaleMix) + 1;
|
||||
if (scaleY > 0.00001f) scaleY *= ((target.ascaleY - 1 + data.offsetScaleY) * scaleMix) + 1;
|
||||
}
|
||||
|
||||
float shearY = bone.ashearY;
|
||||
if (shearMix > 0) shearY += (target.ashearY + data.offsetShearY) * shearMix;
|
||||
|
||||
bone.UpdateWorldTransform(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY);
|
||||
}
|
||||
}
|
||||
|
||||
override public String ToString () {
|
||||
return data.name;
|
||||
}
|
||||
|
||||
@ -38,6 +38,7 @@ namespace Spine {
|
||||
internal BoneData target;
|
||||
internal float rotateMix, translateMix, scaleMix, shearMix;
|
||||
internal float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY;
|
||||
internal bool relative, local;
|
||||
|
||||
public String Name { get { return name; } }
|
||||
public int Order { get { return order; } set { order = value; } }
|
||||
@ -55,6 +56,9 @@ namespace Spine {
|
||||
public float OffsetScaleY { get { return offsetScaleY; } set { offsetScaleY = value; } }
|
||||
public float OffsetShearY { get { return offsetShearY; } set { offsetShearY = value; } }
|
||||
|
||||
public bool Relative { get { return relative; } set { relative = value; } }
|
||||
public bool Local { get { return local; } set { local = value; } }
|
||||
|
||||
public TransformConstraintData (String name) {
|
||||
if (name == null) throw new ArgumentNullException("name", "name cannot be null.");
|
||||
this.name = name;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user