[ts] Ported animation state changes, see #904

This commit is contained in:
badlogic 2017-05-17 11:54:56 +02:00
parent 1af2089157
commit b9b2d81c65
19 changed files with 829 additions and 868 deletions

View File

@ -228,21 +228,24 @@ declare module spine {
declare module spine { declare module spine {
class AnimationState { class AnimationState {
static emptyAnimation: Animation; static emptyAnimation: Animation;
static SUBSEQUENT: number;
static FIRST: number;
static DIP: number;
data: AnimationStateData; data: AnimationStateData;
tracks: TrackEntry[]; tracks: TrackEntry[];
events: Event[]; events: Event[];
listeners: AnimationStateListener2[]; listeners: AnimationStateListener2[];
queue: EventQueue; queue: EventQueue;
propertyIDs: IntSet; propertyIDs: IntSet;
mixingTo: TrackEntry[];
animationsChanged: boolean; animationsChanged: boolean;
multipleMixing: boolean;
timeScale: number; timeScale: number;
trackEntryPool: Pool<TrackEntry>; trackEntryPool: Pool<TrackEntry>;
constructor(data: AnimationStateData); constructor(data: AnimationStateData);
update(delta: number): void; update(delta: number): void;
updateMixingFrom(entry: TrackEntry, delta: number): void; updateMixingFrom(entry: TrackEntry, delta: number, animationCount: number): boolean;
apply(skeleton: Skeleton): void; apply(skeleton: Skeleton): void;
applyMixingFrom(entry: TrackEntry, skeleton: Skeleton): number; applyMixingFrom(to: TrackEntry, skeleton: Skeleton): number;
applyRotateTimeline(timeline: Timeline, skeleton: Skeleton, time: number, alpha: number, setupPose: boolean, timelinesRotation: Array<number>, i: number, firstFrame: boolean): void; applyRotateTimeline(timeline: Timeline, skeleton: Skeleton, time: number, alpha: number, setupPose: boolean, timelinesRotation: Array<number>, i: number, firstFrame: boolean): void;
queueEvents(entry: TrackEntry, animationTime: number): void; queueEvents(entry: TrackEntry, animationTime: number): void;
clearTracks(): void; clearTracks(): void;
@ -259,9 +262,6 @@ declare module spine {
trackEntry(trackIndex: number, animation: Animation, loop: boolean, last: TrackEntry): TrackEntry; trackEntry(trackIndex: number, animation: Animation, loop: boolean, last: TrackEntry): TrackEntry;
disposeNext(entry: TrackEntry): void; disposeNext(entry: TrackEntry): void;
_animationsChanged(): void; _animationsChanged(): void;
setTimelinesFirst(entry: TrackEntry): void;
checkTimelinesFirst(entry: TrackEntry): void;
checkTimelinesUsage(entry: TrackEntry, usageArray: Array<boolean>): void;
getCurrent(trackIndex: number): TrackEntry; getCurrent(trackIndex: number): TrackEntry;
addListener(listener: AnimationStateListener2): void; addListener(listener: AnimationStateListener2): void;
removeListener(listener: AnimationStateListener2): void; removeListener(listener: AnimationStateListener2): void;
@ -291,11 +291,13 @@ declare module spine {
alpha: number; alpha: number;
mixTime: number; mixTime: number;
mixDuration: number; mixDuration: number;
mixAlpha: number; interruptAlpha: number;
timelinesFirst: boolean[]; timelineData: number[];
timelinesLast: boolean[]; timelineDipMix: TrackEntry[];
timelinesRotation: number[]; timelinesRotation: number[];
reset(): void; reset(): void;
setTimelineData(to: TrackEntry, mixingToArray: Array<TrackEntry>, propertyIDs: IntSet): TrackEntry;
hasTimeline(id: number): boolean;
getAnimationTime(): number; getAnimationTime(): number;
setAnimationLast(animationLast: number): void; setAnimationLast(animationLast: number): void;
isComplete(): boolean; isComplete(): boolean;

View File

@ -1056,8 +1056,8 @@ var spine;
this.listeners = new Array(); this.listeners = new Array();
this.queue = new EventQueue(this); this.queue = new EventQueue(this);
this.propertyIDs = new spine.IntSet(); this.propertyIDs = new spine.IntSet();
this.mixingTo = new Array();
this.animationsChanged = false; this.animationsChanged = false;
this.multipleMixing = false;
this.timeScale = 1; this.timeScale = 1;
this.trackEntryPool = new spine.Pool(function () { return new TrackEntry(); }); this.trackEntryPool = new spine.Pool(function () { return new TrackEntry(); });
this.data = data; this.data = data;
@ -1100,25 +1100,35 @@ var spine;
this.disposeNext(current); this.disposeNext(current);
continue; continue;
} }
this.updateMixingFrom(current, delta); if (current.mixingFrom != null && this.updateMixingFrom(current, delta, 2)) {
var from = current.mixingFrom;
current.mixingFrom = null;
while (from != null) {
this.queue.end(from);
from = from.mixingFrom;
}
}
current.trackTime += currentDelta; current.trackTime += currentDelta;
} }
this.queue.drain(); this.queue.drain();
}; };
AnimationState.prototype.updateMixingFrom = function (entry, delta) { AnimationState.prototype.updateMixingFrom = function (entry, delta, animationCount) {
var from = entry.mixingFrom; var from = entry.mixingFrom;
if (from == null) if (from == null)
return; return true;
this.updateMixingFrom(from, delta); var finished = this.updateMixingFrom(from, delta, animationCount + 1);
if (entry.mixTime >= entry.mixDuration && from.mixingFrom == null && entry.mixTime > 0) { if (entry.mixTime > 0 && (entry.mixTime >= entry.mixDuration || entry.timeScale == 0)) {
entry.mixingFrom = null; if (animationCount > 6 && from.mixingFrom == null) {
this.queue.end(from); entry.mixingFrom = null;
return; this.queue.end(from);
}
return finished;
} }
from.animationLast = from.nextAnimationLast; from.animationLast = from.nextAnimationLast;
from.trackLast = from.nextTrackLast; from.trackLast = from.nextTrackLast;
from.trackTime += delta * from.timeScale; from.trackTime += delta * from.timeScale;
entry.mixTime += delta * from.timeScale; entry.mixTime += delta * entry.timeScale;
return false;
}; };
AnimationState.prototype.apply = function (skeleton) { AnimationState.prototype.apply = function (skeleton) {
if (skeleton == null) if (skeleton == null)
@ -1144,18 +1154,18 @@ var spine;
timelines[ii].apply(skeleton, animationLast, animationTime, events, 1, true, false); timelines[ii].apply(skeleton, animationLast, animationTime, events, 1, true, false);
} }
else { else {
var timelineData = current.timelineData;
var firstFrame = current.timelinesRotation.length == 0; var firstFrame = current.timelinesRotation.length == 0;
if (firstFrame) if (firstFrame)
spine.Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null); spine.Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null);
var timelinesRotation = current.timelinesRotation; var timelinesRotation = current.timelinesRotation;
var timelinesFirst = current.timelinesFirst;
for (var ii = 0; ii < timelineCount; ii++) { for (var ii = 0; ii < timelineCount; ii++) {
var timeline = timelines[ii]; var timeline = timelines[ii];
if (timeline instanceof spine.RotateTimeline) { if (timeline instanceof spine.RotateTimeline) {
this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelinesFirst[ii], timelinesRotation, ii << 1, firstFrame); this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineData[ii] > 0, timelinesRotation, ii << 1, firstFrame);
} }
else else
timeline.apply(skeleton, animationLast, animationTime, events, mix, timelinesFirst[ii], false); timeline.apply(skeleton, animationLast, animationTime, events, mix, timelineData[ii] > 0, false);
} }
} }
this.queueEvents(current, animationTime); this.queueEvents(current, animationTime);
@ -1165,15 +1175,15 @@ var spine;
} }
this.queue.drain(); this.queue.drain();
}; };
AnimationState.prototype.applyMixingFrom = function (entry, skeleton) { AnimationState.prototype.applyMixingFrom = function (to, skeleton) {
var from = entry.mixingFrom; var from = to.mixingFrom;
if (from.mixingFrom != null) if (from.mixingFrom != null)
this.applyMixingFrom(from, skeleton); this.applyMixingFrom(from, skeleton);
var mix = 0; var mix = 0;
if (entry.mixDuration == 0) if (to.mixDuration == 0)
mix = 1; mix = 1;
else { else {
mix = entry.mixTime / entry.mixDuration; mix = to.mixTime / to.mixDuration;
if (mix > 1) if (mix > 1)
mix = 1; mix = 1;
} }
@ -1182,31 +1192,46 @@ var spine;
var animationLast = from.animationLast, animationTime = from.getAnimationTime(); var animationLast = from.animationLast, animationTime = from.getAnimationTime();
var timelineCount = from.animation.timelines.length; var timelineCount = from.animation.timelines.length;
var timelines = from.animation.timelines; var timelines = from.animation.timelines;
var timelinesFirst = from.timelinesFirst; var timelineData = from.timelineData;
var timelinesLast = this.multipleMixing ? null : from.timelinesLast; var timelineDipMix = from.timelineDipMix;
var alphaBase = from.alpha * entry.mixAlpha;
var alphaMix = alphaBase * (1 - mix);
var firstFrame = from.timelinesRotation.length == 0; var firstFrame = from.timelinesRotation.length == 0;
if (firstFrame) if (firstFrame)
spine.Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null); spine.Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null);
var timelinesRotation = from.timelinesRotation; var timelinesRotation = from.timelinesRotation;
var first = false;
var alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha;
for (var i = 0; i < timelineCount; i++) { for (var i = 0; i < timelineCount; i++) {
var timeline = timelines[i]; var timeline = timelines[i];
var setupPose = timelinesFirst[i]; switch (timelineData[i]) {
var alpha = timelinesLast != null && setupPose && !timelinesLast[i] ? alphaBase : alphaMix; case AnimationState.SUBSEQUENT:
first = false;
alpha = alphaMix;
break;
case AnimationState.FIRST:
first = true;
alpha = alphaMix;
break;
default:
first = true;
alpha = alphaDip;
var dipMix = timelineDipMix[i];
if (dipMix != null)
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
break;
}
if (timeline instanceof spine.RotateTimeline) if (timeline instanceof spine.RotateTimeline)
this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, setupPose, timelinesRotation, i << 1, firstFrame); this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, first, timelinesRotation, i << 1, firstFrame);
else { else {
if (!setupPose) { if (!first) {
if (!attachments && timeline instanceof spine.AttachmentTimeline) if (!attachments && timeline instanceof spine.AttachmentTimeline)
continue; continue;
if (!drawOrder && timeline instanceof spine.DrawOrderTimeline) if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
continue; continue;
} }
timeline.apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true); timeline.apply(skeleton, animationLast, animationTime, events, alpha, first, true);
} }
} }
if (entry.mixDuration > 0) if (to.mixDuration > 0)
this.queueEvents(from, animationTime); this.queueEvents(from, animationTime);
this.events.length = 0; this.events.length = 0;
from.nextAnimationLast = animationTime; from.nextAnimationLast = animationTime;
@ -1334,25 +1359,8 @@ var spine;
this.queue.interrupt(from); this.queue.interrupt(from);
current.mixingFrom = from; current.mixingFrom = from;
current.mixTime = 0; current.mixTime = 0;
var mixingFrom = from.mixingFrom; if (from.mixingFrom != null && from.mixDuration > 0)
if (mixingFrom != null && from.mixDuration > 0) { current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration);
if (this.multipleMixing) {
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
}
else {
if (from.mixTime / from.mixDuration < 0.5 && mixingFrom.animation != AnimationState.emptyAnimation) {
current.mixingFrom = mixingFrom;
mixingFrom.mixingFrom = from;
mixingFrom.mixTime = from.mixDuration - from.mixTime;
mixingFrom.mixDuration = from.mixDuration;
from.mixingFrom = null;
from = mixingFrom;
}
from.mixAlpha = 0;
from.mixTime = 0;
from.mixDuration = 0;
}
}
from.timelinesRotation.length = 0; from.timelinesRotation.length = 0;
} }
this.queue.start(current); this.queue.start(current);
@ -1468,7 +1476,7 @@ var spine;
entry.trackEnd = Number.MAX_VALUE; entry.trackEnd = Number.MAX_VALUE;
entry.timeScale = 1; entry.timeScale = 1;
entry.alpha = 1; entry.alpha = 1;
entry.mixAlpha = 1; entry.interruptAlpha = 1;
entry.mixTime = 0; entry.mixTime = 0;
entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation); entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation);
return entry; return entry;
@ -1484,74 +1492,17 @@ var spine;
AnimationState.prototype._animationsChanged = function () { AnimationState.prototype._animationsChanged = function () {
this.animationsChanged = false; this.animationsChanged = false;
var propertyIDs = this.propertyIDs; var propertyIDs = this.propertyIDs;
var i = 0, n = this.tracks.length;
propertyIDs.clear(); propertyIDs.clear();
for (; i < n; i++) { var mixingTo = this.mixingTo;
var lastEntry = null;
for (var i = 0, n = this.tracks.length; i < n; i++) {
var entry = this.tracks[i]; var entry = this.tracks[i];
if (entry == null) if (entry != null) {
continue; entry.setTimelineData(lastEntry, mixingTo, propertyIDs);
this.setTimelinesFirst(entry); lastEntry = entry;
i++;
break;
}
for (; i < n; i++) {
var entry = this.tracks[i];
if (entry != null)
this.checkTimelinesFirst(entry);
}
if (this.multipleMixing)
return;
propertyIDs.clear();
var lowestMixingFrom = n;
for (i = 0; i < n; i++) {
var entry = this.tracks[i];
if (entry == null || entry.mixingFrom == null)
continue;
lowestMixingFrom = i;
break;
}
for (i = n - 1; i >= lowestMixingFrom; i--) {
var entry = this.tracks[i];
if (entry == null)
continue;
var timelines = entry.animation.timelines;
for (var ii = 0, nn = entry.animation.timelines.length; ii < nn; ii++)
propertyIDs.add(timelines[ii].getPropertyId());
entry = entry.mixingFrom;
while (entry != null) {
this.checkTimelinesUsage(entry, entry.timelinesLast);
entry = entry.mixingFrom;
} }
} }
}; };
AnimationState.prototype.setTimelinesFirst = function (entry) {
if (entry.mixingFrom != null) {
this.setTimelinesFirst(entry.mixingFrom);
this.checkTimelinesUsage(entry, entry.timelinesFirst);
return;
}
var propertyIDs = this.propertyIDs;
var timelines = entry.animation.timelines;
var n = timelines.length;
var usage = spine.Utils.setArraySize(entry.timelinesFirst, n, false);
for (var i = 0; i < n; i++) {
propertyIDs.add(timelines[i].getPropertyId());
usage[i] = true;
}
};
AnimationState.prototype.checkTimelinesFirst = function (entry) {
if (entry.mixingFrom != null)
this.checkTimelinesFirst(entry.mixingFrom);
this.checkTimelinesUsage(entry, entry.timelinesFirst);
};
AnimationState.prototype.checkTimelinesUsage = function (entry, usageArray) {
var propertyIDs = this.propertyIDs;
var timelines = entry.animation.timelines;
var n = timelines.length;
var usage = spine.Utils.setArraySize(usageArray, n);
for (var i = 0; i < n; i++)
usage[i] = propertyIDs.add(timelines[i].getPropertyId());
};
AnimationState.prototype.getCurrent = function (trackIndex) { AnimationState.prototype.getCurrent = function (trackIndex) {
if (trackIndex >= this.tracks.length) if (trackIndex >= this.tracks.length)
return null; return null;
@ -1576,11 +1527,14 @@ var spine;
return AnimationState; return AnimationState;
}()); }());
AnimationState.emptyAnimation = new spine.Animation("<empty>", [], 0); AnimationState.emptyAnimation = new spine.Animation("<empty>", [], 0);
AnimationState.SUBSEQUENT = 0;
AnimationState.FIRST = 1;
AnimationState.DIP = 2;
spine.AnimationState = AnimationState; spine.AnimationState = AnimationState;
var TrackEntry = (function () { var TrackEntry = (function () {
function TrackEntry() { function TrackEntry() {
this.timelinesFirst = new Array(); this.timelineData = new Array();
this.timelinesLast = new Array(); this.timelineDipMix = new Array();
this.timelinesRotation = new Array(); this.timelinesRotation = new Array();
} }
TrackEntry.prototype.reset = function () { TrackEntry.prototype.reset = function () {
@ -1588,10 +1542,49 @@ var spine;
this.mixingFrom = null; this.mixingFrom = null;
this.animation = null; this.animation = null;
this.listener = null; this.listener = null;
this.timelinesFirst.length = 0; this.timelineData.length = 0;
this.timelinesLast.length = 0; this.timelineDipMix.length = 0;
this.timelinesRotation.length = 0; this.timelinesRotation.length = 0;
}; };
TrackEntry.prototype.setTimelineData = function (to, mixingToArray, propertyIDs) {
if (to != null)
mixingToArray.push(to);
var lastEntry = this.mixingFrom != null ? this.mixingFrom.setTimelineData(this, mixingToArray, propertyIDs) : this;
if (to != null)
mixingToArray.pop();
var mixingTo = mixingToArray;
var mixingToLast = mixingToArray.length - 1;
var timelines = this.animation.timelines;
var timelinesCount = this.animation.timelines.length;
var timelineData = spine.Utils.setArraySize(this.timelineData, timelinesCount);
var timelineDipMix = spine.Utils.setArraySize(this.timelineDipMix, timelinesCount);
outer: for (var i = 0; i < timelinesCount; i++) {
var id = timelines[i].getPropertyId();
if (!propertyIDs.add(id))
timelineData[i] = AnimationState.SUBSEQUENT;
else if (to == null || !to.hasTimeline(id))
timelineData[i] = AnimationState.FIRST;
else {
timelineData[i] = AnimationState.DIP;
for (var ii = mixingToLast; ii >= 0; ii--) {
var entry = mixingTo[ii];
if (!entry.hasTimeline(id)) {
timelineDipMix[i] = entry;
continue outer;
}
}
timelineDipMix[i] = null;
}
}
return lastEntry;
};
TrackEntry.prototype.hasTimeline = function (id) {
var timelines = this.animation.timelines;
for (var i = 0, n = timelines.length; i < n; i++)
if (timelines[i].getPropertyId() == id)
return true;
return false;
};
TrackEntry.prototype.getAnimationTime = function () { TrackEntry.prototype.getAnimationTime = function () {
if (this.loop) { if (this.loop) {
var duration = this.animationEnd - this.animationStart; var duration = this.animationEnd - this.animationStart;

File diff suppressed because one or more lines are too long

View File

@ -228,21 +228,24 @@ declare module spine {
declare module spine { declare module spine {
class AnimationState { class AnimationState {
static emptyAnimation: Animation; static emptyAnimation: Animation;
static SUBSEQUENT: number;
static FIRST: number;
static DIP: number;
data: AnimationStateData; data: AnimationStateData;
tracks: TrackEntry[]; tracks: TrackEntry[];
events: Event[]; events: Event[];
listeners: AnimationStateListener2[]; listeners: AnimationStateListener2[];
queue: EventQueue; queue: EventQueue;
propertyIDs: IntSet; propertyIDs: IntSet;
mixingTo: TrackEntry[];
animationsChanged: boolean; animationsChanged: boolean;
multipleMixing: boolean;
timeScale: number; timeScale: number;
trackEntryPool: Pool<TrackEntry>; trackEntryPool: Pool<TrackEntry>;
constructor(data: AnimationStateData); constructor(data: AnimationStateData);
update(delta: number): void; update(delta: number): void;
updateMixingFrom(entry: TrackEntry, delta: number): void; updateMixingFrom(entry: TrackEntry, delta: number, animationCount: number): boolean;
apply(skeleton: Skeleton): void; apply(skeleton: Skeleton): void;
applyMixingFrom(entry: TrackEntry, skeleton: Skeleton): number; applyMixingFrom(to: TrackEntry, skeleton: Skeleton): number;
applyRotateTimeline(timeline: Timeline, skeleton: Skeleton, time: number, alpha: number, setupPose: boolean, timelinesRotation: Array<number>, i: number, firstFrame: boolean): void; applyRotateTimeline(timeline: Timeline, skeleton: Skeleton, time: number, alpha: number, setupPose: boolean, timelinesRotation: Array<number>, i: number, firstFrame: boolean): void;
queueEvents(entry: TrackEntry, animationTime: number): void; queueEvents(entry: TrackEntry, animationTime: number): void;
clearTracks(): void; clearTracks(): void;
@ -259,9 +262,6 @@ declare module spine {
trackEntry(trackIndex: number, animation: Animation, loop: boolean, last: TrackEntry): TrackEntry; trackEntry(trackIndex: number, animation: Animation, loop: boolean, last: TrackEntry): TrackEntry;
disposeNext(entry: TrackEntry): void; disposeNext(entry: TrackEntry): void;
_animationsChanged(): void; _animationsChanged(): void;
setTimelinesFirst(entry: TrackEntry): void;
checkTimelinesFirst(entry: TrackEntry): void;
checkTimelinesUsage(entry: TrackEntry, usageArray: Array<boolean>): void;
getCurrent(trackIndex: number): TrackEntry; getCurrent(trackIndex: number): TrackEntry;
addListener(listener: AnimationStateListener2): void; addListener(listener: AnimationStateListener2): void;
removeListener(listener: AnimationStateListener2): void; removeListener(listener: AnimationStateListener2): void;
@ -291,11 +291,13 @@ declare module spine {
alpha: number; alpha: number;
mixTime: number; mixTime: number;
mixDuration: number; mixDuration: number;
mixAlpha: number; interruptAlpha: number;
timelinesFirst: boolean[]; timelineData: number[];
timelinesLast: boolean[]; timelineDipMix: TrackEntry[];
timelinesRotation: number[]; timelinesRotation: number[];
reset(): void; reset(): void;
setTimelineData(to: TrackEntry, mixingToArray: Array<TrackEntry>, propertyIDs: IntSet): TrackEntry;
hasTimeline(id: number): boolean;
getAnimationTime(): number; getAnimationTime(): number;
setAnimationLast(animationLast: number): void; setAnimationLast(animationLast: number): void;
isComplete(): boolean; isComplete(): boolean;

View File

@ -1056,8 +1056,8 @@ var spine;
this.listeners = new Array(); this.listeners = new Array();
this.queue = new EventQueue(this); this.queue = new EventQueue(this);
this.propertyIDs = new spine.IntSet(); this.propertyIDs = new spine.IntSet();
this.mixingTo = new Array();
this.animationsChanged = false; this.animationsChanged = false;
this.multipleMixing = false;
this.timeScale = 1; this.timeScale = 1;
this.trackEntryPool = new spine.Pool(function () { return new TrackEntry(); }); this.trackEntryPool = new spine.Pool(function () { return new TrackEntry(); });
this.data = data; this.data = data;
@ -1100,25 +1100,35 @@ var spine;
this.disposeNext(current); this.disposeNext(current);
continue; continue;
} }
this.updateMixingFrom(current, delta); if (current.mixingFrom != null && this.updateMixingFrom(current, delta, 2)) {
var from = current.mixingFrom;
current.mixingFrom = null;
while (from != null) {
this.queue.end(from);
from = from.mixingFrom;
}
}
current.trackTime += currentDelta; current.trackTime += currentDelta;
} }
this.queue.drain(); this.queue.drain();
}; };
AnimationState.prototype.updateMixingFrom = function (entry, delta) { AnimationState.prototype.updateMixingFrom = function (entry, delta, animationCount) {
var from = entry.mixingFrom; var from = entry.mixingFrom;
if (from == null) if (from == null)
return; return true;
this.updateMixingFrom(from, delta); var finished = this.updateMixingFrom(from, delta, animationCount + 1);
if (entry.mixTime >= entry.mixDuration && from.mixingFrom == null && entry.mixTime > 0) { if (entry.mixTime > 0 && (entry.mixTime >= entry.mixDuration || entry.timeScale == 0)) {
entry.mixingFrom = null; if (animationCount > 6 && from.mixingFrom == null) {
this.queue.end(from); entry.mixingFrom = null;
return; this.queue.end(from);
}
return finished;
} }
from.animationLast = from.nextAnimationLast; from.animationLast = from.nextAnimationLast;
from.trackLast = from.nextTrackLast; from.trackLast = from.nextTrackLast;
from.trackTime += delta * from.timeScale; from.trackTime += delta * from.timeScale;
entry.mixTime += delta * from.timeScale; entry.mixTime += delta * entry.timeScale;
return false;
}; };
AnimationState.prototype.apply = function (skeleton) { AnimationState.prototype.apply = function (skeleton) {
if (skeleton == null) if (skeleton == null)
@ -1144,18 +1154,18 @@ var spine;
timelines[ii].apply(skeleton, animationLast, animationTime, events, 1, true, false); timelines[ii].apply(skeleton, animationLast, animationTime, events, 1, true, false);
} }
else { else {
var timelineData = current.timelineData;
var firstFrame = current.timelinesRotation.length == 0; var firstFrame = current.timelinesRotation.length == 0;
if (firstFrame) if (firstFrame)
spine.Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null); spine.Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null);
var timelinesRotation = current.timelinesRotation; var timelinesRotation = current.timelinesRotation;
var timelinesFirst = current.timelinesFirst;
for (var ii = 0; ii < timelineCount; ii++) { for (var ii = 0; ii < timelineCount; ii++) {
var timeline = timelines[ii]; var timeline = timelines[ii];
if (timeline instanceof spine.RotateTimeline) { if (timeline instanceof spine.RotateTimeline) {
this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelinesFirst[ii], timelinesRotation, ii << 1, firstFrame); this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineData[ii] > 0, timelinesRotation, ii << 1, firstFrame);
} }
else else
timeline.apply(skeleton, animationLast, animationTime, events, mix, timelinesFirst[ii], false); timeline.apply(skeleton, animationLast, animationTime, events, mix, timelineData[ii] > 0, false);
} }
} }
this.queueEvents(current, animationTime); this.queueEvents(current, animationTime);
@ -1165,15 +1175,15 @@ var spine;
} }
this.queue.drain(); this.queue.drain();
}; };
AnimationState.prototype.applyMixingFrom = function (entry, skeleton) { AnimationState.prototype.applyMixingFrom = function (to, skeleton) {
var from = entry.mixingFrom; var from = to.mixingFrom;
if (from.mixingFrom != null) if (from.mixingFrom != null)
this.applyMixingFrom(from, skeleton); this.applyMixingFrom(from, skeleton);
var mix = 0; var mix = 0;
if (entry.mixDuration == 0) if (to.mixDuration == 0)
mix = 1; mix = 1;
else { else {
mix = entry.mixTime / entry.mixDuration; mix = to.mixTime / to.mixDuration;
if (mix > 1) if (mix > 1)
mix = 1; mix = 1;
} }
@ -1182,31 +1192,46 @@ var spine;
var animationLast = from.animationLast, animationTime = from.getAnimationTime(); var animationLast = from.animationLast, animationTime = from.getAnimationTime();
var timelineCount = from.animation.timelines.length; var timelineCount = from.animation.timelines.length;
var timelines = from.animation.timelines; var timelines = from.animation.timelines;
var timelinesFirst = from.timelinesFirst; var timelineData = from.timelineData;
var timelinesLast = this.multipleMixing ? null : from.timelinesLast; var timelineDipMix = from.timelineDipMix;
var alphaBase = from.alpha * entry.mixAlpha;
var alphaMix = alphaBase * (1 - mix);
var firstFrame = from.timelinesRotation.length == 0; var firstFrame = from.timelinesRotation.length == 0;
if (firstFrame) if (firstFrame)
spine.Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null); spine.Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null);
var timelinesRotation = from.timelinesRotation; var timelinesRotation = from.timelinesRotation;
var first = false;
var alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha;
for (var i = 0; i < timelineCount; i++) { for (var i = 0; i < timelineCount; i++) {
var timeline = timelines[i]; var timeline = timelines[i];
var setupPose = timelinesFirst[i]; switch (timelineData[i]) {
var alpha = timelinesLast != null && setupPose && !timelinesLast[i] ? alphaBase : alphaMix; case AnimationState.SUBSEQUENT:
first = false;
alpha = alphaMix;
break;
case AnimationState.FIRST:
first = true;
alpha = alphaMix;
break;
default:
first = true;
alpha = alphaDip;
var dipMix = timelineDipMix[i];
if (dipMix != null)
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
break;
}
if (timeline instanceof spine.RotateTimeline) if (timeline instanceof spine.RotateTimeline)
this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, setupPose, timelinesRotation, i << 1, firstFrame); this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, first, timelinesRotation, i << 1, firstFrame);
else { else {
if (!setupPose) { if (!first) {
if (!attachments && timeline instanceof spine.AttachmentTimeline) if (!attachments && timeline instanceof spine.AttachmentTimeline)
continue; continue;
if (!drawOrder && timeline instanceof spine.DrawOrderTimeline) if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
continue; continue;
} }
timeline.apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true); timeline.apply(skeleton, animationLast, animationTime, events, alpha, first, true);
} }
} }
if (entry.mixDuration > 0) if (to.mixDuration > 0)
this.queueEvents(from, animationTime); this.queueEvents(from, animationTime);
this.events.length = 0; this.events.length = 0;
from.nextAnimationLast = animationTime; from.nextAnimationLast = animationTime;
@ -1334,25 +1359,8 @@ var spine;
this.queue.interrupt(from); this.queue.interrupt(from);
current.mixingFrom = from; current.mixingFrom = from;
current.mixTime = 0; current.mixTime = 0;
var mixingFrom = from.mixingFrom; if (from.mixingFrom != null && from.mixDuration > 0)
if (mixingFrom != null && from.mixDuration > 0) { current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration);
if (this.multipleMixing) {
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
}
else {
if (from.mixTime / from.mixDuration < 0.5 && mixingFrom.animation != AnimationState.emptyAnimation) {
current.mixingFrom = mixingFrom;
mixingFrom.mixingFrom = from;
mixingFrom.mixTime = from.mixDuration - from.mixTime;
mixingFrom.mixDuration = from.mixDuration;
from.mixingFrom = null;
from = mixingFrom;
}
from.mixAlpha = 0;
from.mixTime = 0;
from.mixDuration = 0;
}
}
from.timelinesRotation.length = 0; from.timelinesRotation.length = 0;
} }
this.queue.start(current); this.queue.start(current);
@ -1468,7 +1476,7 @@ var spine;
entry.trackEnd = Number.MAX_VALUE; entry.trackEnd = Number.MAX_VALUE;
entry.timeScale = 1; entry.timeScale = 1;
entry.alpha = 1; entry.alpha = 1;
entry.mixAlpha = 1; entry.interruptAlpha = 1;
entry.mixTime = 0; entry.mixTime = 0;
entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation); entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation);
return entry; return entry;
@ -1484,74 +1492,17 @@ var spine;
AnimationState.prototype._animationsChanged = function () { AnimationState.prototype._animationsChanged = function () {
this.animationsChanged = false; this.animationsChanged = false;
var propertyIDs = this.propertyIDs; var propertyIDs = this.propertyIDs;
var i = 0, n = this.tracks.length;
propertyIDs.clear(); propertyIDs.clear();
for (; i < n; i++) { var mixingTo = this.mixingTo;
var lastEntry = null;
for (var i = 0, n = this.tracks.length; i < n; i++) {
var entry = this.tracks[i]; var entry = this.tracks[i];
if (entry == null) if (entry != null) {
continue; entry.setTimelineData(lastEntry, mixingTo, propertyIDs);
this.setTimelinesFirst(entry); lastEntry = entry;
i++;
break;
}
for (; i < n; i++) {
var entry = this.tracks[i];
if (entry != null)
this.checkTimelinesFirst(entry);
}
if (this.multipleMixing)
return;
propertyIDs.clear();
var lowestMixingFrom = n;
for (i = 0; i < n; i++) {
var entry = this.tracks[i];
if (entry == null || entry.mixingFrom == null)
continue;
lowestMixingFrom = i;
break;
}
for (i = n - 1; i >= lowestMixingFrom; i--) {
var entry = this.tracks[i];
if (entry == null)
continue;
var timelines = entry.animation.timelines;
for (var ii = 0, nn = entry.animation.timelines.length; ii < nn; ii++)
propertyIDs.add(timelines[ii].getPropertyId());
entry = entry.mixingFrom;
while (entry != null) {
this.checkTimelinesUsage(entry, entry.timelinesLast);
entry = entry.mixingFrom;
} }
} }
}; };
AnimationState.prototype.setTimelinesFirst = function (entry) {
if (entry.mixingFrom != null) {
this.setTimelinesFirst(entry.mixingFrom);
this.checkTimelinesUsage(entry, entry.timelinesFirst);
return;
}
var propertyIDs = this.propertyIDs;
var timelines = entry.animation.timelines;
var n = timelines.length;
var usage = spine.Utils.setArraySize(entry.timelinesFirst, n, false);
for (var i = 0; i < n; i++) {
propertyIDs.add(timelines[i].getPropertyId());
usage[i] = true;
}
};
AnimationState.prototype.checkTimelinesFirst = function (entry) {
if (entry.mixingFrom != null)
this.checkTimelinesFirst(entry.mixingFrom);
this.checkTimelinesUsage(entry, entry.timelinesFirst);
};
AnimationState.prototype.checkTimelinesUsage = function (entry, usageArray) {
var propertyIDs = this.propertyIDs;
var timelines = entry.animation.timelines;
var n = timelines.length;
var usage = spine.Utils.setArraySize(usageArray, n);
for (var i = 0; i < n; i++)
usage[i] = propertyIDs.add(timelines[i].getPropertyId());
};
AnimationState.prototype.getCurrent = function (trackIndex) { AnimationState.prototype.getCurrent = function (trackIndex) {
if (trackIndex >= this.tracks.length) if (trackIndex >= this.tracks.length)
return null; return null;
@ -1576,11 +1527,14 @@ var spine;
return AnimationState; return AnimationState;
}()); }());
AnimationState.emptyAnimation = new spine.Animation("<empty>", [], 0); AnimationState.emptyAnimation = new spine.Animation("<empty>", [], 0);
AnimationState.SUBSEQUENT = 0;
AnimationState.FIRST = 1;
AnimationState.DIP = 2;
spine.AnimationState = AnimationState; spine.AnimationState = AnimationState;
var TrackEntry = (function () { var TrackEntry = (function () {
function TrackEntry() { function TrackEntry() {
this.timelinesFirst = new Array(); this.timelineData = new Array();
this.timelinesLast = new Array(); this.timelineDipMix = new Array();
this.timelinesRotation = new Array(); this.timelinesRotation = new Array();
} }
TrackEntry.prototype.reset = function () { TrackEntry.prototype.reset = function () {
@ -1588,10 +1542,49 @@ var spine;
this.mixingFrom = null; this.mixingFrom = null;
this.animation = null; this.animation = null;
this.listener = null; this.listener = null;
this.timelinesFirst.length = 0; this.timelineData.length = 0;
this.timelinesLast.length = 0; this.timelineDipMix.length = 0;
this.timelinesRotation.length = 0; this.timelinesRotation.length = 0;
}; };
TrackEntry.prototype.setTimelineData = function (to, mixingToArray, propertyIDs) {
if (to != null)
mixingToArray.push(to);
var lastEntry = this.mixingFrom != null ? this.mixingFrom.setTimelineData(this, mixingToArray, propertyIDs) : this;
if (to != null)
mixingToArray.pop();
var mixingTo = mixingToArray;
var mixingToLast = mixingToArray.length - 1;
var timelines = this.animation.timelines;
var timelinesCount = this.animation.timelines.length;
var timelineData = spine.Utils.setArraySize(this.timelineData, timelinesCount);
var timelineDipMix = spine.Utils.setArraySize(this.timelineDipMix, timelinesCount);
outer: for (var i = 0; i < timelinesCount; i++) {
var id = timelines[i].getPropertyId();
if (!propertyIDs.add(id))
timelineData[i] = AnimationState.SUBSEQUENT;
else if (to == null || !to.hasTimeline(id))
timelineData[i] = AnimationState.FIRST;
else {
timelineData[i] = AnimationState.DIP;
for (var ii = mixingToLast; ii >= 0; ii--) {
var entry = mixingTo[ii];
if (!entry.hasTimeline(id)) {
timelineDipMix[i] = entry;
continue outer;
}
}
timelineDipMix[i] = null;
}
}
return lastEntry;
};
TrackEntry.prototype.hasTimeline = function (id) {
var timelines = this.animation.timelines;
for (var i = 0, n = timelines.length; i < n; i++)
if (timelines[i].getPropertyId() == id)
return true;
return false;
};
TrackEntry.prototype.getAnimationTime = function () { TrackEntry.prototype.getAnimationTime = function () {
if (this.loop) { if (this.loop) {
var duration = this.animationEnd - this.animationStart; var duration = this.animationEnd - this.animationStart;

File diff suppressed because one or more lines are too long

View File

@ -228,21 +228,24 @@ declare module spine {
declare module spine { declare module spine {
class AnimationState { class AnimationState {
static emptyAnimation: Animation; static emptyAnimation: Animation;
static SUBSEQUENT: number;
static FIRST: number;
static DIP: number;
data: AnimationStateData; data: AnimationStateData;
tracks: TrackEntry[]; tracks: TrackEntry[];
events: Event[]; events: Event[];
listeners: AnimationStateListener2[]; listeners: AnimationStateListener2[];
queue: EventQueue; queue: EventQueue;
propertyIDs: IntSet; propertyIDs: IntSet;
mixingTo: TrackEntry[];
animationsChanged: boolean; animationsChanged: boolean;
multipleMixing: boolean;
timeScale: number; timeScale: number;
trackEntryPool: Pool<TrackEntry>; trackEntryPool: Pool<TrackEntry>;
constructor(data: AnimationStateData); constructor(data: AnimationStateData);
update(delta: number): void; update(delta: number): void;
updateMixingFrom(entry: TrackEntry, delta: number): void; updateMixingFrom(entry: TrackEntry, delta: number, animationCount: number): boolean;
apply(skeleton: Skeleton): void; apply(skeleton: Skeleton): void;
applyMixingFrom(entry: TrackEntry, skeleton: Skeleton): number; applyMixingFrom(to: TrackEntry, skeleton: Skeleton): number;
applyRotateTimeline(timeline: Timeline, skeleton: Skeleton, time: number, alpha: number, setupPose: boolean, timelinesRotation: Array<number>, i: number, firstFrame: boolean): void; applyRotateTimeline(timeline: Timeline, skeleton: Skeleton, time: number, alpha: number, setupPose: boolean, timelinesRotation: Array<number>, i: number, firstFrame: boolean): void;
queueEvents(entry: TrackEntry, animationTime: number): void; queueEvents(entry: TrackEntry, animationTime: number): void;
clearTracks(): void; clearTracks(): void;
@ -259,9 +262,6 @@ declare module spine {
trackEntry(trackIndex: number, animation: Animation, loop: boolean, last: TrackEntry): TrackEntry; trackEntry(trackIndex: number, animation: Animation, loop: boolean, last: TrackEntry): TrackEntry;
disposeNext(entry: TrackEntry): void; disposeNext(entry: TrackEntry): void;
_animationsChanged(): void; _animationsChanged(): void;
setTimelinesFirst(entry: TrackEntry): void;
checkTimelinesFirst(entry: TrackEntry): void;
checkTimelinesUsage(entry: TrackEntry, usageArray: Array<boolean>): void;
getCurrent(trackIndex: number): TrackEntry; getCurrent(trackIndex: number): TrackEntry;
addListener(listener: AnimationStateListener2): void; addListener(listener: AnimationStateListener2): void;
removeListener(listener: AnimationStateListener2): void; removeListener(listener: AnimationStateListener2): void;
@ -291,11 +291,13 @@ declare module spine {
alpha: number; alpha: number;
mixTime: number; mixTime: number;
mixDuration: number; mixDuration: number;
mixAlpha: number; interruptAlpha: number;
timelinesFirst: boolean[]; timelineData: number[];
timelinesLast: boolean[]; timelineDipMix: TrackEntry[];
timelinesRotation: number[]; timelinesRotation: number[];
reset(): void; reset(): void;
setTimelineData(to: TrackEntry, mixingToArray: Array<TrackEntry>, propertyIDs: IntSet): TrackEntry;
hasTimeline(id: number): boolean;
getAnimationTime(): number; getAnimationTime(): number;
setAnimationLast(animationLast: number): void; setAnimationLast(animationLast: number): void;
isComplete(): boolean; isComplete(): boolean;

View File

@ -1056,8 +1056,8 @@ var spine;
this.listeners = new Array(); this.listeners = new Array();
this.queue = new EventQueue(this); this.queue = new EventQueue(this);
this.propertyIDs = new spine.IntSet(); this.propertyIDs = new spine.IntSet();
this.mixingTo = new Array();
this.animationsChanged = false; this.animationsChanged = false;
this.multipleMixing = false;
this.timeScale = 1; this.timeScale = 1;
this.trackEntryPool = new spine.Pool(function () { return new TrackEntry(); }); this.trackEntryPool = new spine.Pool(function () { return new TrackEntry(); });
this.data = data; this.data = data;
@ -1100,25 +1100,35 @@ var spine;
this.disposeNext(current); this.disposeNext(current);
continue; continue;
} }
this.updateMixingFrom(current, delta); if (current.mixingFrom != null && this.updateMixingFrom(current, delta, 2)) {
var from = current.mixingFrom;
current.mixingFrom = null;
while (from != null) {
this.queue.end(from);
from = from.mixingFrom;
}
}
current.trackTime += currentDelta; current.trackTime += currentDelta;
} }
this.queue.drain(); this.queue.drain();
}; };
AnimationState.prototype.updateMixingFrom = function (entry, delta) { AnimationState.prototype.updateMixingFrom = function (entry, delta, animationCount) {
var from = entry.mixingFrom; var from = entry.mixingFrom;
if (from == null) if (from == null)
return; return true;
this.updateMixingFrom(from, delta); var finished = this.updateMixingFrom(from, delta, animationCount + 1);
if (entry.mixTime >= entry.mixDuration && from.mixingFrom == null && entry.mixTime > 0) { if (entry.mixTime > 0 && (entry.mixTime >= entry.mixDuration || entry.timeScale == 0)) {
entry.mixingFrom = null; if (animationCount > 6 && from.mixingFrom == null) {
this.queue.end(from); entry.mixingFrom = null;
return; this.queue.end(from);
}
return finished;
} }
from.animationLast = from.nextAnimationLast; from.animationLast = from.nextAnimationLast;
from.trackLast = from.nextTrackLast; from.trackLast = from.nextTrackLast;
from.trackTime += delta * from.timeScale; from.trackTime += delta * from.timeScale;
entry.mixTime += delta * from.timeScale; entry.mixTime += delta * entry.timeScale;
return false;
}; };
AnimationState.prototype.apply = function (skeleton) { AnimationState.prototype.apply = function (skeleton) {
if (skeleton == null) if (skeleton == null)
@ -1144,18 +1154,18 @@ var spine;
timelines[ii].apply(skeleton, animationLast, animationTime, events, 1, true, false); timelines[ii].apply(skeleton, animationLast, animationTime, events, 1, true, false);
} }
else { else {
var timelineData = current.timelineData;
var firstFrame = current.timelinesRotation.length == 0; var firstFrame = current.timelinesRotation.length == 0;
if (firstFrame) if (firstFrame)
spine.Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null); spine.Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null);
var timelinesRotation = current.timelinesRotation; var timelinesRotation = current.timelinesRotation;
var timelinesFirst = current.timelinesFirst;
for (var ii = 0; ii < timelineCount; ii++) { for (var ii = 0; ii < timelineCount; ii++) {
var timeline = timelines[ii]; var timeline = timelines[ii];
if (timeline instanceof spine.RotateTimeline) { if (timeline instanceof spine.RotateTimeline) {
this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelinesFirst[ii], timelinesRotation, ii << 1, firstFrame); this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineData[ii] > 0, timelinesRotation, ii << 1, firstFrame);
} }
else else
timeline.apply(skeleton, animationLast, animationTime, events, mix, timelinesFirst[ii], false); timeline.apply(skeleton, animationLast, animationTime, events, mix, timelineData[ii] > 0, false);
} }
} }
this.queueEvents(current, animationTime); this.queueEvents(current, animationTime);
@ -1165,15 +1175,15 @@ var spine;
} }
this.queue.drain(); this.queue.drain();
}; };
AnimationState.prototype.applyMixingFrom = function (entry, skeleton) { AnimationState.prototype.applyMixingFrom = function (to, skeleton) {
var from = entry.mixingFrom; var from = to.mixingFrom;
if (from.mixingFrom != null) if (from.mixingFrom != null)
this.applyMixingFrom(from, skeleton); this.applyMixingFrom(from, skeleton);
var mix = 0; var mix = 0;
if (entry.mixDuration == 0) if (to.mixDuration == 0)
mix = 1; mix = 1;
else { else {
mix = entry.mixTime / entry.mixDuration; mix = to.mixTime / to.mixDuration;
if (mix > 1) if (mix > 1)
mix = 1; mix = 1;
} }
@ -1182,31 +1192,46 @@ var spine;
var animationLast = from.animationLast, animationTime = from.getAnimationTime(); var animationLast = from.animationLast, animationTime = from.getAnimationTime();
var timelineCount = from.animation.timelines.length; var timelineCount = from.animation.timelines.length;
var timelines = from.animation.timelines; var timelines = from.animation.timelines;
var timelinesFirst = from.timelinesFirst; var timelineData = from.timelineData;
var timelinesLast = this.multipleMixing ? null : from.timelinesLast; var timelineDipMix = from.timelineDipMix;
var alphaBase = from.alpha * entry.mixAlpha;
var alphaMix = alphaBase * (1 - mix);
var firstFrame = from.timelinesRotation.length == 0; var firstFrame = from.timelinesRotation.length == 0;
if (firstFrame) if (firstFrame)
spine.Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null); spine.Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null);
var timelinesRotation = from.timelinesRotation; var timelinesRotation = from.timelinesRotation;
var first = false;
var alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha;
for (var i = 0; i < timelineCount; i++) { for (var i = 0; i < timelineCount; i++) {
var timeline = timelines[i]; var timeline = timelines[i];
var setupPose = timelinesFirst[i]; switch (timelineData[i]) {
var alpha = timelinesLast != null && setupPose && !timelinesLast[i] ? alphaBase : alphaMix; case AnimationState.SUBSEQUENT:
first = false;
alpha = alphaMix;
break;
case AnimationState.FIRST:
first = true;
alpha = alphaMix;
break;
default:
first = true;
alpha = alphaDip;
var dipMix = timelineDipMix[i];
if (dipMix != null)
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
break;
}
if (timeline instanceof spine.RotateTimeline) if (timeline instanceof spine.RotateTimeline)
this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, setupPose, timelinesRotation, i << 1, firstFrame); this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, first, timelinesRotation, i << 1, firstFrame);
else { else {
if (!setupPose) { if (!first) {
if (!attachments && timeline instanceof spine.AttachmentTimeline) if (!attachments && timeline instanceof spine.AttachmentTimeline)
continue; continue;
if (!drawOrder && timeline instanceof spine.DrawOrderTimeline) if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
continue; continue;
} }
timeline.apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true); timeline.apply(skeleton, animationLast, animationTime, events, alpha, first, true);
} }
} }
if (entry.mixDuration > 0) if (to.mixDuration > 0)
this.queueEvents(from, animationTime); this.queueEvents(from, animationTime);
this.events.length = 0; this.events.length = 0;
from.nextAnimationLast = animationTime; from.nextAnimationLast = animationTime;
@ -1334,25 +1359,8 @@ var spine;
this.queue.interrupt(from); this.queue.interrupt(from);
current.mixingFrom = from; current.mixingFrom = from;
current.mixTime = 0; current.mixTime = 0;
var mixingFrom = from.mixingFrom; if (from.mixingFrom != null && from.mixDuration > 0)
if (mixingFrom != null && from.mixDuration > 0) { current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration);
if (this.multipleMixing) {
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
}
else {
if (from.mixTime / from.mixDuration < 0.5 && mixingFrom.animation != AnimationState.emptyAnimation) {
current.mixingFrom = mixingFrom;
mixingFrom.mixingFrom = from;
mixingFrom.mixTime = from.mixDuration - from.mixTime;
mixingFrom.mixDuration = from.mixDuration;
from.mixingFrom = null;
from = mixingFrom;
}
from.mixAlpha = 0;
from.mixTime = 0;
from.mixDuration = 0;
}
}
from.timelinesRotation.length = 0; from.timelinesRotation.length = 0;
} }
this.queue.start(current); this.queue.start(current);
@ -1468,7 +1476,7 @@ var spine;
entry.trackEnd = Number.MAX_VALUE; entry.trackEnd = Number.MAX_VALUE;
entry.timeScale = 1; entry.timeScale = 1;
entry.alpha = 1; entry.alpha = 1;
entry.mixAlpha = 1; entry.interruptAlpha = 1;
entry.mixTime = 0; entry.mixTime = 0;
entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation); entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation);
return entry; return entry;
@ -1484,74 +1492,17 @@ var spine;
AnimationState.prototype._animationsChanged = function () { AnimationState.prototype._animationsChanged = function () {
this.animationsChanged = false; this.animationsChanged = false;
var propertyIDs = this.propertyIDs; var propertyIDs = this.propertyIDs;
var i = 0, n = this.tracks.length;
propertyIDs.clear(); propertyIDs.clear();
for (; i < n; i++) { var mixingTo = this.mixingTo;
var lastEntry = null;
for (var i = 0, n = this.tracks.length; i < n; i++) {
var entry = this.tracks[i]; var entry = this.tracks[i];
if (entry == null) if (entry != null) {
continue; entry.setTimelineData(lastEntry, mixingTo, propertyIDs);
this.setTimelinesFirst(entry); lastEntry = entry;
i++;
break;
}
for (; i < n; i++) {
var entry = this.tracks[i];
if (entry != null)
this.checkTimelinesFirst(entry);
}
if (this.multipleMixing)
return;
propertyIDs.clear();
var lowestMixingFrom = n;
for (i = 0; i < n; i++) {
var entry = this.tracks[i];
if (entry == null || entry.mixingFrom == null)
continue;
lowestMixingFrom = i;
break;
}
for (i = n - 1; i >= lowestMixingFrom; i--) {
var entry = this.tracks[i];
if (entry == null)
continue;
var timelines = entry.animation.timelines;
for (var ii = 0, nn = entry.animation.timelines.length; ii < nn; ii++)
propertyIDs.add(timelines[ii].getPropertyId());
entry = entry.mixingFrom;
while (entry != null) {
this.checkTimelinesUsage(entry, entry.timelinesLast);
entry = entry.mixingFrom;
} }
} }
}; };
AnimationState.prototype.setTimelinesFirst = function (entry) {
if (entry.mixingFrom != null) {
this.setTimelinesFirst(entry.mixingFrom);
this.checkTimelinesUsage(entry, entry.timelinesFirst);
return;
}
var propertyIDs = this.propertyIDs;
var timelines = entry.animation.timelines;
var n = timelines.length;
var usage = spine.Utils.setArraySize(entry.timelinesFirst, n, false);
for (var i = 0; i < n; i++) {
propertyIDs.add(timelines[i].getPropertyId());
usage[i] = true;
}
};
AnimationState.prototype.checkTimelinesFirst = function (entry) {
if (entry.mixingFrom != null)
this.checkTimelinesFirst(entry.mixingFrom);
this.checkTimelinesUsage(entry, entry.timelinesFirst);
};
AnimationState.prototype.checkTimelinesUsage = function (entry, usageArray) {
var propertyIDs = this.propertyIDs;
var timelines = entry.animation.timelines;
var n = timelines.length;
var usage = spine.Utils.setArraySize(usageArray, n);
for (var i = 0; i < n; i++)
usage[i] = propertyIDs.add(timelines[i].getPropertyId());
};
AnimationState.prototype.getCurrent = function (trackIndex) { AnimationState.prototype.getCurrent = function (trackIndex) {
if (trackIndex >= this.tracks.length) if (trackIndex >= this.tracks.length)
return null; return null;
@ -1576,11 +1527,14 @@ var spine;
return AnimationState; return AnimationState;
}()); }());
AnimationState.emptyAnimation = new spine.Animation("<empty>", [], 0); AnimationState.emptyAnimation = new spine.Animation("<empty>", [], 0);
AnimationState.SUBSEQUENT = 0;
AnimationState.FIRST = 1;
AnimationState.DIP = 2;
spine.AnimationState = AnimationState; spine.AnimationState = AnimationState;
var TrackEntry = (function () { var TrackEntry = (function () {
function TrackEntry() { function TrackEntry() {
this.timelinesFirst = new Array(); this.timelineData = new Array();
this.timelinesLast = new Array(); this.timelineDipMix = new Array();
this.timelinesRotation = new Array(); this.timelinesRotation = new Array();
} }
TrackEntry.prototype.reset = function () { TrackEntry.prototype.reset = function () {
@ -1588,10 +1542,49 @@ var spine;
this.mixingFrom = null; this.mixingFrom = null;
this.animation = null; this.animation = null;
this.listener = null; this.listener = null;
this.timelinesFirst.length = 0; this.timelineData.length = 0;
this.timelinesLast.length = 0; this.timelineDipMix.length = 0;
this.timelinesRotation.length = 0; this.timelinesRotation.length = 0;
}; };
TrackEntry.prototype.setTimelineData = function (to, mixingToArray, propertyIDs) {
if (to != null)
mixingToArray.push(to);
var lastEntry = this.mixingFrom != null ? this.mixingFrom.setTimelineData(this, mixingToArray, propertyIDs) : this;
if (to != null)
mixingToArray.pop();
var mixingTo = mixingToArray;
var mixingToLast = mixingToArray.length - 1;
var timelines = this.animation.timelines;
var timelinesCount = this.animation.timelines.length;
var timelineData = spine.Utils.setArraySize(this.timelineData, timelinesCount);
var timelineDipMix = spine.Utils.setArraySize(this.timelineDipMix, timelinesCount);
outer: for (var i = 0; i < timelinesCount; i++) {
var id = timelines[i].getPropertyId();
if (!propertyIDs.add(id))
timelineData[i] = AnimationState.SUBSEQUENT;
else if (to == null || !to.hasTimeline(id))
timelineData[i] = AnimationState.FIRST;
else {
timelineData[i] = AnimationState.DIP;
for (var ii = mixingToLast; ii >= 0; ii--) {
var entry = mixingTo[ii];
if (!entry.hasTimeline(id)) {
timelineDipMix[i] = entry;
continue outer;
}
}
timelineDipMix[i] = null;
}
}
return lastEntry;
};
TrackEntry.prototype.hasTimeline = function (id) {
var timelines = this.animation.timelines;
for (var i = 0, n = timelines.length; i < n; i++)
if (timelines[i].getPropertyId() == id)
return true;
return false;
};
TrackEntry.prototype.getAnimationTime = function () { TrackEntry.prototype.getAnimationTime = function () {
if (this.loop) { if (this.loop) {
var duration = this.animationEnd - this.animationStart; var duration = this.animationEnd - this.animationStart;

File diff suppressed because one or more lines are too long

View File

@ -228,21 +228,24 @@ declare module spine {
declare module spine { declare module spine {
class AnimationState { class AnimationState {
static emptyAnimation: Animation; static emptyAnimation: Animation;
static SUBSEQUENT: number;
static FIRST: number;
static DIP: number;
data: AnimationStateData; data: AnimationStateData;
tracks: TrackEntry[]; tracks: TrackEntry[];
events: Event[]; events: Event[];
listeners: AnimationStateListener2[]; listeners: AnimationStateListener2[];
queue: EventQueue; queue: EventQueue;
propertyIDs: IntSet; propertyIDs: IntSet;
mixingTo: TrackEntry[];
animationsChanged: boolean; animationsChanged: boolean;
multipleMixing: boolean;
timeScale: number; timeScale: number;
trackEntryPool: Pool<TrackEntry>; trackEntryPool: Pool<TrackEntry>;
constructor(data: AnimationStateData); constructor(data: AnimationStateData);
update(delta: number): void; update(delta: number): void;
updateMixingFrom(entry: TrackEntry, delta: number): void; updateMixingFrom(entry: TrackEntry, delta: number, animationCount: number): boolean;
apply(skeleton: Skeleton): void; apply(skeleton: Skeleton): void;
applyMixingFrom(entry: TrackEntry, skeleton: Skeleton): number; applyMixingFrom(to: TrackEntry, skeleton: Skeleton): number;
applyRotateTimeline(timeline: Timeline, skeleton: Skeleton, time: number, alpha: number, setupPose: boolean, timelinesRotation: Array<number>, i: number, firstFrame: boolean): void; applyRotateTimeline(timeline: Timeline, skeleton: Skeleton, time: number, alpha: number, setupPose: boolean, timelinesRotation: Array<number>, i: number, firstFrame: boolean): void;
queueEvents(entry: TrackEntry, animationTime: number): void; queueEvents(entry: TrackEntry, animationTime: number): void;
clearTracks(): void; clearTracks(): void;
@ -259,9 +262,6 @@ declare module spine {
trackEntry(trackIndex: number, animation: Animation, loop: boolean, last: TrackEntry): TrackEntry; trackEntry(trackIndex: number, animation: Animation, loop: boolean, last: TrackEntry): TrackEntry;
disposeNext(entry: TrackEntry): void; disposeNext(entry: TrackEntry): void;
_animationsChanged(): void; _animationsChanged(): void;
setTimelinesFirst(entry: TrackEntry): void;
checkTimelinesFirst(entry: TrackEntry): void;
checkTimelinesUsage(entry: TrackEntry, usageArray: Array<boolean>): void;
getCurrent(trackIndex: number): TrackEntry; getCurrent(trackIndex: number): TrackEntry;
addListener(listener: AnimationStateListener2): void; addListener(listener: AnimationStateListener2): void;
removeListener(listener: AnimationStateListener2): void; removeListener(listener: AnimationStateListener2): void;
@ -291,11 +291,13 @@ declare module spine {
alpha: number; alpha: number;
mixTime: number; mixTime: number;
mixDuration: number; mixDuration: number;
mixAlpha: number; interruptAlpha: number;
timelinesFirst: boolean[]; timelineData: number[];
timelinesLast: boolean[]; timelineDipMix: TrackEntry[];
timelinesRotation: number[]; timelinesRotation: number[];
reset(): void; reset(): void;
setTimelineData(to: TrackEntry, mixingToArray: Array<TrackEntry>, propertyIDs: IntSet): TrackEntry;
hasTimeline(id: number): boolean;
getAnimationTime(): number; getAnimationTime(): number;
setAnimationLast(animationLast: number): void; setAnimationLast(animationLast: number): void;
isComplete(): boolean; isComplete(): boolean;

View File

@ -1056,8 +1056,8 @@ var spine;
this.listeners = new Array(); this.listeners = new Array();
this.queue = new EventQueue(this); this.queue = new EventQueue(this);
this.propertyIDs = new spine.IntSet(); this.propertyIDs = new spine.IntSet();
this.mixingTo = new Array();
this.animationsChanged = false; this.animationsChanged = false;
this.multipleMixing = false;
this.timeScale = 1; this.timeScale = 1;
this.trackEntryPool = new spine.Pool(function () { return new TrackEntry(); }); this.trackEntryPool = new spine.Pool(function () { return new TrackEntry(); });
this.data = data; this.data = data;
@ -1100,25 +1100,35 @@ var spine;
this.disposeNext(current); this.disposeNext(current);
continue; continue;
} }
this.updateMixingFrom(current, delta); if (current.mixingFrom != null && this.updateMixingFrom(current, delta, 2)) {
var from = current.mixingFrom;
current.mixingFrom = null;
while (from != null) {
this.queue.end(from);
from = from.mixingFrom;
}
}
current.trackTime += currentDelta; current.trackTime += currentDelta;
} }
this.queue.drain(); this.queue.drain();
}; };
AnimationState.prototype.updateMixingFrom = function (entry, delta) { AnimationState.prototype.updateMixingFrom = function (entry, delta, animationCount) {
var from = entry.mixingFrom; var from = entry.mixingFrom;
if (from == null) if (from == null)
return; return true;
this.updateMixingFrom(from, delta); var finished = this.updateMixingFrom(from, delta, animationCount + 1);
if (entry.mixTime >= entry.mixDuration && from.mixingFrom == null && entry.mixTime > 0) { if (entry.mixTime > 0 && (entry.mixTime >= entry.mixDuration || entry.timeScale == 0)) {
entry.mixingFrom = null; if (animationCount > 6 && from.mixingFrom == null) {
this.queue.end(from); entry.mixingFrom = null;
return; this.queue.end(from);
}
return finished;
} }
from.animationLast = from.nextAnimationLast; from.animationLast = from.nextAnimationLast;
from.trackLast = from.nextTrackLast; from.trackLast = from.nextTrackLast;
from.trackTime += delta * from.timeScale; from.trackTime += delta * from.timeScale;
entry.mixTime += delta * from.timeScale; entry.mixTime += delta * entry.timeScale;
return false;
}; };
AnimationState.prototype.apply = function (skeleton) { AnimationState.prototype.apply = function (skeleton) {
if (skeleton == null) if (skeleton == null)
@ -1144,18 +1154,18 @@ var spine;
timelines[ii].apply(skeleton, animationLast, animationTime, events, 1, true, false); timelines[ii].apply(skeleton, animationLast, animationTime, events, 1, true, false);
} }
else { else {
var timelineData = current.timelineData;
var firstFrame = current.timelinesRotation.length == 0; var firstFrame = current.timelinesRotation.length == 0;
if (firstFrame) if (firstFrame)
spine.Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null); spine.Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null);
var timelinesRotation = current.timelinesRotation; var timelinesRotation = current.timelinesRotation;
var timelinesFirst = current.timelinesFirst;
for (var ii = 0; ii < timelineCount; ii++) { for (var ii = 0; ii < timelineCount; ii++) {
var timeline = timelines[ii]; var timeline = timelines[ii];
if (timeline instanceof spine.RotateTimeline) { if (timeline instanceof spine.RotateTimeline) {
this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelinesFirst[ii], timelinesRotation, ii << 1, firstFrame); this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineData[ii] > 0, timelinesRotation, ii << 1, firstFrame);
} }
else else
timeline.apply(skeleton, animationLast, animationTime, events, mix, timelinesFirst[ii], false); timeline.apply(skeleton, animationLast, animationTime, events, mix, timelineData[ii] > 0, false);
} }
} }
this.queueEvents(current, animationTime); this.queueEvents(current, animationTime);
@ -1165,15 +1175,15 @@ var spine;
} }
this.queue.drain(); this.queue.drain();
}; };
AnimationState.prototype.applyMixingFrom = function (entry, skeleton) { AnimationState.prototype.applyMixingFrom = function (to, skeleton) {
var from = entry.mixingFrom; var from = to.mixingFrom;
if (from.mixingFrom != null) if (from.mixingFrom != null)
this.applyMixingFrom(from, skeleton); this.applyMixingFrom(from, skeleton);
var mix = 0; var mix = 0;
if (entry.mixDuration == 0) if (to.mixDuration == 0)
mix = 1; mix = 1;
else { else {
mix = entry.mixTime / entry.mixDuration; mix = to.mixTime / to.mixDuration;
if (mix > 1) if (mix > 1)
mix = 1; mix = 1;
} }
@ -1182,31 +1192,46 @@ var spine;
var animationLast = from.animationLast, animationTime = from.getAnimationTime(); var animationLast = from.animationLast, animationTime = from.getAnimationTime();
var timelineCount = from.animation.timelines.length; var timelineCount = from.animation.timelines.length;
var timelines = from.animation.timelines; var timelines = from.animation.timelines;
var timelinesFirst = from.timelinesFirst; var timelineData = from.timelineData;
var timelinesLast = this.multipleMixing ? null : from.timelinesLast; var timelineDipMix = from.timelineDipMix;
var alphaBase = from.alpha * entry.mixAlpha;
var alphaMix = alphaBase * (1 - mix);
var firstFrame = from.timelinesRotation.length == 0; var firstFrame = from.timelinesRotation.length == 0;
if (firstFrame) if (firstFrame)
spine.Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null); spine.Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null);
var timelinesRotation = from.timelinesRotation; var timelinesRotation = from.timelinesRotation;
var first = false;
var alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha;
for (var i = 0; i < timelineCount; i++) { for (var i = 0; i < timelineCount; i++) {
var timeline = timelines[i]; var timeline = timelines[i];
var setupPose = timelinesFirst[i]; switch (timelineData[i]) {
var alpha = timelinesLast != null && setupPose && !timelinesLast[i] ? alphaBase : alphaMix; case AnimationState.SUBSEQUENT:
first = false;
alpha = alphaMix;
break;
case AnimationState.FIRST:
first = true;
alpha = alphaMix;
break;
default:
first = true;
alpha = alphaDip;
var dipMix = timelineDipMix[i];
if (dipMix != null)
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
break;
}
if (timeline instanceof spine.RotateTimeline) if (timeline instanceof spine.RotateTimeline)
this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, setupPose, timelinesRotation, i << 1, firstFrame); this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, first, timelinesRotation, i << 1, firstFrame);
else { else {
if (!setupPose) { if (!first) {
if (!attachments && timeline instanceof spine.AttachmentTimeline) if (!attachments && timeline instanceof spine.AttachmentTimeline)
continue; continue;
if (!drawOrder && timeline instanceof spine.DrawOrderTimeline) if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
continue; continue;
} }
timeline.apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true); timeline.apply(skeleton, animationLast, animationTime, events, alpha, first, true);
} }
} }
if (entry.mixDuration > 0) if (to.mixDuration > 0)
this.queueEvents(from, animationTime); this.queueEvents(from, animationTime);
this.events.length = 0; this.events.length = 0;
from.nextAnimationLast = animationTime; from.nextAnimationLast = animationTime;
@ -1334,25 +1359,8 @@ var spine;
this.queue.interrupt(from); this.queue.interrupt(from);
current.mixingFrom = from; current.mixingFrom = from;
current.mixTime = 0; current.mixTime = 0;
var mixingFrom = from.mixingFrom; if (from.mixingFrom != null && from.mixDuration > 0)
if (mixingFrom != null && from.mixDuration > 0) { current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration);
if (this.multipleMixing) {
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
}
else {
if (from.mixTime / from.mixDuration < 0.5 && mixingFrom.animation != AnimationState.emptyAnimation) {
current.mixingFrom = mixingFrom;
mixingFrom.mixingFrom = from;
mixingFrom.mixTime = from.mixDuration - from.mixTime;
mixingFrom.mixDuration = from.mixDuration;
from.mixingFrom = null;
from = mixingFrom;
}
from.mixAlpha = 0;
from.mixTime = 0;
from.mixDuration = 0;
}
}
from.timelinesRotation.length = 0; from.timelinesRotation.length = 0;
} }
this.queue.start(current); this.queue.start(current);
@ -1468,7 +1476,7 @@ var spine;
entry.trackEnd = Number.MAX_VALUE; entry.trackEnd = Number.MAX_VALUE;
entry.timeScale = 1; entry.timeScale = 1;
entry.alpha = 1; entry.alpha = 1;
entry.mixAlpha = 1; entry.interruptAlpha = 1;
entry.mixTime = 0; entry.mixTime = 0;
entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation); entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation);
return entry; return entry;
@ -1484,74 +1492,17 @@ var spine;
AnimationState.prototype._animationsChanged = function () { AnimationState.prototype._animationsChanged = function () {
this.animationsChanged = false; this.animationsChanged = false;
var propertyIDs = this.propertyIDs; var propertyIDs = this.propertyIDs;
var i = 0, n = this.tracks.length;
propertyIDs.clear(); propertyIDs.clear();
for (; i < n; i++) { var mixingTo = this.mixingTo;
var lastEntry = null;
for (var i = 0, n = this.tracks.length; i < n; i++) {
var entry = this.tracks[i]; var entry = this.tracks[i];
if (entry == null) if (entry != null) {
continue; entry.setTimelineData(lastEntry, mixingTo, propertyIDs);
this.setTimelinesFirst(entry); lastEntry = entry;
i++;
break;
}
for (; i < n; i++) {
var entry = this.tracks[i];
if (entry != null)
this.checkTimelinesFirst(entry);
}
if (this.multipleMixing)
return;
propertyIDs.clear();
var lowestMixingFrom = n;
for (i = 0; i < n; i++) {
var entry = this.tracks[i];
if (entry == null || entry.mixingFrom == null)
continue;
lowestMixingFrom = i;
break;
}
for (i = n - 1; i >= lowestMixingFrom; i--) {
var entry = this.tracks[i];
if (entry == null)
continue;
var timelines = entry.animation.timelines;
for (var ii = 0, nn = entry.animation.timelines.length; ii < nn; ii++)
propertyIDs.add(timelines[ii].getPropertyId());
entry = entry.mixingFrom;
while (entry != null) {
this.checkTimelinesUsage(entry, entry.timelinesLast);
entry = entry.mixingFrom;
} }
} }
}; };
AnimationState.prototype.setTimelinesFirst = function (entry) {
if (entry.mixingFrom != null) {
this.setTimelinesFirst(entry.mixingFrom);
this.checkTimelinesUsage(entry, entry.timelinesFirst);
return;
}
var propertyIDs = this.propertyIDs;
var timelines = entry.animation.timelines;
var n = timelines.length;
var usage = spine.Utils.setArraySize(entry.timelinesFirst, n, false);
for (var i = 0; i < n; i++) {
propertyIDs.add(timelines[i].getPropertyId());
usage[i] = true;
}
};
AnimationState.prototype.checkTimelinesFirst = function (entry) {
if (entry.mixingFrom != null)
this.checkTimelinesFirst(entry.mixingFrom);
this.checkTimelinesUsage(entry, entry.timelinesFirst);
};
AnimationState.prototype.checkTimelinesUsage = function (entry, usageArray) {
var propertyIDs = this.propertyIDs;
var timelines = entry.animation.timelines;
var n = timelines.length;
var usage = spine.Utils.setArraySize(usageArray, n);
for (var i = 0; i < n; i++)
usage[i] = propertyIDs.add(timelines[i].getPropertyId());
};
AnimationState.prototype.getCurrent = function (trackIndex) { AnimationState.prototype.getCurrent = function (trackIndex) {
if (trackIndex >= this.tracks.length) if (trackIndex >= this.tracks.length)
return null; return null;
@ -1576,11 +1527,14 @@ var spine;
return AnimationState; return AnimationState;
}()); }());
AnimationState.emptyAnimation = new spine.Animation("<empty>", [], 0); AnimationState.emptyAnimation = new spine.Animation("<empty>", [], 0);
AnimationState.SUBSEQUENT = 0;
AnimationState.FIRST = 1;
AnimationState.DIP = 2;
spine.AnimationState = AnimationState; spine.AnimationState = AnimationState;
var TrackEntry = (function () { var TrackEntry = (function () {
function TrackEntry() { function TrackEntry() {
this.timelinesFirst = new Array(); this.timelineData = new Array();
this.timelinesLast = new Array(); this.timelineDipMix = new Array();
this.timelinesRotation = new Array(); this.timelinesRotation = new Array();
} }
TrackEntry.prototype.reset = function () { TrackEntry.prototype.reset = function () {
@ -1588,10 +1542,49 @@ var spine;
this.mixingFrom = null; this.mixingFrom = null;
this.animation = null; this.animation = null;
this.listener = null; this.listener = null;
this.timelinesFirst.length = 0; this.timelineData.length = 0;
this.timelinesLast.length = 0; this.timelineDipMix.length = 0;
this.timelinesRotation.length = 0; this.timelinesRotation.length = 0;
}; };
TrackEntry.prototype.setTimelineData = function (to, mixingToArray, propertyIDs) {
if (to != null)
mixingToArray.push(to);
var lastEntry = this.mixingFrom != null ? this.mixingFrom.setTimelineData(this, mixingToArray, propertyIDs) : this;
if (to != null)
mixingToArray.pop();
var mixingTo = mixingToArray;
var mixingToLast = mixingToArray.length - 1;
var timelines = this.animation.timelines;
var timelinesCount = this.animation.timelines.length;
var timelineData = spine.Utils.setArraySize(this.timelineData, timelinesCount);
var timelineDipMix = spine.Utils.setArraySize(this.timelineDipMix, timelinesCount);
outer: for (var i = 0; i < timelinesCount; i++) {
var id = timelines[i].getPropertyId();
if (!propertyIDs.add(id))
timelineData[i] = AnimationState.SUBSEQUENT;
else if (to == null || !to.hasTimeline(id))
timelineData[i] = AnimationState.FIRST;
else {
timelineData[i] = AnimationState.DIP;
for (var ii = mixingToLast; ii >= 0; ii--) {
var entry = mixingTo[ii];
if (!entry.hasTimeline(id)) {
timelineDipMix[i] = entry;
continue outer;
}
}
timelineDipMix[i] = null;
}
}
return lastEntry;
};
TrackEntry.prototype.hasTimeline = function (id) {
var timelines = this.animation.timelines;
for (var i = 0, n = timelines.length; i < n; i++)
if (timelines[i].getPropertyId() == id)
return true;
return false;
};
TrackEntry.prototype.getAnimationTime = function () { TrackEntry.prototype.getAnimationTime = function () {
if (this.loop) { if (this.loop) {
var duration = this.animationEnd - this.animationStart; var duration = this.animationEnd - this.animationStart;

File diff suppressed because one or more lines are too long

View File

@ -228,21 +228,24 @@ declare module spine {
declare module spine { declare module spine {
class AnimationState { class AnimationState {
static emptyAnimation: Animation; static emptyAnimation: Animation;
static SUBSEQUENT: number;
static FIRST: number;
static DIP: number;
data: AnimationStateData; data: AnimationStateData;
tracks: TrackEntry[]; tracks: TrackEntry[];
events: Event[]; events: Event[];
listeners: AnimationStateListener2[]; listeners: AnimationStateListener2[];
queue: EventQueue; queue: EventQueue;
propertyIDs: IntSet; propertyIDs: IntSet;
mixingTo: TrackEntry[];
animationsChanged: boolean; animationsChanged: boolean;
multipleMixing: boolean;
timeScale: number; timeScale: number;
trackEntryPool: Pool<TrackEntry>; trackEntryPool: Pool<TrackEntry>;
constructor(data: AnimationStateData); constructor(data: AnimationStateData);
update(delta: number): void; update(delta: number): void;
updateMixingFrom(entry: TrackEntry, delta: number): void; updateMixingFrom(entry: TrackEntry, delta: number, animationCount: number): boolean;
apply(skeleton: Skeleton): void; apply(skeleton: Skeleton): void;
applyMixingFrom(entry: TrackEntry, skeleton: Skeleton): number; applyMixingFrom(to: TrackEntry, skeleton: Skeleton): number;
applyRotateTimeline(timeline: Timeline, skeleton: Skeleton, time: number, alpha: number, setupPose: boolean, timelinesRotation: Array<number>, i: number, firstFrame: boolean): void; applyRotateTimeline(timeline: Timeline, skeleton: Skeleton, time: number, alpha: number, setupPose: boolean, timelinesRotation: Array<number>, i: number, firstFrame: boolean): void;
queueEvents(entry: TrackEntry, animationTime: number): void; queueEvents(entry: TrackEntry, animationTime: number): void;
clearTracks(): void; clearTracks(): void;
@ -259,9 +262,6 @@ declare module spine {
trackEntry(trackIndex: number, animation: Animation, loop: boolean, last: TrackEntry): TrackEntry; trackEntry(trackIndex: number, animation: Animation, loop: boolean, last: TrackEntry): TrackEntry;
disposeNext(entry: TrackEntry): void; disposeNext(entry: TrackEntry): void;
_animationsChanged(): void; _animationsChanged(): void;
setTimelinesFirst(entry: TrackEntry): void;
checkTimelinesFirst(entry: TrackEntry): void;
checkTimelinesUsage(entry: TrackEntry, usageArray: Array<boolean>): void;
getCurrent(trackIndex: number): TrackEntry; getCurrent(trackIndex: number): TrackEntry;
addListener(listener: AnimationStateListener2): void; addListener(listener: AnimationStateListener2): void;
removeListener(listener: AnimationStateListener2): void; removeListener(listener: AnimationStateListener2): void;
@ -291,11 +291,13 @@ declare module spine {
alpha: number; alpha: number;
mixTime: number; mixTime: number;
mixDuration: number; mixDuration: number;
mixAlpha: number; interruptAlpha: number;
timelinesFirst: boolean[]; timelineData: number[];
timelinesLast: boolean[]; timelineDipMix: TrackEntry[];
timelinesRotation: number[]; timelinesRotation: number[];
reset(): void; reset(): void;
setTimelineData(to: TrackEntry, mixingToArray: Array<TrackEntry>, propertyIDs: IntSet): TrackEntry;
hasTimeline(id: number): boolean;
getAnimationTime(): number; getAnimationTime(): number;
setAnimationLast(animationLast: number): void; setAnimationLast(animationLast: number): void;
isComplete(): boolean; isComplete(): boolean;

View File

@ -1056,8 +1056,8 @@ var spine;
this.listeners = new Array(); this.listeners = new Array();
this.queue = new EventQueue(this); this.queue = new EventQueue(this);
this.propertyIDs = new spine.IntSet(); this.propertyIDs = new spine.IntSet();
this.mixingTo = new Array();
this.animationsChanged = false; this.animationsChanged = false;
this.multipleMixing = false;
this.timeScale = 1; this.timeScale = 1;
this.trackEntryPool = new spine.Pool(function () { return new TrackEntry(); }); this.trackEntryPool = new spine.Pool(function () { return new TrackEntry(); });
this.data = data; this.data = data;
@ -1100,25 +1100,35 @@ var spine;
this.disposeNext(current); this.disposeNext(current);
continue; continue;
} }
this.updateMixingFrom(current, delta); if (current.mixingFrom != null && this.updateMixingFrom(current, delta, 2)) {
var from = current.mixingFrom;
current.mixingFrom = null;
while (from != null) {
this.queue.end(from);
from = from.mixingFrom;
}
}
current.trackTime += currentDelta; current.trackTime += currentDelta;
} }
this.queue.drain(); this.queue.drain();
}; };
AnimationState.prototype.updateMixingFrom = function (entry, delta) { AnimationState.prototype.updateMixingFrom = function (entry, delta, animationCount) {
var from = entry.mixingFrom; var from = entry.mixingFrom;
if (from == null) if (from == null)
return; return true;
this.updateMixingFrom(from, delta); var finished = this.updateMixingFrom(from, delta, animationCount + 1);
if (entry.mixTime >= entry.mixDuration && from.mixingFrom == null && entry.mixTime > 0) { if (entry.mixTime > 0 && (entry.mixTime >= entry.mixDuration || entry.timeScale == 0)) {
entry.mixingFrom = null; if (animationCount > 6 && from.mixingFrom == null) {
this.queue.end(from); entry.mixingFrom = null;
return; this.queue.end(from);
}
return finished;
} }
from.animationLast = from.nextAnimationLast; from.animationLast = from.nextAnimationLast;
from.trackLast = from.nextTrackLast; from.trackLast = from.nextTrackLast;
from.trackTime += delta * from.timeScale; from.trackTime += delta * from.timeScale;
entry.mixTime += delta * from.timeScale; entry.mixTime += delta * entry.timeScale;
return false;
}; };
AnimationState.prototype.apply = function (skeleton) { AnimationState.prototype.apply = function (skeleton) {
if (skeleton == null) if (skeleton == null)
@ -1144,18 +1154,18 @@ var spine;
timelines[ii].apply(skeleton, animationLast, animationTime, events, 1, true, false); timelines[ii].apply(skeleton, animationLast, animationTime, events, 1, true, false);
} }
else { else {
var timelineData = current.timelineData;
var firstFrame = current.timelinesRotation.length == 0; var firstFrame = current.timelinesRotation.length == 0;
if (firstFrame) if (firstFrame)
spine.Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null); spine.Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null);
var timelinesRotation = current.timelinesRotation; var timelinesRotation = current.timelinesRotation;
var timelinesFirst = current.timelinesFirst;
for (var ii = 0; ii < timelineCount; ii++) { for (var ii = 0; ii < timelineCount; ii++) {
var timeline = timelines[ii]; var timeline = timelines[ii];
if (timeline instanceof spine.RotateTimeline) { if (timeline instanceof spine.RotateTimeline) {
this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelinesFirst[ii], timelinesRotation, ii << 1, firstFrame); this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineData[ii] > 0, timelinesRotation, ii << 1, firstFrame);
} }
else else
timeline.apply(skeleton, animationLast, animationTime, events, mix, timelinesFirst[ii], false); timeline.apply(skeleton, animationLast, animationTime, events, mix, timelineData[ii] > 0, false);
} }
} }
this.queueEvents(current, animationTime); this.queueEvents(current, animationTime);
@ -1165,15 +1175,15 @@ var spine;
} }
this.queue.drain(); this.queue.drain();
}; };
AnimationState.prototype.applyMixingFrom = function (entry, skeleton) { AnimationState.prototype.applyMixingFrom = function (to, skeleton) {
var from = entry.mixingFrom; var from = to.mixingFrom;
if (from.mixingFrom != null) if (from.mixingFrom != null)
this.applyMixingFrom(from, skeleton); this.applyMixingFrom(from, skeleton);
var mix = 0; var mix = 0;
if (entry.mixDuration == 0) if (to.mixDuration == 0)
mix = 1; mix = 1;
else { else {
mix = entry.mixTime / entry.mixDuration; mix = to.mixTime / to.mixDuration;
if (mix > 1) if (mix > 1)
mix = 1; mix = 1;
} }
@ -1182,31 +1192,46 @@ var spine;
var animationLast = from.animationLast, animationTime = from.getAnimationTime(); var animationLast = from.animationLast, animationTime = from.getAnimationTime();
var timelineCount = from.animation.timelines.length; var timelineCount = from.animation.timelines.length;
var timelines = from.animation.timelines; var timelines = from.animation.timelines;
var timelinesFirst = from.timelinesFirst; var timelineData = from.timelineData;
var timelinesLast = this.multipleMixing ? null : from.timelinesLast; var timelineDipMix = from.timelineDipMix;
var alphaBase = from.alpha * entry.mixAlpha;
var alphaMix = alphaBase * (1 - mix);
var firstFrame = from.timelinesRotation.length == 0; var firstFrame = from.timelinesRotation.length == 0;
if (firstFrame) if (firstFrame)
spine.Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null); spine.Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null);
var timelinesRotation = from.timelinesRotation; var timelinesRotation = from.timelinesRotation;
var first = false;
var alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha;
for (var i = 0; i < timelineCount; i++) { for (var i = 0; i < timelineCount; i++) {
var timeline = timelines[i]; var timeline = timelines[i];
var setupPose = timelinesFirst[i]; switch (timelineData[i]) {
var alpha = timelinesLast != null && setupPose && !timelinesLast[i] ? alphaBase : alphaMix; case AnimationState.SUBSEQUENT:
first = false;
alpha = alphaMix;
break;
case AnimationState.FIRST:
first = true;
alpha = alphaMix;
break;
default:
first = true;
alpha = alphaDip;
var dipMix = timelineDipMix[i];
if (dipMix != null)
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
break;
}
if (timeline instanceof spine.RotateTimeline) if (timeline instanceof spine.RotateTimeline)
this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, setupPose, timelinesRotation, i << 1, firstFrame); this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, first, timelinesRotation, i << 1, firstFrame);
else { else {
if (!setupPose) { if (!first) {
if (!attachments && timeline instanceof spine.AttachmentTimeline) if (!attachments && timeline instanceof spine.AttachmentTimeline)
continue; continue;
if (!drawOrder && timeline instanceof spine.DrawOrderTimeline) if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
continue; continue;
} }
timeline.apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true); timeline.apply(skeleton, animationLast, animationTime, events, alpha, first, true);
} }
} }
if (entry.mixDuration > 0) if (to.mixDuration > 0)
this.queueEvents(from, animationTime); this.queueEvents(from, animationTime);
this.events.length = 0; this.events.length = 0;
from.nextAnimationLast = animationTime; from.nextAnimationLast = animationTime;
@ -1334,25 +1359,8 @@ var spine;
this.queue.interrupt(from); this.queue.interrupt(from);
current.mixingFrom = from; current.mixingFrom = from;
current.mixTime = 0; current.mixTime = 0;
var mixingFrom = from.mixingFrom; if (from.mixingFrom != null && from.mixDuration > 0)
if (mixingFrom != null && from.mixDuration > 0) { current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration);
if (this.multipleMixing) {
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
}
else {
if (from.mixTime / from.mixDuration < 0.5 && mixingFrom.animation != AnimationState.emptyAnimation) {
current.mixingFrom = mixingFrom;
mixingFrom.mixingFrom = from;
mixingFrom.mixTime = from.mixDuration - from.mixTime;
mixingFrom.mixDuration = from.mixDuration;
from.mixingFrom = null;
from = mixingFrom;
}
from.mixAlpha = 0;
from.mixTime = 0;
from.mixDuration = 0;
}
}
from.timelinesRotation.length = 0; from.timelinesRotation.length = 0;
} }
this.queue.start(current); this.queue.start(current);
@ -1468,7 +1476,7 @@ var spine;
entry.trackEnd = Number.MAX_VALUE; entry.trackEnd = Number.MAX_VALUE;
entry.timeScale = 1; entry.timeScale = 1;
entry.alpha = 1; entry.alpha = 1;
entry.mixAlpha = 1; entry.interruptAlpha = 1;
entry.mixTime = 0; entry.mixTime = 0;
entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation); entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation);
return entry; return entry;
@ -1484,74 +1492,17 @@ var spine;
AnimationState.prototype._animationsChanged = function () { AnimationState.prototype._animationsChanged = function () {
this.animationsChanged = false; this.animationsChanged = false;
var propertyIDs = this.propertyIDs; var propertyIDs = this.propertyIDs;
var i = 0, n = this.tracks.length;
propertyIDs.clear(); propertyIDs.clear();
for (; i < n; i++) { var mixingTo = this.mixingTo;
var lastEntry = null;
for (var i = 0, n = this.tracks.length; i < n; i++) {
var entry = this.tracks[i]; var entry = this.tracks[i];
if (entry == null) if (entry != null) {
continue; entry.setTimelineData(lastEntry, mixingTo, propertyIDs);
this.setTimelinesFirst(entry); lastEntry = entry;
i++;
break;
}
for (; i < n; i++) {
var entry = this.tracks[i];
if (entry != null)
this.checkTimelinesFirst(entry);
}
if (this.multipleMixing)
return;
propertyIDs.clear();
var lowestMixingFrom = n;
for (i = 0; i < n; i++) {
var entry = this.tracks[i];
if (entry == null || entry.mixingFrom == null)
continue;
lowestMixingFrom = i;
break;
}
for (i = n - 1; i >= lowestMixingFrom; i--) {
var entry = this.tracks[i];
if (entry == null)
continue;
var timelines = entry.animation.timelines;
for (var ii = 0, nn = entry.animation.timelines.length; ii < nn; ii++)
propertyIDs.add(timelines[ii].getPropertyId());
entry = entry.mixingFrom;
while (entry != null) {
this.checkTimelinesUsage(entry, entry.timelinesLast);
entry = entry.mixingFrom;
} }
} }
}; };
AnimationState.prototype.setTimelinesFirst = function (entry) {
if (entry.mixingFrom != null) {
this.setTimelinesFirst(entry.mixingFrom);
this.checkTimelinesUsage(entry, entry.timelinesFirst);
return;
}
var propertyIDs = this.propertyIDs;
var timelines = entry.animation.timelines;
var n = timelines.length;
var usage = spine.Utils.setArraySize(entry.timelinesFirst, n, false);
for (var i = 0; i < n; i++) {
propertyIDs.add(timelines[i].getPropertyId());
usage[i] = true;
}
};
AnimationState.prototype.checkTimelinesFirst = function (entry) {
if (entry.mixingFrom != null)
this.checkTimelinesFirst(entry.mixingFrom);
this.checkTimelinesUsage(entry, entry.timelinesFirst);
};
AnimationState.prototype.checkTimelinesUsage = function (entry, usageArray) {
var propertyIDs = this.propertyIDs;
var timelines = entry.animation.timelines;
var n = timelines.length;
var usage = spine.Utils.setArraySize(usageArray, n);
for (var i = 0; i < n; i++)
usage[i] = propertyIDs.add(timelines[i].getPropertyId());
};
AnimationState.prototype.getCurrent = function (trackIndex) { AnimationState.prototype.getCurrent = function (trackIndex) {
if (trackIndex >= this.tracks.length) if (trackIndex >= this.tracks.length)
return null; return null;
@ -1576,11 +1527,14 @@ var spine;
return AnimationState; return AnimationState;
}()); }());
AnimationState.emptyAnimation = new spine.Animation("<empty>", [], 0); AnimationState.emptyAnimation = new spine.Animation("<empty>", [], 0);
AnimationState.SUBSEQUENT = 0;
AnimationState.FIRST = 1;
AnimationState.DIP = 2;
spine.AnimationState = AnimationState; spine.AnimationState = AnimationState;
var TrackEntry = (function () { var TrackEntry = (function () {
function TrackEntry() { function TrackEntry() {
this.timelinesFirst = new Array(); this.timelineData = new Array();
this.timelinesLast = new Array(); this.timelineDipMix = new Array();
this.timelinesRotation = new Array(); this.timelinesRotation = new Array();
} }
TrackEntry.prototype.reset = function () { TrackEntry.prototype.reset = function () {
@ -1588,10 +1542,49 @@ var spine;
this.mixingFrom = null; this.mixingFrom = null;
this.animation = null; this.animation = null;
this.listener = null; this.listener = null;
this.timelinesFirst.length = 0; this.timelineData.length = 0;
this.timelinesLast.length = 0; this.timelineDipMix.length = 0;
this.timelinesRotation.length = 0; this.timelinesRotation.length = 0;
}; };
TrackEntry.prototype.setTimelineData = function (to, mixingToArray, propertyIDs) {
if (to != null)
mixingToArray.push(to);
var lastEntry = this.mixingFrom != null ? this.mixingFrom.setTimelineData(this, mixingToArray, propertyIDs) : this;
if (to != null)
mixingToArray.pop();
var mixingTo = mixingToArray;
var mixingToLast = mixingToArray.length - 1;
var timelines = this.animation.timelines;
var timelinesCount = this.animation.timelines.length;
var timelineData = spine.Utils.setArraySize(this.timelineData, timelinesCount);
var timelineDipMix = spine.Utils.setArraySize(this.timelineDipMix, timelinesCount);
outer: for (var i = 0; i < timelinesCount; i++) {
var id = timelines[i].getPropertyId();
if (!propertyIDs.add(id))
timelineData[i] = AnimationState.SUBSEQUENT;
else if (to == null || !to.hasTimeline(id))
timelineData[i] = AnimationState.FIRST;
else {
timelineData[i] = AnimationState.DIP;
for (var ii = mixingToLast; ii >= 0; ii--) {
var entry = mixingTo[ii];
if (!entry.hasTimeline(id)) {
timelineDipMix[i] = entry;
continue outer;
}
}
timelineDipMix[i] = null;
}
}
return lastEntry;
};
TrackEntry.prototype.hasTimeline = function (id) {
var timelines = this.animation.timelines;
for (var i = 0, n = timelines.length; i < n; i++)
if (timelines[i].getPropertyId() == id)
return true;
return false;
};
TrackEntry.prototype.getAnimationTime = function () { TrackEntry.prototype.getAnimationTime = function () {
if (this.loop) { if (this.loop) {
var duration = this.animationEnd - this.animationStart; var duration = this.animationEnd - this.animationStart;

File diff suppressed because one or more lines are too long

View File

@ -228,21 +228,24 @@ declare module spine {
declare module spine { declare module spine {
class AnimationState { class AnimationState {
static emptyAnimation: Animation; static emptyAnimation: Animation;
static SUBSEQUENT: number;
static FIRST: number;
static DIP: number;
data: AnimationStateData; data: AnimationStateData;
tracks: TrackEntry[]; tracks: TrackEntry[];
events: Event[]; events: Event[];
listeners: AnimationStateListener2[]; listeners: AnimationStateListener2[];
queue: EventQueue; queue: EventQueue;
propertyIDs: IntSet; propertyIDs: IntSet;
mixingTo: TrackEntry[];
animationsChanged: boolean; animationsChanged: boolean;
multipleMixing: boolean;
timeScale: number; timeScale: number;
trackEntryPool: Pool<TrackEntry>; trackEntryPool: Pool<TrackEntry>;
constructor(data: AnimationStateData); constructor(data: AnimationStateData);
update(delta: number): void; update(delta: number): void;
updateMixingFrom(entry: TrackEntry, delta: number): void; updateMixingFrom(entry: TrackEntry, delta: number, animationCount: number): boolean;
apply(skeleton: Skeleton): void; apply(skeleton: Skeleton): void;
applyMixingFrom(entry: TrackEntry, skeleton: Skeleton): number; applyMixingFrom(to: TrackEntry, skeleton: Skeleton): number;
applyRotateTimeline(timeline: Timeline, skeleton: Skeleton, time: number, alpha: number, setupPose: boolean, timelinesRotation: Array<number>, i: number, firstFrame: boolean): void; applyRotateTimeline(timeline: Timeline, skeleton: Skeleton, time: number, alpha: number, setupPose: boolean, timelinesRotation: Array<number>, i: number, firstFrame: boolean): void;
queueEvents(entry: TrackEntry, animationTime: number): void; queueEvents(entry: TrackEntry, animationTime: number): void;
clearTracks(): void; clearTracks(): void;
@ -259,9 +262,6 @@ declare module spine {
trackEntry(trackIndex: number, animation: Animation, loop: boolean, last: TrackEntry): TrackEntry; trackEntry(trackIndex: number, animation: Animation, loop: boolean, last: TrackEntry): TrackEntry;
disposeNext(entry: TrackEntry): void; disposeNext(entry: TrackEntry): void;
_animationsChanged(): void; _animationsChanged(): void;
setTimelinesFirst(entry: TrackEntry): void;
checkTimelinesFirst(entry: TrackEntry): void;
checkTimelinesUsage(entry: TrackEntry, usageArray: Array<boolean>): void;
getCurrent(trackIndex: number): TrackEntry; getCurrent(trackIndex: number): TrackEntry;
addListener(listener: AnimationStateListener2): void; addListener(listener: AnimationStateListener2): void;
removeListener(listener: AnimationStateListener2): void; removeListener(listener: AnimationStateListener2): void;
@ -291,11 +291,13 @@ declare module spine {
alpha: number; alpha: number;
mixTime: number; mixTime: number;
mixDuration: number; mixDuration: number;
mixAlpha: number; interruptAlpha: number;
timelinesFirst: boolean[]; timelineData: number[];
timelinesLast: boolean[]; timelineDipMix: TrackEntry[];
timelinesRotation: number[]; timelinesRotation: number[];
reset(): void; reset(): void;
setTimelineData(to: TrackEntry, mixingToArray: Array<TrackEntry>, propertyIDs: IntSet): TrackEntry;
hasTimeline(id: number): boolean;
getAnimationTime(): number; getAnimationTime(): number;
setAnimationLast(animationLast: number): void; setAnimationLast(animationLast: number): void;
isComplete(): boolean; isComplete(): boolean;

View File

@ -1056,8 +1056,8 @@ var spine;
this.listeners = new Array(); this.listeners = new Array();
this.queue = new EventQueue(this); this.queue = new EventQueue(this);
this.propertyIDs = new spine.IntSet(); this.propertyIDs = new spine.IntSet();
this.mixingTo = new Array();
this.animationsChanged = false; this.animationsChanged = false;
this.multipleMixing = false;
this.timeScale = 1; this.timeScale = 1;
this.trackEntryPool = new spine.Pool(function () { return new TrackEntry(); }); this.trackEntryPool = new spine.Pool(function () { return new TrackEntry(); });
this.data = data; this.data = data;
@ -1100,25 +1100,35 @@ var spine;
this.disposeNext(current); this.disposeNext(current);
continue; continue;
} }
this.updateMixingFrom(current, delta); if (current.mixingFrom != null && this.updateMixingFrom(current, delta, 2)) {
var from = current.mixingFrom;
current.mixingFrom = null;
while (from != null) {
this.queue.end(from);
from = from.mixingFrom;
}
}
current.trackTime += currentDelta; current.trackTime += currentDelta;
} }
this.queue.drain(); this.queue.drain();
}; };
AnimationState.prototype.updateMixingFrom = function (entry, delta) { AnimationState.prototype.updateMixingFrom = function (entry, delta, animationCount) {
var from = entry.mixingFrom; var from = entry.mixingFrom;
if (from == null) if (from == null)
return; return true;
this.updateMixingFrom(from, delta); var finished = this.updateMixingFrom(from, delta, animationCount + 1);
if (entry.mixTime >= entry.mixDuration && from.mixingFrom == null && entry.mixTime > 0) { if (entry.mixTime > 0 && (entry.mixTime >= entry.mixDuration || entry.timeScale == 0)) {
entry.mixingFrom = null; if (animationCount > 6 && from.mixingFrom == null) {
this.queue.end(from); entry.mixingFrom = null;
return; this.queue.end(from);
}
return finished;
} }
from.animationLast = from.nextAnimationLast; from.animationLast = from.nextAnimationLast;
from.trackLast = from.nextTrackLast; from.trackLast = from.nextTrackLast;
from.trackTime += delta * from.timeScale; from.trackTime += delta * from.timeScale;
entry.mixTime += delta * from.timeScale; entry.mixTime += delta * entry.timeScale;
return false;
}; };
AnimationState.prototype.apply = function (skeleton) { AnimationState.prototype.apply = function (skeleton) {
if (skeleton == null) if (skeleton == null)
@ -1144,18 +1154,18 @@ var spine;
timelines[ii].apply(skeleton, animationLast, animationTime, events, 1, true, false); timelines[ii].apply(skeleton, animationLast, animationTime, events, 1, true, false);
} }
else { else {
var timelineData = current.timelineData;
var firstFrame = current.timelinesRotation.length == 0; var firstFrame = current.timelinesRotation.length == 0;
if (firstFrame) if (firstFrame)
spine.Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null); spine.Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null);
var timelinesRotation = current.timelinesRotation; var timelinesRotation = current.timelinesRotation;
var timelinesFirst = current.timelinesFirst;
for (var ii = 0; ii < timelineCount; ii++) { for (var ii = 0; ii < timelineCount; ii++) {
var timeline = timelines[ii]; var timeline = timelines[ii];
if (timeline instanceof spine.RotateTimeline) { if (timeline instanceof spine.RotateTimeline) {
this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelinesFirst[ii], timelinesRotation, ii << 1, firstFrame); this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineData[ii] > 0, timelinesRotation, ii << 1, firstFrame);
} }
else else
timeline.apply(skeleton, animationLast, animationTime, events, mix, timelinesFirst[ii], false); timeline.apply(skeleton, animationLast, animationTime, events, mix, timelineData[ii] > 0, false);
} }
} }
this.queueEvents(current, animationTime); this.queueEvents(current, animationTime);
@ -1165,15 +1175,15 @@ var spine;
} }
this.queue.drain(); this.queue.drain();
}; };
AnimationState.prototype.applyMixingFrom = function (entry, skeleton) { AnimationState.prototype.applyMixingFrom = function (to, skeleton) {
var from = entry.mixingFrom; var from = to.mixingFrom;
if (from.mixingFrom != null) if (from.mixingFrom != null)
this.applyMixingFrom(from, skeleton); this.applyMixingFrom(from, skeleton);
var mix = 0; var mix = 0;
if (entry.mixDuration == 0) if (to.mixDuration == 0)
mix = 1; mix = 1;
else { else {
mix = entry.mixTime / entry.mixDuration; mix = to.mixTime / to.mixDuration;
if (mix > 1) if (mix > 1)
mix = 1; mix = 1;
} }
@ -1182,31 +1192,46 @@ var spine;
var animationLast = from.animationLast, animationTime = from.getAnimationTime(); var animationLast = from.animationLast, animationTime = from.getAnimationTime();
var timelineCount = from.animation.timelines.length; var timelineCount = from.animation.timelines.length;
var timelines = from.animation.timelines; var timelines = from.animation.timelines;
var timelinesFirst = from.timelinesFirst; var timelineData = from.timelineData;
var timelinesLast = this.multipleMixing ? null : from.timelinesLast; var timelineDipMix = from.timelineDipMix;
var alphaBase = from.alpha * entry.mixAlpha;
var alphaMix = alphaBase * (1 - mix);
var firstFrame = from.timelinesRotation.length == 0; var firstFrame = from.timelinesRotation.length == 0;
if (firstFrame) if (firstFrame)
spine.Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null); spine.Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null);
var timelinesRotation = from.timelinesRotation; var timelinesRotation = from.timelinesRotation;
var first = false;
var alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha;
for (var i = 0; i < timelineCount; i++) { for (var i = 0; i < timelineCount; i++) {
var timeline = timelines[i]; var timeline = timelines[i];
var setupPose = timelinesFirst[i]; switch (timelineData[i]) {
var alpha = timelinesLast != null && setupPose && !timelinesLast[i] ? alphaBase : alphaMix; case AnimationState.SUBSEQUENT:
first = false;
alpha = alphaMix;
break;
case AnimationState.FIRST:
first = true;
alpha = alphaMix;
break;
default:
first = true;
alpha = alphaDip;
var dipMix = timelineDipMix[i];
if (dipMix != null)
alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
break;
}
if (timeline instanceof spine.RotateTimeline) if (timeline instanceof spine.RotateTimeline)
this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, setupPose, timelinesRotation, i << 1, firstFrame); this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, first, timelinesRotation, i << 1, firstFrame);
else { else {
if (!setupPose) { if (!first) {
if (!attachments && timeline instanceof spine.AttachmentTimeline) if (!attachments && timeline instanceof spine.AttachmentTimeline)
continue; continue;
if (!drawOrder && timeline instanceof spine.DrawOrderTimeline) if (!drawOrder && timeline instanceof spine.DrawOrderTimeline)
continue; continue;
} }
timeline.apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true); timeline.apply(skeleton, animationLast, animationTime, events, alpha, first, true);
} }
} }
if (entry.mixDuration > 0) if (to.mixDuration > 0)
this.queueEvents(from, animationTime); this.queueEvents(from, animationTime);
this.events.length = 0; this.events.length = 0;
from.nextAnimationLast = animationTime; from.nextAnimationLast = animationTime;
@ -1334,25 +1359,8 @@ var spine;
this.queue.interrupt(from); this.queue.interrupt(from);
current.mixingFrom = from; current.mixingFrom = from;
current.mixTime = 0; current.mixTime = 0;
var mixingFrom = from.mixingFrom; if (from.mixingFrom != null && from.mixDuration > 0)
if (mixingFrom != null && from.mixDuration > 0) { current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration);
if (this.multipleMixing) {
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
}
else {
if (from.mixTime / from.mixDuration < 0.5 && mixingFrom.animation != AnimationState.emptyAnimation) {
current.mixingFrom = mixingFrom;
mixingFrom.mixingFrom = from;
mixingFrom.mixTime = from.mixDuration - from.mixTime;
mixingFrom.mixDuration = from.mixDuration;
from.mixingFrom = null;
from = mixingFrom;
}
from.mixAlpha = 0;
from.mixTime = 0;
from.mixDuration = 0;
}
}
from.timelinesRotation.length = 0; from.timelinesRotation.length = 0;
} }
this.queue.start(current); this.queue.start(current);
@ -1468,7 +1476,7 @@ var spine;
entry.trackEnd = Number.MAX_VALUE; entry.trackEnd = Number.MAX_VALUE;
entry.timeScale = 1; entry.timeScale = 1;
entry.alpha = 1; entry.alpha = 1;
entry.mixAlpha = 1; entry.interruptAlpha = 1;
entry.mixTime = 0; entry.mixTime = 0;
entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation); entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation);
return entry; return entry;
@ -1484,74 +1492,17 @@ var spine;
AnimationState.prototype._animationsChanged = function () { AnimationState.prototype._animationsChanged = function () {
this.animationsChanged = false; this.animationsChanged = false;
var propertyIDs = this.propertyIDs; var propertyIDs = this.propertyIDs;
var i = 0, n = this.tracks.length;
propertyIDs.clear(); propertyIDs.clear();
for (; i < n; i++) { var mixingTo = this.mixingTo;
var lastEntry = null;
for (var i = 0, n = this.tracks.length; i < n; i++) {
var entry = this.tracks[i]; var entry = this.tracks[i];
if (entry == null) if (entry != null) {
continue; entry.setTimelineData(lastEntry, mixingTo, propertyIDs);
this.setTimelinesFirst(entry); lastEntry = entry;
i++;
break;
}
for (; i < n; i++) {
var entry = this.tracks[i];
if (entry != null)
this.checkTimelinesFirst(entry);
}
if (this.multipleMixing)
return;
propertyIDs.clear();
var lowestMixingFrom = n;
for (i = 0; i < n; i++) {
var entry = this.tracks[i];
if (entry == null || entry.mixingFrom == null)
continue;
lowestMixingFrom = i;
break;
}
for (i = n - 1; i >= lowestMixingFrom; i--) {
var entry = this.tracks[i];
if (entry == null)
continue;
var timelines = entry.animation.timelines;
for (var ii = 0, nn = entry.animation.timelines.length; ii < nn; ii++)
propertyIDs.add(timelines[ii].getPropertyId());
entry = entry.mixingFrom;
while (entry != null) {
this.checkTimelinesUsage(entry, entry.timelinesLast);
entry = entry.mixingFrom;
} }
} }
}; };
AnimationState.prototype.setTimelinesFirst = function (entry) {
if (entry.mixingFrom != null) {
this.setTimelinesFirst(entry.mixingFrom);
this.checkTimelinesUsage(entry, entry.timelinesFirst);
return;
}
var propertyIDs = this.propertyIDs;
var timelines = entry.animation.timelines;
var n = timelines.length;
var usage = spine.Utils.setArraySize(entry.timelinesFirst, n, false);
for (var i = 0; i < n; i++) {
propertyIDs.add(timelines[i].getPropertyId());
usage[i] = true;
}
};
AnimationState.prototype.checkTimelinesFirst = function (entry) {
if (entry.mixingFrom != null)
this.checkTimelinesFirst(entry.mixingFrom);
this.checkTimelinesUsage(entry, entry.timelinesFirst);
};
AnimationState.prototype.checkTimelinesUsage = function (entry, usageArray) {
var propertyIDs = this.propertyIDs;
var timelines = entry.animation.timelines;
var n = timelines.length;
var usage = spine.Utils.setArraySize(usageArray, n);
for (var i = 0; i < n; i++)
usage[i] = propertyIDs.add(timelines[i].getPropertyId());
};
AnimationState.prototype.getCurrent = function (trackIndex) { AnimationState.prototype.getCurrent = function (trackIndex) {
if (trackIndex >= this.tracks.length) if (trackIndex >= this.tracks.length)
return null; return null;
@ -1576,11 +1527,14 @@ var spine;
return AnimationState; return AnimationState;
}()); }());
AnimationState.emptyAnimation = new spine.Animation("<empty>", [], 0); AnimationState.emptyAnimation = new spine.Animation("<empty>", [], 0);
AnimationState.SUBSEQUENT = 0;
AnimationState.FIRST = 1;
AnimationState.DIP = 2;
spine.AnimationState = AnimationState; spine.AnimationState = AnimationState;
var TrackEntry = (function () { var TrackEntry = (function () {
function TrackEntry() { function TrackEntry() {
this.timelinesFirst = new Array(); this.timelineData = new Array();
this.timelinesLast = new Array(); this.timelineDipMix = new Array();
this.timelinesRotation = new Array(); this.timelinesRotation = new Array();
} }
TrackEntry.prototype.reset = function () { TrackEntry.prototype.reset = function () {
@ -1588,10 +1542,49 @@ var spine;
this.mixingFrom = null; this.mixingFrom = null;
this.animation = null; this.animation = null;
this.listener = null; this.listener = null;
this.timelinesFirst.length = 0; this.timelineData.length = 0;
this.timelinesLast.length = 0; this.timelineDipMix.length = 0;
this.timelinesRotation.length = 0; this.timelinesRotation.length = 0;
}; };
TrackEntry.prototype.setTimelineData = function (to, mixingToArray, propertyIDs) {
if (to != null)
mixingToArray.push(to);
var lastEntry = this.mixingFrom != null ? this.mixingFrom.setTimelineData(this, mixingToArray, propertyIDs) : this;
if (to != null)
mixingToArray.pop();
var mixingTo = mixingToArray;
var mixingToLast = mixingToArray.length - 1;
var timelines = this.animation.timelines;
var timelinesCount = this.animation.timelines.length;
var timelineData = spine.Utils.setArraySize(this.timelineData, timelinesCount);
var timelineDipMix = spine.Utils.setArraySize(this.timelineDipMix, timelinesCount);
outer: for (var i = 0; i < timelinesCount; i++) {
var id = timelines[i].getPropertyId();
if (!propertyIDs.add(id))
timelineData[i] = AnimationState.SUBSEQUENT;
else if (to == null || !to.hasTimeline(id))
timelineData[i] = AnimationState.FIRST;
else {
timelineData[i] = AnimationState.DIP;
for (var ii = mixingToLast; ii >= 0; ii--) {
var entry = mixingTo[ii];
if (!entry.hasTimeline(id)) {
timelineDipMix[i] = entry;
continue outer;
}
}
timelineDipMix[i] = null;
}
}
return lastEntry;
};
TrackEntry.prototype.hasTimeline = function (id) {
var timelines = this.animation.timelines;
for (var i = 0, n = timelines.length; i < n; i++)
if (timelines[i].getPropertyId() == id)
return true;
return false;
};
TrackEntry.prototype.getAnimationTime = function () { TrackEntry.prototype.getAnimationTime = function () {
if (this.loop) { if (this.loop) {
var duration = this.animationEnd - this.animationStart; var duration = this.animationEnd - this.animationStart;

File diff suppressed because one or more lines are too long

View File

@ -31,6 +31,9 @@
module spine { module spine {
export class AnimationState { export class AnimationState {
static emptyAnimation = new Animation("<empty>", [], 0); static emptyAnimation = new Animation("<empty>", [], 0);
static SUBSEQUENT = 0;
static FIRST = 1;
static DIP = 2;
data: AnimationStateData; data: AnimationStateData;
tracks = new Array<TrackEntry>(); tracks = new Array<TrackEntry>();
@ -38,8 +41,8 @@ module spine {
listeners = new Array<AnimationStateListener2>(); listeners = new Array<AnimationStateListener2>();
queue = new EventQueue(this); queue = new EventQueue(this);
propertyIDs = new IntSet(); propertyIDs = new IntSet();
mixingTo = new Array<TrackEntry>();
animationsChanged = false; animationsChanged = false;
multipleMixing = false;
timeScale = 1; timeScale = 1;
trackEntryPool = new Pool<TrackEntry>(() => new TrackEntry()); trackEntryPool = new Pool<TrackEntry>(() => new TrackEntry());
@ -88,7 +91,15 @@ module spine {
this.disposeNext(current); this.disposeNext(current);
continue; continue;
} }
this.updateMixingFrom(current, delta); if (current.mixingFrom != null && this.updateMixingFrom(current, delta, 2)) {
// End mixing from entries once all have completed.
let from = current.mixingFrom;
current.mixingFrom = null;
while (from != null) {
this.queue.end(from);
from = from.mixingFrom;
}
}
current.trackTime += currentDelta; current.trackTime += currentDelta;
} }
@ -96,22 +107,26 @@ module spine {
this.queue.drain(); this.queue.drain();
} }
updateMixingFrom (entry: TrackEntry, delta: number) { updateMixingFrom (entry: TrackEntry, delta: number, animationCount: number): boolean {
let from = entry.mixingFrom; let from = entry.mixingFrom;
if (from == null) return; if (from == null) return true;
this.updateMixingFrom(from, delta); let finished = this.updateMixingFrom(from, delta, animationCount + 1);
if (entry.mixTime >= entry.mixDuration && from.mixingFrom == null && entry.mixTime > 0) { // Require mixTime > 0 to ensure the mixing from entry was applied at least once.
entry.mixingFrom = null; if (entry.mixTime > 0 && (entry.mixTime >= entry.mixDuration || entry.timeScale == 0)) {
this.queue.end(from); if (animationCount > 6 && from.mixingFrom == null) { // Limit the mixing from linked list.
return; entry.mixingFrom = null;
this.queue.end(from);
}
return finished;
} }
from.animationLast = from.nextAnimationLast; from.animationLast = from.nextAnimationLast;
from.trackLast = from.nextTrackLast; from.trackLast = from.nextTrackLast;
from.trackTime += delta * from.timeScale; from.trackTime += delta * from.timeScale;
entry.mixTime += delta * from.timeScale; entry.mixTime += delta * entry.timeScale;
return false;
} }
apply (skeleton: Skeleton) { apply (skeleton: Skeleton) {
@ -140,18 +155,19 @@ module spine {
for (let ii = 0; ii < timelineCount; ii++) for (let ii = 0; ii < timelineCount; ii++)
timelines[ii].apply(skeleton, animationLast, animationTime, events, 1, true, false); timelines[ii].apply(skeleton, animationLast, animationTime, events, 1, true, false);
} else { } else {
let timelineData = current.timelineData;
let firstFrame = current.timelinesRotation.length == 0; let firstFrame = current.timelinesRotation.length == 0;
if (firstFrame) Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null); if (firstFrame) Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null);
let timelinesRotation = current.timelinesRotation; let timelinesRotation = current.timelinesRotation;
let timelinesFirst = current.timelinesFirst;
for (let ii = 0; ii < timelineCount; ii++) { for (let ii = 0; ii < timelineCount; ii++) {
let timeline = timelines[ii]; let timeline = timelines[ii];
if (timeline instanceof RotateTimeline) { if (timeline instanceof RotateTimeline) {
this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelinesFirst[ii], timelinesRotation, ii << 1, this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineData[ii] > 0, timelinesRotation, ii << 1,
firstFrame); firstFrame);
} else } else
timeline.apply(skeleton, animationLast, animationTime, events, mix, timelinesFirst[ii], false); timeline.apply(skeleton, animationLast, animationTime, events, mix, timelineData[ii] > 0, false);
} }
} }
this.queueEvents(current, animationTime); this.queueEvents(current, animationTime);
@ -163,15 +179,15 @@ module spine {
this.queue.drain(); this.queue.drain();
} }
applyMixingFrom (entry: TrackEntry, skeleton: Skeleton) { applyMixingFrom (to: TrackEntry, skeleton: Skeleton) {
let from = entry.mixingFrom; let from = to.mixingFrom;
if (from.mixingFrom != null) this.applyMixingFrom(from, skeleton); if (from.mixingFrom != null) this.applyMixingFrom(from, skeleton);
let mix = 0; let mix = 0;
if (entry.mixDuration == 0) // Single frame mix to undo mixingFrom changes. if (to.mixDuration == 0) // Single frame mix to undo mixingFrom changes.
mix = 1; mix = 1;
else { else {
mix = entry.mixTime / entry.mixDuration; mix = to.mixTime / to.mixDuration;
if (mix > 1) mix = 1; if (mix > 1) mix = 1;
} }
@ -180,31 +196,45 @@ module spine {
let animationLast = from.animationLast, animationTime = from.getAnimationTime(); let animationLast = from.animationLast, animationTime = from.getAnimationTime();
let timelineCount = from.animation.timelines.length; let timelineCount = from.animation.timelines.length;
let timelines = from.animation.timelines; let timelines = from.animation.timelines;
let timelinesFirst = from.timelinesFirst; let timelineData = from.timelineData;
let timelinesLast = this.multipleMixing ? null : from.timelinesLast; let timelineDipMix = from.timelineDipMix;
let alphaBase = from.alpha * entry.mixAlpha;
let alphaMix = alphaBase * (1 - mix);
let firstFrame = from.timelinesRotation.length == 0; let firstFrame = from.timelinesRotation.length == 0;
if (firstFrame) Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null); if (firstFrame) Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null);
let timelinesRotation = from.timelinesRotation; let timelinesRotation = from.timelinesRotation;
for (let i = 0; i < timelineCount; i++) { let first = false;
let alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha;
for (var i = 0; i < timelineCount; i++) {
let timeline = timelines[i]; let timeline = timelines[i];
let setupPose = timelinesFirst[i]; switch (timelineData[i]) {
let alpha = timelinesLast != null && setupPose && !timelinesLast[i] ? alphaBase : alphaMix; case AnimationState.SUBSEQUENT:
first = false;
alpha = alphaMix;
break;
case AnimationState.FIRST:
first = true;
alpha = alphaMix;
break;
default:
first = true;
alpha = alphaDip;
let dipMix = timelineDipMix[i];
if (dipMix != null) alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration);
break;
}
if (timeline instanceof RotateTimeline) if (timeline instanceof RotateTimeline)
this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, setupPose, timelinesRotation, i << 1, firstFrame); this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, first, timelinesRotation, i << 1, firstFrame);
else { else {
if (!setupPose) { if (!first) {
if (!attachments && timeline instanceof AttachmentTimeline) continue; if (!attachments && timeline instanceof AttachmentTimeline) continue;
if (!drawOrder && timeline instanceof DrawOrderTimeline) continue; if (!drawOrder && timeline instanceof DrawOrderTimeline) continue;
} }
timeline.apply(skeleton, animationLast, animationTime, events, alpha, setupPose, true); timeline.apply(skeleton, animationLast, animationTime, events, alpha, first, true);
} }
} }
if (entry.mixDuration > 0) this.queueEvents(from, animationTime); if (to.mixDuration > 0) this.queueEvents(from, animationTime);
this.events.length = 0; this.events.length = 0;
from.nextAnimationLast = animationTime; from.nextAnimationLast = animationTime;
from.nextTrackLast = from.trackTime; from.nextTrackLast = from.trackTime;
@ -349,30 +379,11 @@ module spine {
current.mixingFrom = from; current.mixingFrom = from;
current.mixTime = 0; current.mixTime = 0;
let mixingFrom = from.mixingFrom; // Store the interrupted mix percentage.
if (mixingFrom != null && from.mixDuration > 0) { if (from.mixingFrom != null && from.mixDuration > 0)
if (this.multipleMixing) { current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration);
// The interrupted mix will mix out from its current percentage to zero.
current.mixAlpha *= Math.min(from.mixTime / from.mixDuration, 1);
} else {
// A mix was interrupted, mix from the closest animation.
if (from.mixTime / from.mixDuration < 0.5 && mixingFrom.animation != AnimationState.emptyAnimation) {
current.mixingFrom = mixingFrom;
mixingFrom.mixingFrom = from;
mixingFrom.mixTime = from.mixDuration - from.mixTime;
mixingFrom.mixDuration = from.mixDuration;
from.mixingFrom = null;
from = mixingFrom;
}
// End the other animation after it is applied one last time. from.timelinesRotation.length = 0; // Reset rotation for mixing out, in case entry was mixed in.
from.mixAlpha = 0;
from.mixTime = 0;
from.mixDuration = 0;
}
}
from.timelinesRotation.length = 0;
} }
this.queue.start(current); this.queue.start(current);
@ -497,7 +508,7 @@ module spine {
entry.timeScale = 1; entry.timeScale = 1;
entry.alpha = 1; entry.alpha = 1;
entry.mixAlpha = 1; entry.interruptAlpha = 1;
entry.mixTime = 0; entry.mixTime = 0;
entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation); entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation);
return entry; return entry;
@ -516,80 +527,19 @@ module spine {
this.animationsChanged = false; this.animationsChanged = false;
let propertyIDs = this.propertyIDs; let propertyIDs = this.propertyIDs;
// Compute timelinesFirst from lowest to highest track entries.
let i = 0, n = this.tracks.length;
propertyIDs.clear(); propertyIDs.clear();
for (; i < n; i++) { // Find first non-null entry. let mixingTo = this.mixingTo;
let entry = this.tracks[i];
if (entry == null) continue;
this.setTimelinesFirst(entry);
i++;
break;
}
for (; i < n; i++) { // Rest of entries.
let entry = this.tracks[i];
if (entry != null) this.checkTimelinesFirst(entry);
}
if (this.multipleMixing) return; let lastEntry: TrackEntry = null;
for (var i = 0, n = this.tracks.length; i < n; i++) {
// Set timelinesLast for mixingFrom entries, from highest track to lowest that has mixingFrom.
propertyIDs.clear();
let lowestMixingFrom = n;
for (i = 0; i < n; i++) { // Find lowest track with a mixingFrom entry.
let entry = this.tracks[i]; let entry = this.tracks[i];
if (entry == null || entry.mixingFrom == null) continue; if (entry != null) {
lowestMixingFrom = i; entry.setTimelineData(lastEntry, mixingTo, propertyIDs);
break; lastEntry = entry;
}
for (i = n - 1; i >= lowestMixingFrom; i--) { // Find first non-null entry.
let entry = this.tracks[i];
if (entry == null) continue;
// Store properties for non-mixingFrom entry but don't set timelinesLast, which is only used for mixingFrom entries.
let timelines = entry.animation.timelines;
for (let ii = 0, nn = entry.animation.timelines.length; ii < nn; ii++)
propertyIDs.add(timelines[ii].getPropertyId());
entry = entry.mixingFrom;
while (entry != null) {
this.checkTimelinesUsage(entry, entry.timelinesLast);
entry = entry.mixingFrom;
} }
} }
} }
setTimelinesFirst (entry: TrackEntry) {
if (entry.mixingFrom != null) {
this.setTimelinesFirst(entry.mixingFrom);
this.checkTimelinesUsage(entry, entry.timelinesFirst);
return;
}
let propertyIDs = this.propertyIDs;
let timelines = entry.animation.timelines;
let n = timelines.length;
let usage = Utils.setArraySize(entry.timelinesFirst, n, false);
for (let i = 0; i < n; i++) {
propertyIDs.add(timelines[i].getPropertyId());
usage[i] = true;
}
}
checkTimelinesFirst (entry: TrackEntry) {
if (entry.mixingFrom != null) this.checkTimelinesFirst(entry.mixingFrom);
this.checkTimelinesUsage(entry, entry.timelinesFirst);
}
checkTimelinesUsage (entry: TrackEntry, usageArray: Array<boolean>) {
let propertyIDs = this.propertyIDs;
let timelines = entry.animation.timelines;
let n = timelines.length;
let usage = Utils.setArraySize(usageArray, n);
for (let i = 0; i < n; i++)
usage[i] = propertyIDs.add(timelines[i].getPropertyId());
}
getCurrent (trackIndex: number) { getCurrent (trackIndex: number) {
if (trackIndex >= this.tracks.length) return null; if (trackIndex >= this.tracks.length) return null;
return this.tracks[trackIndex]; return this.tracks[trackIndex];
@ -624,9 +574,9 @@ module spine {
eventThreshold: number; attachmentThreshold: number; drawOrderThreshold: number; eventThreshold: number; attachmentThreshold: number; drawOrderThreshold: number;
animationStart: number; animationEnd: number; animationLast: number; nextAnimationLast: number; animationStart: number; animationEnd: number; animationLast: number; nextAnimationLast: number;
delay: number; trackTime: number; trackLast: number; nextTrackLast: number; trackEnd: number; timeScale: number; delay: number; trackTime: number; trackLast: number; nextTrackLast: number; trackEnd: number; timeScale: number;
alpha: number; mixTime: number; mixDuration: number; mixAlpha: number; alpha: number; mixTime: number; mixDuration: number; interruptAlpha: number;
timelinesFirst = new Array<boolean>(); timelineData = new Array<number>();
timelinesLast = new Array<boolean>(); timelineDipMix = new Array<TrackEntry>();
timelinesRotation = new Array<number>(); timelinesRotation = new Array<number>();
reset () { reset () {
@ -634,11 +584,52 @@ module spine {
this.mixingFrom = null; this.mixingFrom = null;
this.animation = null; this.animation = null;
this.listener = null; this.listener = null;
this.timelinesFirst.length = 0; this.timelineData.length = 0;
this.timelinesLast.length = 0; this.timelineDipMix.length = 0;
this.timelinesRotation.length = 0; this.timelinesRotation.length = 0;
} }
setTimelineData (to: TrackEntry, mixingToArray: Array<TrackEntry>, propertyIDs: IntSet) : TrackEntry {
if (to != null) mixingToArray.push(to);
let lastEntry = this.mixingFrom != null ? this.mixingFrom.setTimelineData(this, mixingToArray, propertyIDs) : this;
if (to != null) mixingToArray.pop();
let mixingTo = mixingToArray;
let mixingToLast = mixingToArray.length - 1;
let timelines = this.animation.timelines;
let timelinesCount = this.animation.timelines.length;
let timelineData = Utils.setArraySize(this.timelineData, timelinesCount);
let timelineDipMix = Utils.setArraySize(this.timelineDipMix, timelinesCount);
outer:
for (var i = 0; i < timelinesCount; i++) {
let id = timelines[i].getPropertyId();
if (!propertyIDs.add(id))
timelineData[i] = AnimationState.SUBSEQUENT;
else if (to == null || !to.hasTimeline(id))
timelineData[i] = AnimationState.FIRST;
else {
timelineData[i] = AnimationState.DIP;
for (var ii = mixingToLast; ii >= 0; ii--) {
let entry = mixingTo[ii];
if (!entry.hasTimeline(id)) {
timelineDipMix[i] = entry;
continue outer;
}
}
timelineDipMix[i] = null;
}
}
return lastEntry;
}
hasTimeline (id: number) : boolean {
let timelines = this.animation.timelines;
for (var i = 0, n = timelines.length; i < n; i++)
if (timelines[i].getPropertyId() == id) return true;
return false;
}
getAnimationTime () { getAnimationTime () {
if (this.loop) { if (this.loop) {
let duration = this.animationEnd - this.animationStart; let duration = this.animationEnd - this.animationStart;