UNPKG

ngx-spine

Version:

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

1,452 lines 255 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 } from "./Utils"; import { VertexAttachment } from "./attachments/Attachment"; export class Animation { /** * @param {?} name * @param {?} timelines * @param {?} duration */ constructor(name, timelines, duration) { if (name == null) throw new Error("name cannot be null."); if (timelines == null) throw new Error("timelines cannot be null."); this.name = name; this.timelines = timelines; this.timelineIds = []; for (var i = 0; i < timelines.length; i++) this.timelineIds[timelines[i].getPropertyId()] = true; this.duration = duration; } /** * @param {?} id * @return {?} */ hasTimeline(id) { return this.timelineIds[id] == true; } /** * @param {?} skeleton * @param {?} lastTime * @param {?} time * @param {?} loop * @param {?} events * @param {?} alpha * @param {?} blend * @param {?} direction * @return {?} */ apply(skeleton, lastTime, time, loop, events, alpha, blend, direction) { if (skeleton == null) throw new Error("skeleton cannot be null."); if (loop && this.duration != 0) { time %= this.duration; if (lastTime > 0) lastTime %= this.duration; } /** @type {?} */ let timelines = this.timelines; for (let i = 0, n = timelines.length; i < n; i++) timelines[i].apply(skeleton, lastTime, time, events, alpha, blend, direction); } /** * @param {?} values * @param {?} target * @param {?=} step * @return {?} */ static binarySearch(values, target, step = 1) { /** @type {?} */ let low = 0; /** @type {?} */ let high = values.length / step - 2; if (high == 0) return step; /** @type {?} */ let current = high >>> 1; while (true) { if (values[(current + 1) * step] <= target) low = current + 1; else high = current; if (low == high) return (low + 1) * step; current = (low + high) >>> 1; } } /** * @param {?} values * @param {?} target * @param {?} step * @return {?} */ static linearSearch(values, target, step) { for (let i = 0, last = values.length - step; i <= last; i += step) if (values[i] > target) return i; return -1; } } if (false) { /** @type {?} */ Animation.prototype.name; /** @type {?} */ Animation.prototype.timelines; /** @type {?} */ Animation.prototype.timelineIds; /** @type {?} */ Animation.prototype.duration; } /** * @record */ export function Timeline() { } if (false) { /** * @param {?} skeleton * @param {?} lastTime * @param {?} time * @param {?} events * @param {?} alpha * @param {?} blend * @param {?} direction * @return {?} */ Timeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { }; /** * @return {?} */ Timeline.prototype.getPropertyId = function () { }; } /** @enum {number} */ const MixBlend = { setup: 0, first: 1, replace: 2, add: 3, }; export { MixBlend }; MixBlend[MixBlend.setup] = 'setup'; MixBlend[MixBlend.first] = 'first'; MixBlend[MixBlend.replace] = 'replace'; MixBlend[MixBlend.add] = 'add'; /** @enum {number} */ const MixDirection = { mixIn: 0, mixOut: 1, }; export { MixDirection }; MixDirection[MixDirection.mixIn] = 'mixIn'; MixDirection[MixDirection.mixOut] = 'mixOut'; /** @enum {number} */ const TimelineType = { rotate: 0, translate: 1, scale: 2, shear: 3, attachment: 4, color: 5, deform: 6, event: 7, drawOrder: 8, ikConstraint: 9, transformConstraint: 10, pathConstraintPosition: 11, pathConstraintSpacing: 12, pathConstraintMix: 13, twoColor: 14, }; export { TimelineType }; TimelineType[TimelineType.rotate] = 'rotate'; TimelineType[TimelineType.translate] = 'translate'; TimelineType[TimelineType.scale] = 'scale'; TimelineType[TimelineType.shear] = 'shear'; TimelineType[TimelineType.attachment] = 'attachment'; TimelineType[TimelineType.color] = 'color'; TimelineType[TimelineType.deform] = 'deform'; TimelineType[TimelineType.event] = 'event'; TimelineType[TimelineType.drawOrder] = 'drawOrder'; TimelineType[TimelineType.ikConstraint] = 'ikConstraint'; TimelineType[TimelineType.transformConstraint] = 'transformConstraint'; TimelineType[TimelineType.pathConstraintPosition] = 'pathConstraintPosition'; TimelineType[TimelineType.pathConstraintSpacing] = 'pathConstraintSpacing'; TimelineType[TimelineType.pathConstraintMix] = 'pathConstraintMix'; TimelineType[TimelineType.twoColor] = 'twoColor'; /** * @abstract */ export class CurveTimeline { /** * @param {?} frameCount */ constructor(frameCount) { if (frameCount <= 0) throw new Error("frameCount must be > 0: " + frameCount); this.curves = Utils.newFloatArray((frameCount - 1) * CurveTimeline.BEZIER_SIZE); } /** * @return {?} */ getFrameCount() { return this.curves.length / CurveTimeline.BEZIER_SIZE + 1; } /** * @param {?} frameIndex * @return {?} */ setLinear(frameIndex) { this.curves[frameIndex * CurveTimeline.BEZIER_SIZE] = CurveTimeline.LINEAR; } /** * @param {?} frameIndex * @return {?} */ setStepped(frameIndex) { this.curves[frameIndex * CurveTimeline.BEZIER_SIZE] = CurveTimeline.STEPPED; } /** * @param {?} frameIndex * @return {?} */ getCurveType(frameIndex) { /** @type {?} */ let index = frameIndex * CurveTimeline.BEZIER_SIZE; if (index == this.curves.length) return CurveTimeline.LINEAR; /** @type {?} */ let type = this.curves[index]; if (type == CurveTimeline.LINEAR) return CurveTimeline.LINEAR; if (type == CurveTimeline.STEPPED) return CurveTimeline.STEPPED; return CurveTimeline.BEZIER; } /** * Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next. * cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of * the difference between the keyframe's values. * @param {?} frameIndex * @param {?} cx1 * @param {?} cy1 * @param {?} cx2 * @param {?} cy2 * @return {?} */ setCurve(frameIndex, cx1, cy1, cx2, cy2) { /** @type {?} */ let tmpx = (-cx1 * 2 + cx2) * 0.03; /** @type {?} */ let tmpy = (-cy1 * 2 + cy2) * 0.03; /** @type {?} */ let dddfx = ((cx1 - cx2) * 3 + 1) * 0.006; /** @type {?} */ let dddfy = ((cy1 - cy2) * 3 + 1) * 0.006; /** @type {?} */ let ddfx = tmpx * 2 + dddfx; /** @type {?} */ let ddfy = tmpy * 2 + dddfy; /** @type {?} */ let dfx = cx1 * 0.3 + tmpx + dddfx * 0.16666667; /** @type {?} */ let dfy = cy1 * 0.3 + tmpy + dddfy * 0.16666667; /** @type {?} */ let i = frameIndex * CurveTimeline.BEZIER_SIZE; /** @type {?} */ let curves = this.curves; curves[i++] = CurveTimeline.BEZIER; /** @type {?} */ let x = dfx; /** @type {?} */ let y = dfy; for (let n = i + CurveTimeline.BEZIER_SIZE - 1; i < n; i += 2) { curves[i] = x; curves[i + 1] = y; dfx += ddfx; dfy += ddfy; ddfx += dddfx; ddfy += dddfy; x += dfx; y += dfy; } } /** * @param {?} frameIndex * @param {?} percent * @return {?} */ getCurvePercent(frameIndex, percent) { percent = MathUtils.clamp(percent, 0, 1); /** @type {?} */ let curves = this.curves; /** @type {?} */ let i = frameIndex * CurveTimeline.BEZIER_SIZE; /** @type {?} */ let type = curves[i]; if (type == CurveTimeline.LINEAR) return percent; if (type == CurveTimeline.STEPPED) return 0; i++; /** @type {?} */ let x = 0; for (let start = i, n = i + CurveTimeline.BEZIER_SIZE - 1; i < n; i += 2) { x = curves[i]; if (x >= percent) { /** @type {?} */ let prevX; /** @type {?} */ let prevY; if (i == start) { prevX = 0; prevY = 0; } else { prevX = curves[i - 2]; prevY = curves[i - 1]; } return (prevY + ((curves[i + 1] - prevY) * (percent - prevX)) / (x - prevX)); } } /** @type {?} */ let y = curves[i - 1]; return y + ((1 - y) * (percent - x)) / (1 - x); // Last point is 1,1. } } CurveTimeline.LINEAR = 0; CurveTimeline.STEPPED = 1; CurveTimeline.BEZIER = 2; CurveTimeline.BEZIER_SIZE = 10 * 2 - 1; if (false) { /** @type {?} */ CurveTimeline.LINEAR; /** @type {?} */ CurveTimeline.STEPPED; /** @type {?} */ CurveTimeline.BEZIER; /** @type {?} */ CurveTimeline.BEZIER_SIZE; /** * @type {?} * @private */ CurveTimeline.prototype.curves; /** * @abstract * @return {?} */ CurveTimeline.prototype.getPropertyId = function () { }; /** * @abstract * @param {?} skeleton * @param {?} lastTime * @param {?} time * @param {?} events * @param {?} alpha * @param {?} blend * @param {?} direction * @return {?} */ CurveTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { }; } export class RotateTimeline extends CurveTimeline { // time, degrees, /.index. /** * @param {?} frameCount */ constructor(frameCount) { super(frameCount); this.frames = Utils.newFloatArray(frameCount << 1); } /** * @return {?} */ getPropertyId() { return (TimelineType.rotate << 24) + this.boneIndex; } /** * Sets the time and angle of the specified keyframe. * @param {?} frameIndex * @param {?} time * @param {?} degrees * @return {?} */ setFrame(frameIndex, time, degrees) { frameIndex <<= 1; this.frames[frameIndex] = time; this.frames[frameIndex + RotateTimeline.ROTATION] = degrees; } /** * @param {?} skeleton * @param {?} lastTime * @param {?} time * @param {?} events * @param {?} alpha * @param {?} blend * @param {?} direction * @return {?} */ apply(skeleton, lastTime, time, events, alpha, blend, direction) { /** @type {?} */ let frames = this.frames; /** @type {?} */ let bone = skeleton.bones[this.boneIndex]; if (!bone.active) return; if (time < frames[0]) { switch (blend) { case MixBlend.setup: bone.rotation = bone.data.rotation; return; case MixBlend.first: /** @type {?} */ let r = bone.data.rotation - bone.rotation; bone.rotation += (r - (16384 - ((16384.499999999996 - r / 360) | 0)) * 360) * alpha; } return; } if (time >= frames[frames.length - RotateTimeline.ENTRIES]) { // Time is after last frame. /** @type {?} */ let r = frames[frames.length + RotateTimeline.PREV_ROTATION]; switch (blend) { case MixBlend.setup: bone.rotation = bone.data.rotation + r * alpha; break; case MixBlend.first: case MixBlend.replace: r += bone.data.rotation - bone.rotation; r -= (16384 - ((16384.499999999996 - r / 360) | 0)) * 360; // Wrap within -180 and 180. case MixBlend.add: bone.rotation += r * alpha; } return; } // Interpolate between the previous frame and the current frame. /** @type {?} */ let frame = Animation.binarySearch(frames, time, RotateTimeline.ENTRIES); /** @type {?} */ let prevRotation = frames[frame + RotateTimeline.PREV_ROTATION]; /** @type {?} */ let frameTime = frames[frame]; /** @type {?} */ let percent = this.getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + RotateTimeline.PREV_TIME] - frameTime)); /** @type {?} */ let r = frames[frame + RotateTimeline.ROTATION] - prevRotation; r = prevRotation + (r - (16384 - ((16384.499999999996 - r / 360) | 0)) * 360) * percent; switch (blend) { case MixBlend.setup: bone.rotation = bone.data.rotation + (r - (16384 - ((16384.499999999996 - r / 360) | 0)) * 360) * alpha; break; case MixBlend.first: case MixBlend.replace: r += bone.data.rotation - bone.rotation; case MixBlend.add: bone.rotation += (r - (16384 - ((16384.499999999996 - r / 360) | 0)) * 360) * alpha; } } } RotateTimeline.ENTRIES = 2; RotateTimeline.PREV_TIME = -2; RotateTimeline.PREV_ROTATION = -1; RotateTimeline.ROTATION = 1; if (false) { /** @type {?} */ RotateTimeline.ENTRIES; /** @type {?} */ RotateTimeline.PREV_TIME; /** @type {?} */ RotateTimeline.PREV_ROTATION; /** @type {?} */ RotateTimeline.ROTATION; /** @type {?} */ RotateTimeline.prototype.boneIndex; /** @type {?} */ RotateTimeline.prototype.frames; } export class TranslateTimeline extends CurveTimeline { // time, x, y, /.index. /** * @param {?} frameCount */ constructor(frameCount) { super(frameCount); this.frames = Utils.newFloatArray(frameCount * TranslateTimeline.ENTRIES); } /** * @return {?} */ getPropertyId() { return (TimelineType.translate << 24) + this.boneIndex; } /** * Sets the time and value of the specified keyframe. * @param {?} frameIndex * @param {?} time * @param {?} x * @param {?} y * @return {?} */ setFrame(frameIndex, time, x, y) { frameIndex *= TranslateTimeline.ENTRIES; this.frames[frameIndex] = time; this.frames[frameIndex + TranslateTimeline.X] = x; this.frames[frameIndex + TranslateTimeline.Y] = y; } /** * @param {?} skeleton * @param {?} lastTime * @param {?} time * @param {?} events * @param {?} alpha * @param {?} blend * @param {?} direction * @return {?} */ apply(skeleton, lastTime, time, events, alpha, blend, direction) { /** @type {?} */ let frames = this.frames; /** @type {?} */ let bone = skeleton.bones[this.boneIndex]; if (!bone.active) return; if (time < frames[0]) { switch (blend) { case MixBlend.setup: bone.x = bone.data.x; bone.y = bone.data.y; return; case MixBlend.first: bone.x += (bone.data.x - bone.x) * alpha; bone.y += (bone.data.y - bone.y) * alpha; } return; } /** @type {?} */ let x = 0; /** @type {?} */ let y = 0; if (time >= frames[frames.length - TranslateTimeline.ENTRIES]) { // Time is after last frame. x = frames[frames.length + TranslateTimeline.PREV_X]; y = frames[frames.length + TranslateTimeline.PREV_Y]; } else { // Interpolate between the previous frame and the current frame. /** @type {?} */ let frame = Animation.binarySearch(frames, time, TranslateTimeline.ENTRIES); x = frames[frame + TranslateTimeline.PREV_X]; y = frames[frame + TranslateTimeline.PREV_Y]; /** @type {?} */ let frameTime = frames[frame]; /** @type {?} */ let percent = this.getCurvePercent(frame / TranslateTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + TranslateTimeline.PREV_TIME] - frameTime)); x += (frames[frame + TranslateTimeline.X] - x) * percent; y += (frames[frame + TranslateTimeline.Y] - y) * percent; } switch (blend) { case MixBlend.setup: bone.x = bone.data.x + x * alpha; bone.y = bone.data.y + y * alpha; break; case MixBlend.first: case MixBlend.replace: bone.x += (bone.data.x + x - bone.x) * alpha; bone.y += (bone.data.y + y - bone.y) * alpha; break; case MixBlend.add: bone.x += x * alpha; bone.y += y * alpha; } } } TranslateTimeline.ENTRIES = 3; TranslateTimeline.PREV_TIME = -3; TranslateTimeline.PREV_X = -2; TranslateTimeline.PREV_Y = -1; TranslateTimeline.X = 1; TranslateTimeline.Y = 2; if (false) { /** @type {?} */ TranslateTimeline.ENTRIES; /** @type {?} */ TranslateTimeline.PREV_TIME; /** @type {?} */ TranslateTimeline.PREV_X; /** @type {?} */ TranslateTimeline.PREV_Y; /** @type {?} */ TranslateTimeline.X; /** @type {?} */ TranslateTimeline.Y; /** @type {?} */ TranslateTimeline.prototype.boneIndex; /** @type {?} */ TranslateTimeline.prototype.frames; } export class ScaleTimeline extends TranslateTimeline { /** * @param {?} frameCount */ constructor(frameCount) { super(frameCount); } /** * @return {?} */ getPropertyId() { return (TimelineType.scale << 24) + this.boneIndex; } /** * @param {?} skeleton * @param {?} lastTime * @param {?} time * @param {?} events * @param {?} alpha * @param {?} blend * @param {?} direction * @return {?} */ apply(skeleton, lastTime, time, events, alpha, blend, direction) { /** @type {?} */ let frames = this.frames; /** @type {?} */ let bone = skeleton.bones[this.boneIndex]; if (!bone.active) return; if (time < frames[0]) { switch (blend) { case MixBlend.setup: bone.scaleX = bone.data.scaleX; bone.scaleY = bone.data.scaleY; return; case MixBlend.first: bone.scaleX += (bone.data.scaleX - bone.scaleX) * alpha; bone.scaleY += (bone.data.scaleY - bone.scaleY) * alpha; } return; } /** @type {?} */ let x = 0; /** @type {?} */ let y = 0; if (time >= frames[frames.length - ScaleTimeline.ENTRIES]) { // Time is after last frame. x = frames[frames.length + ScaleTimeline.PREV_X] * bone.data.scaleX; y = frames[frames.length + ScaleTimeline.PREV_Y] * bone.data.scaleY; } else { // Interpolate between the previous frame and the current frame. /** @type {?} */ let frame = Animation.binarySearch(frames, time, ScaleTimeline.ENTRIES); x = frames[frame + ScaleTimeline.PREV_X]; y = frames[frame + ScaleTimeline.PREV_Y]; /** @type {?} */ let frameTime = frames[frame]; /** @type {?} */ let percent = this.getCurvePercent(frame / ScaleTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + ScaleTimeline.PREV_TIME] - frameTime)); x = (x + (frames[frame + ScaleTimeline.X] - x) * percent) * bone.data.scaleX; y = (y + (frames[frame + ScaleTimeline.Y] - y) * percent) * bone.data.scaleY; } if (alpha == 1) { if (blend == MixBlend.add) { bone.scaleX += x - bone.data.scaleX; bone.scaleY += y - bone.data.scaleY; } else { bone.scaleX = x; bone.scaleY = y; } } else { /** @type {?} */ let bx = 0; /** @type {?} */ let by = 0; if (direction == MixDirection.mixOut) { switch (blend) { case MixBlend.setup: bx = bone.data.scaleX; by = bone.data.scaleY; bone.scaleX = bx + (Math.abs(x) * MathUtils.signum(bx) - bx) * alpha; bone.scaleY = by + (Math.abs(y) * MathUtils.signum(by) - by) * alpha; break; case MixBlend.first: case MixBlend.replace: bx = bone.scaleX; by = bone.scaleY; bone.scaleX = bx + (Math.abs(x) * MathUtils.signum(bx) - bx) * alpha; bone.scaleY = by + (Math.abs(y) * MathUtils.signum(by) - by) * alpha; break; case MixBlend.add: bx = bone.scaleX; by = bone.scaleY; bone.scaleX = bx + (Math.abs(x) * MathUtils.signum(bx) - bone.data.scaleX) * alpha; bone.scaleY = by + (Math.abs(y) * MathUtils.signum(by) - bone.data.scaleY) * alpha; } } else { switch (blend) { case MixBlend.setup: bx = Math.abs(bone.data.scaleX) * MathUtils.signum(x); by = Math.abs(bone.data.scaleY) * MathUtils.signum(y); bone.scaleX = bx + (x - bx) * alpha; bone.scaleY = by + (y - by) * alpha; break; case MixBlend.first: case MixBlend.replace: bx = Math.abs(bone.scaleX) * MathUtils.signum(x); by = Math.abs(bone.scaleY) * MathUtils.signum(y); bone.scaleX = bx + (x - bx) * alpha; bone.scaleY = by + (y - by) * alpha; break; case MixBlend.add: bx = MathUtils.signum(x); by = MathUtils.signum(y); bone.scaleX = Math.abs(bone.scaleX) * bx + (x - Math.abs(bone.data.scaleX) * bx) * alpha; bone.scaleY = Math.abs(bone.scaleY) * by + (y - Math.abs(bone.data.scaleY) * by) * alpha; } } } } } export class ShearTimeline extends TranslateTimeline { /** * @param {?} frameCount */ constructor(frameCount) { super(frameCount); } /** * @return {?} */ getPropertyId() { return (TimelineType.shear << 24) + this.boneIndex; } /** * @param {?} skeleton * @param {?} lastTime * @param {?} time * @param {?} events * @param {?} alpha * @param {?} blend * @param {?} direction * @return {?} */ apply(skeleton, lastTime, time, events, alpha, blend, direction) { /** @type {?} */ let frames = this.frames; /** @type {?} */ let bone = skeleton.bones[this.boneIndex]; if (!bone.active) return; if (time < frames[0]) { switch (blend) { case MixBlend.setup: bone.shearX = bone.data.shearX; bone.shearY = bone.data.shearY; return; case MixBlend.first: bone.shearX += (bone.data.shearX - bone.shearX) * alpha; bone.shearY += (bone.data.shearY - bone.shearY) * alpha; } return; } /** @type {?} */ let x = 0; /** @type {?} */ let y = 0; if (time >= frames[frames.length - ShearTimeline.ENTRIES]) { // Time is after last frame. x = frames[frames.length + ShearTimeline.PREV_X]; y = frames[frames.length + ShearTimeline.PREV_Y]; } else { // Interpolate between the previous frame and the current frame. /** @type {?} */ let frame = Animation.binarySearch(frames, time, ShearTimeline.ENTRIES); x = frames[frame + ShearTimeline.PREV_X]; y = frames[frame + ShearTimeline.PREV_Y]; /** @type {?} */ let frameTime = frames[frame]; /** @type {?} */ let percent = this.getCurvePercent(frame / ShearTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + ShearTimeline.PREV_TIME] - frameTime)); x = x + (frames[frame + ShearTimeline.X] - x) * percent; y = y + (frames[frame + ShearTimeline.Y] - y) * percent; } switch (blend) { case MixBlend.setup: bone.shearX = bone.data.shearX + x * alpha; bone.shearY = bone.data.shearY + y * alpha; break; case MixBlend.first: case MixBlend.replace: bone.shearX += (bone.data.shearX + x - bone.shearX) * alpha; bone.shearY += (bone.data.shearY + y - bone.shearY) * alpha; break; case MixBlend.add: bone.shearX += x * alpha; bone.shearY += y * alpha; } } } export class ColorTimeline extends CurveTimeline { // time, r, g, b, a, /.index. /** * @param {?} frameCount */ constructor(frameCount) { super(frameCount); this.frames = Utils.newFloatArray(frameCount * ColorTimeline.ENTRIES); } /** * @return {?} */ getPropertyId() { return (TimelineType.color << 24) + this.slotIndex; } /** * Sets the time and value of the specified keyframe. * @param {?} frameIndex * @param {?} time * @param {?} r * @param {?} g * @param {?} b * @param {?} a * @return {?} */ setFrame(frameIndex, time, r, g, b, a) { frameIndex *= ColorTimeline.ENTRIES; this.frames[frameIndex] = time; this.frames[frameIndex + ColorTimeline.R] = r; this.frames[frameIndex + ColorTimeline.G] = g; this.frames[frameIndex + ColorTimeline.B] = b; this.frames[frameIndex + ColorTimeline.A] = a; } /** * @param {?} skeleton * @param {?} lastTime * @param {?} time * @param {?} events * @param {?} alpha * @param {?} blend * @param {?} direction * @return {?} */ apply(skeleton, lastTime, time, events, alpha, blend, direction) { /** @type {?} */ let slot = skeleton.slots[this.slotIndex]; if (!slot.bone.active) return; /** @type {?} */ let frames = this.frames; if (time < frames[0]) { switch (blend) { case MixBlend.setup: slot.color.setFromColor(slot.data.color); return; case MixBlend.first: /** @type {?} */ let color = slot.color; /** @type {?} */ let setup = slot.data.color; color.add((setup.r - color.r) * alpha, (setup.g - color.g) * alpha, (setup.b - color.b) * alpha, (setup.a - color.a) * alpha); } return; } /** @type {?} */ let r = 0; /** @type {?} */ let g = 0; /** @type {?} */ let b = 0; /** @type {?} */ let a = 0; if (time >= frames[frames.length - ColorTimeline.ENTRIES]) { // Time is after last frame. /** @type {?} */ let i = frames.length; r = frames[i + ColorTimeline.PREV_R]; g = frames[i + ColorTimeline.PREV_G]; b = frames[i + ColorTimeline.PREV_B]; a = frames[i + ColorTimeline.PREV_A]; } else { // Interpolate between the previous frame and the current frame. /** @type {?} */ let frame = Animation.binarySearch(frames, time, ColorTimeline.ENTRIES); r = frames[frame + ColorTimeline.PREV_R]; g = frames[frame + ColorTimeline.PREV_G]; b = frames[frame + ColorTimeline.PREV_B]; a = frames[frame + ColorTimeline.PREV_A]; /** @type {?} */ let frameTime = frames[frame]; /** @type {?} */ let percent = this.getCurvePercent(frame / ColorTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + ColorTimeline.PREV_TIME] - frameTime)); r += (frames[frame + ColorTimeline.R] - r) * percent; g += (frames[frame + ColorTimeline.G] - g) * percent; b += (frames[frame + ColorTimeline.B] - b) * percent; a += (frames[frame + ColorTimeline.A] - a) * percent; } if (alpha == 1) slot.color.set(r, g, b, a); else { /** @type {?} */ let color = slot.color; if (blend == MixBlend.setup) color.setFromColor(slot.data.color); color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha); } } } ColorTimeline.ENTRIES = 5; ColorTimeline.PREV_TIME = -5; ColorTimeline.PREV_R = -4; ColorTimeline.PREV_G = -3; ColorTimeline.PREV_B = -2; ColorTimeline.PREV_A = -1; ColorTimeline.R = 1; ColorTimeline.G = 2; ColorTimeline.B = 3; ColorTimeline.A = 4; if (false) { /** @type {?} */ ColorTimeline.ENTRIES; /** @type {?} */ ColorTimeline.PREV_TIME; /** @type {?} */ ColorTimeline.PREV_R; /** @type {?} */ ColorTimeline.PREV_G; /** @type {?} */ ColorTimeline.PREV_B; /** @type {?} */ ColorTimeline.PREV_A; /** @type {?} */ ColorTimeline.R; /** @type {?} */ ColorTimeline.G; /** @type {?} */ ColorTimeline.B; /** @type {?} */ ColorTimeline.A; /** @type {?} */ ColorTimeline.prototype.slotIndex; /** @type {?} */ ColorTimeline.prototype.frames; } export class TwoColorTimeline extends CurveTimeline { // time, r, g, b, a, r2, g2, b2, /.index. /** * @param {?} frameCount */ constructor(frameCount) { super(frameCount); this.frames = Utils.newFloatArray(frameCount * TwoColorTimeline.ENTRIES); } /** * @return {?} */ getPropertyId() { return (TimelineType.twoColor << 24) + this.slotIndex; } /** * Sets the time and value of the specified keyframe. * @param {?} frameIndex * @param {?} time * @param {?} r * @param {?} g * @param {?} b * @param {?} a * @param {?} r2 * @param {?} g2 * @param {?} b2 * @return {?} */ setFrame(frameIndex, time, r, g, b, a, r2, g2, b2) { frameIndex *= TwoColorTimeline.ENTRIES; this.frames[frameIndex] = time; this.frames[frameIndex + TwoColorTimeline.R] = r; this.frames[frameIndex + TwoColorTimeline.G] = g; this.frames[frameIndex + TwoColorTimeline.B] = b; this.frames[frameIndex + TwoColorTimeline.A] = a; this.frames[frameIndex + TwoColorTimeline.R2] = r2; this.frames[frameIndex + TwoColorTimeline.G2] = g2; this.frames[frameIndex + TwoColorTimeline.B2] = b2; } /** * @param {?} skeleton * @param {?} lastTime * @param {?} time * @param {?} events * @param {?} alpha * @param {?} blend * @param {?} direction * @return {?} */ apply(skeleton, lastTime, time, events, alpha, blend, direction) { /** @type {?} */ let slot = skeleton.slots[this.slotIndex]; if (!slot.bone.active) return; /** @type {?} */ let frames = this.frames; if (time < frames[0]) { switch (blend) { case MixBlend.setup: slot.color.setFromColor(slot.data.color); slot.darkColor.setFromColor(slot.data.darkColor); return; case MixBlend.first: /** @type {?} */ let light = slot.color; /** @type {?} */ let dark = slot.darkColor; /** @type {?} */ let setupLight = slot.data.color; /** @type {?} */ let setupDark = slot.data.darkColor; light.add((setupLight.r - light.r) * alpha, (setupLight.g - light.g) * alpha, (setupLight.b - light.b) * alpha, (setupLight.a - light.a) * alpha); dark.add((setupDark.r - dark.r) * alpha, (setupDark.g - dark.g) * alpha, (setupDark.b - dark.b) * alpha, 0); } return; } /** @type {?} */ let r = 0; /** @type {?} */ let g = 0; /** @type {?} */ let b = 0; /** @type {?} */ let a = 0; /** @type {?} */ let r2 = 0; /** @type {?} */ let g2 = 0; /** @type {?} */ let b2 = 0; if (time >= frames[frames.length - TwoColorTimeline.ENTRIES]) { // Time is after last frame. /** @type {?} */ let i = frames.length; r = frames[i + TwoColorTimeline.PREV_R]; g = frames[i + TwoColorTimeline.PREV_G]; b = frames[i + TwoColorTimeline.PREV_B]; a = frames[i + TwoColorTimeline.PREV_A]; r2 = frames[i + TwoColorTimeline.PREV_R2]; g2 = frames[i + TwoColorTimeline.PREV_G2]; b2 = frames[i + TwoColorTimeline.PREV_B2]; } else { // Interpolate between the previous frame and the current frame. /** @type {?} */ let frame = Animation.binarySearch(frames, time, TwoColorTimeline.ENTRIES); r = frames[frame + TwoColorTimeline.PREV_R]; g = frames[frame + TwoColorTimeline.PREV_G]; b = frames[frame + TwoColorTimeline.PREV_B]; a = frames[frame + TwoColorTimeline.PREV_A]; r2 = frames[frame + TwoColorTimeline.PREV_R2]; g2 = frames[frame + TwoColorTimeline.PREV_G2]; b2 = frames[frame + TwoColorTimeline.PREV_B2]; /** @type {?} */ let frameTime = frames[frame]; /** @type {?} */ let percent = this.getCurvePercent(frame / TwoColorTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + TwoColorTimeline.PREV_TIME] - frameTime)); r += (frames[frame + TwoColorTimeline.R] - r) * percent; g += (frames[frame + TwoColorTimeline.G] - g) * percent; b += (frames[frame + TwoColorTimeline.B] - b) * percent; a += (frames[frame + TwoColorTimeline.A] - a) * percent; r2 += (frames[frame + TwoColorTimeline.R2] - r2) * percent; g2 += (frames[frame + TwoColorTimeline.G2] - g2) * percent; b2 += (frames[frame + TwoColorTimeline.B2] - b2) * percent; } if (alpha == 1) { slot.color.set(r, g, b, a); slot.darkColor.set(r2, g2, b2, 1); } else { /** @type {?} */ let light = slot.color; /** @type {?} */ let dark = slot.darkColor; if (blend == MixBlend.setup) { light.setFromColor(slot.data.color); dark.setFromColor(slot.data.darkColor); } light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha); dark.add((r2 - dark.r) * alpha, (g2 - dark.g) * alpha, (b2 - dark.b) * alpha, 0); } } } TwoColorTimeline.ENTRIES = 8; TwoColorTimeline.PREV_TIME = -8; TwoColorTimeline.PREV_R = -7; TwoColorTimeline.PREV_G = -6; TwoColorTimeline.PREV_B = -5; TwoColorTimeline.PREV_A = -4; TwoColorTimeline.PREV_R2 = -3; TwoColorTimeline.PREV_G2 = -2; TwoColorTimeline.PREV_B2 = -1; TwoColorTimeline.R = 1; TwoColorTimeline.G = 2; TwoColorTimeline.B = 3; TwoColorTimeline.A = 4; TwoColorTimeline.R2 = 5; TwoColorTimeline.G2 = 6; TwoColorTimeline.B2 = 7; if (false) { /** @type {?} */ TwoColorTimeline.ENTRIES; /** @type {?} */ TwoColorTimeline.PREV_TIME; /** @type {?} */ TwoColorTimeline.PREV_R; /** @type {?} */ TwoColorTimeline.PREV_G; /** @type {?} */ TwoColorTimeline.PREV_B; /** @type {?} */ TwoColorTimeline.PREV_A; /** @type {?} */ TwoColorTimeline.PREV_R2; /** @type {?} */ TwoColorTimeline.PREV_G2; /** @type {?} */ TwoColorTimeline.PREV_B2; /** @type {?} */ TwoColorTimeline.R; /** @type {?} */ TwoColorTimeline.G; /** @type {?} */ TwoColorTimeline.B; /** @type {?} */ TwoColorTimeline.A; /** @type {?} */ TwoColorTimeline.R2; /** @type {?} */ TwoColorTimeline.G2; /** @type {?} */ TwoColorTimeline.B2; /** @type {?} */ TwoColorTimeline.prototype.slotIndex; /** @type {?} */ TwoColorTimeline.prototype.frames; } export class AttachmentTimeline { /** * @param {?} frameCount */ constructor(frameCount) { this.frames = Utils.newFloatArray(frameCount); this.attachmentNames = new Array(frameCount); } /** * @return {?} */ getPropertyId() { return (TimelineType.attachment << 24) + this.slotIndex; } /** * @return {?} */ getFrameCount() { return this.frames.length; } /** * Sets the time and value of the specified keyframe. * @param {?} frameIndex * @param {?} time * @param {?} attachmentName * @return {?} */ setFrame(frameIndex, time, attachmentName) { this.frames[frameIndex] = time; this.attachmentNames[frameIndex] = attachmentName; } /** * @param {?} skeleton * @param {?} lastTime * @param {?} time * @param {?} events * @param {?} alpha * @param {?} blend * @param {?} direction * @return {?} */ apply(skeleton, lastTime, time, events, alpha, blend, direction) { /** @type {?} */ let slot = skeleton.slots[this.slotIndex]; if (!slot.bone.active) return; if (direction == MixDirection.mixOut && blend == MixBlend.setup) { /** @type {?} */ let attachmentName = slot.data.attachmentName; slot.setAttachment(attachmentName == null ? null : skeleton.getAttachment(this.slotIndex, attachmentName)); return; } /** @type {?} */ let frames = this.frames; if (time < frames[0]) { if (blend == MixBlend.setup || blend == MixBlend.first) { /** @type {?} */ let attachmentName = slot.data.attachmentName; slot.setAttachment(attachmentName == null ? null : skeleton.getAttachment(this.slotIndex, attachmentName)); } return; } /** @type {?} */ let frameIndex = 0; if (time >= frames[frames.length - 1]) // Time is after last frame. frameIndex = frames.length - 1; else frameIndex = Animation.binarySearch(frames, time, 1) - 1; /** @type {?} */ let attachmentName = this.attachmentNames[frameIndex]; skeleton.slots[this.slotIndex].setAttachment(attachmentName == null ? null : skeleton.getAttachment(this.slotIndex, attachmentName)); } } if (false) { /** @type {?} */ AttachmentTimeline.prototype.slotIndex; /** @type {?} */ AttachmentTimeline.prototype.frames; /** @type {?} */ AttachmentTimeline.prototype.attachmentNames; } /** @type {?} */ let zeros = null; export class DeformTimeline extends CurveTimeline { /** * @param {?} frameCount */ constructor(frameCount) { super(frameCount); this.frames = Utils.newFloatArray(frameCount); this.frameVertices = new Array(frameCount); if (zeros == null) zeros = Utils.newFloatArray(64); } /** * @return {?} */ getPropertyId() { return (TimelineType.deform << 27) + +this.attachment.id + this.slotIndex; } /** * Sets the time of the specified keyframe. * @param {?} frameIndex * @param {?} time * @param {?} vertices * @return {?} */ setFrame(frameIndex, time, vertices) { this.frames[frameIndex] = time; this.frameVertices[frameIndex] = vertices; } /** * @param {?} skeleton * @param {?} lastTime * @param {?} time * @param {?} firedEvents * @param {?} alpha * @param {?} blend * @param {?} direction * @return {?} */ apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { /** @type {?} */ let slot = skeleton.slots[this.slotIndex]; if (!slot.bone.active) return; /** @type {?} */ let slotAttachment = slot.getAttachment(); if (!(slotAttachment instanceof VertexAttachment) || !(((/** @type {?} */ (slotAttachment))).deformAttachment == this.attachment)) return; /** @type {?} */ let deformArray = slot.deform; if (deformArray.length == 0) blend = MixBlend.setup; /** @type {?} */ let frameVertices = this.frameVertices; /** @type {?} */ let vertexCount = frameVertices[0].length; /** @type {?} */ let frames = this.frames; if (time < frames[0]) { /** @type {?} */ let vertexAttachment = (/** @type {?} */ (slotAttachment)); switch (blend) { case MixBlend.setup: deformArray.length = 0; return; case MixBlend.first: if (alpha == 1) { deformArray.length = 0; break; } /** @type {?} */ let deform = Utils.setArraySize(deformArray, vertexCount); if (vertexAttachment.bones == null) { // Unweighted vertex positions. /** @type {?} */ let setupVertices = vertexAttachment.vertices; for (var i = 0; i < vertexCount; i++) deform[i] += (setupVertices[i] - deform[i]) * alpha; } else { // Weighted deform offsets. alpha = 1 - alpha; for (var i = 0; i < vertexCount; i++) deform[i] *= alpha; } } return; } /** @type {?} */ let deform = Utils.setArraySize(deformArray, vertexCount); if (time >= frames[frames.length - 1]) { // Time is after last frame. /** @type {?} */ let lastVertices = frameVertices[frames.length - 1]; if (alpha == 1) { if (blend == MixBlend.add) { /** @type {?} */ let vertexAttachment = (/** @type {?} */ (slotAttachment)); if (vertexAttachment.bones == null) { // Unweighted vertex positions, with alpha. /** @type {?} */ let setupVertices = vertexAttachment.vertices; for (let i = 0; i < vertexCount; i++) { deform[i] += lastVertices[i] - setupVertices[i]; } } else { // Weighted deform offsets, with alpha. for (let i = 0; i < vertexCount; i++) deform[i] += lastVertices[i]; } } else { Utils.arrayCopy(lastVertices, 0, deform, 0, vertexCount); } } else { switch (blend) { case MixBlend.setup: { /** @type {?} */ let vertexAttachment = (/** @type {?} */ (slotAttachment)); if (vertexAttachment.bones == null) { // Unweighted vertex positions, with alpha. /** @type {?} */ let setupVertices = vertexAttachment.vertices; for (let i = 0; i < vertexCount; i++) { /** @type {?} */ let setup = setupVertices[i]; deform[i] = setup + (lastVertices[i] - setup) * alpha; } } else { // Weighted deform offsets, with alpha. for (let i = 0; i < vertexCount; i++) deform[i] = lastVertices[i] * alpha; } break; } case MixBlend.first: case MixBlend.replace: for (let i = 0; i < vertexCount; i++) deform[i] += (lastVertices[i] - deform[i]) * alpha; case MixBlend.add: /** @type {?} */ let vertexAttachment = (/** @type {?} */ (slotAttachment)); if (vertexAttachment.bones == null) { // Unweighted vertex positions, with alpha. /** @type {?} */ let setupVertices = vertexAttachment.vertices; for (let i = 0; i < vertexCount; i++) { deform[i] += (lastVertices[i] - setupVertices[i]) * alpha; } } else { // Weighted deform offsets, with alpha. for (let i = 0; i < vertexCount; i++) deform[i] += lastVertices[i] * alpha; } } } return; } // Interpolate between t