UNPKG

ngx-spine

Version:

[![Build Status](https://travis-ci.org/PoiScript/ngx-spine.svg?branch=master)](https://travis-ci.org/PoiScript/ngx-spine)

1,453 lines 141 kB
/** * @fileoverview added by tsickle * @suppress {checkTypes,constantProperty,extraRequire,missingOverride,missingReturn,unusedPrivateMembers,uselessCode} checked by tsc */ /****************************************************************************** * Spine Runtimes License Agreement * Last updated May 1, 2019. Replaces all prior versions. * * Copyright (c) 2013-2019, Esoteric Software LLC * * Integration of the Spine Runtimes into software or otherwise creating * derivative works of the Spine Runtimes is permitted under the terms and * conditions of Section 2 of the Spine Editor License Agreement: * http://esotericsoftware.com/spine-editor-license * * Otherwise, it is permitted to integrate the Spine Runtimes into software * or otherwise create derivative works of the Spine Runtimes (collectively, * "Products"), provided that each user of the Products must obtain their own * Spine Editor license and redistribution of the Products in any form must * include this license and copyright notice. * * THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN * NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS * INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *****************************************************************************/ import { MathUtils, Utils, IntSet, Pool } from "./Utils"; import { Animation, MixBlend, AttachmentTimeline, MixDirection, DrawOrderTimeline, RotateTimeline, EventTimeline } from "./Animation"; var AnimationState = /** @class */ (function () { function AnimationState(data) { this.tracks = new Array(); this.events = new Array(); this.listeners = new Array(); this.queue = new EventQueue(this); this.propertyIDs = new IntSet(); this.animationsChanged = false; this.timeScale = 1; this.trackEntryPool = new Pool((/** * @return {?} */ function () { return new TrackEntry(); })); this.data = data; } /** * @param {?} delta * @return {?} */ AnimationState.prototype.update = /** * @param {?} delta * @return {?} */ function (delta) { delta *= this.timeScale; /** @type {?} */ var tracks = this.tracks; for (var i = 0, n = tracks.length; i < n; i++) { /** @type {?} */ var current = tracks[i]; if (current == null) continue; current.animationLast = current.nextAnimationLast; current.trackLast = current.nextTrackLast; /** @type {?} */ var currentDelta = delta * current.timeScale; if (current.delay > 0) { current.delay -= currentDelta; if (current.delay > 0) continue; currentDelta = -current.delay; current.delay = 0; } /** @type {?} */ var next = current.next; if (next != null) { // When the next entry's delay is passed, change to the next entry, preserving leftover time. /** @type {?} */ var nextTime = current.trackLast - next.delay; if (nextTime >= 0) { next.delay = 0; next.trackTime += current.timeScale == 0 ? 0 : (nextTime / current.timeScale + delta) * next.timeScale; current.trackTime += currentDelta; this.setCurrent(i, next, true); while (next.mixingFrom != null) { next.mixTime += delta; next = next.mixingFrom; } continue; } } else if (current.trackLast >= current.trackEnd && current.mixingFrom == null) { tracks[i] = null; this.queue.end(current); this.disposeNext(current); continue; } if (current.mixingFrom != null && this.updateMixingFrom(current, delta)) { // End mixing from entries once all have completed. /** @type {?} */ var from = current.mixingFrom; current.mixingFrom = null; if (from != null) from.mixingTo = null; while (from != null) { this.queue.end(from); from = from.mixingFrom; } } current.trackTime += currentDelta; } this.queue.drain(); }; /** * @param {?} to * @param {?} delta * @return {?} */ AnimationState.prototype.updateMixingFrom = /** * @param {?} to * @param {?} delta * @return {?} */ function (to, delta) { /** @type {?} */ var from = to.mixingFrom; if (from == null) return true; /** @type {?} */ var finished = this.updateMixingFrom(from, delta); from.animationLast = from.nextAnimationLast; from.trackLast = from.nextTrackLast; // Require mixTime > 0 to ensure the mixing from entry was applied at least once. if (to.mixTime > 0 && to.mixTime >= to.mixDuration) { // Require totalAlpha == 0 to ensure mixing is complete, unless mixDuration == 0 (the transition is a single frame). if (from.totalAlpha == 0 || to.mixDuration == 0) { to.mixingFrom = from.mixingFrom; if (from.mixingFrom != null) from.mixingFrom.mixingTo = to; to.interruptAlpha = from.interruptAlpha; this.queue.end(from); } return finished; } from.trackTime += delta * from.timeScale; to.mixTime += delta; return false; }; /** * @param {?} skeleton * @return {?} */ AnimationState.prototype.apply = /** * @param {?} skeleton * @return {?} */ function (skeleton) { if (skeleton == null) throw new Error("skeleton cannot be null."); if (this.animationsChanged) this._animationsChanged(); /** @type {?} */ var events = this.events; /** @type {?} */ var tracks = this.tracks; /** @type {?} */ var applied = false; for (var i = 0, n = tracks.length; i < n; i++) { /** @type {?} */ var current = tracks[i]; if (current == null || current.delay > 0) continue; applied = true; /** @type {?} */ var blend = i == 0 ? MixBlend.first : current.mixBlend; // Apply mixing from entries first. /** @type {?} */ var mix = current.alpha; if (current.mixingFrom != null) mix *= this.applyMixingFrom(current, skeleton, blend); else if (current.trackTime >= current.trackEnd && current.next == null) mix = 0; // Apply current entry. /** @type {?} */ var animationLast = current.animationLast; /** @type {?} */ var animationTime = current.getAnimationTime(); /** @type {?} */ var timelineCount = current.animation.timelines.length; /** @type {?} */ var timelines = current.animation.timelines; if ((i == 0 && mix == 1) || blend == MixBlend.add) { for (var ii = 0; ii < timelineCount; ii++) { // Fixes issue #302 on IOS9 where mix, blend sometimes became undefined and caused assets // to sometimes stop rendering when using color correction, as their RGBA values become NaN. // (https://github.com/pixijs/pixi-spine/issues/302) Utils.webkit602BugfixHelper(mix, blend); timelines[ii].apply(skeleton, animationLast, animationTime, events, mix, blend, MixDirection.mixIn); } } else { /** @type {?} */ var timelineMode = current.timelineMode; /** @type {?} */ var firstFrame = current.timelinesRotation.length == 0; if (firstFrame) Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null); /** @type {?} */ var timelinesRotation = current.timelinesRotation; for (var ii = 0; ii < timelineCount; ii++) { /** @type {?} */ var timeline = timelines[ii]; /** @type {?} */ var timelineBlend = (timelineMode[ii] & (AnimationState.NOT_LAST - 1)) == AnimationState.SUBSEQUENT ? blend : MixBlend.setup; if (timeline instanceof RotateTimeline) { this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame); } else { // This fixes the WebKit 602 specific issue described at http://esotericsoftware.com/forum/iOS-10-disappearing-graphics-10109 Utils.webkit602BugfixHelper(mix, blend); timeline.apply(skeleton, animationLast, animationTime, events, mix, timelineBlend, MixDirection.mixIn); } } } this.queueEvents(current, animationTime); events.length = 0; current.nextAnimationLast = animationTime; current.nextTrackLast = current.trackTime; } this.queue.drain(); return applied; }; /** * @param {?} to * @param {?} skeleton * @param {?} blend * @return {?} */ AnimationState.prototype.applyMixingFrom = /** * @param {?} to * @param {?} skeleton * @param {?} blend * @return {?} */ function (to, skeleton, blend) { /** @type {?} */ var from = to.mixingFrom; if (from.mixingFrom != null) this.applyMixingFrom(from, skeleton, blend); /** @type {?} */ var mix = 0; if (to.mixDuration == 0) { // Single frame mix to undo mixingFrom changes. mix = 1; if (blend == MixBlend.first) blend = MixBlend.setup; } else { mix = to.mixTime / to.mixDuration; if (mix > 1) mix = 1; if (blend != MixBlend.first) blend = from.mixBlend; } /** @type {?} */ var events = mix < from.eventThreshold ? this.events : null; /** @type {?} */ var attachments = mix < from.attachmentThreshold; /** @type {?} */ var drawOrder = mix < from.drawOrderThreshold; /** @type {?} */ var animationLast = from.animationLast; /** @type {?} */ var animationTime = from.getAnimationTime(); /** @type {?} */ var timelineCount = from.animation.timelines.length; /** @type {?} */ var timelines = from.animation.timelines; /** @type {?} */ var alphaHold = from.alpha * to.interruptAlpha; /** @type {?} */ var alphaMix = alphaHold * (1 - mix); if (blend == MixBlend.add) { for (var i = 0; i < timelineCount; i++) timelines[i].apply(skeleton, animationLast, animationTime, events, alphaMix, blend, MixDirection.mixOut); } else { /** @type {?} */ var timelineMode = from.timelineMode; /** @type {?} */ var timelineHoldMix = from.timelineHoldMix; /** @type {?} */ var firstFrame = from.timelinesRotation.length == 0; if (firstFrame) Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null); /** @type {?} */ var timelinesRotation = from.timelinesRotation; from.totalAlpha = 0; for (var i = 0; i < timelineCount; i++) { /** @type {?} */ var timeline = timelines[i]; /** @type {?} */ var direction = MixDirection.mixOut; /** @type {?} */ var timelineBlend = void 0; /** @type {?} */ var alpha = 0; switch (timelineMode[i] & (AnimationState.NOT_LAST - 1)) { case AnimationState.SUBSEQUENT: timelineBlend = blend; if (!attachments && timeline instanceof AttachmentTimeline) { if ((timelineMode[i] & AnimationState.NOT_LAST) == AnimationState.NOT_LAST) continue; timelineBlend = MixBlend.setup; } if (!drawOrder && timeline instanceof DrawOrderTimeline) continue; alpha = alphaMix; break; case AnimationState.FIRST: timelineBlend = MixBlend.setup; alpha = alphaMix; break; case AnimationState.HOLD: timelineBlend = MixBlend.setup; alpha = alphaHold; break; default: timelineBlend = MixBlend.setup; /** @type {?} */ var holdMix = timelineHoldMix[i]; alpha = alphaHold * Math.max(0, 1 - holdMix.mixTime / holdMix.mixDuration); break; } from.totalAlpha += alpha; if (timeline instanceof RotateTimeline) this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame); else { // This fixes the WebKit 602 specific issue described at http://esotericsoftware.com/forum/iOS-10-disappearing-graphics-10109 Utils.webkit602BugfixHelper(alpha, blend); if (timelineBlend == MixBlend.setup) { if (timeline instanceof AttachmentTimeline) { if (attachments || (timelineMode[i] & AnimationState.NOT_LAST) == AnimationState.NOT_LAST) direction = MixDirection.mixIn; } else if (timeline instanceof DrawOrderTimeline) { if (drawOrder) direction = MixDirection.mixIn; } } timeline.apply(skeleton, animationLast, animationTime, events, alpha, timelineBlend, direction); } } } if (to.mixDuration > 0) this.queueEvents(from, animationTime); this.events.length = 0; from.nextAnimationLast = animationTime; from.nextTrackLast = from.trackTime; return mix; }; /** * @param {?} timeline * @param {?} skeleton * @param {?} time * @param {?} alpha * @param {?} blend * @param {?} timelinesRotation * @param {?} i * @param {?} firstFrame * @return {?} */ AnimationState.prototype.applyRotateTimeline = /** * @param {?} timeline * @param {?} skeleton * @param {?} time * @param {?} alpha * @param {?} blend * @param {?} timelinesRotation * @param {?} i * @param {?} firstFrame * @return {?} */ function (timeline, skeleton, time, alpha, blend, timelinesRotation, i, firstFrame) { if (firstFrame) timelinesRotation[i] = 0; if (alpha == 1) { timeline.apply(skeleton, 0, time, null, 1, blend, MixDirection.mixIn); return; } /** @type {?} */ var rotateTimeline = (/** @type {?} */ (timeline)); /** @type {?} */ var frames = rotateTimeline.frames; /** @type {?} */ var bone = skeleton.bones[rotateTimeline.boneIndex]; if (!bone.active) return; /** @type {?} */ var r1 = 0; /** @type {?} */ var r2 = 0; if (time < frames[0]) { switch (blend) { case MixBlend.setup: bone.rotation = bone.data.rotation; default: return; case MixBlend.first: r1 = bone.rotation; r2 = bone.data.rotation; } } else { r1 = blend == MixBlend.setup ? bone.data.rotation : bone.rotation; if (time >= frames[frames.length - RotateTimeline.ENTRIES]) // Time is after last frame. r2 = bone.data.rotation + frames[frames.length + RotateTimeline.PREV_ROTATION]; else { // Interpolate between the previous frame and the current frame. /** @type {?} */ var frame = Animation.binarySearch(frames, time, RotateTimeline.ENTRIES); /** @type {?} */ var prevRotation = frames[frame + RotateTimeline.PREV_ROTATION]; /** @type {?} */ var frameTime = frames[frame]; /** @type {?} */ var percent = rotateTimeline.getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + RotateTimeline.PREV_TIME] - frameTime)); r2 = frames[frame + RotateTimeline.ROTATION] - prevRotation; r2 -= (16384 - ((16384.499999999996 - r2 / 360) | 0)) * 360; r2 = prevRotation + r2 * percent + bone.data.rotation; r2 -= (16384 - ((16384.499999999996 - r2 / 360) | 0)) * 360; } } // Mix between rotations using the direction of the shortest route on the first frame while detecting crosses. /** @type {?} */ var total = 0; /** @type {?} */ var diff = r2 - r1; diff -= (16384 - ((16384.499999999996 - diff / 360) | 0)) * 360; if (diff == 0) { total = timelinesRotation[i]; } else { /** @type {?} */ var lastTotal = 0; /** @type {?} */ var lastDiff = 0; if (firstFrame) { lastTotal = 0; lastDiff = diff; } else { lastTotal = timelinesRotation[i]; // Angle and direction of mix, including loops. lastDiff = timelinesRotation[i + 1]; // Difference between bones. } /** @type {?} */ var current = diff > 0; /** @type {?} */ var dir = lastTotal >= 0; // Detect cross at 0 (not 180). if (MathUtils.signum(lastDiff) != MathUtils.signum(diff) && Math.abs(lastDiff) <= 90) { // A cross after a 360 rotation is a loop. if (Math.abs(lastTotal) > 180) lastTotal += 360 * MathUtils.signum(lastTotal); dir = current; } total = diff + lastTotal - (lastTotal % 360); // Store loops as part of lastTotal. if (dir != current) total += 360 * MathUtils.signum(lastTotal); timelinesRotation[i] = total; } timelinesRotation[i + 1] = diff; r1 += total * alpha; bone.rotation = r1 - (16384 - ((16384.499999999996 - r1 / 360) | 0)) * 360; }; /** * @param {?} entry * @param {?} animationTime * @return {?} */ AnimationState.prototype.queueEvents = /** * @param {?} entry * @param {?} animationTime * @return {?} */ function (entry, animationTime) { /** @type {?} */ var animationStart = entry.animationStart; /** @type {?} */ var animationEnd = entry.animationEnd; /** @type {?} */ var duration = animationEnd - animationStart; /** @type {?} */ var trackLastWrapped = entry.trackLast % duration; // Queue events before complete. /** @type {?} */ var events = this.events; /** @type {?} */ var i = 0; /** @type {?} */ var n = events.length; for (; i < n; i++) { /** @type {?} */ var event_1 = events[i]; if (event_1.time < trackLastWrapped) break; if (event_1.time > animationEnd) continue; // Discard events outside animation start/end. this.queue.event(entry, event_1); } // Queue complete if completed a loop iteration or the animation. /** @type {?} */ var complete = false; if (entry.loop) complete = duration == 0 || trackLastWrapped > entry.trackTime % duration; else complete = animationTime >= animationEnd && entry.animationLast < animationEnd; if (complete) this.queue.complete(entry); // Queue events after complete. for (; i < n; i++) { /** @type {?} */ var event_2 = events[i]; if (event_2.time < animationStart) continue; // Discard events outside animation start/end. this.queue.event(entry, events[i]); } }; /** * @return {?} */ AnimationState.prototype.clearTracks = /** * @return {?} */ function () { /** @type {?} */ var oldDrainDisabled = this.queue.drainDisabled; this.queue.drainDisabled = true; for (var i = 0, n = this.tracks.length; i < n; i++) this.clearTrack(i); this.tracks.length = 0; this.queue.drainDisabled = oldDrainDisabled; this.queue.drain(); }; /** * @param {?} trackIndex * @return {?} */ AnimationState.prototype.clearTrack = /** * @param {?} trackIndex * @return {?} */ function (trackIndex) { if (trackIndex >= this.tracks.length) return; /** @type {?} */ var current = this.tracks[trackIndex]; if (current == null) return; this.queue.end(current); this.disposeNext(current); /** @type {?} */ var entry = current; while (true) { /** @type {?} */ var from = entry.mixingFrom; if (from == null) break; this.queue.end(from); entry.mixingFrom = null; entry.mixingTo = null; entry = from; } this.tracks[current.trackIndex] = null; this.queue.drain(); }; /** * @param {?} index * @param {?} current * @param {?} interrupt * @return {?} */ AnimationState.prototype.setCurrent = /** * @param {?} index * @param {?} current * @param {?} interrupt * @return {?} */ function (index, current, interrupt) { /** @type {?} */ var from = this.expandToIndex(index); this.tracks[index] = current; if (from != null) { if (interrupt) this.queue.interrupt(from); current.mixingFrom = from; from.mixingTo = current; current.mixTime = 0; // Store the interrupted mix percentage. if (from.mixingFrom != null && from.mixDuration > 0) current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration); from.timelinesRotation.length = 0; // Reset rotation for mixing out, in case entry was mixed in. } this.queue.start(current); }; /** * @param {?} trackIndex * @param {?} animationName * @param {?} loop * @return {?} */ AnimationState.prototype.setAnimation = /** * @param {?} trackIndex * @param {?} animationName * @param {?} loop * @return {?} */ function (trackIndex, animationName, loop) { /** @type {?} */ var animation = this.data.skeletonData.findAnimation(animationName); if (animation == null) throw new Error("Animation not found: " + animationName); return this.setAnimationWith(trackIndex, animation, loop); }; /** * @param {?} trackIndex * @param {?} animation * @param {?} loop * @return {?} */ AnimationState.prototype.setAnimationWith = /** * @param {?} trackIndex * @param {?} animation * @param {?} loop * @return {?} */ function (trackIndex, animation, loop) { if (animation == null) throw new Error("animation cannot be null."); /** @type {?} */ var interrupt = true; /** @type {?} */ var current = this.expandToIndex(trackIndex); if (current != null) { if (current.nextTrackLast == -1) { // Don't mix from an entry that was never applied. this.tracks[trackIndex] = current.mixingFrom; this.queue.interrupt(current); this.queue.end(current); this.disposeNext(current); current = current.mixingFrom; interrupt = false; } else this.disposeNext(current); } /** @type {?} */ var entry = this.trackEntry(trackIndex, animation, loop, current); this.setCurrent(trackIndex, entry, interrupt); this.queue.drain(); return entry; }; /** * @param {?} trackIndex * @param {?} animationName * @param {?} loop * @param {?} delay * @return {?} */ AnimationState.prototype.addAnimation = /** * @param {?} trackIndex * @param {?} animationName * @param {?} loop * @param {?} delay * @return {?} */ function (trackIndex, animationName, loop, delay) { /** @type {?} */ var animation = this.data.skeletonData.findAnimation(animationName); if (animation == null) throw new Error("Animation not found: " + animationName); return this.addAnimationWith(trackIndex, animation, loop, delay); }; /** * @param {?} trackIndex * @param {?} animation * @param {?} loop * @param {?} delay * @return {?} */ AnimationState.prototype.addAnimationWith = /** * @param {?} trackIndex * @param {?} animation * @param {?} loop * @param {?} delay * @return {?} */ function (trackIndex, animation, loop, delay) { if (animation == null) throw new Error("animation cannot be null."); /** @type {?} */ var last = this.expandToIndex(trackIndex); if (last != null) { while (last.next != null) last = last.next; } /** @type {?} */ var entry = this.trackEntry(trackIndex, animation, loop, last); if (last == null) { this.setCurrent(trackIndex, entry, true); this.queue.drain(); } else { last.next = entry; if (delay <= 0) { /** @type {?} */ var duration = last.animationEnd - last.animationStart; if (duration != 0) { if (last.loop) delay += duration * (1 + ((last.trackTime / duration) | 0)); else delay += Math.max(duration, last.trackTime); delay -= this.data.getMix(last.animation, animation); } else delay = last.trackTime; } } entry.delay = delay; return entry; }; /** * @param {?} trackIndex * @param {?} mixDuration * @return {?} */ AnimationState.prototype.setEmptyAnimation = /** * @param {?} trackIndex * @param {?} mixDuration * @return {?} */ function (trackIndex, mixDuration) { /** @type {?} */ var entry = this.setAnimationWith(trackIndex, AnimationState.emptyAnimation, false); entry.mixDuration = mixDuration; entry.trackEnd = mixDuration; return entry; }; /** * @param {?} trackIndex * @param {?} mixDuration * @param {?} delay * @return {?} */ AnimationState.prototype.addEmptyAnimation = /** * @param {?} trackIndex * @param {?} mixDuration * @param {?} delay * @return {?} */ function (trackIndex, mixDuration, delay) { if (delay <= 0) delay -= mixDuration; /** @type {?} */ var entry = this.addAnimationWith(trackIndex, AnimationState.emptyAnimation, false, delay); entry.mixDuration = mixDuration; entry.trackEnd = mixDuration; return entry; }; /** * @param {?} mixDuration * @return {?} */ AnimationState.prototype.setEmptyAnimations = /** * @param {?} mixDuration * @return {?} */ function (mixDuration) { /** @type {?} */ var oldDrainDisabled = this.queue.drainDisabled; this.queue.drainDisabled = true; for (var i = 0, n = this.tracks.length; i < n; i++) { /** @type {?} */ var current = this.tracks[i]; if (current != null) this.setEmptyAnimation(current.trackIndex, mixDuration); } this.queue.drainDisabled = oldDrainDisabled; this.queue.drain(); }; /** * @param {?} index * @return {?} */ AnimationState.prototype.expandToIndex = /** * @param {?} index * @return {?} */ function (index) { if (index < this.tracks.length) return this.tracks[index]; Utils.ensureArrayCapacity(this.tracks, index + 1, null); this.tracks.length = index + 1; return null; }; /** * @param {?} trackIndex * @param {?} animation * @param {?} loop * @param {?} last * @return {?} */ AnimationState.prototype.trackEntry = /** * @param {?} trackIndex * @param {?} animation * @param {?} loop * @param {?} last * @return {?} */ function (trackIndex, animation, loop, last) { /** @type {?} */ var entry = this.trackEntryPool.obtain(); entry.trackIndex = trackIndex; entry.animation = animation; entry.loop = loop; entry.holdPrevious = false; entry.eventThreshold = 0; entry.attachmentThreshold = 0; entry.drawOrderThreshold = 0; entry.animationStart = 0; entry.animationEnd = animation.duration; entry.animationLast = -1; entry.nextAnimationLast = -1; entry.delay = 0; entry.trackTime = 0; entry.trackLast = -1; entry.nextTrackLast = -1; entry.trackEnd = Number.MAX_VALUE; entry.timeScale = 1; entry.alpha = 1; entry.interruptAlpha = 1; entry.mixTime = 0; entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation); return entry; }; /** * @param {?} entry * @return {?} */ AnimationState.prototype.disposeNext = /** * @param {?} entry * @return {?} */ function (entry) { /** @type {?} */ var next = entry.next; while (next != null) { this.queue.dispose(next); next = next.next; } entry.next = null; }; /** * @return {?} */ AnimationState.prototype._animationsChanged = /** * @return {?} */ function () { this.animationsChanged = false; this.propertyIDs.clear(); for (var i = 0, n = this.tracks.length; i < n; i++) { /** @type {?} */ var entry = this.tracks[i]; if (entry == null) continue; while (entry.mixingFrom != null) entry = entry.mixingFrom; do { if (entry.mixingFrom == null || entry.mixBlend != MixBlend.add) this.computeHold(entry); entry = entry.mixingTo; } while (entry != null); } this.propertyIDs.clear(); for (var i = this.tracks.length - 1; i >= 0; i--) { /** @type {?} */ var entry = this.tracks[i]; while (entry != null) { this.computeNotLast(entry); entry = entry.mixingFrom; } } }; /** * @param {?} entry * @return {?} */ AnimationState.prototype.computeHold = /** * @param {?} entry * @return {?} */ function (entry) { /** @type {?} */ var to = entry.mixingTo; /** @type {?} */ var timelines = entry.animation.timelines; /** @type {?} */ var timelinesCount = entry.animation.timelines.length; /** @type {?} */ var timelineMode = Utils.setArraySize(entry.timelineMode, timelinesCount); entry.timelineHoldMix.length = 0; /** @type {?} */ var timelineDipMix = Utils.setArraySize(entry.timelineHoldMix, timelinesCount); /** @type {?} */ var propertyIDs = this.propertyIDs; if (to != null && to.holdPrevious) { for (var i = 0; i < timelinesCount; i++) { propertyIDs.add(timelines[i].getPropertyId()); timelineMode[i] = AnimationState.HOLD; } return; } outer: for (var i = 0; i < timelinesCount; i++) { /** @type {?} */ var timeline = timelines[i]; /** @type {?} */ var id = timeline.getPropertyId(); if (!propertyIDs.add(id)) timelineMode[i] = AnimationState.SUBSEQUENT; else if (to == null || timeline instanceof AttachmentTimeline || timeline instanceof DrawOrderTimeline || timeline instanceof EventTimeline || !to.animation.hasTimeline(id)) { timelineMode[i] = AnimationState.FIRST; } else { for (var next = to.mixingTo; next != null; next = next.mixingTo) { if (next.animation.hasTimeline(id)) continue; if (entry.mixDuration > 0) { timelineMode[i] = AnimationState.HOLD_MIX; timelineDipMix[i] = next; continue outer; } break; } timelineMode[i] = AnimationState.HOLD; } } }; /** * @param {?} entry * @return {?} */ AnimationState.prototype.computeNotLast = /** * @param {?} entry * @return {?} */ function (entry) { /** @type {?} */ var timelines = entry.animation.timelines; /** @type {?} */ var timelinesCount = entry.animation.timelines.length; /** @type {?} */ var timelineMode = entry.timelineMode; /** @type {?} */ var propertyIDs = this.propertyIDs; for (var i = 0; i < timelinesCount; i++) { if (timelines[i] instanceof AttachmentTimeline) { /** @type {?} */ var timeline = (/** @type {?} */ (timelines[i])); if (!propertyIDs.add(timeline.slotIndex)) timelineMode[i] |= AnimationState.NOT_LAST; } } }; /** * @param {?} trackIndex * @return {?} */ AnimationState.prototype.getCurrent = /** * @param {?} trackIndex * @return {?} */ function (trackIndex) { if (trackIndex >= this.tracks.length) return null; return this.tracks[trackIndex]; }; /** * @param {?} listener * @return {?} */ AnimationState.prototype.addListener = /** * @param {?} listener * @return {?} */ function (listener) { if (listener == null) throw new Error("listener cannot be null."); this.listeners.push(listener); }; /** Removes the listener added with {@link #addListener(AnimationStateListener)}. */ /** * Removes the listener added with {\@link #addListener(AnimationStateListener)}. * @param {?} listener * @return {?} */ AnimationState.prototype.removeListener = /** * Removes the listener added with {\@link #addListener(AnimationStateListener)}. * @param {?} listener * @return {?} */ function (listener) { /** @type {?} */ var index = this.listeners.indexOf(listener); if (index >= 0) this.listeners.splice(index, 1); }; /** * @return {?} */ AnimationState.prototype.clearListeners = /** * @return {?} */ function () { this.listeners.length = 0; }; /** * @return {?} */ AnimationState.prototype.clearListenerNotifications = /** * @return {?} */ function () { this.queue.clear(); }; AnimationState.emptyAnimation = new Animation("<empty>", [], 0); AnimationState.SUBSEQUENT = 0; AnimationState.FIRST = 1; AnimationState.HOLD = 2; AnimationState.HOLD_MIX = 3; AnimationState.NOT_LAST = 4; return AnimationState; }()); export { AnimationState }; if (false) { /** @type {?} */ AnimationState.emptyAnimation; /** @type {?} */ AnimationState.SUBSEQUENT; /** @type {?} */ AnimationState.FIRST; /** @type {?} */ AnimationState.HOLD; /** @type {?} */ AnimationState.HOLD_MIX; /** @type {?} */ AnimationState.NOT_LAST; /** @type {?} */ AnimationState.prototype.data; /** @type {?} */ AnimationState.prototype.tracks; /** @type {?} */ AnimationState.prototype.events; /** @type {?} */ AnimationState.prototype.listeners; /** @type {?} */ AnimationState.prototype.queue; /** @type {?} */ AnimationState.prototype.propertyIDs; /** @type {?} */ AnimationState.prototype.animationsChanged; /** @type {?} */ AnimationState.prototype.timeScale; /** @type {?} */ AnimationState.prototype.trackEntryPool; } var TrackEntry = /** @class */ (function () { function TrackEntry() { this.mixBlend = MixBlend.replace; this.timelineMode = new Array(); this.timelineHoldMix = new Array(); this.timelinesRotation = new Array(); } /** * @return {?} */ TrackEntry.prototype.reset = /** * @return {?} */ function () { this.next = null; this.mixingFrom = null; this.mixingTo = null; this.animation = null; this.listener = null; this.timelineMode.length = 0; this.timelineHoldMix.length = 0; this.timelinesRotation.length = 0; }; /** * @return {?} */ TrackEntry.prototype.getAnimationTime = /** * @return {?} */ function () { if (this.loop) { /** @type {?} */ var duration = this.animationEnd - this.animationStart; if (duration == 0) return this.animationStart; return (this.trackTime % duration) + this.animationStart; } return Math.min(this.trackTime + this.animationStart, this.animationEnd); }; /** * @param {?} animationLast * @return {?} */ TrackEntry.prototype.setAnimationLast = /** * @param {?} animationLast * @return {?} */ function (animationLast) { this.animationLast = animationLast; this.nextAnimationLast = animationLast; }; /** * @return {?} */ TrackEntry.prototype.isComplete = /** * @return {?} */ function () { return this.trackTime >= this.animationEnd - this.animationStart; }; /** * @return {?} */ TrackEntry.prototype.resetRotationDirections = /** * @return {?} */ function () { this.timelinesRotation.length = 0; }; return TrackEntry; }()); export { TrackEntry }; if (false) { /** @type {?} */ TrackEntry.prototype.animation; /** @type {?} */ TrackEntry.prototype.next; /** @type {?} */ TrackEntry.prototype.mixingFrom; /** @type {?} */ TrackEntry.prototype.mixingTo; /** @type {?} */ TrackEntry.prototype.listener; /** @type {?} */ TrackEntry.prototype.trackIndex; /** @type {?} */ TrackEntry.prototype.loop; /** @type {?} */ TrackEntry.prototype.holdPrevious; /** @type {?} */ TrackEntry.prototype.eventThreshold; /** @type {?} */ TrackEntry.prototype.attachmentThreshold; /** @type {?} */ TrackEntry.prototype.drawOrderThreshold; /** @type {?} */ TrackEntry.prototype.animationStart; /** @type {?} */ TrackEntry.prototype.animationEnd; /** @type {?} */ TrackEntry.prototype.animationLast; /** @type {?} */ TrackEntry.prototype.nextAnimationLast; /** @type {?} */ TrackEntry.prototype.delay; /** @type {?} */ TrackEntry.prototype.trackTime; /** @type {?} */ TrackEntry.prototype.trackLast; /** @type {?} */ TrackEntry.prototype.nextTrackLast; /** @type {?} */ TrackEntry.prototype.trackEnd; /** @type {?} */ TrackEntry.prototype.timeScale; /** @type {?} */ TrackEntry.prototype.alpha; /** @type {?} */ TrackEntry.prototype.mixTime; /** @type {?} */ TrackEntry.prototype.mixDuration; /** @type {?} */ TrackEntry.prototype.interruptAlpha; /** @type {?} */ TrackEntry.prototype.totalAlpha; /** @type {?} */ TrackEntry.prototype.mixBlend; /** @type {?} */ TrackEntry.prototype.timelineMode; /** @type {?} */ TrackEntry.prototype.timelineHoldMix; /** @type {?} */ TrackEntry.prototype.timelinesRotation; } var EventQueue = /** @class */ (function () { function EventQueue(animState) { this.objects = []; this.drainDisabled = false; this.animState = animState; } /** * @param {?} entry * @return {?} */ EventQueue.prototype.start = /** * @param {?} entry * @return {?} */ function (entry) { this.objects.push(EventType.start); this.objects.push(entry); this.animState.animationsChanged = true; }; /** * @param {?} entry * @return {?} */ EventQueue.prototype.interrupt = /** * @param {?} entry * @return {?} */ function (entry) { this.objects.push(EventType.interrupt); this.objects.push(entry); }; /** * @param {?} entry * @return {?} */ EventQueue.prototype.end = /** * @param {?} entry * @return {?} */ function (entry) { this.objects.push(EventType.end); this.objects.push(entry); this.animState.animationsChanged = true; }; /** * @param {?} entry * @return {?} */ EventQueue.prototype.dispose = /** * @param {?} entry * @return {?} */ function (entry) { this.objects.push(EventType.dispose); this.objects.push(entry); }; /** * @param {?} entry * @return {?} */ EventQueue.prototype.complete = /** * @param {?} entry * @return {?} */ function (entry) { this.objects.push(EventType.complete); this.objects.push(entry); }; /** * @param {?} entry * @param {?} event * @return {?} */ EventQueue.prototype.event = /** * @param {?} entry * @param {?} event * @return {?} */ function (entry, event) { this.objects.push(EventType.event); this.objects.push(entry); this.objects.push(event); }; /** * @return {?} */ EventQueue.prototype.drain = /** * @return {?} */ function () { if (this.drainDisabled) return; this.drainDisabled = true; /** @type {?} */ var objects = this.objects; /** @type {?} */ var listeners = this.animState.listeners; for (var i = 0; i < objects.length; i += 2) { /** @type {?} */ var type = (/** @type {?} */ (objects[i])); /** @type {?} */ var entry = (/** @type {?} */ (objects[i + 1])); switch (type) { case EventType.start: if (entry.listener != null && entry.listener.start) entry.listener.start(entry); for (var ii = 0; ii < listeners.length; ii++) if (listeners[ii].start) listeners[ii].start(entry); break; case EventType.interrupt: if (entry.listener != null && entry.listener.interrupt) entry.listener.interrupt(entry); for (var ii = 0; ii < listeners.length; ii++) if (listeners[ii].interrupt) listeners[ii].interrupt(entry); break; case EventType.end: if (entry.listener != null && entry.listener.end) entry.listener.end(entry); for (var ii = 0; ii < listeners.length; ii++) if (listeners[ii].end) listeners[ii].end(entry); // Fall through. case EventType.dispose: if (entry.listener != null && entry.listener.dispose) entry.listener.dispose(entry); for (var ii = 0; ii < listeners.length; ii++) if (listeners[ii].dispose) listeners[ii].dispose(entry); this.animState.trackEntryPool.free(entry); break; case EventType.complete: if (entry.listener != null && entry.listener.complete) entry.listener.complete(entry); for (var ii = 0; ii < listeners.length; ii++) if (listeners[ii].complete) listeners[ii].complete(entry); break; case EventType.event: /** @type {?} */ var event_3 = (/** @type {?} */ (objects[i++ + 2])); if (entry.listener != null && entry.listener.event) entry.listener.event(entry, event_3); for (var ii = 0; ii < listeners.length; ii++) if (listeners[ii].event) listeners[ii].event(entry, event_3); break; } } this.clear(); this.drainDisabled = false; }; /** * @return {?} */ EventQueue.prototype.clear = /** * @return {?} */ function () { this.objects.length = 0; }; return EventQueue; }()); export { EventQueue }; if (false) { /** @type {?} */ EventQueue.prototype.objects; /** @type {?} */ EventQueue.prototype.drainDisabled; /** @type {?} */ EventQueue.prototype.animState; } /** @enum {number} */ var EventType = { start: 0, interrupt: 1, end: 2, dispose: 3, complete: 4, event: 5, }; export { EventType }; EventType[EventType.start] = 'start'; EventType[EventType.interrupt] = 'interrupt'; EventType[EventType.end] = 'end'; EventType[EventType.dispose] = 'dispose'; EventType[EventType.complete] = 'complete'; EventType[EventType.event] = 'event'; /** * @record */ export function AnimationStateListener2() { } if (false) { /** * Invoked when this entry has been set as the current entry. * @param {?} entry * @return {?} */ AnimationStateListener2.prototype.start = function (entry) { }; /** * Invoked when another entry has replaced this entry as the current entry. This entry may continue being applied for * mixing. * @param {?} entry * @return {?} */ AnimationStateListener2.prototype.interrupt = function (entry) { }; /** * Invoked when this entry is no longer the current entry and will never be applied again. * @param {?} entry * @return {?} */ AnimationStateListener2.prototype.end = function (entry) { }; /** * Invoked when this entry will be disposed. This may occur without the entry ever being set as the current en