mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-20 00:36:43 +08:00
[csharp] Porting of commits dbd90ca, da1b280, 10d5a91 and e14db0e (includes 4.0 format changes). Fixed errors in color parsing introduced by previous porting 4.0 commit.
* Added separate X and Y for transform constraint translate and scale mix. * Renamed `xxxMix` to `mixXxx` to avoid names like `scaleXMix`. * Added separate X and Y sliders for path constraint translate mix. * Added a proportional spacing mode to path constraints. * Fixed path constraint when a parent bone of the path is scaled.
This commit is contained in:
parent
e14db0ec2c
commit
7ef2fc96db
@ -199,7 +199,7 @@ namespace Spine {
|
||||
}
|
||||
|
||||
internal enum Property {
|
||||
Rotate=0, TranslateX, TranslateY, ScaleX, ScaleY, ShearX, ShearY, //
|
||||
Rotate=0, X, Y, ScaleX, ScaleY, ShearX, ShearY, //
|
||||
RGB, Alpha, RGB2, //
|
||||
Attachment, Deform, //
|
||||
Event, DrawOrder, //
|
||||
@ -333,7 +333,7 @@ namespace Spine {
|
||||
/// <param name="bezier">The ordinal of this Bezier curve for this timeline, between 0 and <code>bezierCount - 1</code> (specified
|
||||
/// in the constructor), inclusive.</param>
|
||||
/// <param name="frame">Between 0 and <code>frameCount - 1</code>, inclusive.</param>
|
||||
/// <param name="value">The index of the value for this frame that this curve is used for.</param>
|
||||
/// <param name="value">The index of the value for the frame this curve is used for.</param>
|
||||
/// <param name="time1">The time for the first key.</param>
|
||||
/// <param name="value1">The value for the first key.</param>
|
||||
/// <param name="cx1">The time for the first Bezier handle.</param>
|
||||
@ -518,8 +518,8 @@ namespace Spine {
|
||||
|
||||
public TranslateTimeline (int frameCount, int bezierCount, int boneIndex)
|
||||
: base(frameCount, bezierCount, //
|
||||
(int)Property.TranslateX + "|" + boneIndex, //
|
||||
(int) Property.TranslateY + "|" + boneIndex) {
|
||||
(int)Property.X + "|" + boneIndex, //
|
||||
(int) Property.Y + "|" + boneIndex) {
|
||||
this.boneIndex = boneIndex;
|
||||
}
|
||||
|
||||
@ -593,7 +593,7 @@ namespace Spine {
|
||||
readonly int boneIndex;
|
||||
|
||||
public TranslateXTimeline (int frameCount, int bezierCount, int boneIndex)
|
||||
: base(frameCount, bezierCount, (int)Property.TranslateX + "|" + boneIndex) {
|
||||
: base(frameCount, bezierCount, (int)Property.X + "|" + boneIndex) {
|
||||
this.boneIndex = boneIndex;
|
||||
}
|
||||
|
||||
@ -642,7 +642,7 @@ namespace Spine {
|
||||
readonly int boneIndex;
|
||||
|
||||
public TranslateYTimeline (int frameCount, int bezierCount, int boneIndex)
|
||||
: base(frameCount, bezierCount, (int)Property.TranslateY + "|" + boneIndex) {
|
||||
: base(frameCount, bezierCount, (int)Property.Y + "|" + boneIndex) {
|
||||
this.boneIndex = boneIndex;
|
||||
}
|
||||
|
||||
@ -1705,12 +1705,11 @@ namespace Spine {
|
||||
slot.ClampSecondColor();
|
||||
}
|
||||
else {
|
||||
float br, bg, bb, ba, br2, bg2, bb2;
|
||||
float br, bg, bb, br2, bg2, bb2;
|
||||
if (blend == MixBlend.Setup) {
|
||||
br = slot.data.r;
|
||||
bg = slot.data.g;
|
||||
bb = slot.data.b;
|
||||
ba = slot.data.a;
|
||||
br2 = slot.data.r2;
|
||||
bg2 = slot.data.g2;
|
||||
bb2 = slot.data.b2;
|
||||
@ -1719,7 +1718,6 @@ namespace Spine {
|
||||
br = slot.r;
|
||||
bg = slot.g;
|
||||
bb = slot.b;
|
||||
ba = slot.a;
|
||||
br2 = slot.r2;
|
||||
bg2 = slot.g2;
|
||||
bb2 = slot.b2;
|
||||
@ -2308,8 +2306,8 @@ namespace Spine {
|
||||
|
||||
/// <summary>Changes a transform constraint's mixes.</summary>
|
||||
public class TransformConstraintTimeline : CurveTimeline {
|
||||
public const int ENTRIES = 5;
|
||||
private const int ROTATE = 1, TRANSLATE = 2, SCALE = 3, SHEAR = 4;
|
||||
public const int ENTRIES = 7;
|
||||
private const int ROTATE = 1, X = 2, Y = 3, SCALEX = 4, SCALEY = 5, SHEARY = 6;
|
||||
|
||||
readonly int transformConstraintIndex;
|
||||
|
||||
@ -2335,13 +2333,16 @@ namespace Spine {
|
||||
/// <summary>Sets the time, rotate mix, translate mix, scale mix, and shear mix for the specified frame.</summary>
|
||||
/// <param name="frame">Between 0 and <code>frameCount</code>, inclusive.</param>
|
||||
/// <param name="time">The frame time in seconds.</param>
|
||||
public void SetFrame (int frame, float time, float rotateMix, float translateMix, float scaleMix, float shearMix) {
|
||||
public void SetFrame (int frame, float time, float mixRotate, float mixX, float mixY, float mixScaleX, float mixScaleY,
|
||||
float mixShearY) {
|
||||
frame *= ENTRIES;
|
||||
frames[frame] = time;
|
||||
frames[frame + ROTATE] = rotateMix;
|
||||
frames[frame + TRANSLATE] = translateMix;
|
||||
frames[frame + SCALE] = scaleMix;
|
||||
frames[frame + SHEAR] = shearMix;
|
||||
frames[frame + ROTATE] = mixRotate;
|
||||
frames[frame + X] = mixX;
|
||||
frames[frame + Y] = mixY;
|
||||
frames[frame + SCALEX] = mixScaleX;
|
||||
frames[frame + SCALEY] = mixScaleY;
|
||||
frames[frame + SHEARY] = mixShearY;
|
||||
}
|
||||
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend,
|
||||
@ -2354,61 +2355,77 @@ namespace Spine {
|
||||
TransformConstraintData data = constraint.data;
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
constraint.rotateMix = data.rotateMix;
|
||||
constraint.translateMix = data.translateMix;
|
||||
constraint.scaleMix = data.scaleMix;
|
||||
constraint.shearMix = data.shearMix;
|
||||
constraint.mixRotate = data.mixRotate;
|
||||
constraint.mixX = data.mixX;
|
||||
constraint.mixY = data.mixY;
|
||||
constraint.mixScaleX = data.mixScaleX;
|
||||
constraint.mixScaleY = data.mixScaleY;
|
||||
constraint.mixShearY = data.mixShearY;
|
||||
return;
|
||||
case MixBlend.First:
|
||||
constraint.rotateMix += (data.rotateMix - constraint.rotateMix) * alpha;
|
||||
constraint.translateMix += (data.translateMix - constraint.translateMix) * alpha;
|
||||
constraint.scaleMix += (data.scaleMix - constraint.scaleMix) * alpha;
|
||||
constraint.shearMix += (data.shearMix - constraint.shearMix) * alpha;
|
||||
constraint.mixRotate += (data.mixRotate - constraint.mixRotate) * alpha;
|
||||
constraint.mixX += (data.mixX - constraint.mixX) * alpha;
|
||||
constraint.mixY += (data.mixY - constraint.mixY) * alpha;
|
||||
constraint.mixScaleX += (data.mixScaleX - constraint.mixScaleX) * alpha;
|
||||
constraint.mixScaleY += (data.mixScaleY - constraint.mixScaleY) * alpha;
|
||||
constraint.mixShearY += (data.mixShearY - constraint.mixShearY) * alpha;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
float rotate, translate, scale, shear;
|
||||
float rotate, x, y, scaleX, scaleY, shearY;
|
||||
int i = Animation.Search(frames, time, ENTRIES), curveType = (int)curves[i / ENTRIES];
|
||||
switch (curveType) {
|
||||
case LINEAR:
|
||||
float before = frames[i];
|
||||
rotate = frames[i + ROTATE];
|
||||
translate = frames[i + TRANSLATE];
|
||||
scale = frames[i + SCALE];
|
||||
shear = frames[i + SHEAR];
|
||||
x = frames[i + X];
|
||||
y = frames[i + Y];
|
||||
scaleX = frames[i + SCALEX];
|
||||
scaleY = frames[i + SCALEY];
|
||||
shearY = frames[i + SHEARY];
|
||||
float t = (time - before) / (frames[i + ENTRIES] - before);
|
||||
rotate += (frames[i + ENTRIES + ROTATE] - rotate) * t;
|
||||
translate += (frames[i + ENTRIES + TRANSLATE] - translate) * t;
|
||||
scale += (frames[i + ENTRIES + SCALE] - scale) * t;
|
||||
shear += (frames[i + ENTRIES + SHEAR] - shear) * t;
|
||||
x += (frames[i + ENTRIES + X] - x) * t;
|
||||
y += (frames[i + ENTRIES + Y] - y) * t;
|
||||
scaleX += (frames[i + ENTRIES + SCALEX] - scaleX) * t;
|
||||
scaleY += (frames[i + ENTRIES + SCALEY] - scaleY) * t;
|
||||
shearY += (frames[i + ENTRIES + SHEARY] - shearY) * t;
|
||||
break;
|
||||
case STEPPED:
|
||||
rotate = frames[i + ROTATE];
|
||||
translate = frames[i + TRANSLATE];
|
||||
scale = frames[i + SCALE];
|
||||
shear = frames[i + SHEAR];
|
||||
x = frames[i + X];
|
||||
y = frames[i + Y];
|
||||
scaleX = frames[i + SCALEX];
|
||||
scaleY = frames[i + SCALEY];
|
||||
shearY = frames[i + SHEARY];
|
||||
break;
|
||||
default:
|
||||
rotate = GetBezierValue(time, i, ROTATE, curveType - BEZIER);
|
||||
translate = GetBezierValue(time, i, TRANSLATE, curveType + BEZIER_SIZE - BEZIER);
|
||||
scale = GetBezierValue(time, i, TRANSLATE, curveType + BEZIER_SIZE * 2 - BEZIER);
|
||||
shear = GetBezierValue(time, i, TRANSLATE, curveType + BEZIER_SIZE * 3 - BEZIER);
|
||||
x = GetBezierValue(time, i, X, curveType + BEZIER_SIZE - BEZIER);
|
||||
y = GetBezierValue(time, i, Y, curveType + BEZIER_SIZE * 2 - BEZIER);
|
||||
scaleX = GetBezierValue(time, i, SCALEX, curveType + BEZIER_SIZE * 3 - BEZIER);
|
||||
scaleY = GetBezierValue(time, i, SCALEY, curveType + BEZIER_SIZE * 4 - BEZIER);
|
||||
shearY = GetBezierValue(time, i, SHEARY, curveType + BEZIER_SIZE * 5 - BEZIER);
|
||||
break;
|
||||
}
|
||||
|
||||
if (blend == MixBlend.Setup) {
|
||||
TransformConstraintData data = constraint.data;
|
||||
constraint.rotateMix = data.rotateMix + (rotate - data.rotateMix) * alpha;
|
||||
constraint.translateMix = data.translateMix + (translate - data.translateMix) * alpha;
|
||||
constraint.scaleMix = data.scaleMix + (scale - data.scaleMix) * alpha;
|
||||
constraint.shearMix = data.shearMix + (shear - data.shearMix) * alpha;
|
||||
constraint.mixRotate = data.mixRotate + (rotate - data.mixRotate) * alpha;
|
||||
constraint.mixX = data.mixX + (x - data.mixX) * alpha;
|
||||
constraint.mixY = data.mixY + (y - data.mixY) * alpha;
|
||||
constraint.mixScaleX = data.mixScaleX + (scaleX - data.mixScaleX) * alpha;
|
||||
constraint.mixScaleY = data.mixScaleY + (scaleY - data.mixScaleY) * alpha;
|
||||
constraint.mixShearY = data.mixShearY + (shearY - data.mixShearY) * alpha;
|
||||
} else {
|
||||
constraint.rotateMix += (rotate - constraint.rotateMix) * alpha;
|
||||
constraint.translateMix += (translate - constraint.translateMix) * alpha;
|
||||
constraint.scaleMix += (scale - constraint.scaleMix) * alpha;
|
||||
constraint.shearMix += (shear - constraint.shearMix) * alpha;
|
||||
constraint.mixRotate += (rotate - constraint.mixRotate) * alpha;
|
||||
constraint.mixX += (x - constraint.mixX) * alpha;
|
||||
constraint.mixY += (y - constraint.mixY) * alpha;
|
||||
constraint.mixScaleX += (scaleX - constraint.mixScaleX) * alpha;
|
||||
constraint.mixScaleY += (scaleY - constraint.mixScaleY) * alpha;
|
||||
constraint.mixShearY += (shearY - constraint.mixShearY) * alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2499,8 +2516,12 @@ namespace Spine {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Changes a path constraint's mixes.</summary>
|
||||
public class PathConstraintMixTimeline : CurveTimeline2 {
|
||||
/// <summary> Changes a transform constraint's <see cref="PathConstraint.MixRotate"/>, <see cref="PathConstraint.MixX"/>, and
|
||||
/// <see cref="PathConstraint.MixY"/>.</summary>
|
||||
public class PathConstraintMixTimeline : CurveTimeline {
|
||||
public const int ENTRIES = 4;
|
||||
private const int ROTATE = 1, X = 2, Y = 3;
|
||||
|
||||
readonly int pathConstraintIndex;
|
||||
|
||||
public PathConstraintMixTimeline (int frameCount, int bezierCount, int pathConstraintIndex)
|
||||
@ -2508,6 +2529,10 @@ namespace Spine {
|
||||
this.pathConstraintIndex = pathConstraintIndex;
|
||||
}
|
||||
|
||||
public override int FrameEntries {
|
||||
get { return ENTRIES; }
|
||||
}
|
||||
|
||||
/// <summary>The index of the path constraint slot in <see cref="Skeleton.PathConstraints"/> that will be changed when this timeline
|
||||
/// is applied.</summary>
|
||||
public int PathConstraintIndex {
|
||||
@ -2516,6 +2541,17 @@ namespace Spine {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Sets the time and color for the specified frame.</summary>
|
||||
/// <param name="frame">Between 0 and <code>frameCount</code>, inclusive.</param>
|
||||
/// <param name="time">The frame time in seconds.</param>
|
||||
public void SetFrame (int frame, float time, float mixRotate, float mixX, float mixY) {
|
||||
frame <<= 2;
|
||||
frames[frame] = time;
|
||||
frames[frame + ROTATE] = mixRotate;
|
||||
frames[frame + X] = mixX;
|
||||
frames[frame + Y] = mixY;
|
||||
}
|
||||
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend,
|
||||
MixDirection direction) {
|
||||
PathConstraint constraint = skeleton.pathConstraints.Items[pathConstraintIndex];
|
||||
@ -2525,44 +2561,53 @@ namespace Spine {
|
||||
if (time < frames[0]) { // Time is before first frame.
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
constraint.rotateMix = constraint.data.rotateMix;
|
||||
constraint.translateMix = constraint.data.translateMix;
|
||||
constraint.mixRotate = constraint.data.mixRotate;
|
||||
constraint.mixX = constraint.data.mixX;
|
||||
constraint.mixY = constraint.data.mixY;
|
||||
return;
|
||||
case MixBlend.First:
|
||||
constraint.rotateMix += (constraint.data.rotateMix - constraint.rotateMix) * alpha;
|
||||
constraint.translateMix += (constraint.data.translateMix - constraint.translateMix) * alpha;
|
||||
constraint.mixRotate += (constraint.data.mixRotate - constraint.mixRotate) * alpha;
|
||||
constraint.mixX += (constraint.data.mixX - constraint.mixX) * alpha;
|
||||
constraint.mixY += (constraint.data.mixY - constraint.mixY) * alpha;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
float rotate, translate;
|
||||
int i = Animation.Search(frames, time, ENTRIES), curveType = (int)curves[i / ENTRIES];
|
||||
float rotate, x, y;
|
||||
int i = Animation.Search(frames, time, ENTRIES), curveType = (int)curves[i >> 2];
|
||||
switch (curveType) {
|
||||
case LINEAR:
|
||||
float before = frames[i];
|
||||
rotate = frames[i + VALUE1];
|
||||
translate = frames[i + VALUE2];
|
||||
rotate = frames[i + ROTATE];
|
||||
x = frames[i + X];
|
||||
y = frames[i + Y];
|
||||
float t = (time - before) / (frames[i + ENTRIES] - before);
|
||||
rotate += (frames[i + ENTRIES + VALUE1] - rotate) * t;
|
||||
translate += (frames[i + ENTRIES + VALUE2] - translate) * t;
|
||||
rotate += (frames[i + ENTRIES + ROTATE] - rotate) * t;
|
||||
x += (frames[i + ENTRIES + X] - x) * t;
|
||||
y += (frames[i + ENTRIES + Y] - y) * t;
|
||||
break;
|
||||
case STEPPED:
|
||||
rotate = frames[i + VALUE1];
|
||||
translate = frames[i + VALUE2];
|
||||
rotate = frames[i + ROTATE];
|
||||
x = frames[i + X];
|
||||
y = frames[i + Y];
|
||||
break;
|
||||
default:
|
||||
rotate = GetBezierValue(time, i, VALUE1, curveType - BEZIER);
|
||||
translate = GetBezierValue(time, i, VALUE2, curveType + BEZIER_SIZE - BEZIER);
|
||||
rotate = GetBezierValue(time, i, ROTATE, curveType - BEZIER);
|
||||
x = GetBezierValue(time, i, X, curveType + BEZIER_SIZE - BEZIER);
|
||||
y = GetBezierValue(time, i, Y, curveType + BEZIER_SIZE * 2 - BEZIER);
|
||||
break;
|
||||
}
|
||||
|
||||
if (blend == MixBlend.Setup) {
|
||||
constraint.rotateMix = constraint.data.rotateMix + (rotate - constraint.data.rotateMix) * alpha;
|
||||
constraint.translateMix = constraint.data.translateMix + (translate - constraint.data.translateMix) * alpha;
|
||||
PathConstraintData data = constraint.data;
|
||||
constraint.mixRotate = data.mixRotate + (rotate - data.mixRotate) * alpha;
|
||||
constraint.mixX = data.mixX + (x - data.mixX) * alpha;
|
||||
constraint.mixY = data.mixY + (y - data.mixY) * alpha;
|
||||
} else {
|
||||
constraint.rotateMix += (rotate - constraint.rotateMix) * alpha;
|
||||
constraint.translateMix += (translate - constraint.translateMix) * alpha;
|
||||
constraint.mixRotate += (rotate - constraint.mixRotate) * alpha;
|
||||
constraint.mixX += (x - constraint.mixX) * alpha;
|
||||
constraint.mixY += (y - constraint.mixY) * alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,7 +37,10 @@ namespace Spine {
|
||||
|
||||
/// <summary>The length in the setup pose from the start of the path to the end of each curve.</summary>
|
||||
public float[] Lengths { get { return lengths; } set { lengths = value; } }
|
||||
/// <summary>If true, the start and end knots are connected.</summary>
|
||||
public bool Closed { get { return closed; } set { closed = value; } }
|
||||
/// <summary>If true, additional calculations are performed to make computing positions along the path more accurate and movement along
|
||||
/// the path have a constant speed.</summary>
|
||||
public bool ConstantSpeed { get { return constantSpeed; } set { constantSpeed = value; } }
|
||||
|
||||
public PathAttachment (String name)
|
||||
|
||||
@ -104,7 +104,7 @@ namespace Spine {
|
||||
set { target = value; }
|
||||
}
|
||||
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained rotations.</summary>
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained rotation.</summary>
|
||||
public float Mix {
|
||||
get { return mix; }
|
||||
set { mix = value; }
|
||||
|
||||
@ -54,7 +54,7 @@ namespace Spine {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A percentage (0-1) that controls the mix between the constraint and unconstrained rotations.</summary>
|
||||
/// A percentage (0-1) that controls the mix between the constraint and unconstrained rotation.</summary>
|
||||
public float Mix {
|
||||
get { return mix; }
|
||||
set { mix = value; }
|
||||
|
||||
@ -45,7 +45,7 @@ namespace Spine {
|
||||
internal PathConstraintData data;
|
||||
internal ExposedList<Bone> bones;
|
||||
internal Slot target;
|
||||
internal float position, spacing, rotateMix, translateMix;
|
||||
internal float position, spacing, mixRotate, mixX, mixY;
|
||||
|
||||
internal bool active;
|
||||
|
||||
@ -63,8 +63,9 @@ namespace Spine {
|
||||
target = skeleton.FindSlot(data.target.name);
|
||||
position = data.position;
|
||||
spacing = data.spacing;
|
||||
rotateMix = data.rotateMix;
|
||||
translateMix = data.translateMix;
|
||||
mixRotate = data.mixRotate;
|
||||
mixX = data.mixX;
|
||||
mixY = data.mixY;
|
||||
}
|
||||
|
||||
/// <summary>Copy constructor.</summary>
|
||||
@ -78,60 +79,88 @@ namespace Spine {
|
||||
target = skeleton.slots.Items[constraint.target.data.index];
|
||||
position = constraint.position;
|
||||
spacing = constraint.spacing;
|
||||
rotateMix = constraint.rotateMix;
|
||||
translateMix = constraint.translateMix;
|
||||
mixRotate = constraint.mixRotate;
|
||||
mixX = constraint.mixX;
|
||||
mixY = constraint.mixY;
|
||||
}
|
||||
|
||||
public void Update () {
|
||||
PathAttachment attachment = target.Attachment as PathAttachment;
|
||||
if (attachment == null) return;
|
||||
|
||||
float rotateMix = this.rotateMix, translateMix = this.translateMix;
|
||||
bool translate = translateMix > 0, rotate = rotateMix > 0;
|
||||
if (!translate && !rotate) return;
|
||||
float mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY;
|
||||
if (mixRotate == 0 && mixX == 0 && mixY == 0) return;
|
||||
|
||||
PathConstraintData data = this.data;
|
||||
bool percentSpacing = data.spacingMode == SpacingMode.Percent;
|
||||
RotateMode rotateMode = data.rotateMode;
|
||||
bool tangents = rotateMode == RotateMode.Tangent, scale = rotateMode == RotateMode.ChainScale;
|
||||
bool tangents = data.rotateMode == RotateMode.Tangent, scale = data.rotateMode == RotateMode.ChainScale;
|
||||
int boneCount = this.bones.Count, spacesCount = tangents ? boneCount : boneCount + 1;
|
||||
Bone[] bonesItems = this.bones.Items;
|
||||
ExposedList<float> spaces = this.spaces.Resize(spacesCount), lengths = null;
|
||||
float[] spaces = this.spaces.Resize(spacesCount).Items, lengths = scale ? this.lengths.Resize(boneCount).Items : null;
|
||||
float spacing = this.spacing;
|
||||
if (scale || !percentSpacing) {
|
||||
if (scale) lengths = this.lengths.Resize(boneCount);
|
||||
bool lengthSpacing = data.spacingMode == SpacingMode.Length;
|
||||
for (int i = 0, n = spacesCount - 1; i < n;) {
|
||||
Bone bone = bonesItems[i];
|
||||
float setupLength = bone.data.length;
|
||||
if (setupLength < PathConstraint.Epsilon) {
|
||||
if (scale) lengths.Items[i] = 0;
|
||||
spaces.Items[++i] = 0;
|
||||
} else if (percentSpacing) {
|
||||
if (scale) {
|
||||
switch (data.spacingMode) {
|
||||
case SpacingMode.Percent:
|
||||
for (int i = 0, n = spacesCount - 1; i < n;) {
|
||||
Bone bone = bonesItems[i];
|
||||
float setupLength = bone.data.length;
|
||||
if (setupLength < PathConstraint.Epsilon) {
|
||||
if (scale) lengths[i] = 0;
|
||||
spaces[++i] = 0;
|
||||
} else {
|
||||
if (scale) {
|
||||
float x = setupLength * bone.a, y = setupLength * bone.c;
|
||||
lengths[i] = (float)Math.Sqrt(x * x + y * y);
|
||||
}
|
||||
spaces[++i] = spacing;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case SpacingMode.Proportional: {
|
||||
float sum = 0;
|
||||
for (int i = 0; i < boneCount;) {
|
||||
Bone bone = bonesItems[i];
|
||||
float setupLength = bone.data.length;
|
||||
if (setupLength < PathConstraint.Epsilon) {
|
||||
if (scale) lengths[i] = 0;
|
||||
spaces[++i] = 0;
|
||||
} else {
|
||||
float x = setupLength * bone.a, y = setupLength * bone.c;
|
||||
float length = (float)Math.Sqrt(x * x + y * y);
|
||||
lengths.Items[i] = length;
|
||||
if (scale) lengths[i] = length;
|
||||
spaces[++i] = length;
|
||||
sum += length;
|
||||
}
|
||||
spaces.Items[++i] = spacing;
|
||||
} else {
|
||||
float x = setupLength * bone.a, y = setupLength * bone.c;
|
||||
float length = (float)Math.Sqrt(x * x + y * y);
|
||||
if (scale) lengths.Items[i] = length;
|
||||
spaces.Items[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
|
||||
}
|
||||
sum = spacesCount / sum * spacing;
|
||||
for (int i = 1; i < spacesCount; i++)
|
||||
spaces[i] *= sum;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
bool lengthSpacing = data.spacingMode == SpacingMode.Length;
|
||||
|
||||
for (int i = 0, n = spacesCount - 1; i < n;) {
|
||||
Bone bone = bonesItems[i];
|
||||
float setupLength = bone.data.length;
|
||||
if (setupLength < PathConstraint.Epsilon) {
|
||||
if (scale) lengths[i] = 0;
|
||||
spaces[++i] = 0;
|
||||
}
|
||||
else {
|
||||
float x = setupLength * bone.a, y = setupLength * bone.c;
|
||||
float length = (float)Math.Sqrt(x * x + y * y);
|
||||
if (scale) lengths[i] = length;
|
||||
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
for (int i = 1; i < spacesCount; i++)
|
||||
spaces.Items[i] = spacing;
|
||||
}
|
||||
|
||||
float[] positions = ComputeWorldPositions(attachment, spacesCount, tangents,
|
||||
data.positionMode == PositionMode.Percent, percentSpacing);
|
||||
float[] positions = ComputeWorldPositions(attachment, spacesCount, tangents);
|
||||
float boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation;
|
||||
bool tip;
|
||||
if (offsetRotation == 0) {
|
||||
tip = rotateMode == RotateMode.Chain;
|
||||
tip = data.rotateMode == RotateMode.Chain;
|
||||
} else {
|
||||
tip = false;
|
||||
Bone p = target.bone;
|
||||
@ -139,24 +168,24 @@ namespace Spine {
|
||||
}
|
||||
for (int i = 0, p = 3; i < boneCount; i++, p += 3) {
|
||||
Bone bone = bonesItems[i];
|
||||
bone.worldX += (boneX - bone.worldX) * translateMix;
|
||||
bone.worldY += (boneY - bone.worldY) * translateMix;
|
||||
bone.worldX += (boneX - bone.worldX) * mixX;
|
||||
bone.worldY += (boneY - bone.worldY) * mixY;
|
||||
float x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY;
|
||||
if (scale) {
|
||||
float length = lengths.Items[i];
|
||||
float length = lengths[i];
|
||||
if (length >= PathConstraint.Epsilon) {
|
||||
float s = ((float)Math.Sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1;
|
||||
float s = ((float)Math.Sqrt(dx * dx + dy * dy) / length - 1) * mixRotate + 1;
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
}
|
||||
}
|
||||
boneX = x;
|
||||
boneY = y;
|
||||
if (rotate) {
|
||||
if (mixRotate > 0) {
|
||||
float a = bone.a, b = bone.b, c = bone.c, d = bone.d, r, cos, sin;
|
||||
if (tangents)
|
||||
r = positions[p - 1];
|
||||
else if (spaces.Items[i + 1] < PathConstraint.Epsilon)
|
||||
else if (spaces[i + 1] < PathConstraint.Epsilon)
|
||||
r = positions[p + 2];
|
||||
else
|
||||
r = MathUtils.Atan2(dy, dx);
|
||||
@ -165,15 +194,15 @@ namespace Spine {
|
||||
cos = MathUtils.Cos(r);
|
||||
sin = MathUtils.Sin(r);
|
||||
float length = bone.data.length;
|
||||
boneX += (length * (cos * a - sin * c) - dx) * rotateMix;
|
||||
boneY += (length * (sin * a + cos * c) - dy) * rotateMix;
|
||||
boneX += (length * (cos * a - sin * c) - dx) * mixRotate;
|
||||
boneY += (length * (sin * a + cos * c) - dy) * mixRotate;
|
||||
} else
|
||||
r += offsetRotation;
|
||||
if (r > MathUtils.PI)
|
||||
r -= MathUtils.PI2;
|
||||
else if (r < -MathUtils.PI) //
|
||||
r += MathUtils.PI2;
|
||||
r *= rotateMix;
|
||||
r *= mixRotate;
|
||||
cos = MathUtils.Cos(r);
|
||||
sin = MathUtils.Sin(r);
|
||||
bone.a = cos * a - sin * c;
|
||||
@ -185,28 +214,38 @@ namespace Spine {
|
||||
}
|
||||
}
|
||||
|
||||
float[] ComputeWorldPositions (PathAttachment path, int spacesCount, bool tangents, bool percentPosition,
|
||||
bool percentSpacing) {
|
||||
float[] ComputeWorldPositions (PathAttachment path, int spacesCount, bool tangents) {
|
||||
|
||||
Slot target = this.target;
|
||||
float position = this.position;
|
||||
float[] spacesItems = this.spaces.Items, output = this.positions.Resize(spacesCount * 3 + 2).Items, world;
|
||||
float[] spaces = this.spaces.Items, output = this.positions.Resize(spacesCount * 3 + 2).Items, world;
|
||||
bool closed = path.Closed;
|
||||
int verticesLength = path.WorldVerticesLength, curveCount = verticesLength / 6, prevCurve = NONE;
|
||||
float pathLength = 0;
|
||||
|
||||
float pathLength;
|
||||
float multiplier;
|
||||
if (!path.ConstantSpeed) {
|
||||
float[] lengths = path.Lengths;
|
||||
curveCount -= closed ? 1 : 2;
|
||||
pathLength = lengths[curveCount];
|
||||
if (percentPosition) position *= pathLength;
|
||||
if (percentSpacing) {
|
||||
for (int i = 1; i < spacesCount; i++)
|
||||
spacesItems[i] *= pathLength;
|
||||
|
||||
if (data.positionMode == PositionMode.Percent) position *= pathLength;
|
||||
|
||||
//float multiplier;
|
||||
switch (data.spacingMode) {
|
||||
case SpacingMode.Percent:
|
||||
multiplier = pathLength;
|
||||
break;
|
||||
case SpacingMode.Proportional:
|
||||
multiplier = pathLength / spacesCount;
|
||||
break;
|
||||
default:
|
||||
multiplier = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
world = this.world.Resize(8).Items;
|
||||
for (int i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) {
|
||||
float space = spacesItems[i];
|
||||
float space = spaces[i] * multiplier;
|
||||
position += space;
|
||||
float p = position;
|
||||
|
||||
@ -307,20 +346,26 @@ namespace Spine {
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
}
|
||||
if (percentPosition)
|
||||
position *= pathLength;
|
||||
else
|
||||
position *= pathLength / path.lengths[curveCount - 1];
|
||||
|
||||
if (percentSpacing) {
|
||||
for (int i = 1; i < spacesCount; i++)
|
||||
spacesItems[i] *= pathLength;
|
||||
if (data.positionMode == PositionMode.Percent) position *= pathLength;
|
||||
|
||||
//float multiplier;
|
||||
switch (data.spacingMode) {
|
||||
case SpacingMode.Percent:
|
||||
multiplier = pathLength;
|
||||
break;
|
||||
case SpacingMode.Proportional:
|
||||
multiplier = pathLength / spacesCount;
|
||||
break;
|
||||
default:
|
||||
multiplier = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
float[] segments = this.segments;
|
||||
float curveLength = 0;
|
||||
for (int i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) {
|
||||
float space = spacesItems[i];
|
||||
float space = spaces[i] * multiplier;
|
||||
position += space;
|
||||
float p = position;
|
||||
|
||||
@ -448,9 +493,11 @@ namespace Spine {
|
||||
/// <summary>The spacing between bones.</summary>
|
||||
public float Spacing { get { return spacing; } set { spacing = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained rotations.</summary>
|
||||
public float RotateMix { get { return rotateMix; } set { rotateMix = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained translations.</summary>
|
||||
public float TranslateMix { get { return translateMix; } set { translateMix = value; } }
|
||||
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>
|
||||
public float MixX { get { return mixX; } set { mixX = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y.</summary>
|
||||
public float MixY { get { return mixY; } set { mixY = value; } }
|
||||
/// <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>
|
||||
|
||||
@ -37,7 +37,7 @@ namespace Spine {
|
||||
internal SpacingMode spacingMode;
|
||||
internal RotateMode rotateMode;
|
||||
internal float offsetRotation;
|
||||
internal float position, spacing, rotateMix, translateMix;
|
||||
internal float position, spacing, mixRotate, mixX, mixY;
|
||||
|
||||
public PathConstraintData (string name) : base(name) {
|
||||
}
|
||||
@ -50,8 +50,12 @@ namespace Spine {
|
||||
public float OffsetRotation { get { return offsetRotation; } set { offsetRotation = value; } }
|
||||
public float Position { get { return position; } set { position = value; } }
|
||||
public float Spacing { get { return spacing; } set { spacing = value; } }
|
||||
public float RotateMix { get { return rotateMix; } set { rotateMix = value; } }
|
||||
public float TranslateMix { get { return translateMix; } set { translateMix = value; } }
|
||||
/// <summary> A percentage (0-1) that controls the mix between the constrained and unconstrained rotation.</summary>
|
||||
public float RotateMix { get { return mixRotate; } set { mixRotate = value; } }
|
||||
/// <summary> A percentage (0-1) that controls the mix between the constrained and unconstrained translation X.</summary>
|
||||
public float MixX { get { return mixX; } set { mixX = value; } }
|
||||
/// <summary> A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y.</summary>
|
||||
public float MixY { get { return mixY; } set { mixY = value; } }
|
||||
}
|
||||
|
||||
public enum PositionMode {
|
||||
@ -59,7 +63,7 @@ namespace Spine {
|
||||
}
|
||||
|
||||
public enum SpacingMode {
|
||||
Length, Fixed, Percent
|
||||
Length, Fixed, Percent, Proportional
|
||||
}
|
||||
|
||||
public enum RotateMode {
|
||||
|
||||
@ -379,10 +379,12 @@ namespace Spine {
|
||||
for (int i = 0, n = this.transformConstraints.Count; i < n; i++) {
|
||||
TransformConstraint constraint = transformConstraints[i];
|
||||
TransformConstraintData constraintData = constraint.data;
|
||||
constraint.rotateMix = constraintData.rotateMix;
|
||||
constraint.translateMix = constraintData.translateMix;
|
||||
constraint.scaleMix = constraintData.scaleMix;
|
||||
constraint.shearMix = constraintData.shearMix;
|
||||
constraint.mixRotate = constraintData.mixRotate;
|
||||
constraint.mixX = constraintData.mixX;
|
||||
constraint.mixY = constraintData.mixY;
|
||||
constraint.mixScaleX = constraintData.mixScaleX;
|
||||
constraint.mixScaleY = constraintData.mixScaleY;
|
||||
constraint.mixShearY = constraintData.mixShearY;
|
||||
}
|
||||
|
||||
var pathConstraints = this.pathConstraints.Items;
|
||||
@ -391,8 +393,9 @@ namespace Spine {
|
||||
PathConstraintData constraintData = constraint.data;
|
||||
constraint.position = constraintData.position;
|
||||
constraint.spacing = constraintData.spacing;
|
||||
constraint.rotateMix = constraintData.rotateMix;
|
||||
constraint.translateMix = constraintData.translateMix;
|
||||
constraint.mixRotate = constraintData.mixRotate;
|
||||
constraint.mixX = constraintData.mixX;
|
||||
constraint.mixY = constraintData.mixY;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -57,9 +57,9 @@ namespace Spine {
|
||||
public const int SLOT_ATTACHMENT = 0;
|
||||
public const int SLOT_RGBA = 1;
|
||||
public const int SLOT_RGB = 2;
|
||||
public const int SLOT_ALPHA = 3;
|
||||
public const int SLOT_RGBA2 = 4;
|
||||
public const int SLOT_RGB2 = 5;
|
||||
public const int SLOT_RGBA2 = 3;
|
||||
public const int SLOT_RGB2 = 4;
|
||||
public const int SLOT_ALPHA = 5;
|
||||
|
||||
public const int PATH_POSITION = 0;
|
||||
public const int PATH_SPACING = 1;
|
||||
@ -240,10 +240,12 @@ namespace Spine {
|
||||
data.offsetScaleX = input.ReadFloat();
|
||||
data.offsetScaleY = input.ReadFloat();
|
||||
data.offsetShearY = input.ReadFloat();
|
||||
data.rotateMix = input.ReadFloat();
|
||||
data.translateMix = input.ReadFloat();
|
||||
data.scaleMix = input.ReadFloat();
|
||||
data.shearMix = input.ReadFloat();
|
||||
data.mixRotate = input.ReadFloat();
|
||||
data.mixX = input.ReadFloat();
|
||||
data.mixY = input.ReadFloat();
|
||||
data.mixScaleX = input.ReadFloat();
|
||||
data.mixScaleY = input.ReadFloat();
|
||||
data.mixShearY = input.ReadFloat();
|
||||
o[i] = data;
|
||||
}
|
||||
|
||||
@ -265,8 +267,9 @@ namespace Spine {
|
||||
if (data.positionMode == PositionMode.Fixed) data.position *= scale;
|
||||
data.spacing = input.ReadFloat();
|
||||
if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) data.spacing *= scale;
|
||||
data.rotateMix = input.ReadFloat();
|
||||
data.translateMix = input.ReadFloat();
|
||||
data.mixRotate = input.ReadFloat();
|
||||
data.mixX = input.ReadFloat();
|
||||
data.mixY = input.ReadFloat();
|
||||
o[i] = data;
|
||||
}
|
||||
|
||||
@ -637,8 +640,7 @@ namespace Spine {
|
||||
timeline.SetFrame(frame, time, r, g, b);
|
||||
if (frame == frameLast) break;
|
||||
float time2 = input.ReadFloat();
|
||||
float r2 = input.Read() / 255f, g2 = input.Read() / 255f;
|
||||
float b2 = input.Read() / 255f, a2 = input.Read() / 255f;
|
||||
float r2 = input.Read() / 255f, g2 = input.Read() / 255f, b2 = input.Read() / 255f;
|
||||
switch (input.ReadByte()) {
|
||||
case CURVE_STEPPED:
|
||||
timeline.SetStepped(frame);
|
||||
@ -826,29 +828,33 @@ namespace Spine {
|
||||
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);
|
||||
float time = input.ReadFloat(), rotateMix = input.ReadFloat(), translateMix = input.ReadFloat(),
|
||||
scaleMix = input.ReadFloat(), shearMix = input.ReadFloat();
|
||||
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++) {
|
||||
timeline.SetFrame(frame, time, rotateMix, translateMix, scaleMix, shearMix);
|
||||
timeline.SetFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY);
|
||||
if (frame == frameLast) break;
|
||||
float time2 = input.ReadFloat(), rotateMix2 = input.ReadFloat(), translateMix2 = input.ReadFloat(),
|
||||
scaleMix2 = input.ReadFloat(), shearMix2 = input.ReadFloat();
|
||||
float time2 = input.ReadFloat(), mixRotate2 = input.ReadFloat(), mixX2 = input.ReadFloat(), mixY2 = input.ReadFloat(),
|
||||
mixScaleX2 = input.ReadFloat(), mixScaleY2 = input.ReadFloat(), mixShearY2 = input.ReadFloat();
|
||||
switch (input.ReadByte()) {
|
||||
case CURVE_STEPPED:
|
||||
timeline.SetStepped(frame);
|
||||
break;
|
||||
case CURVE_BEZIER:
|
||||
SetBezier(input, timeline, bezier++, frame, 0, time, time2, rotateMix, rotateMix2, 1);
|
||||
SetBezier(input, timeline, bezier++, frame, 1, time, time2, translateMix, translateMix2, 1);
|
||||
SetBezier(input, timeline, bezier++, frame, 2, time, time2, scaleMix, scaleMix2, 1);
|
||||
SetBezier(input, timeline, bezier++, frame, 3, time, time2, shearMix, shearMix2, 1);
|
||||
SetBezier(input, timeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1);
|
||||
SetBezier(input, timeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1);
|
||||
SetBezier(input, timeline, bezier++, frame, 2, time, time2, mixY, mixY2, 1);
|
||||
SetBezier(input, timeline, bezier++, frame, 3, time, time2, mixScaleX, mixScaleX2, 1);
|
||||
SetBezier(input, timeline, bezier++, frame, 4, time, time2, mixScaleY, mixScaleY2, 1);
|
||||
SetBezier(input, timeline, bezier++, frame, 5, time, time2, mixShearY, mixShearY2, 1);
|
||||
break;
|
||||
}
|
||||
time = time2;
|
||||
rotateMix = rotateMix2;
|
||||
translateMix = translateMix2;
|
||||
scaleMix = scaleMix2;
|
||||
shearMix = shearMix2;
|
||||
mixRotate = mixRotate2;
|
||||
mixX = mixX2;
|
||||
mixY = mixY2;
|
||||
mixScaleX = mixScaleX2;
|
||||
mixScaleY = mixScaleY2;
|
||||
mixShearY = mixShearY2;
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
}
|
||||
@ -870,8 +876,30 @@ namespace Spine {
|
||||
data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed ? scale : 1));
|
||||
break;
|
||||
case PATH_MIX:
|
||||
timelines
|
||||
.Add(ReadTimeline(input, new PathConstraintMixTimeline(input.ReadInt(true), input.ReadInt(true), index), 1));
|
||||
PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(input.ReadInt(true), input.ReadInt(true),
|
||||
index);
|
||||
float time = input.ReadFloat(), mixRotate = input.ReadFloat(), mixX = input.ReadFloat(), mixY = input.ReadFloat();
|
||||
for (int frame = 0, bezier = 0, frameLast = nn - 1; ; frame++) {
|
||||
timeline.SetFrame(frame, time, mixRotate, mixX, mixY);
|
||||
if (frame == frameLast) break;
|
||||
float time2 = input.ReadFloat(), mixRotate2 = input.ReadFloat(), mixX2 = input.ReadFloat(),
|
||||
mixY2 = input.ReadFloat();
|
||||
switch (input.ReadByte()) {
|
||||
case CURVE_STEPPED:
|
||||
timeline.SetStepped(frame);
|
||||
break;
|
||||
case CURVE_BEZIER:
|
||||
SetBezier(input, timeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1);
|
||||
SetBezier(input, timeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1);
|
||||
SetBezier(input, timeline, bezier++, frame, 2, time, time2, mixY, mixY2, 1);
|
||||
break;
|
||||
}
|
||||
time = time2;
|
||||
mixRotate = mixRotate2;
|
||||
mixX = mixX2;
|
||||
mixY = mixY2;
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -231,10 +231,12 @@ namespace Spine {
|
||||
data.offsetScaleY = GetFloat(constraintMap, "scaleY", 0);
|
||||
data.offsetShearY = GetFloat(constraintMap, "shearY", 0);
|
||||
|
||||
data.rotateMix = GetFloat(constraintMap, "rotateMix", 1);
|
||||
data.translateMix = GetFloat(constraintMap, "translateMix", 1);
|
||||
data.scaleMix = GetFloat(constraintMap, "scaleMix", 1);
|
||||
data.shearMix = GetFloat(constraintMap, "shearMix", 1);
|
||||
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);
|
||||
|
||||
skeletonData.transformConstraints.Add(data);
|
||||
}
|
||||
@ -267,8 +269,10 @@ namespace Spine {
|
||||
if (data.positionMode == PositionMode.Fixed) data.position *= scale;
|
||||
data.spacing = GetFloat(constraintMap, "spacing", 0);
|
||||
if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) data.spacing *= scale;
|
||||
data.rotateMix = GetFloat(constraintMap, "rotateMix", 1);
|
||||
data.translateMix = GetFloat(constraintMap, "translateMix", 1);
|
||||
data.mixRotate = GetFloat(constraintMap, "mixRotate", 1);
|
||||
data.mixX = GetFloat(constraintMap, "mixX", 1);
|
||||
data.mixY = GetFloat(constraintMap, "mixY", 1);
|
||||
|
||||
|
||||
skeletonData.pathConstraints.Add(data);
|
||||
}
|
||||
@ -595,9 +599,9 @@ namespace Spine {
|
||||
var keyMap = (Dictionary<string, Object>)keyMapEnumerator.Current;
|
||||
float time = GetFloat(keyMap, "time", 0);
|
||||
string color = (string)keyMap["color"];
|
||||
float r = ToColor(color, 0);
|
||||
float g = ToColor(color, 1);
|
||||
float b = ToColor(color, 2);
|
||||
float r = ToColor(color, 0, 6);
|
||||
float g = ToColor(color, 1, 6);
|
||||
float b = ToColor(color, 2, 6);
|
||||
for (int frame = 0, bezier = 0; ; frame++) {
|
||||
timeline.SetFrame(frame, time, r, g, b);
|
||||
bool hasNext = keyMapEnumerator.MoveNext();
|
||||
@ -609,9 +613,9 @@ namespace Spine {
|
||||
|
||||
float time2 = GetFloat(nextMap, "time", 0);
|
||||
color = (string)nextMap["color"];
|
||||
float nr = ToColor(color, 0);
|
||||
float ng = ToColor(color, 1);
|
||||
float nb = ToColor(color, 2);
|
||||
float nr = ToColor(color, 0, 6);
|
||||
float ng = ToColor(color, 1, 6);
|
||||
float nb = ToColor(color, 2, 6);
|
||||
|
||||
if (keyMap.ContainsKey("curve")) {
|
||||
object curve = keyMap["curve"];
|
||||
@ -645,9 +649,9 @@ namespace Spine {
|
||||
float b = ToColor(color, 2);
|
||||
float a = ToColor(color, 3);
|
||||
color = (string)keyMap["dark"];
|
||||
float r2 = ToColor(color, 0);
|
||||
float g2 = ToColor(color, 1);
|
||||
float b2 = ToColor(color, 2);
|
||||
float r2 = ToColor(color, 0, 6);
|
||||
float g2 = ToColor(color, 1, 6);
|
||||
float b2 = ToColor(color, 2, 6);
|
||||
for (int frame = 0, bezier = 0; ; frame++) {
|
||||
timeline.SetFrame(frame, time, r, g, b, a, r2, g2, b2);
|
||||
bool hasNext = keyMapEnumerator.MoveNext();
|
||||
@ -664,9 +668,9 @@ namespace Spine {
|
||||
float nb = ToColor(color, 2);
|
||||
float na = ToColor(color, 3);
|
||||
color = (string)nextMap["dark"];
|
||||
float nr2 = ToColor(color, 0);
|
||||
float ng2 = ToColor(color, 1);
|
||||
float nb2 = ToColor(color, 2);
|
||||
float nr2 = ToColor(color, 0, 6);
|
||||
float ng2 = ToColor(color, 1, 6);
|
||||
float nb2 = ToColor(color, 2, 6);
|
||||
|
||||
if (keyMap.ContainsKey("curve")) {
|
||||
object curve = keyMap["curve"];
|
||||
@ -698,13 +702,13 @@ namespace Spine {
|
||||
var keyMap = (Dictionary<string, Object>)keyMapEnumerator.Current;
|
||||
float time = GetFloat(keyMap, "time", 0);
|
||||
string color = (string)keyMap["light"];
|
||||
float r = ToColor(color, 0);
|
||||
float g = ToColor(color, 1);
|
||||
float b = ToColor(color, 2);
|
||||
float r = ToColor(color, 0, 6);
|
||||
float g = ToColor(color, 1, 6);
|
||||
float b = ToColor(color, 2, 6);
|
||||
color = (string)keyMap["dark"];
|
||||
float r2 = ToColor(color, 0);
|
||||
float g2 = ToColor(color, 1);
|
||||
float b2 = ToColor(color, 2);
|
||||
float r2 = ToColor(color, 0, 6);
|
||||
float g2 = ToColor(color, 1, 6);
|
||||
float b2 = ToColor(color, 2, 6);
|
||||
for (int frame = 0, bezier = 0; ; frame++) {
|
||||
timeline.SetFrame(frame, time, r, g, b, r2, g2, b2);
|
||||
bool hasNext = keyMapEnumerator.MoveNext();
|
||||
@ -716,13 +720,13 @@ namespace Spine {
|
||||
|
||||
float time2 = GetFloat(nextMap, "time", 0);
|
||||
color = (string)nextMap["light"];
|
||||
float nr = ToColor(color, 0);
|
||||
float ng = ToColor(color, 1);
|
||||
float nb = ToColor(color, 2);
|
||||
float nr = ToColor(color, 0, 6);
|
||||
float ng = ToColor(color, 1, 6);
|
||||
float nb = ToColor(color, 2, 6);
|
||||
color = (string)nextMap["dark"];
|
||||
float nr2 = ToColor(color, 0);
|
||||
float ng2 = ToColor(color, 1);
|
||||
float nb2 = ToColor(color, 2);
|
||||
float nr2 = ToColor(color, 0, 6);
|
||||
float ng2 = ToColor(color, 1, 6);
|
||||
float nb2 = ToColor(color, 2, 6);
|
||||
|
||||
if (keyMap.ContainsKey("curve")) {
|
||||
object curve = keyMap["curve"];
|
||||
@ -849,10 +853,11 @@ namespace Spine {
|
||||
TransformConstraintTimeline timeline = new TransformConstraintTimeline(timelineMapValues.Count, timelineMapValues.Count << 2,
|
||||
skeletonData.TransformConstraints.IndexOf(constraint));
|
||||
float time = GetFloat(keyMap, "time", 0);
|
||||
float rotateMix = GetFloat(keyMap, "rotateMix", 1), translateMix = GetFloat(keyMap, "translateMix", 1);
|
||||
float scaleMix = GetFloat(keyMap, "scaleMix", 1), shearMix = GetFloat(keyMap, "shearMix", 1);
|
||||
float mixRotate = GetFloat(keyMap, "mixRotate", 1), mixShearY = GetFloat(keyMap, "mixShearY", 1);
|
||||
float mixX = GetFloat(keyMap, "mixX", 1), mixY = GetFloat(keyMap, "mixY", mixX);
|
||||
float mixScaleX = GetFloat(keyMap, "mixScaleX", 1), mixScaleY = GetFloat(keyMap, "mixScaleY", mixScaleX);
|
||||
for (int frame = 0, bezier = 0; ; frame++) {
|
||||
timeline.SetFrame(frame, time, rotateMix, translateMix, scaleMix, shearMix);
|
||||
timeline.SetFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY);
|
||||
hasNext = keyMapEnumerator.MoveNext();
|
||||
if (!hasNext) {
|
||||
timeline.Shrink(bezier);
|
||||
@ -860,20 +865,25 @@ namespace Spine {
|
||||
}
|
||||
var nextMap = (Dictionary<string, Object>)keyMapEnumerator.Current;
|
||||
float time2 = GetFloat(nextMap, "time", 0);
|
||||
float rotateMix2 = GetFloat(nextMap, "rotateMix", 1), translateMix2 = GetFloat(nextMap, "translateMix", 1);
|
||||
float scaleMix2 = GetFloat(nextMap, "scaleMix", 1), shearMix2 = GetFloat(nextMap, "shearMix", 1);
|
||||
float mixRotate2 = GetFloat(nextMap, "mixRotate", 1), mixShearY2 = GetFloat(nextMap, "mixShearY", 1);
|
||||
float mixX2 = GetFloat(nextMap, "mixX", 1), mixY2 = GetFloat(nextMap, "mixY", mixX2);
|
||||
float mixScaleX2 = GetFloat(nextMap, "mixScaleX", 1), mixScaleY2 = GetFloat(nextMap, "mixScaleY", mixScaleX2);
|
||||
if (keyMap.ContainsKey("curve")) {
|
||||
object curve = keyMap["curve"];
|
||||
bezier = ReadCurve(curve, timeline, bezier, frame, 0, time, time2, rotateMix, rotateMix2, 1);
|
||||
bezier = ReadCurve(curve, timeline, bezier, frame, 1, time, time2, translateMix, translateMix2, 1);
|
||||
bezier = ReadCurve(curve, timeline, bezier, frame, 2, time, time2, scaleMix, scaleMix2, 1);
|
||||
bezier = ReadCurve(curve, timeline, bezier, frame, 3, time, time2, shearMix, shearMix2, 1);
|
||||
bezier = ReadCurve(curve, timeline, bezier, frame, 0, time, time2, mixRotate, mixRotate2, 1);
|
||||
bezier = ReadCurve(curve, timeline, bezier, frame, 1, time, time2, mixX, mixX2, 1);
|
||||
bezier = ReadCurve(curve, timeline, bezier, frame, 2, time, time2, mixY, mixY2, 1);
|
||||
bezier = ReadCurve(curve, timeline, bezier, frame, 3, time, time2, mixScaleX, mixScaleX2, 1);
|
||||
bezier = ReadCurve(curve, timeline, bezier, frame, 4, time, time2, mixScaleY, mixScaleY2, 1);
|
||||
bezier = ReadCurve(curve, timeline, bezier, frame, 5, time, time2, mixShearY, mixShearY2, 1);
|
||||
}
|
||||
time = time2;
|
||||
rotateMix = rotateMix2;
|
||||
translateMix = translateMix2;
|
||||
scaleMix = scaleMix2;
|
||||
shearMix = shearMix2;
|
||||
mixRotate = mixRotate2;
|
||||
mixX = mixX2;
|
||||
mixY = mixY2;
|
||||
mixScaleX = mixScaleX2;
|
||||
mixScaleY = mixScaleY2;
|
||||
mixScaleX = mixScaleX2;
|
||||
keyMap = nextMap;
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
@ -903,8 +913,35 @@ namespace Spine {
|
||||
data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed ? scale : 1));
|
||||
}
|
||||
else if (timelineName == "mix") {
|
||||
CurveTimeline2 timeline = new PathConstraintMixTimeline(values.Count, values.Count << 1, index);
|
||||
timelines.Add(ReadTimeline(ref keyMapEnumerator, timeline, "rotateMix", "translateMix", 1, 1));
|
||||
PathConstraintMixTimeline timeline = new PathConstraintMixTimeline(values.Count, values.Count * 3, index);
|
||||
var keyMap = (Dictionary<string, Object>)keyMapEnumerator.Current;
|
||||
float time = GetFloat(keyMap, "time", 0);
|
||||
float mixRotate = GetFloat(keyMap, "mixRotate", 1);
|
||||
float mixX = GetFloat(keyMap, "mixX", 1), mixY = GetFloat(keyMap, "mixY", mixX);
|
||||
for (int frame = 0, bezier = 0; ; frame++) {
|
||||
timeline.SetFrame(frame, time, mixRotate, mixX, mixY);
|
||||
hasNext = keyMapEnumerator.MoveNext();
|
||||
if (!hasNext) {
|
||||
timeline.Shrink(bezier);
|
||||
break;
|
||||
}
|
||||
var nextMap = (Dictionary<string, Object>)keyMapEnumerator.Current;
|
||||
float time2 = GetFloat(nextMap, "time", 0);
|
||||
float mixRotate2 = GetFloat(nextMap, "mixRotate", 1);
|
||||
float mixX2 = GetFloat(nextMap, "mixX", 1), mixY2 = GetFloat(nextMap, "mixY", mixX2);
|
||||
if (keyMap.ContainsKey("curve")) {
|
||||
object curve = keyMap["curve"];
|
||||
bezier = ReadCurve(curve, timeline, bezier, frame, 0, time, time2, mixRotate, mixRotate2, 1);
|
||||
bezier = ReadCurve(curve, timeline, bezier, frame, 1, time, time2, mixX, mixX2, 1);
|
||||
bezier = ReadCurve(curve, timeline, bezier, frame, 2, time, time2, mixY, mixY2, 1);
|
||||
}
|
||||
time = time2;
|
||||
mixRotate = mixRotate2;
|
||||
mixX = mixX2;
|
||||
mixY = mixY2;
|
||||
keyMap = nextMap;
|
||||
}
|
||||
timelines.Add(timeline);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ namespace Spine {
|
||||
internal TransformConstraintData data;
|
||||
internal ExposedList<Bone> bones;
|
||||
internal Bone target;
|
||||
internal float rotateMix, translateMix, scaleMix, shearMix;
|
||||
internal float mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY;
|
||||
|
||||
internal bool active;
|
||||
|
||||
@ -49,11 +49,12 @@ namespace Spine {
|
||||
if (data == null) throw new ArgumentNullException("data", "data cannot be null.");
|
||||
if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null.");
|
||||
this.data = data;
|
||||
rotateMix = data.rotateMix;
|
||||
translateMix = data.translateMix;
|
||||
scaleMix = data.scaleMix;
|
||||
shearMix = data.shearMix;
|
||||
|
||||
mixRotate = data.mixRotate;
|
||||
mixX = data.mixX;
|
||||
mixY = data.mixY;
|
||||
mixScaleX = data.mixScaleX;
|
||||
mixScaleY = data.mixScaleY;
|
||||
mixShearY = data.mixShearY;
|
||||
bones = new ExposedList<Bone>();
|
||||
foreach (BoneData boneData in data.bones)
|
||||
bones.Add (skeleton.FindBone(boneData.name));
|
||||
@ -70,14 +71,16 @@ namespace Spine {
|
||||
foreach (Bone bone in constraint.Bones)
|
||||
bones.Add(skeleton.Bones.Items[bone.data.index]);
|
||||
target = skeleton.Bones.Items[constraint.target.data.index];
|
||||
rotateMix = constraint.rotateMix;
|
||||
translateMix = constraint.translateMix;
|
||||
scaleMix = constraint.scaleMix;
|
||||
shearMix = constraint.shearMix;
|
||||
mixRotate = constraint.mixRotate;
|
||||
mixX = constraint.mixX;
|
||||
mixY = constraint.mixY;
|
||||
mixScaleX = constraint.mixScaleX;
|
||||
mixScaleY = constraint.mixScaleY;
|
||||
mixShearY = constraint.mixShearY;
|
||||
}
|
||||
|
||||
public void Update () {
|
||||
if (rotateMix == 0 && translateMix == 0 && scaleMix == 0 && shearMix == 0) return;
|
||||
if (mixRotate == 0 && mixX == 0 && mixY == 0 && mixScaleX == 0 && mixScaleX == 0 && mixShearY == 0) return;
|
||||
if (data.local) {
|
||||
if (data.relative)
|
||||
ApplyRelativeLocal();
|
||||
@ -92,22 +95,27 @@ namespace Spine {
|
||||
}
|
||||
|
||||
void ApplyAbsoluteWorld () {
|
||||
float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix;
|
||||
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;
|
||||
|
||||
var bones = this.bones.Items;
|
||||
for (int i = 0, n = this.bones.Count; i < n; i++) {
|
||||
Bone bone = bones[i];
|
||||
|
||||
if (rotateMix != 0) {
|
||||
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 *= rotateMix;
|
||||
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;
|
||||
@ -115,32 +123,35 @@ namespace Spine {
|
||||
bone.d = sin * b + cos * d;
|
||||
}
|
||||
|
||||
if (translateMix != 0) {
|
||||
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) * translateMix;
|
||||
bone.worldY += (ty - bone.worldY) * translateMix;
|
||||
bone.worldX += (tx - bone.worldX) * mixX;
|
||||
bone.worldY += (ty - bone.worldY) * mixY;
|
||||
}
|
||||
|
||||
if (scaleMix > 0) {
|
||||
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) * scaleMix) / s;
|
||||
if (s != 0) s = (s + ((float)Math.Sqrt(ta * ta + tc * tc) - s + data.offsetScaleX) * mixScaleX) / s;
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
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) * scaleMix) / 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 (shearMix > 0) {
|
||||
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) * shearMix;
|
||||
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;
|
||||
@ -151,22 +162,27 @@ namespace Spine {
|
||||
}
|
||||
|
||||
void ApplyRelativeWorld () {
|
||||
float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix;
|
||||
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;
|
||||
|
||||
var bones = this.bones.Items;
|
||||
for (int i = 0, n = this.bones.Count; i < n; i++) {
|
||||
Bone bone = bones[i];
|
||||
|
||||
if (rotateMix != 0) {
|
||||
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 *= rotateMix;
|
||||
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;
|
||||
@ -174,29 +190,32 @@ namespace Spine {
|
||||
bone.d = sin * b + cos * d;
|
||||
}
|
||||
|
||||
if (translateMix != 0) {
|
||||
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 * translateMix;
|
||||
bone.worldY += ty * translateMix;
|
||||
bone.worldX += tx * mixX;
|
||||
bone.worldY += ty * mixY;
|
||||
}
|
||||
|
||||
if (scaleMix > 0) {
|
||||
float s = ((float)Math.Sqrt(ta * ta + tc * tc) - 1 + data.offsetScaleX) * scaleMix + 1;
|
||||
if (mixScaleX != 0) {
|
||||
float s = ((float)Math.Sqrt(ta * ta + tc * tc) - 1 + data.offsetScaleX) * mixScaleX + 1;
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
s = ((float)Math.Sqrt(tb * tb + td * td) - 1 + data.offsetScaleY) * scaleMix + 1;
|
||||
}
|
||||
if (mixScaleY != 0) {
|
||||
float s = ((float)Math.Sqrt(tb * tb + td * td) - 1 + data.offsetScaleY) * mixScaleY + 1;
|
||||
bone.b *= s;
|
||||
bone.d *= s;
|
||||
}
|
||||
|
||||
if (shearMix > 0) {
|
||||
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;
|
||||
else if (r < -MathUtils.PI) //
|
||||
r += MathUtils.PI2;
|
||||
float b = bone.b, d = bone.d;
|
||||
r = MathUtils.Atan2(d, b) + (r - MathUtils.PI / 2 + offsetShearY) * shearMix;
|
||||
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;
|
||||
@ -207,38 +226,39 @@ namespace Spine {
|
||||
}
|
||||
|
||||
void ApplyAbsoluteLocal () {
|
||||
float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix;
|
||||
float mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX,
|
||||
mixScaleY = this.mixScaleY, mixShearY = this.mixShearY;
|
||||
|
||||
Bone target = this.target;
|
||||
if (!target.appliedValid) target.UpdateAppliedTransform();
|
||||
|
||||
var bones = this.bones.Items;
|
||||
for (int i = 0, n = this.bones.Count; i < n; i++) {
|
||||
Bone bone = bones[i];
|
||||
if (!bone.appliedValid) bone.UpdateAppliedTransform();
|
||||
|
||||
float rotation = bone.arotation;
|
||||
if (rotateMix != 0) {
|
||||
if (mixRotate != 0) {
|
||||
float r = target.arotation - rotation + data.offsetRotation;
|
||||
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
|
||||
rotation += r * rotateMix;
|
||||
rotation += r * mixRotate;
|
||||
}
|
||||
|
||||
float x = bone.ax, y = bone.ay;
|
||||
if (translateMix != 0) {
|
||||
x += (target.ax - x + data.offsetX) * translateMix;
|
||||
y += (target.ay - y + data.offsetY) * translateMix;
|
||||
}
|
||||
x += (target.ax - x + data.offsetX) * mixX;
|
||||
y += (target.ay - y + data.offsetY) * mixY;
|
||||
|
||||
float scaleX = bone.ascaleX, scaleY = bone.ascaleY;
|
||||
if (scaleMix != 0) {
|
||||
if (scaleX != 0) scaleX = (scaleX + (target.ascaleX - scaleX + data.offsetScaleX) * scaleMix) / scaleX;
|
||||
if (scaleY != 0) scaleY = (scaleY + (target.ascaleY - scaleY + data.offsetScaleY) * scaleMix) / scaleY;
|
||||
}
|
||||
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 (shearMix != 0) {
|
||||
if (mixShearY != 0) {
|
||||
float r = target.ashearY - shearY + data.offsetShearY;
|
||||
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
|
||||
shearY += r * shearMix;
|
||||
shearY += r * mixShearY;
|
||||
}
|
||||
|
||||
bone.UpdateWorldTransform(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY);
|
||||
@ -246,31 +266,23 @@ namespace Spine {
|
||||
}
|
||||
|
||||
void ApplyRelativeLocal () {
|
||||
float rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix;
|
||||
float mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX,
|
||||
mixScaleY = this.mixScaleY, mixShearY = this.mixShearY;
|
||||
|
||||
Bone target = this.target;
|
||||
if (!target.appliedValid) target.UpdateAppliedTransform();
|
||||
|
||||
var bones = this.bones.Items;
|
||||
for (int i = 0, n = this.bones.Count; i < n; i++) {
|
||||
Bone bone = bones[i];
|
||||
if (!bone.appliedValid) bone.UpdateAppliedTransform();
|
||||
|
||||
float rotation = bone.arotation;
|
||||
if (rotateMix != 0) rotation += (target.arotation + data.offsetRotation) * rotateMix;
|
||||
|
||||
float x = bone.ax, y = bone.ay;
|
||||
if (translateMix != 0) {
|
||||
x += (target.ax + data.offsetX) * translateMix;
|
||||
y += (target.ay + data.offsetY) * translateMix;
|
||||
}
|
||||
|
||||
float scaleX = bone.ascaleX, scaleY = bone.ascaleY;
|
||||
if (scaleMix != 0) {
|
||||
scaleX *= ((target.ascaleX - 1 + data.offsetScaleX) * scaleMix) + 1;
|
||||
scaleY *= ((target.ascaleY - 1 + data.offsetScaleY) * scaleMix) + 1;
|
||||
}
|
||||
|
||||
float shearY = bone.ashearY;
|
||||
if (shearMix != 0) shearY += (target.ashearY + data.offsetShearY) * shearMix;
|
||||
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);
|
||||
}
|
||||
@ -280,14 +292,18 @@ namespace Spine {
|
||||
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>A percentage (0-1) that controls the mix between the constrained and unconstrained rotations.</summary>
|
||||
public float RotateMix { get { return rotateMix; } set { rotateMix = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained translations.</summary>
|
||||
public float TranslateMix { get { return translateMix; } set { translateMix = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained scales.</summary>
|
||||
public float ScaleMix { get { return scaleMix; } set { scaleMix = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained scales.</summary>
|
||||
public float ShearMix { get { return shearMix; } set { shearMix = 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>
|
||||
public float MixX { get { return mixX; } set { mixX = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y.</summary>
|
||||
public float MixY { get { return mixY; } set { mixY = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained scale X.</summary>
|
||||
public float MixScaleX { get { return mixScaleX; } set { mixScaleX = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained scale Y.</summary>
|
||||
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 bool Active { get { return active; } }
|
||||
/// <summary>The transform constraint's setup pose data.</summary>
|
||||
public TransformConstraintData Data { get { return data; } }
|
||||
|
||||
@ -33,16 +33,24 @@ namespace Spine {
|
||||
public class TransformConstraintData : ConstraintData {
|
||||
internal ExposedList<BoneData> bones = new ExposedList<BoneData>();
|
||||
internal BoneData target;
|
||||
internal float rotateMix, translateMix, scaleMix, shearMix;
|
||||
internal float mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY;
|
||||
internal float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY;
|
||||
internal bool relative, local;
|
||||
|
||||
public ExposedList<BoneData> Bones { get { return bones; } }
|
||||
public BoneData Target { get { return target; } set { target = value; } }
|
||||
public float RotateMix { get { return rotateMix; } set { rotateMix = value; } }
|
||||
public float TranslateMix { get { return translateMix; } set { translateMix = value; } }
|
||||
public float ScaleMix { get { return scaleMix; } set { scaleMix = value; } }
|
||||
public float ShearMix { get { return shearMix; } set { shearMix = 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>
|
||||
public float MixX { get { return mixX; } set { mixX = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y.</summary>
|
||||
public float MixY { get { return mixY; } set { mixY = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained scale X.</summary>
|
||||
public float MixScaleX { get { return mixScaleX; } set { mixScaleX = value; } }
|
||||
/// <summary>A percentage (0-1) that controls the mix between the constrained and unconstrained scale Y.</summary>
|
||||
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; } }
|
||||
public float OffsetX { get { return offsetX; } set { offsetX = value; } }
|
||||
|
||||
@ -206,7 +206,7 @@ namespace Spine.Unity.Examples {
|
||||
static TransformConstraintTimeline GetFillerTimeline (TransformConstraintTimeline timeline, SkeletonData skeletonData) {
|
||||
var t = new TransformConstraintTimeline(1, 0, timeline.TransformConstraintIndex);
|
||||
var data = skeletonData.TransformConstraints.Items[timeline.TransformConstraintIndex];
|
||||
t.SetFrame(0, 0, data.RotateMix, data.TranslateMix, data.ScaleMix, data.ShearMix);
|
||||
t.SetFrame(0, 0, data.MixRotate, data.MixX, data.MixY, data.MixScaleX, data.MixScaleY, data.MixShearY);
|
||||
return t;
|
||||
}
|
||||
|
||||
@ -227,7 +227,7 @@ namespace Spine.Unity.Examples {
|
||||
static PathConstraintMixTimeline GetFillerTimeline (PathConstraintMixTimeline timeline, SkeletonData skeletonData) {
|
||||
var t = new PathConstraintMixTimeline(1, 0, timeline.PathConstraintIndex);
|
||||
var data = skeletonData.PathConstraints.Items[timeline.PathConstraintIndex];
|
||||
t.SetFrame(0, 0, data.RotateMix, data.TranslateMix);
|
||||
t.SetFrame(0, 0, data.RotateMix, data.MixX, data.MixY);
|
||||
return t;
|
||||
}
|
||||
#endregion
|
||||
|
||||
@ -212,16 +212,19 @@ namespace Spine.Unity.Examples {
|
||||
if (disableOtherConstraints) {
|
||||
var transformConstraints = skeleton.TransformConstraints;
|
||||
for (int i = 0, n = transformConstraints.Count; i < n; i++) {
|
||||
transformConstraints.Items[i].RotateMix = 0;
|
||||
transformConstraints.Items[i].ScaleMix = 0;
|
||||
transformConstraints.Items[i].ShearMix = 0;
|
||||
transformConstraints.Items[i].TranslateMix = 0;
|
||||
transformConstraints.Items[i].MixRotate = 0;
|
||||
transformConstraints.Items[i].MixScaleX = 0;
|
||||
transformConstraints.Items[i].MixScaleY = 0;
|
||||
transformConstraints.Items[i].MixShearY = 0;
|
||||
transformConstraints.Items[i].MixX = 0;
|
||||
transformConstraints.Items[i].MixY = 0;
|
||||
}
|
||||
|
||||
var pathConstraints = skeleton.PathConstraints;
|
||||
for (int i = 0, n = pathConstraints.Count; i < n; i++) {
|
||||
pathConstraints.Items[i].RotateMix = 0;
|
||||
pathConstraints.Items[i].TranslateMix = 0;
|
||||
pathConstraints.Items[i].MixRotate = 0;
|
||||
pathConstraints.Items[i].MixX = 0;
|
||||
pathConstraints.Items[i].MixY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -224,16 +224,19 @@ namespace Spine.Unity.Examples {
|
||||
if (disableOtherConstraints) {
|
||||
var transformConstraints = skeleton.TransformConstraints;
|
||||
for (int i = 0, n = transformConstraints.Count; i < n; i++) {
|
||||
transformConstraints.Items[i].RotateMix = 0;
|
||||
transformConstraints.Items[i].ScaleMix = 0;
|
||||
transformConstraints.Items[i].ShearMix = 0;
|
||||
transformConstraints.Items[i].TranslateMix = 0;
|
||||
transformConstraints.Items[i].MixRotate = 0;
|
||||
transformConstraints.Items[i].MixScaleX = 0;
|
||||
transformConstraints.Items[i].MixScaleY = 0;
|
||||
transformConstraints.Items[i].MixShearY = 0;
|
||||
transformConstraints.Items[i].MixX = 0;
|
||||
transformConstraints.Items[i].MixY = 0;
|
||||
}
|
||||
|
||||
var pathConstraints = skeleton.PathConstraints;
|
||||
for (int i = 0, n = pathConstraints.Count; i < n; i++) {
|
||||
pathConstraints.Items[i].RotateMix = 0;
|
||||
pathConstraints.Items[i].TranslateMix = 0;
|
||||
pathConstraints.Items[i].MixRotate = 0;
|
||||
pathConstraints.Items[i].MixX = 0;
|
||||
pathConstraints.Items[i].MixY = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -359,8 +359,9 @@ namespace Spine.Unity.Editor {
|
||||
var targetBone = tc.Target;
|
||||
targetPos = targetBone.GetWorldPosition(transform, skeletonRenderScale);
|
||||
|
||||
if (tc.TranslateMix > 0) {
|
||||
if (tc.TranslateMix != 1f) {
|
||||
if (tc.MixX > 0 || tc.MixY > 0) {
|
||||
if ((tc.MixX > 0 && tc.MixX != 1f) ||
|
||||
(tc.MixY > 0 && tc.MixY != 1f)) {
|
||||
Handles.color = handleColor;
|
||||
foreach (var b in tc.Bones) {
|
||||
pos = b.GetWorldPosition(transform, skeletonRenderScale);
|
||||
@ -416,7 +417,7 @@ namespace Spine.Unity.Editor {
|
||||
// Path Constraints
|
||||
handleColor = SpineHandles.PathColor;
|
||||
foreach (var pc in skeleton.PathConstraints) {
|
||||
active = pc.TranslateMix > 0;
|
||||
active = pc.MixX > 0 || pc.MixY > 0 || pc.MixRotate > 0;
|
||||
if (active)
|
||||
foreach (var b in pc.Bones)
|
||||
SpineHandles.DrawBoneCircle(b.GetWorldPosition(transform, skeletonRenderScale), handleColor, normal, 1f * skeletonRenderScale);
|
||||
|
||||
@ -419,10 +419,12 @@ namespace Spine.Unity.Editor {
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
c.TranslateMix = EditorGUILayout.Slider("TranslateMix", c.TranslateMix, MixMin, MixMax);
|
||||
c.RotateMix = EditorGUILayout.Slider("RotateMix", c.RotateMix, MixMin, MixMax);
|
||||
c.ScaleMix = EditorGUILayout.Slider("ScaleMix", c.ScaleMix, MixMin, MixMax);
|
||||
c.ShearMix = EditorGUILayout.Slider("ShearMix", c.ShearMix, MixMin, MixMax);
|
||||
c.MixX = EditorGUILayout.Slider("Mix Translate X", c.MixX, MixMin, MixMax);
|
||||
c.MixY = EditorGUILayout.Slider("Mix Translate Y", c.MixY, MixMin, MixMax);
|
||||
c.MixRotate = EditorGUILayout.Slider("Mix Rotate", c.MixRotate, MixMin, MixMax);
|
||||
c.MixScaleX = EditorGUILayout.Slider("Mix Scale X", c.MixScaleX, MixMin, MixMax);
|
||||
c.MixScaleY = EditorGUILayout.Slider("Mix Scale Y", c.MixScaleY, MixMin, MixMax);
|
||||
c.MixShearY = EditorGUILayout.Slider("Mix Shear Y", c.MixShearY, MixMin, MixMax);
|
||||
if (EditorGUI.EndChangeCheck()) requireRepaint = true;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
@ -452,8 +454,9 @@ namespace Spine.Unity.Editor {
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
c.RotateMix = EditorGUILayout.Slider("RotateMix", c.RotateMix, MixMin, MixMax);
|
||||
c.TranslateMix = EditorGUILayout.Slider("TranslateMix", c.TranslateMix, MixMin, MixMax);
|
||||
c.MixRotate = EditorGUILayout.Slider("Mix Rotate", c.MixRotate, MixMin, MixMax);
|
||||
c.MixX = EditorGUILayout.Slider("Mix Translate X", c.MixX, MixMin, MixMax);
|
||||
c.MixY = EditorGUILayout.Slider("Mix Translate Y", c.MixY, MixMin, MixMax);
|
||||
c.Position = EditorGUILayout.FloatField("Position", c.Position);
|
||||
c.Spacing = EditorGUILayout.FloatField("Spacing", c.Spacing);
|
||||
if (EditorGUI.EndChangeCheck()) requireRepaint = true;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user