mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-20 09:16:01 +08:00
[csharp][unity] Port of Transform constraint property mapping and cumulated 4.3 changes. Excluding import scale fixes.
This commit is contained in:
parent
0ab3a8251a
commit
90bfdba422
@ -63,7 +63,7 @@ namespace Spine {
|
||||
Timeline[] timelinesItems = timelines.Items;
|
||||
for (int t = 0; t < timelinesCount; ++t)
|
||||
idCount += timelinesItems[t].PropertyIds.Length;
|
||||
string[] propertyIds = new string[idCount];
|
||||
var propertyIds = new string[idCount];
|
||||
int currentId = 0;
|
||||
for (int t = 0; t < timelinesCount; ++t) {
|
||||
string[] ids = timelinesItems[t].PropertyIds;
|
||||
@ -320,7 +320,7 @@ namespace Spine {
|
||||
public void Shrink (int bezierCount) {
|
||||
int size = FrameCount + bezierCount * BEZIER_SIZE;
|
||||
if (curves.Length > size) {
|
||||
float[] newCurves = new float[size];
|
||||
var newCurves = new float[size];
|
||||
Array.Copy(curves, 0, newCurves, 0, size);
|
||||
curves = newCurves;
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
* Integration of the Spine Runtimes into software or otherwise creating
|
||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||
* http://esotericsoftware.com/spine-editor-license
|
||||
* https://esotericsoftware.com/spine-editor-license
|
||||
*
|
||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||
@ -37,7 +37,7 @@ namespace Spine {
|
||||
/// Applies animations over time, queues animations for later playback, mixes (crossfading) between animations, and applies
|
||||
/// multiple animations on top of each other (layering).</para>
|
||||
/// <para>
|
||||
/// See <a href='http://esotericsoftware.com/spine-applying-animations/'>Applying Animations</a> in the Spine Runtimes Guide.</para>
|
||||
/// See <see href='https://esotericsoftware.com/spine-applying-animations/'>Applying Animations</a> in the Spine Runtimes Guide.</para>
|
||||
/// </summary>
|
||||
public class AnimationState {
|
||||
internal static readonly Animation EmptyAnimation = new Animation("<empty>", new ExposedList<Timeline>(), 0);
|
||||
@ -87,7 +87,7 @@ namespace Spine {
|
||||
internal void OnEvent (TrackEntry entry, Event e) { if (Event != null) Event(entry, e); }
|
||||
|
||||
public delegate void TrackEntryDelegate (TrackEntry trackEntry);
|
||||
/// <summary>See <see href="http://esotericsoftware.com/spine-api-reference#AnimationStateListener-Methods">
|
||||
/// <summary>See <see href="https://esotericsoftware.com/spine-api-reference#AnimationStateListener-Methods">
|
||||
/// API Reference documentation pages here</see> for details. Usage in C# and spine-unity is explained
|
||||
/// <see href="https://esotericsoftware.com/spine-unity-main-components#Processing-AnimationState-Events">here</see>
|
||||
/// on the spine-unity documentation pages.</summary>
|
||||
@ -726,7 +726,7 @@ namespace Spine {
|
||||
return AddAnimation(trackIndex, animation, loop, delay);
|
||||
}
|
||||
|
||||
/// <summary>Adds an animation to be played after the current or last queued animation for a track. If the track is empty, it is
|
||||
/// <summary>Adds an animation to be played after the current or last queued animation for a track. If the track has no entries, this is
|
||||
/// equivalent to calling <see cref="SetAnimation(int, Animation, bool)"/>.</summary>
|
||||
/// <param name="delay">
|
||||
/// If > 0, sets <see cref="TrackEntry.Delay"/>. If <= 0, the delay set is the duration of the previous track entry
|
||||
@ -774,8 +774,10 @@ namespace Spine {
|
||||
/// <see cref="AnimationState.AddAnimation(int, Animation, bool, float)"/> with the desired delay (an empty animation has a duration of 0) and on
|
||||
/// the returned track entry, set the <see cref="TrackEntry.SetMixDuration(float)"/>. Mixing from an empty animation causes the new
|
||||
/// animation to be applied more and more over the mix duration. Properties keyed in the new animation transition from the value
|
||||
/// from lower tracks or from the setup pose value if no lower tracks key the property to the value keyed in the new
|
||||
/// animation.</para></summary>
|
||||
/// from lower tracks or from the setup pose value if no lower tracks key the property to the value keyed in the new animation.</para>
|
||||
/// <para>
|
||||
/// See <see href='https://esotericsoftware.com/spine-applying-animations/#Empty-animations'>Empty animations</a> in the Spine
|
||||
/// Runtimes Guide.</para></summary>
|
||||
public TrackEntry SetEmptyAnimation (int trackIndex, float mixDuration) {
|
||||
TrackEntry entry = SetAnimation(trackIndex, AnimationState.EmptyAnimation, false);
|
||||
entry.mixDuration = mixDuration;
|
||||
@ -785,7 +787,7 @@ namespace Spine {
|
||||
|
||||
/// <summary>
|
||||
/// Adds an empty animation to be played after the current or last queued animation for a track, and sets the track entry's
|
||||
/// <see cref="TrackEntry.MixDuration"/>. If the track is empty, it is equivalent to calling
|
||||
/// <see cref="TrackEntry.MixDuration"/>. If the track has no entries, this is equivalent to calling
|
||||
/// <see cref="AnimationState.SetEmptyAnimation(int, float)"/>.</summary>
|
||||
/// <seealso cref="AnimationState.SetEmptyAnimation(int, float)"/>
|
||||
/// <param name="trackIndex">Track number.</param>
|
||||
@ -967,7 +969,7 @@ namespace Spine {
|
||||
public ExposedList<TrackEntry> Tracks { get { return tracks; } }
|
||||
|
||||
override public string ToString () {
|
||||
System.Text.StringBuilder buffer = new System.Text.StringBuilder();
|
||||
var buffer = new System.Text.StringBuilder();
|
||||
TrackEntry[] tracksItems = tracks.Items;
|
||||
for (int i = 0, n = tracks.Count; i < n; i++) {
|
||||
TrackEntry entry = tracksItems[i];
|
||||
@ -991,7 +993,7 @@ namespace Spine {
|
||||
|
||||
internal TrackEntry previous, next, mixingFrom, mixingTo;
|
||||
// difference to libgdx reference: delegates are used for event callbacks instead of 'AnimationStateListener listener'.
|
||||
/// <summary>See <see href="http://esotericsoftware.com/spine-api-reference#AnimationStateListener-Methods">
|
||||
/// <summary>See <see href="https://esotericsoftware.com/spine-api-reference#AnimationStateListener-Methods">
|
||||
/// API Reference documentation pages here</see> for details. Usage in C# and spine-unity is explained
|
||||
/// <see href="https://esotericsoftware.com/spine-unity-main-components#Processing-AnimationState-Events">here</see>
|
||||
/// on the spine-unity documentation pages.</summary>
|
||||
|
||||
@ -64,7 +64,7 @@ namespace Spine {
|
||||
public void SetMix (Animation from, Animation to, float duration) {
|
||||
if (from == null) throw new ArgumentNullException("from", "from cannot be null.");
|
||||
if (to == null) throw new ArgumentNullException("to", "to cannot be null.");
|
||||
AnimationPair key = new AnimationPair(from, to);
|
||||
var key = new AnimationPair(from, to);
|
||||
animationToMixTime.Remove(key);
|
||||
animationToMixTime.Add(key, duration);
|
||||
}
|
||||
@ -76,7 +76,7 @@ namespace Spine {
|
||||
public float GetMix (Animation from, Animation to) {
|
||||
if (from == null) throw new ArgumentNullException("from", "from cannot be null.");
|
||||
if (to == null) throw new ArgumentNullException("to", "to cannot be null.");
|
||||
AnimationPair key = new AnimationPair(from, to);
|
||||
var key = new AnimationPair(from, to);
|
||||
float duration;
|
||||
if (animationToMixTime.TryGetValue(key, out duration)) return duration;
|
||||
return defaultMix;
|
||||
|
||||
@ -53,7 +53,7 @@ namespace Spine {
|
||||
}
|
||||
|
||||
public RegionAttachment NewRegionAttachment (Skin skin, string name, string path, Sequence sequence) {
|
||||
RegionAttachment attachment = new RegionAttachment(name);
|
||||
var attachment = new RegionAttachment(name);
|
||||
if (sequence != null)
|
||||
LoadSequence(name, path, sequence);
|
||||
else {
|
||||
@ -66,7 +66,7 @@ namespace Spine {
|
||||
}
|
||||
|
||||
public MeshAttachment NewMeshAttachment (Skin skin, string name, string path, Sequence sequence) {
|
||||
MeshAttachment attachment = new MeshAttachment(name);
|
||||
var attachment = new MeshAttachment(name);
|
||||
if (sequence != null)
|
||||
LoadSequence(name, path, sequence);
|
||||
else {
|
||||
|
||||
@ -199,7 +199,7 @@ namespace Spine {
|
||||
|
||||
/// <summary>Returns a new mesh with this mesh set as the <see cref="ParentMesh"/>.
|
||||
public MeshAttachment NewLinkedMesh () {
|
||||
MeshAttachment mesh = new MeshAttachment(Name);
|
||||
var mesh = new MeshAttachment(Name);
|
||||
|
||||
mesh.timelineAttachment = timelineAttachment;
|
||||
mesh.region = region;
|
||||
|
||||
@ -79,7 +79,7 @@ namespace Spine {
|
||||
}
|
||||
|
||||
public string GetPath (string basePath, int index) {
|
||||
StringBuilder buffer = new StringBuilder(basePath.Length + digits);
|
||||
var buffer = new StringBuilder(basePath.Length + digits);
|
||||
buffer.Append(basePath);
|
||||
string frame = (start + index).ToString();
|
||||
for (int i = digits - frame.Length; i > 0; i--)
|
||||
|
||||
@ -45,7 +45,7 @@ namespace Spine {
|
||||
|
||||
internal readonly PathConstraintData data;
|
||||
internal readonly ExposedList<Bone> bones;
|
||||
internal Slot target;
|
||||
internal Slot slot;
|
||||
internal float position, spacing, mixRotate, mixX, mixY;
|
||||
|
||||
internal bool active;
|
||||
@ -63,7 +63,7 @@ namespace Spine {
|
||||
foreach (BoneData boneData in data.bones)
|
||||
bones.Add(skeleton.bones.Items[boneData.index]);
|
||||
|
||||
target = skeleton.slots.Items[data.target.index];
|
||||
slot = skeleton.slots.Items[data.slot.index];
|
||||
|
||||
position = data.position;
|
||||
spacing = data.spacing;
|
||||
@ -98,7 +98,7 @@ namespace Spine {
|
||||
}
|
||||
|
||||
public void Update (Physics physics) {
|
||||
PathAttachment attachment = target.Attachment as PathAttachment;
|
||||
PathAttachment attachment = slot.Attachment as PathAttachment;
|
||||
if (attachment == null) return;
|
||||
|
||||
float mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY;
|
||||
@ -171,7 +171,7 @@ namespace Spine {
|
||||
tip = data.rotateMode == RotateMode.Chain;
|
||||
} else {
|
||||
tip = false;
|
||||
Bone p = target.bone;
|
||||
Bone p = slot.bone;
|
||||
offsetRotation *= p.a * p.d - p.b * p.c > 0 ? MathUtils.DegRad : -MathUtils.DegRad;
|
||||
}
|
||||
for (int i = 0, p = 3; i < boneCount; i++, p += 3) {
|
||||
@ -223,7 +223,7 @@ namespace Spine {
|
||||
}
|
||||
|
||||
float[] ComputeWorldPositions (PathAttachment path, int spacesCount, bool tangents) {
|
||||
Slot target = this.target;
|
||||
Slot target = this.slot;
|
||||
float position = this.position;
|
||||
float[] spaces = this.spaces.Items, output = this.positions.Resize(spacesCount * 3 + 2).Items, world;
|
||||
bool closed = path.Closed;
|
||||
@ -506,7 +506,7 @@ namespace Spine {
|
||||
/// <summary>The bones that will be modified by this path constraint.</summary>
|
||||
public ExposedList<Bone> Bones { get { return bones; } }
|
||||
/// <summary>The slot whose path attachment will be used to constrained the bones.</summary>
|
||||
public Slot Target { get { return target; } set { target = value; } }
|
||||
public Slot Target { get { return slot; } set { slot = value; } }
|
||||
public bool Active { get { return active; } }
|
||||
/// <summary>The path constraint's setup pose data.</summary>
|
||||
public PathConstraintData Data { get { return data; } }
|
||||
|
||||
@ -32,7 +32,7 @@ using System;
|
||||
namespace Spine {
|
||||
public class PathConstraintData : ConstraintData {
|
||||
internal ExposedList<BoneData> bones = new ExposedList<BoneData>();
|
||||
internal SlotData target;
|
||||
internal SlotData slot;
|
||||
internal PositionMode positionMode;
|
||||
internal SpacingMode spacingMode;
|
||||
internal RotateMode rotateMode;
|
||||
@ -43,7 +43,7 @@ namespace Spine {
|
||||
}
|
||||
|
||||
public ExposedList<BoneData> Bones { get { return bones; } }
|
||||
public SlotData Target { get { return target; } set { target = value; } }
|
||||
public SlotData Slot { get { return slot; } set { slot = value; } }
|
||||
public PositionMode PositionMode { get { return positionMode; } set { positionMode = value; } }
|
||||
public SpacingMode SpacingMode { get { return spacingMode; } set { spacingMode = value; } }
|
||||
public RotateMode RotateMode { get { return rotateMode; } set { rotateMode = value; } }
|
||||
|
||||
@ -39,7 +39,7 @@ namespace Spine {
|
||||
/// </summary>
|
||||
public class PhysicsConstraint : IUpdatable {
|
||||
internal readonly PhysicsConstraintData data;
|
||||
public Bone bone;
|
||||
internal Bone bone;
|
||||
internal float inertia, strength, damping, massInverse, wind, gravity, mix;
|
||||
|
||||
bool reset = true;
|
||||
|
||||
@ -289,8 +289,7 @@ namespace Spine {
|
||||
&& (!constraint.data.skinRequired || (skin != null && skin.constraints.Contains(constraint.data)));
|
||||
if (!constraint.active) return;
|
||||
|
||||
Bone target = constraint.target;
|
||||
SortBone(target);
|
||||
SortBone(constraint.target);
|
||||
|
||||
ExposedList<Bone> constrained = constraint.bones;
|
||||
Bone parent = constrained.Items[0];
|
||||
@ -311,15 +310,15 @@ namespace Spine {
|
||||
}
|
||||
|
||||
private void SortTransformConstraint (TransformConstraint constraint) {
|
||||
constraint.active = constraint.target.active
|
||||
constraint.active = constraint.source.active
|
||||
&& (!constraint.data.skinRequired || (skin != null && skin.constraints.Contains(constraint.data)));
|
||||
if (!constraint.active) return;
|
||||
|
||||
SortBone(constraint.target);
|
||||
SortBone(constraint.source);
|
||||
|
||||
Bone[] constrained = constraint.bones.Items;
|
||||
int boneCount = constraint.bones.Count;
|
||||
if (constraint.data.local) {
|
||||
if (constraint.data.localSource) {
|
||||
for (int i = 0; i < boneCount; i++) {
|
||||
Bone child = constrained[i];
|
||||
SortBone(child.parent);
|
||||
@ -339,19 +338,18 @@ namespace Spine {
|
||||
}
|
||||
|
||||
private void SortPathConstraint (PathConstraint constraint) {
|
||||
constraint.active = constraint.target.bone.active
|
||||
constraint.active = constraint.slot.bone.active
|
||||
&& (!constraint.data.skinRequired || (skin != null && skin.constraints.Contains(constraint.data)));
|
||||
if (!constraint.active) return;
|
||||
|
||||
Slot slot = constraint.target;
|
||||
Slot slot = constraint.slot;
|
||||
int slotIndex = slot.data.index;
|
||||
Bone slotBone = slot.bone;
|
||||
if (skin != null) SortPathConstraintAttachment(skin, slotIndex, slotBone);
|
||||
if (data.defaultSkin != null && data.defaultSkin != skin)
|
||||
SortPathConstraintAttachment(data.defaultSkin, slotIndex, slotBone);
|
||||
|
||||
Attachment attachment = slot.attachment;
|
||||
if (attachment is PathAttachment) SortPathConstraintAttachment(attachment, slotBone);
|
||||
SortPathConstraintAttachment(slot.attachment, slotBone);
|
||||
|
||||
Bone[] constrained = constraint.bones.Items;
|
||||
int boneCount = constraint.bones.Count;
|
||||
|
||||
@ -42,6 +42,22 @@ using Windows.Storage;
|
||||
#endif
|
||||
|
||||
namespace Spine {
|
||||
|
||||
using FromProperty = TransformConstraintData.FromProperty;
|
||||
using FromRotate = TransformConstraintData.FromRotate;
|
||||
using FromScaleX = TransformConstraintData.FromScaleX;
|
||||
using FromScaleY = TransformConstraintData.FromScaleY;
|
||||
using FromShearY = TransformConstraintData.FromShearY;
|
||||
using FromX = TransformConstraintData.FromX;
|
||||
using FromY = TransformConstraintData.FromY;
|
||||
using ToProperty = TransformConstraintData.ToProperty;
|
||||
using ToRotate = TransformConstraintData.ToRotate;
|
||||
using ToScaleX = TransformConstraintData.ToScaleX;
|
||||
using ToScaleY = TransformConstraintData.ToScaleY;
|
||||
using ToShearY = TransformConstraintData.ToShearY;
|
||||
using ToX = TransformConstraintData.ToX;
|
||||
using ToY = TransformConstraintData.ToY;
|
||||
|
||||
public class SkeletonBinary : SkeletonLoader {
|
||||
public const int BONE_ROTATE = 0;
|
||||
public const int BONE_TRANSLATE = 1;
|
||||
@ -122,8 +138,7 @@ namespace Spine {
|
||||
/// <summary>Returns the version string of binary skeleton data.</summary>
|
||||
public static string GetVersionString (Stream file) {
|
||||
if (file == null) throw new ArgumentNullException("file");
|
||||
|
||||
SkeletonInput input = new SkeletonInput(file);
|
||||
var input = new SkeletonInput(file);
|
||||
return input.GetVersionString();
|
||||
}
|
||||
|
||||
@ -131,8 +146,8 @@ namespace Spine {
|
||||
if (file == null) throw new ArgumentNullException("file");
|
||||
float scale = this.scale;
|
||||
|
||||
SkeletonData skeletonData = new SkeletonData();
|
||||
SkeletonInput input = new SkeletonInput(file);
|
||||
var skeletonData = new SkeletonData();
|
||||
var input = new SkeletonInput(file);
|
||||
|
||||
long hash = input.ReadLong();
|
||||
skeletonData.hash = hash == 0 ? null : hash.ToString();
|
||||
@ -171,7 +186,7 @@ namespace Spine {
|
||||
for (int i = 0; i < n; i++) {
|
||||
String name = input.ReadString();
|
||||
BoneData parent = i == 0 ? null : bones[input.ReadInt(true)];
|
||||
BoneData data = new BoneData(i, name, parent);
|
||||
var data = new BoneData(i, name, parent);
|
||||
data.rotation = input.ReadFloat();
|
||||
data.x = input.ReadFloat() * scale;
|
||||
data.y = input.ReadFloat() * scale;
|
||||
@ -196,7 +211,7 @@ namespace Spine {
|
||||
String slotName = input.ReadString();
|
||||
|
||||
BoneData boneData = bones[input.ReadInt(true)];
|
||||
SlotData slotData = new SlotData(i, slotName, boneData);
|
||||
var slotData = new SlotData(i, slotName, boneData);
|
||||
int color = input.ReadInt();
|
||||
slotData.r = ((color & 0xff000000) >> 24) / 255f;
|
||||
slotData.g = ((color & 0x00ff0000) >> 16) / 255f;
|
||||
@ -222,7 +237,7 @@ namespace Spine {
|
||||
// IK constraints.
|
||||
o = skeletonData.ikConstraints.Resize(n = input.ReadInt(true)).Items;
|
||||
for (int i = 0, nn; i < n; i++) {
|
||||
IkConstraintData data = new IkConstraintData(input.ReadString());
|
||||
var data = new IkConstraintData(input.ReadString());
|
||||
data.order = input.ReadInt(true);
|
||||
BoneData[] constraintBones = data.bones.Resize(nn = input.ReadInt(true)).Items;
|
||||
for (int ii = 0; ii < nn; ii++)
|
||||
@ -242,42 +257,72 @@ namespace Spine {
|
||||
// Transform constraints.
|
||||
o = skeletonData.transformConstraints.Resize(n = input.ReadInt(true)).Items;
|
||||
for (int i = 0, nn; i < n; i++) {
|
||||
TransformConstraintData data = new TransformConstraintData(input.ReadString());
|
||||
var data = new TransformConstraintData(input.ReadString());
|
||||
data.order = input.ReadInt(true);
|
||||
BoneData[] constraintBones = data.bones.Resize(nn = input.ReadInt(true)).Items;
|
||||
for (int ii = 0; ii < nn; ii++)
|
||||
constraintBones[ii] = bones[input.ReadInt(true)];
|
||||
data.target = bones[input.ReadInt(true)];
|
||||
data.source = bones[input.ReadInt(true)];
|
||||
int flags = input.Read();
|
||||
data.skinRequired = (flags & 1) != 0;
|
||||
data.local = (flags & 2) != 0;
|
||||
data.relative = (flags & 4) != 0;
|
||||
if ((flags & 8) != 0) data.offsetRotation = input.ReadFloat();
|
||||
if ((flags & 16) != 0) data.offsetX = input.ReadFloat() * scale;
|
||||
if ((flags & 32) != 0) data.offsetY = input.ReadFloat() * scale;
|
||||
if ((flags & 64) != 0) data.offsetScaleX = input.ReadFloat();
|
||||
if ((flags & 128) != 0) data.offsetScaleY = input.ReadFloat();
|
||||
data.localSource = (flags & 2) != 0;
|
||||
data.localTarget = (flags & 4) != 0;
|
||||
data.additive = (flags & 8) != 0;
|
||||
data.clamp = (flags & 16) != 0;
|
||||
FromProperty[] froms = data.properties.Resize(nn = flags >> 5).Items;
|
||||
for (int ii = 0, tn; ii < nn; ii++) {
|
||||
FromProperty from;
|
||||
switch (input.ReadSByte()) {
|
||||
case 0: from = new FromRotate(); break;
|
||||
case 1: from = new FromX(); break;
|
||||
case 2: from = new FromY(); break;
|
||||
case 3: from = new FromScaleX(); break;
|
||||
case 4: from = new FromScaleY(); break;
|
||||
case 5: from = new FromShearY(); break;
|
||||
default: from = null; break;
|
||||
};
|
||||
from.offset = input.ReadFloat() * scale;
|
||||
ToProperty[] tos = from.to.Resize(tn = input.ReadSByte()).Items;
|
||||
for (int t = 0; t < tn; t++) {
|
||||
ToProperty to;
|
||||
switch (input.ReadSByte()) {
|
||||
case 0: to = new ToRotate(); break;
|
||||
case 1: to = new ToX(); break;
|
||||
case 2: to = new ToY(); break;
|
||||
case 3: to = new ToScaleX(); break;
|
||||
case 4: to = new ToScaleY(); break;
|
||||
case 5: to = new ToShearY(); break;
|
||||
default: to = null; break;
|
||||
};
|
||||
to.offset = input.ReadFloat() * scale;
|
||||
to.max = input.ReadFloat() * scale;
|
||||
to.scale = input.ReadFloat();
|
||||
tos[t] = to;
|
||||
}
|
||||
froms[ii] = from;
|
||||
}
|
||||
flags = input.Read();
|
||||
if ((flags & 1) != 0) data.offsetShearY = input.ReadFloat();
|
||||
if ((flags & 2) != 0) data.mixRotate = input.ReadFloat();
|
||||
if ((flags & 4) != 0) data.mixX = input.ReadFloat();
|
||||
if ((flags & 8) != 0) data.mixY = input.ReadFloat();
|
||||
if ((flags & 16) != 0) data.mixScaleX = input.ReadFloat();
|
||||
if ((flags & 32) != 0) data.mixScaleY = input.ReadFloat();
|
||||
if ((flags & 64) != 0) data.mixShearY = input.ReadFloat();
|
||||
if ((flags & 1) != 0) data.offsetX = input.ReadFloat();
|
||||
if ((flags & 2) != 0) data.offsetY = input.ReadFloat();
|
||||
if ((flags & 4) != 0) data.mixRotate = input.ReadFloat();
|
||||
if ((flags & 8) != 0) data.mixX = input.ReadFloat();
|
||||
if ((flags & 16) != 0) data.mixY = input.ReadFloat();
|
||||
if ((flags & 32) != 0) data.mixScaleX = input.ReadFloat();
|
||||
if ((flags & 64) != 0) data.mixScaleY = input.ReadFloat();
|
||||
if ((flags & 128) != 0) data.mixShearY = input.ReadFloat();
|
||||
o[i] = data;
|
||||
}
|
||||
|
||||
// Path constraints
|
||||
o = skeletonData.pathConstraints.Resize(n = input.ReadInt(true)).Items;
|
||||
for (int i = 0, nn; i < n; i++) {
|
||||
PathConstraintData data = new PathConstraintData(input.ReadString());
|
||||
var data = new PathConstraintData(input.ReadString());
|
||||
data.order = input.ReadInt(true);
|
||||
data.skinRequired = input.ReadBoolean();
|
||||
BoneData[] constraintBones = data.bones.Resize(nn = input.ReadInt(true)).Items;
|
||||
for (int ii = 0; ii < nn; ii++)
|
||||
constraintBones[ii] = bones[input.ReadInt(true)];
|
||||
data.target = slots[input.ReadInt(true)];
|
||||
data.slot = slots[input.ReadInt(true)];
|
||||
int flags = input.Read();
|
||||
data.positionMode = (PositionMode)Enum.GetValues(typeof(PositionMode)).GetValue(flags & 1);
|
||||
data.spacingMode = (SpacingMode)Enum.GetValues(typeof(SpacingMode)).GetValue((flags >> 1) & 3);
|
||||
@ -297,7 +342,7 @@ namespace Spine {
|
||||
// Physics constraints.
|
||||
o = skeletonData.physicsConstraints.Resize(n = input.ReadInt(true)).Items;
|
||||
for (int i = 0; i < n; i++) {
|
||||
PhysicsConstraintData data = new PhysicsConstraintData(input.ReadString());
|
||||
var data = new PhysicsConstraintData(input.ReadString());
|
||||
data.order = input.ReadInt(true);
|
||||
data.bone = bones[input.ReadInt(true)];
|
||||
int flags = input.Read();
|
||||
@ -358,7 +403,7 @@ namespace Spine {
|
||||
// Events.
|
||||
o = skeletonData.events.Resize(n = input.ReadInt(true)).Items;
|
||||
for (int i = 0; i < n; i++) {
|
||||
EventData data = new EventData(input.ReadString());
|
||||
var data = new EventData(input.ReadString());
|
||||
data.Int = input.ReadInt(false);
|
||||
data.Float = input.ReadFloat();
|
||||
data.String = input.ReadString();
|
||||
@ -547,7 +592,7 @@ namespace Spine {
|
||||
bool closed = (flags & 16) != 0;
|
||||
bool constantSpeed = (flags & 32) != 0;
|
||||
Vertices vertices = ReadVertices(input, (flags & 64) != 0);
|
||||
float[] lengths = new float[vertices.length / 6];
|
||||
var lengths = new float[vertices.length / 6];
|
||||
for (int i = 0, n = lengths.Length; i < n; i++)
|
||||
lengths[i] = input.ReadFloat() * scale;
|
||||
if (nonessential) input.ReadInt(); //int color = nonessential ? input.ReadInt() : 0;
|
||||
@ -596,7 +641,7 @@ namespace Spine {
|
||||
}
|
||||
|
||||
private Sequence ReadSequence (SkeletonInput input) {
|
||||
Sequence sequence = new Sequence(input.ReadInt(true));
|
||||
var sequence = new Sequence(input.ReadInt(true));
|
||||
sequence.Start = input.ReadInt(true);
|
||||
sequence.Digits = input.ReadInt(true);
|
||||
sequence.SetupIndex = input.ReadInt(true);
|
||||
@ -606,14 +651,14 @@ namespace Spine {
|
||||
private Vertices ReadVertices (SkeletonInput input, bool weighted) {
|
||||
float scale = this.scale;
|
||||
int vertexCount = input.ReadInt(true);
|
||||
Vertices vertices = new Vertices();
|
||||
var vertices = new Vertices();
|
||||
vertices.length = vertexCount << 1;
|
||||
if (!weighted) {
|
||||
vertices.vertices = ReadFloatArray(input, vertices.length, scale);
|
||||
return vertices;
|
||||
}
|
||||
ExposedList<float> weights = new ExposedList<float>(vertices.length * 3 * 3);
|
||||
ExposedList<int> bonesArray = new ExposedList<int>(vertices.length * 3);
|
||||
var weights = new ExposedList<float>(vertices.length * 3 * 3);
|
||||
var bonesArray = new ExposedList<int>(vertices.length * 3);
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
int boneCount = input.ReadInt(true);
|
||||
bonesArray.Add(boneCount);
|
||||
@ -631,7 +676,7 @@ namespace Spine {
|
||||
}
|
||||
|
||||
private float[] ReadFloatArray (SkeletonInput input, int n, float scale) {
|
||||
float[] array = new float[n];
|
||||
var array = new float[n];
|
||||
if (scale == 1) {
|
||||
for (int i = 0; i < n; i++)
|
||||
array[i] = input.ReadFloat();
|
||||
@ -643,7 +688,7 @@ namespace Spine {
|
||||
}
|
||||
|
||||
private int[] ReadShortArray (SkeletonInput input, int n) {
|
||||
int[] array = new int[n];
|
||||
var array = new int[n];
|
||||
for (int i = 0; i < n; i++)
|
||||
array[i] = input.ReadInt(true);
|
||||
return array;
|
||||
@ -652,7 +697,7 @@ namespace Spine {
|
||||
/// <exception cref="SerializationException">SerializationException will be thrown when a Vertex attachment is not found.</exception>
|
||||
/// <exception cref="IOException">Throws IOException when a read operation fails.</exception>
|
||||
private Animation ReadAnimation (String name, SkeletonInput input, SkeletonData skeletonData) {
|
||||
ExposedList<Timeline> timelines = new ExposedList<Timeline>(input.ReadInt(true));
|
||||
var timelines = new ExposedList<Timeline>(input.ReadInt(true));
|
||||
float scale = this.scale;
|
||||
|
||||
// Slot timelines.
|
||||
@ -662,14 +707,14 @@ namespace Spine {
|
||||
int timelineType = input.ReadUByte(), frameCount = input.ReadInt(true), frameLast = frameCount - 1;
|
||||
switch (timelineType) {
|
||||
case SLOT_ATTACHMENT: {
|
||||
AttachmentTimeline timeline = new AttachmentTimeline(frameCount, slotIndex);
|
||||
var timeline = new AttachmentTimeline(frameCount, slotIndex);
|
||||
for (int frame = 0; frame < frameCount; frame++)
|
||||
timeline.SetFrame(frame, input.ReadFloat(), input.ReadStringRef());
|
||||
timelines.Add(timeline);
|
||||
break;
|
||||
}
|
||||
case SLOT_RGBA: {
|
||||
RGBATimeline timeline = new RGBATimeline(frameCount, input.ReadInt(true), slotIndex);
|
||||
var timeline = new RGBATimeline(frameCount, input.ReadInt(true), slotIndex);
|
||||
float time = input.ReadFloat();
|
||||
float r = input.Read() / 255f, g = input.Read() / 255f;
|
||||
float b = input.Read() / 255f, a = input.Read() / 255f;
|
||||
@ -700,7 +745,7 @@ namespace Spine {
|
||||
break;
|
||||
}
|
||||
case SLOT_RGB: {
|
||||
RGBTimeline timeline = new RGBTimeline(frameCount, input.ReadInt(true), slotIndex);
|
||||
var timeline = new RGBTimeline(frameCount, input.ReadInt(true), slotIndex);
|
||||
float time = input.ReadFloat();
|
||||
float r = input.Read() / 255f, g = input.Read() / 255f, b = input.Read() / 255f;
|
||||
for (int frame = 0, bezier = 0; ; frame++) {
|
||||
@ -727,7 +772,7 @@ namespace Spine {
|
||||
break;
|
||||
}
|
||||
case SLOT_RGBA2: {
|
||||
RGBA2Timeline timeline = new RGBA2Timeline(frameCount, input.ReadInt(true), slotIndex);
|
||||
var timeline = new RGBA2Timeline(frameCount, input.ReadInt(true), slotIndex);
|
||||
float time = input.ReadFloat();
|
||||
float r = input.Read() / 255f, g = input.Read() / 255f;
|
||||
float b = input.Read() / 255f, a = input.Read() / 255f;
|
||||
@ -766,7 +811,7 @@ namespace Spine {
|
||||
break;
|
||||
}
|
||||
case SLOT_RGB2: {
|
||||
RGB2Timeline timeline = new RGB2Timeline(frameCount, input.ReadInt(true), slotIndex);
|
||||
var timeline = new RGB2Timeline(frameCount, input.ReadInt(true), slotIndex);
|
||||
float time = input.ReadFloat();
|
||||
float r = input.Read() / 255f, g = input.Read() / 255f, b = input.Read() / 255f;
|
||||
float r2 = input.Read() / 255f, g2 = input.Read() / 255f, b2 = input.Read() / 255f;
|
||||
@ -801,7 +846,7 @@ namespace Spine {
|
||||
break;
|
||||
}
|
||||
case SLOT_ALPHA: {
|
||||
AlphaTimeline timeline = new AlphaTimeline(frameCount, input.ReadInt(true), slotIndex);
|
||||
var timeline = new AlphaTimeline(frameCount, input.ReadInt(true), slotIndex);
|
||||
float time = input.ReadFloat(), a = input.Read() / 255f;
|
||||
for (int frame = 0, bezier = 0; ; frame++) {
|
||||
timeline.SetFrame(frame, time, a);
|
||||
@ -832,7 +877,7 @@ namespace Spine {
|
||||
for (int ii = 0, nn = input.ReadInt(true); ii < nn; ii++) {
|
||||
int type = input.ReadUByte(), frameCount = input.ReadInt(true);
|
||||
if (type == BONE_INHERIT) {
|
||||
InheritTimeline timeline = new InheritTimeline(frameCount, boneIndex);
|
||||
var timeline = new InheritTimeline(frameCount, boneIndex);
|
||||
for (int frame = 0; frame < frameCount; frame++)
|
||||
timeline.SetFrame(frame, input.ReadFloat(), InheritEnum.Values[input.ReadUByte()]);
|
||||
timelines.Add(timeline);
|
||||
@ -877,7 +922,7 @@ namespace Spine {
|
||||
// IK constraint timelines.
|
||||
for (int i = 0, n = input.ReadInt(true); i < n; i++) {
|
||||
int index = input.ReadInt(true), frameCount = input.ReadInt(true), frameLast = frameCount - 1;
|
||||
IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount, input.ReadInt(true), index);
|
||||
var timeline = new IkConstraintTimeline(frameCount, input.ReadInt(true), index);
|
||||
int flags = input.Read();
|
||||
float time = input.ReadFloat(), mix = (flags & 1) != 0 ? ((flags & 2) != 0 ? input.ReadFloat() : 1) : 0;
|
||||
float softness = (flags & 4) != 0 ? input.ReadFloat() * scale : 0;
|
||||
@ -904,7 +949,7 @@ namespace Spine {
|
||||
// Transform constraint timelines.
|
||||
for (int i = 0, n = input.ReadInt(true); i < n; i++) {
|
||||
int index = input.ReadInt(true), frameCount = input.ReadInt(true), frameLast = frameCount - 1;
|
||||
TransformConstraintTimeline timeline = new TransformConstraintTimeline(frameCount, input.ReadInt(true), index);
|
||||
var timeline = new TransformConstraintTimeline(frameCount, input.ReadInt(true), index);
|
||||
float time = input.ReadFloat(), mixRotate = input.ReadFloat(), mixX = input.ReadFloat(), mixY = input.ReadFloat(),
|
||||
mixScaleX = input.ReadFloat(), mixScaleY = input.ReadFloat(), mixShearY = input.ReadFloat();
|
||||
for (int frame = 0, bezier = 0; ; frame++) {
|
||||
@ -943,16 +988,18 @@ namespace Spine {
|
||||
for (int ii = 0, nn = input.ReadInt(true); ii < nn; ii++) {
|
||||
int type = input.ReadUByte(), frameCount = input.ReadInt(true), bezierCount = input.ReadInt(true);
|
||||
switch (type) {
|
||||
case PATH_POSITION:
|
||||
case PATH_POSITION: {
|
||||
ReadTimeline(input, timelines, new PathConstraintPositionTimeline(frameCount, bezierCount, index),
|
||||
data.positionMode == PositionMode.Fixed ? scale : 1);
|
||||
break;
|
||||
case PATH_SPACING:
|
||||
}
|
||||
case PATH_SPACING: {
|
||||
ReadTimeline(input, timelines, new PathConstraintSpacingTimeline(frameCount, bezierCount, index),
|
||||
data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed ? scale : 1);
|
||||
break;
|
||||
case PATH_MIX:
|
||||
PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(frameCount, bezierCount, index);
|
||||
}
|
||||
case PATH_MIX: {
|
||||
var timeline = new PathConstraintMixTimeline(frameCount, bezierCount, index);
|
||||
float time = input.ReadFloat(), mixRotate = input.ReadFloat(), mixX = input.ReadFloat(), mixY = input.ReadFloat();
|
||||
for (int frame = 0, bezier = 0, frameLast = timeline.FrameCount - 1; ; frame++) {
|
||||
timeline.SetFrame(frame, time, mixRotate, mixX, mixY);
|
||||
@ -977,6 +1024,7 @@ namespace Spine {
|
||||
timelines.Add(timeline);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -986,36 +1034,40 @@ namespace Spine {
|
||||
for (int ii = 0, nn = input.ReadInt(true); ii < nn; ii++) {
|
||||
int type = input.ReadUByte(), frameCount = input.ReadInt(true);
|
||||
if (type == PHYSICS_RESET) {
|
||||
PhysicsConstraintResetTimeline timeline = new PhysicsConstraintResetTimeline(frameCount, index);
|
||||
var timeline = new PhysicsConstraintResetTimeline(frameCount, index);
|
||||
for (int frame = 0; frame < frameCount; frame++)
|
||||
timeline.SetFrame(frame, input.ReadFloat());
|
||||
timelines.Add(timeline);
|
||||
continue;
|
||||
}
|
||||
int bezierCount = input.ReadInt(true);
|
||||
PhysicsConstraintTimeline newTimeline;
|
||||
switch (type) {
|
||||
case PHYSICS_INERTIA:
|
||||
ReadTimeline(input, timelines, new PhysicsConstraintInertiaTimeline(frameCount, bezierCount, index), 1);
|
||||
newTimeline = new PhysicsConstraintInertiaTimeline(frameCount, bezierCount, index);
|
||||
break;
|
||||
case PHYSICS_STRENGTH:
|
||||
ReadTimeline(input, timelines, new PhysicsConstraintStrengthTimeline(frameCount, bezierCount, index), 1);
|
||||
newTimeline = new PhysicsConstraintStrengthTimeline(frameCount, bezierCount, index);
|
||||
break;
|
||||
case PHYSICS_DAMPING:
|
||||
ReadTimeline(input, timelines, new PhysicsConstraintDampingTimeline(frameCount, bezierCount, index), 1);
|
||||
newTimeline = new PhysicsConstraintDampingTimeline(frameCount, bezierCount, index);
|
||||
break;
|
||||
case PHYSICS_MASS:
|
||||
ReadTimeline(input, timelines, new PhysicsConstraintMassTimeline(frameCount, bezierCount, index), 1);
|
||||
newTimeline = new PhysicsConstraintMassTimeline(frameCount, bezierCount, index);
|
||||
break;
|
||||
case PHYSICS_WIND:
|
||||
ReadTimeline(input, timelines, new PhysicsConstraintWindTimeline(frameCount, bezierCount, index), 1);
|
||||
newTimeline = new PhysicsConstraintWindTimeline(frameCount, bezierCount, index);
|
||||
break;
|
||||
case PHYSICS_GRAVITY:
|
||||
ReadTimeline(input, timelines, new PhysicsConstraintGravityTimeline(frameCount, bezierCount, index), 1);
|
||||
newTimeline = new PhysicsConstraintGravityTimeline(frameCount, bezierCount, index);
|
||||
break;
|
||||
case PHYSICS_MIX:
|
||||
ReadTimeline(input, timelines, new PhysicsConstraintMixTimeline(frameCount, bezierCount, index), 1);
|
||||
newTimeline = new PhysicsConstraintMixTimeline(frameCount, bezierCount, index);
|
||||
break;
|
||||
default:
|
||||
throw new SerializationException();
|
||||
}
|
||||
ReadTimeline(input, timelines, newTimeline, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1037,7 +1089,7 @@ namespace Spine {
|
||||
float[] vertices = vertexAttachment.Vertices;
|
||||
int deformLength = weighted ? (vertices.Length / 3) << 1 : vertices.Length;
|
||||
|
||||
DeformTimeline timeline = new DeformTimeline(frameCount, input.ReadInt(true), slotIndex, vertexAttachment);
|
||||
var timeline = new DeformTimeline(frameCount, input.ReadInt(true), slotIndex, vertexAttachment);
|
||||
|
||||
float time = input.ReadFloat();
|
||||
for (int frame = 0, bezier = 0; ; frame++) {
|
||||
@ -1078,7 +1130,7 @@ namespace Spine {
|
||||
break;
|
||||
}
|
||||
case ATTACHMENT_SEQUENCE: {
|
||||
SequenceTimeline timeline = new SequenceTimeline(frameCount, slotIndex, attachment);
|
||||
var timeline = new SequenceTimeline(frameCount, slotIndex, attachment);
|
||||
for (int frame = 0; frame < frameCount; frame++) {
|
||||
float time = input.ReadFloat();
|
||||
int modeAndIndex = input.ReadInt();
|
||||
@ -1096,15 +1148,15 @@ namespace Spine {
|
||||
// Draw order timeline.
|
||||
int drawOrderCount = input.ReadInt(true);
|
||||
if (drawOrderCount > 0) {
|
||||
DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrderCount);
|
||||
var timeline = new DrawOrderTimeline(drawOrderCount);
|
||||
int slotCount = skeletonData.slots.Count;
|
||||
for (int i = 0; i < drawOrderCount; i++) {
|
||||
float time = input.ReadFloat();
|
||||
int offsetCount = input.ReadInt(true);
|
||||
int[] drawOrder = new int[slotCount];
|
||||
var drawOrder = new int[slotCount];
|
||||
for (int ii = slotCount - 1; ii >= 0; ii--)
|
||||
drawOrder[ii] = -1;
|
||||
int[] unchanged = new int[slotCount - offsetCount];
|
||||
var unchanged = new int[slotCount - offsetCount];
|
||||
int originalIndex = 0, unchangedIndex = 0;
|
||||
for (int ii = 0; ii < offsetCount; ii++) {
|
||||
int slotIndex = input.ReadInt(true);
|
||||
@ -1128,11 +1180,11 @@ namespace Spine {
|
||||
// Event timeline.
|
||||
int eventCount = input.ReadInt(true);
|
||||
if (eventCount > 0) {
|
||||
EventTimeline timeline = new EventTimeline(eventCount);
|
||||
var timeline = new EventTimeline(eventCount);
|
||||
for (int i = 0; i < eventCount; i++) {
|
||||
float time = input.ReadFloat();
|
||||
EventData eventData = skeletonData.events.Items[input.ReadInt(true)];
|
||||
Event e = new Event(time, eventData);
|
||||
var e = new Event(time, eventData);
|
||||
e.intValue = input.ReadInt(false);
|
||||
e.floatValue = input.ReadFloat();
|
||||
e.stringValue = input.ReadString();
|
||||
@ -1353,7 +1405,7 @@ namespace Spine {
|
||||
byteCount = ReadInt(true);
|
||||
if (byteCount > 1 && byteCount <= 13) {
|
||||
byteCount--;
|
||||
byte[] buffer = new byte[byteCount];
|
||||
var buffer = new byte[byteCount];
|
||||
ReadFully(buffer, 0, byteCount);
|
||||
return System.Text.Encoding.UTF8.GetString(buffer, 0, byteCount);
|
||||
}
|
||||
|
||||
@ -42,6 +42,21 @@ using Windows.Storage;
|
||||
|
||||
namespace Spine {
|
||||
|
||||
using FromProperty = TransformConstraintData.FromProperty;
|
||||
using FromRotate = TransformConstraintData.FromRotate;
|
||||
using FromScaleX = TransformConstraintData.FromScaleX;
|
||||
using FromScaleY = TransformConstraintData.FromScaleY;
|
||||
using FromShearY = TransformConstraintData.FromShearY;
|
||||
using FromX = TransformConstraintData.FromX;
|
||||
using FromY = TransformConstraintData.FromY;
|
||||
using ToProperty = TransformConstraintData.ToProperty;
|
||||
using ToRotate = TransformConstraintData.ToRotate;
|
||||
using ToScaleX = TransformConstraintData.ToScaleX;
|
||||
using ToScaleY = TransformConstraintData.ToScaleY;
|
||||
using ToShearY = TransformConstraintData.ToShearY;
|
||||
using ToX = TransformConstraintData.ToX;
|
||||
using ToY = TransformConstraintData.ToY;
|
||||
|
||||
/// <summary>
|
||||
/// Loads skeleton data in the Spine JSON format.
|
||||
/// <para>
|
||||
@ -94,7 +109,7 @@ namespace Spine {
|
||||
if (reader == null) throw new ArgumentNullException("reader", "reader cannot be null.");
|
||||
|
||||
float scale = this.scale;
|
||||
SkeletonData skeletonData = new SkeletonData();
|
||||
var skeletonData = new SkeletonData();
|
||||
|
||||
Dictionary<string, object> root = Json.Deserialize(reader) as Dictionary<string, Object>;
|
||||
if (root == null) throw new Exception("Invalid JSON.");
|
||||
@ -123,7 +138,7 @@ namespace Spine {
|
||||
if (parent == null)
|
||||
throw new Exception("Parent bone not found: " + boneMap["parent"]);
|
||||
}
|
||||
BoneData data = new BoneData(skeletonData.Bones.Count, (string)boneMap["name"], parent);
|
||||
var data = new BoneData(skeletonData.Bones.Count, (string)boneMap["name"], parent);
|
||||
data.length = GetFloat(boneMap, "length", 0) * scale;
|
||||
data.x = GetFloat(boneMap, "x", 0) * scale;
|
||||
data.y = GetFloat(boneMap, "y", 0) * scale;
|
||||
@ -148,7 +163,7 @@ namespace Spine {
|
||||
string boneName = (string)slotMap["bone"];
|
||||
BoneData boneData = skeletonData.FindBone(boneName);
|
||||
if (boneData == null) throw new Exception("Slot bone not found: " + boneName);
|
||||
SlotData data = new SlotData(skeletonData.Slots.Count, slotName, boneData);
|
||||
var data = new SlotData(skeletonData.Slots.Count, slotName, boneData);
|
||||
|
||||
if (slotMap.ContainsKey("color")) {
|
||||
string color = (string)slotMap["color"];
|
||||
@ -179,7 +194,7 @@ namespace Spine {
|
||||
// IK constraints.
|
||||
if (root.ContainsKey("ik")) {
|
||||
foreach (Dictionary<string, Object> constraintMap in (List<Object>)root["ik"]) {
|
||||
IkConstraintData data = new IkConstraintData((string)constraintMap["name"]);
|
||||
var data = new IkConstraintData((string)constraintMap["name"]);
|
||||
data.order = GetInt(constraintMap, "order", 0);
|
||||
data.skinRequired = GetBoolean(constraintMap, "skin", false);
|
||||
|
||||
@ -208,7 +223,7 @@ namespace Spine {
|
||||
// Transform constraints.
|
||||
if (root.ContainsKey("transform")) {
|
||||
foreach (Dictionary<string, Object> constraintMap in (List<Object>)root["transform"]) {
|
||||
TransformConstraintData data = new TransformConstraintData((string)constraintMap["name"]);
|
||||
var data = new TransformConstraintData((string)constraintMap["name"]);
|
||||
data.order = GetInt(constraintMap, "order", 0);
|
||||
data.skinRequired = GetBoolean(constraintMap, "skin", false);
|
||||
|
||||
@ -220,26 +235,89 @@ namespace Spine {
|
||||
}
|
||||
}
|
||||
|
||||
string targetName = (string)constraintMap["target"];
|
||||
data.target = skeletonData.FindBone(targetName);
|
||||
if (data.target == null) throw new Exception("Transform constraint target bone not found: " + targetName);
|
||||
string sourceName = (string)constraintMap["source"];
|
||||
data.source = skeletonData.FindBone(sourceName);
|
||||
if (data.source == null) throw new Exception("Transform constraint source bone not found: " + sourceName);
|
||||
|
||||
data.local = GetBoolean(constraintMap, "local", false);
|
||||
data.relative = GetBoolean(constraintMap, "relative", false);
|
||||
data.localSource = GetBoolean(constraintMap, "localSource", false);
|
||||
data.additive = GetBoolean(constraintMap, "additive", false);
|
||||
data.clamp = GetBoolean(constraintMap, "clamp", false);
|
||||
|
||||
data.offsetRotation = GetFloat(constraintMap, "rotation", 0);
|
||||
data.offsetX = GetFloat(constraintMap, "x", 0) * scale;
|
||||
data.offsetY = GetFloat(constraintMap, "y", 0) * scale;
|
||||
data.offsetScaleX = GetFloat(constraintMap, "scaleX", 0);
|
||||
data.offsetScaleY = GetFloat(constraintMap, "scaleY", 0);
|
||||
data.offsetShearY = GetFloat(constraintMap, "shearY", 0);
|
||||
bool rotate = false, x = false, y = false, scaleX = false, scaleY = false, shearY = false;
|
||||
if (constraintMap.ContainsKey("properties")) {
|
||||
foreach (KeyValuePair<string, Object> fromEntryObject in (Dictionary<string, Object>)constraintMap["properties"]) {
|
||||
var fromEntry = (Dictionary<string, Object>)fromEntryObject.Value;
|
||||
string fromEntryName = fromEntryObject.Key;
|
||||
|
||||
data.mixRotate = GetFloat(constraintMap, "mixRotate", 1);
|
||||
data.mixX = GetFloat(constraintMap, "mixX", 1);
|
||||
data.mixY = GetFloat(constraintMap, "mixY", data.mixX);
|
||||
data.mixScaleX = GetFloat(constraintMap, "mixScaleX", 1);
|
||||
data.mixScaleY = GetFloat(constraintMap, "mixScaleY", data.mixScaleX);
|
||||
data.mixShearY = GetFloat(constraintMap, "mixShearY", 1);
|
||||
FromProperty from;
|
||||
switch (fromEntryName) {
|
||||
case "rotate": from = new FromRotate(); break;
|
||||
case "x": from = new FromX(); break;
|
||||
case "y": from = new FromY(); break;
|
||||
case "scaleX": from = new FromScaleX(); break;
|
||||
case "scaleY": from = new FromScaleY(); break;
|
||||
case "shearY": from = new FromShearY(); break;
|
||||
default: throw new Exception("Invalid transform constraint from property: " + fromEntryName);
|
||||
};
|
||||
|
||||
from.offset = GetFloat(fromEntry, "offset", 0) * scale;
|
||||
if (fromEntry.ContainsKey("to")) {
|
||||
foreach (KeyValuePair<string, Object> toEntryObject in (Dictionary<string, Object>)fromEntry["to"]) {
|
||||
var toEntry = (Dictionary<string, Object>)toEntryObject.Value;
|
||||
string toEntryName = toEntryObject.Key;
|
||||
|
||||
ToProperty to;
|
||||
switch (toEntryName) {
|
||||
case "rotate": {
|
||||
rotate = true;
|
||||
to = new ToRotate();
|
||||
break;
|
||||
}
|
||||
case "x": {
|
||||
x = true;
|
||||
to = new ToX();
|
||||
break;
|
||||
}
|
||||
case "y": {
|
||||
y = true;
|
||||
to = new ToY();
|
||||
break;
|
||||
}
|
||||
case "scaleX": {
|
||||
scaleX = true;
|
||||
to = new ToScaleX();
|
||||
break;
|
||||
}
|
||||
case "scaleY": {
|
||||
scaleY = true;
|
||||
to = new ToScaleY();
|
||||
break;
|
||||
}
|
||||
case "shearY": {
|
||||
shearY = true;
|
||||
to = new ToShearY();
|
||||
break;
|
||||
}
|
||||
default: throw new Exception("Invalid transform constraint to property: " + toEntryName);
|
||||
}
|
||||
to.offset = GetFloat(toEntry, "offset", 0) * scale;
|
||||
to.max = GetFloat(toEntry, "max", 1) * scale;
|
||||
to.scale = GetFloat(toEntry, "scale");
|
||||
from.to.Add(to);
|
||||
}
|
||||
}
|
||||
if (from.to.Count != 0) data.properties.Add(from);
|
||||
}
|
||||
}
|
||||
|
||||
data.offsetX = GetFloat(constraintMap, "x", 0);
|
||||
data.offsetY = GetFloat(constraintMap, "y", 0);
|
||||
if (rotate) data.mixRotate = GetFloat(constraintMap, "mixRotate", 1);
|
||||
if (x) data.mixX = GetFloat(constraintMap, "mixX", 1);
|
||||
if (y) data.mixY = GetFloat(constraintMap, "mixY", data.mixX);
|
||||
if (scaleX) data.mixScaleX = GetFloat(constraintMap, "mixScaleX", 1);
|
||||
if (scaleY) data.mixScaleY = GetFloat(constraintMap, "mixScaleY", data.mixScaleX);
|
||||
if (shearY) data.mixShearY = GetFloat(constraintMap, "mixShearY", 1);
|
||||
|
||||
skeletonData.transformConstraints.Add(data);
|
||||
}
|
||||
@ -248,7 +326,7 @@ namespace Spine {
|
||||
// Path constraints.
|
||||
if (root.ContainsKey("path")) {
|
||||
foreach (Dictionary<string, Object> constraintMap in (List<Object>)root["path"]) {
|
||||
PathConstraintData data = new PathConstraintData((string)constraintMap["name"]);
|
||||
var data = new PathConstraintData((string)constraintMap["name"]);
|
||||
data.order = GetInt(constraintMap, "order", 0);
|
||||
data.skinRequired = GetBoolean(constraintMap, "skin", false);
|
||||
|
||||
@ -260,9 +338,9 @@ namespace Spine {
|
||||
}
|
||||
}
|
||||
|
||||
string targetName = (string)constraintMap["target"];
|
||||
data.target = skeletonData.FindSlot(targetName);
|
||||
if (data.target == null) throw new Exception("Path target slot not found: " + targetName);
|
||||
string slotName = (string)constraintMap["slot"];
|
||||
data.slot = skeletonData.FindSlot(slotName);
|
||||
if (data.slot == null) throw new Exception("Path slot not found: " + slotName);
|
||||
|
||||
data.positionMode = (PositionMode)Enum.Parse(typeof(PositionMode), GetString(constraintMap, "positionMode", "percent"), true);
|
||||
data.spacingMode = (SpacingMode)Enum.Parse(typeof(SpacingMode), GetString(constraintMap, "spacingMode", "length"), true);
|
||||
@ -283,7 +361,7 @@ namespace Spine {
|
||||
// Physics constraints.
|
||||
if (root.ContainsKey("physics")) {
|
||||
foreach (Dictionary<string, Object> constraintMap in (List<Object>)root["physics"]) {
|
||||
PhysicsConstraintData data = new PhysicsConstraintData((string)constraintMap["name"]);
|
||||
var data = new PhysicsConstraintData((string)constraintMap["name"]);
|
||||
data.order = GetInt(constraintMap, "order", 0);
|
||||
data.skinRequired = GetBoolean(constraintMap, "skin", false);
|
||||
|
||||
@ -320,7 +398,7 @@ namespace Spine {
|
||||
// Skins.
|
||||
if (root.ContainsKey("skins")) {
|
||||
foreach (Dictionary<string, object> skinMap in (List<object>)root["skins"]) {
|
||||
Skin skin = new Skin((string)skinMap["name"]);
|
||||
var skin = new Skin((string)skinMap["name"]);
|
||||
if (skinMap.ContainsKey("bones")) {
|
||||
foreach (string entryName in (List<Object>)skinMap["bones"]) {
|
||||
BoneData bone = skeletonData.FindBone(entryName);
|
||||
@ -393,7 +471,7 @@ namespace Spine {
|
||||
if (root.ContainsKey("events")) {
|
||||
foreach (KeyValuePair<string, Object> entry in (Dictionary<string, Object>)root["events"]) {
|
||||
Dictionary<string, object> entryMap = (Dictionary<string, Object>)entry.Value;
|
||||
EventData data = new EventData(entry.Key);
|
||||
var data = new EventData(entry.Key);
|
||||
data.Int = GetInt(entryMap, "int", 0);
|
||||
data.Float = GetFloat(entryMap, "float", 0);
|
||||
data.String = GetString(entryMap, "string", string.Empty);
|
||||
@ -553,7 +631,7 @@ namespace Spine {
|
||||
public static Sequence ReadSequence (object sequenceJson) {
|
||||
Dictionary<string, object> map = sequenceJson as Dictionary<string, Object>;
|
||||
if (map == null) return null;
|
||||
Sequence sequence = new Sequence(GetInt(map, "count"));
|
||||
var sequence = new Sequence(GetInt(map, "count"));
|
||||
sequence.start = GetInt(map, "start", 1);
|
||||
sequence.digits = GetInt(map, "digits", 0);
|
||||
sequence.setupIndex = GetInt(map, "setup", 0);
|
||||
@ -573,8 +651,8 @@ namespace Spine {
|
||||
attachment.vertices = vertices;
|
||||
return;
|
||||
}
|
||||
ExposedList<float> weights = new ExposedList<float>(verticesLength * 3 * 3);
|
||||
ExposedList<int> bones = new ExposedList<int>(verticesLength * 3);
|
||||
var weights = new ExposedList<float>(verticesLength * 3 * 3);
|
||||
var bones = new ExposedList<int>(verticesLength * 3);
|
||||
for (int i = 0, n = vertices.Length; i < n;) {
|
||||
int boneCount = (int)vertices[i++];
|
||||
bones.Add(boneCount);
|
||||
@ -598,7 +676,7 @@ namespace Spine {
|
||||
|
||||
private void ReadAnimation (Dictionary<string, Object> map, string name, SkeletonData skeletonData) {
|
||||
float scale = this.scale;
|
||||
ExposedList<Timeline> timelines = new ExposedList<Timeline>();
|
||||
var timelines = new ExposedList<Timeline>();
|
||||
|
||||
// Slot timelines.
|
||||
if (map.ContainsKey("slots")) {
|
||||
@ -611,16 +689,18 @@ namespace Spine {
|
||||
int frames = values.Count;
|
||||
if (frames == 0) continue;
|
||||
string timelineName = (string)timelineEntry.Key;
|
||||
if (timelineName == "attachment") {
|
||||
AttachmentTimeline timeline = new AttachmentTimeline(frames, slotIndex);
|
||||
switch (timelineName) {
|
||||
case "attachment": {
|
||||
var timeline = new AttachmentTimeline(frames, slotIndex);
|
||||
int frame = 0;
|
||||
foreach (Dictionary<string, Object> keyMap in values) {
|
||||
timeline.SetFrame(frame++, GetFloat(keyMap, "time", 0), GetString(keyMap, "name", null));
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
|
||||
} else if (timelineName == "rgba") {
|
||||
RGBATimeline timeline = new RGBATimeline(frames, frames << 2, slotIndex);
|
||||
break;
|
||||
}
|
||||
case "rgba": {
|
||||
var timeline = new RGBATimeline(frames, frames << 2, slotIndex);
|
||||
|
||||
List<object>.Enumerator keyMapEnumerator = values.GetEnumerator();
|
||||
keyMapEnumerator.MoveNext();
|
||||
@ -661,9 +741,10 @@ namespace Spine {
|
||||
keyMap = nextMap;
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
|
||||
} else if (timelineName == "rgb") {
|
||||
RGBTimeline timeline = new RGBTimeline(frames, frames * 3, slotIndex);
|
||||
break;
|
||||
}
|
||||
case "rgb": {
|
||||
var timeline = new RGBTimeline(frames, frames * 3, slotIndex);
|
||||
|
||||
List<object>.Enumerator keyMapEnumerator = values.GetEnumerator();
|
||||
keyMapEnumerator.MoveNext();
|
||||
@ -700,14 +781,16 @@ namespace Spine {
|
||||
keyMap = nextMap;
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
|
||||
} else if (timelineName == "alpha") {
|
||||
break;
|
||||
}
|
||||
case "alpha": {
|
||||
List<object>.Enumerator keyMapEnumerator = values.GetEnumerator();
|
||||
keyMapEnumerator.MoveNext();
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, new AlphaTimeline(frames, frames, slotIndex), 0, 1));
|
||||
|
||||
} else if (timelineName == "rgba2") {
|
||||
RGBA2Timeline timeline = new RGBA2Timeline(frames, frames * 7, slotIndex);
|
||||
break;
|
||||
}
|
||||
case "rgba2": {
|
||||
var timeline = new RGBA2Timeline(frames, frames * 7, slotIndex);
|
||||
|
||||
List<object>.Enumerator keyMapEnumerator = values.GetEnumerator();
|
||||
keyMapEnumerator.MoveNext();
|
||||
@ -762,9 +845,10 @@ namespace Spine {
|
||||
keyMap = nextMap;
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
|
||||
} else if (timelineName == "rgb2") {
|
||||
RGB2Timeline timeline = new RGB2Timeline(frames, frames * 6, slotIndex);
|
||||
break;
|
||||
}
|
||||
case "rgb2": {
|
||||
var timeline = new RGB2Timeline(frames, frames * 6, slotIndex);
|
||||
|
||||
List<object>.Enumerator keyMapEnumerator = values.GetEnumerator();
|
||||
keyMapEnumerator.MoveNext();
|
||||
@ -815,9 +899,11 @@ namespace Spine {
|
||||
keyMap = nextMap;
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
|
||||
} else
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Exception("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -842,33 +928,46 @@ namespace Spine {
|
||||
if (!keyMapEnumerator.MoveNext()) continue;
|
||||
int frames = values.Count;
|
||||
string timelineName = (string)timelineEntry.Key;
|
||||
if (timelineName == "rotate")
|
||||
switch (timelineName) {
|
||||
case "rotate":
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, new RotateTimeline(frames, frames, boneIndex), 0, 1));
|
||||
else if (timelineName == "translate") {
|
||||
TranslateTimeline timeline = new TranslateTimeline(frames, frames << 1, boneIndex);
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, timeline, "x", "y", 0, scale));
|
||||
} else if (timelineName == "translatex") {
|
||||
break;
|
||||
case "translate": {
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, new TranslateTimeline(frames, frames << 1, boneIndex), "x", "y", 0, scale));
|
||||
break;
|
||||
}
|
||||
case "translatex": {
|
||||
timelines
|
||||
.Add(ReadTimeline(ref keyMapEnumerator, new TranslateXTimeline(frames, frames, boneIndex), 0, scale));
|
||||
} else if (timelineName == "translatey") {
|
||||
break;
|
||||
}
|
||||
case "translatey": {
|
||||
timelines
|
||||
.Add(ReadTimeline(ref keyMapEnumerator, new TranslateYTimeline(frames, frames, boneIndex), 0, scale));
|
||||
} else if (timelineName == "scale") {
|
||||
ScaleTimeline timeline = new ScaleTimeline(frames, frames << 1, boneIndex);
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, timeline, "x", "y", 1, 1));
|
||||
} else if (timelineName == "scalex")
|
||||
break;
|
||||
}
|
||||
case "scale": {
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, new ScaleTimeline(frames, frames << 1, boneIndex), "x", "y", 1, 1));
|
||||
break;
|
||||
}
|
||||
case "scalex":
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, new ScaleXTimeline(frames, frames, boneIndex), 1, 1));
|
||||
else if (timelineName == "scaley")
|
||||
break;
|
||||
case "scaley":
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, new ScaleYTimeline(frames, frames, boneIndex), 1, 1));
|
||||
else if (timelineName == "shear") {
|
||||
ShearTimeline timeline = new ShearTimeline(frames, frames << 1, boneIndex);
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, timeline, "x", "y", 0, 1));
|
||||
} else if (timelineName == "shearx")
|
||||
break;
|
||||
case "shear": {
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, new ShearTimeline(frames, frames << 1, boneIndex), "x", "y", 0, 1));
|
||||
break;
|
||||
}
|
||||
case "shearx":
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, new ShearXTimeline(frames, frames, boneIndex), 0, 1));
|
||||
else if (timelineName == "sheary")
|
||||
break;
|
||||
case "sheary":
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, new ShearYTimeline(frames, frames, boneIndex), 0, 1));
|
||||
else if (timelineName == "inherit") {
|
||||
InheritTimeline timeline = new InheritTimeline(frames, boneIndex);
|
||||
break;
|
||||
case "inherit": {
|
||||
var timeline = new InheritTimeline(frames, boneIndex);
|
||||
for (int frame = 0; ; frame++) {
|
||||
Dictionary<string, object> keyMap = (Dictionary<string, Object>)keyMapEnumerator.Current;
|
||||
float time = GetFloat(keyMap, "time", 0);
|
||||
@ -879,8 +978,11 @@ namespace Spine {
|
||||
}
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
} else
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Exception("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -893,7 +995,7 @@ namespace Spine {
|
||||
if (!keyMapEnumerator.MoveNext()) continue;
|
||||
Dictionary<string, object> keyMap = (Dictionary<string, Object>)keyMapEnumerator.Current;
|
||||
IkConstraintData constraint = skeletonData.FindIkConstraint(timelineMap.Key);
|
||||
IkConstraintTimeline timeline = new IkConstraintTimeline(values.Count, values.Count << 1,
|
||||
var timeline = new IkConstraintTimeline(values.Count, values.Count << 1,
|
||||
skeletonData.IkConstraints.IndexOf(constraint));
|
||||
float time = GetFloat(keyMap, "time", 0);
|
||||
float mix = GetFloat(keyMap, "mix", 1), softness = GetFloat(keyMap, "softness", 0) * scale;
|
||||
@ -929,7 +1031,7 @@ namespace Spine {
|
||||
if (!keyMapEnumerator.MoveNext()) continue;
|
||||
Dictionary<string, object> keyMap = (Dictionary<string, Object>)keyMapEnumerator.Current;
|
||||
TransformConstraintData constraint = skeletonData.FindTransformConstraint(timelineMap.Key);
|
||||
TransformConstraintTimeline timeline = new TransformConstraintTimeline(values.Count, values.Count * 6,
|
||||
var timeline = new TransformConstraintTimeline(values.Count, values.Count * 6,
|
||||
skeletonData.TransformConstraints.IndexOf(constraint));
|
||||
float time = GetFloat(keyMap, "time", 0);
|
||||
float mixRotate = GetFloat(keyMap, "mixRotate", 1), mixShearY = GetFloat(keyMap, "mixShearY", 1);
|
||||
@ -982,15 +1084,20 @@ namespace Spine {
|
||||
|
||||
int frames = values.Count;
|
||||
string timelineName = (string)timelineEntry.Key;
|
||||
if (timelineName == "position") {
|
||||
switch (timelineName) {
|
||||
case "position": {
|
||||
CurveTimeline1 timeline = new PathConstraintPositionTimeline(frames, frames, constraintIndex);
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, timeline, 0, constraint.positionMode == PositionMode.Fixed ? scale : 1));
|
||||
} else if (timelineName == "spacing") {
|
||||
break;
|
||||
}
|
||||
case "spacing": {
|
||||
CurveTimeline1 timeline = new PathConstraintSpacingTimeline(frames, frames, constraintIndex);
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, timeline, 0,
|
||||
constraint.spacingMode == SpacingMode.Length || constraint.spacingMode == SpacingMode.Fixed ? scale : 1));
|
||||
} else if (timelineName == "mix") {
|
||||
PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(frames, frames * 3, constraintIndex);
|
||||
break;
|
||||
}
|
||||
case "mix": {
|
||||
var timeline = new PathConstraintMixTimeline(frames, frames * 3, constraintIndex);
|
||||
Dictionary<string, object> keyMap = (Dictionary<string, Object>)keyMapEnumerator.Current;
|
||||
float time = GetFloat(keyMap, "time", 0);
|
||||
float mixRotate = GetFloat(keyMap, "mixRotate", 1);
|
||||
@ -1018,6 +1125,8 @@ namespace Spine {
|
||||
keyMap = nextMap;
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1040,33 +1149,41 @@ namespace Spine {
|
||||
|
||||
int frames = values.Count;
|
||||
string timelineName = (string)timelineEntry.Key;
|
||||
if (timelineName == "reset") {
|
||||
PhysicsConstraintResetTimeline timeline1 = new PhysicsConstraintResetTimeline(frames, index);
|
||||
CurveTimeline1 timeline;
|
||||
switch (timelineName) {
|
||||
case "reset": {
|
||||
var resetTimeline = new PhysicsConstraintResetTimeline(frames, index);
|
||||
int frame = 0;
|
||||
foreach (Dictionary<string, Object> keyMap in values) {
|
||||
timeline1.SetFrame(frame++, GetFloat(keyMap, "time", 0));
|
||||
resetTimeline.SetFrame(frame++, GetFloat(keyMap, "time", 0));
|
||||
}
|
||||
timelines.Add(timeline1);
|
||||
timelines.Add(resetTimeline);
|
||||
continue;
|
||||
}
|
||||
|
||||
CurveTimeline1 timeline;
|
||||
if (timelineName == "inertia")
|
||||
case "inertia":
|
||||
timeline = new PhysicsConstraintInertiaTimeline(frames, frames, index);
|
||||
else if (timelineName == "strength")
|
||||
break;
|
||||
case "strength":
|
||||
timeline = new PhysicsConstraintStrengthTimeline(frames, frames, index);
|
||||
else if (timelineName == "damping")
|
||||
break;
|
||||
case "damping":
|
||||
timeline = new PhysicsConstraintDampingTimeline(frames, frames, index);
|
||||
else if (timelineName == "mass")
|
||||
break;
|
||||
case "mass":
|
||||
timeline = new PhysicsConstraintMassTimeline(frames, frames, index);
|
||||
else if (timelineName == "wind")
|
||||
break;
|
||||
case "wind":
|
||||
timeline = new PhysicsConstraintWindTimeline(frames, frames, index);
|
||||
else if (timelineName == "gravity")
|
||||
break;
|
||||
case "gravity":
|
||||
timeline = new PhysicsConstraintGravityTimeline(frames, frames, index);
|
||||
else if (timelineName == "mix") //
|
||||
break;
|
||||
case "mix":
|
||||
timeline = new PhysicsConstraintMixTimeline(frames, frames, index);
|
||||
else
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, timeline, 0, 1));
|
||||
}
|
||||
}
|
||||
@ -1089,13 +1206,14 @@ namespace Spine {
|
||||
Dictionary<string, object> keyMap = (Dictionary<string, Object>)keyMapEnumerator.Current;
|
||||
int frames = values.Count;
|
||||
string timelineName = timelineMap.Key;
|
||||
if (timelineName == "deform") {
|
||||
switch (timelineName) {
|
||||
case "deform": {
|
||||
VertexAttachment vertexAttachment = (VertexAttachment)attachment;
|
||||
bool weighted = vertexAttachment.bones != null;
|
||||
float[] vertices = vertexAttachment.vertices;
|
||||
int deformLength = weighted ? (vertices.Length / 3) << 1 : vertices.Length;
|
||||
|
||||
DeformTimeline timeline = new DeformTimeline(frames, frames, slot.Index, vertexAttachment);
|
||||
var timeline = new DeformTimeline(frames, frames, slot.Index, vertexAttachment);
|
||||
float time = GetFloat(keyMap, "time", 0);
|
||||
for (int frame = 0, bezier = 0; ; frame++) {
|
||||
float[] deform;
|
||||
@ -1132,8 +1250,10 @@ namespace Spine {
|
||||
keyMap = nextMap;
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
} else if (timelineName == "sequence") {
|
||||
SequenceTimeline timeline = new SequenceTimeline(frames, slot.index, attachment);
|
||||
break;
|
||||
}
|
||||
case "sequence": {
|
||||
var timeline = new SequenceTimeline(frames, slot.index, attachment);
|
||||
float lastDelay = 0;
|
||||
for (int frame = 0; keyMap != null; keyMap = keyMapEnumerator.MoveNext() ?
|
||||
(Dictionary<string, Object>)keyMapEnumerator.Current : null, frame++) {
|
||||
@ -1146,6 +1266,8 @@ namespace Spine {
|
||||
lastDelay = delay;
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1156,7 +1278,7 @@ namespace Spine {
|
||||
// Draw order timeline.
|
||||
if (map.ContainsKey("drawOrder")) {
|
||||
List<object> values = (List<Object>)map["drawOrder"];
|
||||
DrawOrderTimeline timeline = new DrawOrderTimeline(values.Count);
|
||||
var timeline = new DrawOrderTimeline(values.Count);
|
||||
int slotCount = skeletonData.slots.Count;
|
||||
int frame = 0;
|
||||
foreach (Dictionary<string, Object> keyMap in values) {
|
||||
@ -1193,12 +1315,12 @@ namespace Spine {
|
||||
// Event timeline.
|
||||
if (map.ContainsKey("events")) {
|
||||
List<object> eventsMap = (List<Object>)map["events"];
|
||||
EventTimeline timeline = new EventTimeline(eventsMap.Count);
|
||||
var timeline = new EventTimeline(eventsMap.Count);
|
||||
int frame = 0;
|
||||
foreach (Dictionary<string, Object> keyMap in eventsMap) {
|
||||
EventData eventData = skeletonData.FindEvent((string)keyMap["name"]);
|
||||
if (eventData == null) throw new Exception("Event not found: " + keyMap["name"]);
|
||||
Event e = new Event(GetFloat(keyMap, "time", 0), eventData) {
|
||||
var e = new Event(GetFloat(keyMap, "time", 0), eventData) {
|
||||
intValue = GetInt(keyMap, "int", eventData.Int),
|
||||
floatValue = GetFloat(keyMap, "float", eventData.Float),
|
||||
stringValue = GetString(keyMap, "string", eventData.String)
|
||||
@ -1319,6 +1441,11 @@ namespace Spine {
|
||||
return (float)map[name];
|
||||
}
|
||||
|
||||
static float GetFloat (Dictionary<string, Object> map, string name) {
|
||||
if (!map.ContainsKey(name)) throw new ArgumentException("Named value not found: " + name);
|
||||
return (float)map[name];
|
||||
}
|
||||
|
||||
static int GetInt (Dictionary<string, Object> map, string name, int defaultValue) {
|
||||
if (!map.ContainsKey(name)) return defaultValue;
|
||||
return (int)(float)map[name];
|
||||
|
||||
@ -30,19 +30,21 @@
|
||||
using System;
|
||||
|
||||
namespace Spine {
|
||||
using FromProperty = TransformConstraintData.FromProperty;
|
||||
using Physics = Skeleton.Physics;
|
||||
using ToProperty = TransformConstraintData.ToProperty;
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Stores the current pose for a transform constraint. A transform constraint adjusts the world transform of the constrained
|
||||
/// bones to match that of the target bone.</para>
|
||||
/// bones to match that of the source bone.</para>
|
||||
/// <para>
|
||||
/// See <a href="http://esotericsoftware.com/spine-transform-constraints">Transform constraints</a> in the Spine User Guide.</para>
|
||||
/// </summary>
|
||||
public class TransformConstraint : IUpdatable {
|
||||
internal readonly TransformConstraintData data;
|
||||
internal readonly ExposedList<Bone> bones;
|
||||
internal Bone target;
|
||||
internal Bone source;
|
||||
internal float mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY;
|
||||
|
||||
internal bool active;
|
||||
@ -56,7 +58,7 @@ namespace Spine {
|
||||
foreach (BoneData boneData in data.bones)
|
||||
bones.Add(skeleton.bones.Items[boneData.index]);
|
||||
|
||||
target = skeleton.bones.Items[data.target.index];
|
||||
source = skeleton.bones.Items[data.source.index];
|
||||
|
||||
mixRotate = data.mixRotate;
|
||||
mixX = data.mixX;
|
||||
@ -90,205 +92,44 @@ namespace Spine {
|
||||
|
||||
public void Update (Physics physics) {
|
||||
if (mixRotate == 0 && mixX == 0 && mixY == 0 && mixScaleX == 0 && mixScaleY == 0 && mixShearY == 0) return;
|
||||
if (data.local) {
|
||||
if (data.relative)
|
||||
ApplyRelativeLocal();
|
||||
|
||||
TransformConstraintData data = this.data;
|
||||
bool localFrom = data.localSource, localTarget = data.localTarget, additive = data.additive, clamp = data.clamp;
|
||||
Bone source = this.source;
|
||||
FromProperty[] fromItems = data.properties.Items;
|
||||
int fn = data.properties.Count;
|
||||
Bone[] bones = this.bones.Items;
|
||||
for (int i = 0, n = this.bones.Count; i < n; i++) {
|
||||
var bone = bones[i];
|
||||
for (int f = 0; f < fn; f++) {
|
||||
FromProperty from = fromItems[f];
|
||||
float value = from.Value(data, source, localFrom) - from.offset;
|
||||
ToProperty[] toItems = from.to.Items;
|
||||
for (int t = 0, tn = from.to.Count; t < tn; t++) {
|
||||
var to = (ToProperty)toItems[t];
|
||||
if (to.Mix(this) != 0) {
|
||||
float clamped = to.offset + value * to.scale;
|
||||
if (clamp) {
|
||||
if (to.offset < to.max)
|
||||
clamped = MathUtils.Clamp(clamped, to.offset, to.max);
|
||||
else
|
||||
clamped = MathUtils.Clamp(clamped, to.max, to.offset);
|
||||
}
|
||||
to.Apply(this, bone, clamped, localTarget, additive);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (localTarget)
|
||||
bone.Update(Skeleton.Physics.None); // note: reference implementation passes null, ignored parameter
|
||||
else
|
||||
ApplyAbsoluteLocal();
|
||||
} else {
|
||||
if (data.relative)
|
||||
ApplyRelativeWorld();
|
||||
else
|
||||
ApplyAbsoluteWorld();
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyAbsoluteWorld () {
|
||||
float mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX,
|
||||
mixScaleY = this.mixScaleY, mixShearY = this.mixShearY;
|
||||
bool translate = mixX != 0 || mixY != 0;
|
||||
|
||||
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;
|
||||
|
||||
Bone[] bones = this.bones.Items;
|
||||
for (int i = 0, n = this.bones.Count; i < n; i++) {
|
||||
Bone bone = bones[i];
|
||||
|
||||
if (mixRotate != 0) {
|
||||
float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
|
||||
float r = MathUtils.Atan2(tc, ta) - MathUtils.Atan2(c, a) + offsetRotation;
|
||||
if (r > MathUtils.PI)
|
||||
r -= MathUtils.PI2;
|
||||
else if (r < -MathUtils.PI) //
|
||||
r += MathUtils.PI2;
|
||||
r *= mixRotate;
|
||||
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;
|
||||
}
|
||||
|
||||
if (translate) {
|
||||
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) * mixX;
|
||||
bone.worldY += (ty - bone.worldY) * mixY;
|
||||
}
|
||||
|
||||
if (mixScaleX != 0) {
|
||||
float s = (float)Math.Sqrt(bone.a * bone.a + bone.c * bone.c);
|
||||
if (s != 0) s = (s + ((float)Math.Sqrt(ta * ta + tc * tc) - s + data.offsetScaleX) * mixScaleX) / s;
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
}
|
||||
if (mixScaleY != 0) {
|
||||
float s = (float)Math.Sqrt(bone.b * bone.b + bone.d * bone.d);
|
||||
if (s != 0) s = (s + ((float)Math.Sqrt(tb * tb + td * td) - s + data.offsetScaleY) * mixScaleY) / s;
|
||||
bone.b *= s;
|
||||
bone.d *= s;
|
||||
}
|
||||
|
||||
if (mixShearY > 0) {
|
||||
float b = bone.b, d = bone.d;
|
||||
float by = MathUtils.Atan2(d, b);
|
||||
float r = MathUtils.Atan2(td, tb) - MathUtils.Atan2(tc, ta) - (by - MathUtils.Atan2(bone.c, bone.a));
|
||||
if (r > MathUtils.PI)
|
||||
r -= MathUtils.PI2;
|
||||
else if (r < -MathUtils.PI) //
|
||||
r += MathUtils.PI2;
|
||||
r = by + (r + offsetShearY) * mixShearY;
|
||||
float s = (float)Math.Sqrt(b * b + d * d);
|
||||
bone.b = MathUtils.Cos(r) * s;
|
||||
bone.d = MathUtils.Sin(r) * s;
|
||||
}
|
||||
|
||||
bone.UpdateAppliedTransform();
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyRelativeWorld () {
|
||||
float mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX,
|
||||
mixScaleY = this.mixScaleY, mixShearY = this.mixShearY;
|
||||
bool translate = mixX != 0 || mixY != 0;
|
||||
|
||||
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;
|
||||
|
||||
Bone[] bones = this.bones.Items;
|
||||
for (int i = 0, n = this.bones.Count; i < n; i++) {
|
||||
Bone bone = bones[i];
|
||||
|
||||
if (mixRotate != 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 *= mixRotate;
|
||||
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;
|
||||
}
|
||||
|
||||
if (translate) {
|
||||
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 * mixX;
|
||||
bone.worldY += ty * mixY;
|
||||
}
|
||||
|
||||
if (mixScaleX != 0) {
|
||||
float s = ((float)Math.Sqrt(ta * ta + tc * tc) - 1 + data.offsetScaleX) * mixScaleX + 1;
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
}
|
||||
if (mixScaleY != 0) {
|
||||
float s = ((float)Math.Sqrt(tb * tb + td * td) - 1 + data.offsetScaleY) * mixScaleY + 1;
|
||||
bone.b *= s;
|
||||
bone.d *= s;
|
||||
}
|
||||
|
||||
if (mixShearY > 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) * mixShearY;
|
||||
float s = (float)Math.Sqrt(b * b + d * d);
|
||||
bone.b = MathUtils.Cos(r) * s;
|
||||
bone.d = MathUtils.Sin(r) * s;
|
||||
}
|
||||
|
||||
bone.UpdateAppliedTransform();
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyAbsoluteLocal () {
|
||||
float mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX,
|
||||
mixScaleY = this.mixScaleY, mixShearY = this.mixShearY;
|
||||
|
||||
Bone target = this.target;
|
||||
|
||||
Bone[] bones = this.bones.Items;
|
||||
for (int i = 0, n = this.bones.Count; i < n; i++) {
|
||||
Bone bone = bones[i];
|
||||
|
||||
float rotation = bone.arotation;
|
||||
if (mixRotate != 0) rotation += (target.arotation - rotation + data.offsetRotation) * mixRotate;
|
||||
|
||||
float x = bone.ax, y = bone.ay;
|
||||
x += (target.ax - x + data.offsetX) * mixX;
|
||||
y += (target.ay - y + data.offsetY) * mixY;
|
||||
|
||||
float scaleX = bone.ascaleX, scaleY = bone.ascaleY;
|
||||
if (mixScaleX != 0 && scaleX != 0)
|
||||
scaleX = (scaleX + (target.ascaleX - scaleX + data.offsetScaleX) * mixScaleX) / scaleX;
|
||||
if (mixScaleY != 0 && scaleY != 0)
|
||||
scaleY = (scaleY + (target.ascaleY - scaleY + data.offsetScaleY) * mixScaleY) / scaleY;
|
||||
|
||||
float shearY = bone.ashearY;
|
||||
if (mixShearY != 0) shearY += (target.ashearY - shearY + data.offsetShearY) * mixShearY;
|
||||
|
||||
bone.UpdateWorldTransform(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY);
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyRelativeLocal () {
|
||||
float mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX,
|
||||
mixScaleY = this.mixScaleY, mixShearY = this.mixShearY;
|
||||
|
||||
Bone target = this.target;
|
||||
|
||||
Bone[] bones = this.bones.Items;
|
||||
for (int i = 0, n = this.bones.Count; i < n; i++) {
|
||||
Bone bone = bones[i];
|
||||
|
||||
float rotation = bone.arotation + (target.arotation + data.offsetRotation) * mixRotate;
|
||||
float x = bone.ax + (target.ax + data.offsetX) * mixX;
|
||||
float y = bone.ay + (target.ay + data.offsetY) * mixY;
|
||||
float scaleX = bone.ascaleX * (((target.ascaleX - 1 + data.offsetScaleX) * mixScaleX) + 1);
|
||||
float scaleY = bone.ascaleY * (((target.ascaleY - 1 + data.offsetScaleY) * mixScaleY) + 1);
|
||||
float shearY = bone.ashearY + (target.ashearY + data.offsetShearY) * mixShearY;
|
||||
|
||||
bone.UpdateWorldTransform(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY);
|
||||
bone.UpdateAppliedTransform();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The bones that will be modified by this transform constraint.</summary>
|
||||
public ExposedList<Bone> Bones { get { return bones; } }
|
||||
/// <summary>The target bone whose world transform will be copied to the constrained bones.</summary>
|
||||
public Bone Target { get { return target; } set { target = value; } }
|
||||
/// <summary>The bone whose world transform will be copied to the constrained bones.</summary>
|
||||
public Bone Source { get { return source; } set { source = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained rotation.</summary>
|
||||
public float MixRotate { get { return mixRotate; } set { mixRotate = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained translation X.</summary>
|
||||
|
||||
@ -31,14 +31,31 @@ using System;
|
||||
|
||||
namespace Spine {
|
||||
public class TransformConstraintData : ConstraintData {
|
||||
internal ExposedList<BoneData> bones = new ExposedList<BoneData>();
|
||||
internal BoneData target;
|
||||
internal float mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY;
|
||||
internal float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY;
|
||||
internal bool relative, local;
|
||||
internal readonly ExposedList<BoneData> bones = new ExposedList<BoneData>();
|
||||
internal BoneData source;
|
||||
internal float offsetX, offsetY, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY;
|
||||
internal bool localSource, localTarget, additive, clamp;
|
||||
internal readonly ExposedList<FromProperty> properties = new ExposedList<FromProperty>();
|
||||
|
||||
public TransformConstraintData (string name) : base(name) {
|
||||
}
|
||||
|
||||
public ExposedList<BoneData> Bones { get { return bones; } }
|
||||
public BoneData Target { get { return target; } set { target = value; } }
|
||||
|
||||
/// <summary>The bone whose world transform will be copied to the constrained bones.</summary>
|
||||
public BoneData Source {
|
||||
get { return source; }
|
||||
set {
|
||||
if (source == null) throw new ArgumentNullException("Source", "source cannot be null.");
|
||||
source = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The mapping of transform properties to other transform properties.</summary>
|
||||
public ExposedList<FromProperty> Properties {
|
||||
get { return properties; }
|
||||
}
|
||||
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained rotation.</summary>
|
||||
public float MixRotate { get { return mixRotate; } set { mixRotate = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained translation X.</summary>
|
||||
@ -51,18 +68,222 @@ namespace Spine {
|
||||
public float MixScaleY { get { return mixScaleY; } set { mixScaleY = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained shear Y.</summary>
|
||||
public float MixShearY { get { return mixShearY; } set { mixShearY = value; } }
|
||||
|
||||
public float OffsetRotation { get { return offsetRotation; } set { offsetRotation = value; } }
|
||||
/// <summary>An offset added to the constrained bone X translation.</summary>
|
||||
public float OffsetX { get { return offsetX; } set { offsetX = value; } }
|
||||
/// <summary>An offset added to the constrained bone Y translation.</summary>
|
||||
public float OffsetY { get { return offsetY; } set { offsetY = value; } }
|
||||
public float OffsetScaleX { get { return offsetScaleX; } set { offsetScaleX = value; } }
|
||||
public float OffsetScaleY { get { return offsetScaleY; } set { offsetScaleY = value; } }
|
||||
public float OffsetShearY { get { return offsetShearY; } set { offsetShearY = value; } }
|
||||
/// <summary>Reads the source bone's local transform instead of its world transform.</summary>
|
||||
public bool LocalSource { get { return localSource; } set { localSource = value; } }
|
||||
/// <summary>Sets the constrained bones' local transforms instead of their world transforms.</summary>
|
||||
public bool LocalTarget { get { return localTarget; } set { localTarget = value; } }
|
||||
/// <summary>Adds the source bone transform to the constrained bones instead of setting it absolutely.</summary>
|
||||
public bool Additive { get { return additive; } set { additive = value; } }
|
||||
/// <summary>Prevents constrained bones from exceeding the ranged defined by <see cref="ToProperty.offset"/> and
|
||||
/// <see cref="ToProperty.max"/>.</summary>
|
||||
public bool Clamp { get { return clamp; } set { clamp = value; } }
|
||||
|
||||
public bool Relative { get { return relative; } set { relative = value; } }
|
||||
public bool Local { get { return local; } set { local = value; } }
|
||||
/// <summary>Source property for a <see cref="TransformConstraint"/>.</summary>
|
||||
abstract public class FromProperty {
|
||||
/// <summary>The value of this property that corresponds to <see cref="ToProperty.offset"/>.</summary>
|
||||
public float offset;
|
||||
|
||||
public TransformConstraintData (string name) : base(name) {
|
||||
/// <summary>Constrained properties.</summary>
|
||||
public readonly ExposedList<ToProperty> to = new ExposedList<ToProperty>();
|
||||
|
||||
/// <summary>Reads this property from the specified bone.</summary>
|
||||
abstract public float Value (TransformConstraintData data, Bone source, bool local);
|
||||
}
|
||||
|
||||
///<summary>Constrained property for a <see cref="TransformConstraint"/>.</summary>
|
||||
abstract public class ToProperty {
|
||||
/// <summary>The value of this property that corresponds to <see cref="FromProperty.offset"/>.</summary>
|
||||
public float offset;
|
||||
|
||||
/// <summary>The maximum value of this property when <see cref="TransformConstraintData.clamp"/> clamped.</summary>
|
||||
public float max;
|
||||
|
||||
/// <summary>The scale of the <see cref="FromProperty"/> value in relation to this property.</summary>
|
||||
public float scale;
|
||||
|
||||
/// <summary>Reads the mix for this property from the specified constraint.</summary>
|
||||
public abstract float Mix (TransformConstraint constraint);
|
||||
|
||||
/// <summary>Applies the value to this property.</summary>
|
||||
public abstract void Apply (TransformConstraint constraint, Bone bone, float value, bool local, bool additive);
|
||||
}
|
||||
|
||||
public class FromRotate : FromProperty {
|
||||
public override float Value (TransformConstraintData data, Bone source, bool local) {
|
||||
return local ? source.arotation : MathUtils.Atan2(source.c, source.a) * MathUtils.RadDeg;
|
||||
}
|
||||
}
|
||||
|
||||
public class ToRotate : ToProperty {
|
||||
public override float Mix (TransformConstraint constraint) {
|
||||
return constraint.mixRotate;
|
||||
}
|
||||
|
||||
public override void Apply (TransformConstraint constraint, Bone bone, float value, bool local, bool additive) {
|
||||
if (local) {
|
||||
if (!additive) value -= bone.arotation;
|
||||
bone.arotation += value * constraint.mixRotate;
|
||||
} else {
|
||||
float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
|
||||
value *= MathUtils.DegRad;
|
||||
if (!additive) value -= MathUtils.Atan2(c, a);
|
||||
if (value > MathUtils.PI)
|
||||
value -= MathUtils.PI2;
|
||||
else if (value < -MathUtils.PI) //
|
||||
value += MathUtils.PI2;
|
||||
value *= constraint.mixRotate;
|
||||
float cos = MathUtils.Cos(value), sin = MathUtils.Sin(value);
|
||||
bone.a = cos * a - sin * c;
|
||||
bone.b = cos * b - sin * d;
|
||||
bone.c = sin * a + cos * c;
|
||||
bone.d = sin * b + cos * d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FromX : FromProperty {
|
||||
public override float Value (TransformConstraintData data, Bone source, bool local) {
|
||||
return local ? source.ax + data.offsetX : data.offsetX * source.a + data.offsetY * source.b + source.worldX;
|
||||
}
|
||||
}
|
||||
|
||||
public class ToX : ToProperty {
|
||||
public override float Mix (TransformConstraint constraint) {
|
||||
return constraint.mixX;
|
||||
}
|
||||
|
||||
public override void Apply (TransformConstraint constraint, Bone bone, float value, bool local, bool additive) {
|
||||
if (local) {
|
||||
if (!additive) value -= bone.ax;
|
||||
bone.ax += value * constraint.mixX;
|
||||
} else {
|
||||
if (!additive) value -= bone.worldX;
|
||||
bone.worldX += value * constraint.mixX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FromY : FromProperty {
|
||||
public override float Value (TransformConstraintData data, Bone source, bool local) {
|
||||
return local ? source.ay + data.offsetY : data.offsetX * source.c + data.offsetY * source.d + source.worldY;
|
||||
}
|
||||
}
|
||||
|
||||
public class ToY : ToProperty {
|
||||
public override float Mix (TransformConstraint constraint) {
|
||||
return constraint.mixY;
|
||||
}
|
||||
|
||||
public override void Apply (TransformConstraint constraint, Bone bone, float value, bool local, bool additive) {
|
||||
if (local) {
|
||||
if (!additive) value -= bone.ay;
|
||||
bone.ay += value * constraint.mixY;
|
||||
} else {
|
||||
if (!additive) value -= bone.worldY;
|
||||
bone.worldY += value * constraint.mixY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FromScaleX : FromProperty {
|
||||
public override float Value (TransformConstraintData data, Bone source, bool local) {
|
||||
return local ? source.ascaleX : (float)Math.Sqrt(source.a * source.a + source.c * source.c);
|
||||
}
|
||||
}
|
||||
|
||||
public class ToScaleX : ToProperty {
|
||||
public override float Mix (TransformConstraint constraint) {
|
||||
return constraint.mixScaleX;
|
||||
}
|
||||
|
||||
public override void Apply (TransformConstraint constraint, Bone bone, float value, bool local, bool additive) {
|
||||
if (local) {
|
||||
if (additive)
|
||||
bone.ascaleX *= 1 + ((value - 1) * constraint.mixScaleX);
|
||||
else if (bone.ascaleX != 0) //
|
||||
bone.ascaleX = 1 + (value / bone.ascaleX - 1) * constraint.mixScaleX;
|
||||
} else {
|
||||
float s;
|
||||
if (additive)
|
||||
s = 1 + (value - 1) * constraint.mixScaleX;
|
||||
else {
|
||||
s = (float)Math.Sqrt(bone.a * bone.a + bone.c * bone.c);
|
||||
if (s != 0) s = 1 + (value / s - 1) * constraint.mixScaleX;
|
||||
}
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FromScaleY : FromProperty {
|
||||
public override float Value (TransformConstraintData data, Bone source, bool local) {
|
||||
return local ? source.ascaleY : (float)Math.Sqrt(source.b * source.b + source.d * source.d);
|
||||
}
|
||||
}
|
||||
|
||||
public class ToScaleY : ToProperty {
|
||||
public override float Mix (TransformConstraint constraint) {
|
||||
return constraint.mixScaleY;
|
||||
}
|
||||
|
||||
public override void Apply (TransformConstraint constraint, Bone bone, float value, bool local, bool additive) {
|
||||
if (local) {
|
||||
if (additive)
|
||||
bone.ascaleY *= 1 + ((value - 1) * constraint.mixScaleY);
|
||||
else if (bone.ascaleY != 0) //
|
||||
bone.ascaleY = 1 + (value / bone.ascaleY - 1) * constraint.mixScaleY;
|
||||
} else {
|
||||
float s;
|
||||
if (additive)
|
||||
s = 1 + (value - 1) * constraint.mixScaleY;
|
||||
else {
|
||||
s = (float)Math.Sqrt(bone.b * bone.b + bone.d * bone.d);
|
||||
if (s != 0) s = 1 + (value / s - 1) * constraint.mixScaleY;
|
||||
}
|
||||
bone.b *= s;
|
||||
bone.d *= s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class FromShearY : FromProperty {
|
||||
public override float Value (TransformConstraintData data, Bone source, bool local) {
|
||||
return local ? source.ashearY : (MathUtils.Atan2(source.d, source.b) - MathUtils.Atan2(source.c, source.a)) * MathUtils.RadDeg - 90;
|
||||
}
|
||||
}
|
||||
|
||||
public class ToShearY : ToProperty {
|
||||
public override float Mix (TransformConstraint constraint) {
|
||||
return constraint.mixShearY;
|
||||
}
|
||||
|
||||
public override void Apply (TransformConstraint constraint, Bone bone, float value, bool local, bool additive) {
|
||||
if (local) {
|
||||
if (!additive) value -= bone.ashearY;
|
||||
bone.ashearY += value * constraint.mixShearY;
|
||||
} else {
|
||||
float b = bone.b, d = bone.d, by = MathUtils.Atan2(d, b);
|
||||
value = (value + 90) * MathUtils.DegRad;
|
||||
if (additive)
|
||||
value -= MathUtils.PI / 2;
|
||||
else {
|
||||
value -= by - MathUtils.Atan2(bone.c, bone.a);
|
||||
if (value > MathUtils.PI)
|
||||
value -= MathUtils.PI2;
|
||||
else if (value < -MathUtils.PI) //
|
||||
value += MathUtils.PI2;
|
||||
}
|
||||
value = by + value * constraint.mixShearY;
|
||||
float s = (float)Math.Sqrt(b * b + d * d);
|
||||
bone.b = MathUtils.Cos(value) * s;
|
||||
bone.d = MathUtils.Sin(value) * s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -397,8 +397,8 @@ namespace Spine.Unity.Editor {
|
||||
// Transform Constraints
|
||||
handleColor = SpineHandles.TransformContraintColor;
|
||||
foreach (TransformConstraint tc in skeleton.TransformConstraints) {
|
||||
Bone targetBone = tc.Target;
|
||||
targetPos = targetBone.GetWorldPosition(transform, skeletonRenderScale, offset);
|
||||
Bone sourceBone = tc.Source;
|
||||
targetPos = sourceBone.GetWorldPosition(transform, skeletonRenderScale, offset);
|
||||
|
||||
if (tc.MixX > 0 || tc.MixY > 0) {
|
||||
if ((tc.MixX > 0 && tc.MixX != 1f) ||
|
||||
@ -411,7 +411,7 @@ namespace Spine.Unity.Editor {
|
||||
}
|
||||
SpineHandles.DrawBoneCircle(targetPos, handleColor, normal, 1.3f * skeletonRenderScale);
|
||||
Handles.color = handleColor;
|
||||
SpineHandles.DrawCrosshairs(targetPos, 0.2f, targetBone.A, targetBone.B, targetBone.C, targetBone.D, transform, skeletonRenderScale);
|
||||
SpineHandles.DrawCrosshairs(targetPos, 0.2f, sourceBone.A, sourceBone.B, sourceBone.C, sourceBone.D, transform, skeletonRenderScale);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -415,7 +415,7 @@ namespace Spine.Unity.Editor {
|
||||
foreach (TransformConstraint c in skeleton.TransformConstraints) {
|
||||
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(c.Data.Name, Icons.constraintTransform));
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
FalseDropDown("Goal", c.Data.Target.Name, Icons.bone);
|
||||
FalseDropDown("Source", c.Data.Source.Name, Icons.bone);
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
@ -469,7 +469,7 @@ namespace Spine.Unity.Editor {
|
||||
foreach (PathConstraint c in skeleton.PathConstraints) {
|
||||
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(c.Data.Name, Icons.constraintPath));
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
FalseDropDown("Path Slot", c.Data.Target.Name, Icons.slot);
|
||||
FalseDropDown("Path Slot", c.Data.Slot.Name, Icons.slot);
|
||||
Attachment activeAttachment = c.Target.Attachment;
|
||||
FalseDropDown("Active Path", activeAttachment != null ? activeAttachment.Name : "<None>", activeAttachment is PathAttachment ? Icons.path : null);
|
||||
EditorGUILayout.LabelField("PositionMode." + c.Data.PositionMode);
|
||||
|
||||
@ -446,8 +446,8 @@ namespace Spine.Unity {
|
||||
if (useLastConstraintPos)
|
||||
constraintPos = transformConstraintLastPos[GetConstraintLastPosIndex(constraintIndex)];
|
||||
else {
|
||||
Bone targetBone = constraint.Target;
|
||||
constraintPos = new Vector2(targetBone.X, targetBone.Y);
|
||||
Bone sourceBone = constraint.Source;
|
||||
constraintPos = new Vector2(sourceBone.X, sourceBone.Y);
|
||||
}
|
||||
pos = new Vector2(
|
||||
pos.x * invMixXY.x + constraintPos.x * mixXY.x,
|
||||
@ -465,8 +465,8 @@ namespace Spine.Unity {
|
||||
if (useLastConstraintRotation)
|
||||
constraintRotation = transformConstraintLastRotation[GetConstraintLastPosIndex(constraintIndex)];
|
||||
else {
|
||||
Bone targetBone = constraint.Target;
|
||||
constraintRotation = targetBone.Rotation;
|
||||
Bone sourceBone = constraint.Source;
|
||||
constraintRotation = sourceBone.Rotation;
|
||||
}
|
||||
rotation = rotation * invMixRotate + constraintRotation * mixRotate;
|
||||
}
|
||||
@ -474,16 +474,16 @@ namespace Spine.Unity {
|
||||
void UpdateLastConstraintPos (TransformConstraint[] transformConstraintsItems) {
|
||||
foreach (int constraintIndex in this.transformConstraintIndices) {
|
||||
TransformConstraint constraint = transformConstraintsItems[constraintIndex];
|
||||
Bone targetBone = constraint.Target;
|
||||
transformConstraintLastPos[GetConstraintLastPosIndex(constraintIndex)] = new Vector2(targetBone.X, targetBone.Y);
|
||||
Bone sourceBone = constraint.Source;
|
||||
transformConstraintLastPos[GetConstraintLastPosIndex(constraintIndex)] = new Vector2(sourceBone.X, sourceBone.Y);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateLastConstraintRotation (TransformConstraint[] transformConstraintsItems) {
|
||||
foreach (int constraintIndex in this.transformConstraintIndices) {
|
||||
TransformConstraint constraint = transformConstraintsItems[constraintIndex];
|
||||
Bone targetBone = constraint.Target;
|
||||
transformConstraintLastRotation[GetConstraintLastPosIndex(constraintIndex)] = targetBone.Rotation;
|
||||
Bone sourceBone = constraint.Source;
|
||||
transformConstraintLastRotation[GetConstraintLastPosIndex(constraintIndex)] = sourceBone.Rotation;
|
||||
}
|
||||
}
|
||||
|
||||
@ -524,10 +524,10 @@ namespace Spine.Unity {
|
||||
TransformConstraint constraint = constraintsItems[i];
|
||||
if (constraint.Bones.Contains(rootMotionBone)) {
|
||||
transformConstraintIndices.Add(i);
|
||||
Bone targetBone = constraint.Target;
|
||||
Vector2 constraintPos = new Vector2(targetBone.X, targetBone.Y);
|
||||
Bone sourceBone = constraint.Source;
|
||||
Vector2 constraintPos = new Vector2(sourceBone.X, sourceBone.Y);
|
||||
transformConstraintLastPos.Add(constraintPos);
|
||||
transformConstraintLastRotation.Add(targetBone.Rotation);
|
||||
transformConstraintLastRotation.Add(sourceBone.Rotation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -360,7 +360,7 @@ namespace Spine.Unity {
|
||||
|
||||
ExposedList<TransformConstraint> transformConstraints = skeleton.TransformConstraints;
|
||||
for (int i = 0, n = transformConstraints.Count; i < n; i++)
|
||||
constraintTargets.Add(transformConstraints.Items[i].Target);
|
||||
constraintTargets.Add(transformConstraints.Items[i].Source);
|
||||
|
||||
List<SkeletonUtilityBone> boneComponents = this.boneComponents;
|
||||
for (int i = 0, n = boneComponents.Count; i < n; i++) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user