@pixi-spine/runtime-3.7
Version:
Pixi runtime for spine 3.7 models
1 lines • 73.3 kB
Source Map (JSON)
{"version":3,"file":"AnimationState.mjs","sources":["../../src/core/AnimationState.ts"],"sourcesContent":["import { IAnimationState, IAnimationStateListener, ITrackEntry, MathUtils, MixBlend, MixDirection, Pool, IntSet, Utils } from '@pixi-spine/base';\nimport { Animation, AttachmentTimeline, DrawOrderTimeline, RotateTimeline, Timeline } from './Animation';\nimport type { AnimationStateData } from './AnimationStateData';\nimport type { Event } from './Event';\nimport type { Skeleton } from './Skeleton';\n\n/**\n * @public\n */\nexport class AnimationState implements IAnimationState<AnimationStateData> {\n static emptyAnimation = new Animation('<empty>', [], 0);\n static SUBSEQUENT = 0;\n static FIRST = 1;\n static HOLD = 2;\n static HOLD_MIX = 3;\n\n data: AnimationStateData;\n tracks = new Array<TrackEntry>();\n events = new Array<Event>();\n listeners = new Array<AnimationStateListener>();\n queue = new EventQueue(this);\n propertyIDs = new IntSet();\n animationsChanged = false;\n timeScale = 1;\n\n trackEntryPool = new Pool<TrackEntry>(() => new TrackEntry());\n\n constructor(data: AnimationStateData) {\n this.data = data;\n }\n\n update(delta: number) {\n delta *= this.timeScale;\n const tracks = this.tracks;\n\n for (let i = 0, n = tracks.length; i < n; i++) {\n const current = tracks[i];\n\n if (current == null) continue;\n\n current.animationLast = current.nextAnimationLast;\n current.trackLast = current.nextTrackLast;\n\n let currentDelta = delta * current.timeScale;\n\n if (current.delay > 0) {\n current.delay -= currentDelta;\n if (current.delay > 0) continue;\n currentDelta = -current.delay;\n current.delay = 0;\n }\n\n let next = current.next;\n\n if (next != null) {\n // When the next entry's delay is passed, change to the next entry, preserving leftover time.\n const nextTime = current.trackLast - next.delay;\n\n if (nextTime >= 0) {\n next.delay = 0;\n next.trackTime = current.timeScale == 0 ? 0 : (nextTime / current.timeScale + delta) * next.timeScale;\n current.trackTime += currentDelta;\n this.setCurrent(i, next, true);\n while (next.mixingFrom != null) {\n next.mixTime += delta;\n next = next.mixingFrom;\n }\n continue;\n }\n } else if (current.trackLast >= current.trackEnd && current.mixingFrom == null) {\n tracks[i] = null;\n this.queue.end(current);\n this.disposeNext(current);\n continue;\n }\n if (current.mixingFrom != null && this.updateMixingFrom(current, delta)) {\n // End mixing from entries once all have completed.\n let from = current.mixingFrom;\n\n current.mixingFrom = null;\n if (from != null) from.mixingTo = null;\n while (from != null) {\n this.queue.end(from);\n from = from.mixingFrom;\n }\n }\n\n current.trackTime += currentDelta;\n }\n\n this.queue.drain();\n }\n\n updateMixingFrom(to: TrackEntry, delta: number): boolean {\n const from = to.mixingFrom;\n\n if (from == null) return true;\n\n const finished = this.updateMixingFrom(from, delta);\n\n from.animationLast = from.nextAnimationLast;\n from.trackLast = from.nextTrackLast;\n\n // Require mixTime > 0 to ensure the mixing from entry was applied at least once.\n if (to.mixTime > 0 && to.mixTime >= to.mixDuration) {\n // Require totalAlpha == 0 to ensure mixing is complete, unless mixDuration == 0 (the transition is a single frame).\n if (from.totalAlpha == 0 || to.mixDuration == 0) {\n to.mixingFrom = from.mixingFrom;\n if (from.mixingFrom != null) from.mixingFrom.mixingTo = to;\n to.interruptAlpha = from.interruptAlpha;\n this.queue.end(from);\n }\n\n return finished;\n }\n\n from.trackTime += delta * from.timeScale;\n to.mixTime += delta;\n\n return false;\n }\n\n apply(skeleton: Skeleton): boolean {\n if (skeleton == null) throw new Error('skeleton cannot be null.');\n if (this.animationsChanged) this._animationsChanged();\n\n const events = this.events;\n const tracks = this.tracks;\n let applied = false;\n\n for (let i = 0, n = tracks.length; i < n; i++) {\n const current = tracks[i];\n\n if (current == null || current.delay > 0) continue;\n applied = true;\n const blend: MixBlend = i == 0 ? MixBlend.first : current.mixBlend;\n\n // Apply mixing from entries first.\n let mix = current.alpha;\n\n if (current.mixingFrom != null) mix *= this.applyMixingFrom(current, skeleton, blend);\n else if (current.trackTime >= current.trackEnd && current.next == null) mix = 0;\n\n // Apply current entry.\n const animationLast = current.animationLast;\n const animationTime = current.getAnimationTime();\n const timelineCount = current.animation.timelines.length;\n const timelines = current.animation.timelines;\n\n if ((i == 0 && mix == 1) || blend == MixBlend.add) {\n for (let ii = 0; ii < timelineCount; ii++) {\n // Fixes issue #302 on IOS9 where mix, blend sometimes became undefined and caused assets\n // to sometimes stop rendering when using color correction, as their RGBA values become NaN.\n // (https://github.com/pixijs/pixi-spine/issues/302)\n Utils.webkit602BugfixHelper(mix, blend);\n timelines[ii].apply(skeleton, animationLast, animationTime, events, mix, blend, MixDirection.mixIn);\n }\n } else {\n const timelineMode = current.timelineMode;\n\n const firstFrame = current.timelinesRotation.length == 0;\n\n if (firstFrame) Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null);\n const timelinesRotation = current.timelinesRotation;\n\n for (let ii = 0; ii < timelineCount; ii++) {\n const timeline = timelines[ii];\n const timelineBlend = timelineMode[ii] == AnimationState.SUBSEQUENT ? blend : MixBlend.setup;\n\n if (timeline instanceof RotateTimeline) {\n this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame);\n } else {\n // This fixes the WebKit 602 specific issue described at http://esotericsoftware.com/forum/iOS-10-disappearing-graphics-10109\n Utils.webkit602BugfixHelper(mix, blend);\n timeline.apply(skeleton, animationLast, animationTime, events, mix, timelineBlend, MixDirection.mixIn);\n }\n }\n }\n this.queueEvents(current, animationTime);\n events.length = 0;\n current.nextAnimationLast = animationTime;\n current.nextTrackLast = current.trackTime;\n }\n\n this.queue.drain();\n\n return applied;\n }\n\n applyMixingFrom(to: TrackEntry, skeleton: Skeleton, blend: MixBlend) {\n const from = to.mixingFrom;\n\n if (from.mixingFrom != null) this.applyMixingFrom(from, skeleton, blend);\n\n let mix = 0;\n\n if (to.mixDuration == 0) {\n // Single frame mix to undo mixingFrom changes.\n mix = 1;\n if (blend == MixBlend.first) blend = MixBlend.setup;\n } else {\n mix = to.mixTime / to.mixDuration;\n if (mix > 1) mix = 1;\n if (blend != MixBlend.first) blend = from.mixBlend;\n }\n\n const events = mix < from.eventThreshold ? this.events : null;\n const attachments = mix < from.attachmentThreshold;\n const drawOrder = mix < from.drawOrderThreshold;\n const animationLast = from.animationLast;\n const animationTime = from.getAnimationTime();\n const timelineCount = from.animation.timelines.length;\n const timelines = from.animation.timelines;\n const alphaHold = from.alpha * to.interruptAlpha;\n const alphaMix = alphaHold * (1 - mix);\n\n if (blend == MixBlend.add) {\n for (let i = 0; i < timelineCount; i++) timelines[i].apply(skeleton, animationLast, animationTime, events, alphaMix, blend, MixDirection.mixOut);\n } else {\n const timelineMode = from.timelineMode;\n const timelineHoldMix = from.timelineHoldMix;\n\n const firstFrame = from.timelinesRotation.length == 0;\n\n if (firstFrame) Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null);\n const timelinesRotation = from.timelinesRotation;\n\n from.totalAlpha = 0;\n for (let i = 0; i < timelineCount; i++) {\n const timeline = timelines[i];\n let direction = MixDirection.mixOut;\n let timelineBlend: MixBlend;\n let alpha = 0;\n\n switch (timelineMode[i]) {\n case AnimationState.SUBSEQUENT:\n if (!attachments && timeline instanceof AttachmentTimeline) continue;\n if (!drawOrder && timeline instanceof DrawOrderTimeline) continue;\n timelineBlend = blend;\n alpha = alphaMix;\n break;\n case AnimationState.FIRST:\n timelineBlend = MixBlend.setup;\n alpha = alphaMix;\n break;\n case AnimationState.HOLD:\n timelineBlend = MixBlend.setup;\n alpha = alphaHold;\n break;\n default:\n timelineBlend = MixBlend.setup;\n const holdMix = timelineHoldMix[i];\n\n alpha = alphaHold * Math.max(0, 1 - holdMix.mixTime / holdMix.mixDuration);\n break;\n }\n from.totalAlpha += alpha;\n if (timeline instanceof RotateTimeline) this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame);\n else {\n // This fixes the WebKit 602 specific issue described at http://esotericsoftware.com/forum/iOS-10-disappearing-graphics-10109\n Utils.webkit602BugfixHelper(alpha, blend);\n if (timelineBlend == MixBlend.setup) {\n if (timeline instanceof AttachmentTimeline) {\n if (attachments) direction = MixDirection.mixOut;\n } else if (timeline instanceof DrawOrderTimeline) {\n if (drawOrder) direction = MixDirection.mixOut;\n }\n }\n timeline.apply(skeleton, animationLast, animationTime, events, alpha, timelineBlend, direction);\n }\n }\n }\n\n if (to.mixDuration > 0) this.queueEvents(from, animationTime);\n this.events.length = 0;\n from.nextAnimationLast = animationTime;\n from.nextTrackLast = from.trackTime;\n\n return mix;\n }\n\n applyRotateTimeline(timeline: Timeline, skeleton: Skeleton, time: number, alpha: number, blend: MixBlend, timelinesRotation: Array<number>, i: number, firstFrame: boolean) {\n if (firstFrame) timelinesRotation[i] = 0;\n\n if (alpha == 1) {\n timeline.apply(skeleton, 0, time, null, 1, blend, MixDirection.mixIn);\n\n return;\n }\n\n const rotateTimeline = timeline as RotateTimeline;\n const frames = rotateTimeline.frames;\n const bone = skeleton.bones[rotateTimeline.boneIndex];\n let r1 = 0;\n let r2 = 0;\n\n if (time < frames[0]) {\n switch (blend) {\n case MixBlend.setup:\n bone.rotation = bone.data.rotation;\n default:\n return;\n case MixBlend.first:\n r1 = bone.rotation;\n r2 = bone.data.rotation;\n }\n } else {\n r1 = blend == MixBlend.setup ? bone.data.rotation : bone.rotation;\n if (time >= frames[frames.length - RotateTimeline.ENTRIES])\n // Time is after last frame.\n r2 = bone.data.rotation + frames[frames.length + RotateTimeline.PREV_ROTATION];\n else {\n // Interpolate between the previous frame and the current frame.\n const frame = Animation.binarySearch(frames, time, RotateTimeline.ENTRIES);\n const prevRotation = frames[frame + RotateTimeline.PREV_ROTATION];\n const frameTime = frames[frame];\n const percent = rotateTimeline.getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + RotateTimeline.PREV_TIME] - frameTime));\n\n r2 = frames[frame + RotateTimeline.ROTATION] - prevRotation;\n r2 -= (16384 - ((16384.499999999996 - r2 / 360) | 0)) * 360;\n r2 = prevRotation + r2 * percent + bone.data.rotation;\n r2 -= (16384 - ((16384.499999999996 - r2 / 360) | 0)) * 360;\n }\n }\n\n // Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.\n let total = 0;\n let diff = r2 - r1;\n\n diff -= (16384 - ((16384.499999999996 - diff / 360) | 0)) * 360;\n if (diff == 0) {\n total = timelinesRotation[i];\n } else {\n let lastTotal = 0;\n let lastDiff = 0;\n\n if (firstFrame) {\n lastTotal = 0;\n lastDiff = diff;\n } else {\n lastTotal = timelinesRotation[i]; // Angle and direction of mix, including loops.\n lastDiff = timelinesRotation[i + 1]; // Difference between bones.\n }\n const current = diff > 0;\n let dir = lastTotal >= 0;\n // Detect cross at 0 (not 180).\n\n if (MathUtils.signum(lastDiff) != MathUtils.signum(diff) && Math.abs(lastDiff) <= 90) {\n // A cross after a 360 rotation is a loop.\n if (Math.abs(lastTotal) > 180) lastTotal += 360 * MathUtils.signum(lastTotal);\n dir = current;\n }\n total = diff + lastTotal - (lastTotal % 360); // Store loops as part of lastTotal.\n if (dir != current) total += 360 * MathUtils.signum(lastTotal);\n timelinesRotation[i] = total;\n }\n timelinesRotation[i + 1] = diff;\n r1 += total * alpha;\n bone.rotation = r1 - (16384 - ((16384.499999999996 - r1 / 360) | 0)) * 360;\n }\n\n queueEvents(entry: TrackEntry, animationTime: number) {\n const animationStart = entry.animationStart;\n const animationEnd = entry.animationEnd;\n const duration = animationEnd - animationStart;\n const trackLastWrapped = entry.trackLast % duration;\n\n // Queue events before complete.\n const events = this.events;\n let i = 0;\n const n = events.length;\n\n for (; i < n; i++) {\n const event = events[i];\n\n if (event.time < trackLastWrapped) break;\n if (event.time > animationEnd) continue; // Discard events outside animation start/end.\n this.queue.event(entry, event);\n }\n\n // Queue complete if completed a loop iteration or the animation.\n let complete = false;\n\n if (entry.loop) complete = duration == 0 || trackLastWrapped > entry.trackTime % duration;\n else complete = animationTime >= animationEnd && entry.animationLast < animationEnd;\n if (complete) this.queue.complete(entry);\n\n // Queue events after complete.\n for (; i < n; i++) {\n const event = events[i];\n\n if (event.time < animationStart) continue; // Discard events outside animation start/end.\n this.queue.event(entry, events[i]);\n }\n }\n\n clearTracks() {\n const oldDrainDisabled = this.queue.drainDisabled;\n\n this.queue.drainDisabled = true;\n for (let i = 0, n = this.tracks.length; i < n; i++) this.clearTrack(i);\n this.tracks.length = 0;\n this.queue.drainDisabled = oldDrainDisabled;\n this.queue.drain();\n }\n\n clearTrack(trackIndex: number) {\n if (trackIndex >= this.tracks.length) return;\n const current = this.tracks[trackIndex];\n\n if (current == null) return;\n\n this.queue.end(current);\n\n this.disposeNext(current);\n\n let entry = current;\n\n while (true) {\n const from = entry.mixingFrom;\n\n if (from == null) break;\n this.queue.end(from);\n entry.mixingFrom = null;\n entry.mixingTo = null;\n entry = from;\n }\n\n this.tracks[current.trackIndex] = null;\n\n this.queue.drain();\n }\n\n setCurrent(index: number, current: TrackEntry, interrupt: boolean) {\n const from = this.expandToIndex(index);\n\n this.tracks[index] = current;\n\n if (from != null) {\n if (interrupt) this.queue.interrupt(from);\n current.mixingFrom = from;\n from.mixingTo = current;\n current.mixTime = 0;\n\n // Store the interrupted mix percentage.\n if (from.mixingFrom != null && from.mixDuration > 0) current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration);\n\n from.timelinesRotation.length = 0; // Reset rotation for mixing out, in case entry was mixed in.\n }\n\n this.queue.start(current);\n }\n\n setAnimation(trackIndex: number, animationName: string, loop: boolean) {\n const animation = this.data.skeletonData.findAnimation(animationName);\n\n if (animation == null) throw new Error(`Animation not found: ${animationName}`);\n\n return this.setAnimationWith(trackIndex, animation, loop);\n }\n\n setAnimationWith(trackIndex: number, animation: Animation, loop: boolean) {\n if (animation == null) throw new Error('animation cannot be null.');\n let interrupt = true;\n let current = this.expandToIndex(trackIndex);\n\n if (current != null) {\n if (current.nextTrackLast == -1) {\n // Don't mix from an entry that was never applied.\n this.tracks[trackIndex] = current.mixingFrom;\n this.queue.interrupt(current);\n this.queue.end(current);\n this.disposeNext(current);\n current = current.mixingFrom;\n interrupt = false;\n } else this.disposeNext(current);\n }\n const entry = this.trackEntry(trackIndex, animation, loop, current);\n\n this.setCurrent(trackIndex, entry, interrupt);\n this.queue.drain();\n\n return entry;\n }\n\n addAnimation(trackIndex: number, animationName: string, loop: boolean, delay: number) {\n const animation = this.data.skeletonData.findAnimation(animationName);\n\n if (animation == null) throw new Error(`Animation not found: ${animationName}`);\n\n return this.addAnimationWith(trackIndex, animation, loop, delay);\n }\n\n addAnimationWith(trackIndex: number, animation: Animation, loop: boolean, delay: number) {\n if (animation == null) throw new Error('animation cannot be null.');\n\n let last = this.expandToIndex(trackIndex);\n\n if (last != null) {\n while (last.next != null) last = last.next;\n }\n\n const entry = this.trackEntry(trackIndex, animation, loop, last);\n\n if (last == null) {\n this.setCurrent(trackIndex, entry, true);\n this.queue.drain();\n } else {\n last.next = entry;\n if (delay <= 0) {\n const duration = last.animationEnd - last.animationStart;\n\n if (duration != 0) {\n if (last.loop) delay += duration * (1 + ((last.trackTime / duration) | 0));\n else delay += Math.max(duration, last.trackTime);\n delay -= this.data.getMix(last.animation, animation);\n } else delay = last.trackTime;\n }\n }\n\n entry.delay = delay;\n\n return entry;\n }\n\n setEmptyAnimation(trackIndex: number, mixDuration: number) {\n const entry = this.setAnimationWith(trackIndex, AnimationState.emptyAnimation, false);\n\n entry.mixDuration = mixDuration;\n entry.trackEnd = mixDuration;\n\n return entry;\n }\n\n addEmptyAnimation(trackIndex: number, mixDuration: number, delay: number) {\n if (delay <= 0) delay -= mixDuration;\n const entry = this.addAnimationWith(trackIndex, AnimationState.emptyAnimation, false, delay);\n\n entry.mixDuration = mixDuration;\n entry.trackEnd = mixDuration;\n\n return entry;\n }\n\n setEmptyAnimations(mixDuration: number) {\n const oldDrainDisabled = this.queue.drainDisabled;\n\n this.queue.drainDisabled = true;\n for (let i = 0, n = this.tracks.length; i < n; i++) {\n const current = this.tracks[i];\n\n if (current != null) this.setEmptyAnimation(current.trackIndex, mixDuration);\n }\n this.queue.drainDisabled = oldDrainDisabled;\n this.queue.drain();\n }\n\n expandToIndex(index: number) {\n if (index < this.tracks.length) return this.tracks[index];\n Utils.ensureArrayCapacity(this.tracks, index - this.tracks.length + 1, null);\n this.tracks.length = index + 1;\n\n return null;\n }\n\n trackEntry(trackIndex: number, animation: Animation, loop: boolean, last: TrackEntry) {\n const entry = this.trackEntryPool.obtain();\n\n entry.trackIndex = trackIndex;\n entry.animation = animation;\n entry.loop = loop;\n entry.holdPrevious = false;\n\n entry.eventThreshold = 0;\n entry.attachmentThreshold = 0;\n entry.drawOrderThreshold = 0;\n\n entry.animationStart = 0;\n entry.animationEnd = animation.duration;\n entry.animationLast = -1;\n entry.nextAnimationLast = -1;\n\n entry.delay = 0;\n entry.trackTime = 0;\n entry.trackLast = -1;\n entry.nextTrackLast = -1;\n entry.trackEnd = Number.MAX_VALUE;\n entry.timeScale = 1;\n\n entry.alpha = 1;\n entry.interruptAlpha = 1;\n entry.mixTime = 0;\n entry.mixDuration = last == null ? 0 : this.data.getMix(last.animation, animation);\n\n return entry;\n }\n\n disposeNext(entry: TrackEntry) {\n let next = entry.next;\n\n while (next != null) {\n this.queue.dispose(next);\n next = next.next;\n }\n entry.next = null;\n }\n\n _animationsChanged() {\n this.animationsChanged = false;\n\n this.propertyIDs.clear();\n\n for (let i = 0, n = this.tracks.length; i < n; i++) {\n let entry = this.tracks[i];\n\n if (entry == null) continue;\n while (entry.mixingFrom != null) entry = entry.mixingFrom;\n\n do {\n if (entry.mixingFrom == null || entry.mixBlend != MixBlend.add) this.setTimelineModes(entry);\n entry = entry.mixingTo;\n } while (entry != null);\n }\n }\n\n setTimelineModes(entry: TrackEntry) {\n const to = entry.mixingTo;\n const timelines = entry.animation.timelines;\n const timelinesCount = entry.animation.timelines.length;\n const timelineMode = Utils.setArraySize(entry.timelineMode, timelinesCount);\n\n entry.timelineHoldMix.length = 0;\n const timelineDipMix = Utils.setArraySize(entry.timelineHoldMix, timelinesCount);\n const propertyIDs = this.propertyIDs;\n\n if (to != null && to.holdPrevious) {\n for (let i = 0; i < timelinesCount; i++) {\n propertyIDs.add(timelines[i].getPropertyId());\n timelineMode[i] = AnimationState.HOLD;\n }\n\n return;\n }\n\n // eslint-disable-next-line no-restricted-syntax, no-labels\n outer: for (let i = 0; i < timelinesCount; i++) {\n const id = timelines[i].getPropertyId();\n\n if (!propertyIDs.add(id)) timelineMode[i] = AnimationState.SUBSEQUENT;\n else if (to == null || !this.hasTimeline(to, id)) timelineMode[i] = AnimationState.FIRST;\n else {\n for (let next = to.mixingTo; next != null; next = next.mixingTo) {\n if (this.hasTimeline(next, id)) continue;\n if (entry.mixDuration > 0) {\n timelineMode[i] = AnimationState.HOLD_MIX;\n timelineDipMix[i] = next;\n // eslint-disable-next-line no-labels\n continue outer;\n }\n break;\n }\n timelineMode[i] = AnimationState.HOLD;\n }\n }\n }\n\n hasTimeline(entry: TrackEntry, id: number): boolean {\n const timelines = entry.animation.timelines;\n\n for (let i = 0, n = timelines.length; i < n; i++) if (timelines[i].getPropertyId() == id) return true;\n\n return false;\n }\n\n getCurrent(trackIndex: number) {\n if (trackIndex >= this.tracks.length) return null;\n\n return this.tracks[trackIndex];\n }\n\n addListener(listener: AnimationStateListener) {\n if (listener == null) throw new Error('listener cannot be null.');\n this.listeners.push(listener);\n }\n\n /** Removes the listener added with {@link #addListener(AnimationStateListener)}. */\n removeListener(listener: AnimationStateListener) {\n const index = this.listeners.indexOf(listener);\n\n if (index >= 0) this.listeners.splice(index, 1);\n }\n\n clearListeners() {\n this.listeners.length = 0;\n }\n\n clearListenerNotifications() {\n this.queue.clear();\n }\n\n // deprecated stuff\n onComplete: (trackIndex: number, loopCount: number) => any;\n onEvent: (trackIndex: number, event: Event) => any;\n onStart: (trackIndex: number) => any;\n onEnd: (trackIndex: number) => any;\n\n private static deprecatedWarning1 = false;\n\n setAnimationByName(trackIndex: number, animationName: string, loop: boolean) {\n if (!AnimationState.deprecatedWarning1) {\n AnimationState.deprecatedWarning1 = true;\n console.warn('Spine Deprecation Warning: AnimationState.setAnimationByName is deprecated, please use setAnimation from now on.');\n }\n this.setAnimation(trackIndex, animationName, loop);\n }\n\n private static deprecatedWarning2 = false;\n\n addAnimationByName(trackIndex: number, animationName: string, loop: boolean, delay: number) {\n if (!AnimationState.deprecatedWarning2) {\n AnimationState.deprecatedWarning2 = true;\n console.warn('Spine Deprecation Warning: AnimationState.addAnimationByName is deprecated, please use addAnimation from now on.');\n }\n this.addAnimation(trackIndex, animationName, loop, delay);\n }\n\n private static deprecatedWarning3 = false;\n\n hasAnimation(animationName: string): boolean {\n const animation = this.data.skeletonData.findAnimation(animationName);\n\n return animation !== null;\n }\n\n hasAnimationByName(animationName: string): boolean {\n if (!AnimationState.deprecatedWarning3) {\n AnimationState.deprecatedWarning3 = true;\n console.warn('Spine Deprecation Warning: AnimationState.hasAnimationByName is deprecated, please use hasAnimation from now on.');\n }\n\n return this.hasAnimation(animationName);\n }\n}\n\n/**\n * @public\n */\nexport class TrackEntry implements ITrackEntry {\n animation: Animation;\n next: TrackEntry;\n mixingFrom: TrackEntry;\n mixingTo: TrackEntry;\n listener: AnimationStateListener;\n trackIndex: number;\n loop: boolean;\n holdPrevious: boolean;\n eventThreshold: number;\n attachmentThreshold: number;\n drawOrderThreshold: number;\n animationStart: number;\n animationEnd: number;\n animationLast: number;\n nextAnimationLast: number;\n delay: number;\n trackTime: number;\n trackLast: number;\n nextTrackLast: number;\n trackEnd: number;\n timeScale: number;\n alpha: number;\n mixTime: number;\n mixDuration: number;\n interruptAlpha: number;\n totalAlpha: number;\n mixBlend = MixBlend.replace;\n timelineMode = new Array<number>();\n timelineHoldMix = new Array<TrackEntry>();\n timelinesRotation = new Array<number>();\n\n reset() {\n this.next = null;\n this.mixingFrom = null;\n this.mixingTo = null;\n this.animation = null;\n this.listener = null;\n this.timelineMode.length = 0;\n this.timelineHoldMix.length = 0;\n this.timelinesRotation.length = 0;\n }\n\n getAnimationTime() {\n if (this.loop) {\n const duration = this.animationEnd - this.animationStart;\n\n if (duration == 0) return this.animationStart;\n\n return (this.trackTime % duration) + this.animationStart;\n }\n\n return Math.min(this.trackTime + this.animationStart, this.animationEnd);\n }\n\n setAnimationLast(animationLast: number) {\n this.animationLast = animationLast;\n this.nextAnimationLast = animationLast;\n }\n\n isComplete() {\n return this.trackTime >= this.animationEnd - this.animationStart;\n }\n\n resetRotationDirections() {\n this.timelinesRotation.length = 0;\n }\n\n // deprecated stuff\n onComplete: (trackIndex: number, loopCount: number) => any;\n onEvent: (trackIndex: number, event: Event) => any;\n onStart: (trackIndex: number) => any;\n onEnd: (trackIndex: number) => any;\n\n private static deprecatedWarning1 = false;\n private static deprecatedWarning2 = false;\n\n get time() {\n if (!TrackEntry.deprecatedWarning1) {\n TrackEntry.deprecatedWarning1 = true;\n console.warn('Spine Deprecation Warning: TrackEntry.time is deprecated, please use trackTime from now on.');\n }\n\n return this.trackTime;\n }\n\n set time(value: number) {\n if (!TrackEntry.deprecatedWarning1) {\n TrackEntry.deprecatedWarning1 = true;\n console.warn('Spine Deprecation Warning: TrackEntry.time is deprecated, please use trackTime from now on.');\n }\n this.trackTime = value;\n }\n\n get endTime() {\n if (!TrackEntry.deprecatedWarning2) {\n TrackEntry.deprecatedWarning2 = true;\n console.warn('Spine Deprecation Warning: TrackEntry.endTime is deprecated, please use trackEnd from now on.');\n }\n\n return this.trackTime;\n }\n\n set endTime(value: number) {\n if (!TrackEntry.deprecatedWarning2) {\n TrackEntry.deprecatedWarning2 = true;\n console.warn('Spine Deprecation Warning: TrackEntry.endTime is deprecated, please use trackEnd from now on.');\n }\n this.trackTime = value;\n }\n\n loopsCount() {\n return Math.floor(this.trackTime / this.trackEnd);\n }\n}\n\n/**\n * @public\n */\nexport class EventQueue {\n objects: Array<any> = [];\n drainDisabled = false;\n animState: AnimationState;\n\n constructor(animState: AnimationState) {\n this.animState = animState;\n }\n\n start(entry: TrackEntry) {\n this.objects.push(EventType.start);\n this.objects.push(entry);\n this.animState.animationsChanged = true;\n }\n\n interrupt(entry: TrackEntry) {\n this.objects.push(EventType.interrupt);\n this.objects.push(entry);\n }\n\n end(entry: TrackEntry) {\n this.objects.push(EventType.end);\n this.objects.push(entry);\n this.animState.animationsChanged = true;\n }\n\n dispose(entry: TrackEntry) {\n this.objects.push(EventType.dispose);\n this.objects.push(entry);\n }\n\n complete(entry: TrackEntry) {\n this.objects.push(EventType.complete);\n this.objects.push(entry);\n }\n\n event(entry: TrackEntry, event: Event) {\n this.objects.push(EventType.event);\n this.objects.push(entry);\n this.objects.push(event);\n }\n\n private static deprecatedWarning1 = false;\n\n deprecateStuff() {\n if (!EventQueue.deprecatedWarning1) {\n EventQueue.deprecatedWarning1 = true;\n console.warn(\n \"Spine Deprecation Warning: onComplete, onStart, onEnd, onEvent art deprecated, please use listeners from now on. 'state.addListener({ complete: function(track, event) { } })'\"\n );\n }\n\n return true;\n }\n\n drain() {\n if (this.drainDisabled) return;\n this.drainDisabled = true;\n\n const objects = this.objects;\n const listeners = this.animState.listeners;\n\n for (let i = 0; i < objects.length; i += 2) {\n const type = objects[i] as EventType;\n const entry = objects[i + 1] as TrackEntry;\n\n switch (type) {\n case EventType.start:\n if (entry.listener != null && entry.listener.start) entry.listener.start(entry);\n for (let ii = 0; ii < listeners.length; ii++) if (listeners[ii].start) listeners[ii].start(entry);\n // deprecation\n entry.onStart && this.deprecateStuff() && entry.onStart(entry.trackIndex);\n this.animState.onStart && this.deprecateStuff() && this.deprecateStuff && this.animState.onStart(entry.trackIndex);\n break;\n case EventType.interrupt:\n if (entry.listener != null && entry.listener.interrupt) entry.listener.interrupt(entry);\n for (let ii = 0; ii < listeners.length; ii++) if (listeners[ii].interrupt) listeners[ii].interrupt(entry);\n break;\n case EventType.end:\n if (entry.listener != null && entry.listener.end) entry.listener.end(entry);\n for (let ii = 0; ii < listeners.length; ii++) if (listeners[ii].end) listeners[ii].end(entry);\n // deprecation\n entry.onEnd && this.deprecateStuff() && entry.onEnd(entry.trackIndex);\n this.animState.onEnd && this.deprecateStuff() && this.animState.onEnd(entry.trackIndex);\n // Fall through.\n case EventType.dispose:\n if (entry.listener != null && entry.listener.dispose) entry.listener.dispose(entry);\n for (let ii = 0; ii < listeners.length; ii++) if (listeners[ii].dispose) listeners[ii].dispose(entry);\n this.animState.trackEntryPool.free(entry);\n break;\n case EventType.complete:\n if (entry.listener != null && entry.listener.complete) entry.listener.complete(entry);\n for (let ii = 0; ii < listeners.length; ii++) if (listeners[ii].complete) listeners[ii].complete(entry);\n // deprecation\n\n const count = MathUtils.toInt(entry.loopsCount());\n\n entry.onComplete && this.deprecateStuff() && entry.onComplete(entry.trackIndex, count);\n this.animState.onComplete && this.deprecateStuff() && this.animState.onComplete(entry.trackIndex, count);\n break;\n case EventType.event:\n const event = objects[i++ + 2] as Event;\n\n if (entry.listener != null && entry.listener.event) entry.listener.event(entry, event);\n for (let ii = 0; ii < listeners.length; ii++) if (listeners[ii].event) listeners[ii].event(entry, event);\n // deprecation\n entry.onEvent && this.deprecateStuff() && entry.onEvent(entry.trackIndex, event);\n this.animState.onEvent && this.deprecateStuff() && this.animState.onEvent(entry.trackIndex, event);\n break;\n }\n }\n this.clear();\n\n this.drainDisabled = false;\n }\n\n clear() {\n this.objects.length = 0;\n }\n}\n\n/**\n * @public\n */\nexport enum EventType {\n start,\n interrupt,\n end,\n dispose,\n complete,\n event,\n}\n\n/**\n * @public\n */\nexport interface AnimationStateListener extends IAnimationStateListener {\n /** Invoked when this entry has been set as the current entry. */\n start?(entry: TrackEntry): void;\n\n /** Invoked when another entry has replaced this entry as the current entry. This entry may continue being applied for\n * mixing. */\n interrupt?(entry: TrackEntry): void;\n\n /** Invoked when this entry is no longer the current entry and will never be applied again. */\n end?(entry: TrackEntry): void;\n\n /** Invoked when this entry will be disposed. This may occur without the entry ever being set as the current entry.\n * References to the entry should not be kept after dispose is called, as it may be destroyed or reused. */\n dispose?(entry: TrackEntry): void;\n\n /** Invoked every time this entry's animation completes a loop. */\n complete?(entry: TrackEntry): void;\n\n /** Invoked when this entry's animation triggers an event. */\n event?(entry: TrackEntry, event: Event): void;\n}\n\n/**\n * @public\n */\nexport abstract class AnimationStateAdapter2 implements AnimationStateListener {\n start(entry: TrackEntry) {}\n\n interrupt(entry: TrackEntry) {}\n\n end(entry: TrackEntry) {}\n\n dispose(entry: TrackEntry) {}\n\n complete(entry: TrackEntry) {}\n\n event(entry: TrackEntry, event: Event) {}\n}\n"],"names":["EventType"],"mappings":"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