mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-20 17:26:01 +08:00
[csharp] Animation and AnimationState 3.7
This commit is contained in:
parent
83778a76c1
commit
b4c8deb283
@ -50,8 +50,8 @@ namespace Spine {
|
||||
}
|
||||
|
||||
/// <summary>Applies all the animation's timelines to the specified skeleton.</summary>
|
||||
/// <seealso cref="Timeline.Apply(Skeleton, float, float, ExposedList, float, MixPose, MixDirection)"/>
|
||||
public void Apply (Skeleton skeleton, float lastTime, float time, bool loop, ExposedList<Event> events, float alpha, MixPose pose, MixDirection direction) {
|
||||
/// <seealso cref="Timeline.Apply(Skeleton, float, float, ExposedList, float, MixBlend, MixDirection)"/>
|
||||
public void Apply (Skeleton skeleton, float lastTime, float time, bool loop, ExposedList<Event> events, float alpha, MixBlend pose, MixDirection direction) {
|
||||
if (skeleton == null) throw new ArgumentNullException("skeleton", "skeleton cannot be null.");
|
||||
|
||||
if (loop && duration != 0) {
|
||||
@ -113,28 +113,48 @@ namespace Spine {
|
||||
/// value. Between 0 and 1 applies a value between the current or setup pose and the timeline value. By adjusting
|
||||
/// alpha over time, an animation can be mixed in or out. <code>alpha</code> can also be useful to
|
||||
/// apply animations on top of each other (layered).</param>
|
||||
/// <param name="pose">Controls how mixing is applied when alpha is than 1.</param>
|
||||
/// <param name="blend">Controls how mixing is applied when alpha is than 1.</param>
|
||||
/// <param name="direction">Indicates whether the timeline is mixing in or out. Used by timelines which perform instant transitions such as DrawOrderTimeline and AttachmentTimeline.</param>
|
||||
void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> events, float alpha, MixPose pose, MixDirection direction);
|
||||
void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> events, float alpha, MixBlend blend, MixDirection direction);
|
||||
int PropertyId { get; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Controls how a timeline is mixed with the setup or current pose.</summary>
|
||||
/// <seealso cref="Timeline.Apply(Skeleton, float, float, ExposedList, float, MixPose, MixDirection)"/>
|
||||
public enum MixPose {
|
||||
/// <summary> The timeline value is mixed with the setup pose (the current pose is not used).</summary>
|
||||
/// <seealso cref="Timeline.Apply(Skeleton, float, float, ExposedList, float, MixBlend, MixDirection)"/>
|
||||
public enum MixBlend {
|
||||
|
||||
/// <summary> Transitions from the setup value to the timeline value (the current value is not used). Before the first key, the setup value is set..</summary>
|
||||
Setup,
|
||||
/// <summary> The timeline value is mixed with the current pose. The setup pose is used as the timeline value before the first key,
|
||||
/// except for timelines which perform instant transitions, such as DrawOrderTimeline or AttachmentTimeline.</summary>
|
||||
Current,
|
||||
/// <summary> The timeline value is mixed with the current pose. No change is made before the first key (the current pose is kept until the first key).</summary>
|
||||
CurrentLayered
|
||||
|
||||
/// <summary>
|
||||
/// <para>Transitions from the current value to the timeline value. Before the first key, transitions from the current value to
|
||||
/// the setup value. Timelines which perform instant transitions, such as <see cref="DrawOrderTimeline"/> or <see cref="AttachmentTimeline"/>, use the setup value before the first key.</para>
|
||||
/// <para>
|
||||
/// <code>First</code> is intended for the first animations applied, not for animations layered on top of those.</para>
|
||||
/// </summary>
|
||||
First,
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Transitions from the current value to the timeline value. No change is made before the first key (the current value is kept until the first key).</para>
|
||||
/// <para>
|
||||
/// <code>Replace</code> is intended for animations layered on top of others, not for the first animations applied.</para>
|
||||
/// </summary>
|
||||
Replace,
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Transitions from the current value to the current value plus the timeline value. No change is made before the first key (the current value is kept until the first key).</para>
|
||||
/// <para>
|
||||
/// <code>Add</code> is intended for animations layered on top of others, not for the first animations applied.</para>
|
||||
/// </summary>
|
||||
Add
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether a timeline's <code>alpha</code> is mixing out over time toward 0 (the setup or current pose) or mixing in toward 1 (the timeline's pose).</summary>
|
||||
/// <seealso cref="Timeline.Apply(Skeleton, float, float, ExposedList, float, MixPose, MixDirection)"/>
|
||||
/// Indicates whether a timeline's <code>alpha</code> is mixing out over time toward 0 (the setup or current pose value) or mixing in toward 1 (the timeline's value).</summary>
|
||||
/// <seealso cref="Timeline.Apply(Skeleton, float, float, ExposedList, float, MixBlend, MixDirection)"/>
|
||||
public enum MixDirection {
|
||||
In,
|
||||
Out
|
||||
@ -162,7 +182,7 @@ namespace Spine {
|
||||
curves = new float[(frameCount - 1) * BEZIER_SIZE];
|
||||
}
|
||||
|
||||
abstract public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction);
|
||||
abstract public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend pose, MixDirection direction);
|
||||
|
||||
abstract public int PropertyId { get; }
|
||||
|
||||
@ -258,31 +278,38 @@ namespace Spine {
|
||||
frames[frameIndex + ROTATION] = degrees;
|
||||
}
|
||||
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction) {
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend, MixDirection direction) {
|
||||
Bone bone = skeleton.bones.Items[boneIndex];
|
||||
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) {
|
||||
switch (pose) {
|
||||
case MixPose.Setup:
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
bone.rotation = bone.data.rotation;
|
||||
return;
|
||||
case MixPose.Current:
|
||||
float rr = bone.data.rotation - bone.rotation;
|
||||
rr -= (16384 - (int)(16384.499999999996 - rr / 360)) * 360;
|
||||
bone.rotation += rr * alpha;
|
||||
return;
|
||||
case MixBlend.First:
|
||||
float r = bone.data.rotation - bone.rotation;
|
||||
bone.rotation += (r - (16384 - (int)(16384.499999999996 - r / 360)) * 360) * alpha;
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame.
|
||||
if (pose == MixPose.Setup) {
|
||||
bone.rotation = bone.data.rotation + frames[frames.Length + PREV_ROTATION] * alpha;
|
||||
} else {
|
||||
float rr = bone.data.rotation + frames[frames.Length + PREV_ROTATION] - bone.rotation;
|
||||
rr -= (16384 - (int)(16384.499999999996 - rr / 360)) * 360; // Wrap within -180 and 180.
|
||||
bone.rotation += rr * alpha;
|
||||
float r = frames[frames.Length + PREV_ROTATION];
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
bone.rotation = bone.data.rotation + r * alpha;
|
||||
break;
|
||||
case MixBlend.First:
|
||||
case MixBlend.Replace:
|
||||
r += bone.data.rotation - bone.rotation;
|
||||
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
|
||||
goto case MixBlend.Add; // Fall through.
|
||||
|
||||
case MixBlend.Add:
|
||||
bone.rotation += r * alpha;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -292,18 +319,23 @@ namespace Spine {
|
||||
float prevRotation = frames[frame + PREV_ROTATION];
|
||||
float frameTime = frames[frame];
|
||||
float percent = GetCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
float r = frames[frame + ROTATION] - prevRotation;
|
||||
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
|
||||
r = prevRotation + r * percent;
|
||||
if (pose == MixPose.Setup) {
|
||||
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
|
||||
bone.rotation = bone.data.rotation + r * alpha;
|
||||
} else {
|
||||
r = bone.data.rotation + r - bone.rotation;
|
||||
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
|
||||
bone.rotation += r * alpha;
|
||||
{
|
||||
float r = frames[frame + ROTATION] - prevRotation;
|
||||
r = prevRotation + (r - (16384 - (int)(16384.499999999996 - r / 360)) * 360) * percent;
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
bone.rotation = bone.data.rotation + (r - (16384 - (int)(16384.499999999996 - r / 360)) * 360) * alpha;
|
||||
break;
|
||||
case MixBlend.First:
|
||||
case MixBlend.Replace:
|
||||
r += bone.data.rotation - bone.rotation;
|
||||
goto case MixBlend.Add; // Fall through.
|
||||
case MixBlend.Add:
|
||||
bone.rotation += (r - (16384 - (int)(16384.499999999996 - r / 360)) * 360) * alpha;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,17 +367,17 @@ namespace Spine {
|
||||
frames[frameIndex + Y] = y;
|
||||
}
|
||||
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction) {
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend, MixDirection direction) {
|
||||
Bone bone = skeleton.bones.Items[boneIndex];
|
||||
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) {
|
||||
switch (pose) {
|
||||
case MixPose.Setup:
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
bone.x = bone.data.x;
|
||||
bone.y = bone.data.y;
|
||||
return;
|
||||
case MixPose.Current:
|
||||
case MixBlend.First:
|
||||
bone.x += (bone.data.x - bone.x) * alpha;
|
||||
bone.y += (bone.data.y - bone.y) * alpha;
|
||||
return;
|
||||
@ -369,12 +401,20 @@ namespace Spine {
|
||||
x += (frames[frame + X] - x) * percent;
|
||||
y += (frames[frame + Y] - y) * percent;
|
||||
}
|
||||
if (pose == MixPose.Setup) {
|
||||
bone.x = bone.data.x + x * alpha;
|
||||
bone.y = bone.data.y + y * alpha;
|
||||
} else {
|
||||
bone.x += (bone.data.x + x - bone.x) * alpha;
|
||||
bone.y += (bone.data.y + y - bone.y) * alpha;
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
bone.x = bone.data.x + x * alpha;
|
||||
bone.y = bone.data.y + y * alpha;
|
||||
break;
|
||||
case MixBlend.First:
|
||||
case MixBlend.Replace:
|
||||
bone.x += (bone.data.x + x - bone.x) * alpha;
|
||||
bone.y += (bone.data.y + y - bone.y) * alpha;
|
||||
break;
|
||||
case MixBlend.Add:
|
||||
bone.x += x * alpha;
|
||||
bone.y += y * alpha;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -388,17 +428,17 @@ namespace Spine {
|
||||
: base(frameCount) {
|
||||
}
|
||||
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction) {
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend, MixDirection direction) {
|
||||
Bone bone = skeleton.bones.Items[boneIndex];
|
||||
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) {
|
||||
switch (pose) {
|
||||
case MixPose.Setup:
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
bone.scaleX = bone.data.scaleX;
|
||||
bone.scaleY = bone.data.scaleY;
|
||||
return;
|
||||
case MixPose.Current:
|
||||
case MixBlend.First:
|
||||
bone.scaleX += (bone.data.scaleX - bone.scaleX) * alpha;
|
||||
bone.scaleY += (bone.data.scaleY - bone.scaleY) * alpha;
|
||||
return;
|
||||
@ -423,27 +463,61 @@ namespace Spine {
|
||||
y = (y + (frames[frame + Y] - y) * percent) * bone.data.scaleY;
|
||||
}
|
||||
if (alpha == 1) {
|
||||
bone.scaleX = x;
|
||||
bone.scaleY = y;
|
||||
if (blend == MixBlend.Add) {
|
||||
bone.scaleX += x - bone.data.scaleX;
|
||||
bone.scaleY += y - bone.data.scaleY;
|
||||
} else {
|
||||
bone.scaleX = x;
|
||||
bone.scaleY = y;
|
||||
}
|
||||
} else {
|
||||
float bx, by;
|
||||
if (pose == MixPose.Setup) {
|
||||
bx = bone.data.scaleX;
|
||||
by = bone.data.scaleY;
|
||||
} else {
|
||||
bx = bone.scaleX;
|
||||
by = bone.scaleY;
|
||||
}
|
||||
// Mixing out uses sign of setup or current pose, else use sign of key.
|
||||
float bx, by;
|
||||
if (direction == MixDirection.Out) {
|
||||
x = (x >= 0 ? x : -x) * (bx >= 0 ? 1 : -1);
|
||||
y = (y >= 0 ? y : -y) * (by >= 0 ? 1 : -1);
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
bx = bone.data.scaleX;
|
||||
by = bone.data.scaleY;
|
||||
bone.scaleX = bx + (Math.Abs(x) * Math.Sign(bx) - bx) * alpha;
|
||||
bone.scaleY = by + (Math.Abs(y) * Math.Sign(by) - by) * alpha;
|
||||
break;
|
||||
case MixBlend.First:
|
||||
case MixBlend.Replace:
|
||||
bx = bone.scaleX;
|
||||
by = bone.scaleY;
|
||||
bone.scaleX = bx + (Math.Abs(x) * Math.Sign(bx) - bx) * alpha;
|
||||
bone.scaleY = by + (Math.Abs(y) * Math.Sign(by) - by) * alpha;
|
||||
break;
|
||||
case MixBlend.Add:
|
||||
bx = bone.scaleX;
|
||||
by = bone.scaleY;
|
||||
bone.scaleX = bx + (Math.Abs(x) * Math.Sign(bx) - bone.data.scaleX) * alpha;
|
||||
bone.scaleY = by + (Math.Abs(y) * Math.Sign(by) - bone.data.scaleY) * alpha;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
bx = (bx >= 0 ? bx : -bx) * (x >= 0 ? 1 : -1);
|
||||
by = (by >= 0 ? by : -by) * (y >= 0 ? 1 : -1);
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
bx = Math.Abs(bone.data.scaleX) * Math.Sign(x);
|
||||
by = Math.Abs(bone.data.scaleY) * Math.Sign(y);
|
||||
bone.scaleX = bx + (x - bx) * alpha;
|
||||
bone.scaleY = by + (y - by) * alpha;
|
||||
break;
|
||||
case MixBlend.First:
|
||||
case MixBlend.Replace:
|
||||
bx = Math.Abs(bone.scaleX) * Math.Sign(x);
|
||||
by = Math.Abs(bone.scaleY) * Math.Sign(y);
|
||||
bone.scaleX = bx + (x - bx) * alpha;
|
||||
bone.scaleY = by + (y - by) * alpha;
|
||||
break;
|
||||
case MixBlend.Add:
|
||||
bx = Math.Sign(x);
|
||||
by = Math.Sign(y);
|
||||
bone.scaleX = Math.Abs(bone.scaleX) * bx + (x - Math.Abs(bone.data.scaleX) * bx) * alpha;
|
||||
bone.scaleY = Math.Abs(bone.scaleY) * by + (y - Math.Abs(bone.data.scaleY) * by) * alpha;
|
||||
break;
|
||||
}
|
||||
}
|
||||
bone.scaleX = bx + (x - bx) * alpha;
|
||||
bone.scaleY = by + (y - by) * alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -457,16 +531,16 @@ namespace Spine {
|
||||
: base(frameCount) {
|
||||
}
|
||||
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction) {
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend, MixDirection direction) {
|
||||
Bone bone = skeleton.bones.Items[boneIndex];
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) {
|
||||
switch (pose) {
|
||||
case MixPose.Setup:
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
bone.shearX = bone.data.shearX;
|
||||
bone.shearY = bone.data.shearY;
|
||||
return;
|
||||
case MixPose.Current:
|
||||
case MixBlend.First:
|
||||
bone.shearX += (bone.data.shearX - bone.shearX) * alpha;
|
||||
bone.shearY += (bone.data.shearY - bone.shearY) * alpha;
|
||||
return;
|
||||
@ -490,12 +564,20 @@ namespace Spine {
|
||||
x = x + (frames[frame + X] - x) * percent;
|
||||
y = y + (frames[frame + Y] - y) * percent;
|
||||
}
|
||||
if (pose == MixPose.Setup) {
|
||||
bone.shearX = bone.data.shearX + x * alpha;
|
||||
bone.shearY = bone.data.shearY + y * alpha;
|
||||
} else {
|
||||
bone.shearX += (bone.data.shearX + x - bone.shearX) * alpha;
|
||||
bone.shearY += (bone.data.shearY + y - bone.shearY) * alpha;
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
bone.shearX = bone.data.shearX + x * alpha;
|
||||
bone.shearY = bone.data.shearY + y * alpha;
|
||||
break;
|
||||
case MixBlend.First:
|
||||
case MixBlend.Replace:
|
||||
bone.shearX += (bone.data.shearX + x - bone.shearX) * alpha;
|
||||
bone.shearY += (bone.data.shearY + y - bone.shearY) * alpha;
|
||||
break;
|
||||
case MixBlend.Add:
|
||||
bone.shearX += x * alpha;
|
||||
bone.shearY += y * alpha;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -530,19 +612,19 @@ namespace Spine {
|
||||
frames[frameIndex + A] = a;
|
||||
}
|
||||
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction) {
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend, MixDirection direction) {
|
||||
Slot slot = skeleton.slots.Items[slotIndex];
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) {
|
||||
var slotData = slot.data;
|
||||
switch (pose) {
|
||||
case MixPose.Setup:
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
slot.r = slotData.r;
|
||||
slot.g = slotData.g;
|
||||
slot.b = slotData.b;
|
||||
slot.a = slotData.a;
|
||||
return;
|
||||
case MixPose.Current:
|
||||
case MixBlend.First:
|
||||
slot.r += (slot.r - slotData.r) * alpha;
|
||||
slot.g += (slot.g - slotData.g) * alpha;
|
||||
slot.b += (slot.b - slotData.b) * alpha;
|
||||
@ -582,7 +664,7 @@ namespace Spine {
|
||||
slot.a = a;
|
||||
} else {
|
||||
float br, bg, bb, ba;
|
||||
if (pose == MixPose.Setup) {
|
||||
if (blend == MixBlend.Setup) {
|
||||
br = slot.data.r;
|
||||
bg = slot.data.g;
|
||||
bb = slot.data.b;
|
||||
@ -641,13 +723,13 @@ namespace Spine {
|
||||
frames[frameIndex + B2] = b2;
|
||||
}
|
||||
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction) {
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend, MixDirection direction) {
|
||||
Slot slot = skeleton.slots.Items[slotIndex];
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) { // Time is before first frame.
|
||||
var slotData = slot.data;
|
||||
switch (pose) {
|
||||
case MixPose.Setup:
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
// slot.color.set(slot.data.color);
|
||||
// slot.darkColor.set(slot.data.darkColor);
|
||||
slot.r = slotData.r;
|
||||
@ -658,7 +740,7 @@ namespace Spine {
|
||||
slot.g2 = slotData.g2;
|
||||
slot.b2 = slotData.b2;
|
||||
return;
|
||||
case MixPose.Current:
|
||||
case MixBlend.First:
|
||||
slot.r += (slot.r - slotData.r) * alpha;
|
||||
slot.g += (slot.g - slotData.g) * alpha;
|
||||
slot.b += (slot.b - slotData.b) * alpha;
|
||||
@ -713,7 +795,7 @@ namespace Spine {
|
||||
slot.b2 = b2;
|
||||
} else {
|
||||
float br, bg, bb, ba, br2, bg2, bb2;
|
||||
if (pose == MixPose.Setup) {
|
||||
if (blend == MixBlend.Setup) {
|
||||
br = slot.data.r;
|
||||
bg = slot.data.g;
|
||||
bb = slot.data.b;
|
||||
@ -767,10 +849,10 @@ namespace Spine {
|
||||
attachmentNames[frameIndex] = attachmentName;
|
||||
}
|
||||
|
||||
public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction) {
|
||||
public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend, MixDirection direction) {
|
||||
string attachmentName;
|
||||
Slot slot = skeleton.slots.Items[slotIndex];
|
||||
if (direction == MixDirection.Out && pose == MixPose.Setup) {
|
||||
if (direction == MixDirection.Out && blend == MixBlend.Setup) {
|
||||
attachmentName = slot.data.attachmentName;
|
||||
slot.Attachment = attachmentName == null ? null : skeleton.GetAttachment(slotIndex, attachmentName);
|
||||
return;
|
||||
@ -778,7 +860,7 @@ namespace Spine {
|
||||
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) { // Time is before first frame.
|
||||
if (pose == MixPose.Setup) {
|
||||
if (blend == MixBlend.Setup || blend == MixBlend.First) {
|
||||
attachmentName = slot.data.attachmentName;
|
||||
slot.Attachment = attachmentName == null ? null : skeleton.GetAttachment(slotIndex, attachmentName);
|
||||
}
|
||||
@ -823,13 +905,13 @@ namespace Spine {
|
||||
frameVertices[frameIndex] = vertices;
|
||||
}
|
||||
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction) {
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend, MixDirection direction) {
|
||||
Slot slot = skeleton.slots.Items[slotIndex];
|
||||
VertexAttachment vertexAttachment = slot.attachment as VertexAttachment;
|
||||
if (vertexAttachment == null || !vertexAttachment.ApplyDeform(attachment)) return;
|
||||
|
||||
var verticesArray = slot.attachmentVertices;
|
||||
if (verticesArray.Count == 0) alpha = 1;
|
||||
if (verticesArray.Count == 0) blend = MixBlend.Setup;
|
||||
|
||||
float[][] frameVertices = this.frameVertices;
|
||||
int vertexCount = frameVertices[0].Length;
|
||||
@ -838,11 +920,11 @@ namespace Spine {
|
||||
|
||||
if (time < frames[0]) {
|
||||
|
||||
switch (pose) {
|
||||
case MixPose.Setup:
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
verticesArray.Clear();
|
||||
return;
|
||||
case MixPose.Current:
|
||||
case MixBlend.Replace:
|
||||
if (alpha == 1) {
|
||||
verticesArray.Clear();
|
||||
return;
|
||||
@ -877,27 +959,60 @@ namespace Spine {
|
||||
vertices = verticesArray.Items;
|
||||
|
||||
if (time >= frames[frames.Length - 1]) { // Time is after last frame.
|
||||
|
||||
float[] lastVertices = frameVertices[frames.Length - 1];
|
||||
if (alpha == 1) {
|
||||
// Vertex positions or deform offsets, no alpha.
|
||||
Array.Copy(lastVertices, 0, vertices, 0, vertexCount);
|
||||
} else if (pose == MixPose.Setup) {
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, with alpha.
|
||||
float[] setupVertices = vertexAttachment.vertices;
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float setup = setupVertices[i];
|
||||
vertices[i] = setup + (lastVertices[i] - setup) * alpha;
|
||||
if (blend == MixBlend.Add) {
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, no alpha.
|
||||
float[] setupVertices = vertexAttachment.vertices;
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
vertices[i] += lastVertices[i] - setupVertices[i];
|
||||
} else {
|
||||
// Weighted deform offsets, no alpha.
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
vertices[i] += lastVertices[i];
|
||||
}
|
||||
} else {
|
||||
// Weighted deform offsets, with alpha.
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
vertices[i] = lastVertices[i] * alpha;
|
||||
// Vertex positions or deform offsets, no alpha.
|
||||
Array.Copy(lastVertices, 0, vertices, 0, vertexCount);
|
||||
}
|
||||
} else {
|
||||
// Vertex positions or deform offsets, with alpha.
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
vertices[i] += (lastVertices[i] - vertices[i]) * alpha;
|
||||
switch (blend) {
|
||||
case MixBlend.Setup: {
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, with alpha.
|
||||
float[] setupVertices = vertexAttachment.vertices;
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float setup = setupVertices[i];
|
||||
vertices[i] = setup + (lastVertices[i] - setup) * alpha;
|
||||
}
|
||||
} else {
|
||||
// Weighted deform offsets, with alpha.
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
vertices[i] = lastVertices[i] * alpha;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MixBlend.First:
|
||||
case MixBlend.Replace:
|
||||
// Vertex positions or deform offsets, with alpha.
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
vertices[i] += (lastVertices[i] - vertices[i]) * alpha;
|
||||
break;
|
||||
case MixBlend.Add:
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, no alpha.
|
||||
float[] setupVertices = vertexAttachment.vertices;
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
vertices[i] += (lastVertices[i] - setupVertices[i]) * alpha;
|
||||
} else {
|
||||
// Weighted deform offsets, alpha.
|
||||
for (int i = 0; i < vertexCount; i++)
|
||||
vertices[i] += lastVertices[i] * alpha;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -910,31 +1025,73 @@ namespace Spine {
|
||||
float percent = GetCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime));
|
||||
|
||||
if (alpha == 1) {
|
||||
// Vertex positions or deform offsets, no alpha.
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float prev = prevVertices[i];
|
||||
vertices[i] = prev + (nextVertices[i] - prev) * percent;
|
||||
}
|
||||
} else if (pose == MixPose.Setup) {
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, with alpha.
|
||||
var setupVertices = vertexAttachment.vertices;
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float prev = prevVertices[i], setup = setupVertices[i];
|
||||
vertices[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha;
|
||||
if (blend == MixBlend.Add) {
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, no alpha.
|
||||
float[] setupVertices = vertexAttachment.vertices;
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float prev = prevVertices[i];
|
||||
vertices[i] += prev + (nextVertices[i] - prev) * percent - setupVertices[i];
|
||||
}
|
||||
} else {
|
||||
// Weighted deform offsets, no alpha.
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float prev = prevVertices[i];
|
||||
vertices[i] += prev + (nextVertices[i] - prev) * percent;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Weighted deform offsets, with alpha.
|
||||
// Vertex positions or deform offsets, no alpha.
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float prev = prevVertices[i];
|
||||
vertices[i] = (prev + (nextVertices[i] - prev) * percent) * alpha;
|
||||
vertices[i] = prev + (nextVertices[i] - prev) * percent;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Vertex positions or deform offsets, with alpha.
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float prev = prevVertices[i];
|
||||
vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha;
|
||||
switch (blend) {
|
||||
case MixBlend.Setup: {
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, with alpha.
|
||||
float[] setupVertices = vertexAttachment.vertices;
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float prev = prevVertices[i], setup = setupVertices[i];
|
||||
vertices[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha;
|
||||
}
|
||||
} else {
|
||||
// Weighted deform offsets, with alpha.
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float prev = prevVertices[i];
|
||||
vertices[i] = (prev + (nextVertices[i] - prev) * percent) * alpha;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MixBlend.First:
|
||||
case MixBlend.Replace: {
|
||||
// Vertex positions or deform offsets, with alpha.
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float prev = prevVertices[i];
|
||||
vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case MixBlend.Add: {
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, with alpha.
|
||||
float[] setupVertices = vertexAttachment.vertices;
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float prev = prevVertices[i];
|
||||
vertices[i] += (prev + (nextVertices[i] - prev) * percent - setupVertices[i]) * alpha;
|
||||
}
|
||||
} else {
|
||||
// Weighted deform offsets, with alpha.
|
||||
for (int i = 0; i < vertexCount; i++) {
|
||||
float prev = prevVertices[i];
|
||||
vertices[i] += (prev + (nextVertices[i] - prev) * percent) * alpha;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -964,13 +1121,13 @@ namespace Spine {
|
||||
}
|
||||
|
||||
/// <summary>Fires events for frames > lastTime and <= time.</summary>
|
||||
public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction) {
|
||||
public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend, MixDirection direction) {
|
||||
if (firedEvents == null) return;
|
||||
float[] frames = this.frames;
|
||||
int frameCount = frames.Length;
|
||||
|
||||
if (lastTime > time) { // Fire events after last time for looped animations.
|
||||
Apply(skeleton, lastTime, int.MaxValue, firedEvents, alpha, pose, direction);
|
||||
Apply(skeleton, lastTime, int.MaxValue, firedEvents, alpha, blend, direction);
|
||||
lastTime = -1f;
|
||||
} else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame.
|
||||
return;
|
||||
@ -1016,17 +1173,17 @@ namespace Spine {
|
||||
drawOrders[frameIndex] = drawOrder;
|
||||
}
|
||||
|
||||
public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction) {
|
||||
public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend, MixDirection direction) {
|
||||
ExposedList<Slot> drawOrder = skeleton.drawOrder;
|
||||
ExposedList<Slot> slots = skeleton.slots;
|
||||
if (direction == MixDirection.Out && pose == MixPose.Setup) {
|
||||
if (direction == MixDirection.Out && blend == MixBlend.Setup) {
|
||||
Array.Copy(slots.Items, 0, drawOrder.Items, 0, slots.Count);
|
||||
return;
|
||||
}
|
||||
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) {
|
||||
if (pose == MixPose.Setup) Array.Copy(slots.Items, 0, drawOrder.Items, 0, slots.Count);
|
||||
if (blend == MixBlend.Setup || blend == MixBlend.First) Array.Copy(slots.Items, 0, drawOrder.Items, 0, slots.Count);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1078,16 +1235,16 @@ namespace Spine {
|
||||
frames[frameIndex + BEND_DIRECTION] = bendDirection;
|
||||
}
|
||||
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction) {
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend, MixDirection direction) {
|
||||
IkConstraint constraint = skeleton.ikConstraints.Items[ikConstraintIndex];
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) {
|
||||
switch (pose) {
|
||||
case MixPose.Setup:
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
constraint.mix = constraint.data.mix;
|
||||
constraint.bendDirection = constraint.data.bendDirection;
|
||||
return;
|
||||
case MixPose.Current:
|
||||
case MixBlend.First:
|
||||
constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
|
||||
constraint.bendDirection = constraint.data.bendDirection;
|
||||
return;
|
||||
@ -1096,7 +1253,7 @@ namespace Spine {
|
||||
}
|
||||
|
||||
if (time >= frames[frames.Length - ENTRIES]) { // Time is after last frame.
|
||||
if (pose == MixPose.Setup) {
|
||||
if (blend == MixBlend.Setup) {
|
||||
constraint.mix = constraint.data.mix + (frames[frames.Length + PREV_MIX] - constraint.data.mix) * alpha;
|
||||
constraint.bendDirection = direction == MixDirection.Out ? constraint.data.bendDirection
|
||||
: (int)frames[frames.Length + PREV_BEND_DIRECTION];
|
||||
@ -1113,7 +1270,7 @@ namespace Spine {
|
||||
float frameTime = frames[frame];
|
||||
float percent = GetCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
if (pose == MixPose.Setup) {
|
||||
if (blend == MixBlend.Setup) {
|
||||
constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha;
|
||||
constraint.bendDirection = direction == MixDirection.Out ? constraint.data.bendDirection : (int)frames[frame + PREV_BEND_DIRECTION];
|
||||
} else {
|
||||
@ -1152,19 +1309,19 @@ namespace Spine {
|
||||
frames[frameIndex + SHEAR] = shearMix;
|
||||
}
|
||||
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction) {
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixBlend blend, MixDirection direction) {
|
||||
TransformConstraint constraint = skeleton.transformConstraints.Items[transformConstraintIndex];
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) {
|
||||
var data = constraint.data;
|
||||
switch (pose) {
|
||||
case MixPose.Setup:
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
constraint.rotateMix = data.rotateMix;
|
||||
constraint.translateMix = data.translateMix;
|
||||
constraint.scaleMix = data.scaleMix;
|
||||
constraint.shearMix = data.shearMix;
|
||||
return;
|
||||
case MixPose.Current:
|
||||
case MixBlend.First:
|
||||
constraint.rotateMix += (data.rotateMix - constraint.rotateMix) * alpha;
|
||||
constraint.translateMix += (data.translateMix - constraint.translateMix) * alpha;
|
||||
constraint.scaleMix += (data.scaleMix - constraint.scaleMix) * alpha;
|
||||
@ -1197,7 +1354,7 @@ namespace Spine {
|
||||
scale += (frames[frame + SCALE] - scale) * percent;
|
||||
shear += (frames[frame + SHEAR] - shear) * percent;
|
||||
}
|
||||
if (pose == MixPose.Setup) {
|
||||
if (blend == MixBlend.Setup) {
|
||||
TransformConstraintData data = constraint.data;
|
||||
constraint.rotateMix = data.rotateMix + (rotate - data.rotateMix) * alpha;
|
||||
constraint.translateMix = data.translateMix + (translate - data.translateMix) * alpha;
|
||||
@ -1239,15 +1396,15 @@ namespace Spine {
|
||||
frames[frameIndex + VALUE] = value;
|
||||
}
|
||||
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction) {
|
||||
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];
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) {
|
||||
switch (pose) {
|
||||
case MixPose.Setup:
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
constraint.position = constraint.data.position;
|
||||
return;
|
||||
case MixPose.Current:
|
||||
case MixBlend.First:
|
||||
constraint.position += (constraint.data.position - constraint.position) * alpha;
|
||||
return;
|
||||
}
|
||||
@ -1267,7 +1424,7 @@ namespace Spine {
|
||||
|
||||
position += (frames[frame + VALUE] - position) * percent;
|
||||
}
|
||||
if (pose == MixPose.Setup)
|
||||
if (blend == MixBlend.Setup)
|
||||
constraint.position = constraint.data.position + (position - constraint.data.position) * alpha;
|
||||
else
|
||||
constraint.position += (position - constraint.position) * alpha;
|
||||
@ -1283,15 +1440,15 @@ namespace Spine {
|
||||
: base(frameCount) {
|
||||
}
|
||||
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction) {
|
||||
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];
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) {
|
||||
switch (pose) {
|
||||
case MixPose.Setup:
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
constraint.spacing = constraint.data.spacing;
|
||||
return;
|
||||
case MixPose.Current:
|
||||
case MixBlend.First:
|
||||
constraint.spacing += (constraint.data.spacing - constraint.spacing) * alpha;
|
||||
return;
|
||||
}
|
||||
@ -1312,7 +1469,7 @@ namespace Spine {
|
||||
spacing += (frames[frame + VALUE] - spacing) * percent;
|
||||
}
|
||||
|
||||
if (pose == MixPose.Setup)
|
||||
if (blend == MixBlend.Setup)
|
||||
constraint.spacing = constraint.data.spacing + (spacing - constraint.data.spacing) * alpha;
|
||||
else
|
||||
constraint.spacing += (spacing - constraint.spacing) * alpha;
|
||||
@ -1347,16 +1504,16 @@ namespace Spine {
|
||||
frames[frameIndex + TRANSLATE] = translateMix;
|
||||
}
|
||||
|
||||
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha, MixPose pose, MixDirection direction) {
|
||||
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];
|
||||
float[] frames = this.frames;
|
||||
if (time < frames[0]) {
|
||||
switch (pose) {
|
||||
case MixPose.Setup:
|
||||
switch (blend) {
|
||||
case MixBlend.Setup:
|
||||
constraint.rotateMix = constraint.data.rotateMix;
|
||||
constraint.translateMix = constraint.data.translateMix;
|
||||
return;
|
||||
case MixPose.Current:
|
||||
case MixBlend.First:
|
||||
constraint.rotateMix += (constraint.data.rotateMix - constraint.rotateMix) * alpha;
|
||||
constraint.translateMix += (constraint.data.translateMix - constraint.translateMix) * alpha;
|
||||
return;
|
||||
@ -1381,7 +1538,7 @@ namespace Spine {
|
||||
translate += (frames[frame + TRANSLATE] - translate) * percent;
|
||||
}
|
||||
|
||||
if (pose == MixPose.Setup) {
|
||||
if (blend == MixBlend.Setup) {
|
||||
constraint.rotateMix = constraint.data.rotateMix + (rotate - constraint.data.rotateMix) * alpha;
|
||||
constraint.translateMix = constraint.data.translateMix + (translate - constraint.data.translateMix) * alpha;
|
||||
} else {
|
||||
|
||||
@ -54,13 +54,13 @@ namespace Spine {
|
||||
public ExposedList<TrackEntry> Tracks { get { return tracks; } }
|
||||
public float TimeScale { get { return timeScale; } set { timeScale = value; } }
|
||||
|
||||
public delegate void TrackEntryDelegate (TrackEntry trackEntry);
|
||||
public delegate void TrackEntryDelegate(TrackEntry trackEntry);
|
||||
public event TrackEntryDelegate Start, Interrupt, End, Dispose, Complete;
|
||||
|
||||
public delegate void TrackEntryEventDelegate (TrackEntry trackEntry, Event e);
|
||||
public delegate void TrackEntryEventDelegate(TrackEntry trackEntry, Event e);
|
||||
public event TrackEntryEventDelegate Event;
|
||||
|
||||
public AnimationState (AnimationStateData data) {
|
||||
public AnimationState(AnimationStateData data) {
|
||||
if (data == null) throw new ArgumentNullException("data", "data cannot be null.");
|
||||
this.data = data;
|
||||
this.queue = new EventQueue(
|
||||
@ -171,12 +171,13 @@ namespace Spine {
|
||||
TrackEntry current = tracksItems[i];
|
||||
if (current == null || current.delay > 0) continue;
|
||||
applied = true;
|
||||
MixPose currentPose = i == 0 ? MixPose.Current : MixPose.CurrentLayered;
|
||||
|
||||
MixBlend blend = i == 0 ? MixBlend.First : current.mixBlend;
|
||||
|
||||
// Apply mixing from entries first.
|
||||
float mix = current.alpha;
|
||||
if (current.mixingFrom != null)
|
||||
mix *= ApplyMixingFrom(current, skeleton, currentPose);
|
||||
mix *= ApplyMixingFrom(current, skeleton, blend);
|
||||
else if (current.trackTime >= current.trackEnd && current.next == null) //
|
||||
mix = 0; // Set to setup pose the last time the entry will be applied.
|
||||
|
||||
@ -185,9 +186,9 @@ namespace Spine {
|
||||
int timelineCount = current.animation.timelines.Count;
|
||||
var timelines = current.animation.timelines;
|
||||
var timelinesItems = timelines.Items;
|
||||
if (mix == 1) {
|
||||
if (mix == 1 || blend == MixBlend.Add) {
|
||||
for (int ii = 0; ii < timelineCount; ii++)
|
||||
timelinesItems[ii].Apply(skeleton, animationLast, animationTime, events, 1, MixPose.Setup, MixDirection.In);
|
||||
timelinesItems[ii].Apply(skeleton, animationLast, animationTime, events, mix, blend, MixDirection.In);
|
||||
} else {
|
||||
var timelineData = current.timelineData.Items;
|
||||
|
||||
@ -197,12 +198,12 @@ namespace Spine {
|
||||
|
||||
for (int ii = 0; ii < timelineCount; ii++) {
|
||||
Timeline timeline = timelinesItems[ii];
|
||||
MixPose pose = timelineData[ii] >= AnimationState.First ? MixPose.Setup : currentPose;
|
||||
MixBlend timelineBlend = timelineData[ii] >= AnimationState.Subsequent ? blend : MixBlend.Setup;
|
||||
var rotateTimeline = timeline as RotateTimeline;
|
||||
if (rotateTimeline != null)
|
||||
ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, pose, timelinesRotation, ii << 1, firstFrame);
|
||||
ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);
|
||||
else
|
||||
timeline.Apply(skeleton, animationLast, animationTime, events, mix, pose, MixDirection.In);
|
||||
timeline.Apply(skeleton, animationLast, animationTime, events, mix, timelineBlend, MixDirection.In);
|
||||
}
|
||||
}
|
||||
QueueEvents(current, animationTime);
|
||||
@ -215,17 +216,18 @@ namespace Spine {
|
||||
return applied;
|
||||
}
|
||||
|
||||
private float ApplyMixingFrom (TrackEntry to, Skeleton skeleton, MixPose currentPose) {
|
||||
private float ApplyMixingFrom (TrackEntry to, Skeleton skeleton, MixBlend blend) {
|
||||
TrackEntry from = to.mixingFrom;
|
||||
if (from.mixingFrom != null) ApplyMixingFrom(from, skeleton, currentPose);
|
||||
if (from.mixingFrom != null) ApplyMixingFrom(from, skeleton, blend);
|
||||
|
||||
float mix;
|
||||
if (to.mixDuration == 0) { // Single frame mix to undo mixingFrom changes.
|
||||
mix = 1;
|
||||
currentPose = MixPose.Setup;
|
||||
if (blend == MixBlend.First) blend = MixBlend.Setup; // Tracks > 0 are transparent and can't reset to setup pose.
|
||||
} else {
|
||||
mix = to.mixTime / to.mixDuration;
|
||||
if (mix > 1) mix = 1;
|
||||
if (blend != MixBlend.First) blend = from.mixBlend; // Track 0 ignores frack mix blend.
|
||||
}
|
||||
|
||||
var eventBuffer = mix < from.eventThreshold ? this.events : null;
|
||||
@ -234,45 +236,55 @@ namespace Spine {
|
||||
var timelines = from.animation.timelines;
|
||||
int timelineCount = timelines.Count;
|
||||
var timelinesItems = timelines.Items;
|
||||
var timelineData = from.timelineData.Items;
|
||||
var timelineDipMix = from.timelineDipMix.Items;
|
||||
float alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix);
|
||||
|
||||
bool firstFrame = from.timelinesRotation.Count == 0;
|
||||
if (firstFrame) from.timelinesRotation.Resize(timelines.Count << 1); // from.timelinesRotation.setSize
|
||||
var timelinesRotation = from.timelinesRotation.Items;
|
||||
if (blend == MixBlend.Add) {
|
||||
for (int i = 0; i < timelineCount; i++)
|
||||
(timelinesItems[i]).Apply(skeleton, animationLast, animationTime, eventBuffer, alphaMix, blend, MixDirection.Out);
|
||||
} else {
|
||||
var timelineData = from.timelineData.Items;
|
||||
var timelineDipMix = from.timelineDipMix.Items;
|
||||
|
||||
MixPose pose;
|
||||
float alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha;
|
||||
from.totalAlpha = 0;
|
||||
for (int i = 0; i < timelineCount; i++) {
|
||||
Timeline timeline = timelinesItems[i];
|
||||
switch (timelineData[i]) {
|
||||
case Subsequent:
|
||||
if (!attachments && timeline is AttachmentTimeline) continue;
|
||||
if (!drawOrder && timeline is DrawOrderTimeline) continue;
|
||||
pose = currentPose;
|
||||
alpha = alphaMix;
|
||||
break;
|
||||
case First:
|
||||
pose = MixPose.Setup;
|
||||
alpha = alphaMix;
|
||||
break;
|
||||
case Dip:
|
||||
pose = MixPose.Setup;
|
||||
alpha = alphaDip;
|
||||
break;
|
||||
default:
|
||||
pose = MixPose.Setup;
|
||||
TrackEntry dipMix = timelineDipMix[i];
|
||||
alpha = alphaDip * Math.Max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
||||
break;
|
||||
}
|
||||
from.totalAlpha += alpha;
|
||||
var rotateTimeline = timeline as RotateTimeline;
|
||||
if (rotateTimeline != null) {
|
||||
ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, alpha, pose, timelinesRotation, i << 1, firstFrame);
|
||||
} else {
|
||||
timeline.Apply(skeleton, animationLast, animationTime, eventBuffer, alpha, pose, MixDirection.Out);
|
||||
bool firstFrame = from.timelinesRotation.Count == 0;
|
||||
if (firstFrame) from.timelinesRotation.Resize(timelines.Count << 1); // from.timelinesRotation.setSize
|
||||
var timelinesRotation = from.timelinesRotation.Items;
|
||||
|
||||
from.totalAlpha = 0;
|
||||
for (int i = 0; i < timelineCount; i++) {
|
||||
Timeline timeline = timelinesItems[i];
|
||||
MixBlend timelineBlend;
|
||||
float alpha;
|
||||
switch (timelineData[i]) {
|
||||
case AnimationState.Subsequent:
|
||||
if (!attachments && timeline is AttachmentTimeline)
|
||||
continue;
|
||||
if (!drawOrder && timeline is DrawOrderTimeline)
|
||||
continue;
|
||||
timelineBlend = blend;
|
||||
alpha = alphaMix;
|
||||
break;
|
||||
case AnimationState.First:
|
||||
timelineBlend = MixBlend.Setup;
|
||||
alpha = alphaMix;
|
||||
break;
|
||||
case AnimationState.Dip:
|
||||
timelineBlend = MixBlend.Setup;
|
||||
alpha = alphaDip;
|
||||
break;
|
||||
default:
|
||||
timelineBlend = MixBlend.Setup;
|
||||
TrackEntry dipMix = timelineDipMix[i];
|
||||
alpha = alphaDip * Math.Max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
|
||||
break;
|
||||
}
|
||||
from.totalAlpha += alpha;
|
||||
|
||||
var rotateTimeline = timeline as RotateTimeline;
|
||||
if (rotateTimeline != null) {
|
||||
ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);
|
||||
} else {
|
||||
timeline.Apply(skeleton, animationLast, animationTime, eventBuffer, alpha, timelineBlend, MixDirection.Out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -284,7 +296,7 @@ namespace Spine {
|
||||
return mix;
|
||||
}
|
||||
|
||||
static private void ApplyRotateTimeline (RotateTimeline rotateTimeline, Skeleton skeleton, float time, float alpha, MixPose pose,
|
||||
static private void ApplyRotateTimeline (RotateTimeline rotateTimeline, Skeleton skeleton, float time, float alpha, MixBlend pose,
|
||||
float[] timelinesRotation, int i, bool firstFrame) {
|
||||
|
||||
if (firstFrame) timelinesRotation[i] = 0;
|
||||
@ -297,7 +309,7 @@ namespace Spine {
|
||||
Bone bone = skeleton.bones.Items[rotateTimeline.boneIndex];
|
||||
float[] frames = rotateTimeline.frames;
|
||||
if (time < frames[0]) {
|
||||
if (pose == MixPose.Setup) bone.rotation = bone.data.rotation;
|
||||
if (pose == MixBlend.Setup) bone.rotation = bone.data.rotation;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -319,7 +331,7 @@ namespace Spine {
|
||||
}
|
||||
|
||||
// Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.
|
||||
float r1 = pose == MixPose.Setup ? bone.data.rotation : bone.rotation;
|
||||
float r1 = pose == MixBlend.Setup ? bone.data.rotation : bone.rotation;
|
||||
float total, diff = r2 - r1;
|
||||
if (diff == 0) {
|
||||
total = timelinesRotation[i];
|
||||
@ -490,8 +502,9 @@ namespace Spine {
|
||||
/// <summary>Adds an animation to be played delay seconds after the current or last queued animation
|
||||
/// for a track. If the track is empty, it is equivalent to calling <see cref="SetAnimation"/>.</summary>
|
||||
/// <param name="delay">
|
||||
/// Seconds to begin this animation after the start of the previous animation. May be <= 0 to use the animation
|
||||
/// duration of the previous track minus any mix duration plus the negative delay.
|
||||
/// delay Seconds to begin this animation after the start of the previous animation. If <= 0, uses the duration of the
|
||||
/// previous track entry minus any mix duration plus the specified<code>delay</code>.If the previous entry is
|
||||
/// looping, its next loop completion is used instead of the duration.
|
||||
/// </param>
|
||||
/// <returns>A track entry to allow further customization of animation playback. References to the track entry must not be kept
|
||||
/// after <see cref="AnimationState.Dispose"/></returns>
|
||||
@ -627,7 +640,7 @@ namespace Spine {
|
||||
var tracksItems = tracks.Items;
|
||||
for (int i = 0, n = tracks.Count; i < n; i++) {
|
||||
var entry = tracksItems[i];
|
||||
if (entry != null) entry.SetTimelineData(null, mixingTo, propertyIDs);
|
||||
if (entry != null && (i == 0 || entry.mixBlend != MixBlend.Add)) entry.SetTimelineData(null, mixingTo, propertyIDs);
|
||||
}
|
||||
}
|
||||
|
||||
@ -667,6 +680,7 @@ namespace Spine {
|
||||
internal float animationStart, animationEnd, animationLast, nextAnimationLast;
|
||||
internal float delay, trackTime, trackLast, nextTrackLast, trackEnd, timeScale = 1f;
|
||||
internal float alpha, mixTime, mixDuration, interruptAlpha, totalAlpha;
|
||||
internal MixBlend mixBlend = MixBlend.Replace;
|
||||
internal readonly ExposedList<int> timelineData = new ExposedList<int>();
|
||||
internal readonly ExposedList<TrackEntry> timelineDipMix = new ExposedList<TrackEntry>();
|
||||
internal readonly ExposedList<float> timelinesRotation = new ExposedList<float>();
|
||||
@ -870,6 +884,17 @@ namespace Spine {
|
||||
/// </summary>
|
||||
public float MixDuration { get { return mixDuration; } set { mixDuration = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// Controls how properties keyed in the animation are mixed with lower tracks. Defaults to {@link MixBlend#replace}, which
|
||||
/// replaces the values from the lower tracks with the animation values. {@link MixBlend#add} adds the animation values to
|
||||
/// the values from the lower tracks.
|
||||
/// <para>
|
||||
/// The<code> mixBlend</code> can be set for a new track entry only before
|
||||
/// <code>AnimationState.Apply(Skeleton)</code> is first called.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public MixBlend MixBlend { get { return mixBlend; } set { mixBlend = value; } }
|
||||
|
||||
/// <summary>
|
||||
/// The track entry for the previous animation when mixing from the previous animation to this animation, or null if no
|
||||
/// mixing is currently occuring. When mixing from multiple animations, MixingFrom makes up a linked list.</summary>
|
||||
@ -885,13 +910,17 @@ namespace Spine {
|
||||
internal void OnEvent (Event e) { if (Event != null) Event(this, e); }
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Resets the rotation directions for mixing this entry's rotate timelines. This can be useful to avoid bones rotating the
|
||||
/// long way around when using <see cref="alpha"/> and starting animations on other tracks.
|
||||
///
|
||||
/// Mixing involves finding a rotation between two others, which has two possible solutions: the short way or the long way around.
|
||||
/// The two rotations likely change over time, so which direction is the short or long way also changes.
|
||||
/// If the short way was always chosen, bones would flip to the other side when that direction became the long way.
|
||||
/// TrackEntry chooses the short way the first time it is applied and remembers that direction.</summary>
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Mixing with <see cref="MixBlend.Replace"/> involves finding a rotation between two others, which has two possible solutions:
|
||||
/// the short way or the long way around.The two rotations likely change over time, so which direction is the short or long
|
||||
/// way also changes.If the short way was always chosen, bones would flip to the other side when that direction became the
|
||||
/// long way. TrackEntry chooses the short way the first time it is applied and remembers that direction.
|
||||
/// </para>
|
||||
/// </summary>
|
||||
public void ResetRotationDirections () {
|
||||
timelinesRotation.Clear();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user