From 91815a355b1823955bbe059519a566a4852a5114 Mon Sep 17 00:00:00 2001 From: tianmo Date: Tue, 8 Sep 2026 18:42:08 +0800 Subject: [PATCH] =?UTF-8?q?eagle=E9=A2=84=E8=A7=88spine=E6=8F=92=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 11 + README.md | 81 + SpineViewer.code-workspace | 8 + debug3.js | 13 + js/icns-util.js | 140 + js/image-size.js | 18 + js/spine-render.js | 195 + js/spine-utils.js | 542 ++ lib/3.6/spine-canvas.js | 6860 +++++++++++++++++ lib/3.7/spine-canvas.js | 7117 ++++++++++++++++++ lib/3.8/spine-canvas.js | 8472 +++++++++++++++++++++ lib/4.0/spine-canvas.js | 9066 +++++++++++++++++++++++ lib/4.1/spine-canvas.js | 11055 ++++++++++++++++++++++++++++ lib/4.2/spine-canvas.js | 11714 ++++++++++++++++++++++++++++++ lib/4.3/spine-canvas.js | 13723 +++++++++++++++++++++++++++++++++++ logo.png | Bin 0 -> 15726 bytes manifest.json | 28 + package-lock.json | 212 + package.json | 11 + realdur.js | 26 + test-atlas.js | 17 + test-conc.js | 15 + test.icns | Bin 0 -> 413833 bytes thumbnail/icns.js | 28 + thumbnail/spine.js | 227 + viewer/icns.html | 48 + viewer/spine.html | 797 ++ 27 files changed, 70424 insertions(+) create mode 100644 README.md create mode 100644 SpineViewer.code-workspace create mode 100644 debug3.js create mode 100644 js/icns-util.js create mode 100644 js/image-size.js create mode 100644 js/spine-render.js create mode 100644 js/spine-utils.js create mode 100644 lib/3.6/spine-canvas.js create mode 100644 lib/3.7/spine-canvas.js create mode 100644 lib/3.8/spine-canvas.js create mode 100644 lib/4.0/spine-canvas.js create mode 100644 lib/4.1/spine-canvas.js create mode 100644 lib/4.2/spine-canvas.js create mode 100644 lib/4.3/spine-canvas.js create mode 100644 logo.png create mode 100644 manifest.json create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 realdur.js create mode 100644 test-atlas.js create mode 100644 test-conc.js create mode 100644 test.icns create mode 100644 thumbnail/icns.js create mode 100644 thumbnail/spine.js create mode 100644 viewer/icns.html create mode 100644 viewer/spine.html diff --git a/.gitignore b/.gitignore index e69de29..97b1be8 100644 --- a/.gitignore +++ b/.gitignore @@ -0,0 +1,11 @@ +# Dependencies (需要重新安装;离线打包时需手动包含 node_modules) +node_modules/ + +# OS / editor +.DS_Store +Thumbs.db +*.log + +# Temp test artifacts +/tmp/ +*.png.d.ts diff --git a/README.md b/README.md new file mode 100644 index 0000000..388764c --- /dev/null +++ b/README.md @@ -0,0 +1,81 @@ +# SpineViewer(Eagle 插件) + +一个 **完全离线** 的 Eagle 格式扩展插件,用于在 Eagle 中直接预览由 Spine 导出的骨骼动画。 + +插件只接管「骨骼数据」和「纹理图集数据」类型的预览: +- 骨骼数据:`skel`、`skel.bytes`、`json` +- 纹理图集数据:`atlas`、`atlas.txt` + +普通图片(`png/jpg/jpeg/webp`)仍由 Eagle 原生预览,插件不接管。 + +支持的 Spine 版本:**3.6 / 3.7 / 3.8 / 4.0 / 4.1 / 4.2 / 4.3**。 + +> 关键特性:无需网络、不走 CDN。所有 Spine 官方运行时代码都已拷贝到插件本地 `lib/` 目录,不含 git 子模块。 + +--- + +## 目录结构 + +``` +SpineViewer/ +├─ manifest.json # 插件清单(预览扩展注册) +├─ logo.png # 插件图标 +├─ thumbnail/ +│ └─ spine.js # 缩略图生成(渲染骨骼首帧为 PNG) +├─ viewer/ +│ └─ spine.html # 预览页面(动画播放 / 动画/皮肤切换 / 速度 / 缩放适配) +├─ js/ +│ ├─ spine-utils.js # 资源匹配、版本检测工具 +│ └─ spine-render.js # 纯 Node 渲染模块(缩略图用) +├─ lib/ # 各版本 Spine 官方运行时(已拷贝到本地) +│ ├─ 3.6/ spine-canvas.js +│ ├─ 3.7/ spine-canvas.js +│ ├─ 3.8/ spine-canvas.js +│ ├─ 4.0/ spine-canvas.js +│ ├─ 4.1/ spine-canvas.js +│ ├─ 4.2/ spine-canvas.js +│ └─ 4.3/ spine-canvas.js +└─ node_modules/ # 可选:@napi-rs/canvas(用于高质量缩略图渲染) +``` + +--- + +## 工作原理 + +1. **跨文件夹资源配对**:Eagle 会把导入的每个文件拆分成独立的元数据文件夹(`images/.info/`,内含资产文件与 `metadata.json`),因此配套文件可能不在同一目录。插件会: + - 定位到所选文件的 item 文件夹; + - 扫描其**同级的所有 item 文件夹**,根据文件名(忽略 `-pro`、`-ess`、`-pma` 等常见后缀)自动关联出配套的 **骨骼文件** + **atlas** + **贴图**; + - 从 atlas 中解析它引用的贴图页面,再到库中定位实际贴图文件。 +2. **版本检测**:读取骨骼数据里的版本号(`.json` 读 `skeleton.spine`,`.skel` 读二进制头部),自动选择匹配的本地运行时。 +3. **预览**:查看器通过 Node `fs` 直接读取分离在各 item 文件夹中的骨骼/atlas/贴图文件(无需网络、无 CORS),用 `spine-canvas` 渲染器在 `` 上实时播放动画,并支持: + - 动画列表切换 + - 皮肤切换 + - 播放 / 暂停(空格) + - 循环开关 + - 播放速度调节 + - 自动适配并居中 +4. **缩略图**:使用 `@napi-rs/canvas` 在 Node 中跨 item 文件夹读取资源并渲染骨骼首帧生成 PNG。若该依赖不可用,会自动回退为一条纯 JS 生成的占位 PNG。 + +--- + +## 使用说明 + +- 将 Spine 导出的一整套文件(`.skel`/`.json` + `.atlas` + `.png` 等)放在**同一个文件夹**并导入 Eagle。 +- 点击其中任何一个文件即可预览动画;点击配套的贴图或 atlas 也会自动找到整套资源。 + +--- + +## 关于新版/旧版二进制 + +- **3.8 / 4.x** 的 `.skel` / `.skel.bytes` 二进制文件完整支持。 +- **3.6 / 3.7** 的官方 JS 运行时 **不包含二进制解析器**,且其二进制格式与 3.8 不兼容。因此这两版的 `.skel` / `.skel.bytes` 无法由官方 JS 运行时加载。插件会检测到这种情况并给出提示(缩略图显示占位图),建议改用 **JSON** 导出即可正常预览。 + +--- + +## 可选依赖说明 + +`@napi-rs/canvas` 仅用于缩略图的高质量渲染。它并非必需: +- 若保留 `node_modules/`(当前平台原生二进制),缩略图会渲染骨骼形象。 +- 若删除 `node_modules/`,插件仍可正常预览动画,缩略图会显示一条纯 JS 占位图。 + +如需在多个平台分发,请安装对应平台的 `@napi-rs/canvas` 原生二进制。 diff --git a/SpineViewer.code-workspace b/SpineViewer.code-workspace new file mode 100644 index 0000000..876a149 --- /dev/null +++ b/SpineViewer.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": {} +} \ No newline at end of file diff --git a/debug3.js b/debug3.js new file mode 100644 index 0000000..1346ef0 --- /dev/null +++ b/debug3.js @@ -0,0 +1,13 @@ +const fs=require('fs'); +const path=require('path'); +const utils=require('./js/spine-utils.js'); +const base='/Users/tianmokeji/Desktop/特效/特效.library/images'; +const src=base+'/MTS9JWMH7TLP1.info/spineboy.atlas'; +const itemDir=path.dirname(src); +console.log('itemDir:', itemDir); +console.log('metadata 存在:', fs.existsSync(path.join(itemDir,'metadata.json'))); +console.log('isEagleItemDir:', utils.isEagleItemDir(itemDir)); +console.log('目录内容:', fs.readdirSync(itemDir)); +const roots=utils.getSearchRoots(src); +console.log('getSearchRoots 返回:', roots); +console.log('root 数:', roots.length); diff --git a/js/icns-util.js b/js/icns-util.js new file mode 100644 index 0000000..6039b95 --- /dev/null +++ b/js/icns-util.js @@ -0,0 +1,140 @@ +const fs = require('fs'); + +var OSTYPE = { + ICON: '32×32', + 'ICN#': '32×32', + 'icm#': '16×12', + icm4: '16×12', + icm8: '16×12 ', + 'ics#': '16×16', + ics4: '16×16', + ics8: '16×16', + is32: '16×16', + s8mk: '16×16', + icl4: '32×32', + icl8: '32×32', + il32: '32×32', + l8mk: '32×32', + 'ich#': '48×48', + ich4: '48×48', + ich8: '48×48', + ih32: '48×48', + h8mk: '48×48', + it32: '128×128', + t8mk: '128×128', + icp4: '16x16', + icp5: '32x32', + icp6: '64x64', + ic07: '128x128', + ic08: '256×256', + ic09: '512×512', + ic10: '1024×1024', + ic11: '16x16@2x', + ic12: '32x32@2x', + ic13: '128x128@2x', + ic14: '256x256@2x ', +}; + +var Iconutil = (function () { + function Iconutil(buffer) { + var header = this.fetchHeader(buffer); + var pointer = header.data.length; + var images = []; + while (pointer < header.bytes) { + var _a = this.fetchImages(buffer.slice(pointer)), image = _a.image, data = _a.data, osType_1 = _a.osType; + Buffer.isBuffer(image) && + images.push({ + size: OSTYPE[osType_1], + image: image, + }); + pointer += data.length; + } + this.images = images; + } + Iconutil.prototype.fetchHeader = function (buffer) { + var id = buffer.toString('ascii', 0, 4); + var bytes = buffer.readUInt32BE(4); + var data = Buffer.alloc(8); + data.write(id, 0, 4, 'ascii'); + data.writeUInt32BE(bytes, 4); + return { + bytes: bytes, + data: data, + }; + }; + Iconutil.prototype.fetchImages = function (buffer) { + var osType = buffer.toString('ascii', 0, 4); + var bytes = buffer.readUInt32BE(4); + var image = buffer.slice(8, bytes); + var _buffer = Buffer.alloc(8); + _buffer.write(osType, 0, 4, 'ascii'); + _buffer.writeUInt32BE(bytes, 4); + var data = Buffer.concat([_buffer, image]); + return { + data: data, + image: image, + osType: osType, + }; + }; + return Iconutil; +}()); + +async function icns2png (src, dist) { + return new Promise(async (resolve, reject) => { + try { + let buffer = await fs.promises.readFile(src); + let images = new Iconutil(buffer).images; + let max = 0; + let maxImage; + + images.forEach(function (_a) { + if (_a && _a.image && _a.image.length > max) { + max = _a.image.length; + maxImage = _a.image; + } + }); + + if (maxImage) { + await fs.promises.writeFile(dist, maxImage); + return resolve(); + } + + return reject(new Error(`Can not parse the icns file.`)); + } + catch (err) { + return reject(err); + } + }); +} + +async function icns2buffer (src) { + return new Promise(async (resolve, reject) => { + try { + let buffer = await fs.promises.readFile(src); + let images = new Iconutil(buffer).images; + let max = 0; + let maxImage; + + images.forEach(function (_a) { + if (_a && _a.image && _a.image.length > max) { + max = _a.image.length; + maxImage = _a.image; + } + }); + + if (maxImage) { + return resolve(maxImage); + } + + return reject(new Error(`Can not parse the icns file.`)); + } + catch (err) { + return reject(err); + } + }); +} + +module.exports = { + icns2png: icns2png, + icns2buffer: icns2buffer +}; diff --git a/js/image-size.js b/js/image-size.js new file mode 100644 index 0000000..fe25250 --- /dev/null +++ b/js/image-size.js @@ -0,0 +1,18 @@ +module.exports = async (filePath) => { + return new Promise((resolve, reject) => { + var img = new Image(); + img.onload = function () { + resolve({ + width: img.width, + height: img.height, + }) + }; + img.onerror = function (event) { + resolve({ + width: 0, + height: 0, + }) + }; + img.src = require("url").pathToFileURL(filePath).href; + }); +} \ No newline at end of file diff --git a/js/spine-render.js b/js/spine-render.js new file mode 100644 index 0000000..06d5d26 --- /dev/null +++ b/js/spine-render.js @@ -0,0 +1,195 @@ +/** + * SpineViewer - 缩略图渲染模块(仅 Node 环境使用) + * 在纯 Node 中加载本地 Spine 运行时(通过 vm 注入到 global.spine), + * 使用 @napi-rs/canvas 光栅化骨骼的 setup pose / 首帧动画,输出 PNG buffer。 + */ +const fs = require('fs'); +const vm = require('vm'); +const path = require('path'); +const utils = require('./spine-utils.js'); + +let canvasLib = null; +try { + canvasLib = require('@napi-rs/canvas'); +} catch (e) { + canvasLib = null; +} + +/** + * 在隔离的 vm 上下文中加载本地 Spine 运行时,返回 spine 命名空间对象。 + * 使用独立上下文可避免不同版本运行时的全局变量/类相互污染(例如 4.x 与 3.x + * 的 BinaryInput、DataView 等),因此不会跨版本混用。 + */ +function loadRuntime(dir) { + const code = fs.readFileSync(path.join(__dirname, '..', 'lib', dir, 'spine-canvas.js'), 'utf8'); + const sandbox = { + console, + setTimeout, + clearTimeout, + setInterval, + clearInterval, + performance: { now: () => Date.now() }, + }; + // 部分运行时通过 window/self/globalThis 访问全局 + sandbox.window = sandbox; + sandbox.self = sandbox; + sandbox.globalThis = sandbox; + vm.createContext(sandbox); + vm.runInContext(code, sandbox, { filename: 'lib/' + dir + '/spine-canvas.js' }); + return sandbox.spine; +} + +/** 构造 TextureAtlas 并挂载贴图(跨版本兼容)。 + * texturePaths: { atlas 中引用的贴图名 -> 绝对路径 },用于跨 Eagle item 文件夹解析贴图。 + */ +function buildTextureAtlas(spine, atlasText, dir, texturePaths) { + if (!canvasLib) throw new Error('@napi-rs/canvas 不可用'); + return new Promise((resolve, reject) => { + (async () => { + // 解析所有页面贴图名,并预先异步加载 + let pageNames = []; + try { pageNames = utils.parseAtlasPages(atlasText); } catch (e) { pageNames = []; } + + const textureMap = {}; + await Promise.all(pageNames.map(async (name) => { + // 优先使用跨文件夹解析出的绝对路径,否则回退到 atlas 同目录 + const p = (texturePaths && texturePaths[name]) ? texturePaths[name] : path.join(dir, name); + if (!fs.existsSync(p)) return; + try { + const img = await canvasLib.loadImage(p); + textureMap[name] = img; + } catch (e) { /* ignore */ } + })); + + const makeTexture = (name) => { + let img = textureMap[name]; + if (!img) { + // 找不到图片时用 2x2 灰色占位纹理 + const c = canvasLib.createCanvas(2, 2); + const cx = c.getContext('2d'); + cx.fillStyle = '#888888'; + cx.fillRect(0, 0, 2, 2); + img = c; + } + if (spine.CanvasTexture) return new spine.CanvasTexture(img); + if (spine.canvas && spine.canvas.CanvasTexture) return new spine.canvas.CanvasTexture(img); + return new spine.Texture(img); + }; + + let atlas; + const is4x = typeof spine.TextureAtlas === 'function' && spine.TextureAtlas.length <= 1; + if (is4x) { + atlas = new spine.TextureAtlas(atlasText); + for (const page of atlas.pages) { + const tex = makeTexture(page.name); + if (page.setTexture) page.setTexture(tex); + else page.texture = tex; + } + } else { + atlas = new spine.TextureAtlas(atlasText, (name) => makeTexture(name)); + } + resolve(atlas); + })().catch(reject); + }); +} + +/** 读取骨骼数据(json 或二进制) */ +function readSkeletonData(spine, skeletonPath, atlas, isBinary) { + const atlasLoader = new spine.AtlasAttachmentLoader(atlas); + if (isBinary) { + const loader = new spine.SkeletonBinary(atlasLoader); + loader.scale = 1; + const buf = fs.readFileSync(skeletonPath); + return loader.readSkeletonData(new Uint8Array(buf)); + } else { + const loader = new spine.SkeletonJson(atlasLoader); + loader.scale = 1; + const text = fs.readFileSync(skeletonPath, 'utf8'); + return loader.readSkeletonData(text); + } +} + +/** 计算包围盒(跨版本兼容) */ +function getBounds(spine, skeleton) { + try { + if (skeleton.getBoundsRect) { + const r = skeleton.getBoundsRect(); + if (r && r.width !== undefined) return { x: r.x, y: r.y, width: r.width, height: r.height }; + } + if (skeleton.getBounds) { + const offset = new spine.Vector2(); + const size = new spine.Vector2(); + skeleton.getBounds(offset, size, []); + if (size.x > 0 || size.y > 0) return { x: offset.x, y: offset.y, width: size.x, height: size.y }; + } + } catch (e) { /* ignore */ } + return null; +} + +/** + * 渲染首帧动画到 PNG buffer。 + * @returns {Promise} + */ +async function renderThumbnail({ skeletonPath, atlasPath, texturePaths, version, runtimeDir, size = 400 }) { + if (!canvasLib) throw new Error('@napi-rs/canvas 不可用'); + const isBinary = /\.skel(\.bytes)?$/i.test(skeletonPath); + const dir = path.dirname(skeletonPath); + const atlasText = fs.readFileSync(atlasPath, 'utf8'); + + const spine = loadRuntime(runtimeDir); + const atlas = await buildTextureAtlas(spine, atlasText, dir, texturePaths); + const skeletonData = readSkeletonData(spine, skeletonPath, atlas, isBinary); + + // 3.6/3.7 的二进制骨骼与 3.8 运行时二进制格式不兼容, + // 且 3.6/3.7 的 JS 运行时本身不含二进制解析器,因此这类文件无法加载。 + if (!skeletonData || !skeletonData.bones || skeletonData.bones.length === 0) { + const name = path.basename(skeletonPath); + throw new Error(version && parseFloat(version) < 3.8 + ? 'Spine ' + version + ' 的二进制骨骼(' + name + ')无法由官方 JS 运行时解析,请改用 .json 格式导出。' + : '骨骼数据为空:' + name); + } + const skeleton = new spine.Skeleton(skeletonData); + + // 计算所有动画的包围盒,取最合适的姿态用于缩略图。 + // 默认使用 setup pose(编辑器内的标准站姿),保证缩略图稳定、接近编辑视图。 + let bounds = null; + if (skeleton.setToSetupPose) skeleton.setToSetupPose(); + if (skeleton.updateWorldTransform) { + if (spine.Physics && spine.Physics.update !== undefined) skeleton.updateWorldTransform(spine.Physics.update); + else skeleton.updateWorldTransform(); + } + bounds = getBounds(spine, skeleton); + + const cw = size, ch = size; + const canvas = canvasLib.createCanvas(cw, ch); + const ctx = canvas.getContext('2d'); + ctx.fillStyle = '#1e1e1e'; + ctx.fillRect(0, 0, cw, ch); + + if (bounds && bounds.width > 0 && bounds.height > 0) { + const pad = 0.1; + const scale = Math.min((cw * (1 - pad * 2)) / bounds.width, (ch * (1 - pad * 2)) / bounds.height); + // Spine 世界坐标 Y 轴向上,而 Canvas 2D Y 轴向下,需翻转 Y。 + const cx = bounds.x + bounds.width / 2; + const cy = bounds.y + bounds.height / 2; + ctx.save(); + ctx.translate(cw / 2, ch / 2); + ctx.scale(scale, -scale); + ctx.translate(-cx, -cy); + + let renderer = null; + if (spine.canvas && spine.canvas.SkeletonRenderer) renderer = new spine.canvas.SkeletonRenderer(ctx); + else if (spine.SkeletonRenderer) renderer = new spine.SkeletonRenderer(ctx); + if (renderer) { + // 使用三角渲染,正确处理 mesh 附件(如角色身体的网格) + if ('triangleRendering' in renderer) renderer.triangleRendering = true; + renderer.draw(skeleton); + } + ctx.restore(); + } + + const buf = canvas.toBuffer('image/png'); + return buf; +} + +module.exports = { renderThumbnail, loadRuntime, buildTextureAtlas, readSkeletonData, getBounds, canvasLib }; diff --git a/js/spine-utils.js b/js/spine-utils.js new file mode 100644 index 0000000..0af3e2e --- /dev/null +++ b/js/spine-utils.js @@ -0,0 +1,542 @@ +/** + * SpineViewer - 工具模块 + * 该模块为纯 Node.js CommonJS,供 viewer/thumbnail 复用。 + * 职责: + * - 识别 Spine 导出文件的类型(skel/skel.bytes/json/atlas/atlas.txt/png/jpg/jpeg/webp) + * - 在同一个目录内自动关联配套的骨骼文件、atlas、贴图 + * - 从骨骼数据中检测 Spine 版本 + * - 根据版本选择合适的本地运行时 + */ + +const fs = require('fs'); +const path = require('path'); + +const SKELETON_EXTS = ['.skel', '.skel.bytes', '.json']; +const ATLAS_EXTS = ['.atlas', '.atlas.txt']; +const TEXTURE_EXTS = ['.png', '.jpg', '.jpeg', '.webp']; +const ALL_EXTS = SKELETON_EXTS.concat(ATLAS_EXTS, TEXTURE_EXTS); + +// Spine 导出常见的后缀,匹配时归一化掉 +const SUFFIX_RE = /-(pro|ess|pma|base|atlas|_pma|_pro|_ess)$/i; + +function extOf(name) { + const lower = name.toLowerCase(); + for (let i = 0; i < SKELETON_EXTS.length; i++) { + if (lower.endsWith(SKELETON_EXTS[i])) return SKELETON_EXTS[i]; + } + for (let i = 0; i < ATLAS_EXTS.length; i++) { + if (lower.endsWith(ATLAS_EXTS[i])) return ATLAS_EXTS[i]; + } + for (let i = 0; i < TEXTURE_EXTS.length; i++) { + if (lower.endsWith(TEXTURE_EXTS[i])) return TEXTURE_EXTS[i]; + } + return null; +} + +function isSkeletonFile(name) { + const ext = extOf(name); + return ext === '.skel' || ext === '.skel.bytes' || ext === '.json'; +} + +function isAtlasFile(name) { + const ext = extOf(name); + return ext === '.atlas' || ext === '.atlas.txt'; +} + +function isTextureFile(name) { + const ext = extOf(name); + return TEXTURE_EXTS.indexOf(ext) !== -1; +} + +/** 去掉文件名中的扩展名 */ +function stemOf(name) { + const ext = extOf(name); + if (!ext) return name; + return name.slice(0, name.length - ext.length); +} + +/** 归一化 stem,去掉 Spine 常见后缀,用于跨文件匹配 */ +function normalizeStem(name) { + return stemOf(name).toLowerCase().replace(SUFFIX_RE, ''); +} + +/** 从 JSON 文本中读取 spine 版本 */ +function detectVersionFromJson(text) { + try { + const json = JSON.parse(text); + if (json && json.skeleton && json.skeleton.spine) { + return String(json.skeleton.spine); + } + } catch (e) { /* ignore */ } + return null; +} + +/** 从二进制数据中读取 spine 版本(扫描前若干字节中的版本号) */ +function detectVersionFromBuffer(buf) { + let s = ''; + const bytes = new Uint8Array(buf); + const len = Math.min(bytes.length, 160); + for (let i = 0; i < len; i++) { + s += String.fromCharCode(bytes[i]); + } + const m = s.match(/(\d+\.\d+(?:\.\d+)?)/); + return m ? m[1] : null; +} + +/** 从文件读取 spine 版本 */ +function detectVersion(filePath) { + const lower = filePath.toLowerCase(); + if (lower.endsWith('.json')) { + return detectVersionFromJson(fs.readFileSync(filePath, 'utf8')); + } + return detectVersionFromBuffer(fs.readFileSync(filePath)); +} + +/** + * 根据检测到的版本与文件类型,选择本地运行时目录。 + * - 3.x 只有 3.8 的 JS 构建包含二进制解析器,因此二进制使用 3.8 运行时 + */ +function chooseRuntimeDir(version, isBinary) { + if (!version) return null; + const major = parseInt(version.split('.')[0], 10); + if (major === 3) { + if (isBinary) return '3.8'; + const minor = parseFloat(version); + if (minor <= 3.6) return '3.6'; + if (minor <= 3.7 + 0.0001) return '3.7'; + return '3.8'; + } else if (major === 4) { + const minor = parseFloat(version); + if (minor <= 4.0 + 0.0001) return '4.0'; + if (minor <= 4.1 + 0.0001) return '4.1'; + if (minor <= 4.2 + 0.0001) return '4.2'; + return '4.3'; + } + return null; +} + +/** + * 判断给定的 JSON 文件是否为 Spine 骨骼 JSON,避免把普通 JSON 误判为骨骼数据。 + * 判定条件:存在 `skeleton` 及其 `spine` 版本字段,或同时存在 `bones` + `slots` 数组。 + */ +function looksLikeSkeletonJson(filePath) { + try { + const json = JSON.parse(fs.readFileSync(filePath, 'utf8')); + if (!json || typeof json !== 'object') return false; + if (json.skeleton && json.skeleton.spine) return true; + if (Array.isArray(json.bones) && json.bones.length > 0 && Array.isArray(json.slots)) return true; + return false; + } catch (e) { + return false; + } +} + +/** 文件修改时间(毫秒) */ +function mtimeOf(fp) { + try { return fs.statSync(fp).mtimeMs; } catch (e) { return 0; } +} + +/** 读取某 item 元数据里的创建时间 btime(毫秒),用于按“同一批导入”配对 */ +function btimeOf(fp) { + const d = itemMeta(path.dirname(fp)); + return (d && d.btime) || 0; +} + +/** 骨骼版本所属家族(3x / 4x),atlas 格式按版本家族区分 */ +function versionFamily(version) { + if (!version) return null; + const major = parseInt(version.split('.')[0], 10); + return major <= 3 ? '3x' : '4x'; +} + +/** 根据 atlas 文本判断其格式家族(3x / 4x) */ +function atlasFamily(atlasText) { + if (!atlasText) return null; + // 4.x atlas 用 `bounds:` 定义区域;3.x 用 `xy:`/`size:`/`orig:`/`offset:`。 + // 注意:`scale:` 在 3.x 也会出现(如字体缩放),不能单独作为 4x 依据。 + // 因此以 `bounds:` 作为最可靠的 4.x 标志;若整体含 `xy:` 判定为 3x。 + if (/\bbounds\s*:/.test(atlasText)) return '4x'; + if (/\bxy\s*:/.test(atlasText)) return '3x'; + return '3x'; +} + +/** 读取某 item 文件夹的 metadata.json(含 folders、isDeleted、btime 等) */ +function itemMeta(itemDir) { + if (!itemDir) return null; + try { + return JSON.parse(fs.readFileSync(path.join(itemDir, 'metadata.json'), 'utf8')); + } catch (e) { + return null; + } +} + +/** 读取某个资产文件所属 item 文件夹的 Eagle 逻辑文件夹 id 列表 */ +function foldersOfItem(filePath) { + const d = itemMeta(path.dirname(filePath)); + return d && Array.isArray(d.folders) ? d.folders : []; +} + +/** 判断某 item 是否已被放入 Eagle 回收站(isDeleted) */ +function isItemDeleted(filePath) { + const d = itemMeta(path.dirname(filePath)); + return !!(d && d.isDeleted); +} + +/** 从任意 item 路径向上定位 Eagle 库根目录 */ +function findLibraryRoot(filePath) { + let dir = path.dirname(filePath); // item 文件夹 + for (let i = 0; i < 8; i++) { + const parent = path.dirname(dir); + if (parent === dir) break; + try { + if (fs.existsSync(path.join(parent, 'metadata.json')) && fs.existsSync(path.join(parent, 'images'))) { + return parent; + } + } catch (e) { /* ignore */ } + dir = parent; + } + return null; +} + +/** 解析库根 metadata.json,返回 { folderId -> children[] } 及文件夹名 */ +function readFolderInfo(libRoot) { + const map = {}; + const names = {}; + if (!libRoot) return { map, names }; + try { + const d = JSON.parse(fs.readFileSync(path.join(libRoot, 'metadata.json'), 'utf8')); + const folders = d.folders || []; + for (const f of folders) { + if (!f) continue; + map[f.id] = Array.isArray(f.children) ? f.children : []; + names[f.id] = f.name || ''; + } + } catch (e) { /* ignore */ } + return { map, names }; +} + +/** + * 计算允许匹配的 Eagle 文件夹 id 集合: + * 仅包含「选中文件所在的文件夹」本身,不下钻子文件夹,也不匹配父级/兄弟文件夹。 + */ +function getValidFolders(filePath) { + const itemFolders = foldersOfItem(filePath); + if (itemFolders.length === 0) return null; // 未归入任何 Eagle 文件夹,则不限定 + return new Set(itemFolders); +} + +/** 判断目录是否为 Eagle 的 item 元数据文件夹(包含 metadata.json) */ +function isEagleItemDir(dir) { + try { return fs.existsSync(path.join(dir, 'metadata.json')); } catch (e) { return false; } +} + +/** + * 计算需要搜索的目录列表。 + * Eagle 会把导入的每个文件拆分成独立的元数据文件夹(如 `images/.info/`), + * 因此配套的骨骼/atlas/贴图可能位于不同的 item 文件夹中。 + * 返回:当前 item 文件夹 + 其同级的所有 item 文件夹。 + */ +function getSearchRoots(filePath) { + const roots = []; + const itemDir = path.dirname(filePath); + roots.push(itemDir); + if (isEagleItemDir(itemDir)) { + const parent = path.dirname(itemDir); + try { + for (const name of fs.readdirSync(parent)) { + const sub = path.join(parent, name); + try { + if (fs.statSync(sub).isDirectory() && isEagleItemDir(sub)) { + roots.push(sub); + } + } catch (e) { /* ignore */ } + } + } catch (e) { /* ignore */ } + } + return [...new Set(roots)]; +} + +/** 把库根目录 images/ 下所有 item 文件夹加入搜索根(去重)。 + * 用于覆盖同伴位于不同 .info / 跨批次的情况(全库兜底)。 */ +function buildRootsWithLibraryRoot(filePath, roots) { + const libRoot = findLibraryRoot(filePath); + if (!libRoot) return; + const imagesDir = path.join(libRoot, 'images'); + try { + if (!fs.existsSync(imagesDir)) return; + for (const name of fs.readdirSync(imagesDir)) { + const sub = path.join(imagesDir, name); + try { + if (fs.statSync(sub).isDirectory() && isEagleItemDir(sub)) { + if (roots.indexOf(sub) === -1) roots.push(sub); + } + } catch (e) { /* ignore */ } + } + } catch (e) { /* ignore */ } +} + +/** + * 在多个目录中收集所有 Spine 相关文件,返回 [{ name, fullPath }]。 + * 若传入 validFolders(Eagle 逻辑文件夹 id 集合),则只保留位于这些文件夹内的 item, + * 从而把匹配范围限定在「选中文件所在的 Eagle 文件夹及其子文件夹」内。 + */ +function collectSpineFiles(roots, validFolders) { + const seen = new Set(); + const out = []; + for (const root of roots) { + let entries; + try { entries = fs.readdirSync(root); } catch (e) { continue; } + for (const name of entries) { + const full = path.join(root, name); + try { if (!fs.statSync(full).isFile()) continue; } catch (e) { continue; } + if (!extOf(name)) continue; // 只关心 Spine 相关扩展 + // 排除 Eagle 回收站中已删除的项 + if (isItemDeleted(full)) continue; + if (validFolders && validFolders.size) { + const itemFolders = foldersOfItem(full); + if (!itemFolders.some((f) => validFolders.has(f))) continue; // 不在允许的文件夹内 + } + if (seen.has(full)) continue; + seen.add(full); + out.push({ name, fullPath: full }); + } + } + return out; +} + +/** + * 修正不可靠的源路径。 + * Eagle 传给缩略图 handler 的 src 有时指向一个已清理/不存在的 `.info` 目录 + * (例如其内部临时工作目录)。此时按文件名在整个库 images/ 下找到真实存在的 + * 源文件,作为后续资源发现的基准。 + */ +function resolveRealSource(filePath) { + // 源目录存在且是有效 item 目录 → 直接用 + const dir = path.dirname(filePath); + if (isEagleItemDir(dir)) return filePath; + const name = path.basename(filePath); + const libRoot = findLibraryRoot(filePath); + if (!libRoot) return filePath; + const imagesDir = path.join(libRoot, 'images'); + try { + if (!fs.existsSync(imagesDir)) return filePath; + // 优先找“文件名 + 类型”匹配的真实文件。若存在同名文件,返回它所在目录, + // 以便后续 getSearchRoots/selectBest 能借助其 folders/btime 精确匹配。 + let fallback = null; + for (const d of fs.readdirSync(imagesDir)) { + const sub = path.join(imagesDir, d); + if (!isEagleItemDir(sub)) continue; + const cand = path.join(sub, name); + if (fs.existsSync(cand)) { + // 优先选择未被删除的项 + if (!isItemDeleted(cand)) return cand; + if (!fallback) fallback = cand; + } + } + if (fallback) return fallback; + } catch (e) { /* ignore */ } + return filePath; +} + +/** + * 发现与所选文件 related 的 Spine 资源(跨 Eagle 多个 item 文件夹)。 + * 返回 { skeletonPath, atlasPath, texturePaths, base, isBinary, ... } + * - texturePaths: { atlas 中引用的贴图名 -> 绝对路径 } + */ +function discoverAssets(filePath) { + filePath = resolveRealSource(filePath); + const selected = path.basename(filePath); + const selectedStem = normalizeStem(selected); + // 先扫码“选中 item 文件夹 + 同级所有 .info”(精确、不跨批次)。 + const roots = getSearchRoots(filePath); + // 若同级范围无法凑齐骨架+图集(常见于 Eagle 导入瞬间,同伴落在别的 .info), + // 则扩展搜索到整个库的 images/ 目录(全库兜底,靠“同家族 + 同文件夹 + 最近 btime”配对)。 + buildRootsWithLibraryRoot(filePath, roots); + + // 只匹配选中文件所在的 Eagle 文件夹(及子文件夹)内的资源,避免串到其他项目 + const validFolders = getValidFolders(filePath); + const files = collectSpineFiles(roots, validFolders); + + const skeletonFiles = files.filter((f) => isSkeletonFile(f.name)); + const atlasFiles = files.filter((f) => isAtlasFile(f.name)); + const textureFiles = files.filter((f) => isTextureFile(f.name)); + + // 区分“骨架 json”和“普通 json”:只保留形似骨架的 json + const realSkeletonFiles = skeletonFiles.filter((f) => { + if (f.name.toLowerCase().endsWith('.json')) return looksLikeSkeletonJson(f.fullPath); + return true; + }); + + // 工具:优先选择与 refFile 位于同一个 Eagle 逻辑文件夹的候选; + // 同文件夹内有多个时,再按“创建时间 btime 最接近”选取(视为同一批导入)。 + const selectBest = (cands, refFile) => { + if (!cands || cands.length === 0) return null; + const refFolders = foldersOfItem(refFile); + const refBtime = btimeOf(refFile); + const scored = cands.map((c) => { + let score = 0; + const cFolders = foldersOfItem(c.fullPath); + if (refFolders.length && cFolders.some((f) => refFolders.indexOf(f) !== -1)) score += 1e6; + // btime 越接近越好(差值作为负加成) + score += -Math.abs(btimeOf(c.fullPath) - refBtime); + return { c, score }; + }); + scored.sort((a, b) => b.score - a.score); + return scored[0].c; + }; + + // 辅助:读取候选 atlas 的格式家族,以及候选骨骼的版本家族 + const familyOfAtlas = (f) => { try { return atlasFamily(fs.readFileSync(f.fullPath, 'utf8')); } catch (e) { return null; } }; + const familyOfSkel = (f) => { try { return versionFamily(detectVersion(f.fullPath)); } catch (e) { return null; } }; + + // 选中的文件若是 atlas,则读取其格式家族,用于匹配同家族的骨骼 + const selectedAtlasFamily = isAtlasFile(selected) + ? (() => { try { return atlasFamily(fs.readFileSync(filePath, 'utf8')); } catch (e) { return null; } })() + : null; + + // 1) 骨骼文件 + let skeleton = null; + // 若选中的就是骨骼文件,务必使用它本身(它的版本即最终版本) + if (isSkeletonFile(selected)) { + skeleton = realSkeletonFiles.find((f) => f.name === selected) || null; + } + if (!skeleton) { + // 依选中 stem 匹配;优先与选中 atlas 同家族(3x/4x),再按同文件夹/同批导入 + let cands = realSkeletonFiles.filter((f) => normalizeStem(f.name) === selectedStem); + if (selectedAtlasFamily && cands.length > 1) { + const same = cands.filter((f) => familyOfSkel(f) === selectedAtlasFamily); + if (same.length > 0) cands = same; + } + skeleton = cands.length > 0 ? selectBest(cands, filePath) : null; + } + if (!skeleton && realSkeletonFiles.length > 0) { + // 忽略 stem:优先与选中 atlas 同家族,再按同 Eagle 文件夹 + 最近 btime 选取 + let cands = realSkeletonFiles; + if (selectedAtlasFamily) { + const same = cands.filter((f) => familyOfSkel(f) === selectedAtlasFamily); + if (same.length > 0) cands = same; + } + skeleton = selectBest(cands, filePath); + } + + // 2) atlas 文件 —— 优先与骨骼版本家族一致(3x/4x),避免 3.8 骨骼配 4x atlas + let atlas = null; + if (isAtlasFile(selected)) { + atlas = atlasFiles.find((f) => f.name === selected) || null; + } + // 统一的候选选择:优先“与骨骼同家族(3x/4x)”的 atlas,再按“同文件夹 + 最近 btime”挑选。 + // 家族过滤无条件优先,避免 4x 骨骼配到 3x 图集(会导致 UV/坐标错乱)。 + const pickAtlas = (cands, refFile) => { + if (!cands || cands.length === 0) return null; + const skelFamily = skeleton ? familyOfSkel(skeleton) : null; + if (skelFamily) { + const same = cands.filter((f) => familyOfAtlas(f) === skelFamily); + if (same.length > 0) cands = same; + } + return selectBest(cands, refFile); + }; + + if (!atlas) { + let cands = atlasFiles.filter((f) => normalizeStem(f.name) === selectedStem); + atlas = pickAtlas(cands, filePath); + } + if (!atlas && skeleton) { + const skelStem = normalizeStem(skeleton.name); + let cands = atlasFiles.filter((f) => normalizeStem(f.name) === skelStem); + atlas = pickAtlas(cands, skeleton.fullPath); + } + if (!atlas && skeleton) { + // 忽略 stem:用与骨骼同 Eagle 文件夹 + 同家族(3x/4x) + 最近 btime 的 atlas + atlas = pickAtlas(atlasFiles, skeleton.fullPath); + } + if (!atlas && atlasFiles.length === 1) atlas = atlasFiles[0]; + + // 3) 解析 atlas 引用的贴图路径(多个同名贴图时,优先与 atlas 同文件夹/同批导入的) + let texturePaths = {}; + if (atlas) { + let text = ''; + try { text = fs.readFileSync(atlas.fullPath, 'utf8'); } catch (e) { /* ignore */ } + const pageNames = parseAtlasPages(text); + const atlasDir = path.dirname(atlas.fullPath); // atlas 所在 .info 目录 + for (const pn of pageNames) { + // 1) 优先使用 atlas 所在 .info 目录里的同名贴图(最可靠) + const inAtlasDir = path.join(atlasDir, pn); + if (fs.existsSync(inAtlasDir)) { + texturePaths[pn] = inAtlasDir; + continue; + } + // 2) 否则在候选里按“同 Eagle 文件夹 + 最近 btime”挑选 + let cands = textureFiles.filter((f) => f.name.toLowerCase() === pn.toLowerCase()); + if (cands.length === 0) cands = textureFiles.filter((f) => normalizeStem(f.name) === normalizeStem(pn)); + const hit = selectBest(cands, atlas.fullPath); + if (hit) texturePaths[pn] = hit.fullPath; + } + } + + const base = skeleton ? normalizeStem(skeleton.name) : (atlas ? normalizeStem(atlas.name) : selectedStem); + const skelLower = skeleton ? skeleton.name.toLowerCase() : ''; + const skeletonIsBinary = skelLower.endsWith('.skel') || skelLower.endsWith('.skel.bytes'); + + return { + skeletonPath: skeleton ? skeleton.fullPath : null, + atlasPath: atlas ? atlas.fullPath : null, + texturePaths, + base, + isBinary: skeletonIsBinary, + skeletonCandidates: realSkeletonFiles.map((f) => f.name), + atlasCandidates: atlasFiles.map((f) => f.name), + textureCandidates: textureFiles.map((f) => f.name), + }; +} + +/** 从 atlas 文本中解析出引用的贴图页面文件名 */ +function parseAtlasPages(atlasText) { + const pages = []; + if (!atlasText) return pages; + const lines = atlasText.split(/\r?\n/); + // atlas 中每个页面以一行“xxx.png”之类的文件名开始 + for (let i = 0; i < lines.length; i++) { + const line = lines[i].trim(); + if (/\.(png|jpg|jpeg|webp)$/i.test(line)) { + pages.push(line); + } else if (line === '') { + // 空白行之后的下一个非空行可能是下一页文件名 + continue; + } + } + // 过滤掉显然是属性的行(例如 "size: 512,512"、"filter: " 等) + return pages.filter((p) => !/[=,:]/.test(p)); +} + +module.exports = { + SKELETON_EXTS, + ATLAS_EXTS, + TEXTURE_EXTS, + ALL_EXTS, + extOf, + isSkeletonFile, + isAtlasFile, + isTextureFile, + stemOf, + normalizeStem, + detectVersion, + detectVersionFromJson, + detectVersionFromBuffer, + chooseRuntimeDir, + looksLikeSkeletonJson, + discoverAssets, + parseAtlasPages, + isEagleItemDir, + getSearchRoots, + collectSpineFiles, + foldersOfItem, + findLibraryRoot, + readFolderInfo, + getValidFolders, + mtimeOf, + btimeOf, + versionFamily, + atlasFamily, + itemMeta, + isItemDeleted, +}; diff --git a/lib/3.6/spine-canvas.js b/lib/3.6/spine-canvas.js new file mode 100644 index 0000000..1dc5765 --- /dev/null +++ b/lib/3.6/spine-canvas.js @@ -0,0 +1,6860 @@ +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var spine; +(function (spine) { + var Animation = (function () { + function Animation(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.duration = duration; + } + Animation.prototype.apply = function (skeleton, lastTime, time, loop, events, alpha, pose, 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; + } + var timelines = this.timelines; + for (var i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, lastTime, time, events, alpha, pose, direction); + }; + Animation.binarySearch = function (values, target, step) { + if (step === void 0) { step = 1; } + var low = 0; + var high = values.length / step - 2; + if (high == 0) + return step; + var 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; + } + }; + Animation.linearSearch = function (values, target, step) { + for (var i = 0, last = values.length - step; i <= last; i += step) + if (values[i] > target) + return i; + return -1; + }; + return Animation; + }()); + spine.Animation = Animation; + var MixPose; + (function (MixPose) { + MixPose[MixPose["setup"] = 0] = "setup"; + MixPose[MixPose["current"] = 1] = "current"; + MixPose[MixPose["currentLayered"] = 2] = "currentLayered"; + })(MixPose = spine.MixPose || (spine.MixPose = {})); + var MixDirection; + (function (MixDirection) { + MixDirection[MixDirection["in"] = 0] = "in"; + MixDirection[MixDirection["out"] = 1] = "out"; + })(MixDirection = spine.MixDirection || (spine.MixDirection = {})); + var TimelineType; + (function (TimelineType) { + TimelineType[TimelineType["rotate"] = 0] = "rotate"; + TimelineType[TimelineType["translate"] = 1] = "translate"; + TimelineType[TimelineType["scale"] = 2] = "scale"; + TimelineType[TimelineType["shear"] = 3] = "shear"; + TimelineType[TimelineType["attachment"] = 4] = "attachment"; + TimelineType[TimelineType["color"] = 5] = "color"; + TimelineType[TimelineType["deform"] = 6] = "deform"; + TimelineType[TimelineType["event"] = 7] = "event"; + TimelineType[TimelineType["drawOrder"] = 8] = "drawOrder"; + TimelineType[TimelineType["ikConstraint"] = 9] = "ikConstraint"; + TimelineType[TimelineType["transformConstraint"] = 10] = "transformConstraint"; + TimelineType[TimelineType["pathConstraintPosition"] = 11] = "pathConstraintPosition"; + TimelineType[TimelineType["pathConstraintSpacing"] = 12] = "pathConstraintSpacing"; + TimelineType[TimelineType["pathConstraintMix"] = 13] = "pathConstraintMix"; + TimelineType[TimelineType["twoColor"] = 14] = "twoColor"; + })(TimelineType = spine.TimelineType || (spine.TimelineType = {})); + var CurveTimeline = (function () { + function CurveTimeline(frameCount) { + if (frameCount <= 0) + throw new Error("frameCount must be > 0: " + frameCount); + this.curves = spine.Utils.newFloatArray((frameCount - 1) * CurveTimeline.BEZIER_SIZE); + } + CurveTimeline.prototype.getFrameCount = function () { + return this.curves.length / CurveTimeline.BEZIER_SIZE + 1; + }; + CurveTimeline.prototype.setLinear = function (frameIndex) { + this.curves[frameIndex * CurveTimeline.BEZIER_SIZE] = CurveTimeline.LINEAR; + }; + CurveTimeline.prototype.setStepped = function (frameIndex) { + this.curves[frameIndex * CurveTimeline.BEZIER_SIZE] = CurveTimeline.STEPPED; + }; + CurveTimeline.prototype.getCurveType = function (frameIndex) { + var index = frameIndex * CurveTimeline.BEZIER_SIZE; + if (index == this.curves.length) + return CurveTimeline.LINEAR; + var type = this.curves[index]; + if (type == CurveTimeline.LINEAR) + return CurveTimeline.LINEAR; + if (type == CurveTimeline.STEPPED) + return CurveTimeline.STEPPED; + return CurveTimeline.BEZIER; + }; + CurveTimeline.prototype.setCurve = function (frameIndex, cx1, cy1, cx2, cy2) { + var tmpx = (-cx1 * 2 + cx2) * 0.03, tmpy = (-cy1 * 2 + cy2) * 0.03; + var dddfx = ((cx1 - cx2) * 3 + 1) * 0.006, dddfy = ((cy1 - cy2) * 3 + 1) * 0.006; + var ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy; + var dfx = cx1 * 0.3 + tmpx + dddfx * 0.16666667, dfy = cy1 * 0.3 + tmpy + dddfy * 0.16666667; + var i = frameIndex * CurveTimeline.BEZIER_SIZE; + var curves = this.curves; + curves[i++] = CurveTimeline.BEZIER; + var x = dfx, y = dfy; + for (var 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; + } + }; + CurveTimeline.prototype.getCurvePercent = function (frameIndex, percent) { + percent = spine.MathUtils.clamp(percent, 0, 1); + var curves = this.curves; + var i = frameIndex * CurveTimeline.BEZIER_SIZE; + var type = curves[i]; + if (type == CurveTimeline.LINEAR) + return percent; + if (type == CurveTimeline.STEPPED) + return 0; + i++; + var x = 0; + for (var start = i, n = i + CurveTimeline.BEZIER_SIZE - 1; i < n; i += 2) { + x = curves[i]; + if (x >= percent) { + var prevX = void 0, prevY = void 0; + 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); + } + } + var y = curves[i - 1]; + return y + (1 - y) * (percent - x) / (1 - x); + }; + CurveTimeline.LINEAR = 0; + CurveTimeline.STEPPED = 1; + CurveTimeline.BEZIER = 2; + CurveTimeline.BEZIER_SIZE = 10 * 2 - 1; + return CurveTimeline; + }()); + spine.CurveTimeline = CurveTimeline; + var RotateTimeline = (function (_super) { + __extends(RotateTimeline, _super); + function RotateTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount << 1); + return _this; + } + RotateTimeline.prototype.getPropertyId = function () { + return (TimelineType.rotate << 24) + this.boneIndex; + }; + RotateTimeline.prototype.setFrame = function (frameIndex, time, degrees) { + frameIndex <<= 1; + this.frames[frameIndex] = time; + this.frames[frameIndex + RotateTimeline.ROTATION] = degrees; + }; + RotateTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, pose, direction) { + var frames = this.frames; + var bone = skeleton.bones[this.boneIndex]; + if (time < frames[0]) { + switch (pose) { + case MixPose.setup: + bone.rotation = bone.data.rotation; + return; + case MixPose.current: + var r_1 = bone.data.rotation - bone.rotation; + r_1 -= (16384 - ((16384.499999999996 - r_1 / 360) | 0)) * 360; + bone.rotation += r_1 * alpha; + } + return; + } + if (time >= frames[frames.length - RotateTimeline.ENTRIES]) { + if (pose == MixPose.setup) + bone.rotation = bone.data.rotation + frames[frames.length + RotateTimeline.PREV_ROTATION] * alpha; + else { + var r_2 = bone.data.rotation + frames[frames.length + RotateTimeline.PREV_ROTATION] - bone.rotation; + r_2 -= (16384 - ((16384.499999999996 - r_2 / 360) | 0)) * 360; + bone.rotation += r_2 * alpha; + } + return; + } + var frame = Animation.binarySearch(frames, time, RotateTimeline.ENTRIES); + var prevRotation = frames[frame + RotateTimeline.PREV_ROTATION]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + RotateTimeline.PREV_TIME] - frameTime)); + var r = frames[frame + RotateTimeline.ROTATION] - prevRotation; + r -= (16384 - ((16384.499999999996 - r / 360) | 0)) * 360; + r = prevRotation + r * percent; + if (pose == MixPose.setup) { + r -= (16384 - ((16384.499999999996 - r / 360) | 0)) * 360; + bone.rotation = bone.data.rotation + r * alpha; + } + else { + r = bone.data.rotation + r - bone.rotation; + r -= (16384 - ((16384.499999999996 - r / 360) | 0)) * 360; + bone.rotation += r * alpha; + } + }; + RotateTimeline.ENTRIES = 2; + RotateTimeline.PREV_TIME = -2; + RotateTimeline.PREV_ROTATION = -1; + RotateTimeline.ROTATION = 1; + return RotateTimeline; + }(CurveTimeline)); + spine.RotateTimeline = RotateTimeline; + var TranslateTimeline = (function (_super) { + __extends(TranslateTimeline, _super); + function TranslateTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * TranslateTimeline.ENTRIES); + return _this; + } + TranslateTimeline.prototype.getPropertyId = function () { + return (TimelineType.translate << 24) + this.boneIndex; + }; + TranslateTimeline.prototype.setFrame = function (frameIndex, time, x, y) { + frameIndex *= TranslateTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + TranslateTimeline.X] = x; + this.frames[frameIndex + TranslateTimeline.Y] = y; + }; + TranslateTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, pose, direction) { + var frames = this.frames; + var bone = skeleton.bones[this.boneIndex]; + if (time < frames[0]) { + switch (pose) { + case MixPose.setup: + bone.x = bone.data.x; + bone.y = bone.data.y; + return; + case MixPose.current: + bone.x += (bone.data.x - bone.x) * alpha; + bone.y += (bone.data.y - bone.y) * alpha; + } + return; + } + var x = 0, y = 0; + if (time >= frames[frames.length - TranslateTimeline.ENTRIES]) { + x = frames[frames.length + TranslateTimeline.PREV_X]; + y = frames[frames.length + TranslateTimeline.PREV_Y]; + } + else { + var frame = Animation.binarySearch(frames, time, TranslateTimeline.ENTRIES); + x = frames[frame + TranslateTimeline.PREV_X]; + y = frames[frame + TranslateTimeline.PREV_Y]; + var frameTime = frames[frame]; + var 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; + } + if (pose == MixPose.setup) { + bone.x = bone.data.x + x * alpha; + bone.y = bone.data.y + y * alpha; + } + else { + bone.x += (bone.data.x + x - bone.x) * alpha; + bone.y += (bone.data.y + y - bone.y) * alpha; + } + }; + TranslateTimeline.ENTRIES = 3; + TranslateTimeline.PREV_TIME = -3; + TranslateTimeline.PREV_X = -2; + TranslateTimeline.PREV_Y = -1; + TranslateTimeline.X = 1; + TranslateTimeline.Y = 2; + return TranslateTimeline; + }(CurveTimeline)); + spine.TranslateTimeline = TranslateTimeline; + var ScaleTimeline = (function (_super) { + __extends(ScaleTimeline, _super); + function ScaleTimeline(frameCount) { + return _super.call(this, frameCount) || this; + } + ScaleTimeline.prototype.getPropertyId = function () { + return (TimelineType.scale << 24) + this.boneIndex; + }; + ScaleTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, pose, direction) { + var frames = this.frames; + var bone = skeleton.bones[this.boneIndex]; + if (time < frames[0]) { + switch (pose) { + case MixPose.setup: + bone.scaleX = bone.data.scaleX; + bone.scaleY = bone.data.scaleY; + return; + case MixPose.current: + bone.scaleX += (bone.data.scaleX - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY - bone.scaleY) * alpha; + } + return; + } + var x = 0, y = 0; + if (time >= frames[frames.length - ScaleTimeline.ENTRIES]) { + x = frames[frames.length + ScaleTimeline.PREV_X] * bone.data.scaleX; + y = frames[frames.length + ScaleTimeline.PREV_Y] * bone.data.scaleY; + } + else { + var frame = Animation.binarySearch(frames, time, ScaleTimeline.ENTRIES); + x = frames[frame + ScaleTimeline.PREV_X]; + y = frames[frame + ScaleTimeline.PREV_Y]; + var frameTime = frames[frame]; + var 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) { + bone.scaleX = x; + bone.scaleY = y; + } + else { + var bx = 0, by = 0; + if (pose == MixPose.setup) { + bx = bone.data.scaleX; + by = bone.data.scaleY; + } + else { + bx = bone.scaleX; + by = bone.scaleY; + } + if (direction == MixDirection.out) { + x = Math.abs(x) * spine.MathUtils.signum(bx); + y = Math.abs(y) * spine.MathUtils.signum(by); + } + else { + bx = Math.abs(bx) * spine.MathUtils.signum(x); + by = Math.abs(by) * spine.MathUtils.signum(y); + } + bone.scaleX = bx + (x - bx) * alpha; + bone.scaleY = by + (y - by) * alpha; + } + }; + return ScaleTimeline; + }(TranslateTimeline)); + spine.ScaleTimeline = ScaleTimeline; + var ShearTimeline = (function (_super) { + __extends(ShearTimeline, _super); + function ShearTimeline(frameCount) { + return _super.call(this, frameCount) || this; + } + ShearTimeline.prototype.getPropertyId = function () { + return (TimelineType.shear << 24) + this.boneIndex; + }; + ShearTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, pose, direction) { + var frames = this.frames; + var bone = skeleton.bones[this.boneIndex]; + if (time < frames[0]) { + switch (pose) { + case MixPose.setup: + bone.shearX = bone.data.shearX; + bone.shearY = bone.data.shearY; + return; + case MixPose.current: + bone.shearX += (bone.data.shearX - bone.shearX) * alpha; + bone.shearY += (bone.data.shearY - bone.shearY) * alpha; + } + return; + } + var x = 0, y = 0; + if (time >= frames[frames.length - ShearTimeline.ENTRIES]) { + x = frames[frames.length + ShearTimeline.PREV_X]; + y = frames[frames.length + ShearTimeline.PREV_Y]; + } + else { + var frame = Animation.binarySearch(frames, time, ShearTimeline.ENTRIES); + x = frames[frame + ShearTimeline.PREV_X]; + y = frames[frame + ShearTimeline.PREV_Y]; + var frameTime = frames[frame]; + var 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; + } + if (pose == MixPose.setup) { + bone.shearX = bone.data.shearX + x * alpha; + bone.shearY = bone.data.shearY + y * alpha; + } + else { + bone.shearX += (bone.data.shearX + x - bone.shearX) * alpha; + bone.shearY += (bone.data.shearY + y - bone.shearY) * alpha; + } + }; + return ShearTimeline; + }(TranslateTimeline)); + spine.ShearTimeline = ShearTimeline; + var ColorTimeline = (function (_super) { + __extends(ColorTimeline, _super); + function ColorTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * ColorTimeline.ENTRIES); + return _this; + } + ColorTimeline.prototype.getPropertyId = function () { + return (TimelineType.color << 24) + this.slotIndex; + }; + ColorTimeline.prototype.setFrame = function (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; + }; + ColorTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, pose, direction) { + var slot = skeleton.slots[this.slotIndex]; + var frames = this.frames; + if (time < frames[0]) { + switch (pose) { + case MixPose.setup: + slot.color.setFromColor(slot.data.color); + return; + case MixPose.current: + var color = slot.color, 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; + } + var r = 0, g = 0, b = 0, a = 0; + if (time >= frames[frames.length - ColorTimeline.ENTRIES]) { + var 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 { + var 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]; + var frameTime = frames[frame]; + var 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 { + var color = slot.color; + if (pose == MixPose.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; + return ColorTimeline; + }(CurveTimeline)); + spine.ColorTimeline = ColorTimeline; + var TwoColorTimeline = (function (_super) { + __extends(TwoColorTimeline, _super); + function TwoColorTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * TwoColorTimeline.ENTRIES); + return _this; + } + TwoColorTimeline.prototype.getPropertyId = function () { + return (TimelineType.twoColor << 24) + this.slotIndex; + }; + TwoColorTimeline.prototype.setFrame = function (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; + }; + TwoColorTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, pose, direction) { + var slot = skeleton.slots[this.slotIndex]; + var frames = this.frames; + if (time < frames[0]) { + switch (pose) { + case MixPose.setup: + slot.color.setFromColor(slot.data.color); + slot.darkColor.setFromColor(slot.data.darkColor); + return; + case MixPose.current: + var light = slot.color, dark = slot.darkColor, setupLight = slot.data.color, 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; + } + var r = 0, g = 0, b = 0, a = 0, r2 = 0, g2 = 0, b2 = 0; + if (time >= frames[frames.length - TwoColorTimeline.ENTRIES]) { + var 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 { + var 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]; + var frameTime = frames[frame]; + var 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 { + var light = slot.color, dark = slot.darkColor; + if (pose == MixPose.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; + return TwoColorTimeline; + }(CurveTimeline)); + spine.TwoColorTimeline = TwoColorTimeline; + var AttachmentTimeline = (function () { + function AttachmentTimeline(frameCount) { + this.frames = spine.Utils.newFloatArray(frameCount); + this.attachmentNames = new Array(frameCount); + } + AttachmentTimeline.prototype.getPropertyId = function () { + return (TimelineType.attachment << 24) + this.slotIndex; + }; + AttachmentTimeline.prototype.getFrameCount = function () { + return this.frames.length; + }; + AttachmentTimeline.prototype.setFrame = function (frameIndex, time, attachmentName) { + this.frames[frameIndex] = time; + this.attachmentNames[frameIndex] = attachmentName; + }; + AttachmentTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, pose, direction) { + var slot = skeleton.slots[this.slotIndex]; + if (direction == MixDirection.out && pose == MixPose.setup) { + var attachmentName_1 = slot.data.attachmentName; + slot.setAttachment(attachmentName_1 == null ? null : skeleton.getAttachment(this.slotIndex, attachmentName_1)); + return; + } + var frames = this.frames; + if (time < frames[0]) { + if (pose == MixPose.setup) { + var attachmentName_2 = slot.data.attachmentName; + slot.setAttachment(attachmentName_2 == null ? null : skeleton.getAttachment(this.slotIndex, attachmentName_2)); + } + return; + } + var frameIndex = 0; + if (time >= frames[frames.length - 1]) + frameIndex = frames.length - 1; + else + frameIndex = Animation.binarySearch(frames, time, 1) - 1; + var attachmentName = this.attachmentNames[frameIndex]; + skeleton.slots[this.slotIndex] + .setAttachment(attachmentName == null ? null : skeleton.getAttachment(this.slotIndex, attachmentName)); + }; + return AttachmentTimeline; + }()); + spine.AttachmentTimeline = AttachmentTimeline; + var zeros = null; + var DeformTimeline = (function (_super) { + __extends(DeformTimeline, _super); + function DeformTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount); + _this.frameVertices = new Array(frameCount); + if (zeros == null) + zeros = spine.Utils.newFloatArray(64); + return _this; + } + DeformTimeline.prototype.getPropertyId = function () { + return (TimelineType.deform << 27) + +this.attachment.id + this.slotIndex; + }; + DeformTimeline.prototype.setFrame = function (frameIndex, time, vertices) { + this.frames[frameIndex] = time; + this.frameVertices[frameIndex] = vertices; + }; + DeformTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, pose, direction) { + var slot = skeleton.slots[this.slotIndex]; + var slotAttachment = slot.getAttachment(); + if (!(slotAttachment instanceof spine.VertexAttachment) || !slotAttachment.applyDeform(this.attachment)) + return; + var verticesArray = slot.attachmentVertices; + if (verticesArray.length == 0) + alpha = 1; + var frameVertices = this.frameVertices; + var vertexCount = frameVertices[0].length; + var frames = this.frames; + if (time < frames[0]) { + var vertexAttachment = slotAttachment; + switch (pose) { + case MixPose.setup: + verticesArray.length = 0; + return; + case MixPose.current: + if (alpha == 1) { + verticesArray.length = 0; + break; + } + var vertices_1 = spine.Utils.setArraySize(verticesArray, vertexCount); + if (vertexAttachment.bones == null) { + var setupVertices = vertexAttachment.vertices; + for (var i = 0; i < vertexCount; i++) + vertices_1[i] += (setupVertices[i] - vertices_1[i]) * alpha; + } + else { + alpha = 1 - alpha; + for (var i = 0; i < vertexCount; i++) + vertices_1[i] *= alpha; + } + } + return; + } + var vertices = spine.Utils.setArraySize(verticesArray, vertexCount); + if (time >= frames[frames.length - 1]) { + var lastVertices = frameVertices[frames.length - 1]; + if (alpha == 1) { + spine.Utils.arrayCopy(lastVertices, 0, vertices, 0, vertexCount); + } + else if (pose == MixPose.setup) { + var vertexAttachment = slotAttachment; + if (vertexAttachment.bones == null) { + var setupVertices_1 = vertexAttachment.vertices; + for (var i_1 = 0; i_1 < vertexCount; i_1++) { + var setup = setupVertices_1[i_1]; + vertices[i_1] = setup + (lastVertices[i_1] - setup) * alpha; + } + } + else { + for (var i_2 = 0; i_2 < vertexCount; i_2++) + vertices[i_2] = lastVertices[i_2] * alpha; + } + } + else { + for (var i_3 = 0; i_3 < vertexCount; i_3++) + vertices[i_3] += (lastVertices[i_3] - vertices[i_3]) * alpha; + } + return; + } + var frame = Animation.binarySearch(frames, time); + var prevVertices = frameVertices[frame - 1]; + var nextVertices = frameVertices[frame]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime)); + if (alpha == 1) { + for (var i_4 = 0; i_4 < vertexCount; i_4++) { + var prev = prevVertices[i_4]; + vertices[i_4] = prev + (nextVertices[i_4] - prev) * percent; + } + } + else if (pose == MixPose.setup) { + var vertexAttachment = slotAttachment; + if (vertexAttachment.bones == null) { + var setupVertices_2 = vertexAttachment.vertices; + for (var i_5 = 0; i_5 < vertexCount; i_5++) { + var prev = prevVertices[i_5], setup = setupVertices_2[i_5]; + vertices[i_5] = setup + (prev + (nextVertices[i_5] - prev) * percent - setup) * alpha; + } + } + else { + for (var i_6 = 0; i_6 < vertexCount; i_6++) { + var prev = prevVertices[i_6]; + vertices[i_6] = (prev + (nextVertices[i_6] - prev) * percent) * alpha; + } + } + } + else { + for (var i_7 = 0; i_7 < vertexCount; i_7++) { + var prev = prevVertices[i_7]; + vertices[i_7] += (prev + (nextVertices[i_7] - prev) * percent - vertices[i_7]) * alpha; + } + } + }; + return DeformTimeline; + }(CurveTimeline)); + spine.DeformTimeline = DeformTimeline; + var EventTimeline = (function () { + function EventTimeline(frameCount) { + this.frames = spine.Utils.newFloatArray(frameCount); + this.events = new Array(frameCount); + } + EventTimeline.prototype.getPropertyId = function () { + return TimelineType.event << 24; + }; + EventTimeline.prototype.getFrameCount = function () { + return this.frames.length; + }; + EventTimeline.prototype.setFrame = function (frameIndex, event) { + this.frames[frameIndex] = event.time; + this.events[frameIndex] = event; + }; + EventTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, pose, direction) { + if (firedEvents == null) + return; + var frames = this.frames; + var frameCount = this.frames.length; + if (lastTime > time) { + this.apply(skeleton, lastTime, Number.MAX_VALUE, firedEvents, alpha, pose, direction); + lastTime = -1; + } + else if (lastTime >= frames[frameCount - 1]) + return; + if (time < frames[0]) + return; + var frame = 0; + if (lastTime < frames[0]) + frame = 0; + else { + frame = Animation.binarySearch(frames, lastTime); + var frameTime = frames[frame]; + while (frame > 0) { + if (frames[frame - 1] != frameTime) + break; + frame--; + } + } + for (; frame < frameCount && time >= frames[frame]; frame++) + firedEvents.push(this.events[frame]); + }; + return EventTimeline; + }()); + spine.EventTimeline = EventTimeline; + var DrawOrderTimeline = (function () { + function DrawOrderTimeline(frameCount) { + this.frames = spine.Utils.newFloatArray(frameCount); + this.drawOrders = new Array(frameCount); + } + DrawOrderTimeline.prototype.getPropertyId = function () { + return TimelineType.drawOrder << 24; + }; + DrawOrderTimeline.prototype.getFrameCount = function () { + return this.frames.length; + }; + DrawOrderTimeline.prototype.setFrame = function (frameIndex, time, drawOrder) { + this.frames[frameIndex] = time; + this.drawOrders[frameIndex] = drawOrder; + }; + DrawOrderTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, pose, direction) { + var drawOrder = skeleton.drawOrder; + var slots = skeleton.slots; + if (direction == MixDirection.out && pose == MixPose.setup) { + spine.Utils.arrayCopy(skeleton.slots, 0, skeleton.drawOrder, 0, skeleton.slots.length); + return; + } + var frames = this.frames; + if (time < frames[0]) { + if (pose == MixPose.setup) + spine.Utils.arrayCopy(skeleton.slots, 0, skeleton.drawOrder, 0, skeleton.slots.length); + return; + } + var frame = 0; + if (time >= frames[frames.length - 1]) + frame = frames.length - 1; + else + frame = Animation.binarySearch(frames, time) - 1; + var drawOrderToSetupIndex = this.drawOrders[frame]; + if (drawOrderToSetupIndex == null) + spine.Utils.arrayCopy(slots, 0, drawOrder, 0, slots.length); + else { + for (var i = 0, n = drawOrderToSetupIndex.length; i < n; i++) + drawOrder[i] = slots[drawOrderToSetupIndex[i]]; + } + }; + return DrawOrderTimeline; + }()); + spine.DrawOrderTimeline = DrawOrderTimeline; + var IkConstraintTimeline = (function (_super) { + __extends(IkConstraintTimeline, _super); + function IkConstraintTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * IkConstraintTimeline.ENTRIES); + return _this; + } + IkConstraintTimeline.prototype.getPropertyId = function () { + return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex; + }; + IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, bendDirection) { + frameIndex *= IkConstraintTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + IkConstraintTimeline.MIX] = mix; + this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection; + }; + IkConstraintTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, pose, direction) { + var frames = this.frames; + var constraint = skeleton.ikConstraints[this.ikConstraintIndex]; + if (time < frames[0]) { + switch (pose) { + case MixPose.setup: + constraint.mix = constraint.data.mix; + constraint.bendDirection = constraint.data.bendDirection; + return; + case MixPose.current: + constraint.mix += (constraint.data.mix - constraint.mix) * alpha; + constraint.bendDirection = constraint.data.bendDirection; + } + return; + } + if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) { + if (pose == MixPose.setup) { + constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha; + constraint.bendDirection = direction == MixDirection.out ? constraint.data.bendDirection + : frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION]; + } + else { + constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha; + if (direction == MixDirection["in"]) + constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION]; + } + return; + } + var frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES); + var mix = frames[frame + IkConstraintTimeline.PREV_MIX]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime)); + if (pose == MixPose.setup) { + constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha; + constraint.bendDirection = direction == MixDirection.out ? constraint.data.bendDirection : frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION]; + } + else { + constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha; + if (direction == MixDirection["in"]) + constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION]; + } + }; + IkConstraintTimeline.ENTRIES = 3; + IkConstraintTimeline.PREV_TIME = -3; + IkConstraintTimeline.PREV_MIX = -2; + IkConstraintTimeline.PREV_BEND_DIRECTION = -1; + IkConstraintTimeline.MIX = 1; + IkConstraintTimeline.BEND_DIRECTION = 2; + return IkConstraintTimeline; + }(CurveTimeline)); + spine.IkConstraintTimeline = IkConstraintTimeline; + var TransformConstraintTimeline = (function (_super) { + __extends(TransformConstraintTimeline, _super); + function TransformConstraintTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * TransformConstraintTimeline.ENTRIES); + return _this; + } + TransformConstraintTimeline.prototype.getPropertyId = function () { + return (TimelineType.transformConstraint << 24) + this.transformConstraintIndex; + }; + TransformConstraintTimeline.prototype.setFrame = function (frameIndex, time, rotateMix, translateMix, scaleMix, shearMix) { + frameIndex *= TransformConstraintTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + TransformConstraintTimeline.ROTATE] = rotateMix; + this.frames[frameIndex + TransformConstraintTimeline.TRANSLATE] = translateMix; + this.frames[frameIndex + TransformConstraintTimeline.SCALE] = scaleMix; + this.frames[frameIndex + TransformConstraintTimeline.SHEAR] = shearMix; + }; + TransformConstraintTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, pose, direction) { + var frames = this.frames; + var constraint = skeleton.transformConstraints[this.transformConstraintIndex]; + if (time < frames[0]) { + var data = constraint.data; + switch (pose) { + case MixPose.setup: + constraint.rotateMix = data.rotateMix; + constraint.translateMix = data.translateMix; + constraint.scaleMix = data.scaleMix; + constraint.shearMix = data.shearMix; + return; + case MixPose.current: + constraint.rotateMix += (data.rotateMix - constraint.rotateMix) * alpha; + constraint.translateMix += (data.translateMix - constraint.translateMix) * alpha; + constraint.scaleMix += (data.scaleMix - constraint.scaleMix) * alpha; + constraint.shearMix += (data.shearMix - constraint.shearMix) * alpha; + } + return; + } + var rotate = 0, translate = 0, scale = 0, shear = 0; + if (time >= frames[frames.length - TransformConstraintTimeline.ENTRIES]) { + var i = frames.length; + rotate = frames[i + TransformConstraintTimeline.PREV_ROTATE]; + translate = frames[i + TransformConstraintTimeline.PREV_TRANSLATE]; + scale = frames[i + TransformConstraintTimeline.PREV_SCALE]; + shear = frames[i + TransformConstraintTimeline.PREV_SHEAR]; + } + else { + var frame = Animation.binarySearch(frames, time, TransformConstraintTimeline.ENTRIES); + rotate = frames[frame + TransformConstraintTimeline.PREV_ROTATE]; + translate = frames[frame + TransformConstraintTimeline.PREV_TRANSLATE]; + scale = frames[frame + TransformConstraintTimeline.PREV_SCALE]; + shear = frames[frame + TransformConstraintTimeline.PREV_SHEAR]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame / TransformConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + TransformConstraintTimeline.PREV_TIME] - frameTime)); + rotate += (frames[frame + TransformConstraintTimeline.ROTATE] - rotate) * percent; + translate += (frames[frame + TransformConstraintTimeline.TRANSLATE] - translate) * percent; + scale += (frames[frame + TransformConstraintTimeline.SCALE] - scale) * percent; + shear += (frames[frame + TransformConstraintTimeline.SHEAR] - shear) * percent; + } + if (pose == MixPose.setup) { + var data = constraint.data; + constraint.rotateMix = data.rotateMix + (rotate - data.rotateMix) * alpha; + constraint.translateMix = data.translateMix + (translate - data.translateMix) * alpha; + constraint.scaleMix = data.scaleMix + (scale - data.scaleMix) * alpha; + constraint.shearMix = data.shearMix + (shear - data.shearMix) * alpha; + } + else { + constraint.rotateMix += (rotate - constraint.rotateMix) * alpha; + constraint.translateMix += (translate - constraint.translateMix) * alpha; + constraint.scaleMix += (scale - constraint.scaleMix) * alpha; + constraint.shearMix += (shear - constraint.shearMix) * alpha; + } + }; + TransformConstraintTimeline.ENTRIES = 5; + TransformConstraintTimeline.PREV_TIME = -5; + TransformConstraintTimeline.PREV_ROTATE = -4; + TransformConstraintTimeline.PREV_TRANSLATE = -3; + TransformConstraintTimeline.PREV_SCALE = -2; + TransformConstraintTimeline.PREV_SHEAR = -1; + TransformConstraintTimeline.ROTATE = 1; + TransformConstraintTimeline.TRANSLATE = 2; + TransformConstraintTimeline.SCALE = 3; + TransformConstraintTimeline.SHEAR = 4; + return TransformConstraintTimeline; + }(CurveTimeline)); + spine.TransformConstraintTimeline = TransformConstraintTimeline; + var PathConstraintPositionTimeline = (function (_super) { + __extends(PathConstraintPositionTimeline, _super); + function PathConstraintPositionTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * PathConstraintPositionTimeline.ENTRIES); + return _this; + } + PathConstraintPositionTimeline.prototype.getPropertyId = function () { + return (TimelineType.pathConstraintPosition << 24) + this.pathConstraintIndex; + }; + PathConstraintPositionTimeline.prototype.setFrame = function (frameIndex, time, value) { + frameIndex *= PathConstraintPositionTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + PathConstraintPositionTimeline.VALUE] = value; + }; + PathConstraintPositionTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, pose, direction) { + var frames = this.frames; + var constraint = skeleton.pathConstraints[this.pathConstraintIndex]; + if (time < frames[0]) { + switch (pose) { + case MixPose.setup: + constraint.position = constraint.data.position; + return; + case MixPose.current: + constraint.position += (constraint.data.position - constraint.position) * alpha; + } + return; + } + var position = 0; + if (time >= frames[frames.length - PathConstraintPositionTimeline.ENTRIES]) + position = frames[frames.length + PathConstraintPositionTimeline.PREV_VALUE]; + else { + var frame = Animation.binarySearch(frames, time, PathConstraintPositionTimeline.ENTRIES); + position = frames[frame + PathConstraintPositionTimeline.PREV_VALUE]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame / PathConstraintPositionTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PathConstraintPositionTimeline.PREV_TIME] - frameTime)); + position += (frames[frame + PathConstraintPositionTimeline.VALUE] - position) * percent; + } + if (pose == MixPose.setup) + constraint.position = constraint.data.position + (position - constraint.data.position) * alpha; + else + constraint.position += (position - constraint.position) * alpha; + }; + PathConstraintPositionTimeline.ENTRIES = 2; + PathConstraintPositionTimeline.PREV_TIME = -2; + PathConstraintPositionTimeline.PREV_VALUE = -1; + PathConstraintPositionTimeline.VALUE = 1; + return PathConstraintPositionTimeline; + }(CurveTimeline)); + spine.PathConstraintPositionTimeline = PathConstraintPositionTimeline; + var PathConstraintSpacingTimeline = (function (_super) { + __extends(PathConstraintSpacingTimeline, _super); + function PathConstraintSpacingTimeline(frameCount) { + return _super.call(this, frameCount) || this; + } + PathConstraintSpacingTimeline.prototype.getPropertyId = function () { + return (TimelineType.pathConstraintSpacing << 24) + this.pathConstraintIndex; + }; + PathConstraintSpacingTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, pose, direction) { + var frames = this.frames; + var constraint = skeleton.pathConstraints[this.pathConstraintIndex]; + if (time < frames[0]) { + switch (pose) { + case MixPose.setup: + constraint.spacing = constraint.data.spacing; + return; + case MixPose.current: + constraint.spacing += (constraint.data.spacing - constraint.spacing) * alpha; + } + return; + } + var spacing = 0; + if (time >= frames[frames.length - PathConstraintSpacingTimeline.ENTRIES]) + spacing = frames[frames.length + PathConstraintSpacingTimeline.PREV_VALUE]; + else { + var frame = Animation.binarySearch(frames, time, PathConstraintSpacingTimeline.ENTRIES); + spacing = frames[frame + PathConstraintSpacingTimeline.PREV_VALUE]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame / PathConstraintSpacingTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PathConstraintSpacingTimeline.PREV_TIME] - frameTime)); + spacing += (frames[frame + PathConstraintSpacingTimeline.VALUE] - spacing) * percent; + } + if (pose == MixPose.setup) + constraint.spacing = constraint.data.spacing + (spacing - constraint.data.spacing) * alpha; + else + constraint.spacing += (spacing - constraint.spacing) * alpha; + }; + return PathConstraintSpacingTimeline; + }(PathConstraintPositionTimeline)); + spine.PathConstraintSpacingTimeline = PathConstraintSpacingTimeline; + var PathConstraintMixTimeline = (function (_super) { + __extends(PathConstraintMixTimeline, _super); + function PathConstraintMixTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * PathConstraintMixTimeline.ENTRIES); + return _this; + } + PathConstraintMixTimeline.prototype.getPropertyId = function () { + return (TimelineType.pathConstraintMix << 24) + this.pathConstraintIndex; + }; + PathConstraintMixTimeline.prototype.setFrame = function (frameIndex, time, rotateMix, translateMix) { + frameIndex *= PathConstraintMixTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + PathConstraintMixTimeline.ROTATE] = rotateMix; + this.frames[frameIndex + PathConstraintMixTimeline.TRANSLATE] = translateMix; + }; + PathConstraintMixTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, pose, direction) { + var frames = this.frames; + var constraint = skeleton.pathConstraints[this.pathConstraintIndex]; + if (time < frames[0]) { + switch (pose) { + case MixPose.setup: + constraint.rotateMix = constraint.data.rotateMix; + constraint.translateMix = constraint.data.translateMix; + return; + case MixPose.current: + constraint.rotateMix += (constraint.data.rotateMix - constraint.rotateMix) * alpha; + constraint.translateMix += (constraint.data.translateMix - constraint.translateMix) * alpha; + } + return; + } + var rotate = 0, translate = 0; + if (time >= frames[frames.length - PathConstraintMixTimeline.ENTRIES]) { + rotate = frames[frames.length + PathConstraintMixTimeline.PREV_ROTATE]; + translate = frames[frames.length + PathConstraintMixTimeline.PREV_TRANSLATE]; + } + else { + var frame = Animation.binarySearch(frames, time, PathConstraintMixTimeline.ENTRIES); + rotate = frames[frame + PathConstraintMixTimeline.PREV_ROTATE]; + translate = frames[frame + PathConstraintMixTimeline.PREV_TRANSLATE]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame / PathConstraintMixTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PathConstraintMixTimeline.PREV_TIME] - frameTime)); + rotate += (frames[frame + PathConstraintMixTimeline.ROTATE] - rotate) * percent; + translate += (frames[frame + PathConstraintMixTimeline.TRANSLATE] - translate) * percent; + } + if (pose == MixPose.setup) { + constraint.rotateMix = constraint.data.rotateMix + (rotate - constraint.data.rotateMix) * alpha; + constraint.translateMix = constraint.data.translateMix + (translate - constraint.data.translateMix) * alpha; + } + else { + constraint.rotateMix += (rotate - constraint.rotateMix) * alpha; + constraint.translateMix += (translate - constraint.translateMix) * alpha; + } + }; + PathConstraintMixTimeline.ENTRIES = 3; + PathConstraintMixTimeline.PREV_TIME = -3; + PathConstraintMixTimeline.PREV_ROTATE = -2; + PathConstraintMixTimeline.PREV_TRANSLATE = -1; + PathConstraintMixTimeline.ROTATE = 1; + PathConstraintMixTimeline.TRANSLATE = 2; + return PathConstraintMixTimeline; + }(CurveTimeline)); + spine.PathConstraintMixTimeline = PathConstraintMixTimeline; +})(spine || (spine = {})); +var spine; +(function (spine) { + var AnimationState = (function () { + function AnimationState(data) { + this.tracks = new Array(); + this.events = new Array(); + this.listeners = new Array(); + this.queue = new EventQueue(this); + this.propertyIDs = new spine.IntSet(); + this.mixingTo = new Array(); + this.animationsChanged = false; + this.timeScale = 1; + this.trackEntryPool = new spine.Pool(function () { return new TrackEntry(); }); + this.data = data; + } + AnimationState.prototype.update = function (delta) { + delta *= this.timeScale; + var tracks = this.tracks; + for (var i = 0, n = tracks.length; i < n; i++) { + var current = tracks[i]; + if (current == null) + continue; + current.animationLast = current.nextAnimationLast; + current.trackLast = current.nextTrackLast; + var currentDelta = delta * current.timeScale; + if (current.delay > 0) { + current.delay -= currentDelta; + if (current.delay > 0) + continue; + currentDelta = -current.delay; + current.delay = 0; + } + var next = current.next; + if (next != null) { + var nextTime = current.trackLast - next.delay; + if (nextTime >= 0) { + next.delay = 0; + next.trackTime = nextTime + delta * next.timeScale; + current.trackTime += currentDelta; + this.setCurrent(i, next, true); + while (next.mixingFrom != null) { + next.mixTime += currentDelta; + 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)) { + var from = current.mixingFrom; + current.mixingFrom = null; + while (from != null) { + this.queue.end(from); + from = from.mixingFrom; + } + } + current.trackTime += currentDelta; + } + this.queue.drain(); + }; + AnimationState.prototype.updateMixingFrom = function (to, delta) { + var from = to.mixingFrom; + if (from == null) + return true; + var finished = this.updateMixingFrom(from, delta); + from.animationLast = from.nextAnimationLast; + from.trackLast = from.nextTrackLast; + if (to.mixTime > 0 && (to.mixTime >= to.mixDuration || to.timeScale == 0)) { + if (from.totalAlpha == 0 || to.mixDuration == 0) { + to.mixingFrom = from.mixingFrom; + to.interruptAlpha = from.interruptAlpha; + this.queue.end(from); + } + return finished; + } + from.trackTime += delta * from.timeScale; + to.mixTime += delta * to.timeScale; + return false; + }; + AnimationState.prototype.apply = function (skeleton) { + if (skeleton == null) + throw new Error("skeleton cannot be null."); + if (this.animationsChanged) + this._animationsChanged(); + var events = this.events; + var tracks = this.tracks; + var applied = false; + for (var i = 0, n = tracks.length; i < n; i++) { + var current = tracks[i]; + if (current == null || current.delay > 0) + continue; + applied = true; + var currentPose = i == 0 ? spine.MixPose.current : spine.MixPose.currentLayered; + var mix = current.alpha; + if (current.mixingFrom != null) + mix *= this.applyMixingFrom(current, skeleton, currentPose); + else if (current.trackTime >= current.trackEnd && current.next == null) + mix = 0; + var animationLast = current.animationLast, animationTime = current.getAnimationTime(); + var timelineCount = current.animation.timelines.length; + var timelines = current.animation.timelines; + if (mix == 1) { + for (var ii = 0; ii < timelineCount; ii++) + timelines[ii].apply(skeleton, animationLast, animationTime, events, 1, spine.MixPose.setup, spine.MixDirection["in"]); + } + else { + var timelineData = current.timelineData; + var firstFrame = current.timelinesRotation.length == 0; + if (firstFrame) + spine.Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null); + var timelinesRotation = current.timelinesRotation; + for (var ii = 0; ii < timelineCount; ii++) { + var timeline = timelines[ii]; + var pose = timelineData[ii] >= AnimationState.FIRST ? spine.MixPose.setup : currentPose; + if (timeline instanceof spine.RotateTimeline) { + this.applyRotateTimeline(timeline, skeleton, animationTime, mix, pose, timelinesRotation, ii << 1, firstFrame); + } + else { + spine.Utils.webkit602BugfixHelper(mix, pose); + timeline.apply(skeleton, animationLast, animationTime, events, mix, pose, spine.MixDirection["in"]); + } + } + } + this.queueEvents(current, animationTime); + events.length = 0; + current.nextAnimationLast = animationTime; + current.nextTrackLast = current.trackTime; + } + this.queue.drain(); + return applied; + }; + AnimationState.prototype.applyMixingFrom = function (to, skeleton, currentPose) { + var from = to.mixingFrom; + if (from.mixingFrom != null) + this.applyMixingFrom(from, skeleton, currentPose); + var mix = 0; + if (to.mixDuration == 0) { + mix = 1; + currentPose = spine.MixPose.setup; + } + else { + mix = to.mixTime / to.mixDuration; + if (mix > 1) + mix = 1; + } + var events = mix < from.eventThreshold ? this.events : null; + var attachments = mix < from.attachmentThreshold, drawOrder = mix < from.drawOrderThreshold; + var animationLast = from.animationLast, animationTime = from.getAnimationTime(); + var timelineCount = from.animation.timelines.length; + var timelines = from.animation.timelines; + var timelineData = from.timelineData; + var timelineDipMix = from.timelineDipMix; + var firstFrame = from.timelinesRotation.length == 0; + if (firstFrame) + spine.Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null); + var timelinesRotation = from.timelinesRotation; + var pose; + var alphaDip = from.alpha * to.interruptAlpha, alphaMix = alphaDip * (1 - mix), alpha = 0; + from.totalAlpha = 0; + for (var i = 0; i < timelineCount; i++) { + var timeline = timelines[i]; + switch (timelineData[i]) { + case AnimationState.SUBSEQUENT: + if (!attachments && timeline instanceof spine.AttachmentTimeline) + continue; + if (!drawOrder && timeline instanceof spine.DrawOrderTimeline) + continue; + pose = currentPose; + alpha = alphaMix; + break; + case AnimationState.FIRST: + pose = spine.MixPose.setup; + alpha = alphaMix; + break; + case AnimationState.DIP: + pose = spine.MixPose.setup; + alpha = alphaDip; + break; + default: + pose = spine.MixPose.setup; + alpha = alphaDip; + var dipMix = timelineDipMix[i]; + alpha *= Math.max(0, 1 - dipMix.mixTime / dipMix.mixDuration); + break; + } + from.totalAlpha += alpha; + if (timeline instanceof spine.RotateTimeline) + this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, pose, timelinesRotation, i << 1, firstFrame); + else { + spine.Utils.webkit602BugfixHelper(alpha, pose); + timeline.apply(skeleton, animationLast, animationTime, events, alpha, pose, spine.MixDirection.out); + } + } + if (to.mixDuration > 0) + this.queueEvents(from, animationTime); + this.events.length = 0; + from.nextAnimationLast = animationTime; + from.nextTrackLast = from.trackTime; + return mix; + }; + AnimationState.prototype.applyRotateTimeline = function (timeline, skeleton, time, alpha, pose, timelinesRotation, i, firstFrame) { + if (firstFrame) + timelinesRotation[i] = 0; + if (alpha == 1) { + timeline.apply(skeleton, 0, time, null, 1, pose, spine.MixDirection["in"]); + return; + } + var rotateTimeline = timeline; + var frames = rotateTimeline.frames; + var bone = skeleton.bones[rotateTimeline.boneIndex]; + if (time < frames[0]) { + if (pose == spine.MixPose.setup) + bone.rotation = bone.data.rotation; + return; + } + var r2 = 0; + if (time >= frames[frames.length - spine.RotateTimeline.ENTRIES]) + r2 = bone.data.rotation + frames[frames.length + spine.RotateTimeline.PREV_ROTATION]; + else { + var frame = spine.Animation.binarySearch(frames, time, spine.RotateTimeline.ENTRIES); + var prevRotation = frames[frame + spine.RotateTimeline.PREV_ROTATION]; + var frameTime = frames[frame]; + var percent = rotateTimeline.getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + spine.RotateTimeline.PREV_TIME] - frameTime)); + r2 = frames[frame + spine.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; + } + var r1 = pose == spine.MixPose.setup ? bone.data.rotation : bone.rotation; + var total = 0, diff = r2 - r1; + if (diff == 0) { + total = timelinesRotation[i]; + } + else { + diff -= (16384 - ((16384.499999999996 - diff / 360) | 0)) * 360; + var lastTotal = 0, lastDiff = 0; + if (firstFrame) { + lastTotal = 0; + lastDiff = diff; + } + else { + lastTotal = timelinesRotation[i]; + lastDiff = timelinesRotation[i + 1]; + } + var current = diff > 0, dir = lastTotal >= 0; + if (spine.MathUtils.signum(lastDiff) != spine.MathUtils.signum(diff) && Math.abs(lastDiff) <= 90) { + if (Math.abs(lastTotal) > 180) + lastTotal += 360 * spine.MathUtils.signum(lastTotal); + dir = current; + } + total = diff + lastTotal - lastTotal % 360; + if (dir != current) + total += 360 * spine.MathUtils.signum(lastTotal); + timelinesRotation[i] = total; + } + timelinesRotation[i + 1] = diff; + r1 += total * alpha; + bone.rotation = r1 - (16384 - ((16384.499999999996 - r1 / 360) | 0)) * 360; + }; + AnimationState.prototype.queueEvents = function (entry, animationTime) { + var animationStart = entry.animationStart, animationEnd = entry.animationEnd; + var duration = animationEnd - animationStart; + var trackLastWrapped = entry.trackLast % duration; + var events = this.events; + var i = 0, n = events.length; + for (; i < n; i++) { + var event_1 = events[i]; + if (event_1.time < trackLastWrapped) + break; + if (event_1.time > animationEnd) + continue; + this.queue.event(entry, event_1); + } + 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); + for (; i < n; i++) { + var event_2 = events[i]; + if (event_2.time < animationStart) + continue; + this.queue.event(entry, events[i]); + } + }; + AnimationState.prototype.clearTracks = function () { + 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(); + }; + AnimationState.prototype.clearTrack = function (trackIndex) { + if (trackIndex >= this.tracks.length) + return; + var current = this.tracks[trackIndex]; + if (current == null) + return; + this.queue.end(current); + this.disposeNext(current); + var entry = current; + while (true) { + var from = entry.mixingFrom; + if (from == null) + break; + this.queue.end(from); + entry.mixingFrom = null; + entry = from; + } + this.tracks[current.trackIndex] = null; + this.queue.drain(); + }; + AnimationState.prototype.setCurrent = function (index, current, interrupt) { + var from = this.expandToIndex(index); + this.tracks[index] = current; + if (from != null) { + if (interrupt) + this.queue.interrupt(from); + current.mixingFrom = from; + current.mixTime = 0; + if (from.mixingFrom != null && from.mixDuration > 0) + current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration); + from.timelinesRotation.length = 0; + } + this.queue.start(current); + }; + AnimationState.prototype.setAnimation = function (trackIndex, animationName, loop) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (animation == null) + throw new Error("Animation not found: " + animationName); + return this.setAnimationWith(trackIndex, animation, loop); + }; + AnimationState.prototype.setAnimationWith = function (trackIndex, animation, loop) { + if (animation == null) + throw new Error("animation cannot be null."); + var interrupt = true; + var current = this.expandToIndex(trackIndex); + if (current != null) { + if (current.nextTrackLast == -1) { + 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); + } + var entry = this.trackEntry(trackIndex, animation, loop, current); + this.setCurrent(trackIndex, entry, interrupt); + this.queue.drain(); + return entry; + }; + AnimationState.prototype.addAnimation = function (trackIndex, animationName, loop, delay) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (animation == null) + throw new Error("Animation not found: " + animationName); + return this.addAnimationWith(trackIndex, animation, loop, delay); + }; + AnimationState.prototype.addAnimationWith = function (trackIndex, animation, loop, delay) { + if (animation == null) + throw new Error("animation cannot be null."); + var last = this.expandToIndex(trackIndex); + if (last != null) { + while (last.next != null) + last = last.next; + } + 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) { + var duration = last.animationEnd - last.animationStart; + if (duration != 0) { + if (last.loop) + delay += duration * (1 + ((last.trackTime / duration) | 0)); + else + delay += duration; + delay -= this.data.getMix(last.animation, animation); + } + else + delay = 0; + } + } + entry.delay = delay; + return entry; + }; + AnimationState.prototype.setEmptyAnimation = function (trackIndex, mixDuration) { + var entry = this.setAnimationWith(trackIndex, AnimationState.emptyAnimation, false); + entry.mixDuration = mixDuration; + entry.trackEnd = mixDuration; + return entry; + }; + AnimationState.prototype.addEmptyAnimation = function (trackIndex, mixDuration, delay) { + if (delay <= 0) + delay -= mixDuration; + var entry = this.addAnimationWith(trackIndex, AnimationState.emptyAnimation, false, delay); + entry.mixDuration = mixDuration; + entry.trackEnd = mixDuration; + return entry; + }; + AnimationState.prototype.setEmptyAnimations = function (mixDuration) { + var oldDrainDisabled = this.queue.drainDisabled; + this.queue.drainDisabled = true; + for (var i = 0, n = this.tracks.length; i < n; i++) { + var current = this.tracks[i]; + if (current != null) + this.setEmptyAnimation(current.trackIndex, mixDuration); + } + this.queue.drainDisabled = oldDrainDisabled; + this.queue.drain(); + }; + AnimationState.prototype.expandToIndex = function (index) { + if (index < this.tracks.length) + return this.tracks[index]; + spine.Utils.ensureArrayCapacity(this.tracks, index - this.tracks.length + 1, null); + this.tracks.length = index + 1; + return null; + }; + AnimationState.prototype.trackEntry = function (trackIndex, animation, loop, last) { + var entry = this.trackEntryPool.obtain(); + entry.trackIndex = trackIndex; + entry.animation = animation; + entry.loop = loop; + 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; + }; + AnimationState.prototype.disposeNext = function (entry) { + var next = entry.next; + while (next != null) { + this.queue.dispose(next); + next = next.next; + } + entry.next = null; + }; + AnimationState.prototype._animationsChanged = function () { + this.animationsChanged = false; + var propertyIDs = this.propertyIDs; + propertyIDs.clear(); + var mixingTo = this.mixingTo; + for (var i = 0, n = this.tracks.length; i < n; i++) { + var entry = this.tracks[i]; + if (entry != null) + entry.setTimelineData(null, mixingTo, propertyIDs); + } + }; + AnimationState.prototype.getCurrent = function (trackIndex) { + if (trackIndex >= this.tracks.length) + return null; + return this.tracks[trackIndex]; + }; + AnimationState.prototype.addListener = function (listener) { + if (listener == null) + throw new Error("listener cannot be null."); + this.listeners.push(listener); + }; + AnimationState.prototype.removeListener = function (listener) { + var index = this.listeners.indexOf(listener); + if (index >= 0) + this.listeners.splice(index, 1); + }; + AnimationState.prototype.clearListeners = function () { + this.listeners.length = 0; + }; + AnimationState.prototype.clearListenerNotifications = function () { + this.queue.clear(); + }; + AnimationState.emptyAnimation = new spine.Animation("", [], 0); + AnimationState.SUBSEQUENT = 0; + AnimationState.FIRST = 1; + AnimationState.DIP = 2; + AnimationState.DIP_MIX = 3; + return AnimationState; + }()); + spine.AnimationState = AnimationState; + var TrackEntry = (function () { + function TrackEntry() { + this.timelineData = new Array(); + this.timelineDipMix = new Array(); + this.timelinesRotation = new Array(); + } + TrackEntry.prototype.reset = function () { + this.next = null; + this.mixingFrom = null; + this.animation = null; + this.listener = null; + this.timelineData.length = 0; + this.timelineDipMix.length = 0; + this.timelinesRotation.length = 0; + }; + TrackEntry.prototype.setTimelineData = function (to, mixingToArray, propertyIDs) { + if (to != null) + mixingToArray.push(to); + var lastEntry = this.mixingFrom != null ? this.mixingFrom.setTimelineData(this, mixingToArray, propertyIDs) : this; + if (to != null) + mixingToArray.pop(); + var mixingTo = mixingToArray; + var mixingToLast = mixingToArray.length - 1; + var timelines = this.animation.timelines; + var timelinesCount = this.animation.timelines.length; + var timelineData = spine.Utils.setArraySize(this.timelineData, timelinesCount); + this.timelineDipMix.length = 0; + var timelineDipMix = spine.Utils.setArraySize(this.timelineDipMix, timelinesCount); + outer: for (var i = 0; i < timelinesCount; i++) { + var id = timelines[i].getPropertyId(); + if (!propertyIDs.add(id)) + timelineData[i] = AnimationState.SUBSEQUENT; + else if (to == null || !to.hasTimeline(id)) + timelineData[i] = AnimationState.FIRST; + else { + for (var ii = mixingToLast; ii >= 0; ii--) { + var entry = mixingTo[ii]; + if (!entry.hasTimeline(id)) { + if (entry.mixDuration > 0) { + timelineData[i] = AnimationState.DIP_MIX; + timelineDipMix[i] = entry; + continue outer; + } + } + } + timelineData[i] = AnimationState.DIP; + } + } + return lastEntry; + }; + TrackEntry.prototype.hasTimeline = function (id) { + var timelines = this.animation.timelines; + for (var i = 0, n = timelines.length; i < n; i++) + if (timelines[i].getPropertyId() == id) + return true; + return false; + }; + TrackEntry.prototype.getAnimationTime = function () { + if (this.loop) { + 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); + }; + TrackEntry.prototype.setAnimationLast = function (animationLast) { + this.animationLast = animationLast; + this.nextAnimationLast = animationLast; + }; + TrackEntry.prototype.isComplete = function () { + return this.trackTime >= this.animationEnd - this.animationStart; + }; + TrackEntry.prototype.resetRotationDirections = function () { + this.timelinesRotation.length = 0; + }; + return TrackEntry; + }()); + spine.TrackEntry = TrackEntry; + var EventQueue = (function () { + function EventQueue(animState) { + this.objects = []; + this.drainDisabled = false; + this.animState = animState; + } + EventQueue.prototype.start = function (entry) { + this.objects.push(EventType.start); + this.objects.push(entry); + this.animState.animationsChanged = true; + }; + EventQueue.prototype.interrupt = function (entry) { + this.objects.push(EventType.interrupt); + this.objects.push(entry); + }; + EventQueue.prototype.end = function (entry) { + this.objects.push(EventType.end); + this.objects.push(entry); + this.animState.animationsChanged = true; + }; + EventQueue.prototype.dispose = function (entry) { + this.objects.push(EventType.dispose); + this.objects.push(entry); + }; + EventQueue.prototype.complete = function (entry) { + this.objects.push(EventType.complete); + this.objects.push(entry); + }; + EventQueue.prototype.event = function (entry, event) { + this.objects.push(EventType.event); + this.objects.push(entry); + this.objects.push(event); + }; + EventQueue.prototype.drain = function () { + if (this.drainDisabled) + return; + this.drainDisabled = true; + var objects = this.objects; + var listeners = this.animState.listeners; + for (var i = 0; i < objects.length; i += 2) { + var type = objects[i]; + var entry = 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); + 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: + var event_3 = 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; + }; + EventQueue.prototype.clear = function () { + this.objects.length = 0; + }; + return EventQueue; + }()); + spine.EventQueue = EventQueue; + var EventType; + (function (EventType) { + EventType[EventType["start"] = 0] = "start"; + EventType[EventType["interrupt"] = 1] = "interrupt"; + EventType[EventType["end"] = 2] = "end"; + EventType[EventType["dispose"] = 3] = "dispose"; + EventType[EventType["complete"] = 4] = "complete"; + EventType[EventType["event"] = 5] = "event"; + })(EventType = spine.EventType || (spine.EventType = {})); + var AnimationStateAdapter2 = (function () { + function AnimationStateAdapter2() { + } + AnimationStateAdapter2.prototype.start = function (entry) { + }; + AnimationStateAdapter2.prototype.interrupt = function (entry) { + }; + AnimationStateAdapter2.prototype.end = function (entry) { + }; + AnimationStateAdapter2.prototype.dispose = function (entry) { + }; + AnimationStateAdapter2.prototype.complete = function (entry) { + }; + AnimationStateAdapter2.prototype.event = function (entry, event) { + }; + return AnimationStateAdapter2; + }()); + spine.AnimationStateAdapter2 = AnimationStateAdapter2; +})(spine || (spine = {})); +var spine; +(function (spine) { + var AnimationStateData = (function () { + function AnimationStateData(skeletonData) { + this.animationToMixTime = {}; + this.defaultMix = 0; + if (skeletonData == null) + throw new Error("skeletonData cannot be null."); + this.skeletonData = skeletonData; + } + AnimationStateData.prototype.setMix = function (fromName, toName, duration) { + var from = this.skeletonData.findAnimation(fromName); + if (from == null) + throw new Error("Animation not found: " + fromName); + var to = this.skeletonData.findAnimation(toName); + if (to == null) + throw new Error("Animation not found: " + toName); + this.setMixWith(from, to, duration); + }; + AnimationStateData.prototype.setMixWith = function (from, to, duration) { + if (from == null) + throw new Error("from cannot be null."); + if (to == null) + throw new Error("to cannot be null."); + var key = from.name + "." + to.name; + this.animationToMixTime[key] = duration; + }; + AnimationStateData.prototype.getMix = function (from, to) { + var key = from.name + "." + to.name; + var value = this.animationToMixTime[key]; + return value === undefined ? this.defaultMix : value; + }; + return AnimationStateData; + }()); + spine.AnimationStateData = AnimationStateData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var AssetManager = (function () { + function AssetManager(textureLoader, pathPrefix) { + if (pathPrefix === void 0) { pathPrefix = ""; } + this.assets = {}; + this.errors = {}; + this.toLoad = 0; + this.loaded = 0; + this.textureLoader = textureLoader; + this.pathPrefix = pathPrefix; + } + AssetManager.downloadText = function (url, success, error) { + var request = new XMLHttpRequest(); + request.open("GET", url, true); + request.onload = function () { + if (request.status == 200) { + success(request.responseText); + } + else { + error(request.status, request.responseText); + } + }; + request.onerror = function () { + error(request.status, request.responseText); + }; + request.send(); + }; + AssetManager.downloadBinary = function (url, success, error) { + var request = new XMLHttpRequest(); + request.open("GET", url, true); + request.responseType = "arraybuffer"; + request.onload = function () { + if (request.status == 200) { + success(new Uint8Array(request.response)); + } + else { + error(request.status, request.responseText); + } + }; + request.onerror = function () { + error(request.status, request.responseText); + }; + request.send(); + }; + AssetManager.prototype.loadText = function (path, success, error) { + var _this = this; + if (success === void 0) { success = null; } + if (error === void 0) { error = null; } + path = this.pathPrefix + path; + this.toLoad++; + AssetManager.downloadText(path, function (data) { + _this.assets[path] = data; + if (success) + success(path, data); + _this.toLoad--; + _this.loaded++; + }, function (state, responseText) { + _this.errors[path] = "Couldn't load text " + path + ": status " + status + ", " + responseText; + if (error) + error(path, "Couldn't load text " + path + ": status " + status + ", " + responseText); + _this.toLoad--; + _this.loaded++; + }); + }; + AssetManager.prototype.loadTexture = function (path, success, error) { + var _this = this; + if (success === void 0) { success = null; } + if (error === void 0) { error = null; } + path = this.pathPrefix + path; + this.toLoad++; + var img = new Image(); + img.crossOrigin = "anonymous"; + img.onload = function (ev) { + var texture = _this.textureLoader(img); + _this.assets[path] = texture; + _this.toLoad--; + _this.loaded++; + if (success) + success(path, img); + }; + img.onerror = function (ev) { + _this.errors[path] = "Couldn't load image " + path; + _this.toLoad--; + _this.loaded++; + if (error) + error(path, "Couldn't load image " + path); + }; + img.src = path; + }; + AssetManager.prototype.loadTextureData = function (path, data, success, error) { + var _this = this; + if (success === void 0) { success = null; } + if (error === void 0) { error = null; } + path = this.pathPrefix + path; + this.toLoad++; + var img = new Image(); + img.onload = function (ev) { + var texture = _this.textureLoader(img); + _this.assets[path] = texture; + _this.toLoad--; + _this.loaded++; + if (success) + success(path, img); + }; + img.onerror = function (ev) { + _this.errors[path] = "Couldn't load image " + path; + _this.toLoad--; + _this.loaded++; + if (error) + error(path, "Couldn't load image " + path); + }; + img.src = data; + }; + AssetManager.prototype.loadTextureAtlas = function (path, success, error) { + var _this = this; + if (success === void 0) { success = null; } + if (error === void 0) { error = null; } + var parent = path.lastIndexOf("/") >= 0 ? path.substring(0, path.lastIndexOf("/")) : ""; + path = this.pathPrefix + path; + this.toLoad++; + AssetManager.downloadText(path, function (atlasData) { + var pagesLoaded = { count: 0 }; + var atlasPages = new Array(); + try { + var atlas = new spine.TextureAtlas(atlasData, function (path) { + atlasPages.push(parent + "/" + path); + var image = document.createElement("img"); + image.width = 16; + image.height = 16; + return new spine.FakeTexture(image); + }); + } + catch (e) { + var ex = e; + _this.errors[path] = "Couldn't load texture atlas " + path + ": " + ex.message; + if (error) + error(path, "Couldn't load texture atlas " + path + ": " + ex.message); + _this.toLoad--; + _this.loaded++; + return; + } + var _loop_1 = function (atlasPage) { + var pageLoadError = false; + _this.loadTexture(atlasPage, function (imagePath, image) { + pagesLoaded.count++; + if (pagesLoaded.count == atlasPages.length) { + if (!pageLoadError) { + try { + var atlas = new spine.TextureAtlas(atlasData, function (path) { + return _this.get(parent + "/" + path); + }); + _this.assets[path] = atlas; + if (success) + success(path, atlas); + _this.toLoad--; + _this.loaded++; + } + catch (e) { + var ex = e; + _this.errors[path] = "Couldn't load texture atlas " + path + ": " + ex.message; + if (error) + error(path, "Couldn't load texture atlas " + path + ": " + ex.message); + _this.toLoad--; + _this.loaded++; + } + } + else { + _this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path; + if (error) + error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path); + _this.toLoad--; + _this.loaded++; + } + } + }, function (imagePath, errorMessage) { + pageLoadError = true; + pagesLoaded.count++; + if (pagesLoaded.count == atlasPages.length) { + _this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path; + if (error) + error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path); + _this.toLoad--; + _this.loaded++; + } + }); + }; + for (var _i = 0, atlasPages_1 = atlasPages; _i < atlasPages_1.length; _i++) { + var atlasPage = atlasPages_1[_i]; + _loop_1(atlasPage); + } + }, function (state, responseText) { + _this.errors[path] = "Couldn't load texture atlas " + path + ": status " + status + ", " + responseText; + if (error) + error(path, "Couldn't load texture atlas " + path + ": status " + status + ", " + responseText); + _this.toLoad--; + _this.loaded++; + }); + }; + AssetManager.prototype.get = function (path) { + path = this.pathPrefix + path; + return this.assets[path]; + }; + AssetManager.prototype.remove = function (path) { + path = this.pathPrefix + path; + var asset = this.assets[path]; + if (asset.dispose) + asset.dispose(); + this.assets[path] = null; + }; + AssetManager.prototype.removeAll = function () { + for (var key in this.assets) { + var asset = this.assets[key]; + if (asset.dispose) + asset.dispose(); + } + this.assets = {}; + }; + AssetManager.prototype.isLoadingComplete = function () { + return this.toLoad == 0; + }; + AssetManager.prototype.getToLoad = function () { + return this.toLoad; + }; + AssetManager.prototype.getLoaded = function () { + return this.loaded; + }; + AssetManager.prototype.dispose = function () { + this.removeAll(); + }; + AssetManager.prototype.hasErrors = function () { + return Object.keys(this.errors).length > 0; + }; + AssetManager.prototype.getErrors = function () { + return this.errors; + }; + return AssetManager; + }()); + spine.AssetManager = AssetManager; +})(spine || (spine = {})); +var spine; +(function (spine) { + var AtlasAttachmentLoader = (function () { + function AtlasAttachmentLoader(atlas) { + this.atlas = atlas; + } + AtlasAttachmentLoader.prototype.newRegionAttachment = function (skin, name, path) { + var region = this.atlas.findRegion(path); + if (region == null) + throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")"); + region.renderObject = region; + var attachment = new spine.RegionAttachment(name); + attachment.setRegion(region); + return attachment; + }; + AtlasAttachmentLoader.prototype.newMeshAttachment = function (skin, name, path) { + var region = this.atlas.findRegion(path); + if (region == null) + throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); + region.renderObject = region; + var attachment = new spine.MeshAttachment(name); + attachment.region = region; + return attachment; + }; + AtlasAttachmentLoader.prototype.newBoundingBoxAttachment = function (skin, name) { + return new spine.BoundingBoxAttachment(name); + }; + AtlasAttachmentLoader.prototype.newPathAttachment = function (skin, name) { + return new spine.PathAttachment(name); + }; + AtlasAttachmentLoader.prototype.newPointAttachment = function (skin, name) { + return new spine.PointAttachment(name); + }; + AtlasAttachmentLoader.prototype.newClippingAttachment = function (skin, name) { + return new spine.ClippingAttachment(name); + }; + return AtlasAttachmentLoader; + }()); + spine.AtlasAttachmentLoader = AtlasAttachmentLoader; +})(spine || (spine = {})); +var spine; +(function (spine) { + var BlendMode; + (function (BlendMode) { + BlendMode[BlendMode["Normal"] = 0] = "Normal"; + BlendMode[BlendMode["Additive"] = 1] = "Additive"; + BlendMode[BlendMode["Multiply"] = 2] = "Multiply"; + BlendMode[BlendMode["Screen"] = 3] = "Screen"; + })(BlendMode = spine.BlendMode || (spine.BlendMode = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var Bone = (function () { + function Bone(data, skeleton, parent) { + this.children = new Array(); + this.x = 0; + this.y = 0; + this.rotation = 0; + this.scaleX = 0; + this.scaleY = 0; + this.shearX = 0; + this.shearY = 0; + this.ax = 0; + this.ay = 0; + this.arotation = 0; + this.ascaleX = 0; + this.ascaleY = 0; + this.ashearX = 0; + this.ashearY = 0; + this.appliedValid = false; + this.a = 0; + this.b = 0; + this.worldX = 0; + this.c = 0; + this.d = 0; + this.worldY = 0; + this.sorted = false; + if (data == null) + throw new Error("data cannot be null."); + if (skeleton == null) + throw new Error("skeleton cannot be null."); + this.data = data; + this.skeleton = skeleton; + this.parent = parent; + this.setToSetupPose(); + } + Bone.prototype.update = function () { + this.updateWorldTransformWith(this.x, this.y, this.rotation, this.scaleX, this.scaleY, this.shearX, this.shearY); + }; + Bone.prototype.updateWorldTransform = function () { + this.updateWorldTransformWith(this.x, this.y, this.rotation, this.scaleX, this.scaleY, this.shearX, this.shearY); + }; + Bone.prototype.updateWorldTransformWith = function (x, y, rotation, scaleX, scaleY, shearX, shearY) { + this.ax = x; + this.ay = y; + this.arotation = rotation; + this.ascaleX = scaleX; + this.ascaleY = scaleY; + this.ashearX = shearX; + this.ashearY = shearY; + this.appliedValid = true; + var parent = this.parent; + if (parent == null) { + var rotationY = rotation + 90 + shearY; + var la = spine.MathUtils.cosDeg(rotation + shearX) * scaleX; + var lb = spine.MathUtils.cosDeg(rotationY) * scaleY; + var lc = spine.MathUtils.sinDeg(rotation + shearX) * scaleX; + var ld = spine.MathUtils.sinDeg(rotationY) * scaleY; + var skeleton = this.skeleton; + if (skeleton.flipX) { + x = -x; + la = -la; + lb = -lb; + } + if (skeleton.flipY) { + y = -y; + lc = -lc; + ld = -ld; + } + this.a = la; + this.b = lb; + this.c = lc; + this.d = ld; + this.worldX = x + skeleton.x; + this.worldY = y + skeleton.y; + return; + } + var pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + this.worldX = pa * x + pb * y + parent.worldX; + this.worldY = pc * x + pd * y + parent.worldY; + switch (this.data.transformMode) { + case spine.TransformMode.Normal: { + var rotationY = rotation + 90 + shearY; + var la = spine.MathUtils.cosDeg(rotation + shearX) * scaleX; + var lb = spine.MathUtils.cosDeg(rotationY) * scaleY; + var lc = spine.MathUtils.sinDeg(rotation + shearX) * scaleX; + var ld = spine.MathUtils.sinDeg(rotationY) * scaleY; + this.a = pa * la + pb * lc; + this.b = pa * lb + pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + return; + } + case spine.TransformMode.OnlyTranslation: { + var rotationY = rotation + 90 + shearY; + this.a = spine.MathUtils.cosDeg(rotation + shearX) * scaleX; + this.b = spine.MathUtils.cosDeg(rotationY) * scaleY; + this.c = spine.MathUtils.sinDeg(rotation + shearX) * scaleX; + this.d = spine.MathUtils.sinDeg(rotationY) * scaleY; + break; + } + case spine.TransformMode.NoRotationOrReflection: { + var s = pa * pa + pc * pc; + var prx = 0; + if (s > 0.0001) { + s = Math.abs(pa * pd - pb * pc) / s; + pb = pc * s; + pd = pa * s; + prx = Math.atan2(pc, pa) * spine.MathUtils.radDeg; + } + else { + pa = 0; + pc = 0; + prx = 90 - Math.atan2(pd, pb) * spine.MathUtils.radDeg; + } + var rx = rotation + shearX - prx; + var ry = rotation + shearY - prx + 90; + var la = spine.MathUtils.cosDeg(rx) * scaleX; + var lb = spine.MathUtils.cosDeg(ry) * scaleY; + var lc = spine.MathUtils.sinDeg(rx) * scaleX; + var ld = spine.MathUtils.sinDeg(ry) * scaleY; + this.a = pa * la - pb * lc; + this.b = pa * lb - pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + break; + } + case spine.TransformMode.NoScale: + case spine.TransformMode.NoScaleOrReflection: { + var cos = spine.MathUtils.cosDeg(rotation); + var sin = spine.MathUtils.sinDeg(rotation); + var za = pa * cos + pb * sin; + var zc = pc * cos + pd * sin; + var s = Math.sqrt(za * za + zc * zc); + if (s > 0.00001) + s = 1 / s; + za *= s; + zc *= s; + s = Math.sqrt(za * za + zc * zc); + var r = Math.PI / 2 + Math.atan2(zc, za); + var zb = Math.cos(r) * s; + var zd = Math.sin(r) * s; + var la = spine.MathUtils.cosDeg(shearX) * scaleX; + var lb = spine.MathUtils.cosDeg(90 + shearY) * scaleY; + var lc = spine.MathUtils.sinDeg(shearX) * scaleX; + var ld = spine.MathUtils.sinDeg(90 + shearY) * scaleY; + if (this.data.transformMode != spine.TransformMode.NoScaleOrReflection ? pa * pd - pb * pc < 0 : this.skeleton.flipX != this.skeleton.flipY) { + zb = -zb; + zd = -zd; + } + this.a = za * la + zb * lc; + this.b = za * lb + zb * ld; + this.c = zc * la + zd * lc; + this.d = zc * lb + zd * ld; + return; + } + } + if (this.skeleton.flipX) { + this.a = -this.a; + this.b = -this.b; + } + if (this.skeleton.flipY) { + this.c = -this.c; + this.d = -this.d; + } + }; + Bone.prototype.setToSetupPose = function () { + var data = this.data; + this.x = data.x; + this.y = data.y; + this.rotation = data.rotation; + this.scaleX = data.scaleX; + this.scaleY = data.scaleY; + this.shearX = data.shearX; + this.shearY = data.shearY; + }; + Bone.prototype.getWorldRotationX = function () { + return Math.atan2(this.c, this.a) * spine.MathUtils.radDeg; + }; + Bone.prototype.getWorldRotationY = function () { + return Math.atan2(this.d, this.b) * spine.MathUtils.radDeg; + }; + Bone.prototype.getWorldScaleX = function () { + return Math.sqrt(this.a * this.a + this.c * this.c); + }; + Bone.prototype.getWorldScaleY = function () { + return Math.sqrt(this.b * this.b + this.d * this.d); + }; + Bone.prototype.updateAppliedTransform = function () { + this.appliedValid = true; + var parent = this.parent; + if (parent == null) { + this.ax = this.worldX; + this.ay = this.worldY; + this.arotation = Math.atan2(this.c, this.a) * spine.MathUtils.radDeg; + this.ascaleX = Math.sqrt(this.a * this.a + this.c * this.c); + this.ascaleY = Math.sqrt(this.b * this.b + this.d * this.d); + this.ashearX = 0; + this.ashearY = Math.atan2(this.a * this.b + this.c * this.d, this.a * this.d - this.b * this.c) * spine.MathUtils.radDeg; + return; + } + var pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + var pid = 1 / (pa * pd - pb * pc); + var dx = this.worldX - parent.worldX, dy = this.worldY - parent.worldY; + this.ax = (dx * pd * pid - dy * pb * pid); + this.ay = (dy * pa * pid - dx * pc * pid); + var ia = pid * pd; + var id = pid * pa; + var ib = pid * pb; + var ic = pid * pc; + var ra = ia * this.a - ib * this.c; + var rb = ia * this.b - ib * this.d; + var rc = id * this.c - ic * this.a; + var rd = id * this.d - ic * this.b; + this.ashearX = 0; + this.ascaleX = Math.sqrt(ra * ra + rc * rc); + if (this.ascaleX > 0.0001) { + var det = ra * rd - rb * rc; + this.ascaleY = det / this.ascaleX; + this.ashearY = Math.atan2(ra * rb + rc * rd, det) * spine.MathUtils.radDeg; + this.arotation = Math.atan2(rc, ra) * spine.MathUtils.radDeg; + } + else { + this.ascaleX = 0; + this.ascaleY = Math.sqrt(rb * rb + rd * rd); + this.ashearY = 0; + this.arotation = 90 - Math.atan2(rd, rb) * spine.MathUtils.radDeg; + } + }; + Bone.prototype.worldToLocal = function (world) { + var a = this.a, b = this.b, c = this.c, d = this.d; + var invDet = 1 / (a * d - b * c); + var x = world.x - this.worldX, y = world.y - this.worldY; + world.x = (x * d * invDet - y * b * invDet); + world.y = (y * a * invDet - x * c * invDet); + return world; + }; + Bone.prototype.localToWorld = function (local) { + var x = local.x, y = local.y; + local.x = x * this.a + y * this.b + this.worldX; + local.y = x * this.c + y * this.d + this.worldY; + return local; + }; + Bone.prototype.worldToLocalRotation = function (worldRotation) { + var sin = spine.MathUtils.sinDeg(worldRotation), cos = spine.MathUtils.cosDeg(worldRotation); + return Math.atan2(this.a * sin - this.c * cos, this.d * cos - this.b * sin) * spine.MathUtils.radDeg; + }; + Bone.prototype.localToWorldRotation = function (localRotation) { + var sin = spine.MathUtils.sinDeg(localRotation), cos = spine.MathUtils.cosDeg(localRotation); + return Math.atan2(cos * this.c + sin * this.d, cos * this.a + sin * this.b) * spine.MathUtils.radDeg; + }; + Bone.prototype.rotateWorld = function (degrees) { + var a = this.a, b = this.b, c = this.c, d = this.d; + var cos = spine.MathUtils.cosDeg(degrees), sin = spine.MathUtils.sinDeg(degrees); + this.a = cos * a - sin * c; + this.b = cos * b - sin * d; + this.c = sin * a + cos * c; + this.d = sin * b + cos * d; + this.appliedValid = false; + }; + return Bone; + }()); + spine.Bone = Bone; +})(spine || (spine = {})); +var spine; +(function (spine) { + var BoneData = (function () { + function BoneData(index, name, parent) { + this.x = 0; + this.y = 0; + this.rotation = 0; + this.scaleX = 1; + this.scaleY = 1; + this.shearX = 0; + this.shearY = 0; + this.transformMode = TransformMode.Normal; + if (index < 0) + throw new Error("index must be >= 0."); + if (name == null) + throw new Error("name cannot be null."); + this.index = index; + this.name = name; + this.parent = parent; + } + return BoneData; + }()); + spine.BoneData = BoneData; + var TransformMode; + (function (TransformMode) { + TransformMode[TransformMode["Normal"] = 0] = "Normal"; + TransformMode[TransformMode["OnlyTranslation"] = 1] = "OnlyTranslation"; + TransformMode[TransformMode["NoRotationOrReflection"] = 2] = "NoRotationOrReflection"; + TransformMode[TransformMode["NoScale"] = 3] = "NoScale"; + TransformMode[TransformMode["NoScaleOrReflection"] = 4] = "NoScaleOrReflection"; + })(TransformMode = spine.TransformMode || (spine.TransformMode = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var Event = (function () { + function Event(time, data) { + if (data == null) + throw new Error("data cannot be null."); + this.time = time; + this.data = data; + } + return Event; + }()); + spine.Event = Event; +})(spine || (spine = {})); +var spine; +(function (spine) { + var EventData = (function () { + function EventData(name) { + this.name = name; + } + return EventData; + }()); + spine.EventData = EventData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var IkConstraint = (function () { + function IkConstraint(data, skeleton) { + this.mix = 1; + this.bendDirection = 0; + if (data == null) + throw new Error("data cannot be null."); + if (skeleton == null) + throw new Error("skeleton cannot be null."); + this.data = data; + this.mix = data.mix; + this.bendDirection = data.bendDirection; + this.bones = new Array(); + for (var i = 0; i < data.bones.length; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findBone(data.target.name); + } + IkConstraint.prototype.getOrder = function () { + return this.data.order; + }; + IkConstraint.prototype.apply = function () { + this.update(); + }; + IkConstraint.prototype.update = function () { + var target = this.target; + var bones = this.bones; + switch (bones.length) { + case 1: + this.apply1(bones[0], target.worldX, target.worldY, this.mix); + break; + case 2: + this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.mix); + break; + } + }; + IkConstraint.prototype.apply1 = function (bone, targetX, targetY, alpha) { + if (!bone.appliedValid) + bone.updateAppliedTransform(); + var p = bone.parent; + var id = 1 / (p.a * p.d - p.b * p.c); + var x = targetX - p.worldX, y = targetY - p.worldY; + var tx = (x * p.d - y * p.b) * id - bone.ax, ty = (y * p.a - x * p.c) * id - bone.ay; + var rotationIK = Math.atan2(ty, tx) * spine.MathUtils.radDeg - bone.ashearX - bone.arotation; + if (bone.ascaleX < 0) + rotationIK += 180; + if (rotationIK > 180) + rotationIK -= 360; + else if (rotationIK < -180) + rotationIK += 360; + bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, bone.ascaleX, bone.ascaleY, bone.ashearX, bone.ashearY); + }; + IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, alpha) { + if (alpha == 0) { + child.updateWorldTransform(); + return; + } + if (!parent.appliedValid) + parent.updateAppliedTransform(); + if (!child.appliedValid) + child.updateAppliedTransform(); + var px = parent.ax, py = parent.ay, psx = parent.ascaleX, psy = parent.ascaleY, csx = child.ascaleX; + var os1 = 0, os2 = 0, s2 = 0; + if (psx < 0) { + psx = -psx; + os1 = 180; + s2 = -1; + } + else { + os1 = 0; + s2 = 1; + } + if (psy < 0) { + psy = -psy; + s2 = -s2; + } + if (csx < 0) { + csx = -csx; + os2 = 180; + } + else + os2 = 0; + var cx = child.ax, cy = 0, cwx = 0, cwy = 0, a = parent.a, b = parent.b, c = parent.c, d = parent.d; + var u = Math.abs(psx - psy) <= 0.0001; + if (!u) { + cy = 0; + cwx = a * cx + parent.worldX; + cwy = c * cx + parent.worldY; + } + else { + cy = child.ay; + cwx = a * cx + b * cy + parent.worldX; + cwy = c * cx + d * cy + parent.worldY; + } + var pp = parent.parent; + a = pp.a; + b = pp.b; + c = pp.c; + d = pp.d; + var id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY; + var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py; + x = cwx - pp.worldX; + y = cwy - pp.worldY; + var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; + var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1 = 0, a2 = 0; + outer: if (u) { + l2 *= psx; + var cos = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2); + if (cos < -1) + cos = -1; + else if (cos > 1) + cos = 1; + a2 = Math.acos(cos) * bendDir; + a = l1 + l2 * cos; + b = l2 * Math.sin(a2); + a1 = Math.atan2(ty * a - tx * b, tx * a + ty * b); + } + else { + a = psx * l2; + b = psy * l2; + var aa = a * a, bb = b * b, dd = tx * tx + ty * ty, ta = Math.atan2(ty, tx); + c = bb * l1 * l1 + aa * dd - aa * bb; + var c1 = -2 * bb * l1, c2 = bb - aa; + d = c1 * c1 - 4 * c2 * c; + if (d >= 0) { + var q = Math.sqrt(d); + if (c1 < 0) + q = -q; + q = -(c1 + q) / 2; + var r0 = q / c2, r1 = c / q; + var r = Math.abs(r0) < Math.abs(r1) ? r0 : r1; + if (r * r <= dd) { + y = Math.sqrt(dd - r * r) * bendDir; + a1 = ta - Math.atan2(y, r); + a2 = Math.atan2(y / psy, (r - l1) / psx); + break outer; + } + } + var minAngle = spine.MathUtils.PI, minX = l1 - a, minDist = minX * minX, minY = 0; + var maxAngle = 0, maxX = l1 + a, maxDist = maxX * maxX, maxY = 0; + c = -a * l1 / (aa - bb); + if (c >= -1 && c <= 1) { + c = Math.acos(c); + x = a * Math.cos(c) + l1; + y = b * Math.sin(c); + d = x * x + y * y; + if (d < minDist) { + minAngle = c; + minDist = d; + minX = x; + minY = y; + } + if (d > maxDist) { + maxAngle = c; + maxDist = d; + maxX = x; + maxY = y; + } + } + if (dd <= (minDist + maxDist) / 2) { + a1 = ta - Math.atan2(minY * bendDir, minX); + a2 = minAngle * bendDir; + } + else { + a1 = ta - Math.atan2(maxY * bendDir, maxX); + a2 = maxAngle * bendDir; + } + } + var os = Math.atan2(cy, cx) * s2; + var rotation = parent.arotation; + a1 = (a1 - os) * spine.MathUtils.radDeg + os1 - rotation; + if (a1 > 180) + a1 -= 360; + else if (a1 < -180) + a1 += 360; + parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, parent.ascaleX, parent.ascaleY, 0, 0); + rotation = child.arotation; + a2 = ((a2 + os) * spine.MathUtils.radDeg - child.ashearX) * s2 + os2 - rotation; + if (a2 > 180) + a2 -= 360; + else if (a2 < -180) + a2 += 360; + child.updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY); + }; + return IkConstraint; + }()); + spine.IkConstraint = IkConstraint; +})(spine || (spine = {})); +var spine; +(function (spine) { + var IkConstraintData = (function () { + function IkConstraintData(name) { + this.order = 0; + this.bones = new Array(); + this.bendDirection = 1; + this.mix = 1; + this.name = name; + } + return IkConstraintData; + }()); + spine.IkConstraintData = IkConstraintData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var PathConstraint = (function () { + function PathConstraint(data, skeleton) { + this.position = 0; + this.spacing = 0; + this.rotateMix = 0; + this.translateMix = 0; + this.spaces = new Array(); + this.positions = new Array(); + this.world = new Array(); + this.curves = new Array(); + this.lengths = new Array(); + this.segments = new Array(); + if (data == null) + throw new Error("data cannot be null."); + if (skeleton == null) + throw new Error("skeleton cannot be null."); + this.data = data; + this.bones = new Array(); + for (var i = 0, n = data.bones.length; i < n; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findSlot(data.target.name); + this.position = data.position; + this.spacing = data.spacing; + this.rotateMix = data.rotateMix; + this.translateMix = data.translateMix; + } + PathConstraint.prototype.apply = function () { + this.update(); + }; + PathConstraint.prototype.update = function () { + var attachment = this.target.getAttachment(); + if (!(attachment instanceof spine.PathAttachment)) + return; + var rotateMix = this.rotateMix, translateMix = this.translateMix; + var translate = translateMix > 0, rotate = rotateMix > 0; + if (!translate && !rotate) + return; + var data = this.data; + var spacingMode = data.spacingMode; + var lengthSpacing = spacingMode == spine.SpacingMode.Length; + var rotateMode = data.rotateMode; + var tangents = rotateMode == spine.RotateMode.Tangent, scale = rotateMode == spine.RotateMode.ChainScale; + var boneCount = this.bones.length, spacesCount = tangents ? boneCount : boneCount + 1; + var bones = this.bones; + var spaces = spine.Utils.setArraySize(this.spaces, spacesCount), lengths = null; + var spacing = this.spacing; + if (scale || lengthSpacing) { + if (scale) + lengths = spine.Utils.setArraySize(this.lengths, boneCount); + for (var i = 0, n = spacesCount - 1; i < n;) { + var bone = bones[i]; + var setupLength = bone.data.length; + if (setupLength < PathConstraint.epsilon) { + if (scale) + lengths[i] = 0; + spaces[++i] = 0; + } + else { + var x = setupLength * bone.a, y = setupLength * bone.c; + var length_1 = Math.sqrt(x * x + y * y); + if (scale) + lengths[i] = length_1; + spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length_1 / setupLength; + } + } + } + else { + for (var i = 1; i < spacesCount; i++) + spaces[i] = spacing; + } + var positions = this.computeWorldPositions(attachment, spacesCount, tangents, data.positionMode == spine.PositionMode.Percent, spacingMode == spine.SpacingMode.Percent); + var boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation; + var tip = false; + if (offsetRotation == 0) + tip = rotateMode == spine.RotateMode.Chain; + else { + tip = false; + var p = this.target.bone; + offsetRotation *= p.a * p.d - p.b * p.c > 0 ? spine.MathUtils.degRad : -spine.MathUtils.degRad; + } + for (var i = 0, p = 3; i < boneCount; i++, p += 3) { + var bone = bones[i]; + bone.worldX += (boneX - bone.worldX) * translateMix; + bone.worldY += (boneY - bone.worldY) * translateMix; + var x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY; + if (scale) { + var length_2 = lengths[i]; + if (length_2 != 0) { + var s = (Math.sqrt(dx * dx + dy * dy) / length_2 - 1) * rotateMix + 1; + bone.a *= s; + bone.c *= s; + } + } + boneX = x; + boneY = y; + if (rotate) { + var a = bone.a, b = bone.b, c = bone.c, d = bone.d, r = 0, cos = 0, sin = 0; + if (tangents) + r = positions[p - 1]; + else if (spaces[i + 1] == 0) + r = positions[p + 2]; + else + r = Math.atan2(dy, dx); + r -= Math.atan2(c, a); + if (tip) { + cos = Math.cos(r); + sin = Math.sin(r); + var length_3 = bone.data.length; + boneX += (length_3 * (cos * a - sin * c) - dx) * rotateMix; + boneY += (length_3 * (sin * a + cos * c) - dy) * rotateMix; + } + else { + r += offsetRotation; + } + if (r > spine.MathUtils.PI) + r -= spine.MathUtils.PI2; + else if (r < -spine.MathUtils.PI) + r += spine.MathUtils.PI2; + r *= rotateMix; + cos = Math.cos(r); + sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + bone.appliedValid = false; + } + }; + PathConstraint.prototype.computeWorldPositions = function (path, spacesCount, tangents, percentPosition, percentSpacing) { + var target = this.target; + var position = this.position; + var spaces = this.spaces, out = spine.Utils.setArraySize(this.positions, spacesCount * 3 + 2), world = null; + var closed = path.closed; + var verticesLength = path.worldVerticesLength, curveCount = verticesLength / 6, prevCurve = PathConstraint.NONE; + if (!path.constantSpeed) { + var lengths = path.lengths; + curveCount -= closed ? 1 : 2; + var pathLength_1 = lengths[curveCount]; + if (percentPosition) + position *= pathLength_1; + if (percentSpacing) { + for (var i = 0; i < spacesCount; i++) + spaces[i] *= pathLength_1; + } + world = spine.Utils.setArraySize(this.world, 8); + for (var i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { + var space = spaces[i]; + position += space; + var p = position; + if (closed) { + p %= pathLength_1; + if (p < 0) + p += pathLength_1; + curve = 0; + } + else if (p < 0) { + if (prevCurve != PathConstraint.BEFORE) { + prevCurve = PathConstraint.BEFORE; + path.computeWorldVertices(target, 2, 4, world, 0, 2); + } + this.addBeforePosition(p, world, 0, out, o); + continue; + } + else if (p > pathLength_1) { + if (prevCurve != PathConstraint.AFTER) { + prevCurve = PathConstraint.AFTER; + path.computeWorldVertices(target, verticesLength - 6, 4, world, 0, 2); + } + this.addAfterPosition(p - pathLength_1, world, 0, out, o); + continue; + } + for (;; curve++) { + var length_4 = lengths[curve]; + if (p > length_4) + continue; + if (curve == 0) + p /= length_4; + else { + var prev = lengths[curve - 1]; + p = (p - prev) / (length_4 - prev); + } + break; + } + if (curve != prevCurve) { + prevCurve = curve; + if (closed && curve == curveCount) { + path.computeWorldVertices(target, verticesLength - 4, 4, world, 0, 2); + path.computeWorldVertices(target, 0, 4, world, 4, 2); + } + else + path.computeWorldVertices(target, curve * 6 + 2, 8, world, 0, 2); + } + this.addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], out, o, tangents || (i > 0 && space == 0)); + } + return out; + } + if (closed) { + verticesLength += 2; + world = spine.Utils.setArraySize(this.world, verticesLength); + path.computeWorldVertices(target, 2, verticesLength - 4, world, 0, 2); + path.computeWorldVertices(target, 0, 2, world, verticesLength - 4, 2); + world[verticesLength - 2] = world[0]; + world[verticesLength - 1] = world[1]; + } + else { + curveCount--; + verticesLength -= 4; + world = spine.Utils.setArraySize(this.world, verticesLength); + path.computeWorldVertices(target, 2, verticesLength, world, 0, 2); + } + var curves = spine.Utils.setArraySize(this.curves, curveCount); + var pathLength = 0; + var x1 = world[0], y1 = world[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0; + var tmpx = 0, tmpy = 0, dddfx = 0, dddfy = 0, ddfx = 0, ddfy = 0, dfx = 0, dfy = 0; + for (var i = 0, w = 2; i < curveCount; i++, w += 6) { + cx1 = world[w]; + cy1 = world[w + 1]; + cx2 = world[w + 2]; + cy2 = world[w + 3]; + x2 = world[w + 4]; + y2 = world[w + 5]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.1875; + tmpy = (y1 - cy1 * 2 + cy2) * 0.1875; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + curves[i] = pathLength; + x1 = x2; + y1 = y2; + } + if (percentPosition) + position *= pathLength; + if (percentSpacing) { + for (var i = 0; i < spacesCount; i++) + spaces[i] *= pathLength; + } + var segments = this.segments; + var curveLength = 0; + for (var i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { + var space = spaces[i]; + position += space; + var p = position; + if (closed) { + p %= pathLength; + if (p < 0) + p += pathLength; + curve = 0; + } + else if (p < 0) { + this.addBeforePosition(p, world, 0, out, o); + continue; + } + else if (p > pathLength) { + this.addAfterPosition(p - pathLength, world, verticesLength - 4, out, o); + continue; + } + for (;; curve++) { + var length_5 = curves[curve]; + if (p > length_5) + continue; + if (curve == 0) + p /= length_5; + else { + var prev = curves[curve - 1]; + p = (p - prev) / (length_5 - prev); + } + break; + } + if (curve != prevCurve) { + prevCurve = curve; + var ii = curve * 6; + x1 = world[ii]; + y1 = world[ii + 1]; + cx1 = world[ii + 2]; + cy1 = world[ii + 3]; + cx2 = world[ii + 4]; + cy2 = world[ii + 5]; + x2 = world[ii + 6]; + y2 = world[ii + 7]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.03; + tmpy = (y1 - cy1 * 2 + cy2) * 0.03; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667; + curveLength = Math.sqrt(dfx * dfx + dfy * dfy); + segments[0] = curveLength; + for (ii = 1; ii < 8; ii++) { + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[ii] = curveLength; + } + dfx += ddfx; + dfy += ddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[8] = curveLength; + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[9] = curveLength; + segment = 0; + } + p *= curveLength; + for (;; segment++) { + var length_6 = segments[segment]; + if (p > length_6) + continue; + if (segment == 0) + p /= length_6; + else { + var prev = segments[segment - 1]; + p = segment + (p - prev) / (length_6 - prev); + } + break; + } + this.addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || (i > 0 && space == 0)); + } + return out; + }; + PathConstraint.prototype.addBeforePosition = function (p, temp, i, out, o) { + var x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + }; + PathConstraint.prototype.addAfterPosition = function (p, temp, i, out, o) { + var x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + }; + PathConstraint.prototype.addCurvePosition = function (p, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents) { + if (p == 0 || isNaN(p)) + p = 0.0001; + var tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u; + var ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p; + var x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; + out[o] = x; + out[o + 1] = y; + if (tangents) + out[o + 2] = Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); + }; + PathConstraint.prototype.getOrder = function () { + return this.data.order; + }; + PathConstraint.NONE = -1; + PathConstraint.BEFORE = -2; + PathConstraint.AFTER = -3; + PathConstraint.epsilon = 0.00001; + return PathConstraint; + }()); + spine.PathConstraint = PathConstraint; +})(spine || (spine = {})); +var spine; +(function (spine) { + var PathConstraintData = (function () { + function PathConstraintData(name) { + this.order = 0; + this.bones = new Array(); + this.name = name; + } + return PathConstraintData; + }()); + spine.PathConstraintData = PathConstraintData; + var PositionMode; + (function (PositionMode) { + PositionMode[PositionMode["Fixed"] = 0] = "Fixed"; + PositionMode[PositionMode["Percent"] = 1] = "Percent"; + })(PositionMode = spine.PositionMode || (spine.PositionMode = {})); + var SpacingMode; + (function (SpacingMode) { + SpacingMode[SpacingMode["Length"] = 0] = "Length"; + SpacingMode[SpacingMode["Fixed"] = 1] = "Fixed"; + SpacingMode[SpacingMode["Percent"] = 2] = "Percent"; + })(SpacingMode = spine.SpacingMode || (spine.SpacingMode = {})); + var RotateMode; + (function (RotateMode) { + RotateMode[RotateMode["Tangent"] = 0] = "Tangent"; + RotateMode[RotateMode["Chain"] = 1] = "Chain"; + RotateMode[RotateMode["ChainScale"] = 2] = "ChainScale"; + })(RotateMode = spine.RotateMode || (spine.RotateMode = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var Assets = (function () { + function Assets(clientId) { + this.toLoad = new Array(); + this.assets = {}; + this.clientId = clientId; + } + Assets.prototype.loaded = function () { + var i = 0; + for (var v in this.assets) + i++; + return i; + }; + return Assets; + }()); + var SharedAssetManager = (function () { + function SharedAssetManager(pathPrefix) { + if (pathPrefix === void 0) { pathPrefix = ""; } + this.clientAssets = {}; + this.queuedAssets = {}; + this.rawAssets = {}; + this.errors = {}; + this.pathPrefix = pathPrefix; + } + SharedAssetManager.prototype.queueAsset = function (clientId, textureLoader, path) { + var clientAssets = this.clientAssets[clientId]; + if (clientAssets === null || clientAssets === undefined) { + clientAssets = new Assets(clientId); + this.clientAssets[clientId] = clientAssets; + } + if (textureLoader !== null) + clientAssets.textureLoader = textureLoader; + clientAssets.toLoad.push(path); + if (this.queuedAssets[path] === path) { + return false; + } + else { + this.queuedAssets[path] = path; + return true; + } + }; + SharedAssetManager.prototype.loadText = function (clientId, path) { + var _this = this; + path = this.pathPrefix + path; + if (!this.queueAsset(clientId, null, path)) + return; + var request = new XMLHttpRequest(); + request.onreadystatechange = function () { + if (request.readyState == XMLHttpRequest.DONE) { + if (request.status >= 200 && request.status < 300) { + _this.rawAssets[path] = request.responseText; + } + else { + _this.errors[path] = "Couldn't load text " + path + ": status " + request.status + ", " + request.responseText; + } + } + }; + request.open("GET", path, true); + request.send(); + }; + SharedAssetManager.prototype.loadJson = function (clientId, path) { + var _this = this; + path = this.pathPrefix + path; + if (!this.queueAsset(clientId, null, path)) + return; + var request = new XMLHttpRequest(); + request.onreadystatechange = function () { + if (request.readyState == XMLHttpRequest.DONE) { + if (request.status >= 200 && request.status < 300) { + _this.rawAssets[path] = JSON.parse(request.responseText); + } + else { + _this.errors[path] = "Couldn't load text " + path + ": status " + request.status + ", " + request.responseText; + } + } + }; + request.open("GET", path, true); + request.send(); + }; + SharedAssetManager.prototype.loadTexture = function (clientId, textureLoader, path) { + var _this = this; + path = this.pathPrefix + path; + if (!this.queueAsset(clientId, textureLoader, path)) + return; + var img = new Image(); + img.src = path; + img.crossOrigin = "anonymous"; + img.onload = function (ev) { + _this.rawAssets[path] = img; + }; + img.onerror = function (ev) { + _this.errors[path] = "Couldn't load image " + path; + }; + }; + SharedAssetManager.prototype.get = function (clientId, path) { + path = this.pathPrefix + path; + var clientAssets = this.clientAssets[clientId]; + if (clientAssets === null || clientAssets === undefined) + return true; + return clientAssets.assets[path]; + }; + SharedAssetManager.prototype.updateClientAssets = function (clientAssets) { + for (var i = 0; i < clientAssets.toLoad.length; i++) { + var path = clientAssets.toLoad[i]; + var asset = clientAssets.assets[path]; + if (asset === null || asset === undefined) { + var rawAsset = this.rawAssets[path]; + if (rawAsset === null || rawAsset === undefined) + continue; + if (rawAsset instanceof HTMLImageElement) { + clientAssets.assets[path] = clientAssets.textureLoader(rawAsset); + } + else { + clientAssets.assets[path] = rawAsset; + } + } + } + }; + SharedAssetManager.prototype.isLoadingComplete = function (clientId) { + var clientAssets = this.clientAssets[clientId]; + if (clientAssets === null || clientAssets === undefined) + return true; + this.updateClientAssets(clientAssets); + return clientAssets.toLoad.length == clientAssets.loaded(); + }; + SharedAssetManager.prototype.dispose = function () { + }; + SharedAssetManager.prototype.hasErrors = function () { + return Object.keys(this.errors).length > 0; + }; + SharedAssetManager.prototype.getErrors = function () { + return this.errors; + }; + return SharedAssetManager; + }()); + spine.SharedAssetManager = SharedAssetManager; +})(spine || (spine = {})); +var spine; +(function (spine) { + var Skeleton = (function () { + function Skeleton(data) { + this._updateCache = new Array(); + this.updateCacheReset = new Array(); + this.time = 0; + this.flipX = false; + this.flipY = false; + this.x = 0; + this.y = 0; + if (data == null) + throw new Error("data cannot be null."); + this.data = data; + this.bones = new Array(); + for (var i = 0; i < data.bones.length; i++) { + var boneData = data.bones[i]; + var bone = void 0; + if (boneData.parent == null) + bone = new spine.Bone(boneData, this, null); + else { + var parent_1 = this.bones[boneData.parent.index]; + bone = new spine.Bone(boneData, this, parent_1); + parent_1.children.push(bone); + } + this.bones.push(bone); + } + this.slots = new Array(); + this.drawOrder = new Array(); + for (var i = 0; i < data.slots.length; i++) { + var slotData = data.slots[i]; + var bone = this.bones[slotData.boneData.index]; + var slot = new spine.Slot(slotData, bone); + this.slots.push(slot); + this.drawOrder.push(slot); + } + this.ikConstraints = new Array(); + for (var i = 0; i < data.ikConstraints.length; i++) { + var ikConstraintData = data.ikConstraints[i]; + this.ikConstraints.push(new spine.IkConstraint(ikConstraintData, this)); + } + this.transformConstraints = new Array(); + for (var i = 0; i < data.transformConstraints.length; i++) { + var transformConstraintData = data.transformConstraints[i]; + this.transformConstraints.push(new spine.TransformConstraint(transformConstraintData, this)); + } + this.pathConstraints = new Array(); + for (var i = 0; i < data.pathConstraints.length; i++) { + var pathConstraintData = data.pathConstraints[i]; + this.pathConstraints.push(new spine.PathConstraint(pathConstraintData, this)); + } + this.color = new spine.Color(1, 1, 1, 1); + this.updateCache(); + } + Skeleton.prototype.updateCache = function () { + var updateCache = this._updateCache; + updateCache.length = 0; + this.updateCacheReset.length = 0; + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + bones[i].sorted = false; + var ikConstraints = this.ikConstraints; + var transformConstraints = this.transformConstraints; + var pathConstraints = this.pathConstraints; + var ikCount = ikConstraints.length, transformCount = transformConstraints.length, pathCount = pathConstraints.length; + var constraintCount = ikCount + transformCount + pathCount; + outer: for (var i = 0; i < constraintCount; i++) { + for (var ii = 0; ii < ikCount; ii++) { + var constraint = ikConstraints[ii]; + if (constraint.data.order == i) { + this.sortIkConstraint(constraint); + continue outer; + } + } + for (var ii = 0; ii < transformCount; ii++) { + var constraint = transformConstraints[ii]; + if (constraint.data.order == i) { + this.sortTransformConstraint(constraint); + continue outer; + } + } + for (var ii = 0; ii < pathCount; ii++) { + var constraint = pathConstraints[ii]; + if (constraint.data.order == i) { + this.sortPathConstraint(constraint); + continue outer; + } + } + } + for (var i = 0, n = bones.length; i < n; i++) + this.sortBone(bones[i]); + }; + Skeleton.prototype.sortIkConstraint = function (constraint) { + var target = constraint.target; + this.sortBone(target); + var constrained = constraint.bones; + var parent = constrained[0]; + this.sortBone(parent); + if (constrained.length > 1) { + var child = constrained[constrained.length - 1]; + if (!(this._updateCache.indexOf(child) > -1)) + this.updateCacheReset.push(child); + } + this._updateCache.push(constraint); + this.sortReset(parent.children); + constrained[constrained.length - 1].sorted = true; + }; + Skeleton.prototype.sortPathConstraint = function (constraint) { + var slot = constraint.target; + var slotIndex = slot.data.index; + var slotBone = slot.bone; + if (this.skin != null) + this.sortPathConstraintAttachment(this.skin, slotIndex, slotBone); + if (this.data.defaultSkin != null && this.data.defaultSkin != this.skin) + this.sortPathConstraintAttachment(this.data.defaultSkin, slotIndex, slotBone); + for (var i = 0, n = this.data.skins.length; i < n; i++) + this.sortPathConstraintAttachment(this.data.skins[i], slotIndex, slotBone); + var attachment = slot.getAttachment(); + if (attachment instanceof spine.PathAttachment) + this.sortPathConstraintAttachmentWith(attachment, slotBone); + var constrained = constraint.bones; + var boneCount = constrained.length; + for (var i = 0; i < boneCount; i++) + this.sortBone(constrained[i]); + this._updateCache.push(constraint); + for (var i = 0; i < boneCount; i++) + this.sortReset(constrained[i].children); + for (var i = 0; i < boneCount; i++) + constrained[i].sorted = true; + }; + Skeleton.prototype.sortTransformConstraint = function (constraint) { + this.sortBone(constraint.target); + var constrained = constraint.bones; + var boneCount = constrained.length; + if (constraint.data.local) { + for (var i = 0; i < boneCount; i++) { + var child = constrained[i]; + this.sortBone(child.parent); + if (!(this._updateCache.indexOf(child) > -1)) + this.updateCacheReset.push(child); + } + } + else { + for (var i = 0; i < boneCount; i++) { + this.sortBone(constrained[i]); + } + } + this._updateCache.push(constraint); + for (var ii = 0; ii < boneCount; ii++) + this.sortReset(constrained[ii].children); + for (var ii = 0; ii < boneCount; ii++) + constrained[ii].sorted = true; + }; + Skeleton.prototype.sortPathConstraintAttachment = function (skin, slotIndex, slotBone) { + var attachments = skin.attachments[slotIndex]; + if (!attachments) + return; + for (var key in attachments) { + this.sortPathConstraintAttachmentWith(attachments[key], slotBone); + } + }; + Skeleton.prototype.sortPathConstraintAttachmentWith = function (attachment, slotBone) { + if (!(attachment instanceof spine.PathAttachment)) + return; + var pathBones = attachment.bones; + if (pathBones == null) + this.sortBone(slotBone); + else { + var bones = this.bones; + var i = 0; + while (i < pathBones.length) { + var boneCount = pathBones[i++]; + for (var n = i + boneCount; i < n; i++) { + var boneIndex = pathBones[i]; + this.sortBone(bones[boneIndex]); + } + } + } + }; + Skeleton.prototype.sortBone = function (bone) { + if (bone.sorted) + return; + var parent = bone.parent; + if (parent != null) + this.sortBone(parent); + bone.sorted = true; + this._updateCache.push(bone); + }; + Skeleton.prototype.sortReset = function (bones) { + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + if (bone.sorted) + this.sortReset(bone.children); + bone.sorted = false; + } + }; + Skeleton.prototype.updateWorldTransform = function () { + var updateCacheReset = this.updateCacheReset; + for (var i = 0, n = updateCacheReset.length; i < n; i++) { + var bone = updateCacheReset[i]; + bone.ax = bone.x; + bone.ay = bone.y; + bone.arotation = bone.rotation; + bone.ascaleX = bone.scaleX; + bone.ascaleY = bone.scaleY; + bone.ashearX = bone.shearX; + bone.ashearY = bone.shearY; + bone.appliedValid = true; + } + var updateCache = this._updateCache; + for (var i = 0, n = updateCache.length; i < n; i++) + updateCache[i].update(); + }; + Skeleton.prototype.setToSetupPose = function () { + this.setBonesToSetupPose(); + this.setSlotsToSetupPose(); + }; + Skeleton.prototype.setBonesToSetupPose = function () { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + bones[i].setToSetupPose(); + var ikConstraints = this.ikConstraints; + for (var i = 0, n = ikConstraints.length; i < n; i++) { + var constraint = ikConstraints[i]; + constraint.bendDirection = constraint.data.bendDirection; + constraint.mix = constraint.data.mix; + } + var transformConstraints = this.transformConstraints; + for (var i = 0, n = transformConstraints.length; i < n; i++) { + var constraint = transformConstraints[i]; + var data = constraint.data; + constraint.rotateMix = data.rotateMix; + constraint.translateMix = data.translateMix; + constraint.scaleMix = data.scaleMix; + constraint.shearMix = data.shearMix; + } + var pathConstraints = this.pathConstraints; + for (var i = 0, n = pathConstraints.length; i < n; i++) { + var constraint = pathConstraints[i]; + var data = constraint.data; + constraint.position = data.position; + constraint.spacing = data.spacing; + constraint.rotateMix = data.rotateMix; + constraint.translateMix = data.translateMix; + } + }; + Skeleton.prototype.setSlotsToSetupPose = function () { + var slots = this.slots; + spine.Utils.arrayCopy(slots, 0, this.drawOrder, 0, slots.length); + for (var i = 0, n = slots.length; i < n; i++) + slots[i].setToSetupPose(); + }; + Skeleton.prototype.getRootBone = function () { + if (this.bones.length == 0) + return null; + return this.bones[0]; + }; + Skeleton.prototype.findBone = function (boneName) { + if (boneName == null) + throw new Error("boneName cannot be null."); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + if (bone.data.name == boneName) + return bone; + } + return null; + }; + Skeleton.prototype.findBoneIndex = function (boneName) { + if (boneName == null) + throw new Error("boneName cannot be null."); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].data.name == boneName) + return i; + return -1; + }; + Skeleton.prototype.findSlot = function (slotName) { + if (slotName == null) + throw new Error("slotName cannot be null."); + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + var slot = slots[i]; + if (slot.data.name == slotName) + return slot; + } + return null; + }; + Skeleton.prototype.findSlotIndex = function (slotName) { + if (slotName == null) + throw new Error("slotName cannot be null."); + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].data.name == slotName) + return i; + return -1; + }; + Skeleton.prototype.setSkinByName = function (skinName) { + var skin = this.data.findSkin(skinName); + if (skin == null) + throw new Error("Skin not found: " + skinName); + this.setSkin(skin); + }; + Skeleton.prototype.setSkin = function (newSkin) { + if (newSkin != null) { + if (this.skin != null) + newSkin.attachAll(this, this.skin); + else { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + var slot = slots[i]; + var name_1 = slot.data.attachmentName; + if (name_1 != null) { + var attachment = newSkin.getAttachment(i, name_1); + if (attachment != null) + slot.setAttachment(attachment); + } + } + } + } + this.skin = newSkin; + }; + Skeleton.prototype.getAttachmentByName = function (slotName, attachmentName) { + return this.getAttachment(this.data.findSlotIndex(slotName), attachmentName); + }; + Skeleton.prototype.getAttachment = function (slotIndex, attachmentName) { + if (attachmentName == null) + throw new Error("attachmentName cannot be null."); + if (this.skin != null) { + var attachment = this.skin.getAttachment(slotIndex, attachmentName); + if (attachment != null) + return attachment; + } + if (this.data.defaultSkin != null) + return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); + return null; + }; + Skeleton.prototype.setAttachment = function (slotName, attachmentName) { + if (slotName == null) + throw new Error("slotName cannot be null."); + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + var slot = slots[i]; + if (slot.data.name == slotName) { + var attachment = null; + if (attachmentName != null) { + attachment = this.getAttachment(i, attachmentName); + if (attachment == null) + throw new Error("Attachment not found: " + attachmentName + ", for slot: " + slotName); + } + slot.setAttachment(attachment); + return; + } + } + throw new Error("Slot not found: " + slotName); + }; + Skeleton.prototype.findIkConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var ikConstraints = this.ikConstraints; + for (var i = 0, n = ikConstraints.length; i < n; i++) { + var ikConstraint = ikConstraints[i]; + if (ikConstraint.data.name == constraintName) + return ikConstraint; + } + return null; + }; + Skeleton.prototype.findTransformConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var transformConstraints = this.transformConstraints; + for (var i = 0, n = transformConstraints.length; i < n; i++) { + var constraint = transformConstraints[i]; + if (constraint.data.name == constraintName) + return constraint; + } + return null; + }; + Skeleton.prototype.findPathConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var pathConstraints = this.pathConstraints; + for (var i = 0, n = pathConstraints.length; i < n; i++) { + var constraint = pathConstraints[i]; + if (constraint.data.name == constraintName) + return constraint; + } + return null; + }; + Skeleton.prototype.getBounds = function (offset, size, temp) { + if (offset == null) + throw new Error("offset cannot be null."); + if (size == null) + throw new Error("size cannot be null."); + var drawOrder = this.drawOrder; + var minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var verticesLength = 0; + var vertices = null; + var attachment = slot.getAttachment(); + if (attachment instanceof spine.RegionAttachment) { + verticesLength = 8; + vertices = spine.Utils.setArraySize(temp, verticesLength, 0); + attachment.computeWorldVertices(slot.bone, vertices, 0, 2); + } + else if (attachment instanceof spine.MeshAttachment) { + var mesh = attachment; + verticesLength = mesh.worldVerticesLength; + vertices = spine.Utils.setArraySize(temp, verticesLength, 0); + mesh.computeWorldVertices(slot, 0, verticesLength, vertices, 0, 2); + } + if (vertices != null) { + for (var ii = 0, nn = vertices.length; ii < nn; ii += 2) { + var x = vertices[ii], y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + } + offset.set(minX, minY); + size.set(maxX - minX, maxY - minY); + }; + Skeleton.prototype.update = function (delta) { + this.time += delta; + }; + return Skeleton; + }()); + spine.Skeleton = Skeleton; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SkeletonBounds = (function () { + function SkeletonBounds() { + this.minX = 0; + this.minY = 0; + this.maxX = 0; + this.maxY = 0; + this.boundingBoxes = new Array(); + this.polygons = new Array(); + this.polygonPool = new spine.Pool(function () { + return spine.Utils.newFloatArray(16); + }); + } + SkeletonBounds.prototype.update = function (skeleton, updateAabb) { + if (skeleton == null) + throw new Error("skeleton cannot be null."); + var boundingBoxes = this.boundingBoxes; + var polygons = this.polygons; + var polygonPool = this.polygonPool; + var slots = skeleton.slots; + var slotCount = slots.length; + boundingBoxes.length = 0; + polygonPool.freeAll(polygons); + polygons.length = 0; + for (var i = 0; i < slotCount; i++) { + var slot = slots[i]; + var attachment = slot.getAttachment(); + if (attachment instanceof spine.BoundingBoxAttachment) { + var boundingBox = attachment; + boundingBoxes.push(boundingBox); + var polygon = polygonPool.obtain(); + if (polygon.length != boundingBox.worldVerticesLength) { + polygon = spine.Utils.newFloatArray(boundingBox.worldVerticesLength); + } + polygons.push(polygon); + boundingBox.computeWorldVertices(slot, 0, boundingBox.worldVerticesLength, polygon, 0, 2); + } + } + if (updateAabb) { + this.aabbCompute(); + } + else { + this.minX = Number.POSITIVE_INFINITY; + this.minY = Number.POSITIVE_INFINITY; + this.maxX = Number.NEGATIVE_INFINITY; + this.maxY = Number.NEGATIVE_INFINITY; + } + }; + SkeletonBounds.prototype.aabbCompute = function () { + var minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + var polygons = this.polygons; + for (var i = 0, n = polygons.length; i < n; i++) { + var polygon = polygons[i]; + var vertices = polygon; + for (var ii = 0, nn = polygon.length; ii < nn; ii += 2) { + var x = vertices[ii]; + var y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + }; + SkeletonBounds.prototype.aabbContainsPoint = function (x, y) { + return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY; + }; + SkeletonBounds.prototype.aabbIntersectsSegment = function (x1, y1, x2, y2) { + var minX = this.minX; + var minY = this.minY; + var maxX = this.maxX; + var maxY = this.maxY; + if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) + return false; + var m = (y2 - y1) / (x2 - x1); + var y = m * (minX - x1) + y1; + if (y > minY && y < maxY) + return true; + y = m * (maxX - x1) + y1; + if (y > minY && y < maxY) + return true; + var x = (minY - y1) / m + x1; + if (x > minX && x < maxX) + return true; + x = (maxY - y1) / m + x1; + if (x > minX && x < maxX) + return true; + return false; + }; + SkeletonBounds.prototype.aabbIntersectsSkeleton = function (bounds) { + return this.minX < bounds.maxX && this.maxX > bounds.minX && this.minY < bounds.maxY && this.maxY > bounds.minY; + }; + SkeletonBounds.prototype.containsPoint = function (x, y) { + var polygons = this.polygons; + for (var i = 0, n = polygons.length; i < n; i++) + if (this.containsPointPolygon(polygons[i], x, y)) + return this.boundingBoxes[i]; + return null; + }; + SkeletonBounds.prototype.containsPointPolygon = function (polygon, x, y) { + var vertices = polygon; + var nn = polygon.length; + var prevIndex = nn - 2; + var inside = false; + for (var ii = 0; ii < nn; ii += 2) { + var vertexY = vertices[ii + 1]; + var prevY = vertices[prevIndex + 1]; + if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { + var vertexX = vertices[ii]; + if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) + inside = !inside; + } + prevIndex = ii; + } + return inside; + }; + SkeletonBounds.prototype.intersectsSegment = function (x1, y1, x2, y2) { + var polygons = this.polygons; + for (var i = 0, n = polygons.length; i < n; i++) + if (this.intersectsSegmentPolygon(polygons[i], x1, y1, x2, y2)) + return this.boundingBoxes[i]; + return null; + }; + SkeletonBounds.prototype.intersectsSegmentPolygon = function (polygon, x1, y1, x2, y2) { + var vertices = polygon; + var nn = polygon.length; + var width12 = x1 - x2, height12 = y1 - y2; + var det1 = x1 * y2 - y1 * x2; + var x3 = vertices[nn - 2], y3 = vertices[nn - 1]; + for (var ii = 0; ii < nn; ii += 2) { + var x4 = vertices[ii], y4 = vertices[ii + 1]; + var det2 = x3 * y4 - y3 * x4; + var width34 = x3 - x4, height34 = y3 - y4; + var det3 = width12 * height34 - height12 * width34; + var x = (det1 * width34 - width12 * det2) / det3; + if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { + var y = (det1 * height34 - height12 * det2) / det3; + if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) + return true; + } + x3 = x4; + y3 = y4; + } + return false; + }; + SkeletonBounds.prototype.getPolygon = function (boundingBox) { + if (boundingBox == null) + throw new Error("boundingBox cannot be null."); + var index = this.boundingBoxes.indexOf(boundingBox); + return index == -1 ? null : this.polygons[index]; + }; + SkeletonBounds.prototype.getWidth = function () { + return this.maxX - this.minX; + }; + SkeletonBounds.prototype.getHeight = function () { + return this.maxY - this.minY; + }; + return SkeletonBounds; + }()); + spine.SkeletonBounds = SkeletonBounds; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SkeletonClipping = (function () { + function SkeletonClipping() { + this.triangulator = new spine.Triangulator(); + this.clippingPolygon = new Array(); + this.clipOutput = new Array(); + this.clippedVertices = new Array(); + this.clippedTriangles = new Array(); + this.scratch = new Array(); + } + SkeletonClipping.prototype.clipStart = function (slot, clip) { + if (this.clipAttachment != null) + return 0; + this.clipAttachment = clip; + var n = clip.worldVerticesLength; + var vertices = spine.Utils.setArraySize(this.clippingPolygon, n); + clip.computeWorldVertices(slot, 0, n, vertices, 0, 2); + var clippingPolygon = this.clippingPolygon; + SkeletonClipping.makeClockwise(clippingPolygon); + var clippingPolygons = this.clippingPolygons = this.triangulator.decompose(clippingPolygon, this.triangulator.triangulate(clippingPolygon)); + for (var i = 0, n_1 = clippingPolygons.length; i < n_1; i++) { + var polygon = clippingPolygons[i]; + SkeletonClipping.makeClockwise(polygon); + polygon.push(polygon[0]); + polygon.push(polygon[1]); + } + return clippingPolygons.length; + }; + SkeletonClipping.prototype.clipEndWithSlot = function (slot) { + if (this.clipAttachment != null && this.clipAttachment.endSlot == slot.data) + this.clipEnd(); + }; + SkeletonClipping.prototype.clipEnd = function () { + if (this.clipAttachment == null) + return; + this.clipAttachment = null; + this.clippingPolygons = null; + this.clippedVertices.length = 0; + this.clippedTriangles.length = 0; + this.clippingPolygon.length = 0; + }; + SkeletonClipping.prototype.isClipping = function () { + return this.clipAttachment != null; + }; + SkeletonClipping.prototype.clipTriangles = function (vertices, verticesLength, triangles, trianglesLength, uvs, light, dark, twoColor) { + var clipOutput = this.clipOutput, clippedVertices = this.clippedVertices; + var clippedTriangles = this.clippedTriangles; + var polygons = this.clippingPolygons; + var polygonsCount = this.clippingPolygons.length; + var vertexSize = twoColor ? 12 : 8; + var index = 0; + clippedVertices.length = 0; + clippedTriangles.length = 0; + outer: for (var i = 0; i < trianglesLength; i += 3) { + var vertexOffset = triangles[i] << 1; + var x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1]; + var u1 = uvs[vertexOffset], v1 = uvs[vertexOffset + 1]; + vertexOffset = triangles[i + 1] << 1; + var x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1]; + var u2 = uvs[vertexOffset], v2 = uvs[vertexOffset + 1]; + vertexOffset = triangles[i + 2] << 1; + var x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1]; + var u3 = uvs[vertexOffset], v3 = uvs[vertexOffset + 1]; + for (var p = 0; p < polygonsCount; p++) { + var s = clippedVertices.length; + if (this.clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) { + var clipOutputLength = clipOutput.length; + if (clipOutputLength == 0) + continue; + var d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1; + var d = 1 / (d0 * d2 + d1 * (y1 - y3)); + var clipOutputCount = clipOutputLength >> 1; + var clipOutputItems = this.clipOutput; + var clippedVerticesItems = spine.Utils.setArraySize(clippedVertices, s + clipOutputCount * vertexSize); + for (var ii = 0; ii < clipOutputLength; ii += 2) { + var x = clipOutputItems[ii], y = clipOutputItems[ii + 1]; + clippedVerticesItems[s] = x; + clippedVerticesItems[s + 1] = y; + clippedVerticesItems[s + 2] = light.r; + clippedVerticesItems[s + 3] = light.g; + clippedVerticesItems[s + 4] = light.b; + clippedVerticesItems[s + 5] = light.a; + var c0 = x - x3, c1 = y - y3; + var a = (d0 * c0 + d1 * c1) * d; + var b = (d4 * c0 + d2 * c1) * d; + var c = 1 - a - b; + clippedVerticesItems[s + 6] = u1 * a + u2 * b + u3 * c; + clippedVerticesItems[s + 7] = v1 * a + v2 * b + v3 * c; + if (twoColor) { + clippedVerticesItems[s + 8] = dark.r; + clippedVerticesItems[s + 9] = dark.g; + clippedVerticesItems[s + 10] = dark.b; + clippedVerticesItems[s + 11] = dark.a; + } + s += vertexSize; + } + s = clippedTriangles.length; + var clippedTrianglesItems = spine.Utils.setArraySize(clippedTriangles, s + 3 * (clipOutputCount - 2)); + clipOutputCount--; + for (var ii = 1; ii < clipOutputCount; ii++) { + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = (index + ii); + clippedTrianglesItems[s + 2] = (index + ii + 1); + s += 3; + } + index += clipOutputCount + 1; + } + else { + var clippedVerticesItems = spine.Utils.setArraySize(clippedVertices, s + 3 * vertexSize); + clippedVerticesItems[s] = x1; + clippedVerticesItems[s + 1] = y1; + clippedVerticesItems[s + 2] = light.r; + clippedVerticesItems[s + 3] = light.g; + clippedVerticesItems[s + 4] = light.b; + clippedVerticesItems[s + 5] = light.a; + if (!twoColor) { + clippedVerticesItems[s + 6] = u1; + clippedVerticesItems[s + 7] = v1; + clippedVerticesItems[s + 8] = x2; + clippedVerticesItems[s + 9] = y2; + clippedVerticesItems[s + 10] = light.r; + clippedVerticesItems[s + 11] = light.g; + clippedVerticesItems[s + 12] = light.b; + clippedVerticesItems[s + 13] = light.a; + clippedVerticesItems[s + 14] = u2; + clippedVerticesItems[s + 15] = v2; + clippedVerticesItems[s + 16] = x3; + clippedVerticesItems[s + 17] = y3; + clippedVerticesItems[s + 18] = light.r; + clippedVerticesItems[s + 19] = light.g; + clippedVerticesItems[s + 20] = light.b; + clippedVerticesItems[s + 21] = light.a; + clippedVerticesItems[s + 22] = u3; + clippedVerticesItems[s + 23] = v3; + } + else { + clippedVerticesItems[s + 6] = u1; + clippedVerticesItems[s + 7] = v1; + clippedVerticesItems[s + 8] = dark.r; + clippedVerticesItems[s + 9] = dark.g; + clippedVerticesItems[s + 10] = dark.b; + clippedVerticesItems[s + 11] = dark.a; + clippedVerticesItems[s + 12] = x2; + clippedVerticesItems[s + 13] = y2; + clippedVerticesItems[s + 14] = light.r; + clippedVerticesItems[s + 15] = light.g; + clippedVerticesItems[s + 16] = light.b; + clippedVerticesItems[s + 17] = light.a; + clippedVerticesItems[s + 18] = u2; + clippedVerticesItems[s + 19] = v2; + clippedVerticesItems[s + 20] = dark.r; + clippedVerticesItems[s + 21] = dark.g; + clippedVerticesItems[s + 22] = dark.b; + clippedVerticesItems[s + 23] = dark.a; + clippedVerticesItems[s + 24] = x3; + clippedVerticesItems[s + 25] = y3; + clippedVerticesItems[s + 26] = light.r; + clippedVerticesItems[s + 27] = light.g; + clippedVerticesItems[s + 28] = light.b; + clippedVerticesItems[s + 29] = light.a; + clippedVerticesItems[s + 30] = u3; + clippedVerticesItems[s + 31] = v3; + clippedVerticesItems[s + 32] = dark.r; + clippedVerticesItems[s + 33] = dark.g; + clippedVerticesItems[s + 34] = dark.b; + clippedVerticesItems[s + 35] = dark.a; + } + s = clippedTriangles.length; + var clippedTrianglesItems = spine.Utils.setArraySize(clippedTriangles, s + 3); + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = (index + 1); + clippedTrianglesItems[s + 2] = (index + 2); + index += 3; + continue outer; + } + } + } + }; + SkeletonClipping.prototype.clip = function (x1, y1, x2, y2, x3, y3, clippingArea, output) { + var originalOutput = output; + var clipped = false; + var input = null; + if (clippingArea.length % 4 >= 2) { + input = output; + output = this.scratch; + } + else + input = this.scratch; + input.length = 0; + input.push(x1); + input.push(y1); + input.push(x2); + input.push(y2); + input.push(x3); + input.push(y3); + input.push(x1); + input.push(y1); + output.length = 0; + var clippingVertices = clippingArea; + var clippingVerticesLast = clippingArea.length - 4; + for (var i = 0;; i += 2) { + var edgeX = clippingVertices[i], edgeY = clippingVertices[i + 1]; + var edgeX2 = clippingVertices[i + 2], edgeY2 = clippingVertices[i + 3]; + var deltaX = edgeX - edgeX2, deltaY = edgeY - edgeY2; + var inputVertices = input; + var inputVerticesLength = input.length - 2, outputStart = output.length; + for (var ii = 0; ii < inputVerticesLength; ii += 2) { + var inputX = inputVertices[ii], inputY = inputVertices[ii + 1]; + var inputX2 = inputVertices[ii + 2], inputY2 = inputVertices[ii + 3]; + var side2 = deltaX * (inputY2 - edgeY2) - deltaY * (inputX2 - edgeX2) > 0; + if (deltaX * (inputY - edgeY2) - deltaY * (inputX - edgeX2) > 0) { + if (side2) { + output.push(inputX2); + output.push(inputY2); + continue; + } + var c0 = inputY2 - inputY, c2 = inputX2 - inputX; + var ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / (c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY)); + output.push(edgeX + (edgeX2 - edgeX) * ua); + output.push(edgeY + (edgeY2 - edgeY) * ua); + } + else if (side2) { + var c0 = inputY2 - inputY, c2 = inputX2 - inputX; + var ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / (c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY)); + output.push(edgeX + (edgeX2 - edgeX) * ua); + output.push(edgeY + (edgeY2 - edgeY) * ua); + output.push(inputX2); + output.push(inputY2); + } + clipped = true; + } + if (outputStart == output.length) { + originalOutput.length = 0; + return true; + } + output.push(output[0]); + output.push(output[1]); + if (i == clippingVerticesLast) + break; + var temp = output; + output = input; + output.length = 0; + input = temp; + } + if (originalOutput != output) { + originalOutput.length = 0; + for (var i = 0, n = output.length - 2; i < n; i++) + originalOutput[i] = output[i]; + } + else + originalOutput.length = originalOutput.length - 2; + return clipped; + }; + SkeletonClipping.makeClockwise = function (polygon) { + var vertices = polygon; + var verticeslength = polygon.length; + var area = vertices[verticeslength - 2] * vertices[1] - vertices[0] * vertices[verticeslength - 1], p1x = 0, p1y = 0, p2x = 0, p2y = 0; + for (var i = 0, n = verticeslength - 3; i < n; i += 2) { + p1x = vertices[i]; + p1y = vertices[i + 1]; + p2x = vertices[i + 2]; + p2y = vertices[i + 3]; + area += p1x * p2y - p2x * p1y; + } + if (area < 0) + return; + for (var i = 0, lastX = verticeslength - 2, n = verticeslength >> 1; i < n; i += 2) { + var x = vertices[i], y = vertices[i + 1]; + var other = lastX - i; + vertices[i] = vertices[other]; + vertices[i + 1] = vertices[other + 1]; + vertices[other] = x; + vertices[other + 1] = y; + } + }; + return SkeletonClipping; + }()); + spine.SkeletonClipping = SkeletonClipping; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SkeletonData = (function () { + function SkeletonData() { + this.bones = new Array(); + this.slots = new Array(); + this.skins = new Array(); + this.events = new Array(); + this.animations = new Array(); + this.ikConstraints = new Array(); + this.transformConstraints = new Array(); + this.pathConstraints = new Array(); + this.fps = 0; + } + SkeletonData.prototype.findBone = function (boneName) { + if (boneName == null) + throw new Error("boneName cannot be null."); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + if (bone.name == boneName) + return bone; + } + return null; + }; + SkeletonData.prototype.findBoneIndex = function (boneName) { + if (boneName == null) + throw new Error("boneName cannot be null."); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].name == boneName) + return i; + return -1; + }; + SkeletonData.prototype.findSlot = function (slotName) { + if (slotName == null) + throw new Error("slotName cannot be null."); + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + var slot = slots[i]; + if (slot.name == slotName) + return slot; + } + return null; + }; + SkeletonData.prototype.findSlotIndex = function (slotName) { + if (slotName == null) + throw new Error("slotName cannot be null."); + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].name == slotName) + return i; + return -1; + }; + SkeletonData.prototype.findSkin = function (skinName) { + if (skinName == null) + throw new Error("skinName cannot be null."); + var skins = this.skins; + for (var i = 0, n = skins.length; i < n; i++) { + var skin = skins[i]; + if (skin.name == skinName) + return skin; + } + return null; + }; + SkeletonData.prototype.findEvent = function (eventDataName) { + if (eventDataName == null) + throw new Error("eventDataName cannot be null."); + var events = this.events; + for (var i = 0, n = events.length; i < n; i++) { + var event_4 = events[i]; + if (event_4.name == eventDataName) + return event_4; + } + return null; + }; + SkeletonData.prototype.findAnimation = function (animationName) { + if (animationName == null) + throw new Error("animationName cannot be null."); + var animations = this.animations; + for (var i = 0, n = animations.length; i < n; i++) { + var animation = animations[i]; + if (animation.name == animationName) + return animation; + } + return null; + }; + SkeletonData.prototype.findIkConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var ikConstraints = this.ikConstraints; + for (var i = 0, n = ikConstraints.length; i < n; i++) { + var constraint = ikConstraints[i]; + if (constraint.name == constraintName) + return constraint; + } + return null; + }; + SkeletonData.prototype.findTransformConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var transformConstraints = this.transformConstraints; + for (var i = 0, n = transformConstraints.length; i < n; i++) { + var constraint = transformConstraints[i]; + if (constraint.name == constraintName) + return constraint; + } + return null; + }; + SkeletonData.prototype.findPathConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var pathConstraints = this.pathConstraints; + for (var i = 0, n = pathConstraints.length; i < n; i++) { + var constraint = pathConstraints[i]; + if (constraint.name == constraintName) + return constraint; + } + return null; + }; + SkeletonData.prototype.findPathConstraintIndex = function (pathConstraintName) { + if (pathConstraintName == null) + throw new Error("pathConstraintName cannot be null."); + var pathConstraints = this.pathConstraints; + for (var i = 0, n = pathConstraints.length; i < n; i++) + if (pathConstraints[i].name == pathConstraintName) + return i; + return -1; + }; + return SkeletonData; + }()); + spine.SkeletonData = SkeletonData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SkeletonJson = (function () { + function SkeletonJson(attachmentLoader) { + this.scale = 1; + this.linkedMeshes = new Array(); + this.attachmentLoader = attachmentLoader; + } + SkeletonJson.prototype.readSkeletonData = function (json) { + var scale = this.scale; + var skeletonData = new spine.SkeletonData(); + var root = typeof (json) === "string" ? JSON.parse(json) : json; + var skeletonMap = root.skeleton; + if (skeletonMap != null) { + skeletonData.hash = skeletonMap.hash; + skeletonData.version = skeletonMap.spine; + skeletonData.width = skeletonMap.width; + skeletonData.height = skeletonMap.height; + skeletonData.fps = skeletonMap.fps; + skeletonData.imagesPath = skeletonMap.images; + } + if (root.bones) { + for (var i = 0; i < root.bones.length; i++) { + var boneMap = root.bones[i]; + var parent_2 = null; + var parentName = this.getValue(boneMap, "parent", null); + if (parentName != null) { + parent_2 = skeletonData.findBone(parentName); + if (parent_2 == null) + throw new Error("Parent bone not found: " + parentName); + } + var data = new spine.BoneData(skeletonData.bones.length, boneMap.name, parent_2); + data.length = this.getValue(boneMap, "length", 0) * scale; + data.x = this.getValue(boneMap, "x", 0) * scale; + data.y = this.getValue(boneMap, "y", 0) * scale; + data.rotation = this.getValue(boneMap, "rotation", 0); + data.scaleX = this.getValue(boneMap, "scaleX", 1); + data.scaleY = this.getValue(boneMap, "scaleY", 1); + data.shearX = this.getValue(boneMap, "shearX", 0); + data.shearY = this.getValue(boneMap, "shearY", 0); + data.transformMode = SkeletonJson.transformModeFromString(this.getValue(boneMap, "transform", "normal")); + skeletonData.bones.push(data); + } + } + if (root.slots) { + for (var i = 0; i < root.slots.length; i++) { + var slotMap = root.slots[i]; + var slotName = slotMap.name; + var boneName = slotMap.bone; + var boneData = skeletonData.findBone(boneName); + if (boneData == null) + throw new Error("Slot bone not found: " + boneName); + var data = new spine.SlotData(skeletonData.slots.length, slotName, boneData); + var color = this.getValue(slotMap, "color", null); + if (color != null) + data.color.setFromString(color); + var dark = this.getValue(slotMap, "dark", null); + if (dark != null) { + data.darkColor = new spine.Color(1, 1, 1, 1); + data.darkColor.setFromString(dark); + } + data.attachmentName = this.getValue(slotMap, "attachment", null); + data.blendMode = SkeletonJson.blendModeFromString(this.getValue(slotMap, "blend", "normal")); + skeletonData.slots.push(data); + } + } + if (root.ik) { + for (var i = 0; i < root.ik.length; i++) { + var constraintMap = root.ik[i]; + var data = new spine.IkConstraintData(constraintMap.name); + data.order = this.getValue(constraintMap, "order", 0); + for (var j = 0; j < constraintMap.bones.length; j++) { + var boneName = constraintMap.bones[j]; + var bone = skeletonData.findBone(boneName); + if (bone == null) + throw new Error("IK bone not found: " + boneName); + data.bones.push(bone); + } + var targetName = constraintMap.target; + data.target = skeletonData.findBone(targetName); + if (data.target == null) + throw new Error("IK target bone not found: " + targetName); + data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1; + data.mix = this.getValue(constraintMap, "mix", 1); + skeletonData.ikConstraints.push(data); + } + } + if (root.transform) { + for (var i = 0; i < root.transform.length; i++) { + var constraintMap = root.transform[i]; + var data = new spine.TransformConstraintData(constraintMap.name); + data.order = this.getValue(constraintMap, "order", 0); + for (var j = 0; j < constraintMap.bones.length; j++) { + var boneName = constraintMap.bones[j]; + var bone = skeletonData.findBone(boneName); + if (bone == null) + throw new Error("Transform constraint bone not found: " + boneName); + data.bones.push(bone); + } + var targetName = constraintMap.target; + data.target = skeletonData.findBone(targetName); + if (data.target == null) + throw new Error("Transform constraint target bone not found: " + targetName); + data.local = this.getValue(constraintMap, "local", false); + data.relative = this.getValue(constraintMap, "relative", false); + data.offsetRotation = this.getValue(constraintMap, "rotation", 0); + data.offsetX = this.getValue(constraintMap, "x", 0) * scale; + data.offsetY = this.getValue(constraintMap, "y", 0) * scale; + data.offsetScaleX = this.getValue(constraintMap, "scaleX", 0); + data.offsetScaleY = this.getValue(constraintMap, "scaleY", 0); + data.offsetShearY = this.getValue(constraintMap, "shearY", 0); + data.rotateMix = this.getValue(constraintMap, "rotateMix", 1); + data.translateMix = this.getValue(constraintMap, "translateMix", 1); + data.scaleMix = this.getValue(constraintMap, "scaleMix", 1); + data.shearMix = this.getValue(constraintMap, "shearMix", 1); + skeletonData.transformConstraints.push(data); + } + } + if (root.path) { + for (var i = 0; i < root.path.length; i++) { + var constraintMap = root.path[i]; + var data = new spine.PathConstraintData(constraintMap.name); + data.order = this.getValue(constraintMap, "order", 0); + for (var j = 0; j < constraintMap.bones.length; j++) { + var boneName = constraintMap.bones[j]; + var bone = skeletonData.findBone(boneName); + if (bone == null) + throw new Error("Transform constraint bone not found: " + boneName); + data.bones.push(bone); + } + var targetName = constraintMap.target; + data.target = skeletonData.findSlot(targetName); + if (data.target == null) + throw new Error("Path target slot not found: " + targetName); + data.positionMode = SkeletonJson.positionModeFromString(this.getValue(constraintMap, "positionMode", "percent")); + data.spacingMode = SkeletonJson.spacingModeFromString(this.getValue(constraintMap, "spacingMode", "length")); + data.rotateMode = SkeletonJson.rotateModeFromString(this.getValue(constraintMap, "rotateMode", "tangent")); + data.offsetRotation = this.getValue(constraintMap, "rotation", 0); + data.position = this.getValue(constraintMap, "position", 0); + if (data.positionMode == spine.PositionMode.Fixed) + data.position *= scale; + data.spacing = this.getValue(constraintMap, "spacing", 0); + if (data.spacingMode == spine.SpacingMode.Length || data.spacingMode == spine.SpacingMode.Fixed) + data.spacing *= scale; + data.rotateMix = this.getValue(constraintMap, "rotateMix", 1); + data.translateMix = this.getValue(constraintMap, "translateMix", 1); + skeletonData.pathConstraints.push(data); + } + } + if (root.skins) { + for (var skinName in root.skins) { + var skinMap = root.skins[skinName]; + var skin = new spine.Skin(skinName); + for (var slotName in skinMap) { + var slotIndex = skeletonData.findSlotIndex(slotName); + if (slotIndex == -1) + throw new Error("Slot not found: " + slotName); + var slotMap = skinMap[slotName]; + for (var entryName in slotMap) { + var attachment = this.readAttachment(slotMap[entryName], skin, slotIndex, entryName, skeletonData); + if (attachment != null) + skin.addAttachment(slotIndex, entryName, attachment); + } + } + skeletonData.skins.push(skin); + if (skin.name == "default") + skeletonData.defaultSkin = skin; + } + } + for (var i = 0, n = this.linkedMeshes.length; i < n; i++) { + var linkedMesh = this.linkedMeshes[i]; + var skin = linkedMesh.skin == null ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin); + if (skin == null) + throw new Error("Skin not found: " + linkedMesh.skin); + var parent_3 = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); + if (parent_3 == null) + throw new Error("Parent mesh not found: " + linkedMesh.parent); + linkedMesh.mesh.setParentMesh(parent_3); + linkedMesh.mesh.updateUVs(); + } + this.linkedMeshes.length = 0; + if (root.events) { + for (var eventName in root.events) { + var eventMap = root.events[eventName]; + var data = new spine.EventData(eventName); + data.intValue = this.getValue(eventMap, "int", 0); + data.floatValue = this.getValue(eventMap, "float", 0); + data.stringValue = this.getValue(eventMap, "string", ""); + skeletonData.events.push(data); + } + } + if (root.animations) { + for (var animationName in root.animations) { + var animationMap = root.animations[animationName]; + this.readAnimation(animationMap, animationName, skeletonData); + } + } + return skeletonData; + }; + SkeletonJson.prototype.readAttachment = function (map, skin, slotIndex, name, skeletonData) { + var scale = this.scale; + name = this.getValue(map, "name", name); + var type = this.getValue(map, "type", "region"); + switch (type) { + case "region": { + var path = this.getValue(map, "path", name); + var region = this.attachmentLoader.newRegionAttachment(skin, name, path); + if (region == null) + return null; + region.path = path; + region.x = this.getValue(map, "x", 0) * scale; + region.y = this.getValue(map, "y", 0) * scale; + region.scaleX = this.getValue(map, "scaleX", 1); + region.scaleY = this.getValue(map, "scaleY", 1); + region.rotation = this.getValue(map, "rotation", 0); + region.width = map.width * scale; + region.height = map.height * scale; + var color = this.getValue(map, "color", null); + if (color != null) + region.color.setFromString(color); + region.updateOffset(); + return region; + } + case "boundingbox": { + var box = this.attachmentLoader.newBoundingBoxAttachment(skin, name); + if (box == null) + return null; + this.readVertices(map, box, map.vertexCount << 1); + var color = this.getValue(map, "color", null); + if (color != null) + box.color.setFromString(color); + return box; + } + case "mesh": + case "linkedmesh": { + var path = this.getValue(map, "path", name); + var mesh = this.attachmentLoader.newMeshAttachment(skin, name, path); + if (mesh == null) + return null; + mesh.path = path; + var color = this.getValue(map, "color", null); + if (color != null) + mesh.color.setFromString(color); + var parent_4 = this.getValue(map, "parent", null); + if (parent_4 != null) { + mesh.inheritDeform = this.getValue(map, "deform", true); + this.linkedMeshes.push(new LinkedMesh(mesh, this.getValue(map, "skin", null), slotIndex, parent_4)); + return mesh; + } + var uvs = map.uvs; + this.readVertices(map, mesh, uvs.length); + mesh.triangles = map.triangles; + mesh.regionUVs = uvs; + mesh.updateUVs(); + mesh.hullLength = this.getValue(map, "hull", 0) * 2; + return mesh; + } + case "path": { + var path = this.attachmentLoader.newPathAttachment(skin, name); + if (path == null) + return null; + path.closed = this.getValue(map, "closed", false); + path.constantSpeed = this.getValue(map, "constantSpeed", true); + var vertexCount = map.vertexCount; + this.readVertices(map, path, vertexCount << 1); + var lengths = spine.Utils.newArray(vertexCount / 3, 0); + for (var i = 0; i < map.lengths.length; i++) + lengths[i] = map.lengths[i] * scale; + path.lengths = lengths; + var color = this.getValue(map, "color", null); + if (color != null) + path.color.setFromString(color); + return path; + } + case "point": { + var point = this.attachmentLoader.newPointAttachment(skin, name); + if (point == null) + return null; + point.x = this.getValue(map, "x", 0) * scale; + point.y = this.getValue(map, "y", 0) * scale; + point.rotation = this.getValue(map, "rotation", 0); + var color = this.getValue(map, "color", null); + if (color != null) + point.color.setFromString(color); + return point; + } + case "clipping": { + var clip = this.attachmentLoader.newClippingAttachment(skin, name); + if (clip == null) + return null; + var end = this.getValue(map, "end", null); + if (end != null) { + var slot = skeletonData.findSlot(end); + if (slot == null) + throw new Error("Clipping end slot not found: " + end); + clip.endSlot = slot; + } + var vertexCount = map.vertexCount; + this.readVertices(map, clip, vertexCount << 1); + var color = this.getValue(map, "color", null); + if (color != null) + clip.color.setFromString(color); + return clip; + } + } + return null; + }; + SkeletonJson.prototype.readVertices = function (map, attachment, verticesLength) { + var scale = this.scale; + attachment.worldVerticesLength = verticesLength; + var vertices = map.vertices; + if (verticesLength == vertices.length) { + var scaledVertices = spine.Utils.toFloatArray(vertices); + if (scale != 1) { + for (var i = 0, n = vertices.length; i < n; i++) + scaledVertices[i] *= scale; + } + attachment.vertices = scaledVertices; + return; + } + var weights = new Array(); + var bones = new Array(); + for (var i = 0, n = vertices.length; i < n;) { + var boneCount = vertices[i++]; + bones.push(boneCount); + for (var nn = i + boneCount * 4; i < nn; i += 4) { + bones.push(vertices[i]); + weights.push(vertices[i + 1] * scale); + weights.push(vertices[i + 2] * scale); + weights.push(vertices[i + 3]); + } + } + attachment.bones = bones; + attachment.vertices = spine.Utils.toFloatArray(weights); + }; + SkeletonJson.prototype.readAnimation = function (map, name, skeletonData) { + var scale = this.scale; + var timelines = new Array(); + var duration = 0; + if (map.slots) { + for (var slotName in map.slots) { + var slotMap = map.slots[slotName]; + var slotIndex = skeletonData.findSlotIndex(slotName); + if (slotIndex == -1) + throw new Error("Slot not found: " + slotName); + for (var timelineName in slotMap) { + var timelineMap = slotMap[timelineName]; + if (timelineName == "attachment") { + var timeline = new spine.AttachmentTimeline(timelineMap.length); + timeline.slotIndex = slotIndex; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + timeline.setFrame(frameIndex++, valueMap.time, valueMap.name); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + else if (timelineName == "color") { + var timeline = new spine.ColorTimeline(timelineMap.length); + timeline.slotIndex = slotIndex; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + var color = new spine.Color(); + color.setFromString(valueMap.color); + timeline.setFrame(frameIndex, valueMap.time, color.r, color.g, color.b, color.a); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.ColorTimeline.ENTRIES]); + } + else if (timelineName == "twoColor") { + var timeline = new spine.TwoColorTimeline(timelineMap.length); + timeline.slotIndex = slotIndex; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + var light = new spine.Color(); + var dark = new spine.Color(); + light.setFromString(valueMap.light); + dark.setFromString(valueMap.dark); + timeline.setFrame(frameIndex, valueMap.time, light.r, light.g, light.b, light.a, dark.r, dark.g, dark.b); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.TwoColorTimeline.ENTRIES]); + } + else + throw new Error("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"); + } + } + } + if (map.bones) { + for (var boneName in map.bones) { + var boneMap = map.bones[boneName]; + var boneIndex = skeletonData.findBoneIndex(boneName); + if (boneIndex == -1) + throw new Error("Bone not found: " + boneName); + for (var timelineName in boneMap) { + var timelineMap = boneMap[timelineName]; + if (timelineName === "rotate") { + var timeline = new spine.RotateTimeline(timelineMap.length); + timeline.boneIndex = boneIndex; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + timeline.setFrame(frameIndex, valueMap.time, valueMap.angle); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.RotateTimeline.ENTRIES]); + } + else if (timelineName === "translate" || timelineName === "scale" || timelineName === "shear") { + var timeline = null; + var timelineScale = 1; + if (timelineName === "scale") + timeline = new spine.ScaleTimeline(timelineMap.length); + else if (timelineName === "shear") + timeline = new spine.ShearTimeline(timelineMap.length); + else { + timeline = new spine.TranslateTimeline(timelineMap.length); + timelineScale = scale; + } + timeline.boneIndex = boneIndex; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + var x = this.getValue(valueMap, "x", 0), y = this.getValue(valueMap, "y", 0); + timeline.setFrame(frameIndex, valueMap.time, x * timelineScale, y * timelineScale); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.TranslateTimeline.ENTRIES]); + } + else + throw new Error("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"); + } + } + } + if (map.ik) { + for (var constraintName in map.ik) { + var constraintMap = map.ik[constraintName]; + var constraint = skeletonData.findIkConstraint(constraintName); + var timeline = new spine.IkConstraintTimeline(constraintMap.length); + timeline.ikConstraintIndex = skeletonData.ikConstraints.indexOf(constraint); + var frameIndex = 0; + for (var i = 0; i < constraintMap.length; i++) { + var valueMap = constraintMap[i]; + timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "bendPositive", true) ? 1 : -1); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.IkConstraintTimeline.ENTRIES]); + } + } + if (map.transform) { + for (var constraintName in map.transform) { + var constraintMap = map.transform[constraintName]; + var constraint = skeletonData.findTransformConstraint(constraintName); + var timeline = new spine.TransformConstraintTimeline(constraintMap.length); + timeline.transformConstraintIndex = skeletonData.transformConstraints.indexOf(constraint); + var frameIndex = 0; + for (var i = 0; i < constraintMap.length; i++) { + var valueMap = constraintMap[i]; + timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, "rotateMix", 1), this.getValue(valueMap, "translateMix", 1), this.getValue(valueMap, "scaleMix", 1), this.getValue(valueMap, "shearMix", 1)); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.TransformConstraintTimeline.ENTRIES]); + } + } + if (map.paths) { + for (var constraintName in map.paths) { + var constraintMap = map.paths[constraintName]; + var index = skeletonData.findPathConstraintIndex(constraintName); + if (index == -1) + throw new Error("Path constraint not found: " + constraintName); + var data = skeletonData.pathConstraints[index]; + for (var timelineName in constraintMap) { + var timelineMap = constraintMap[timelineName]; + if (timelineName === "position" || timelineName === "spacing") { + var timeline = null; + var timelineScale = 1; + if (timelineName === "spacing") { + timeline = new spine.PathConstraintSpacingTimeline(timelineMap.length); + if (data.spacingMode == spine.SpacingMode.Length || data.spacingMode == spine.SpacingMode.Fixed) + timelineScale = scale; + } + else { + timeline = new spine.PathConstraintPositionTimeline(timelineMap.length); + if (data.positionMode == spine.PositionMode.Fixed) + timelineScale = scale; + } + timeline.pathConstraintIndex = index; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, timelineName, 0) * timelineScale); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.PathConstraintPositionTimeline.ENTRIES]); + } + else if (timelineName === "mix") { + var timeline = new spine.PathConstraintMixTimeline(timelineMap.length); + timeline.pathConstraintIndex = index; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, "rotateMix", 1), this.getValue(valueMap, "translateMix", 1)); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.PathConstraintMixTimeline.ENTRIES]); + } + } + } + } + if (map.deform) { + for (var deformName in map.deform) { + var deformMap = map.deform[deformName]; + var skin = skeletonData.findSkin(deformName); + if (skin == null) + throw new Error("Skin not found: " + deformName); + for (var slotName in deformMap) { + var slotMap = deformMap[slotName]; + var slotIndex = skeletonData.findSlotIndex(slotName); + if (slotIndex == -1) + throw new Error("Slot not found: " + slotMap.name); + for (var timelineName in slotMap) { + var timelineMap = slotMap[timelineName]; + var attachment = skin.getAttachment(slotIndex, timelineName); + if (attachment == null) + throw new Error("Deform attachment not found: " + timelineMap.name); + var weighted = attachment.bones != null; + var vertices = attachment.vertices; + var deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + var timeline = new spine.DeformTimeline(timelineMap.length); + timeline.slotIndex = slotIndex; + timeline.attachment = attachment; + var frameIndex = 0; + for (var j = 0; j < timelineMap.length; j++) { + var valueMap = timelineMap[j]; + var deform = void 0; + var verticesValue = this.getValue(valueMap, "vertices", null); + if (verticesValue == null) + deform = weighted ? spine.Utils.newFloatArray(deformLength) : vertices; + else { + deform = spine.Utils.newFloatArray(deformLength); + var start = this.getValue(valueMap, "offset", 0); + spine.Utils.arrayCopy(verticesValue, 0, deform, start, verticesValue.length); + if (scale != 1) { + for (var i = start, n = i + verticesValue.length; i < n; i++) + deform[i] *= scale; + } + if (!weighted) { + for (var i = 0; i < deformLength; i++) + deform[i] += vertices[i]; + } + } + timeline.setFrame(frameIndex, valueMap.time, deform); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + } + } + } + var drawOrderNode = map.drawOrder; + if (drawOrderNode == null) + drawOrderNode = map.draworder; + if (drawOrderNode != null) { + var timeline = new spine.DrawOrderTimeline(drawOrderNode.length); + var slotCount = skeletonData.slots.length; + var frameIndex = 0; + for (var j = 0; j < drawOrderNode.length; j++) { + var drawOrderMap = drawOrderNode[j]; + var drawOrder = null; + var offsets = this.getValue(drawOrderMap, "offsets", null); + if (offsets != null) { + drawOrder = spine.Utils.newArray(slotCount, -1); + var unchanged = spine.Utils.newArray(slotCount - offsets.length, 0); + var originalIndex = 0, unchangedIndex = 0; + for (var i = 0; i < offsets.length; i++) { + var offsetMap = offsets[i]; + var slotIndex = skeletonData.findSlotIndex(offsetMap.slot); + if (slotIndex == -1) + throw new Error("Slot not found: " + offsetMap.slot); + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + drawOrder[originalIndex + offsetMap.offset] = originalIndex++; + } + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + for (var i = slotCount - 1; i >= 0; i--) + if (drawOrder[i] == -1) + drawOrder[i] = unchanged[--unchangedIndex]; + } + timeline.setFrame(frameIndex++, drawOrderMap.time, drawOrder); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + if (map.events) { + var timeline = new spine.EventTimeline(map.events.length); + var frameIndex = 0; + for (var i = 0; i < map.events.length; i++) { + var eventMap = map.events[i]; + var eventData = skeletonData.findEvent(eventMap.name); + if (eventData == null) + throw new Error("Event not found: " + eventMap.name); + var event_5 = new spine.Event(spine.Utils.toSinglePrecision(eventMap.time), eventData); + event_5.intValue = this.getValue(eventMap, "int", eventData.intValue); + event_5.floatValue = this.getValue(eventMap, "float", eventData.floatValue); + event_5.stringValue = this.getValue(eventMap, "string", eventData.stringValue); + timeline.setFrame(frameIndex++, event_5); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + if (isNaN(duration)) { + throw new Error("Error while parsing animation, duration is NaN"); + } + skeletonData.animations.push(new spine.Animation(name, timelines, duration)); + }; + SkeletonJson.prototype.readCurve = function (map, timeline, frameIndex) { + if (!map.curve) + return; + if (map.curve === "stepped") + timeline.setStepped(frameIndex); + else if (Object.prototype.toString.call(map.curve) === '[object Array]') { + var curve = map.curve; + timeline.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); + } + }; + SkeletonJson.prototype.getValue = function (map, prop, defaultValue) { + return map[prop] !== undefined ? map[prop] : defaultValue; + }; + SkeletonJson.blendModeFromString = function (str) { + str = str.toLowerCase(); + if (str == "normal") + return spine.BlendMode.Normal; + if (str == "additive") + return spine.BlendMode.Additive; + if (str == "multiply") + return spine.BlendMode.Multiply; + if (str == "screen") + return spine.BlendMode.Screen; + throw new Error("Unknown blend mode: " + str); + }; + SkeletonJson.positionModeFromString = function (str) { + str = str.toLowerCase(); + if (str == "fixed") + return spine.PositionMode.Fixed; + if (str == "percent") + return spine.PositionMode.Percent; + throw new Error("Unknown position mode: " + str); + }; + SkeletonJson.spacingModeFromString = function (str) { + str = str.toLowerCase(); + if (str == "length") + return spine.SpacingMode.Length; + if (str == "fixed") + return spine.SpacingMode.Fixed; + if (str == "percent") + return spine.SpacingMode.Percent; + throw new Error("Unknown position mode: " + str); + }; + SkeletonJson.rotateModeFromString = function (str) { + str = str.toLowerCase(); + if (str == "tangent") + return spine.RotateMode.Tangent; + if (str == "chain") + return spine.RotateMode.Chain; + if (str == "chainscale") + return spine.RotateMode.ChainScale; + throw new Error("Unknown rotate mode: " + str); + }; + SkeletonJson.transformModeFromString = function (str) { + str = str.toLowerCase(); + if (str == "normal") + return spine.TransformMode.Normal; + if (str == "onlytranslation") + return spine.TransformMode.OnlyTranslation; + if (str == "norotationorreflection") + return spine.TransformMode.NoRotationOrReflection; + if (str == "noscale") + return spine.TransformMode.NoScale; + if (str == "noscaleorreflection") + return spine.TransformMode.NoScaleOrReflection; + throw new Error("Unknown transform mode: " + str); + }; + return SkeletonJson; + }()); + spine.SkeletonJson = SkeletonJson; + var LinkedMesh = (function () { + function LinkedMesh(mesh, skin, slotIndex, parent) { + this.mesh = mesh; + this.skin = skin; + this.slotIndex = slotIndex; + this.parent = parent; + } + return LinkedMesh; + }()); +})(spine || (spine = {})); +var spine; +(function (spine) { + var Skin = (function () { + function Skin(name) { + this.attachments = new Array(); + if (name == null) + throw new Error("name cannot be null."); + this.name = name; + } + Skin.prototype.addAttachment = function (slotIndex, name, attachment) { + if (attachment == null) + throw new Error("attachment cannot be null."); + var attachments = this.attachments; + if (slotIndex >= attachments.length) + attachments.length = slotIndex + 1; + if (!attachments[slotIndex]) + attachments[slotIndex] = {}; + attachments[slotIndex][name] = attachment; + }; + Skin.prototype.getAttachment = function (slotIndex, name) { + var dictionary = this.attachments[slotIndex]; + return dictionary ? dictionary[name] : null; + }; + Skin.prototype.attachAll = function (skeleton, oldSkin) { + var slotIndex = 0; + for (var i = 0; i < skeleton.slots.length; i++) { + var slot = skeleton.slots[i]; + var slotAttachment = slot.getAttachment(); + if (slotAttachment && slotIndex < oldSkin.attachments.length) { + var dictionary = oldSkin.attachments[slotIndex]; + for (var key in dictionary) { + var skinAttachment = dictionary[key]; + if (slotAttachment == skinAttachment) { + var attachment = this.getAttachment(slotIndex, key); + if (attachment != null) + slot.setAttachment(attachment); + break; + } + } + } + slotIndex++; + } + }; + return Skin; + }()); + spine.Skin = Skin; +})(spine || (spine = {})); +var spine; +(function (spine) { + var Slot = (function () { + function Slot(data, bone) { + this.attachmentVertices = new Array(); + if (data == null) + throw new Error("data cannot be null."); + if (bone == null) + throw new Error("bone cannot be null."); + this.data = data; + this.bone = bone; + this.color = new spine.Color(); + this.darkColor = data.darkColor == null ? null : new spine.Color(); + this.setToSetupPose(); + } + Slot.prototype.getAttachment = function () { + return this.attachment; + }; + Slot.prototype.setAttachment = function (attachment) { + if (this.attachment == attachment) + return; + this.attachment = attachment; + this.attachmentTime = this.bone.skeleton.time; + this.attachmentVertices.length = 0; + }; + Slot.prototype.setAttachmentTime = function (time) { + this.attachmentTime = this.bone.skeleton.time - time; + }; + Slot.prototype.getAttachmentTime = function () { + return this.bone.skeleton.time - this.attachmentTime; + }; + Slot.prototype.setToSetupPose = function () { + this.color.setFromColor(this.data.color); + if (this.darkColor != null) + this.darkColor.setFromColor(this.data.darkColor); + if (this.data.attachmentName == null) + this.attachment = null; + else { + this.attachment = null; + this.setAttachment(this.bone.skeleton.getAttachment(this.data.index, this.data.attachmentName)); + } + }; + return Slot; + }()); + spine.Slot = Slot; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SlotData = (function () { + function SlotData(index, name, boneData) { + this.color = new spine.Color(1, 1, 1, 1); + if (index < 0) + throw new Error("index must be >= 0."); + if (name == null) + throw new Error("name cannot be null."); + if (boneData == null) + throw new Error("boneData cannot be null."); + this.index = index; + this.name = name; + this.boneData = boneData; + } + return SlotData; + }()); + spine.SlotData = SlotData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var Texture = (function () { + function Texture(image) { + this._image = image; + } + Texture.prototype.getImage = function () { + return this._image; + }; + Texture.filterFromString = function (text) { + switch (text.toLowerCase()) { + case "nearest": return TextureFilter.Nearest; + case "linear": return TextureFilter.Linear; + case "mipmap": return TextureFilter.MipMap; + case "mipmapnearestnearest": return TextureFilter.MipMapNearestNearest; + case "mipmaplinearnearest": return TextureFilter.MipMapLinearNearest; + case "mipmapnearestlinear": return TextureFilter.MipMapNearestLinear; + case "mipmaplinearlinear": return TextureFilter.MipMapLinearLinear; + default: throw new Error("Unknown texture filter " + text); + } + }; + Texture.wrapFromString = function (text) { + switch (text.toLowerCase()) { + case "mirroredtepeat": return TextureWrap.MirroredRepeat; + case "clamptoedge": return TextureWrap.ClampToEdge; + case "repeat": return TextureWrap.Repeat; + default: throw new Error("Unknown texture wrap " + text); + } + }; + return Texture; + }()); + spine.Texture = Texture; + var TextureFilter; + (function (TextureFilter) { + TextureFilter[TextureFilter["Nearest"] = 9728] = "Nearest"; + TextureFilter[TextureFilter["Linear"] = 9729] = "Linear"; + TextureFilter[TextureFilter["MipMap"] = 9987] = "MipMap"; + TextureFilter[TextureFilter["MipMapNearestNearest"] = 9984] = "MipMapNearestNearest"; + TextureFilter[TextureFilter["MipMapLinearNearest"] = 9985] = "MipMapLinearNearest"; + TextureFilter[TextureFilter["MipMapNearestLinear"] = 9986] = "MipMapNearestLinear"; + TextureFilter[TextureFilter["MipMapLinearLinear"] = 9987] = "MipMapLinearLinear"; + })(TextureFilter = spine.TextureFilter || (spine.TextureFilter = {})); + var TextureWrap; + (function (TextureWrap) { + TextureWrap[TextureWrap["MirroredRepeat"] = 33648] = "MirroredRepeat"; + TextureWrap[TextureWrap["ClampToEdge"] = 33071] = "ClampToEdge"; + TextureWrap[TextureWrap["Repeat"] = 10497] = "Repeat"; + })(TextureWrap = spine.TextureWrap || (spine.TextureWrap = {})); + var TextureRegion = (function () { + function TextureRegion() { + this.u = 0; + this.v = 0; + this.u2 = 0; + this.v2 = 0; + this.width = 0; + this.height = 0; + this.rotate = false; + this.offsetX = 0; + this.offsetY = 0; + this.originalWidth = 0; + this.originalHeight = 0; + } + return TextureRegion; + }()); + spine.TextureRegion = TextureRegion; + var FakeTexture = (function (_super) { + __extends(FakeTexture, _super); + function FakeTexture() { + return _super !== null && _super.apply(this, arguments) || this; + } + FakeTexture.prototype.setFilters = function (minFilter, magFilter) { }; + FakeTexture.prototype.setWraps = function (uWrap, vWrap) { }; + FakeTexture.prototype.dispose = function () { }; + return FakeTexture; + }(spine.Texture)); + spine.FakeTexture = FakeTexture; +})(spine || (spine = {})); +var spine; +(function (spine) { + var TextureAtlas = (function () { + function TextureAtlas(atlasText, textureLoader) { + this.pages = new Array(); + this.regions = new Array(); + this.load(atlasText, textureLoader); + } + TextureAtlas.prototype.load = function (atlasText, textureLoader) { + if (textureLoader == null) + throw new Error("textureLoader cannot be null."); + var reader = new TextureAtlasReader(atlasText); + var tuple = new Array(4); + var page = null; + while (true) { + var line = reader.readLine(); + if (line == null) + break; + line = line.trim(); + if (line.length == 0) + page = null; + else if (!page) { + page = new TextureAtlasPage(); + page.name = line; + if (reader.readTuple(tuple) == 2) { + page.width = parseInt(tuple[0]); + page.height = parseInt(tuple[1]); + reader.readTuple(tuple); + } + reader.readTuple(tuple); + page.minFilter = spine.Texture.filterFromString(tuple[0]); + page.magFilter = spine.Texture.filterFromString(tuple[1]); + var direction = reader.readValue(); + page.uWrap = spine.TextureWrap.ClampToEdge; + page.vWrap = spine.TextureWrap.ClampToEdge; + if (direction == "x") + page.uWrap = spine.TextureWrap.Repeat; + else if (direction == "y") + page.vWrap = spine.TextureWrap.Repeat; + else if (direction == "xy") + page.uWrap = page.vWrap = spine.TextureWrap.Repeat; + page.texture = textureLoader(line); + page.texture.setFilters(page.minFilter, page.magFilter); + page.texture.setWraps(page.uWrap, page.vWrap); + page.width = page.texture.getImage().width; + page.height = page.texture.getImage().height; + this.pages.push(page); + } + else { + var region = new TextureAtlasRegion(); + region.name = line; + region.page = page; + region.rotate = reader.readValue() == "true"; + reader.readTuple(tuple); + var x = parseInt(tuple[0]); + var y = parseInt(tuple[1]); + reader.readTuple(tuple); + var width = parseInt(tuple[0]); + var height = parseInt(tuple[1]); + region.u = x / page.width; + region.v = y / page.height; + if (region.rotate) { + region.u2 = (x + height) / page.width; + region.v2 = (y + width) / page.height; + } + else { + region.u2 = (x + width) / page.width; + region.v2 = (y + height) / page.height; + } + region.x = x; + region.y = y; + region.width = Math.abs(width); + region.height = Math.abs(height); + if (reader.readTuple(tuple) == 4) { + if (reader.readTuple(tuple) == 4) { + reader.readTuple(tuple); + } + } + region.originalWidth = parseInt(tuple[0]); + region.originalHeight = parseInt(tuple[1]); + reader.readTuple(tuple); + region.offsetX = parseInt(tuple[0]); + region.offsetY = parseInt(tuple[1]); + region.index = parseInt(reader.readValue()); + region.texture = page.texture; + this.regions.push(region); + } + } + }; + TextureAtlas.prototype.findRegion = function (name) { + for (var i = 0; i < this.regions.length; i++) { + if (this.regions[i].name == name) { + return this.regions[i]; + } + } + return null; + }; + TextureAtlas.prototype.dispose = function () { + for (var i = 0; i < this.pages.length; i++) { + this.pages[i].texture.dispose(); + } + }; + return TextureAtlas; + }()); + spine.TextureAtlas = TextureAtlas; + var TextureAtlasReader = (function () { + function TextureAtlasReader(text) { + this.index = 0; + this.lines = text.split(/\r\n|\r|\n/); + } + TextureAtlasReader.prototype.readLine = function () { + if (this.index >= this.lines.length) + return null; + return this.lines[this.index++]; + }; + TextureAtlasReader.prototype.readValue = function () { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) + throw new Error("Invalid line: " + line); + return line.substring(colon + 1).trim(); + }; + TextureAtlasReader.prototype.readTuple = function (tuple) { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) + throw new Error("Invalid line: " + line); + var i = 0, lastMatch = colon + 1; + for (; i < 3; i++) { + var comma = line.indexOf(",", lastMatch); + if (comma == -1) + break; + tuple[i] = line.substr(lastMatch, comma - lastMatch).trim(); + lastMatch = comma + 1; + } + tuple[i] = line.substring(lastMatch).trim(); + return i + 1; + }; + return TextureAtlasReader; + }()); + var TextureAtlasPage = (function () { + function TextureAtlasPage() { + } + return TextureAtlasPage; + }()); + spine.TextureAtlasPage = TextureAtlasPage; + var TextureAtlasRegion = (function (_super) { + __extends(TextureAtlasRegion, _super); + function TextureAtlasRegion() { + return _super !== null && _super.apply(this, arguments) || this; + } + return TextureAtlasRegion; + }(spine.TextureRegion)); + spine.TextureAtlasRegion = TextureAtlasRegion; +})(spine || (spine = {})); +var spine; +(function (spine) { + var TransformConstraint = (function () { + function TransformConstraint(data, skeleton) { + this.rotateMix = 0; + this.translateMix = 0; + this.scaleMix = 0; + this.shearMix = 0; + this.temp = new spine.Vector2(); + if (data == null) + throw new Error("data cannot be null."); + if (skeleton == null) + throw new Error("skeleton cannot be null."); + this.data = data; + this.rotateMix = data.rotateMix; + this.translateMix = data.translateMix; + this.scaleMix = data.scaleMix; + this.shearMix = data.shearMix; + this.bones = new Array(); + for (var i = 0; i < data.bones.length; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findBone(data.target.name); + } + TransformConstraint.prototype.apply = function () { + this.update(); + }; + TransformConstraint.prototype.update = function () { + if (this.data.local) { + if (this.data.relative) + this.applyRelativeLocal(); + else + this.applyAbsoluteLocal(); + } + else { + if (this.data.relative) + this.applyRelativeWorld(); + else + this.applyAbsoluteWorld(); + } + }; + TransformConstraint.prototype.applyAbsoluteWorld = function () { + var rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; + var target = this.target; + var ta = target.a, tb = target.b, tc = target.c, td = target.d; + var degRadReflect = ta * td - tb * tc > 0 ? spine.MathUtils.degRad : -spine.MathUtils.degRad; + var offsetRotation = this.data.offsetRotation * degRadReflect; + var offsetShearY = this.data.offsetShearY * degRadReflect; + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + var modified = false; + if (rotateMix != 0) { + var a = bone.a, b = bone.b, c = bone.c, d = bone.d; + var r = Math.atan2(tc, ta) - Math.atan2(c, a) + offsetRotation; + if (r > spine.MathUtils.PI) + r -= spine.MathUtils.PI2; + else if (r < -spine.MathUtils.PI) + r += spine.MathUtils.PI2; + r *= rotateMix; + var cos = Math.cos(r), sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + modified = true; + } + if (translateMix != 0) { + var temp = this.temp; + target.localToWorld(temp.set(this.data.offsetX, this.data.offsetY)); + bone.worldX += (temp.x - bone.worldX) * translateMix; + bone.worldY += (temp.y - bone.worldY) * translateMix; + modified = true; + } + if (scaleMix > 0) { + var s = Math.sqrt(bone.a * bone.a + bone.c * bone.c); + var ts = Math.sqrt(ta * ta + tc * tc); + if (s > 0.00001) + s = (s + (ts - s + this.data.offsetScaleX) * scaleMix) / s; + bone.a *= s; + bone.c *= s; + s = Math.sqrt(bone.b * bone.b + bone.d * bone.d); + ts = Math.sqrt(tb * tb + td * td); + if (s > 0.00001) + s = (s + (ts - s + this.data.offsetScaleY) * scaleMix) / s; + bone.b *= s; + bone.d *= s; + modified = true; + } + if (shearMix > 0) { + var b = bone.b, d = bone.d; + var by = Math.atan2(d, b); + var r = Math.atan2(td, tb) - Math.atan2(tc, ta) - (by - Math.atan2(bone.c, bone.a)); + if (r > spine.MathUtils.PI) + r -= spine.MathUtils.PI2; + else if (r < -spine.MathUtils.PI) + r += spine.MathUtils.PI2; + r = by + (r + offsetShearY) * shearMix; + var s = Math.sqrt(b * b + d * d); + bone.b = Math.cos(r) * s; + bone.d = Math.sin(r) * s; + modified = true; + } + if (modified) + bone.appliedValid = false; + } + }; + TransformConstraint.prototype.applyRelativeWorld = function () { + var rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; + var target = this.target; + var ta = target.a, tb = target.b, tc = target.c, td = target.d; + var degRadReflect = ta * td - tb * tc > 0 ? spine.MathUtils.degRad : -spine.MathUtils.degRad; + var offsetRotation = this.data.offsetRotation * degRadReflect, offsetShearY = this.data.offsetShearY * degRadReflect; + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + var modified = false; + if (rotateMix != 0) { + var a = bone.a, b = bone.b, c = bone.c, d = bone.d; + var r = Math.atan2(tc, ta) + offsetRotation; + if (r > spine.MathUtils.PI) + r -= spine.MathUtils.PI2; + else if (r < -spine.MathUtils.PI) + r += spine.MathUtils.PI2; + r *= rotateMix; + var cos = Math.cos(r), sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + modified = true; + } + if (translateMix != 0) { + var temp = this.temp; + target.localToWorld(temp.set(this.data.offsetX, this.data.offsetY)); + bone.worldX += temp.x * translateMix; + bone.worldY += temp.y * translateMix; + modified = true; + } + if (scaleMix > 0) { + var s = (Math.sqrt(ta * ta + tc * tc) - 1 + this.data.offsetScaleX) * scaleMix + 1; + bone.a *= s; + bone.c *= s; + s = (Math.sqrt(tb * tb + td * td) - 1 + this.data.offsetScaleY) * scaleMix + 1; + bone.b *= s; + bone.d *= s; + modified = true; + } + if (shearMix > 0) { + var r = Math.atan2(td, tb) - Math.atan2(tc, ta); + if (r > spine.MathUtils.PI) + r -= spine.MathUtils.PI2; + else if (r < -spine.MathUtils.PI) + r += spine.MathUtils.PI2; + var b = bone.b, d = bone.d; + r = Math.atan2(d, b) + (r - spine.MathUtils.PI / 2 + offsetShearY) * shearMix; + var s = Math.sqrt(b * b + d * d); + bone.b = Math.cos(r) * s; + bone.d = Math.sin(r) * s; + modified = true; + } + if (modified) + bone.appliedValid = false; + } + }; + TransformConstraint.prototype.applyAbsoluteLocal = function () { + var rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; + var target = this.target; + if (!target.appliedValid) + target.updateAppliedTransform(); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + if (!bone.appliedValid) + bone.updateAppliedTransform(); + var rotation = bone.arotation; + if (rotateMix != 0) { + var r = target.arotation - rotation + this.data.offsetRotation; + r -= (16384 - ((16384.499999999996 - r / 360) | 0)) * 360; + rotation += r * rotateMix; + } + var x = bone.ax, y = bone.ay; + if (translateMix != 0) { + x += (target.ax - x + this.data.offsetX) * translateMix; + y += (target.ay - y + this.data.offsetY) * translateMix; + } + var scaleX = bone.ascaleX, scaleY = bone.ascaleY; + if (scaleMix > 0) { + if (scaleX > 0.00001) + scaleX = (scaleX + (target.ascaleX - scaleX + this.data.offsetScaleX) * scaleMix) / scaleX; + if (scaleY > 0.00001) + scaleY = (scaleY + (target.ascaleY - scaleY + this.data.offsetScaleY) * scaleMix) / scaleY; + } + var shearY = bone.ashearY; + if (shearMix > 0) { + var r = target.ashearY - shearY + this.data.offsetShearY; + r -= (16384 - ((16384.499999999996 - r / 360) | 0)) * 360; + bone.shearY += r * shearMix; + } + bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY); + } + }; + TransformConstraint.prototype.applyRelativeLocal = function () { + var rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; + var target = this.target; + if (!target.appliedValid) + target.updateAppliedTransform(); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + if (!bone.appliedValid) + bone.updateAppliedTransform(); + var rotation = bone.arotation; + if (rotateMix != 0) + rotation += (target.arotation + this.data.offsetRotation) * rotateMix; + var x = bone.ax, y = bone.ay; + if (translateMix != 0) { + x += (target.ax + this.data.offsetX) * translateMix; + y += (target.ay + this.data.offsetY) * translateMix; + } + var scaleX = bone.ascaleX, scaleY = bone.ascaleY; + if (scaleMix > 0) { + if (scaleX > 0.00001) + scaleX *= ((target.ascaleX - 1 + this.data.offsetScaleX) * scaleMix) + 1; + if (scaleY > 0.00001) + scaleY *= ((target.ascaleY - 1 + this.data.offsetScaleY) * scaleMix) + 1; + } + var shearY = bone.ashearY; + if (shearMix > 0) + shearY += (target.ashearY + this.data.offsetShearY) * shearMix; + bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY); + } + }; + TransformConstraint.prototype.getOrder = function () { + return this.data.order; + }; + return TransformConstraint; + }()); + spine.TransformConstraint = TransformConstraint; +})(spine || (spine = {})); +var spine; +(function (spine) { + var TransformConstraintData = (function () { + function TransformConstraintData(name) { + this.order = 0; + this.bones = new Array(); + this.rotateMix = 0; + this.translateMix = 0; + this.scaleMix = 0; + this.shearMix = 0; + this.offsetRotation = 0; + this.offsetX = 0; + this.offsetY = 0; + this.offsetScaleX = 0; + this.offsetScaleY = 0; + this.offsetShearY = 0; + this.relative = false; + this.local = false; + if (name == null) + throw new Error("name cannot be null."); + this.name = name; + } + return TransformConstraintData; + }()); + spine.TransformConstraintData = TransformConstraintData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var Triangulator = (function () { + function Triangulator() { + this.convexPolygons = new Array(); + this.convexPolygonsIndices = new Array(); + this.indicesArray = new Array(); + this.isConcaveArray = new Array(); + this.triangles = new Array(); + this.polygonPool = new spine.Pool(function () { + return new Array(); + }); + this.polygonIndicesPool = new spine.Pool(function () { + return new Array(); + }); + } + Triangulator.prototype.triangulate = function (verticesArray) { + var vertices = verticesArray; + var vertexCount = verticesArray.length >> 1; + var indices = this.indicesArray; + indices.length = 0; + for (var i = 0; i < vertexCount; i++) + indices[i] = i; + var isConcave = this.isConcaveArray; + isConcave.length = 0; + for (var i = 0, n = vertexCount; i < n; ++i) + isConcave[i] = Triangulator.isConcave(i, vertexCount, vertices, indices); + var triangles = this.triangles; + triangles.length = 0; + while (vertexCount > 3) { + var previous = vertexCount - 1, i = 0, next = 1; + while (true) { + outer: if (!isConcave[i]) { + var p1 = indices[previous] << 1, p2 = indices[i] << 1, p3 = indices[next] << 1; + var p1x = vertices[p1], p1y = vertices[p1 + 1]; + var p2x = vertices[p2], p2y = vertices[p2 + 1]; + var p3x = vertices[p3], p3y = vertices[p3 + 1]; + for (var ii = (next + 1) % vertexCount; ii != previous; ii = (ii + 1) % vertexCount) { + if (!isConcave[ii]) + continue; + var v = indices[ii] << 1; + var vx = vertices[v], vy = vertices[v + 1]; + if (Triangulator.positiveArea(p3x, p3y, p1x, p1y, vx, vy)) { + if (Triangulator.positiveArea(p1x, p1y, p2x, p2y, vx, vy)) { + if (Triangulator.positiveArea(p2x, p2y, p3x, p3y, vx, vy)) + break outer; + } + } + } + break; + } + if (next == 0) { + do { + if (!isConcave[i]) + break; + i--; + } while (i > 0); + break; + } + previous = i; + i = next; + next = (next + 1) % vertexCount; + } + triangles.push(indices[(vertexCount + i - 1) % vertexCount]); + triangles.push(indices[i]); + triangles.push(indices[(i + 1) % vertexCount]); + indices.splice(i, 1); + isConcave.splice(i, 1); + vertexCount--; + var previousIndex = (vertexCount + i - 1) % vertexCount; + var nextIndex = i == vertexCount ? 0 : i; + isConcave[previousIndex] = Triangulator.isConcave(previousIndex, vertexCount, vertices, indices); + isConcave[nextIndex] = Triangulator.isConcave(nextIndex, vertexCount, vertices, indices); + } + if (vertexCount == 3) { + triangles.push(indices[2]); + triangles.push(indices[0]); + triangles.push(indices[1]); + } + return triangles; + }; + Triangulator.prototype.decompose = function (verticesArray, triangles) { + var vertices = verticesArray; + var convexPolygons = this.convexPolygons; + this.polygonPool.freeAll(convexPolygons); + convexPolygons.length = 0; + var convexPolygonsIndices = this.convexPolygonsIndices; + this.polygonIndicesPool.freeAll(convexPolygonsIndices); + convexPolygonsIndices.length = 0; + var polygonIndices = this.polygonIndicesPool.obtain(); + polygonIndices.length = 0; + var polygon = this.polygonPool.obtain(); + polygon.length = 0; + var fanBaseIndex = -1, lastWinding = 0; + for (var i = 0, n = triangles.length; i < n; i += 3) { + var t1 = triangles[i] << 1, t2 = triangles[i + 1] << 1, t3 = triangles[i + 2] << 1; + var x1 = vertices[t1], y1 = vertices[t1 + 1]; + var x2 = vertices[t2], y2 = vertices[t2 + 1]; + var x3 = vertices[t3], y3 = vertices[t3 + 1]; + var merged = false; + if (fanBaseIndex == t1) { + var o = polygon.length - 4; + var winding1 = Triangulator.winding(polygon[o], polygon[o + 1], polygon[o + 2], polygon[o + 3], x3, y3); + var winding2 = Triangulator.winding(x3, y3, polygon[0], polygon[1], polygon[2], polygon[3]); + if (winding1 == lastWinding && winding2 == lastWinding) { + polygon.push(x3); + polygon.push(y3); + polygonIndices.push(t3); + merged = true; + } + } + if (!merged) { + if (polygon.length > 0) { + convexPolygons.push(polygon); + convexPolygonsIndices.push(polygonIndices); + } + else { + this.polygonPool.free(polygon); + this.polygonIndicesPool.free(polygonIndices); + } + polygon = this.polygonPool.obtain(); + polygon.length = 0; + polygon.push(x1); + polygon.push(y1); + polygon.push(x2); + polygon.push(y2); + polygon.push(x3); + polygon.push(y3); + polygonIndices = this.polygonIndicesPool.obtain(); + polygonIndices.length = 0; + polygonIndices.push(t1); + polygonIndices.push(t2); + polygonIndices.push(t3); + lastWinding = Triangulator.winding(x1, y1, x2, y2, x3, y3); + fanBaseIndex = t1; + } + } + if (polygon.length > 0) { + convexPolygons.push(polygon); + convexPolygonsIndices.push(polygonIndices); + } + for (var i = 0, n = convexPolygons.length; i < n; i++) { + polygonIndices = convexPolygonsIndices[i]; + if (polygonIndices.length == 0) + continue; + var firstIndex = polygonIndices[0]; + var lastIndex = polygonIndices[polygonIndices.length - 1]; + polygon = convexPolygons[i]; + var o = polygon.length - 4; + var prevPrevX = polygon[o], prevPrevY = polygon[o + 1]; + var prevX = polygon[o + 2], prevY = polygon[o + 3]; + var firstX = polygon[0], firstY = polygon[1]; + var secondX = polygon[2], secondY = polygon[3]; + var winding = Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, firstX, firstY); + for (var ii = 0; ii < n; ii++) { + if (ii == i) + continue; + var otherIndices = convexPolygonsIndices[ii]; + if (otherIndices.length != 3) + continue; + var otherFirstIndex = otherIndices[0]; + var otherSecondIndex = otherIndices[1]; + var otherLastIndex = otherIndices[2]; + var otherPoly = convexPolygons[ii]; + var x3 = otherPoly[otherPoly.length - 2], y3 = otherPoly[otherPoly.length - 1]; + if (otherFirstIndex != firstIndex || otherSecondIndex != lastIndex) + continue; + var winding1 = Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, x3, y3); + var winding2 = Triangulator.winding(x3, y3, firstX, firstY, secondX, secondY); + if (winding1 == winding && winding2 == winding) { + otherPoly.length = 0; + otherIndices.length = 0; + polygon.push(x3); + polygon.push(y3); + polygonIndices.push(otherLastIndex); + prevPrevX = prevX; + prevPrevY = prevY; + prevX = x3; + prevY = y3; + ii = 0; + } + } + } + for (var i = convexPolygons.length - 1; i >= 0; i--) { + polygon = convexPolygons[i]; + if (polygon.length == 0) { + convexPolygons.splice(i, 1); + this.polygonPool.free(polygon); + polygonIndices = convexPolygonsIndices[i]; + convexPolygonsIndices.splice(i, 1); + this.polygonIndicesPool.free(polygonIndices); + } + } + return convexPolygons; + }; + Triangulator.isConcave = function (index, vertexCount, vertices, indices) { + var previous = indices[(vertexCount + index - 1) % vertexCount] << 1; + var current = indices[index] << 1; + var next = indices[(index + 1) % vertexCount] << 1; + return !this.positiveArea(vertices[previous], vertices[previous + 1], vertices[current], vertices[current + 1], vertices[next], vertices[next + 1]); + }; + Triangulator.positiveArea = function (p1x, p1y, p2x, p2y, p3x, p3y) { + return p1x * (p3y - p2y) + p2x * (p1y - p3y) + p3x * (p2y - p1y) >= 0; + }; + Triangulator.winding = function (p1x, p1y, p2x, p2y, p3x, p3y) { + var px = p2x - p1x, py = p2y - p1y; + return p3x * py - p3y * px + px * p1y - p1x * py >= 0 ? 1 : -1; + }; + return Triangulator; + }()); + spine.Triangulator = Triangulator; +})(spine || (spine = {})); +var spine; +(function (spine) { + var IntSet = (function () { + function IntSet() { + this.array = new Array(); + } + IntSet.prototype.add = function (value) { + var contains = this.contains(value); + this.array[value | 0] = value | 0; + return !contains; + }; + IntSet.prototype.contains = function (value) { + return this.array[value | 0] != undefined; + }; + IntSet.prototype.remove = function (value) { + this.array[value | 0] = undefined; + }; + IntSet.prototype.clear = function () { + this.array.length = 0; + }; + return IntSet; + }()); + spine.IntSet = IntSet; + var Color = (function () { + function Color(r, g, b, a) { + if (r === void 0) { r = 0; } + if (g === void 0) { g = 0; } + if (b === void 0) { b = 0; } + if (a === void 0) { a = 0; } + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + Color.prototype.set = function (r, g, b, a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + this.clamp(); + return this; + }; + Color.prototype.setFromColor = function (c) { + this.r = c.r; + this.g = c.g; + this.b = c.b; + this.a = c.a; + return this; + }; + Color.prototype.setFromString = function (hex) { + hex = hex.charAt(0) == '#' ? hex.substr(1) : hex; + this.r = parseInt(hex.substr(0, 2), 16) / 255.0; + this.g = parseInt(hex.substr(2, 2), 16) / 255.0; + this.b = parseInt(hex.substr(4, 2), 16) / 255.0; + this.a = (hex.length != 8 ? 255 : parseInt(hex.substr(6, 2), 16)) / 255.0; + return this; + }; + Color.prototype.add = function (r, g, b, a) { + this.r += r; + this.g += g; + this.b += b; + this.a += a; + this.clamp(); + return this; + }; + Color.prototype.clamp = function () { + if (this.r < 0) + this.r = 0; + else if (this.r > 1) + this.r = 1; + if (this.g < 0) + this.g = 0; + else if (this.g > 1) + this.g = 1; + if (this.b < 0) + this.b = 0; + else if (this.b > 1) + this.b = 1; + if (this.a < 0) + this.a = 0; + else if (this.a > 1) + this.a = 1; + return this; + }; + Color.WHITE = new Color(1, 1, 1, 1); + Color.RED = new Color(1, 0, 0, 1); + Color.GREEN = new Color(0, 1, 0, 1); + Color.BLUE = new Color(0, 0, 1, 1); + Color.MAGENTA = new Color(1, 0, 1, 1); + return Color; + }()); + spine.Color = Color; + var MathUtils = (function () { + function MathUtils() { + } + MathUtils.clamp = function (value, min, max) { + if (value < min) + return min; + if (value > max) + return max; + return value; + }; + MathUtils.cosDeg = function (degrees) { + return Math.cos(degrees * MathUtils.degRad); + }; + MathUtils.sinDeg = function (degrees) { + return Math.sin(degrees * MathUtils.degRad); + }; + MathUtils.signum = function (value) { + return value > 0 ? 1 : value < 0 ? -1 : 0; + }; + MathUtils.toInt = function (x) { + return x > 0 ? Math.floor(x) : Math.ceil(x); + }; + MathUtils.cbrt = function (x) { + var y = Math.pow(Math.abs(x), 1 / 3); + return x < 0 ? -y : y; + }; + MathUtils.randomTriangular = function (min, max) { + return MathUtils.randomTriangularWith(min, max, (min + max) * 0.5); + }; + MathUtils.randomTriangularWith = function (min, max, mode) { + var u = Math.random(); + var d = max - min; + if (u <= (mode - min) / d) + return min + Math.sqrt(u * d * (mode - min)); + return max - Math.sqrt((1 - u) * d * (max - mode)); + }; + MathUtils.PI = 3.1415927; + MathUtils.PI2 = MathUtils.PI * 2; + MathUtils.radiansToDegrees = 180 / MathUtils.PI; + MathUtils.radDeg = MathUtils.radiansToDegrees; + MathUtils.degreesToRadians = MathUtils.PI / 180; + MathUtils.degRad = MathUtils.degreesToRadians; + return MathUtils; + }()); + spine.MathUtils = MathUtils; + var Interpolation = (function () { + function Interpolation() { + } + Interpolation.prototype.apply = function (start, end, a) { + return start + (end - start) * this.applyInternal(a); + }; + return Interpolation; + }()); + spine.Interpolation = Interpolation; + var Pow = (function (_super) { + __extends(Pow, _super); + function Pow(power) { + var _this = _super.call(this) || this; + _this.power = 2; + _this.power = power; + return _this; + } + Pow.prototype.applyInternal = function (a) { + if (a <= 0.5) + return Math.pow(a * 2, this.power) / 2; + return Math.pow((a - 1) * 2, this.power) / (this.power % 2 == 0 ? -2 : 2) + 1; + }; + return Pow; + }(Interpolation)); + spine.Pow = Pow; + var PowOut = (function (_super) { + __extends(PowOut, _super); + function PowOut(power) { + return _super.call(this, power) || this; + } + PowOut.prototype.applyInternal = function (a) { + return Math.pow(a - 1, this.power) * (this.power % 2 == 0 ? -1 : 1) + 1; + }; + return PowOut; + }(Pow)); + spine.PowOut = PowOut; + var Utils = (function () { + function Utils() { + } + Utils.arrayCopy = function (source, sourceStart, dest, destStart, numElements) { + for (var i = sourceStart, j = destStart; i < sourceStart + numElements; i++, j++) { + dest[j] = source[i]; + } + }; + Utils.setArraySize = function (array, size, value) { + if (value === void 0) { value = 0; } + var oldSize = array.length; + if (oldSize == size) + return array; + array.length = size; + if (oldSize < size) { + for (var i = oldSize; i < size; i++) + array[i] = value; + } + return array; + }; + Utils.ensureArrayCapacity = function (array, size, value) { + if (value === void 0) { value = 0; } + if (array.length >= size) + return array; + return Utils.setArraySize(array, size, value); + }; + Utils.newArray = function (size, defaultValue) { + var array = new Array(size); + for (var i = 0; i < size; i++) + array[i] = defaultValue; + return array; + }; + Utils.newFloatArray = function (size) { + if (Utils.SUPPORTS_TYPED_ARRAYS) { + return new Float32Array(size); + } + else { + var array = new Array(size); + for (var i = 0; i < array.length; i++) + array[i] = 0; + return array; + } + }; + Utils.newShortArray = function (size) { + if (Utils.SUPPORTS_TYPED_ARRAYS) { + return new Int16Array(size); + } + else { + var array = new Array(size); + for (var i = 0; i < array.length; i++) + array[i] = 0; + return array; + } + }; + Utils.toFloatArray = function (array) { + return Utils.SUPPORTS_TYPED_ARRAYS ? new Float32Array(array) : array; + }; + Utils.toSinglePrecision = function (value) { + return Utils.SUPPORTS_TYPED_ARRAYS ? Math.fround(value) : value; + }; + Utils.webkit602BugfixHelper = function (alpha, pose) { + }; + Utils.SUPPORTS_TYPED_ARRAYS = typeof (Float32Array) !== "undefined"; + return Utils; + }()); + spine.Utils = Utils; + var DebugUtils = (function () { + function DebugUtils() { + } + DebugUtils.logBones = function (skeleton) { + for (var i = 0; i < skeleton.bones.length; i++) { + var bone = skeleton.bones[i]; + console.log(bone.data.name + ", " + bone.a + ", " + bone.b + ", " + bone.c + ", " + bone.d + ", " + bone.worldX + ", " + bone.worldY); + } + }; + return DebugUtils; + }()); + spine.DebugUtils = DebugUtils; + var Pool = (function () { + function Pool(instantiator) { + this.items = new Array(); + this.instantiator = instantiator; + } + Pool.prototype.obtain = function () { + return this.items.length > 0 ? this.items.pop() : this.instantiator(); + }; + Pool.prototype.free = function (item) { + if (item.reset) + item.reset(); + this.items.push(item); + }; + Pool.prototype.freeAll = function (items) { + for (var i = 0; i < items.length; i++) { + if (items[i].reset) + items[i].reset(); + this.items[i] = items[i]; + } + }; + Pool.prototype.clear = function () { + this.items.length = 0; + }; + return Pool; + }()); + spine.Pool = Pool; + var Vector2 = (function () { + function Vector2(x, y) { + if (x === void 0) { x = 0; } + if (y === void 0) { y = 0; } + this.x = x; + this.y = y; + } + Vector2.prototype.set = function (x, y) { + this.x = x; + this.y = y; + return this; + }; + Vector2.prototype.length = function () { + var x = this.x; + var y = this.y; + return Math.sqrt(x * x + y * y); + }; + Vector2.prototype.normalize = function () { + var len = this.length(); + if (len != 0) { + this.x /= len; + this.y /= len; + } + return this; + }; + return Vector2; + }()); + spine.Vector2 = Vector2; + var TimeKeeper = (function () { + function TimeKeeper() { + this.maxDelta = 0.064; + this.framesPerSecond = 0; + this.delta = 0; + this.totalTime = 0; + this.lastTime = Date.now() / 1000; + this.frameCount = 0; + this.frameTime = 0; + } + TimeKeeper.prototype.update = function () { + var now = Date.now() / 1000; + this.delta = now - this.lastTime; + this.frameTime += this.delta; + this.totalTime += this.delta; + if (this.delta > this.maxDelta) + this.delta = this.maxDelta; + this.lastTime = now; + this.frameCount++; + if (this.frameTime > 1) { + this.framesPerSecond = this.frameCount / this.frameTime; + this.frameTime = 0; + this.frameCount = 0; + } + }; + return TimeKeeper; + }()); + spine.TimeKeeper = TimeKeeper; + var WindowedMean = (function () { + function WindowedMean(windowSize) { + if (windowSize === void 0) { windowSize = 32; } + this.addedValues = 0; + this.lastValue = 0; + this.mean = 0; + this.dirty = true; + this.values = new Array(windowSize); + } + WindowedMean.prototype.hasEnoughData = function () { + return this.addedValues >= this.values.length; + }; + WindowedMean.prototype.addValue = function (value) { + if (this.addedValues < this.values.length) + this.addedValues++; + this.values[this.lastValue++] = value; + if (this.lastValue > this.values.length - 1) + this.lastValue = 0; + this.dirty = true; + }; + WindowedMean.prototype.getMean = function () { + if (this.hasEnoughData()) { + if (this.dirty) { + var mean = 0; + for (var i = 0; i < this.values.length; i++) { + mean += this.values[i]; + } + this.mean = mean / this.values.length; + this.dirty = false; + } + return this.mean; + } + else { + return 0; + } + }; + return WindowedMean; + }()); + spine.WindowedMean = WindowedMean; +})(spine || (spine = {})); +(function () { + if (!Math.fround) { + Math.fround = (function (array) { + return function (x) { + return array[0] = x, array[0]; + }; + })(new Float32Array(1)); + } +})(); +var spine; +(function (spine) { + var Attachment = (function () { + function Attachment(name) { + if (name == null) + throw new Error("name cannot be null."); + this.name = name; + } + return Attachment; + }()); + spine.Attachment = Attachment; + var VertexAttachment = (function (_super) { + __extends(VertexAttachment, _super); + function VertexAttachment(name) { + var _this = _super.call(this, name) || this; + _this.id = (VertexAttachment.nextID++ & 65535) << 11; + _this.worldVerticesLength = 0; + return _this; + } + VertexAttachment.prototype.computeWorldVertices = function (slot, start, count, worldVertices, offset, stride) { + count = offset + (count >> 1) * stride; + var skeleton = slot.bone.skeleton; + var deformArray = slot.attachmentVertices; + var vertices = this.vertices; + var bones = this.bones; + if (bones == null) { + if (deformArray.length > 0) + vertices = deformArray; + var bone = slot.bone; + var x = bone.worldX; + var y = bone.worldY; + var a = bone.a, b = bone.b, c = bone.c, d = bone.d; + for (var v_1 = start, w = offset; w < count; v_1 += 2, w += stride) { + var vx = vertices[v_1], vy = vertices[v_1 + 1]; + worldVertices[w] = vx * a + vy * b + x; + worldVertices[w + 1] = vx * c + vy * d + y; + } + return; + } + var v = 0, skip = 0; + for (var i = 0; i < start; i += 2) { + var n = bones[v]; + v += n + 1; + skip += n; + } + var skeletonBones = skeleton.bones; + if (deformArray.length == 0) { + for (var w = offset, b = skip * 3; w < count; w += stride) { + var wx = 0, wy = 0; + var n = bones[v++]; + n += v; + for (; v < n; v++, b += 3) { + var bone = skeletonBones[bones[v]]; + var vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } + else { + var deform = deformArray; + for (var w = offset, b = skip * 3, f = skip << 1; w < count; w += stride) { + var wx = 0, wy = 0; + var n = bones[v++]; + n += v; + for (; v < n; v++, b += 3, f += 2) { + var bone = skeletonBones[bones[v]]; + var vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } + }; + VertexAttachment.prototype.applyDeform = function (sourceAttachment) { + return this == sourceAttachment; + }; + VertexAttachment.nextID = 0; + return VertexAttachment; + }(Attachment)); + spine.VertexAttachment = VertexAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var AttachmentType; + (function (AttachmentType) { + AttachmentType[AttachmentType["Region"] = 0] = "Region"; + AttachmentType[AttachmentType["BoundingBox"] = 1] = "BoundingBox"; + AttachmentType[AttachmentType["Mesh"] = 2] = "Mesh"; + AttachmentType[AttachmentType["LinkedMesh"] = 3] = "LinkedMesh"; + AttachmentType[AttachmentType["Path"] = 4] = "Path"; + AttachmentType[AttachmentType["Point"] = 5] = "Point"; + })(AttachmentType = spine.AttachmentType || (spine.AttachmentType = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var BoundingBoxAttachment = (function (_super) { + __extends(BoundingBoxAttachment, _super); + function BoundingBoxAttachment(name) { + var _this = _super.call(this, name) || this; + _this.color = new spine.Color(1, 1, 1, 1); + return _this; + } + return BoundingBoxAttachment; + }(spine.VertexAttachment)); + spine.BoundingBoxAttachment = BoundingBoxAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var ClippingAttachment = (function (_super) { + __extends(ClippingAttachment, _super); + function ClippingAttachment(name) { + var _this = _super.call(this, name) || this; + _this.color = new spine.Color(0.2275, 0.2275, 0.8078, 1); + return _this; + } + return ClippingAttachment; + }(spine.VertexAttachment)); + spine.ClippingAttachment = ClippingAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var MeshAttachment = (function (_super) { + __extends(MeshAttachment, _super); + function MeshAttachment(name) { + var _this = _super.call(this, name) || this; + _this.color = new spine.Color(1, 1, 1, 1); + _this.inheritDeform = false; + _this.tempColor = new spine.Color(0, 0, 0, 0); + return _this; + } + MeshAttachment.prototype.updateUVs = function () { + var u = 0, v = 0, width = 0, height = 0; + if (this.region == null) { + u = v = 0; + width = height = 1; + } + else { + u = this.region.u; + v = this.region.v; + width = this.region.u2 - u; + height = this.region.v2 - v; + } + var regionUVs = this.regionUVs; + if (this.uvs == null || this.uvs.length != regionUVs.length) + this.uvs = spine.Utils.newFloatArray(regionUVs.length); + var uvs = this.uvs; + if (this.region.rotate) { + for (var i = 0, n = uvs.length; i < n; i += 2) { + uvs[i] = u + regionUVs[i + 1] * width; + uvs[i + 1] = v + height - regionUVs[i] * height; + } + } + else { + for (var i = 0, n = uvs.length; i < n; i += 2) { + uvs[i] = u + regionUVs[i] * width; + uvs[i + 1] = v + regionUVs[i + 1] * height; + } + } + }; + MeshAttachment.prototype.applyDeform = function (sourceAttachment) { + return this == sourceAttachment || (this.inheritDeform && this.parentMesh == sourceAttachment); + }; + MeshAttachment.prototype.getParentMesh = function () { + return this.parentMesh; + }; + MeshAttachment.prototype.setParentMesh = function (parentMesh) { + this.parentMesh = parentMesh; + if (parentMesh != null) { + this.bones = parentMesh.bones; + this.vertices = parentMesh.vertices; + this.worldVerticesLength = parentMesh.worldVerticesLength; + this.regionUVs = parentMesh.regionUVs; + this.triangles = parentMesh.triangles; + this.hullLength = parentMesh.hullLength; + this.worldVerticesLength = parentMesh.worldVerticesLength; + } + }; + return MeshAttachment; + }(spine.VertexAttachment)); + spine.MeshAttachment = MeshAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var PathAttachment = (function (_super) { + __extends(PathAttachment, _super); + function PathAttachment(name) { + var _this = _super.call(this, name) || this; + _this.closed = false; + _this.constantSpeed = false; + _this.color = new spine.Color(1, 1, 1, 1); + return _this; + } + return PathAttachment; + }(spine.VertexAttachment)); + spine.PathAttachment = PathAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var PointAttachment = (function (_super) { + __extends(PointAttachment, _super); + function PointAttachment(name) { + var _this = _super.call(this, name) || this; + _this.color = new spine.Color(0.38, 0.94, 0, 1); + return _this; + } + PointAttachment.prototype.computeWorldPosition = function (bone, point) { + point.x = this.x * bone.a + this.y * bone.b + bone.worldX; + point.y = this.x * bone.c + this.y * bone.d + bone.worldY; + return point; + }; + PointAttachment.prototype.computeWorldRotation = function (bone) { + var cos = spine.MathUtils.cosDeg(this.rotation), sin = spine.MathUtils.sinDeg(this.rotation); + var x = cos * bone.a + sin * bone.b; + var y = cos * bone.c + sin * bone.d; + return Math.atan2(y, x) * spine.MathUtils.radDeg; + }; + return PointAttachment; + }(spine.VertexAttachment)); + spine.PointAttachment = PointAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var RegionAttachment = (function (_super) { + __extends(RegionAttachment, _super); + function RegionAttachment(name) { + var _this = _super.call(this, name) || this; + _this.x = 0; + _this.y = 0; + _this.scaleX = 1; + _this.scaleY = 1; + _this.rotation = 0; + _this.width = 0; + _this.height = 0; + _this.color = new spine.Color(1, 1, 1, 1); + _this.offset = spine.Utils.newFloatArray(8); + _this.uvs = spine.Utils.newFloatArray(8); + _this.tempColor = new spine.Color(1, 1, 1, 1); + return _this; + } + RegionAttachment.prototype.updateOffset = function () { + var regionScaleX = this.width / this.region.originalWidth * this.scaleX; + var regionScaleY = this.height / this.region.originalHeight * this.scaleY; + var localX = -this.width / 2 * this.scaleX + this.region.offsetX * regionScaleX; + var localY = -this.height / 2 * this.scaleY + this.region.offsetY * regionScaleY; + var localX2 = localX + this.region.width * regionScaleX; + var localY2 = localY + this.region.height * regionScaleY; + var radians = this.rotation * Math.PI / 180; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + var localXCos = localX * cos + this.x; + var localXSin = localX * sin; + var localYCos = localY * cos + this.y; + var localYSin = localY * sin; + var localX2Cos = localX2 * cos + this.x; + var localX2Sin = localX2 * sin; + var localY2Cos = localY2 * cos + this.y; + var localY2Sin = localY2 * sin; + var offset = this.offset; + offset[RegionAttachment.OX1] = localXCos - localYSin; + offset[RegionAttachment.OY1] = localYCos + localXSin; + offset[RegionAttachment.OX2] = localXCos - localY2Sin; + offset[RegionAttachment.OY2] = localY2Cos + localXSin; + offset[RegionAttachment.OX3] = localX2Cos - localY2Sin; + offset[RegionAttachment.OY3] = localY2Cos + localX2Sin; + offset[RegionAttachment.OX4] = localX2Cos - localYSin; + offset[RegionAttachment.OY4] = localYCos + localX2Sin; + }; + RegionAttachment.prototype.setRegion = function (region) { + this.region = region; + var uvs = this.uvs; + if (region.rotate) { + uvs[2] = region.u; + uvs[3] = region.v2; + uvs[4] = region.u; + uvs[5] = region.v; + uvs[6] = region.u2; + uvs[7] = region.v; + uvs[0] = region.u2; + uvs[1] = region.v2; + } + else { + uvs[0] = region.u; + uvs[1] = region.v2; + uvs[2] = region.u; + uvs[3] = region.v; + uvs[4] = region.u2; + uvs[5] = region.v; + uvs[6] = region.u2; + uvs[7] = region.v2; + } + }; + RegionAttachment.prototype.computeWorldVertices = function (bone, worldVertices, offset, stride) { + var vertexOffset = this.offset; + var x = bone.worldX, y = bone.worldY; + var a = bone.a, b = bone.b, c = bone.c, d = bone.d; + var offsetX = 0, offsetY = 0; + offsetX = vertexOffset[RegionAttachment.OX1]; + offsetY = vertexOffset[RegionAttachment.OY1]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[RegionAttachment.OX2]; + offsetY = vertexOffset[RegionAttachment.OY2]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[RegionAttachment.OX3]; + offsetY = vertexOffset[RegionAttachment.OY3]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[RegionAttachment.OX4]; + offsetY = vertexOffset[RegionAttachment.OY4]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + }; + RegionAttachment.OX1 = 0; + RegionAttachment.OY1 = 1; + RegionAttachment.OX2 = 2; + RegionAttachment.OY2 = 3; + RegionAttachment.OX3 = 4; + RegionAttachment.OY3 = 5; + RegionAttachment.OX4 = 6; + RegionAttachment.OY4 = 7; + RegionAttachment.X1 = 0; + RegionAttachment.Y1 = 1; + RegionAttachment.C1R = 2; + RegionAttachment.C1G = 3; + RegionAttachment.C1B = 4; + RegionAttachment.C1A = 5; + RegionAttachment.U1 = 6; + RegionAttachment.V1 = 7; + RegionAttachment.X2 = 8; + RegionAttachment.Y2 = 9; + RegionAttachment.C2R = 10; + RegionAttachment.C2G = 11; + RegionAttachment.C2B = 12; + RegionAttachment.C2A = 13; + RegionAttachment.U2 = 14; + RegionAttachment.V2 = 15; + RegionAttachment.X3 = 16; + RegionAttachment.Y3 = 17; + RegionAttachment.C3R = 18; + RegionAttachment.C3G = 19; + RegionAttachment.C3B = 20; + RegionAttachment.C3A = 21; + RegionAttachment.U3 = 22; + RegionAttachment.V3 = 23; + RegionAttachment.X4 = 24; + RegionAttachment.Y4 = 25; + RegionAttachment.C4R = 26; + RegionAttachment.C4G = 27; + RegionAttachment.C4B = 28; + RegionAttachment.C4A = 29; + RegionAttachment.U4 = 30; + RegionAttachment.V4 = 31; + return RegionAttachment; + }(spine.Attachment)); + spine.RegionAttachment = RegionAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var JitterEffect = (function () { + function JitterEffect(jitterX, jitterY) { + this.jitterX = 0; + this.jitterY = 0; + this.jitterX = jitterX; + this.jitterY = jitterY; + } + JitterEffect.prototype.begin = function (skeleton) { + }; + JitterEffect.prototype.transform = function (position, uv, light, dark) { + position.x += spine.MathUtils.randomTriangular(-this.jitterX, this.jitterY); + position.y += spine.MathUtils.randomTriangular(-this.jitterX, this.jitterY); + }; + JitterEffect.prototype.end = function () { + }; + return JitterEffect; + }()); + spine.JitterEffect = JitterEffect; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SwirlEffect = (function () { + function SwirlEffect(radius) { + this.centerX = 0; + this.centerY = 0; + this.radius = 0; + this.angle = 0; + this.worldX = 0; + this.worldY = 0; + this.radius = radius; + } + SwirlEffect.prototype.begin = function (skeleton) { + this.worldX = skeleton.x + this.centerX; + this.worldY = skeleton.y + this.centerY; + }; + SwirlEffect.prototype.transform = function (position, uv, light, dark) { + var radAngle = this.angle * spine.MathUtils.degreesToRadians; + var x = position.x - this.worldX; + var y = position.y - this.worldY; + var dist = Math.sqrt(x * x + y * y); + if (dist < this.radius) { + var theta = SwirlEffect.interpolation.apply(0, radAngle, (this.radius - dist) / this.radius); + var cos = Math.cos(theta); + var sin = Math.sin(theta); + position.x = cos * x - sin * y + this.worldX; + position.y = sin * x + cos * y + this.worldY; + } + }; + SwirlEffect.prototype.end = function () { + }; + SwirlEffect.interpolation = new spine.PowOut(2); + return SwirlEffect; + }()); + spine.SwirlEffect = SwirlEffect; +})(spine || (spine = {})); +var spine; +(function (spine) { + var canvas; + (function (canvas) { + var AssetManager = (function (_super) { + __extends(AssetManager, _super); + function AssetManager(pathPrefix) { + if (pathPrefix === void 0) { pathPrefix = ""; } + return _super.call(this, function (image) { return new spine.canvas.CanvasTexture(image); }, pathPrefix) || this; + } + return AssetManager; + }(spine.AssetManager)); + canvas.AssetManager = AssetManager; + })(canvas = spine.canvas || (spine.canvas = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var canvas; + (function (canvas) { + var CanvasTexture = (function (_super) { + __extends(CanvasTexture, _super); + function CanvasTexture(image) { + return _super.call(this, image) || this; + } + CanvasTexture.prototype.setFilters = function (minFilter, magFilter) { }; + CanvasTexture.prototype.setWraps = function (uWrap, vWrap) { }; + CanvasTexture.prototype.dispose = function () { }; + return CanvasTexture; + }(spine.Texture)); + canvas.CanvasTexture = CanvasTexture; + })(canvas = spine.canvas || (spine.canvas = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var canvas; + (function (canvas) { + var SkeletonRenderer = (function () { + function SkeletonRenderer(context) { + this.triangleRendering = false; + this.debugRendering = false; + this.vertices = spine.Utils.newFloatArray(8 * 1024); + this.tempColor = new spine.Color(); + this.ctx = context; + } + SkeletonRenderer.prototype.draw = function (skeleton) { + if (this.triangleRendering) + this.drawTriangles(skeleton); + else + this.drawImages(skeleton); + }; + SkeletonRenderer.prototype.drawImages = function (skeleton) { + var ctx = this.ctx; + var drawOrder = skeleton.drawOrder; + if (this.debugRendering) + ctx.strokeStyle = "green"; + ctx.save(); + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.getAttachment(); + var regionAttachment = null; + var region = null; + var image = null; + if (attachment instanceof spine.RegionAttachment) { + regionAttachment = attachment; + region = regionAttachment.region; + image = region.texture.getImage(); + } + else + continue; + var skeleton_1 = slot.bone.skeleton; + var skeletonColor = skeleton_1.color; + var slotColor = slot.color; + var regionColor = regionAttachment.color; + var alpha = skeletonColor.a * slotColor.a * regionColor.a; + var color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * regionColor.r, skeletonColor.g * slotColor.g * regionColor.g, skeletonColor.b * slotColor.b * regionColor.b, alpha); + var att = attachment; + var bone = slot.bone; + var w = region.width; + var h = region.height; + ctx.save(); + ctx.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY); + ctx.translate(attachment.offset[0], attachment.offset[1]); + ctx.rotate(attachment.rotation * Math.PI / 180); + var atlasScale = att.width / w; + ctx.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY); + ctx.translate(w / 2, h / 2); + if (attachment.region.rotate) { + var t = w; + w = h; + h = t; + ctx.rotate(-Math.PI / 2); + } + ctx.scale(1, -1); + ctx.translate(-w / 2, -h / 2); + if (color.r != 1 || color.g != 1 || color.b != 1 || color.a != 1) { + ctx.globalAlpha = color.a; + } + ctx.drawImage(image, region.x, region.y, w, h, 0, 0, w, h); + if (this.debugRendering) + ctx.strokeRect(0, 0, w, h); + ctx.restore(); + } + ctx.restore(); + }; + SkeletonRenderer.prototype.drawTriangles = function (skeleton) { + var blendMode = null; + var vertices = this.vertices; + var triangles = null; + var drawOrder = skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.getAttachment(); + var texture = null; + var region = null; + if (attachment instanceof spine.RegionAttachment) { + var regionAttachment = attachment; + vertices = this.computeRegionVertices(slot, regionAttachment, false); + triangles = SkeletonRenderer.QUAD_TRIANGLES; + region = regionAttachment.region; + texture = region.texture.getImage(); + } + else if (attachment instanceof spine.MeshAttachment) { + var mesh = attachment; + vertices = this.computeMeshVertices(slot, mesh, false); + triangles = mesh.triangles; + texture = mesh.region.renderObject.texture.getImage(); + } + else + continue; + if (texture != null) { + var slotBlendMode = slot.data.blendMode; + if (slotBlendMode != blendMode) { + blendMode = slotBlendMode; + } + var skeleton_2 = slot.bone.skeleton; + var skeletonColor = skeleton_2.color; + var slotColor = slot.color; + var attachmentColor = attachment.color; + var alpha = skeletonColor.a * slotColor.a * attachmentColor.a; + var color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * attachmentColor.r, skeletonColor.g * slotColor.g * attachmentColor.g, skeletonColor.b * slotColor.b * attachmentColor.b, alpha); + var ctx = this.ctx; + if (color.r != 1 || color.g != 1 || color.b != 1 || color.a != 1) { + ctx.globalAlpha = color.a; + } + for (var j = 0; j < triangles.length; j += 3) { + var t1 = triangles[j] * 8, t2 = triangles[j + 1] * 8, t3 = triangles[j + 2] * 8; + var x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7]; + var x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7]; + var x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7]; + this.drawTriangle(texture, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2); + if (this.debugRendering) { + ctx.strokeStyle = "green"; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.lineTo(x0, y0); + ctx.stroke(); + } + } + } + } + this.ctx.globalAlpha = 1; + }; + SkeletonRenderer.prototype.drawTriangle = function (img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2) { + var ctx = this.ctx; + u0 *= img.width; + v0 *= img.height; + u1 *= img.width; + v1 *= img.height; + u2 *= img.width; + v2 *= img.height; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.closePath(); + x1 -= x0; + y1 -= y0; + x2 -= x0; + y2 -= y0; + u1 -= u0; + v1 -= v0; + u2 -= u0; + v2 -= v0; + var det = 1 / (u1 * v2 - u2 * v1), a = (v2 * x1 - v1 * x2) * det, b = (v2 * y1 - v1 * y2) * det, c = (u1 * x2 - u2 * x1) * det, d = (u1 * y2 - u2 * y1) * det, e = x0 - a * u0 - c * v0, f = y0 - b * u0 - d * v0; + ctx.save(); + ctx.transform(a, b, c, d, e, f); + ctx.clip(); + ctx.drawImage(img, 0, 0); + ctx.restore(); + }; + SkeletonRenderer.prototype.computeRegionVertices = function (slot, region, pma) { + var skeleton = slot.bone.skeleton; + var skeletonColor = skeleton.color; + var slotColor = slot.color; + var regionColor = region.color; + var alpha = skeletonColor.a * slotColor.a * regionColor.a; + var multiplier = pma ? alpha : 1; + var color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier, skeletonColor.g * slotColor.g * regionColor.g * multiplier, skeletonColor.b * slotColor.b * regionColor.b * multiplier, alpha); + region.computeWorldVertices(slot.bone, this.vertices, 0, SkeletonRenderer.VERTEX_SIZE); + var vertices = this.vertices; + var uvs = region.uvs; + vertices[spine.RegionAttachment.C1R] = color.r; + vertices[spine.RegionAttachment.C1G] = color.g; + vertices[spine.RegionAttachment.C1B] = color.b; + vertices[spine.RegionAttachment.C1A] = color.a; + vertices[spine.RegionAttachment.U1] = uvs[0]; + vertices[spine.RegionAttachment.V1] = uvs[1]; + vertices[spine.RegionAttachment.C2R] = color.r; + vertices[spine.RegionAttachment.C2G] = color.g; + vertices[spine.RegionAttachment.C2B] = color.b; + vertices[spine.RegionAttachment.C2A] = color.a; + vertices[spine.RegionAttachment.U2] = uvs[2]; + vertices[spine.RegionAttachment.V2] = uvs[3]; + vertices[spine.RegionAttachment.C3R] = color.r; + vertices[spine.RegionAttachment.C3G] = color.g; + vertices[spine.RegionAttachment.C3B] = color.b; + vertices[spine.RegionAttachment.C3A] = color.a; + vertices[spine.RegionAttachment.U3] = uvs[4]; + vertices[spine.RegionAttachment.V3] = uvs[5]; + vertices[spine.RegionAttachment.C4R] = color.r; + vertices[spine.RegionAttachment.C4G] = color.g; + vertices[spine.RegionAttachment.C4B] = color.b; + vertices[spine.RegionAttachment.C4A] = color.a; + vertices[spine.RegionAttachment.U4] = uvs[6]; + vertices[spine.RegionAttachment.V4] = uvs[7]; + return vertices; + }; + SkeletonRenderer.prototype.computeMeshVertices = function (slot, mesh, pma) { + var skeleton = slot.bone.skeleton; + var skeletonColor = skeleton.color; + var slotColor = slot.color; + var regionColor = mesh.color; + var alpha = skeletonColor.a * slotColor.a * regionColor.a; + var multiplier = pma ? alpha : 1; + var color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier, skeletonColor.g * slotColor.g * regionColor.g * multiplier, skeletonColor.b * slotColor.b * regionColor.b * multiplier, alpha); + var numVertices = mesh.worldVerticesLength / 2; + if (this.vertices.length < mesh.worldVerticesLength) { + this.vertices = spine.Utils.newFloatArray(mesh.worldVerticesLength); + } + var vertices = this.vertices; + mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, SkeletonRenderer.VERTEX_SIZE); + var uvs = mesh.uvs; + for (var i = 0, n = numVertices, u = 0, v = 2; i < n; i++) { + vertices[v++] = color.r; + vertices[v++] = color.g; + vertices[v++] = color.b; + vertices[v++] = color.a; + vertices[v++] = uvs[u++]; + vertices[v++] = uvs[u++]; + v += 2; + } + return vertices; + }; + SkeletonRenderer.QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; + SkeletonRenderer.VERTEX_SIZE = 2 + 2 + 4; + return SkeletonRenderer; + }()); + canvas.SkeletonRenderer = SkeletonRenderer; + })(canvas = spine.canvas || (spine.canvas = {})); +})(spine || (spine = {})); +//# sourceMappingURL=spine-canvas.js.map \ No newline at end of file diff --git a/lib/3.7/spine-canvas.js b/lib/3.7/spine-canvas.js new file mode 100644 index 0000000..7288639 --- /dev/null +++ b/lib/3.7/spine-canvas.js @@ -0,0 +1,7117 @@ +var __extends = (this && this.__extends) || (function () { + var extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; + return function (d, b) { + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var spine; +(function (spine) { + var Animation = (function () { + function Animation(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.duration = duration; + } + Animation.prototype.apply = function (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; + } + var timelines = this.timelines; + for (var i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, lastTime, time, events, alpha, blend, direction); + }; + Animation.binarySearch = function (values, target, step) { + if (step === void 0) { step = 1; } + var low = 0; + var high = values.length / step - 2; + if (high == 0) + return step; + var 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; + } + }; + Animation.linearSearch = function (values, target, step) { + for (var i = 0, last = values.length - step; i <= last; i += step) + if (values[i] > target) + return i; + return -1; + }; + return Animation; + }()); + spine.Animation = Animation; + var MixBlend; + (function (MixBlend) { + MixBlend[MixBlend["setup"] = 0] = "setup"; + MixBlend[MixBlend["first"] = 1] = "first"; + MixBlend[MixBlend["replace"] = 2] = "replace"; + MixBlend[MixBlend["add"] = 3] = "add"; + })(MixBlend = spine.MixBlend || (spine.MixBlend = {})); + var MixDirection; + (function (MixDirection) { + MixDirection[MixDirection["in"] = 0] = "in"; + MixDirection[MixDirection["out"] = 1] = "out"; + })(MixDirection = spine.MixDirection || (spine.MixDirection = {})); + var TimelineType; + (function (TimelineType) { + TimelineType[TimelineType["rotate"] = 0] = "rotate"; + TimelineType[TimelineType["translate"] = 1] = "translate"; + TimelineType[TimelineType["scale"] = 2] = "scale"; + TimelineType[TimelineType["shear"] = 3] = "shear"; + TimelineType[TimelineType["attachment"] = 4] = "attachment"; + TimelineType[TimelineType["color"] = 5] = "color"; + TimelineType[TimelineType["deform"] = 6] = "deform"; + TimelineType[TimelineType["event"] = 7] = "event"; + TimelineType[TimelineType["drawOrder"] = 8] = "drawOrder"; + TimelineType[TimelineType["ikConstraint"] = 9] = "ikConstraint"; + TimelineType[TimelineType["transformConstraint"] = 10] = "transformConstraint"; + TimelineType[TimelineType["pathConstraintPosition"] = 11] = "pathConstraintPosition"; + TimelineType[TimelineType["pathConstraintSpacing"] = 12] = "pathConstraintSpacing"; + TimelineType[TimelineType["pathConstraintMix"] = 13] = "pathConstraintMix"; + TimelineType[TimelineType["twoColor"] = 14] = "twoColor"; + })(TimelineType = spine.TimelineType || (spine.TimelineType = {})); + var CurveTimeline = (function () { + function CurveTimeline(frameCount) { + if (frameCount <= 0) + throw new Error("frameCount must be > 0: " + frameCount); + this.curves = spine.Utils.newFloatArray((frameCount - 1) * CurveTimeline.BEZIER_SIZE); + } + CurveTimeline.prototype.getFrameCount = function () { + return this.curves.length / CurveTimeline.BEZIER_SIZE + 1; + }; + CurveTimeline.prototype.setLinear = function (frameIndex) { + this.curves[frameIndex * CurveTimeline.BEZIER_SIZE] = CurveTimeline.LINEAR; + }; + CurveTimeline.prototype.setStepped = function (frameIndex) { + this.curves[frameIndex * CurveTimeline.BEZIER_SIZE] = CurveTimeline.STEPPED; + }; + CurveTimeline.prototype.getCurveType = function (frameIndex) { + var index = frameIndex * CurveTimeline.BEZIER_SIZE; + if (index == this.curves.length) + return CurveTimeline.LINEAR; + var type = this.curves[index]; + if (type == CurveTimeline.LINEAR) + return CurveTimeline.LINEAR; + if (type == CurveTimeline.STEPPED) + return CurveTimeline.STEPPED; + return CurveTimeline.BEZIER; + }; + CurveTimeline.prototype.setCurve = function (frameIndex, cx1, cy1, cx2, cy2) { + var tmpx = (-cx1 * 2 + cx2) * 0.03, tmpy = (-cy1 * 2 + cy2) * 0.03; + var dddfx = ((cx1 - cx2) * 3 + 1) * 0.006, dddfy = ((cy1 - cy2) * 3 + 1) * 0.006; + var ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy; + var dfx = cx1 * 0.3 + tmpx + dddfx * 0.16666667, dfy = cy1 * 0.3 + tmpy + dddfy * 0.16666667; + var i = frameIndex * CurveTimeline.BEZIER_SIZE; + var curves = this.curves; + curves[i++] = CurveTimeline.BEZIER; + var x = dfx, y = dfy; + for (var 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; + } + }; + CurveTimeline.prototype.getCurvePercent = function (frameIndex, percent) { + percent = spine.MathUtils.clamp(percent, 0, 1); + var curves = this.curves; + var i = frameIndex * CurveTimeline.BEZIER_SIZE; + var type = curves[i]; + if (type == CurveTimeline.LINEAR) + return percent; + if (type == CurveTimeline.STEPPED) + return 0; + i++; + var x = 0; + for (var start = i, n = i + CurveTimeline.BEZIER_SIZE - 1; i < n; i += 2) { + x = curves[i]; + if (x >= percent) { + var prevX = void 0, prevY = void 0; + 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); + } + } + var y = curves[i - 1]; + return y + (1 - y) * (percent - x) / (1 - x); + }; + CurveTimeline.LINEAR = 0; + CurveTimeline.STEPPED = 1; + CurveTimeline.BEZIER = 2; + CurveTimeline.BEZIER_SIZE = 10 * 2 - 1; + return CurveTimeline; + }()); + spine.CurveTimeline = CurveTimeline; + var RotateTimeline = (function (_super) { + __extends(RotateTimeline, _super); + function RotateTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount << 1); + return _this; + } + RotateTimeline.prototype.getPropertyId = function () { + return (TimelineType.rotate << 24) + this.boneIndex; + }; + RotateTimeline.prototype.setFrame = function (frameIndex, time, degrees) { + frameIndex <<= 1; + this.frames[frameIndex] = time; + this.frames[frameIndex + RotateTimeline.ROTATION] = degrees; + }; + RotateTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { + var frames = this.frames; + var bone = skeleton.bones[this.boneIndex]; + if (time < frames[0]) { + switch (blend) { + case MixBlend.setup: + bone.rotation = bone.data.rotation; + return; + case MixBlend.first: + var r_1 = bone.data.rotation - bone.rotation; + bone.rotation += (r_1 - (16384 - ((16384.499999999996 - r_1 / 360) | 0)) * 360) * alpha; + } + return; + } + if (time >= frames[frames.length - RotateTimeline.ENTRIES]) { + var r_2 = frames[frames.length + RotateTimeline.PREV_ROTATION]; + switch (blend) { + case MixBlend.setup: + bone.rotation = bone.data.rotation + r_2 * alpha; + break; + case MixBlend.first: + case MixBlend.replace: + r_2 += bone.data.rotation - bone.rotation; + r_2 -= (16384 - ((16384.499999999996 - r_2 / 360) | 0)) * 360; + case MixBlend.add: + bone.rotation += r_2 * alpha; + } + return; + } + var frame = Animation.binarySearch(frames, time, RotateTimeline.ENTRIES); + var prevRotation = frames[frame + RotateTimeline.PREV_ROTATION]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + RotateTimeline.PREV_TIME] - frameTime)); + var 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; + return RotateTimeline; + }(CurveTimeline)); + spine.RotateTimeline = RotateTimeline; + var TranslateTimeline = (function (_super) { + __extends(TranslateTimeline, _super); + function TranslateTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * TranslateTimeline.ENTRIES); + return _this; + } + TranslateTimeline.prototype.getPropertyId = function () { + return (TimelineType.translate << 24) + this.boneIndex; + }; + TranslateTimeline.prototype.setFrame = function (frameIndex, time, x, y) { + frameIndex *= TranslateTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + TranslateTimeline.X] = x; + this.frames[frameIndex + TranslateTimeline.Y] = y; + }; + TranslateTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { + var frames = this.frames; + var bone = skeleton.bones[this.boneIndex]; + 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; + } + var x = 0, y = 0; + if (time >= frames[frames.length - TranslateTimeline.ENTRIES]) { + x = frames[frames.length + TranslateTimeline.PREV_X]; + y = frames[frames.length + TranslateTimeline.PREV_Y]; + } + else { + var frame = Animation.binarySearch(frames, time, TranslateTimeline.ENTRIES); + x = frames[frame + TranslateTimeline.PREV_X]; + y = frames[frame + TranslateTimeline.PREV_Y]; + var frameTime = frames[frame]; + var 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; + return TranslateTimeline; + }(CurveTimeline)); + spine.TranslateTimeline = TranslateTimeline; + var ScaleTimeline = (function (_super) { + __extends(ScaleTimeline, _super); + function ScaleTimeline(frameCount) { + return _super.call(this, frameCount) || this; + } + ScaleTimeline.prototype.getPropertyId = function () { + return (TimelineType.scale << 24) + this.boneIndex; + }; + ScaleTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { + var frames = this.frames; + var bone = skeleton.bones[this.boneIndex]; + 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; + } + var x = 0, y = 0; + if (time >= frames[frames.length - ScaleTimeline.ENTRIES]) { + x = frames[frames.length + ScaleTimeline.PREV_X] * bone.data.scaleX; + y = frames[frames.length + ScaleTimeline.PREV_Y] * bone.data.scaleY; + } + else { + var frame = Animation.binarySearch(frames, time, ScaleTimeline.ENTRIES); + x = frames[frame + ScaleTimeline.PREV_X]; + y = frames[frame + ScaleTimeline.PREV_Y]; + var frameTime = frames[frame]; + var 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 { + var bx = 0, by = 0; + if (direction == MixDirection.out) { + switch (blend) { + case MixBlend.setup: + bx = bone.data.scaleX; + by = bone.data.scaleY; + bone.scaleX = bx + (Math.abs(x) * spine.MathUtils.signum(bx) - bx) * alpha; + bone.scaleY = by + (Math.abs(y) * spine.MathUtils.signum(by) - by) * alpha; + break; + case MixBlend.first: + case MixBlend.replace: + bx = bone.scaleX; + by = bone.scaleY; + bone.scaleX = bx + (Math.abs(x) * spine.MathUtils.signum(bx) - bx) * alpha; + bone.scaleY = by + (Math.abs(y) * spine.MathUtils.signum(by) - by) * alpha; + break; + case MixBlend.add: + bx = bone.scaleX; + by = bone.scaleY; + bone.scaleX = bx + (Math.abs(x) * spine.MathUtils.signum(bx) - bone.data.scaleX) * alpha; + bone.scaleY = by + (Math.abs(y) * spine.MathUtils.signum(by) - bone.data.scaleY) * alpha; + } + } + else { + switch (blend) { + case MixBlend.setup: + bx = Math.abs(bone.data.scaleX) * spine.MathUtils.signum(x); + by = Math.abs(bone.data.scaleY) * spine.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) * spine.MathUtils.signum(x); + by = Math.abs(bone.scaleY) * spine.MathUtils.signum(y); + bone.scaleX = bx + (x - bx) * alpha; + bone.scaleY = by + (y - by) * alpha; + break; + case MixBlend.add: + bx = spine.MathUtils.signum(x); + by = spine.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; + } + } + } + }; + return ScaleTimeline; + }(TranslateTimeline)); + spine.ScaleTimeline = ScaleTimeline; + var ShearTimeline = (function (_super) { + __extends(ShearTimeline, _super); + function ShearTimeline(frameCount) { + return _super.call(this, frameCount) || this; + } + ShearTimeline.prototype.getPropertyId = function () { + return (TimelineType.shear << 24) + this.boneIndex; + }; + ShearTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { + var frames = this.frames; + var bone = skeleton.bones[this.boneIndex]; + 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; + } + var x = 0, y = 0; + if (time >= frames[frames.length - ShearTimeline.ENTRIES]) { + x = frames[frames.length + ShearTimeline.PREV_X]; + y = frames[frames.length + ShearTimeline.PREV_Y]; + } + else { + var frame = Animation.binarySearch(frames, time, ShearTimeline.ENTRIES); + x = frames[frame + ShearTimeline.PREV_X]; + y = frames[frame + ShearTimeline.PREV_Y]; + var frameTime = frames[frame]; + var 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; + } + }; + return ShearTimeline; + }(TranslateTimeline)); + spine.ShearTimeline = ShearTimeline; + var ColorTimeline = (function (_super) { + __extends(ColorTimeline, _super); + function ColorTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * ColorTimeline.ENTRIES); + return _this; + } + ColorTimeline.prototype.getPropertyId = function () { + return (TimelineType.color << 24) + this.slotIndex; + }; + ColorTimeline.prototype.setFrame = function (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; + }; + ColorTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { + var slot = skeleton.slots[this.slotIndex]; + var frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case MixBlend.setup: + slot.color.setFromColor(slot.data.color); + return; + case MixBlend.first: + var color = slot.color, 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; + } + var r = 0, g = 0, b = 0, a = 0; + if (time >= frames[frames.length - ColorTimeline.ENTRIES]) { + var 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 { + var 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]; + var frameTime = frames[frame]; + var 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 { + var 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; + return ColorTimeline; + }(CurveTimeline)); + spine.ColorTimeline = ColorTimeline; + var TwoColorTimeline = (function (_super) { + __extends(TwoColorTimeline, _super); + function TwoColorTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * TwoColorTimeline.ENTRIES); + return _this; + } + TwoColorTimeline.prototype.getPropertyId = function () { + return (TimelineType.twoColor << 24) + this.slotIndex; + }; + TwoColorTimeline.prototype.setFrame = function (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; + }; + TwoColorTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { + var slot = skeleton.slots[this.slotIndex]; + var 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: + var light = slot.color, dark = slot.darkColor, setupLight = slot.data.color, 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; + } + var r = 0, g = 0, b = 0, a = 0, r2 = 0, g2 = 0, b2 = 0; + if (time >= frames[frames.length - TwoColorTimeline.ENTRIES]) { + var 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 { + var 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]; + var frameTime = frames[frame]; + var 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 { + var light = slot.color, 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; + return TwoColorTimeline; + }(CurveTimeline)); + spine.TwoColorTimeline = TwoColorTimeline; + var AttachmentTimeline = (function () { + function AttachmentTimeline(frameCount) { + this.frames = spine.Utils.newFloatArray(frameCount); + this.attachmentNames = new Array(frameCount); + } + AttachmentTimeline.prototype.getPropertyId = function () { + return (TimelineType.attachment << 24) + this.slotIndex; + }; + AttachmentTimeline.prototype.getFrameCount = function () { + return this.frames.length; + }; + AttachmentTimeline.prototype.setFrame = function (frameIndex, time, attachmentName) { + this.frames[frameIndex] = time; + this.attachmentNames[frameIndex] = attachmentName; + }; + AttachmentTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { + var slot = skeleton.slots[this.slotIndex]; + if (direction == MixDirection.out && blend == MixBlend.setup) { + var attachmentName_1 = slot.data.attachmentName; + slot.setAttachment(attachmentName_1 == null ? null : skeleton.getAttachment(this.slotIndex, attachmentName_1)); + return; + } + var frames = this.frames; + if (time < frames[0]) { + if (blend == MixBlend.setup || blend == MixBlend.first) { + var attachmentName_2 = slot.data.attachmentName; + slot.setAttachment(attachmentName_2 == null ? null : skeleton.getAttachment(this.slotIndex, attachmentName_2)); + } + return; + } + var frameIndex = 0; + if (time >= frames[frames.length - 1]) + frameIndex = frames.length - 1; + else + frameIndex = Animation.binarySearch(frames, time, 1) - 1; + var attachmentName = this.attachmentNames[frameIndex]; + skeleton.slots[this.slotIndex] + .setAttachment(attachmentName == null ? null : skeleton.getAttachment(this.slotIndex, attachmentName)); + }; + return AttachmentTimeline; + }()); + spine.AttachmentTimeline = AttachmentTimeline; + var zeros = null; + var DeformTimeline = (function (_super) { + __extends(DeformTimeline, _super); + function DeformTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount); + _this.frameVertices = new Array(frameCount); + if (zeros == null) + zeros = spine.Utils.newFloatArray(64); + return _this; + } + DeformTimeline.prototype.getPropertyId = function () { + return (TimelineType.deform << 27) + +this.attachment.id + this.slotIndex; + }; + DeformTimeline.prototype.setFrame = function (frameIndex, time, vertices) { + this.frames[frameIndex] = time; + this.frameVertices[frameIndex] = vertices; + }; + DeformTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + var slot = skeleton.slots[this.slotIndex]; + var slotAttachment = slot.getAttachment(); + if (!(slotAttachment instanceof spine.VertexAttachment) || !slotAttachment.applyDeform(this.attachment)) + return; + var verticesArray = slot.attachmentVertices; + if (verticesArray.length == 0) + blend = MixBlend.setup; + var frameVertices = this.frameVertices; + var vertexCount = frameVertices[0].length; + var frames = this.frames; + if (time < frames[0]) { + var vertexAttachment = slotAttachment; + switch (blend) { + case MixBlend.setup: + verticesArray.length = 0; + return; + case MixBlend.first: + if (alpha == 1) { + verticesArray.length = 0; + break; + } + var vertices_1 = spine.Utils.setArraySize(verticesArray, vertexCount); + if (vertexAttachment.bones == null) { + var setupVertices = vertexAttachment.vertices; + for (var i = 0; i < vertexCount; i++) + vertices_1[i] += (setupVertices[i] - vertices_1[i]) * alpha; + } + else { + alpha = 1 - alpha; + for (var i = 0; i < vertexCount; i++) + vertices_1[i] *= alpha; + } + } + return; + } + var vertices = spine.Utils.setArraySize(verticesArray, vertexCount); + if (time >= frames[frames.length - 1]) { + var lastVertices = frameVertices[frames.length - 1]; + if (alpha == 1) { + if (blend == MixBlend.add) { + var vertexAttachment = slotAttachment; + if (vertexAttachment.bones == null) { + var setupVertices = vertexAttachment.vertices; + for (var i_1 = 0; i_1 < vertexCount; i_1++) { + vertices[i_1] += lastVertices[i_1] - setupVertices[i_1]; + } + } + else { + for (var i_2 = 0; i_2 < vertexCount; i_2++) + vertices[i_2] += lastVertices[i_2]; + } + } + else { + spine.Utils.arrayCopy(lastVertices, 0, vertices, 0, vertexCount); + } + } + else { + switch (blend) { + case MixBlend.setup: { + var vertexAttachment_1 = slotAttachment; + if (vertexAttachment_1.bones == null) { + var setupVertices = vertexAttachment_1.vertices; + for (var i_3 = 0; i_3 < vertexCount; i_3++) { + var setup = setupVertices[i_3]; + vertices[i_3] = setup + (lastVertices[i_3] - setup) * alpha; + } + } + else { + for (var i_4 = 0; i_4 < vertexCount; i_4++) + vertices[i_4] = lastVertices[i_4] * alpha; + } + break; + } + case MixBlend.first: + case MixBlend.replace: + for (var i_5 = 0; i_5 < vertexCount; i_5++) + vertices[i_5] += (lastVertices[i_5] - vertices[i_5]) * alpha; + case MixBlend.add: + var vertexAttachment = slotAttachment; + if (vertexAttachment.bones == null) { + var setupVertices = vertexAttachment.vertices; + for (var i_6 = 0; i_6 < vertexCount; i_6++) { + vertices[i_6] += (lastVertices[i_6] - setupVertices[i_6]) * alpha; + } + } + else { + for (var i_7 = 0; i_7 < vertexCount; i_7++) + vertices[i_7] += lastVertices[i_7] * alpha; + } + } + } + return; + } + var frame = Animation.binarySearch(frames, time); + var prevVertices = frameVertices[frame - 1]; + var nextVertices = frameVertices[frame]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime)); + if (alpha == 1) { + if (blend == MixBlend.add) { + var vertexAttachment = slotAttachment; + if (vertexAttachment.bones == null) { + var setupVertices = vertexAttachment.vertices; + for (var i_8 = 0; i_8 < vertexCount; i_8++) { + var prev = prevVertices[i_8]; + vertices[i_8] += prev + (nextVertices[i_8] - prev) * percent - setupVertices[i_8]; + } + } + else { + for (var i_9 = 0; i_9 < vertexCount; i_9++) { + var prev = prevVertices[i_9]; + vertices[i_9] += prev + (nextVertices[i_9] - prev) * percent; + } + } + } + else { + for (var i_10 = 0; i_10 < vertexCount; i_10++) { + var prev = prevVertices[i_10]; + vertices[i_10] = prev + (nextVertices[i_10] - prev) * percent; + } + } + } + else { + switch (blend) { + case MixBlend.setup: { + var vertexAttachment_2 = slotAttachment; + if (vertexAttachment_2.bones == null) { + var setupVertices = vertexAttachment_2.vertices; + for (var i_11 = 0; i_11 < vertexCount; i_11++) { + var prev = prevVertices[i_11], setup = setupVertices[i_11]; + vertices[i_11] = setup + (prev + (nextVertices[i_11] - prev) * percent - setup) * alpha; + } + } + else { + for (var i_12 = 0; i_12 < vertexCount; i_12++) { + var prev = prevVertices[i_12]; + vertices[i_12] = (prev + (nextVertices[i_12] - prev) * percent) * alpha; + } + } + break; + } + case MixBlend.first: + case MixBlend.replace: + for (var i_13 = 0; i_13 < vertexCount; i_13++) { + var prev = prevVertices[i_13]; + vertices[i_13] += (prev + (nextVertices[i_13] - prev) * percent - vertices[i_13]) * alpha; + } + break; + case MixBlend.add: + var vertexAttachment = slotAttachment; + if (vertexAttachment.bones == null) { + var setupVertices = vertexAttachment.vertices; + for (var i_14 = 0; i_14 < vertexCount; i_14++) { + var prev = prevVertices[i_14]; + vertices[i_14] += (prev + (nextVertices[i_14] - prev) * percent - setupVertices[i_14]) * alpha; + } + } + else { + for (var i_15 = 0; i_15 < vertexCount; i_15++) { + var prev = prevVertices[i_15]; + vertices[i_15] += (prev + (nextVertices[i_15] - prev) * percent) * alpha; + } + } + } + } + }; + return DeformTimeline; + }(CurveTimeline)); + spine.DeformTimeline = DeformTimeline; + var EventTimeline = (function () { + function EventTimeline(frameCount) { + this.frames = spine.Utils.newFloatArray(frameCount); + this.events = new Array(frameCount); + } + EventTimeline.prototype.getPropertyId = function () { + return TimelineType.event << 24; + }; + EventTimeline.prototype.getFrameCount = function () { + return this.frames.length; + }; + EventTimeline.prototype.setFrame = function (frameIndex, event) { + this.frames[frameIndex] = event.time; + this.events[frameIndex] = event; + }; + EventTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + if (firedEvents == null) + return; + var frames = this.frames; + var frameCount = this.frames.length; + if (lastTime > time) { + this.apply(skeleton, lastTime, Number.MAX_VALUE, firedEvents, alpha, blend, direction); + lastTime = -1; + } + else if (lastTime >= frames[frameCount - 1]) + return; + if (time < frames[0]) + return; + var frame = 0; + if (lastTime < frames[0]) + frame = 0; + else { + frame = Animation.binarySearch(frames, lastTime); + var frameTime = frames[frame]; + while (frame > 0) { + if (frames[frame - 1] != frameTime) + break; + frame--; + } + } + for (; frame < frameCount && time >= frames[frame]; frame++) + firedEvents.push(this.events[frame]); + }; + return EventTimeline; + }()); + spine.EventTimeline = EventTimeline; + var DrawOrderTimeline = (function () { + function DrawOrderTimeline(frameCount) { + this.frames = spine.Utils.newFloatArray(frameCount); + this.drawOrders = new Array(frameCount); + } + DrawOrderTimeline.prototype.getPropertyId = function () { + return TimelineType.drawOrder << 24; + }; + DrawOrderTimeline.prototype.getFrameCount = function () { + return this.frames.length; + }; + DrawOrderTimeline.prototype.setFrame = function (frameIndex, time, drawOrder) { + this.frames[frameIndex] = time; + this.drawOrders[frameIndex] = drawOrder; + }; + DrawOrderTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + var drawOrder = skeleton.drawOrder; + var slots = skeleton.slots; + if (direction == MixDirection.out && blend == MixBlend.setup) { + spine.Utils.arrayCopy(skeleton.slots, 0, skeleton.drawOrder, 0, skeleton.slots.length); + return; + } + var frames = this.frames; + if (time < frames[0]) { + if (blend == MixBlend.setup || blend == MixBlend.first) + spine.Utils.arrayCopy(skeleton.slots, 0, skeleton.drawOrder, 0, skeleton.slots.length); + return; + } + var frame = 0; + if (time >= frames[frames.length - 1]) + frame = frames.length - 1; + else + frame = Animation.binarySearch(frames, time) - 1; + var drawOrderToSetupIndex = this.drawOrders[frame]; + if (drawOrderToSetupIndex == null) + spine.Utils.arrayCopy(slots, 0, drawOrder, 0, slots.length); + else { + for (var i = 0, n = drawOrderToSetupIndex.length; i < n; i++) + drawOrder[i] = slots[drawOrderToSetupIndex[i]]; + } + }; + return DrawOrderTimeline; + }()); + spine.DrawOrderTimeline = DrawOrderTimeline; + var IkConstraintTimeline = (function (_super) { + __extends(IkConstraintTimeline, _super); + function IkConstraintTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * IkConstraintTimeline.ENTRIES); + return _this; + } + IkConstraintTimeline.prototype.getPropertyId = function () { + return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex; + }; + IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, bendDirection, compress, stretch) { + frameIndex *= IkConstraintTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + IkConstraintTimeline.MIX] = mix; + this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection; + this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0; + this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0; + }; + IkConstraintTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + var frames = this.frames; + var constraint = skeleton.ikConstraints[this.ikConstraintIndex]; + if (time < frames[0]) { + switch (blend) { + case MixBlend.setup: + constraint.mix = constraint.data.mix; + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + return; + case MixBlend.first: + constraint.mix += (constraint.data.mix - constraint.mix) * alpha; + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } + return; + } + if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) { + if (blend == MixBlend.setup) { + constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha; + if (direction == MixDirection.out) { + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } + else { + constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION]; + constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0; + constraint.stretch = frames[frames.length + IkConstraintTimeline.PREV_STRETCH] != 0; + } + } + else { + constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha; + if (direction == MixDirection["in"]) { + constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION]; + constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0; + constraint.stretch = frames[frames.length + IkConstraintTimeline.PREV_STRETCH] != 0; + } + } + return; + } + var frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES); + var mix = frames[frame + IkConstraintTimeline.PREV_MIX]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime)); + if (blend == MixBlend.setup) { + constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha; + if (direction == MixDirection.out) { + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } + else { + constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION]; + constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0; + constraint.stretch = frames[frame + IkConstraintTimeline.PREV_STRETCH] != 0; + } + } + else { + constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha; + if (direction == MixDirection["in"]) { + constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION]; + constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0; + constraint.stretch = frames[frame + IkConstraintTimeline.PREV_STRETCH] != 0; + } + } + }; + IkConstraintTimeline.ENTRIES = 5; + IkConstraintTimeline.PREV_TIME = -5; + IkConstraintTimeline.PREV_MIX = -4; + IkConstraintTimeline.PREV_BEND_DIRECTION = -3; + IkConstraintTimeline.PREV_COMPRESS = -2; + IkConstraintTimeline.PREV_STRETCH = -1; + IkConstraintTimeline.MIX = 1; + IkConstraintTimeline.BEND_DIRECTION = 2; + IkConstraintTimeline.COMPRESS = 3; + IkConstraintTimeline.STRETCH = 4; + return IkConstraintTimeline; + }(CurveTimeline)); + spine.IkConstraintTimeline = IkConstraintTimeline; + var TransformConstraintTimeline = (function (_super) { + __extends(TransformConstraintTimeline, _super); + function TransformConstraintTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * TransformConstraintTimeline.ENTRIES); + return _this; + } + TransformConstraintTimeline.prototype.getPropertyId = function () { + return (TimelineType.transformConstraint << 24) + this.transformConstraintIndex; + }; + TransformConstraintTimeline.prototype.setFrame = function (frameIndex, time, rotateMix, translateMix, scaleMix, shearMix) { + frameIndex *= TransformConstraintTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + TransformConstraintTimeline.ROTATE] = rotateMix; + this.frames[frameIndex + TransformConstraintTimeline.TRANSLATE] = translateMix; + this.frames[frameIndex + TransformConstraintTimeline.SCALE] = scaleMix; + this.frames[frameIndex + TransformConstraintTimeline.SHEAR] = shearMix; + }; + TransformConstraintTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + var frames = this.frames; + var constraint = skeleton.transformConstraints[this.transformConstraintIndex]; + if (time < frames[0]) { + var data = constraint.data; + switch (blend) { + case MixBlend.setup: + constraint.rotateMix = data.rotateMix; + constraint.translateMix = data.translateMix; + constraint.scaleMix = data.scaleMix; + constraint.shearMix = data.shearMix; + return; + case MixBlend.first: + constraint.rotateMix += (data.rotateMix - constraint.rotateMix) * alpha; + constraint.translateMix += (data.translateMix - constraint.translateMix) * alpha; + constraint.scaleMix += (data.scaleMix - constraint.scaleMix) * alpha; + constraint.shearMix += (data.shearMix - constraint.shearMix) * alpha; + } + return; + } + var rotate = 0, translate = 0, scale = 0, shear = 0; + if (time >= frames[frames.length - TransformConstraintTimeline.ENTRIES]) { + var i = frames.length; + rotate = frames[i + TransformConstraintTimeline.PREV_ROTATE]; + translate = frames[i + TransformConstraintTimeline.PREV_TRANSLATE]; + scale = frames[i + TransformConstraintTimeline.PREV_SCALE]; + shear = frames[i + TransformConstraintTimeline.PREV_SHEAR]; + } + else { + var frame = Animation.binarySearch(frames, time, TransformConstraintTimeline.ENTRIES); + rotate = frames[frame + TransformConstraintTimeline.PREV_ROTATE]; + translate = frames[frame + TransformConstraintTimeline.PREV_TRANSLATE]; + scale = frames[frame + TransformConstraintTimeline.PREV_SCALE]; + shear = frames[frame + TransformConstraintTimeline.PREV_SHEAR]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame / TransformConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + TransformConstraintTimeline.PREV_TIME] - frameTime)); + rotate += (frames[frame + TransformConstraintTimeline.ROTATE] - rotate) * percent; + translate += (frames[frame + TransformConstraintTimeline.TRANSLATE] - translate) * percent; + scale += (frames[frame + TransformConstraintTimeline.SCALE] - scale) * percent; + shear += (frames[frame + TransformConstraintTimeline.SHEAR] - shear) * percent; + } + if (blend == MixBlend.setup) { + var data = constraint.data; + constraint.rotateMix = data.rotateMix + (rotate - data.rotateMix) * alpha; + constraint.translateMix = data.translateMix + (translate - data.translateMix) * alpha; + constraint.scaleMix = data.scaleMix + (scale - data.scaleMix) * alpha; + constraint.shearMix = data.shearMix + (shear - data.shearMix) * alpha; + } + else { + constraint.rotateMix += (rotate - constraint.rotateMix) * alpha; + constraint.translateMix += (translate - constraint.translateMix) * alpha; + constraint.scaleMix += (scale - constraint.scaleMix) * alpha; + constraint.shearMix += (shear - constraint.shearMix) * alpha; + } + }; + TransformConstraintTimeline.ENTRIES = 5; + TransformConstraintTimeline.PREV_TIME = -5; + TransformConstraintTimeline.PREV_ROTATE = -4; + TransformConstraintTimeline.PREV_TRANSLATE = -3; + TransformConstraintTimeline.PREV_SCALE = -2; + TransformConstraintTimeline.PREV_SHEAR = -1; + TransformConstraintTimeline.ROTATE = 1; + TransformConstraintTimeline.TRANSLATE = 2; + TransformConstraintTimeline.SCALE = 3; + TransformConstraintTimeline.SHEAR = 4; + return TransformConstraintTimeline; + }(CurveTimeline)); + spine.TransformConstraintTimeline = TransformConstraintTimeline; + var PathConstraintPositionTimeline = (function (_super) { + __extends(PathConstraintPositionTimeline, _super); + function PathConstraintPositionTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * PathConstraintPositionTimeline.ENTRIES); + return _this; + } + PathConstraintPositionTimeline.prototype.getPropertyId = function () { + return (TimelineType.pathConstraintPosition << 24) + this.pathConstraintIndex; + }; + PathConstraintPositionTimeline.prototype.setFrame = function (frameIndex, time, value) { + frameIndex *= PathConstraintPositionTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + PathConstraintPositionTimeline.VALUE] = value; + }; + PathConstraintPositionTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + var frames = this.frames; + var constraint = skeleton.pathConstraints[this.pathConstraintIndex]; + if (time < frames[0]) { + switch (blend) { + case MixBlend.setup: + constraint.position = constraint.data.position; + return; + case MixBlend.first: + constraint.position += (constraint.data.position - constraint.position) * alpha; + } + return; + } + var position = 0; + if (time >= frames[frames.length - PathConstraintPositionTimeline.ENTRIES]) + position = frames[frames.length + PathConstraintPositionTimeline.PREV_VALUE]; + else { + var frame = Animation.binarySearch(frames, time, PathConstraintPositionTimeline.ENTRIES); + position = frames[frame + PathConstraintPositionTimeline.PREV_VALUE]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame / PathConstraintPositionTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PathConstraintPositionTimeline.PREV_TIME] - frameTime)); + position += (frames[frame + PathConstraintPositionTimeline.VALUE] - position) * percent; + } + if (blend == MixBlend.setup) + constraint.position = constraint.data.position + (position - constraint.data.position) * alpha; + else + constraint.position += (position - constraint.position) * alpha; + }; + PathConstraintPositionTimeline.ENTRIES = 2; + PathConstraintPositionTimeline.PREV_TIME = -2; + PathConstraintPositionTimeline.PREV_VALUE = -1; + PathConstraintPositionTimeline.VALUE = 1; + return PathConstraintPositionTimeline; + }(CurveTimeline)); + spine.PathConstraintPositionTimeline = PathConstraintPositionTimeline; + var PathConstraintSpacingTimeline = (function (_super) { + __extends(PathConstraintSpacingTimeline, _super); + function PathConstraintSpacingTimeline(frameCount) { + return _super.call(this, frameCount) || this; + } + PathConstraintSpacingTimeline.prototype.getPropertyId = function () { + return (TimelineType.pathConstraintSpacing << 24) + this.pathConstraintIndex; + }; + PathConstraintSpacingTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + var frames = this.frames; + var constraint = skeleton.pathConstraints[this.pathConstraintIndex]; + if (time < frames[0]) { + switch (blend) { + case MixBlend.setup: + constraint.spacing = constraint.data.spacing; + return; + case MixBlend.first: + constraint.spacing += (constraint.data.spacing - constraint.spacing) * alpha; + } + return; + } + var spacing = 0; + if (time >= frames[frames.length - PathConstraintSpacingTimeline.ENTRIES]) + spacing = frames[frames.length + PathConstraintSpacingTimeline.PREV_VALUE]; + else { + var frame = Animation.binarySearch(frames, time, PathConstraintSpacingTimeline.ENTRIES); + spacing = frames[frame + PathConstraintSpacingTimeline.PREV_VALUE]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame / PathConstraintSpacingTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PathConstraintSpacingTimeline.PREV_TIME] - frameTime)); + spacing += (frames[frame + PathConstraintSpacingTimeline.VALUE] - spacing) * percent; + } + if (blend == MixBlend.setup) + constraint.spacing = constraint.data.spacing + (spacing - constraint.data.spacing) * alpha; + else + constraint.spacing += (spacing - constraint.spacing) * alpha; + }; + return PathConstraintSpacingTimeline; + }(PathConstraintPositionTimeline)); + spine.PathConstraintSpacingTimeline = PathConstraintSpacingTimeline; + var PathConstraintMixTimeline = (function (_super) { + __extends(PathConstraintMixTimeline, _super); + function PathConstraintMixTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * PathConstraintMixTimeline.ENTRIES); + return _this; + } + PathConstraintMixTimeline.prototype.getPropertyId = function () { + return (TimelineType.pathConstraintMix << 24) + this.pathConstraintIndex; + }; + PathConstraintMixTimeline.prototype.setFrame = function (frameIndex, time, rotateMix, translateMix) { + frameIndex *= PathConstraintMixTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + PathConstraintMixTimeline.ROTATE] = rotateMix; + this.frames[frameIndex + PathConstraintMixTimeline.TRANSLATE] = translateMix; + }; + PathConstraintMixTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + var frames = this.frames; + var constraint = skeleton.pathConstraints[this.pathConstraintIndex]; + if (time < frames[0]) { + switch (blend) { + case MixBlend.setup: + constraint.rotateMix = constraint.data.rotateMix; + constraint.translateMix = constraint.data.translateMix; + return; + case MixBlend.first: + constraint.rotateMix += (constraint.data.rotateMix - constraint.rotateMix) * alpha; + constraint.translateMix += (constraint.data.translateMix - constraint.translateMix) * alpha; + } + return; + } + var rotate = 0, translate = 0; + if (time >= frames[frames.length - PathConstraintMixTimeline.ENTRIES]) { + rotate = frames[frames.length + PathConstraintMixTimeline.PREV_ROTATE]; + translate = frames[frames.length + PathConstraintMixTimeline.PREV_TRANSLATE]; + } + else { + var frame = Animation.binarySearch(frames, time, PathConstraintMixTimeline.ENTRIES); + rotate = frames[frame + PathConstraintMixTimeline.PREV_ROTATE]; + translate = frames[frame + PathConstraintMixTimeline.PREV_TRANSLATE]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame / PathConstraintMixTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PathConstraintMixTimeline.PREV_TIME] - frameTime)); + rotate += (frames[frame + PathConstraintMixTimeline.ROTATE] - rotate) * percent; + translate += (frames[frame + PathConstraintMixTimeline.TRANSLATE] - translate) * percent; + } + if (blend == MixBlend.setup) { + constraint.rotateMix = constraint.data.rotateMix + (rotate - constraint.data.rotateMix) * alpha; + constraint.translateMix = constraint.data.translateMix + (translate - constraint.data.translateMix) * alpha; + } + else { + constraint.rotateMix += (rotate - constraint.rotateMix) * alpha; + constraint.translateMix += (translate - constraint.translateMix) * alpha; + } + }; + PathConstraintMixTimeline.ENTRIES = 3; + PathConstraintMixTimeline.PREV_TIME = -3; + PathConstraintMixTimeline.PREV_ROTATE = -2; + PathConstraintMixTimeline.PREV_TRANSLATE = -1; + PathConstraintMixTimeline.ROTATE = 1; + PathConstraintMixTimeline.TRANSLATE = 2; + return PathConstraintMixTimeline; + }(CurveTimeline)); + spine.PathConstraintMixTimeline = PathConstraintMixTimeline; +})(spine || (spine = {})); +var spine; +(function (spine) { + var AnimationState = (function () { + function AnimationState(data) { + this.tracks = new Array(); + this.events = new Array(); + this.listeners = new Array(); + this.queue = new EventQueue(this); + this.propertyIDs = new spine.IntSet(); + this.animationsChanged = false; + this.timeScale = 1; + this.trackEntryPool = new spine.Pool(function () { return new TrackEntry(); }); + this.data = data; + } + AnimationState.prototype.update = function (delta) { + delta *= this.timeScale; + var tracks = this.tracks; + for (var i = 0, n = tracks.length; i < n; i++) { + var current = tracks[i]; + if (current == null) + continue; + current.animationLast = current.nextAnimationLast; + current.trackLast = current.nextTrackLast; + var currentDelta = delta * current.timeScale; + if (current.delay > 0) { + current.delay -= currentDelta; + if (current.delay > 0) + continue; + currentDelta = -current.delay; + current.delay = 0; + } + var next = current.next; + if (next != null) { + 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)) { + 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(); + }; + AnimationState.prototype.updateMixingFrom = function (to, delta) { + var from = to.mixingFrom; + if (from == null) + return true; + var finished = this.updateMixingFrom(from, delta); + from.animationLast = from.nextAnimationLast; + from.trackLast = from.nextTrackLast; + if (to.mixTime > 0 && to.mixTime >= to.mixDuration) { + 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; + }; + AnimationState.prototype.apply = function (skeleton) { + if (skeleton == null) + throw new Error("skeleton cannot be null."); + if (this.animationsChanged) + this._animationsChanged(); + var events = this.events; + var tracks = this.tracks; + var applied = false; + for (var i = 0, n = tracks.length; i < n; i++) { + var current = tracks[i]; + if (current == null || current.delay > 0) + continue; + applied = true; + var blend = i == 0 ? spine.MixBlend.first : current.mixBlend; + 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; + var animationLast = current.animationLast, animationTime = current.getAnimationTime(); + var timelineCount = current.animation.timelines.length; + var timelines = current.animation.timelines; + if ((i == 0 && mix == 1) || blend == spine.MixBlend.add) { + for (var ii = 0; ii < timelineCount; ii++) + timelines[ii].apply(skeleton, animationLast, animationTime, events, mix, blend, spine.MixDirection["in"]); + } + else { + var timelineMode = current.timelineMode; + var firstFrame = current.timelinesRotation.length == 0; + if (firstFrame) + spine.Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null); + var timelinesRotation = current.timelinesRotation; + for (var ii = 0; ii < timelineCount; ii++) { + var timeline = timelines[ii]; + var timelineBlend = timelineMode[ii] == AnimationState.SUBSEQUENT ? blend : spine.MixBlend.setup; + if (timeline instanceof spine.RotateTimeline) { + this.applyRotateTimeline(timeline, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame); + } + else { + spine.Utils.webkit602BugfixHelper(mix, blend); + timeline.apply(skeleton, animationLast, animationTime, events, mix, timelineBlend, spine.MixDirection["in"]); + } + } + } + this.queueEvents(current, animationTime); + events.length = 0; + current.nextAnimationLast = animationTime; + current.nextTrackLast = current.trackTime; + } + this.queue.drain(); + return applied; + }; + AnimationState.prototype.applyMixingFrom = function (to, skeleton, blend) { + var from = to.mixingFrom; + if (from.mixingFrom != null) + this.applyMixingFrom(from, skeleton, blend); + var mix = 0; + if (to.mixDuration == 0) { + mix = 1; + if (blend == spine.MixBlend.first) + blend = spine.MixBlend.setup; + } + else { + mix = to.mixTime / to.mixDuration; + if (mix > 1) + mix = 1; + if (blend != spine.MixBlend.first) + blend = from.mixBlend; + } + var events = mix < from.eventThreshold ? this.events : null; + var attachments = mix < from.attachmentThreshold, drawOrder = mix < from.drawOrderThreshold; + var animationLast = from.animationLast, animationTime = from.getAnimationTime(); + var timelineCount = from.animation.timelines.length; + var timelines = from.animation.timelines; + var alphaHold = from.alpha * to.interruptAlpha, alphaMix = alphaHold * (1 - mix); + if (blend == spine.MixBlend.add) { + for (var i = 0; i < timelineCount; i++) + timelines[i].apply(skeleton, animationLast, animationTime, events, alphaMix, blend, spine.MixDirection.out); + } + else { + var timelineMode = from.timelineMode; + var timelineHoldMix = from.timelineHoldMix; + var firstFrame = from.timelinesRotation.length == 0; + if (firstFrame) + spine.Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null); + var timelinesRotation = from.timelinesRotation; + from.totalAlpha = 0; + for (var i = 0; i < timelineCount; i++) { + var timeline = timelines[i]; + var direction = spine.MixDirection.out; + var timelineBlend = void 0; + var alpha = 0; + switch (timelineMode[i]) { + case AnimationState.SUBSEQUENT: + if (!attachments && timeline instanceof spine.AttachmentTimeline) + continue; + if (!drawOrder && timeline instanceof spine.DrawOrderTimeline) + continue; + timelineBlend = blend; + alpha = alphaMix; + break; + case AnimationState.FIRST: + timelineBlend = spine.MixBlend.setup; + alpha = alphaMix; + break; + case AnimationState.HOLD: + timelineBlend = spine.MixBlend.setup; + alpha = alphaHold; + break; + default: + timelineBlend = spine.MixBlend.setup; + var holdMix = timelineHoldMix[i]; + alpha = alphaHold * Math.max(0, 1 - holdMix.mixTime / holdMix.mixDuration); + break; + } + from.totalAlpha += alpha; + if (timeline instanceof spine.RotateTimeline) + this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame); + else { + spine.Utils.webkit602BugfixHelper(alpha, blend); + if (timelineBlend == spine.MixBlend.setup) { + if (timeline instanceof spine.AttachmentTimeline) { + if (attachments) + direction = spine.MixDirection.out; + } + else if (timeline instanceof spine.DrawOrderTimeline) { + if (drawOrder) + direction = spine.MixDirection.out; + } + } + 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; + }; + AnimationState.prototype.applyRotateTimeline = 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, spine.MixDirection["in"]); + return; + } + var rotateTimeline = timeline; + var frames = rotateTimeline.frames; + var bone = skeleton.bones[rotateTimeline.boneIndex]; + var r1 = 0, r2 = 0; + if (time < frames[0]) { + switch (blend) { + case spine.MixBlend.setup: + bone.rotation = bone.data.rotation; + default: + return; + case spine.MixBlend.first: + r1 = bone.rotation; + r2 = bone.data.rotation; + } + } + else { + r1 = blend == spine.MixBlend.setup ? bone.data.rotation : bone.rotation; + if (time >= frames[frames.length - spine.RotateTimeline.ENTRIES]) + r2 = bone.data.rotation + frames[frames.length + spine.RotateTimeline.PREV_ROTATION]; + else { + var frame = spine.Animation.binarySearch(frames, time, spine.RotateTimeline.ENTRIES); + var prevRotation = frames[frame + spine.RotateTimeline.PREV_ROTATION]; + var frameTime = frames[frame]; + var percent = rotateTimeline.getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + spine.RotateTimeline.PREV_TIME] - frameTime)); + r2 = frames[frame + spine.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; + } + } + var total = 0, diff = r2 - r1; + diff -= (16384 - ((16384.499999999996 - diff / 360) | 0)) * 360; + if (diff == 0) { + total = timelinesRotation[i]; + } + else { + var lastTotal = 0, lastDiff = 0; + if (firstFrame) { + lastTotal = 0; + lastDiff = diff; + } + else { + lastTotal = timelinesRotation[i]; + lastDiff = timelinesRotation[i + 1]; + } + var current = diff > 0, dir = lastTotal >= 0; + if (spine.MathUtils.signum(lastDiff) != spine.MathUtils.signum(diff) && Math.abs(lastDiff) <= 90) { + if (Math.abs(lastTotal) > 180) + lastTotal += 360 * spine.MathUtils.signum(lastTotal); + dir = current; + } + total = diff + lastTotal - lastTotal % 360; + if (dir != current) + total += 360 * spine.MathUtils.signum(lastTotal); + timelinesRotation[i] = total; + } + timelinesRotation[i + 1] = diff; + r1 += total * alpha; + bone.rotation = r1 - (16384 - ((16384.499999999996 - r1 / 360) | 0)) * 360; + }; + AnimationState.prototype.queueEvents = function (entry, animationTime) { + var animationStart = entry.animationStart, animationEnd = entry.animationEnd; + var duration = animationEnd - animationStart; + var trackLastWrapped = entry.trackLast % duration; + var events = this.events; + var i = 0, n = events.length; + for (; i < n; i++) { + var event_1 = events[i]; + if (event_1.time < trackLastWrapped) + break; + if (event_1.time > animationEnd) + continue; + this.queue.event(entry, event_1); + } + 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); + for (; i < n; i++) { + var event_2 = events[i]; + if (event_2.time < animationStart) + continue; + this.queue.event(entry, events[i]); + } + }; + AnimationState.prototype.clearTracks = function () { + 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(); + }; + AnimationState.prototype.clearTrack = function (trackIndex) { + if (trackIndex >= this.tracks.length) + return; + var current = this.tracks[trackIndex]; + if (current == null) + return; + this.queue.end(current); + this.disposeNext(current); + var entry = current; + while (true) { + 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(); + }; + AnimationState.prototype.setCurrent = function (index, current, interrupt) { + 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; + if (from.mixingFrom != null && from.mixDuration > 0) + current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration); + from.timelinesRotation.length = 0; + } + this.queue.start(current); + }; + AnimationState.prototype.setAnimation = function (trackIndex, animationName, loop) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (animation == null) + throw new Error("Animation not found: " + animationName); + return this.setAnimationWith(trackIndex, animation, loop); + }; + AnimationState.prototype.setAnimationWith = function (trackIndex, animation, loop) { + if (animation == null) + throw new Error("animation cannot be null."); + var interrupt = true; + var current = this.expandToIndex(trackIndex); + if (current != null) { + if (current.nextTrackLast == -1) { + 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); + } + var entry = this.trackEntry(trackIndex, animation, loop, current); + this.setCurrent(trackIndex, entry, interrupt); + this.queue.drain(); + return entry; + }; + AnimationState.prototype.addAnimation = function (trackIndex, animationName, loop, delay) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (animation == null) + throw new Error("Animation not found: " + animationName); + return this.addAnimationWith(trackIndex, animation, loop, delay); + }; + AnimationState.prototype.addAnimationWith = function (trackIndex, animation, loop, delay) { + if (animation == null) + throw new Error("animation cannot be null."); + var last = this.expandToIndex(trackIndex); + if (last != null) { + while (last.next != null) + last = last.next; + } + 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) { + 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; + }; + AnimationState.prototype.setEmptyAnimation = function (trackIndex, mixDuration) { + var entry = this.setAnimationWith(trackIndex, AnimationState.emptyAnimation, false); + entry.mixDuration = mixDuration; + entry.trackEnd = mixDuration; + return entry; + }; + AnimationState.prototype.addEmptyAnimation = function (trackIndex, mixDuration, delay) { + if (delay <= 0) + delay -= mixDuration; + var entry = this.addAnimationWith(trackIndex, AnimationState.emptyAnimation, false, delay); + entry.mixDuration = mixDuration; + entry.trackEnd = mixDuration; + return entry; + }; + AnimationState.prototype.setEmptyAnimations = function (mixDuration) { + var oldDrainDisabled = this.queue.drainDisabled; + this.queue.drainDisabled = true; + for (var i = 0, n = this.tracks.length; i < n; i++) { + var current = this.tracks[i]; + if (current != null) + this.setEmptyAnimation(current.trackIndex, mixDuration); + } + this.queue.drainDisabled = oldDrainDisabled; + this.queue.drain(); + }; + AnimationState.prototype.expandToIndex = function (index) { + if (index < this.tracks.length) + return this.tracks[index]; + spine.Utils.ensureArrayCapacity(this.tracks, index + 1, null); + this.tracks.length = index + 1; + return null; + }; + AnimationState.prototype.trackEntry = function (trackIndex, animation, loop, last) { + 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; + }; + AnimationState.prototype.disposeNext = function (entry) { + var next = entry.next; + while (next != null) { + this.queue.dispose(next); + next = next.next; + } + entry.next = null; + }; + AnimationState.prototype._animationsChanged = function () { + this.animationsChanged = false; + this.propertyIDs.clear(); + for (var i = 0, n = this.tracks.length; i < n; i++) { + var entry = this.tracks[i]; + if (entry == null) + continue; + while (entry.mixingFrom != null) + entry = entry.mixingFrom; + do { + if (entry.mixingFrom == null || entry.mixBlend != spine.MixBlend.add) + this.setTimelineModes(entry); + entry = entry.mixingTo; + } while (entry != null); + } + }; + AnimationState.prototype.setTimelineModes = function (entry) { + var to = entry.mixingTo; + var timelines = entry.animation.timelines; + var timelinesCount = entry.animation.timelines.length; + var timelineMode = spine.Utils.setArraySize(entry.timelineMode, timelinesCount); + entry.timelineHoldMix.length = 0; + var timelineDipMix = spine.Utils.setArraySize(entry.timelineHoldMix, timelinesCount); + 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++) { + var id = timelines[i].getPropertyId(); + if (!propertyIDs.add(id)) + timelineMode[i] = AnimationState.SUBSEQUENT; + else if (to == null || !this.hasTimeline(to, id)) + timelineMode[i] = AnimationState.FIRST; + else { + for (var next = to.mixingTo; next != null; next = next.mixingTo) { + if (this.hasTimeline(next, id)) + continue; + if (entry.mixDuration > 0) { + timelineMode[i] = AnimationState.HOLD_MIX; + timelineDipMix[i] = next; + continue outer; + } + break; + } + timelineMode[i] = AnimationState.HOLD; + } + } + }; + AnimationState.prototype.hasTimeline = function (entry, id) { + var timelines = entry.animation.timelines; + for (var i = 0, n = timelines.length; i < n; i++) + if (timelines[i].getPropertyId() == id) + return true; + return false; + }; + AnimationState.prototype.getCurrent = function (trackIndex) { + if (trackIndex >= this.tracks.length) + return null; + return this.tracks[trackIndex]; + }; + AnimationState.prototype.addListener = function (listener) { + if (listener == null) + throw new Error("listener cannot be null."); + this.listeners.push(listener); + }; + AnimationState.prototype.removeListener = function (listener) { + var index = this.listeners.indexOf(listener); + if (index >= 0) + this.listeners.splice(index, 1); + }; + AnimationState.prototype.clearListeners = function () { + this.listeners.length = 0; + }; + AnimationState.prototype.clearListenerNotifications = function () { + this.queue.clear(); + }; + AnimationState.emptyAnimation = new spine.Animation("", [], 0); + AnimationState.SUBSEQUENT = 0; + AnimationState.FIRST = 1; + AnimationState.HOLD = 2; + AnimationState.HOLD_MIX = 3; + return AnimationState; + }()); + spine.AnimationState = AnimationState; + var TrackEntry = (function () { + function TrackEntry() { + this.mixBlend = spine.MixBlend.replace; + this.timelineMode = new Array(); + this.timelineHoldMix = new Array(); + this.timelinesRotation = new Array(); + } + TrackEntry.prototype.reset = 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; + }; + TrackEntry.prototype.getAnimationTime = function () { + if (this.loop) { + 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); + }; + TrackEntry.prototype.setAnimationLast = function (animationLast) { + this.animationLast = animationLast; + this.nextAnimationLast = animationLast; + }; + TrackEntry.prototype.isComplete = function () { + return this.trackTime >= this.animationEnd - this.animationStart; + }; + TrackEntry.prototype.resetRotationDirections = function () { + this.timelinesRotation.length = 0; + }; + return TrackEntry; + }()); + spine.TrackEntry = TrackEntry; + var EventQueue = (function () { + function EventQueue(animState) { + this.objects = []; + this.drainDisabled = false; + this.animState = animState; + } + EventQueue.prototype.start = function (entry) { + this.objects.push(EventType.start); + this.objects.push(entry); + this.animState.animationsChanged = true; + }; + EventQueue.prototype.interrupt = function (entry) { + this.objects.push(EventType.interrupt); + this.objects.push(entry); + }; + EventQueue.prototype.end = function (entry) { + this.objects.push(EventType.end); + this.objects.push(entry); + this.animState.animationsChanged = true; + }; + EventQueue.prototype.dispose = function (entry) { + this.objects.push(EventType.dispose); + this.objects.push(entry); + }; + EventQueue.prototype.complete = function (entry) { + this.objects.push(EventType.complete); + this.objects.push(entry); + }; + EventQueue.prototype.event = function (entry, event) { + this.objects.push(EventType.event); + this.objects.push(entry); + this.objects.push(event); + }; + EventQueue.prototype.drain = function () { + if (this.drainDisabled) + return; + this.drainDisabled = true; + var objects = this.objects; + var listeners = this.animState.listeners; + for (var i = 0; i < objects.length; i += 2) { + var type = objects[i]; + var entry = 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); + 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: + var event_3 = 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; + }; + EventQueue.prototype.clear = function () { + this.objects.length = 0; + }; + return EventQueue; + }()); + spine.EventQueue = EventQueue; + var EventType; + (function (EventType) { + EventType[EventType["start"] = 0] = "start"; + EventType[EventType["interrupt"] = 1] = "interrupt"; + EventType[EventType["end"] = 2] = "end"; + EventType[EventType["dispose"] = 3] = "dispose"; + EventType[EventType["complete"] = 4] = "complete"; + EventType[EventType["event"] = 5] = "event"; + })(EventType = spine.EventType || (spine.EventType = {})); + var AnimationStateAdapter2 = (function () { + function AnimationStateAdapter2() { + } + AnimationStateAdapter2.prototype.start = function (entry) { + }; + AnimationStateAdapter2.prototype.interrupt = function (entry) { + }; + AnimationStateAdapter2.prototype.end = function (entry) { + }; + AnimationStateAdapter2.prototype.dispose = function (entry) { + }; + AnimationStateAdapter2.prototype.complete = function (entry) { + }; + AnimationStateAdapter2.prototype.event = function (entry, event) { + }; + return AnimationStateAdapter2; + }()); + spine.AnimationStateAdapter2 = AnimationStateAdapter2; +})(spine || (spine = {})); +var spine; +(function (spine) { + var AnimationStateData = (function () { + function AnimationStateData(skeletonData) { + this.animationToMixTime = {}; + this.defaultMix = 0; + if (skeletonData == null) + throw new Error("skeletonData cannot be null."); + this.skeletonData = skeletonData; + } + AnimationStateData.prototype.setMix = function (fromName, toName, duration) { + var from = this.skeletonData.findAnimation(fromName); + if (from == null) + throw new Error("Animation not found: " + fromName); + var to = this.skeletonData.findAnimation(toName); + if (to == null) + throw new Error("Animation not found: " + toName); + this.setMixWith(from, to, duration); + }; + AnimationStateData.prototype.setMixWith = function (from, to, duration) { + if (from == null) + throw new Error("from cannot be null."); + if (to == null) + throw new Error("to cannot be null."); + var key = from.name + "." + to.name; + this.animationToMixTime[key] = duration; + }; + AnimationStateData.prototype.getMix = function (from, to) { + var key = from.name + "." + to.name; + var value = this.animationToMixTime[key]; + return value === undefined ? this.defaultMix : value; + }; + return AnimationStateData; + }()); + spine.AnimationStateData = AnimationStateData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var AssetManager = (function () { + function AssetManager(textureLoader, pathPrefix) { + if (pathPrefix === void 0) { pathPrefix = ""; } + this.assets = {}; + this.errors = {}; + this.toLoad = 0; + this.loaded = 0; + this.textureLoader = textureLoader; + this.pathPrefix = pathPrefix; + } + AssetManager.downloadText = function (url, success, error) { + var request = new XMLHttpRequest(); + request.open("GET", url, true); + request.onload = function () { + if (request.status == 200) { + success(request.responseText); + } + else { + error(request.status, request.responseText); + } + }; + request.onerror = function () { + error(request.status, request.responseText); + }; + request.send(); + }; + AssetManager.downloadBinary = function (url, success, error) { + var request = new XMLHttpRequest(); + request.open("GET", url, true); + request.responseType = "arraybuffer"; + request.onload = function () { + if (request.status == 200) { + success(new Uint8Array(request.response)); + } + else { + error(request.status, request.responseText); + } + }; + request.onerror = function () { + error(request.status, request.responseText); + }; + request.send(); + }; + AssetManager.prototype.loadText = function (path, success, error) { + var _this = this; + if (success === void 0) { success = null; } + if (error === void 0) { error = null; } + path = this.pathPrefix + path; + this.toLoad++; + AssetManager.downloadText(path, function (data) { + _this.assets[path] = data; + if (success) + success(path, data); + _this.toLoad--; + _this.loaded++; + }, function (state, responseText) { + _this.errors[path] = "Couldn't load text " + path + ": status " + status + ", " + responseText; + if (error) + error(path, "Couldn't load text " + path + ": status " + status + ", " + responseText); + _this.toLoad--; + _this.loaded++; + }); + }; + AssetManager.prototype.loadTexture = function (path, success, error) { + var _this = this; + if (success === void 0) { success = null; } + if (error === void 0) { error = null; } + path = this.pathPrefix + path; + this.toLoad++; + var img = new Image(); + img.crossOrigin = "anonymous"; + img.onload = function (ev) { + var texture = _this.textureLoader(img); + _this.assets[path] = texture; + _this.toLoad--; + _this.loaded++; + if (success) + success(path, img); + }; + img.onerror = function (ev) { + _this.errors[path] = "Couldn't load image " + path; + _this.toLoad--; + _this.loaded++; + if (error) + error(path, "Couldn't load image " + path); + }; + img.src = path; + }; + AssetManager.prototype.loadTextureData = function (path, data, success, error) { + var _this = this; + if (success === void 0) { success = null; } + if (error === void 0) { error = null; } + path = this.pathPrefix + path; + this.toLoad++; + var img = new Image(); + img.onload = function (ev) { + var texture = _this.textureLoader(img); + _this.assets[path] = texture; + _this.toLoad--; + _this.loaded++; + if (success) + success(path, img); + }; + img.onerror = function (ev) { + _this.errors[path] = "Couldn't load image " + path; + _this.toLoad--; + _this.loaded++; + if (error) + error(path, "Couldn't load image " + path); + }; + img.src = data; + }; + AssetManager.prototype.loadTextureAtlas = function (path, success, error) { + var _this = this; + if (success === void 0) { success = null; } + if (error === void 0) { error = null; } + var parent = path.lastIndexOf("/") >= 0 ? path.substring(0, path.lastIndexOf("/")) : ""; + path = this.pathPrefix + path; + this.toLoad++; + AssetManager.downloadText(path, function (atlasData) { + var pagesLoaded = { count: 0 }; + var atlasPages = new Array(); + try { + var atlas = new spine.TextureAtlas(atlasData, function (path) { + atlasPages.push(parent + "/" + path); + var image = document.createElement("img"); + image.width = 16; + image.height = 16; + return new spine.FakeTexture(image); + }); + } + catch (e) { + var ex = e; + _this.errors[path] = "Couldn't load texture atlas " + path + ": " + ex.message; + if (error) + error(path, "Couldn't load texture atlas " + path + ": " + ex.message); + _this.toLoad--; + _this.loaded++; + return; + } + var _loop_1 = function (atlasPage) { + var pageLoadError = false; + _this.loadTexture(atlasPage, function (imagePath, image) { + pagesLoaded.count++; + if (pagesLoaded.count == atlasPages.length) { + if (!pageLoadError) { + try { + var atlas = new spine.TextureAtlas(atlasData, function (path) { + return _this.get(parent + "/" + path); + }); + _this.assets[path] = atlas; + if (success) + success(path, atlas); + _this.toLoad--; + _this.loaded++; + } + catch (e) { + var ex = e; + _this.errors[path] = "Couldn't load texture atlas " + path + ": " + ex.message; + if (error) + error(path, "Couldn't load texture atlas " + path + ": " + ex.message); + _this.toLoad--; + _this.loaded++; + } + } + else { + _this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path; + if (error) + error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path); + _this.toLoad--; + _this.loaded++; + } + } + }, function (imagePath, errorMessage) { + pageLoadError = true; + pagesLoaded.count++; + if (pagesLoaded.count == atlasPages.length) { + _this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path; + if (error) + error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path); + _this.toLoad--; + _this.loaded++; + } + }); + }; + for (var _i = 0, atlasPages_1 = atlasPages; _i < atlasPages_1.length; _i++) { + var atlasPage = atlasPages_1[_i]; + _loop_1(atlasPage); + } + }, function (state, responseText) { + _this.errors[path] = "Couldn't load texture atlas " + path + ": status " + status + ", " + responseText; + if (error) + error(path, "Couldn't load texture atlas " + path + ": status " + status + ", " + responseText); + _this.toLoad--; + _this.loaded++; + }); + }; + AssetManager.prototype.get = function (path) { + path = this.pathPrefix + path; + return this.assets[path]; + }; + AssetManager.prototype.remove = function (path) { + path = this.pathPrefix + path; + var asset = this.assets[path]; + if (asset.dispose) + asset.dispose(); + this.assets[path] = null; + }; + AssetManager.prototype.removeAll = function () { + for (var key in this.assets) { + var asset = this.assets[key]; + if (asset.dispose) + asset.dispose(); + } + this.assets = {}; + }; + AssetManager.prototype.isLoadingComplete = function () { + return this.toLoad == 0; + }; + AssetManager.prototype.getToLoad = function () { + return this.toLoad; + }; + AssetManager.prototype.getLoaded = function () { + return this.loaded; + }; + AssetManager.prototype.dispose = function () { + this.removeAll(); + }; + AssetManager.prototype.hasErrors = function () { + return Object.keys(this.errors).length > 0; + }; + AssetManager.prototype.getErrors = function () { + return this.errors; + }; + return AssetManager; + }()); + spine.AssetManager = AssetManager; +})(spine || (spine = {})); +var spine; +(function (spine) { + var AtlasAttachmentLoader = (function () { + function AtlasAttachmentLoader(atlas) { + this.atlas = atlas; + } + AtlasAttachmentLoader.prototype.newRegionAttachment = function (skin, name, path) { + var region = this.atlas.findRegion(path); + if (region == null) + throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")"); + region.renderObject = region; + var attachment = new spine.RegionAttachment(name); + attachment.setRegion(region); + return attachment; + }; + AtlasAttachmentLoader.prototype.newMeshAttachment = function (skin, name, path) { + var region = this.atlas.findRegion(path); + if (region == null) + throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); + region.renderObject = region; + var attachment = new spine.MeshAttachment(name); + attachment.region = region; + return attachment; + }; + AtlasAttachmentLoader.prototype.newBoundingBoxAttachment = function (skin, name) { + return new spine.BoundingBoxAttachment(name); + }; + AtlasAttachmentLoader.prototype.newPathAttachment = function (skin, name) { + return new spine.PathAttachment(name); + }; + AtlasAttachmentLoader.prototype.newPointAttachment = function (skin, name) { + return new spine.PointAttachment(name); + }; + AtlasAttachmentLoader.prototype.newClippingAttachment = function (skin, name) { + return new spine.ClippingAttachment(name); + }; + return AtlasAttachmentLoader; + }()); + spine.AtlasAttachmentLoader = AtlasAttachmentLoader; +})(spine || (spine = {})); +var spine; +(function (spine) { + var BlendMode; + (function (BlendMode) { + BlendMode[BlendMode["Normal"] = 0] = "Normal"; + BlendMode[BlendMode["Additive"] = 1] = "Additive"; + BlendMode[BlendMode["Multiply"] = 2] = "Multiply"; + BlendMode[BlendMode["Screen"] = 3] = "Screen"; + })(BlendMode = spine.BlendMode || (spine.BlendMode = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var Bone = (function () { + function Bone(data, skeleton, parent) { + this.children = new Array(); + this.x = 0; + this.y = 0; + this.rotation = 0; + this.scaleX = 0; + this.scaleY = 0; + this.shearX = 0; + this.shearY = 0; + this.ax = 0; + this.ay = 0; + this.arotation = 0; + this.ascaleX = 0; + this.ascaleY = 0; + this.ashearX = 0; + this.ashearY = 0; + this.appliedValid = false; + this.a = 0; + this.b = 0; + this.worldX = 0; + this.c = 0; + this.d = 0; + this.worldY = 0; + this.sorted = false; + if (data == null) + throw new Error("data cannot be null."); + if (skeleton == null) + throw new Error("skeleton cannot be null."); + this.data = data; + this.skeleton = skeleton; + this.parent = parent; + this.setToSetupPose(); + } + Bone.prototype.update = function () { + this.updateWorldTransformWith(this.x, this.y, this.rotation, this.scaleX, this.scaleY, this.shearX, this.shearY); + }; + Bone.prototype.updateWorldTransform = function () { + this.updateWorldTransformWith(this.x, this.y, this.rotation, this.scaleX, this.scaleY, this.shearX, this.shearY); + }; + Bone.prototype.updateWorldTransformWith = function (x, y, rotation, scaleX, scaleY, shearX, shearY) { + this.ax = x; + this.ay = y; + this.arotation = rotation; + this.ascaleX = scaleX; + this.ascaleY = scaleY; + this.ashearX = shearX; + this.ashearY = shearY; + this.appliedValid = true; + var parent = this.parent; + if (parent == null) { + var skeleton = this.skeleton; + var rotationY = rotation + 90 + shearY; + var sx = skeleton.scaleX; + var sy = skeleton.scaleY; + this.a = spine.MathUtils.cosDeg(rotation + shearX) * scaleX * sx; + this.b = spine.MathUtils.cosDeg(rotationY) * scaleY * sx; + this.c = spine.MathUtils.sinDeg(rotation + shearX) * scaleX * sy; + this.d = spine.MathUtils.sinDeg(rotationY) * scaleY * sy; + this.worldX = x * sx + skeleton.x; + this.worldY = y * sy + skeleton.y; + return; + } + var pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + this.worldX = pa * x + pb * y + parent.worldX; + this.worldY = pc * x + pd * y + parent.worldY; + switch (this.data.transformMode) { + case spine.TransformMode.Normal: { + var rotationY = rotation + 90 + shearY; + var la = spine.MathUtils.cosDeg(rotation + shearX) * scaleX; + var lb = spine.MathUtils.cosDeg(rotationY) * scaleY; + var lc = spine.MathUtils.sinDeg(rotation + shearX) * scaleX; + var ld = spine.MathUtils.sinDeg(rotationY) * scaleY; + this.a = pa * la + pb * lc; + this.b = pa * lb + pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + return; + } + case spine.TransformMode.OnlyTranslation: { + var rotationY = rotation + 90 + shearY; + this.a = spine.MathUtils.cosDeg(rotation + shearX) * scaleX; + this.b = spine.MathUtils.cosDeg(rotationY) * scaleY; + this.c = spine.MathUtils.sinDeg(rotation + shearX) * scaleX; + this.d = spine.MathUtils.sinDeg(rotationY) * scaleY; + break; + } + case spine.TransformMode.NoRotationOrReflection: { + var s = pa * pa + pc * pc; + var prx = 0; + if (s > 0.0001) { + s = Math.abs(pa * pd - pb * pc) / s; + pb = pc * s; + pd = pa * s; + prx = Math.atan2(pc, pa) * spine.MathUtils.radDeg; + } + else { + pa = 0; + pc = 0; + prx = 90 - Math.atan2(pd, pb) * spine.MathUtils.radDeg; + } + var rx = rotation + shearX - prx; + var ry = rotation + shearY - prx + 90; + var la = spine.MathUtils.cosDeg(rx) * scaleX; + var lb = spine.MathUtils.cosDeg(ry) * scaleY; + var lc = spine.MathUtils.sinDeg(rx) * scaleX; + var ld = spine.MathUtils.sinDeg(ry) * scaleY; + this.a = pa * la - pb * lc; + this.b = pa * lb - pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + break; + } + case spine.TransformMode.NoScale: + case spine.TransformMode.NoScaleOrReflection: { + var cos = spine.MathUtils.cosDeg(rotation); + var sin = spine.MathUtils.sinDeg(rotation); + var za = (pa * cos + pb * sin) / this.skeleton.scaleX; + var zc = (pc * cos + pd * sin) / this.skeleton.scaleY; + var s = Math.sqrt(za * za + zc * zc); + if (s > 0.00001) + s = 1 / s; + za *= s; + zc *= s; + s = Math.sqrt(za * za + zc * zc); + if (this.data.transformMode == spine.TransformMode.NoScale + && (pa * pd - pb * pc < 0) != (this.skeleton.scaleX < 0 != this.skeleton.scaleY < 0)) + s = -s; + var r = Math.PI / 2 + Math.atan2(zc, za); + var zb = Math.cos(r) * s; + var zd = Math.sin(r) * s; + var la = spine.MathUtils.cosDeg(shearX) * scaleX; + var lb = spine.MathUtils.cosDeg(90 + shearY) * scaleY; + var lc = spine.MathUtils.sinDeg(shearX) * scaleX; + var ld = spine.MathUtils.sinDeg(90 + shearY) * scaleY; + this.a = za * la + zb * lc; + this.b = za * lb + zb * ld; + this.c = zc * la + zd * lc; + this.d = zc * lb + zd * ld; + break; + } + } + this.a *= this.skeleton.scaleX; + this.b *= this.skeleton.scaleX; + this.c *= this.skeleton.scaleY; + this.d *= this.skeleton.scaleY; + }; + Bone.prototype.setToSetupPose = function () { + var data = this.data; + this.x = data.x; + this.y = data.y; + this.rotation = data.rotation; + this.scaleX = data.scaleX; + this.scaleY = data.scaleY; + this.shearX = data.shearX; + this.shearY = data.shearY; + }; + Bone.prototype.getWorldRotationX = function () { + return Math.atan2(this.c, this.a) * spine.MathUtils.radDeg; + }; + Bone.prototype.getWorldRotationY = function () { + return Math.atan2(this.d, this.b) * spine.MathUtils.radDeg; + }; + Bone.prototype.getWorldScaleX = function () { + return Math.sqrt(this.a * this.a + this.c * this.c); + }; + Bone.prototype.getWorldScaleY = function () { + return Math.sqrt(this.b * this.b + this.d * this.d); + }; + Bone.prototype.updateAppliedTransform = function () { + this.appliedValid = true; + var parent = this.parent; + if (parent == null) { + this.ax = this.worldX; + this.ay = this.worldY; + this.arotation = Math.atan2(this.c, this.a) * spine.MathUtils.radDeg; + this.ascaleX = Math.sqrt(this.a * this.a + this.c * this.c); + this.ascaleY = Math.sqrt(this.b * this.b + this.d * this.d); + this.ashearX = 0; + this.ashearY = Math.atan2(this.a * this.b + this.c * this.d, this.a * this.d - this.b * this.c) * spine.MathUtils.radDeg; + return; + } + var pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + var pid = 1 / (pa * pd - pb * pc); + var dx = this.worldX - parent.worldX, dy = this.worldY - parent.worldY; + this.ax = (dx * pd * pid - dy * pb * pid); + this.ay = (dy * pa * pid - dx * pc * pid); + var ia = pid * pd; + var id = pid * pa; + var ib = pid * pb; + var ic = pid * pc; + var ra = ia * this.a - ib * this.c; + var rb = ia * this.b - ib * this.d; + var rc = id * this.c - ic * this.a; + var rd = id * this.d - ic * this.b; + this.ashearX = 0; + this.ascaleX = Math.sqrt(ra * ra + rc * rc); + if (this.ascaleX > 0.0001) { + var det = ra * rd - rb * rc; + this.ascaleY = det / this.ascaleX; + this.ashearY = Math.atan2(ra * rb + rc * rd, det) * spine.MathUtils.radDeg; + this.arotation = Math.atan2(rc, ra) * spine.MathUtils.radDeg; + } + else { + this.ascaleX = 0; + this.ascaleY = Math.sqrt(rb * rb + rd * rd); + this.ashearY = 0; + this.arotation = 90 - Math.atan2(rd, rb) * spine.MathUtils.radDeg; + } + }; + Bone.prototype.worldToLocal = function (world) { + var a = this.a, b = this.b, c = this.c, d = this.d; + var invDet = 1 / (a * d - b * c); + var x = world.x - this.worldX, y = world.y - this.worldY; + world.x = (x * d * invDet - y * b * invDet); + world.y = (y * a * invDet - x * c * invDet); + return world; + }; + Bone.prototype.localToWorld = function (local) { + var x = local.x, y = local.y; + local.x = x * this.a + y * this.b + this.worldX; + local.y = x * this.c + y * this.d + this.worldY; + return local; + }; + Bone.prototype.worldToLocalRotation = function (worldRotation) { + var sin = spine.MathUtils.sinDeg(worldRotation), cos = spine.MathUtils.cosDeg(worldRotation); + return Math.atan2(this.a * sin - this.c * cos, this.d * cos - this.b * sin) * spine.MathUtils.radDeg + this.rotation - this.shearX; + }; + Bone.prototype.localToWorldRotation = function (localRotation) { + localRotation -= this.rotation - this.shearX; + var sin = spine.MathUtils.sinDeg(localRotation), cos = spine.MathUtils.cosDeg(localRotation); + return Math.atan2(cos * this.c + sin * this.d, cos * this.a + sin * this.b) * spine.MathUtils.radDeg; + }; + Bone.prototype.rotateWorld = function (degrees) { + var a = this.a, b = this.b, c = this.c, d = this.d; + var cos = spine.MathUtils.cosDeg(degrees), sin = spine.MathUtils.sinDeg(degrees); + this.a = cos * a - sin * c; + this.b = cos * b - sin * d; + this.c = sin * a + cos * c; + this.d = sin * b + cos * d; + this.appliedValid = false; + }; + return Bone; + }()); + spine.Bone = Bone; +})(spine || (spine = {})); +var spine; +(function (spine) { + var BoneData = (function () { + function BoneData(index, name, parent) { + this.x = 0; + this.y = 0; + this.rotation = 0; + this.scaleX = 1; + this.scaleY = 1; + this.shearX = 0; + this.shearY = 0; + this.transformMode = TransformMode.Normal; + if (index < 0) + throw new Error("index must be >= 0."); + if (name == null) + throw new Error("name cannot be null."); + this.index = index; + this.name = name; + this.parent = parent; + } + return BoneData; + }()); + spine.BoneData = BoneData; + var TransformMode; + (function (TransformMode) { + TransformMode[TransformMode["Normal"] = 0] = "Normal"; + TransformMode[TransformMode["OnlyTranslation"] = 1] = "OnlyTranslation"; + TransformMode[TransformMode["NoRotationOrReflection"] = 2] = "NoRotationOrReflection"; + TransformMode[TransformMode["NoScale"] = 3] = "NoScale"; + TransformMode[TransformMode["NoScaleOrReflection"] = 4] = "NoScaleOrReflection"; + })(TransformMode = spine.TransformMode || (spine.TransformMode = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var Event = (function () { + function Event(time, data) { + if (data == null) + throw new Error("data cannot be null."); + this.time = time; + this.data = data; + } + return Event; + }()); + spine.Event = Event; +})(spine || (spine = {})); +var spine; +(function (spine) { + var EventData = (function () { + function EventData(name) { + this.name = name; + } + return EventData; + }()); + spine.EventData = EventData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var IkConstraint = (function () { + function IkConstraint(data, skeleton) { + this.bendDirection = 0; + this.compress = false; + this.stretch = false; + this.mix = 1; + if (data == null) + throw new Error("data cannot be null."); + if (skeleton == null) + throw new Error("skeleton cannot be null."); + this.data = data; + this.mix = data.mix; + this.bendDirection = data.bendDirection; + this.compress = data.compress; + this.stretch = data.stretch; + this.bones = new Array(); + for (var i = 0; i < data.bones.length; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findBone(data.target.name); + } + IkConstraint.prototype.getOrder = function () { + return this.data.order; + }; + IkConstraint.prototype.apply = function () { + this.update(); + }; + IkConstraint.prototype.update = function () { + var target = this.target; + var bones = this.bones; + switch (bones.length) { + case 1: + this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix); + break; + case 2: + this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.mix); + break; + } + }; + IkConstraint.prototype.apply1 = function (bone, targetX, targetY, compress, stretch, uniform, alpha) { + if (!bone.appliedValid) + bone.updateAppliedTransform(); + var p = bone.parent; + var id = 1 / (p.a * p.d - p.b * p.c); + var x = targetX - p.worldX, y = targetY - p.worldY; + var tx = (x * p.d - y * p.b) * id - bone.ax, ty = (y * p.a - x * p.c) * id - bone.ay; + var rotationIK = Math.atan2(ty, tx) * spine.MathUtils.radDeg - bone.ashearX - bone.arotation; + if (bone.ascaleX < 0) + rotationIK += 180; + if (rotationIK > 180) + rotationIK -= 360; + else if (rotationIK < -180) + rotationIK += 360; + var sx = bone.ascaleX, sy = bone.ascaleY; + if (compress || stretch) { + var b = bone.data.length * sx, dd = Math.sqrt(tx * tx + ty * ty); + if ((compress && dd < b) || (stretch && dd > b) && b > 0.0001) { + var s = (dd / b - 1) * alpha + 1; + sx *= s; + if (uniform) + sy *= s; + } + } + bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY); + }; + IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, alpha) { + if (alpha == 0) { + child.updateWorldTransform(); + return; + } + if (!parent.appliedValid) + parent.updateAppliedTransform(); + if (!child.appliedValid) + child.updateAppliedTransform(); + var px = parent.ax, py = parent.ay, psx = parent.ascaleX, sx = psx, psy = parent.ascaleY, csx = child.ascaleX; + var os1 = 0, os2 = 0, s2 = 0; + if (psx < 0) { + psx = -psx; + os1 = 180; + s2 = -1; + } + else { + os1 = 0; + s2 = 1; + } + if (psy < 0) { + psy = -psy; + s2 = -s2; + } + if (csx < 0) { + csx = -csx; + os2 = 180; + } + else + os2 = 0; + var cx = child.ax, cy = 0, cwx = 0, cwy = 0, a = parent.a, b = parent.b, c = parent.c, d = parent.d; + var u = Math.abs(psx - psy) <= 0.0001; + if (!u) { + cy = 0; + cwx = a * cx + parent.worldX; + cwy = c * cx + parent.worldY; + } + else { + cy = child.ay; + cwx = a * cx + b * cy + parent.worldX; + cwy = c * cx + d * cy + parent.worldY; + } + var pp = parent.parent; + a = pp.a; + b = pp.b; + c = pp.c; + d = pp.d; + var id = 1 / (a * d - b * c), x = targetX - pp.worldX, y = targetY - pp.worldY; + var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py, dd = tx * tx + ty * ty; + x = cwx - pp.worldX; + y = cwy - pp.worldY; + var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; + var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1 = 0, a2 = 0; + outer: if (u) { + l2 *= psx; + var cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2); + if (cos < -1) + cos = -1; + else if (cos > 1) { + cos = 1; + if (stretch && l1 + l2 > 0.0001) + sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1; + } + a2 = Math.acos(cos) * bendDir; + a = l1 + l2 * cos; + b = l2 * Math.sin(a2); + a1 = Math.atan2(ty * a - tx * b, tx * a + ty * b); + } + else { + a = psx * l2; + b = psy * l2; + var aa = a * a, bb = b * b, ta = Math.atan2(ty, tx); + c = bb * l1 * l1 + aa * dd - aa * bb; + var c1 = -2 * bb * l1, c2 = bb - aa; + d = c1 * c1 - 4 * c2 * c; + if (d >= 0) { + var q = Math.sqrt(d); + if (c1 < 0) + q = -q; + q = -(c1 + q) / 2; + var r0 = q / c2, r1 = c / q; + var r = Math.abs(r0) < Math.abs(r1) ? r0 : r1; + if (r * r <= dd) { + y = Math.sqrt(dd - r * r) * bendDir; + a1 = ta - Math.atan2(y, r); + a2 = Math.atan2(y / psy, (r - l1) / psx); + break outer; + } + } + var minAngle = spine.MathUtils.PI, minX = l1 - a, minDist = minX * minX, minY = 0; + var maxAngle = 0, maxX = l1 + a, maxDist = maxX * maxX, maxY = 0; + c = -a * l1 / (aa - bb); + if (c >= -1 && c <= 1) { + c = Math.acos(c); + x = a * Math.cos(c) + l1; + y = b * Math.sin(c); + d = x * x + y * y; + if (d < minDist) { + minAngle = c; + minDist = d; + minX = x; + minY = y; + } + if (d > maxDist) { + maxAngle = c; + maxDist = d; + maxX = x; + maxY = y; + } + } + if (dd <= (minDist + maxDist) / 2) { + a1 = ta - Math.atan2(minY * bendDir, minX); + a2 = minAngle * bendDir; + } + else { + a1 = ta - Math.atan2(maxY * bendDir, maxX); + a2 = maxAngle * bendDir; + } + } + var os = Math.atan2(cy, cx) * s2; + var rotation = parent.arotation; + a1 = (a1 - os) * spine.MathUtils.radDeg + os1 - rotation; + if (a1 > 180) + a1 -= 360; + else if (a1 < -180) + a1 += 360; + parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, sx, parent.ascaleY, 0, 0); + rotation = child.arotation; + a2 = ((a2 + os) * spine.MathUtils.radDeg - child.ashearX) * s2 + os2 - rotation; + if (a2 > 180) + a2 -= 360; + else if (a2 < -180) + a2 += 360; + child.updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY); + }; + return IkConstraint; + }()); + spine.IkConstraint = IkConstraint; +})(spine || (spine = {})); +var spine; +(function (spine) { + var IkConstraintData = (function () { + function IkConstraintData(name) { + this.order = 0; + this.bones = new Array(); + this.bendDirection = 1; + this.compress = false; + this.stretch = false; + this.uniform = false; + this.mix = 1; + this.name = name; + } + return IkConstraintData; + }()); + spine.IkConstraintData = IkConstraintData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var PathConstraint = (function () { + function PathConstraint(data, skeleton) { + this.position = 0; + this.spacing = 0; + this.rotateMix = 0; + this.translateMix = 0; + this.spaces = new Array(); + this.positions = new Array(); + this.world = new Array(); + this.curves = new Array(); + this.lengths = new Array(); + this.segments = new Array(); + if (data == null) + throw new Error("data cannot be null."); + if (skeleton == null) + throw new Error("skeleton cannot be null."); + this.data = data; + this.bones = new Array(); + for (var i = 0, n = data.bones.length; i < n; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findSlot(data.target.name); + this.position = data.position; + this.spacing = data.spacing; + this.rotateMix = data.rotateMix; + this.translateMix = data.translateMix; + } + PathConstraint.prototype.apply = function () { + this.update(); + }; + PathConstraint.prototype.update = function () { + var attachment = this.target.getAttachment(); + if (!(attachment instanceof spine.PathAttachment)) + return; + var rotateMix = this.rotateMix, translateMix = this.translateMix; + var translate = translateMix > 0, rotate = rotateMix > 0; + if (!translate && !rotate) + return; + var data = this.data; + var percentSpacing = data.spacingMode == spine.SpacingMode.Percent; + var rotateMode = data.rotateMode; + var tangents = rotateMode == spine.RotateMode.Tangent, scale = rotateMode == spine.RotateMode.ChainScale; + var boneCount = this.bones.length, spacesCount = tangents ? boneCount : boneCount + 1; + var bones = this.bones; + var spaces = spine.Utils.setArraySize(this.spaces, spacesCount), lengths = null; + var spacing = this.spacing; + if (scale || !percentSpacing) { + if (scale) + lengths = spine.Utils.setArraySize(this.lengths, boneCount); + var lengthSpacing = data.spacingMode == spine.SpacingMode.Length; + for (var i = 0, n = spacesCount - 1; i < n;) { + var bone = bones[i]; + var setupLength = bone.data.length; + if (setupLength < PathConstraint.epsilon) { + if (scale) + lengths[i] = 0; + spaces[++i] = 0; + } + else if (percentSpacing) { + if (scale) { + var x = setupLength * bone.a, y = setupLength * bone.c; + var length_1 = Math.sqrt(x * x + y * y); + lengths[i] = length_1; + } + spaces[++i] = spacing; + } + else { + var x = setupLength * bone.a, y = setupLength * bone.c; + var length_2 = Math.sqrt(x * x + y * y); + if (scale) + lengths[i] = length_2; + spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length_2 / setupLength; + } + } + } + else { + for (var i = 1; i < spacesCount; i++) + spaces[i] = spacing; + } + var positions = this.computeWorldPositions(attachment, spacesCount, tangents, data.positionMode == spine.PositionMode.Percent, percentSpacing); + var boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation; + var tip = false; + if (offsetRotation == 0) + tip = rotateMode == spine.RotateMode.Chain; + else { + tip = false; + var p = this.target.bone; + offsetRotation *= p.a * p.d - p.b * p.c > 0 ? spine.MathUtils.degRad : -spine.MathUtils.degRad; + } + for (var i = 0, p = 3; i < boneCount; i++, p += 3) { + var bone = bones[i]; + bone.worldX += (boneX - bone.worldX) * translateMix; + bone.worldY += (boneY - bone.worldY) * translateMix; + var x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY; + if (scale) { + var length_3 = lengths[i]; + if (length_3 != 0) { + var s = (Math.sqrt(dx * dx + dy * dy) / length_3 - 1) * rotateMix + 1; + bone.a *= s; + bone.c *= s; + } + } + boneX = x; + boneY = y; + if (rotate) { + var a = bone.a, b = bone.b, c = bone.c, d = bone.d, r = 0, cos = 0, sin = 0; + if (tangents) + r = positions[p - 1]; + else if (spaces[i + 1] == 0) + r = positions[p + 2]; + else + r = Math.atan2(dy, dx); + r -= Math.atan2(c, a); + if (tip) { + cos = Math.cos(r); + sin = Math.sin(r); + var length_4 = bone.data.length; + boneX += (length_4 * (cos * a - sin * c) - dx) * rotateMix; + boneY += (length_4 * (sin * a + cos * c) - dy) * rotateMix; + } + else { + r += offsetRotation; + } + if (r > spine.MathUtils.PI) + r -= spine.MathUtils.PI2; + else if (r < -spine.MathUtils.PI) + r += spine.MathUtils.PI2; + r *= rotateMix; + cos = Math.cos(r); + sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + bone.appliedValid = false; + } + }; + PathConstraint.prototype.computeWorldPositions = function (path, spacesCount, tangents, percentPosition, percentSpacing) { + var target = this.target; + var position = this.position; + var spaces = this.spaces, out = spine.Utils.setArraySize(this.positions, spacesCount * 3 + 2), world = null; + var closed = path.closed; + var verticesLength = path.worldVerticesLength, curveCount = verticesLength / 6, prevCurve = PathConstraint.NONE; + if (!path.constantSpeed) { + var lengths = path.lengths; + curveCount -= closed ? 1 : 2; + var pathLength_1 = lengths[curveCount]; + if (percentPosition) + position *= pathLength_1; + if (percentSpacing) { + for (var i = 1; i < spacesCount; i++) + spaces[i] *= pathLength_1; + } + world = spine.Utils.setArraySize(this.world, 8); + for (var i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { + var space = spaces[i]; + position += space; + var p = position; + if (closed) { + p %= pathLength_1; + if (p < 0) + p += pathLength_1; + curve = 0; + } + else if (p < 0) { + if (prevCurve != PathConstraint.BEFORE) { + prevCurve = PathConstraint.BEFORE; + path.computeWorldVertices(target, 2, 4, world, 0, 2); + } + this.addBeforePosition(p, world, 0, out, o); + continue; + } + else if (p > pathLength_1) { + if (prevCurve != PathConstraint.AFTER) { + prevCurve = PathConstraint.AFTER; + path.computeWorldVertices(target, verticesLength - 6, 4, world, 0, 2); + } + this.addAfterPosition(p - pathLength_1, world, 0, out, o); + continue; + } + for (;; curve++) { + var length_5 = lengths[curve]; + if (p > length_5) + continue; + if (curve == 0) + p /= length_5; + else { + var prev = lengths[curve - 1]; + p = (p - prev) / (length_5 - prev); + } + break; + } + if (curve != prevCurve) { + prevCurve = curve; + if (closed && curve == curveCount) { + path.computeWorldVertices(target, verticesLength - 4, 4, world, 0, 2); + path.computeWorldVertices(target, 0, 4, world, 4, 2); + } + else + path.computeWorldVertices(target, curve * 6 + 2, 8, world, 0, 2); + } + this.addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], out, o, tangents || (i > 0 && space == 0)); + } + return out; + } + if (closed) { + verticesLength += 2; + world = spine.Utils.setArraySize(this.world, verticesLength); + path.computeWorldVertices(target, 2, verticesLength - 4, world, 0, 2); + path.computeWorldVertices(target, 0, 2, world, verticesLength - 4, 2); + world[verticesLength - 2] = world[0]; + world[verticesLength - 1] = world[1]; + } + else { + curveCount--; + verticesLength -= 4; + world = spine.Utils.setArraySize(this.world, verticesLength); + path.computeWorldVertices(target, 2, verticesLength, world, 0, 2); + } + var curves = spine.Utils.setArraySize(this.curves, curveCount); + var pathLength = 0; + var x1 = world[0], y1 = world[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0; + var tmpx = 0, tmpy = 0, dddfx = 0, dddfy = 0, ddfx = 0, ddfy = 0, dfx = 0, dfy = 0; + for (var i = 0, w = 2; i < curveCount; i++, w += 6) { + cx1 = world[w]; + cy1 = world[w + 1]; + cx2 = world[w + 2]; + cy2 = world[w + 3]; + x2 = world[w + 4]; + y2 = world[w + 5]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.1875; + tmpy = (y1 - cy1 * 2 + cy2) * 0.1875; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + curves[i] = pathLength; + x1 = x2; + y1 = y2; + } + if (percentPosition) + position *= pathLength; + else + position *= pathLength / path.lengths[curveCount - 1]; + if (percentSpacing) { + for (var i = 1; i < spacesCount; i++) + spaces[i] *= pathLength; + } + var segments = this.segments; + var curveLength = 0; + for (var i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { + var space = spaces[i]; + position += space; + var p = position; + if (closed) { + p %= pathLength; + if (p < 0) + p += pathLength; + curve = 0; + } + else if (p < 0) { + this.addBeforePosition(p, world, 0, out, o); + continue; + } + else if (p > pathLength) { + this.addAfterPosition(p - pathLength, world, verticesLength - 4, out, o); + continue; + } + for (;; curve++) { + var length_6 = curves[curve]; + if (p > length_6) + continue; + if (curve == 0) + p /= length_6; + else { + var prev = curves[curve - 1]; + p = (p - prev) / (length_6 - prev); + } + break; + } + if (curve != prevCurve) { + prevCurve = curve; + var ii = curve * 6; + x1 = world[ii]; + y1 = world[ii + 1]; + cx1 = world[ii + 2]; + cy1 = world[ii + 3]; + cx2 = world[ii + 4]; + cy2 = world[ii + 5]; + x2 = world[ii + 6]; + y2 = world[ii + 7]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.03; + tmpy = (y1 - cy1 * 2 + cy2) * 0.03; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667; + curveLength = Math.sqrt(dfx * dfx + dfy * dfy); + segments[0] = curveLength; + for (ii = 1; ii < 8; ii++) { + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[ii] = curveLength; + } + dfx += ddfx; + dfy += ddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[8] = curveLength; + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[9] = curveLength; + segment = 0; + } + p *= curveLength; + for (;; segment++) { + var length_7 = segments[segment]; + if (p > length_7) + continue; + if (segment == 0) + p /= length_7; + else { + var prev = segments[segment - 1]; + p = segment + (p - prev) / (length_7 - prev); + } + break; + } + this.addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || (i > 0 && space == 0)); + } + return out; + }; + PathConstraint.prototype.addBeforePosition = function (p, temp, i, out, o) { + var x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + }; + PathConstraint.prototype.addAfterPosition = function (p, temp, i, out, o) { + var x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + }; + PathConstraint.prototype.addCurvePosition = function (p, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents) { + if (p == 0 || isNaN(p)) { + out[o] = x1; + out[o + 1] = y1; + out[o + 2] = Math.atan2(cy1 - y1, cx1 - x1); + return; + } + var tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u; + var ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p; + var x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; + out[o] = x; + out[o + 1] = y; + if (tangents) { + if (p < 0.001) + out[o + 2] = Math.atan2(cy1 - y1, cx1 - x1); + else + out[o + 2] = Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); + } + }; + PathConstraint.prototype.getOrder = function () { + return this.data.order; + }; + PathConstraint.NONE = -1; + PathConstraint.BEFORE = -2; + PathConstraint.AFTER = -3; + PathConstraint.epsilon = 0.00001; + return PathConstraint; + }()); + spine.PathConstraint = PathConstraint; +})(spine || (spine = {})); +var spine; +(function (spine) { + var PathConstraintData = (function () { + function PathConstraintData(name) { + this.order = 0; + this.bones = new Array(); + this.name = name; + } + return PathConstraintData; + }()); + spine.PathConstraintData = PathConstraintData; + var PositionMode; + (function (PositionMode) { + PositionMode[PositionMode["Fixed"] = 0] = "Fixed"; + PositionMode[PositionMode["Percent"] = 1] = "Percent"; + })(PositionMode = spine.PositionMode || (spine.PositionMode = {})); + var SpacingMode; + (function (SpacingMode) { + SpacingMode[SpacingMode["Length"] = 0] = "Length"; + SpacingMode[SpacingMode["Fixed"] = 1] = "Fixed"; + SpacingMode[SpacingMode["Percent"] = 2] = "Percent"; + })(SpacingMode = spine.SpacingMode || (spine.SpacingMode = {})); + var RotateMode; + (function (RotateMode) { + RotateMode[RotateMode["Tangent"] = 0] = "Tangent"; + RotateMode[RotateMode["Chain"] = 1] = "Chain"; + RotateMode[RotateMode["ChainScale"] = 2] = "ChainScale"; + })(RotateMode = spine.RotateMode || (spine.RotateMode = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var Assets = (function () { + function Assets(clientId) { + this.toLoad = new Array(); + this.assets = {}; + this.clientId = clientId; + } + Assets.prototype.loaded = function () { + var i = 0; + for (var v in this.assets) + i++; + return i; + }; + return Assets; + }()); + var SharedAssetManager = (function () { + function SharedAssetManager(pathPrefix) { + if (pathPrefix === void 0) { pathPrefix = ""; } + this.clientAssets = {}; + this.queuedAssets = {}; + this.rawAssets = {}; + this.errors = {}; + this.pathPrefix = pathPrefix; + } + SharedAssetManager.prototype.queueAsset = function (clientId, textureLoader, path) { + var clientAssets = this.clientAssets[clientId]; + if (clientAssets === null || clientAssets === undefined) { + clientAssets = new Assets(clientId); + this.clientAssets[clientId] = clientAssets; + } + if (textureLoader !== null) + clientAssets.textureLoader = textureLoader; + clientAssets.toLoad.push(path); + if (this.queuedAssets[path] === path) { + return false; + } + else { + this.queuedAssets[path] = path; + return true; + } + }; + SharedAssetManager.prototype.loadText = function (clientId, path) { + var _this = this; + path = this.pathPrefix + path; + if (!this.queueAsset(clientId, null, path)) + return; + var request = new XMLHttpRequest(); + request.onreadystatechange = function () { + if (request.readyState == XMLHttpRequest.DONE) { + if (request.status >= 200 && request.status < 300) { + _this.rawAssets[path] = request.responseText; + } + else { + _this.errors[path] = "Couldn't load text " + path + ": status " + request.status + ", " + request.responseText; + } + } + }; + request.open("GET", path, true); + request.send(); + }; + SharedAssetManager.prototype.loadJson = function (clientId, path) { + var _this = this; + path = this.pathPrefix + path; + if (!this.queueAsset(clientId, null, path)) + return; + var request = new XMLHttpRequest(); + request.onreadystatechange = function () { + if (request.readyState == XMLHttpRequest.DONE) { + if (request.status >= 200 && request.status < 300) { + _this.rawAssets[path] = JSON.parse(request.responseText); + } + else { + _this.errors[path] = "Couldn't load text " + path + ": status " + request.status + ", " + request.responseText; + } + } + }; + request.open("GET", path, true); + request.send(); + }; + SharedAssetManager.prototype.loadTexture = function (clientId, textureLoader, path) { + var _this = this; + path = this.pathPrefix + path; + if (!this.queueAsset(clientId, textureLoader, path)) + return; + var img = new Image(); + img.src = path; + img.crossOrigin = "anonymous"; + img.onload = function (ev) { + _this.rawAssets[path] = img; + }; + img.onerror = function (ev) { + _this.errors[path] = "Couldn't load image " + path; + }; + }; + SharedAssetManager.prototype.get = function (clientId, path) { + path = this.pathPrefix + path; + var clientAssets = this.clientAssets[clientId]; + if (clientAssets === null || clientAssets === undefined) + return true; + return clientAssets.assets[path]; + }; + SharedAssetManager.prototype.updateClientAssets = function (clientAssets) { + for (var i = 0; i < clientAssets.toLoad.length; i++) { + var path = clientAssets.toLoad[i]; + var asset = clientAssets.assets[path]; + if (asset === null || asset === undefined) { + var rawAsset = this.rawAssets[path]; + if (rawAsset === null || rawAsset === undefined) + continue; + if (rawAsset instanceof HTMLImageElement) { + clientAssets.assets[path] = clientAssets.textureLoader(rawAsset); + } + else { + clientAssets.assets[path] = rawAsset; + } + } + } + }; + SharedAssetManager.prototype.isLoadingComplete = function (clientId) { + var clientAssets = this.clientAssets[clientId]; + if (clientAssets === null || clientAssets === undefined) + return true; + this.updateClientAssets(clientAssets); + return clientAssets.toLoad.length == clientAssets.loaded(); + }; + SharedAssetManager.prototype.dispose = function () { + }; + SharedAssetManager.prototype.hasErrors = function () { + return Object.keys(this.errors).length > 0; + }; + SharedAssetManager.prototype.getErrors = function () { + return this.errors; + }; + return SharedAssetManager; + }()); + spine.SharedAssetManager = SharedAssetManager; +})(spine || (spine = {})); +var spine; +(function (spine) { + var Skeleton = (function () { + function Skeleton(data) { + this._updateCache = new Array(); + this.updateCacheReset = new Array(); + this.time = 0; + this.scaleX = 1; + this.scaleY = 1; + this.x = 0; + this.y = 0; + if (data == null) + throw new Error("data cannot be null."); + this.data = data; + this.bones = new Array(); + for (var i = 0; i < data.bones.length; i++) { + var boneData = data.bones[i]; + var bone = void 0; + if (boneData.parent == null) + bone = new spine.Bone(boneData, this, null); + else { + var parent_1 = this.bones[boneData.parent.index]; + bone = new spine.Bone(boneData, this, parent_1); + parent_1.children.push(bone); + } + this.bones.push(bone); + } + this.slots = new Array(); + this.drawOrder = new Array(); + for (var i = 0; i < data.slots.length; i++) { + var slotData = data.slots[i]; + var bone = this.bones[slotData.boneData.index]; + var slot = new spine.Slot(slotData, bone); + this.slots.push(slot); + this.drawOrder.push(slot); + } + this.ikConstraints = new Array(); + for (var i = 0; i < data.ikConstraints.length; i++) { + var ikConstraintData = data.ikConstraints[i]; + this.ikConstraints.push(new spine.IkConstraint(ikConstraintData, this)); + } + this.transformConstraints = new Array(); + for (var i = 0; i < data.transformConstraints.length; i++) { + var transformConstraintData = data.transformConstraints[i]; + this.transformConstraints.push(new spine.TransformConstraint(transformConstraintData, this)); + } + this.pathConstraints = new Array(); + for (var i = 0; i < data.pathConstraints.length; i++) { + var pathConstraintData = data.pathConstraints[i]; + this.pathConstraints.push(new spine.PathConstraint(pathConstraintData, this)); + } + this.color = new spine.Color(1, 1, 1, 1); + this.updateCache(); + } + Skeleton.prototype.updateCache = function () { + var updateCache = this._updateCache; + updateCache.length = 0; + this.updateCacheReset.length = 0; + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + bones[i].sorted = false; + var ikConstraints = this.ikConstraints; + var transformConstraints = this.transformConstraints; + var pathConstraints = this.pathConstraints; + var ikCount = ikConstraints.length, transformCount = transformConstraints.length, pathCount = pathConstraints.length; + var constraintCount = ikCount + transformCount + pathCount; + outer: for (var i = 0; i < constraintCount; i++) { + for (var ii = 0; ii < ikCount; ii++) { + var constraint = ikConstraints[ii]; + if (constraint.data.order == i) { + this.sortIkConstraint(constraint); + continue outer; + } + } + for (var ii = 0; ii < transformCount; ii++) { + var constraint = transformConstraints[ii]; + if (constraint.data.order == i) { + this.sortTransformConstraint(constraint); + continue outer; + } + } + for (var ii = 0; ii < pathCount; ii++) { + var constraint = pathConstraints[ii]; + if (constraint.data.order == i) { + this.sortPathConstraint(constraint); + continue outer; + } + } + } + for (var i = 0, n = bones.length; i < n; i++) + this.sortBone(bones[i]); + }; + Skeleton.prototype.sortIkConstraint = function (constraint) { + var target = constraint.target; + this.sortBone(target); + var constrained = constraint.bones; + var parent = constrained[0]; + this.sortBone(parent); + if (constrained.length > 1) { + var child = constrained[constrained.length - 1]; + if (!(this._updateCache.indexOf(child) > -1)) + this.updateCacheReset.push(child); + } + this._updateCache.push(constraint); + this.sortReset(parent.children); + constrained[constrained.length - 1].sorted = true; + }; + Skeleton.prototype.sortPathConstraint = function (constraint) { + var slot = constraint.target; + var slotIndex = slot.data.index; + var slotBone = slot.bone; + if (this.skin != null) + this.sortPathConstraintAttachment(this.skin, slotIndex, slotBone); + if (this.data.defaultSkin != null && this.data.defaultSkin != this.skin) + this.sortPathConstraintAttachment(this.data.defaultSkin, slotIndex, slotBone); + for (var i = 0, n = this.data.skins.length; i < n; i++) + this.sortPathConstraintAttachment(this.data.skins[i], slotIndex, slotBone); + var attachment = slot.getAttachment(); + if (attachment instanceof spine.PathAttachment) + this.sortPathConstraintAttachmentWith(attachment, slotBone); + var constrained = constraint.bones; + var boneCount = constrained.length; + for (var i = 0; i < boneCount; i++) + this.sortBone(constrained[i]); + this._updateCache.push(constraint); + for (var i = 0; i < boneCount; i++) + this.sortReset(constrained[i].children); + for (var i = 0; i < boneCount; i++) + constrained[i].sorted = true; + }; + Skeleton.prototype.sortTransformConstraint = function (constraint) { + this.sortBone(constraint.target); + var constrained = constraint.bones; + var boneCount = constrained.length; + if (constraint.data.local) { + for (var i = 0; i < boneCount; i++) { + var child = constrained[i]; + this.sortBone(child.parent); + if (!(this._updateCache.indexOf(child) > -1)) + this.updateCacheReset.push(child); + } + } + else { + for (var i = 0; i < boneCount; i++) { + this.sortBone(constrained[i]); + } + } + this._updateCache.push(constraint); + for (var ii = 0; ii < boneCount; ii++) + this.sortReset(constrained[ii].children); + for (var ii = 0; ii < boneCount; ii++) + constrained[ii].sorted = true; + }; + Skeleton.prototype.sortPathConstraintAttachment = function (skin, slotIndex, slotBone) { + var attachments = skin.attachments[slotIndex]; + if (!attachments) + return; + for (var key in attachments) { + this.sortPathConstraintAttachmentWith(attachments[key], slotBone); + } + }; + Skeleton.prototype.sortPathConstraintAttachmentWith = function (attachment, slotBone) { + if (!(attachment instanceof spine.PathAttachment)) + return; + var pathBones = attachment.bones; + if (pathBones == null) + this.sortBone(slotBone); + else { + var bones = this.bones; + var i = 0; + while (i < pathBones.length) { + var boneCount = pathBones[i++]; + for (var n = i + boneCount; i < n; i++) { + var boneIndex = pathBones[i]; + this.sortBone(bones[boneIndex]); + } + } + } + }; + Skeleton.prototype.sortBone = function (bone) { + if (bone.sorted) + return; + var parent = bone.parent; + if (parent != null) + this.sortBone(parent); + bone.sorted = true; + this._updateCache.push(bone); + }; + Skeleton.prototype.sortReset = function (bones) { + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + if (bone.sorted) + this.sortReset(bone.children); + bone.sorted = false; + } + }; + Skeleton.prototype.updateWorldTransform = function () { + var updateCacheReset = this.updateCacheReset; + for (var i = 0, n = updateCacheReset.length; i < n; i++) { + var bone = updateCacheReset[i]; + bone.ax = bone.x; + bone.ay = bone.y; + bone.arotation = bone.rotation; + bone.ascaleX = bone.scaleX; + bone.ascaleY = bone.scaleY; + bone.ashearX = bone.shearX; + bone.ashearY = bone.shearY; + bone.appliedValid = true; + } + var updateCache = this._updateCache; + for (var i = 0, n = updateCache.length; i < n; i++) + updateCache[i].update(); + }; + Skeleton.prototype.setToSetupPose = function () { + this.setBonesToSetupPose(); + this.setSlotsToSetupPose(); + }; + Skeleton.prototype.setBonesToSetupPose = function () { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + bones[i].setToSetupPose(); + var ikConstraints = this.ikConstraints; + for (var i = 0, n = ikConstraints.length; i < n; i++) { + var constraint = ikConstraints[i]; + constraint.mix = constraint.data.mix; + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } + var transformConstraints = this.transformConstraints; + for (var i = 0, n = transformConstraints.length; i < n; i++) { + var constraint = transformConstraints[i]; + var data = constraint.data; + constraint.rotateMix = data.rotateMix; + constraint.translateMix = data.translateMix; + constraint.scaleMix = data.scaleMix; + constraint.shearMix = data.shearMix; + } + var pathConstraints = this.pathConstraints; + for (var i = 0, n = pathConstraints.length; i < n; i++) { + var constraint = pathConstraints[i]; + var data = constraint.data; + constraint.position = data.position; + constraint.spacing = data.spacing; + constraint.rotateMix = data.rotateMix; + constraint.translateMix = data.translateMix; + } + }; + Skeleton.prototype.setSlotsToSetupPose = function () { + var slots = this.slots; + spine.Utils.arrayCopy(slots, 0, this.drawOrder, 0, slots.length); + for (var i = 0, n = slots.length; i < n; i++) + slots[i].setToSetupPose(); + }; + Skeleton.prototype.getRootBone = function () { + if (this.bones.length == 0) + return null; + return this.bones[0]; + }; + Skeleton.prototype.findBone = function (boneName) { + if (boneName == null) + throw new Error("boneName cannot be null."); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + if (bone.data.name == boneName) + return bone; + } + return null; + }; + Skeleton.prototype.findBoneIndex = function (boneName) { + if (boneName == null) + throw new Error("boneName cannot be null."); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].data.name == boneName) + return i; + return -1; + }; + Skeleton.prototype.findSlot = function (slotName) { + if (slotName == null) + throw new Error("slotName cannot be null."); + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + var slot = slots[i]; + if (slot.data.name == slotName) + return slot; + } + return null; + }; + Skeleton.prototype.findSlotIndex = function (slotName) { + if (slotName == null) + throw new Error("slotName cannot be null."); + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].data.name == slotName) + return i; + return -1; + }; + Skeleton.prototype.setSkinByName = function (skinName) { + var skin = this.data.findSkin(skinName); + if (skin == null) + throw new Error("Skin not found: " + skinName); + this.setSkin(skin); + }; + Skeleton.prototype.setSkin = function (newSkin) { + if (newSkin != null) { + if (this.skin != null) + newSkin.attachAll(this, this.skin); + else { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + var slot = slots[i]; + var name_1 = slot.data.attachmentName; + if (name_1 != null) { + var attachment = newSkin.getAttachment(i, name_1); + if (attachment != null) + slot.setAttachment(attachment); + } + } + } + } + this.skin = newSkin; + }; + Skeleton.prototype.getAttachmentByName = function (slotName, attachmentName) { + return this.getAttachment(this.data.findSlotIndex(slotName), attachmentName); + }; + Skeleton.prototype.getAttachment = function (slotIndex, attachmentName) { + if (attachmentName == null) + throw new Error("attachmentName cannot be null."); + if (this.skin != null) { + var attachment = this.skin.getAttachment(slotIndex, attachmentName); + if (attachment != null) + return attachment; + } + if (this.data.defaultSkin != null) + return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); + return null; + }; + Skeleton.prototype.setAttachment = function (slotName, attachmentName) { + if (slotName == null) + throw new Error("slotName cannot be null."); + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + var slot = slots[i]; + if (slot.data.name == slotName) { + var attachment = null; + if (attachmentName != null) { + attachment = this.getAttachment(i, attachmentName); + if (attachment == null) + throw new Error("Attachment not found: " + attachmentName + ", for slot: " + slotName); + } + slot.setAttachment(attachment); + return; + } + } + throw new Error("Slot not found: " + slotName); + }; + Skeleton.prototype.findIkConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var ikConstraints = this.ikConstraints; + for (var i = 0, n = ikConstraints.length; i < n; i++) { + var ikConstraint = ikConstraints[i]; + if (ikConstraint.data.name == constraintName) + return ikConstraint; + } + return null; + }; + Skeleton.prototype.findTransformConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var transformConstraints = this.transformConstraints; + for (var i = 0, n = transformConstraints.length; i < n; i++) { + var constraint = transformConstraints[i]; + if (constraint.data.name == constraintName) + return constraint; + } + return null; + }; + Skeleton.prototype.findPathConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var pathConstraints = this.pathConstraints; + for (var i = 0, n = pathConstraints.length; i < n; i++) { + var constraint = pathConstraints[i]; + if (constraint.data.name == constraintName) + return constraint; + } + return null; + }; + Skeleton.prototype.getBounds = function (offset, size, temp) { + if (temp === void 0) { temp = new Array(2); } + if (offset == null) + throw new Error("offset cannot be null."); + if (size == null) + throw new Error("size cannot be null."); + var drawOrder = this.drawOrder; + var minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var verticesLength = 0; + var vertices = null; + var attachment = slot.getAttachment(); + if (attachment instanceof spine.RegionAttachment) { + verticesLength = 8; + vertices = spine.Utils.setArraySize(temp, verticesLength, 0); + attachment.computeWorldVertices(slot.bone, vertices, 0, 2); + } + else if (attachment instanceof spine.MeshAttachment) { + var mesh = attachment; + verticesLength = mesh.worldVerticesLength; + vertices = spine.Utils.setArraySize(temp, verticesLength, 0); + mesh.computeWorldVertices(slot, 0, verticesLength, vertices, 0, 2); + } + if (vertices != null) { + for (var ii = 0, nn = vertices.length; ii < nn; ii += 2) { + var x = vertices[ii], y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + } + offset.set(minX, minY); + size.set(maxX - minX, maxY - minY); + }; + Skeleton.prototype.update = function (delta) { + this.time += delta; + }; + return Skeleton; + }()); + spine.Skeleton = Skeleton; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SkeletonBounds = (function () { + function SkeletonBounds() { + this.minX = 0; + this.minY = 0; + this.maxX = 0; + this.maxY = 0; + this.boundingBoxes = new Array(); + this.polygons = new Array(); + this.polygonPool = new spine.Pool(function () { + return spine.Utils.newFloatArray(16); + }); + } + SkeletonBounds.prototype.update = function (skeleton, updateAabb) { + if (skeleton == null) + throw new Error("skeleton cannot be null."); + var boundingBoxes = this.boundingBoxes; + var polygons = this.polygons; + var polygonPool = this.polygonPool; + var slots = skeleton.slots; + var slotCount = slots.length; + boundingBoxes.length = 0; + polygonPool.freeAll(polygons); + polygons.length = 0; + for (var i = 0; i < slotCount; i++) { + var slot = slots[i]; + var attachment = slot.getAttachment(); + if (attachment instanceof spine.BoundingBoxAttachment) { + var boundingBox = attachment; + boundingBoxes.push(boundingBox); + var polygon = polygonPool.obtain(); + if (polygon.length != boundingBox.worldVerticesLength) { + polygon = spine.Utils.newFloatArray(boundingBox.worldVerticesLength); + } + polygons.push(polygon); + boundingBox.computeWorldVertices(slot, 0, boundingBox.worldVerticesLength, polygon, 0, 2); + } + } + if (updateAabb) { + this.aabbCompute(); + } + else { + this.minX = Number.POSITIVE_INFINITY; + this.minY = Number.POSITIVE_INFINITY; + this.maxX = Number.NEGATIVE_INFINITY; + this.maxY = Number.NEGATIVE_INFINITY; + } + }; + SkeletonBounds.prototype.aabbCompute = function () { + var minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + var polygons = this.polygons; + for (var i = 0, n = polygons.length; i < n; i++) { + var polygon = polygons[i]; + var vertices = polygon; + for (var ii = 0, nn = polygon.length; ii < nn; ii += 2) { + var x = vertices[ii]; + var y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + }; + SkeletonBounds.prototype.aabbContainsPoint = function (x, y) { + return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY; + }; + SkeletonBounds.prototype.aabbIntersectsSegment = function (x1, y1, x2, y2) { + var minX = this.minX; + var minY = this.minY; + var maxX = this.maxX; + var maxY = this.maxY; + if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) + return false; + var m = (y2 - y1) / (x2 - x1); + var y = m * (minX - x1) + y1; + if (y > minY && y < maxY) + return true; + y = m * (maxX - x1) + y1; + if (y > minY && y < maxY) + return true; + var x = (minY - y1) / m + x1; + if (x > minX && x < maxX) + return true; + x = (maxY - y1) / m + x1; + if (x > minX && x < maxX) + return true; + return false; + }; + SkeletonBounds.prototype.aabbIntersectsSkeleton = function (bounds) { + return this.minX < bounds.maxX && this.maxX > bounds.minX && this.minY < bounds.maxY && this.maxY > bounds.minY; + }; + SkeletonBounds.prototype.containsPoint = function (x, y) { + var polygons = this.polygons; + for (var i = 0, n = polygons.length; i < n; i++) + if (this.containsPointPolygon(polygons[i], x, y)) + return this.boundingBoxes[i]; + return null; + }; + SkeletonBounds.prototype.containsPointPolygon = function (polygon, x, y) { + var vertices = polygon; + var nn = polygon.length; + var prevIndex = nn - 2; + var inside = false; + for (var ii = 0; ii < nn; ii += 2) { + var vertexY = vertices[ii + 1]; + var prevY = vertices[prevIndex + 1]; + if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { + var vertexX = vertices[ii]; + if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) + inside = !inside; + } + prevIndex = ii; + } + return inside; + }; + SkeletonBounds.prototype.intersectsSegment = function (x1, y1, x2, y2) { + var polygons = this.polygons; + for (var i = 0, n = polygons.length; i < n; i++) + if (this.intersectsSegmentPolygon(polygons[i], x1, y1, x2, y2)) + return this.boundingBoxes[i]; + return null; + }; + SkeletonBounds.prototype.intersectsSegmentPolygon = function (polygon, x1, y1, x2, y2) { + var vertices = polygon; + var nn = polygon.length; + var width12 = x1 - x2, height12 = y1 - y2; + var det1 = x1 * y2 - y1 * x2; + var x3 = vertices[nn - 2], y3 = vertices[nn - 1]; + for (var ii = 0; ii < nn; ii += 2) { + var x4 = vertices[ii], y4 = vertices[ii + 1]; + var det2 = x3 * y4 - y3 * x4; + var width34 = x3 - x4, height34 = y3 - y4; + var det3 = width12 * height34 - height12 * width34; + var x = (det1 * width34 - width12 * det2) / det3; + if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { + var y = (det1 * height34 - height12 * det2) / det3; + if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) + return true; + } + x3 = x4; + y3 = y4; + } + return false; + }; + SkeletonBounds.prototype.getPolygon = function (boundingBox) { + if (boundingBox == null) + throw new Error("boundingBox cannot be null."); + var index = this.boundingBoxes.indexOf(boundingBox); + return index == -1 ? null : this.polygons[index]; + }; + SkeletonBounds.prototype.getWidth = function () { + return this.maxX - this.minX; + }; + SkeletonBounds.prototype.getHeight = function () { + return this.maxY - this.minY; + }; + return SkeletonBounds; + }()); + spine.SkeletonBounds = SkeletonBounds; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SkeletonClipping = (function () { + function SkeletonClipping() { + this.triangulator = new spine.Triangulator(); + this.clippingPolygon = new Array(); + this.clipOutput = new Array(); + this.clippedVertices = new Array(); + this.clippedTriangles = new Array(); + this.scratch = new Array(); + } + SkeletonClipping.prototype.clipStart = function (slot, clip) { + if (this.clipAttachment != null) + return 0; + this.clipAttachment = clip; + var n = clip.worldVerticesLength; + var vertices = spine.Utils.setArraySize(this.clippingPolygon, n); + clip.computeWorldVertices(slot, 0, n, vertices, 0, 2); + var clippingPolygon = this.clippingPolygon; + SkeletonClipping.makeClockwise(clippingPolygon); + var clippingPolygons = this.clippingPolygons = this.triangulator.decompose(clippingPolygon, this.triangulator.triangulate(clippingPolygon)); + for (var i = 0, n_1 = clippingPolygons.length; i < n_1; i++) { + var polygon = clippingPolygons[i]; + SkeletonClipping.makeClockwise(polygon); + polygon.push(polygon[0]); + polygon.push(polygon[1]); + } + return clippingPolygons.length; + }; + SkeletonClipping.prototype.clipEndWithSlot = function (slot) { + if (this.clipAttachment != null && this.clipAttachment.endSlot == slot.data) + this.clipEnd(); + }; + SkeletonClipping.prototype.clipEnd = function () { + if (this.clipAttachment == null) + return; + this.clipAttachment = null; + this.clippingPolygons = null; + this.clippedVertices.length = 0; + this.clippedTriangles.length = 0; + this.clippingPolygon.length = 0; + }; + SkeletonClipping.prototype.isClipping = function () { + return this.clipAttachment != null; + }; + SkeletonClipping.prototype.clipTriangles = function (vertices, verticesLength, triangles, trianglesLength, uvs, light, dark, twoColor) { + var clipOutput = this.clipOutput, clippedVertices = this.clippedVertices; + var clippedTriangles = this.clippedTriangles; + var polygons = this.clippingPolygons; + var polygonsCount = this.clippingPolygons.length; + var vertexSize = twoColor ? 12 : 8; + var index = 0; + clippedVertices.length = 0; + clippedTriangles.length = 0; + outer: for (var i = 0; i < trianglesLength; i += 3) { + var vertexOffset = triangles[i] << 1; + var x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1]; + var u1 = uvs[vertexOffset], v1 = uvs[vertexOffset + 1]; + vertexOffset = triangles[i + 1] << 1; + var x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1]; + var u2 = uvs[vertexOffset], v2 = uvs[vertexOffset + 1]; + vertexOffset = triangles[i + 2] << 1; + var x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1]; + var u3 = uvs[vertexOffset], v3 = uvs[vertexOffset + 1]; + for (var p = 0; p < polygonsCount; p++) { + var s = clippedVertices.length; + if (this.clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) { + var clipOutputLength = clipOutput.length; + if (clipOutputLength == 0) + continue; + var d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1; + var d = 1 / (d0 * d2 + d1 * (y1 - y3)); + var clipOutputCount = clipOutputLength >> 1; + var clipOutputItems = this.clipOutput; + var clippedVerticesItems = spine.Utils.setArraySize(clippedVertices, s + clipOutputCount * vertexSize); + for (var ii = 0; ii < clipOutputLength; ii += 2) { + var x = clipOutputItems[ii], y = clipOutputItems[ii + 1]; + clippedVerticesItems[s] = x; + clippedVerticesItems[s + 1] = y; + clippedVerticesItems[s + 2] = light.r; + clippedVerticesItems[s + 3] = light.g; + clippedVerticesItems[s + 4] = light.b; + clippedVerticesItems[s + 5] = light.a; + var c0 = x - x3, c1 = y - y3; + var a = (d0 * c0 + d1 * c1) * d; + var b = (d4 * c0 + d2 * c1) * d; + var c = 1 - a - b; + clippedVerticesItems[s + 6] = u1 * a + u2 * b + u3 * c; + clippedVerticesItems[s + 7] = v1 * a + v2 * b + v3 * c; + if (twoColor) { + clippedVerticesItems[s + 8] = dark.r; + clippedVerticesItems[s + 9] = dark.g; + clippedVerticesItems[s + 10] = dark.b; + clippedVerticesItems[s + 11] = dark.a; + } + s += vertexSize; + } + s = clippedTriangles.length; + var clippedTrianglesItems = spine.Utils.setArraySize(clippedTriangles, s + 3 * (clipOutputCount - 2)); + clipOutputCount--; + for (var ii = 1; ii < clipOutputCount; ii++) { + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = (index + ii); + clippedTrianglesItems[s + 2] = (index + ii + 1); + s += 3; + } + index += clipOutputCount + 1; + } + else { + var clippedVerticesItems = spine.Utils.setArraySize(clippedVertices, s + 3 * vertexSize); + clippedVerticesItems[s] = x1; + clippedVerticesItems[s + 1] = y1; + clippedVerticesItems[s + 2] = light.r; + clippedVerticesItems[s + 3] = light.g; + clippedVerticesItems[s + 4] = light.b; + clippedVerticesItems[s + 5] = light.a; + if (!twoColor) { + clippedVerticesItems[s + 6] = u1; + clippedVerticesItems[s + 7] = v1; + clippedVerticesItems[s + 8] = x2; + clippedVerticesItems[s + 9] = y2; + clippedVerticesItems[s + 10] = light.r; + clippedVerticesItems[s + 11] = light.g; + clippedVerticesItems[s + 12] = light.b; + clippedVerticesItems[s + 13] = light.a; + clippedVerticesItems[s + 14] = u2; + clippedVerticesItems[s + 15] = v2; + clippedVerticesItems[s + 16] = x3; + clippedVerticesItems[s + 17] = y3; + clippedVerticesItems[s + 18] = light.r; + clippedVerticesItems[s + 19] = light.g; + clippedVerticesItems[s + 20] = light.b; + clippedVerticesItems[s + 21] = light.a; + clippedVerticesItems[s + 22] = u3; + clippedVerticesItems[s + 23] = v3; + } + else { + clippedVerticesItems[s + 6] = u1; + clippedVerticesItems[s + 7] = v1; + clippedVerticesItems[s + 8] = dark.r; + clippedVerticesItems[s + 9] = dark.g; + clippedVerticesItems[s + 10] = dark.b; + clippedVerticesItems[s + 11] = dark.a; + clippedVerticesItems[s + 12] = x2; + clippedVerticesItems[s + 13] = y2; + clippedVerticesItems[s + 14] = light.r; + clippedVerticesItems[s + 15] = light.g; + clippedVerticesItems[s + 16] = light.b; + clippedVerticesItems[s + 17] = light.a; + clippedVerticesItems[s + 18] = u2; + clippedVerticesItems[s + 19] = v2; + clippedVerticesItems[s + 20] = dark.r; + clippedVerticesItems[s + 21] = dark.g; + clippedVerticesItems[s + 22] = dark.b; + clippedVerticesItems[s + 23] = dark.a; + clippedVerticesItems[s + 24] = x3; + clippedVerticesItems[s + 25] = y3; + clippedVerticesItems[s + 26] = light.r; + clippedVerticesItems[s + 27] = light.g; + clippedVerticesItems[s + 28] = light.b; + clippedVerticesItems[s + 29] = light.a; + clippedVerticesItems[s + 30] = u3; + clippedVerticesItems[s + 31] = v3; + clippedVerticesItems[s + 32] = dark.r; + clippedVerticesItems[s + 33] = dark.g; + clippedVerticesItems[s + 34] = dark.b; + clippedVerticesItems[s + 35] = dark.a; + } + s = clippedTriangles.length; + var clippedTrianglesItems = spine.Utils.setArraySize(clippedTriangles, s + 3); + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = (index + 1); + clippedTrianglesItems[s + 2] = (index + 2); + index += 3; + continue outer; + } + } + } + }; + SkeletonClipping.prototype.clip = function (x1, y1, x2, y2, x3, y3, clippingArea, output) { + var originalOutput = output; + var clipped = false; + var input = null; + if (clippingArea.length % 4 >= 2) { + input = output; + output = this.scratch; + } + else + input = this.scratch; + input.length = 0; + input.push(x1); + input.push(y1); + input.push(x2); + input.push(y2); + input.push(x3); + input.push(y3); + input.push(x1); + input.push(y1); + output.length = 0; + var clippingVertices = clippingArea; + var clippingVerticesLast = clippingArea.length - 4; + for (var i = 0;; i += 2) { + var edgeX = clippingVertices[i], edgeY = clippingVertices[i + 1]; + var edgeX2 = clippingVertices[i + 2], edgeY2 = clippingVertices[i + 3]; + var deltaX = edgeX - edgeX2, deltaY = edgeY - edgeY2; + var inputVertices = input; + var inputVerticesLength = input.length - 2, outputStart = output.length; + for (var ii = 0; ii < inputVerticesLength; ii += 2) { + var inputX = inputVertices[ii], inputY = inputVertices[ii + 1]; + var inputX2 = inputVertices[ii + 2], inputY2 = inputVertices[ii + 3]; + var side2 = deltaX * (inputY2 - edgeY2) - deltaY * (inputX2 - edgeX2) > 0; + if (deltaX * (inputY - edgeY2) - deltaY * (inputX - edgeX2) > 0) { + if (side2) { + output.push(inputX2); + output.push(inputY2); + continue; + } + var c0 = inputY2 - inputY, c2 = inputX2 - inputX; + var s = c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY); + if (Math.abs(s) > 0.000001) { + var ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / s; + output.push(edgeX + (edgeX2 - edgeX) * ua); + output.push(edgeY + (edgeY2 - edgeY) * ua); + } + else { + output.push(edgeX); + output.push(edgeY); + } + } + else if (side2) { + var c0 = inputY2 - inputY, c2 = inputX2 - inputX; + var s = c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY); + if (Math.abs(s) > 0.000001) { + var ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / s; + output.push(edgeX + (edgeX2 - edgeX) * ua); + output.push(edgeY + (edgeY2 - edgeY) * ua); + } + else { + output.push(edgeX); + output.push(edgeY); + } + output.push(inputX2); + output.push(inputY2); + } + clipped = true; + } + if (outputStart == output.length) { + originalOutput.length = 0; + return true; + } + output.push(output[0]); + output.push(output[1]); + if (i == clippingVerticesLast) + break; + var temp = output; + output = input; + output.length = 0; + input = temp; + } + if (originalOutput != output) { + originalOutput.length = 0; + for (var i = 0, n = output.length - 2; i < n; i++) + originalOutput[i] = output[i]; + } + else + originalOutput.length = originalOutput.length - 2; + return clipped; + }; + SkeletonClipping.makeClockwise = function (polygon) { + var vertices = polygon; + var verticeslength = polygon.length; + var area = vertices[verticeslength - 2] * vertices[1] - vertices[0] * vertices[verticeslength - 1], p1x = 0, p1y = 0, p2x = 0, p2y = 0; + for (var i = 0, n = verticeslength - 3; i < n; i += 2) { + p1x = vertices[i]; + p1y = vertices[i + 1]; + p2x = vertices[i + 2]; + p2y = vertices[i + 3]; + area += p1x * p2y - p2x * p1y; + } + if (area < 0) + return; + for (var i = 0, lastX = verticeslength - 2, n = verticeslength >> 1; i < n; i += 2) { + var x = vertices[i], y = vertices[i + 1]; + var other = lastX - i; + vertices[i] = vertices[other]; + vertices[i + 1] = vertices[other + 1]; + vertices[other] = x; + vertices[other + 1] = y; + } + }; + return SkeletonClipping; + }()); + spine.SkeletonClipping = SkeletonClipping; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SkeletonData = (function () { + function SkeletonData() { + this.bones = new Array(); + this.slots = new Array(); + this.skins = new Array(); + this.events = new Array(); + this.animations = new Array(); + this.ikConstraints = new Array(); + this.transformConstraints = new Array(); + this.pathConstraints = new Array(); + this.fps = 0; + } + SkeletonData.prototype.findBone = function (boneName) { + if (boneName == null) + throw new Error("boneName cannot be null."); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + if (bone.name == boneName) + return bone; + } + return null; + }; + SkeletonData.prototype.findBoneIndex = function (boneName) { + if (boneName == null) + throw new Error("boneName cannot be null."); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].name == boneName) + return i; + return -1; + }; + SkeletonData.prototype.findSlot = function (slotName) { + if (slotName == null) + throw new Error("slotName cannot be null."); + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + var slot = slots[i]; + if (slot.name == slotName) + return slot; + } + return null; + }; + SkeletonData.prototype.findSlotIndex = function (slotName) { + if (slotName == null) + throw new Error("slotName cannot be null."); + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].name == slotName) + return i; + return -1; + }; + SkeletonData.prototype.findSkin = function (skinName) { + if (skinName == null) + throw new Error("skinName cannot be null."); + var skins = this.skins; + for (var i = 0, n = skins.length; i < n; i++) { + var skin = skins[i]; + if (skin.name == skinName) + return skin; + } + return null; + }; + SkeletonData.prototype.findEvent = function (eventDataName) { + if (eventDataName == null) + throw new Error("eventDataName cannot be null."); + var events = this.events; + for (var i = 0, n = events.length; i < n; i++) { + var event_4 = events[i]; + if (event_4.name == eventDataName) + return event_4; + } + return null; + }; + SkeletonData.prototype.findAnimation = function (animationName) { + if (animationName == null) + throw new Error("animationName cannot be null."); + var animations = this.animations; + for (var i = 0, n = animations.length; i < n; i++) { + var animation = animations[i]; + if (animation.name == animationName) + return animation; + } + return null; + }; + SkeletonData.prototype.findIkConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var ikConstraints = this.ikConstraints; + for (var i = 0, n = ikConstraints.length; i < n; i++) { + var constraint = ikConstraints[i]; + if (constraint.name == constraintName) + return constraint; + } + return null; + }; + SkeletonData.prototype.findTransformConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var transformConstraints = this.transformConstraints; + for (var i = 0, n = transformConstraints.length; i < n; i++) { + var constraint = transformConstraints[i]; + if (constraint.name == constraintName) + return constraint; + } + return null; + }; + SkeletonData.prototype.findPathConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var pathConstraints = this.pathConstraints; + for (var i = 0, n = pathConstraints.length; i < n; i++) { + var constraint = pathConstraints[i]; + if (constraint.name == constraintName) + return constraint; + } + return null; + }; + SkeletonData.prototype.findPathConstraintIndex = function (pathConstraintName) { + if (pathConstraintName == null) + throw new Error("pathConstraintName cannot be null."); + var pathConstraints = this.pathConstraints; + for (var i = 0, n = pathConstraints.length; i < n; i++) + if (pathConstraints[i].name == pathConstraintName) + return i; + return -1; + }; + return SkeletonData; + }()); + spine.SkeletonData = SkeletonData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SkeletonJson = (function () { + function SkeletonJson(attachmentLoader) { + this.scale = 1; + this.linkedMeshes = new Array(); + this.attachmentLoader = attachmentLoader; + } + SkeletonJson.prototype.readSkeletonData = function (json) { + var scale = this.scale; + var skeletonData = new spine.SkeletonData(); + var root = typeof (json) === "string" ? JSON.parse(json) : json; + var skeletonMap = root.skeleton; + if (skeletonMap != null) { + skeletonData.hash = skeletonMap.hash; + skeletonData.version = skeletonMap.spine; + skeletonData.width = skeletonMap.width; + skeletonData.height = skeletonMap.height; + skeletonData.fps = skeletonMap.fps; + skeletonData.imagesPath = skeletonMap.images; + } + if (root.bones) { + for (var i = 0; i < root.bones.length; i++) { + var boneMap = root.bones[i]; + var parent_2 = null; + var parentName = this.getValue(boneMap, "parent", null); + if (parentName != null) { + parent_2 = skeletonData.findBone(parentName); + if (parent_2 == null) + throw new Error("Parent bone not found: " + parentName); + } + var data = new spine.BoneData(skeletonData.bones.length, boneMap.name, parent_2); + data.length = this.getValue(boneMap, "length", 0) * scale; + data.x = this.getValue(boneMap, "x", 0) * scale; + data.y = this.getValue(boneMap, "y", 0) * scale; + data.rotation = this.getValue(boneMap, "rotation", 0); + data.scaleX = this.getValue(boneMap, "scaleX", 1); + data.scaleY = this.getValue(boneMap, "scaleY", 1); + data.shearX = this.getValue(boneMap, "shearX", 0); + data.shearY = this.getValue(boneMap, "shearY", 0); + data.transformMode = SkeletonJson.transformModeFromString(this.getValue(boneMap, "transform", "normal")); + skeletonData.bones.push(data); + } + } + if (root.slots) { + for (var i = 0; i < root.slots.length; i++) { + var slotMap = root.slots[i]; + var slotName = slotMap.name; + var boneName = slotMap.bone; + var boneData = skeletonData.findBone(boneName); + if (boneData == null) + throw new Error("Slot bone not found: " + boneName); + var data = new spine.SlotData(skeletonData.slots.length, slotName, boneData); + var color = this.getValue(slotMap, "color", null); + if (color != null) + data.color.setFromString(color); + var dark = this.getValue(slotMap, "dark", null); + if (dark != null) { + data.darkColor = new spine.Color(1, 1, 1, 1); + data.darkColor.setFromString(dark); + } + data.attachmentName = this.getValue(slotMap, "attachment", null); + data.blendMode = SkeletonJson.blendModeFromString(this.getValue(slotMap, "blend", "normal")); + skeletonData.slots.push(data); + } + } + if (root.ik) { + for (var i = 0; i < root.ik.length; i++) { + var constraintMap = root.ik[i]; + var data = new spine.IkConstraintData(constraintMap.name); + data.order = this.getValue(constraintMap, "order", 0); + for (var j = 0; j < constraintMap.bones.length; j++) { + var boneName = constraintMap.bones[j]; + var bone = skeletonData.findBone(boneName); + if (bone == null) + throw new Error("IK bone not found: " + boneName); + data.bones.push(bone); + } + var targetName = constraintMap.target; + data.target = skeletonData.findBone(targetName); + if (data.target == null) + throw new Error("IK target bone not found: " + targetName); + data.mix = this.getValue(constraintMap, "mix", 1); + data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1; + data.compress = this.getValue(constraintMap, "compress", false); + data.stretch = this.getValue(constraintMap, "stretch", false); + data.uniform = this.getValue(constraintMap, "uniform", false); + skeletonData.ikConstraints.push(data); + } + } + if (root.transform) { + for (var i = 0; i < root.transform.length; i++) { + var constraintMap = root.transform[i]; + var data = new spine.TransformConstraintData(constraintMap.name); + data.order = this.getValue(constraintMap, "order", 0); + for (var j = 0; j < constraintMap.bones.length; j++) { + var boneName = constraintMap.bones[j]; + var bone = skeletonData.findBone(boneName); + if (bone == null) + throw new Error("Transform constraint bone not found: " + boneName); + data.bones.push(bone); + } + var targetName = constraintMap.target; + data.target = skeletonData.findBone(targetName); + if (data.target == null) + throw new Error("Transform constraint target bone not found: " + targetName); + data.local = this.getValue(constraintMap, "local", false); + data.relative = this.getValue(constraintMap, "relative", false); + data.offsetRotation = this.getValue(constraintMap, "rotation", 0); + data.offsetX = this.getValue(constraintMap, "x", 0) * scale; + data.offsetY = this.getValue(constraintMap, "y", 0) * scale; + data.offsetScaleX = this.getValue(constraintMap, "scaleX", 0); + data.offsetScaleY = this.getValue(constraintMap, "scaleY", 0); + data.offsetShearY = this.getValue(constraintMap, "shearY", 0); + data.rotateMix = this.getValue(constraintMap, "rotateMix", 1); + data.translateMix = this.getValue(constraintMap, "translateMix", 1); + data.scaleMix = this.getValue(constraintMap, "scaleMix", 1); + data.shearMix = this.getValue(constraintMap, "shearMix", 1); + skeletonData.transformConstraints.push(data); + } + } + if (root.path) { + for (var i = 0; i < root.path.length; i++) { + var constraintMap = root.path[i]; + var data = new spine.PathConstraintData(constraintMap.name); + data.order = this.getValue(constraintMap, "order", 0); + for (var j = 0; j < constraintMap.bones.length; j++) { + var boneName = constraintMap.bones[j]; + var bone = skeletonData.findBone(boneName); + if (bone == null) + throw new Error("Transform constraint bone not found: " + boneName); + data.bones.push(bone); + } + var targetName = constraintMap.target; + data.target = skeletonData.findSlot(targetName); + if (data.target == null) + throw new Error("Path target slot not found: " + targetName); + data.positionMode = SkeletonJson.positionModeFromString(this.getValue(constraintMap, "positionMode", "percent")); + data.spacingMode = SkeletonJson.spacingModeFromString(this.getValue(constraintMap, "spacingMode", "length")); + data.rotateMode = SkeletonJson.rotateModeFromString(this.getValue(constraintMap, "rotateMode", "tangent")); + data.offsetRotation = this.getValue(constraintMap, "rotation", 0); + data.position = this.getValue(constraintMap, "position", 0); + if (data.positionMode == spine.PositionMode.Fixed) + data.position *= scale; + data.spacing = this.getValue(constraintMap, "spacing", 0); + if (data.spacingMode == spine.SpacingMode.Length || data.spacingMode == spine.SpacingMode.Fixed) + data.spacing *= scale; + data.rotateMix = this.getValue(constraintMap, "rotateMix", 1); + data.translateMix = this.getValue(constraintMap, "translateMix", 1); + skeletonData.pathConstraints.push(data); + } + } + if (root.skins) { + for (var skinName in root.skins) { + var skinMap = root.skins[skinName]; + var skin = new spine.Skin(skinName); + for (var slotName in skinMap) { + var slotIndex = skeletonData.findSlotIndex(slotName); + if (slotIndex == -1) + throw new Error("Slot not found: " + slotName); + var slotMap = skinMap[slotName]; + for (var entryName in slotMap) { + var attachment = this.readAttachment(slotMap[entryName], skin, slotIndex, entryName, skeletonData); + if (attachment != null) + skin.addAttachment(slotIndex, entryName, attachment); + } + } + skeletonData.skins.push(skin); + if (skin.name == "default") + skeletonData.defaultSkin = skin; + } + } + for (var i = 0, n = this.linkedMeshes.length; i < n; i++) { + var linkedMesh = this.linkedMeshes[i]; + var skin = linkedMesh.skin == null ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin); + if (skin == null) + throw new Error("Skin not found: " + linkedMesh.skin); + var parent_3 = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); + if (parent_3 == null) + throw new Error("Parent mesh not found: " + linkedMesh.parent); + linkedMesh.mesh.setParentMesh(parent_3); + linkedMesh.mesh.updateUVs(); + } + this.linkedMeshes.length = 0; + if (root.events) { + for (var eventName in root.events) { + var eventMap = root.events[eventName]; + var data = new spine.EventData(eventName); + data.intValue = this.getValue(eventMap, "int", 0); + data.floatValue = this.getValue(eventMap, "float", 0); + data.stringValue = this.getValue(eventMap, "string", ""); + data.audioPath = this.getValue(eventMap, "audio", null); + if (data.audioPath != null) { + data.volume = this.getValue(eventMap, "volume", 1); + data.balance = this.getValue(eventMap, "balance", 0); + } + skeletonData.events.push(data); + } + } + if (root.animations) { + for (var animationName in root.animations) { + var animationMap = root.animations[animationName]; + this.readAnimation(animationMap, animationName, skeletonData); + } + } + return skeletonData; + }; + SkeletonJson.prototype.readAttachment = function (map, skin, slotIndex, name, skeletonData) { + var scale = this.scale; + name = this.getValue(map, "name", name); + var type = this.getValue(map, "type", "region"); + switch (type) { + case "region": { + var path = this.getValue(map, "path", name); + var region = this.attachmentLoader.newRegionAttachment(skin, name, path); + if (region == null) + return null; + region.path = path; + region.x = this.getValue(map, "x", 0) * scale; + region.y = this.getValue(map, "y", 0) * scale; + region.scaleX = this.getValue(map, "scaleX", 1); + region.scaleY = this.getValue(map, "scaleY", 1); + region.rotation = this.getValue(map, "rotation", 0); + region.width = map.width * scale; + region.height = map.height * scale; + var color = this.getValue(map, "color", null); + if (color != null) + region.color.setFromString(color); + region.updateOffset(); + return region; + } + case "boundingbox": { + var box = this.attachmentLoader.newBoundingBoxAttachment(skin, name); + if (box == null) + return null; + this.readVertices(map, box, map.vertexCount << 1); + var color = this.getValue(map, "color", null); + if (color != null) + box.color.setFromString(color); + return box; + } + case "mesh": + case "linkedmesh": { + var path = this.getValue(map, "path", name); + var mesh = this.attachmentLoader.newMeshAttachment(skin, name, path); + if (mesh == null) + return null; + mesh.path = path; + var color = this.getValue(map, "color", null); + if (color != null) + mesh.color.setFromString(color); + var parent_4 = this.getValue(map, "parent", null); + if (parent_4 != null) { + mesh.inheritDeform = this.getValue(map, "deform", true); + this.linkedMeshes.push(new LinkedMesh(mesh, this.getValue(map, "skin", null), slotIndex, parent_4)); + return mesh; + } + var uvs = map.uvs; + this.readVertices(map, mesh, uvs.length); + mesh.triangles = map.triangles; + mesh.regionUVs = uvs; + mesh.updateUVs(); + mesh.hullLength = this.getValue(map, "hull", 0) * 2; + return mesh; + } + case "path": { + var path = this.attachmentLoader.newPathAttachment(skin, name); + if (path == null) + return null; + path.closed = this.getValue(map, "closed", false); + path.constantSpeed = this.getValue(map, "constantSpeed", true); + var vertexCount = map.vertexCount; + this.readVertices(map, path, vertexCount << 1); + var lengths = spine.Utils.newArray(vertexCount / 3, 0); + for (var i = 0; i < map.lengths.length; i++) + lengths[i] = map.lengths[i] * scale; + path.lengths = lengths; + var color = this.getValue(map, "color", null); + if (color != null) + path.color.setFromString(color); + return path; + } + case "point": { + var point = this.attachmentLoader.newPointAttachment(skin, name); + if (point == null) + return null; + point.x = this.getValue(map, "x", 0) * scale; + point.y = this.getValue(map, "y", 0) * scale; + point.rotation = this.getValue(map, "rotation", 0); + var color = this.getValue(map, "color", null); + if (color != null) + point.color.setFromString(color); + return point; + } + case "clipping": { + var clip = this.attachmentLoader.newClippingAttachment(skin, name); + if (clip == null) + return null; + var end = this.getValue(map, "end", null); + if (end != null) { + var slot = skeletonData.findSlot(end); + if (slot == null) + throw new Error("Clipping end slot not found: " + end); + clip.endSlot = slot; + } + var vertexCount = map.vertexCount; + this.readVertices(map, clip, vertexCount << 1); + var color = this.getValue(map, "color", null); + if (color != null) + clip.color.setFromString(color); + return clip; + } + } + return null; + }; + SkeletonJson.prototype.readVertices = function (map, attachment, verticesLength) { + var scale = this.scale; + attachment.worldVerticesLength = verticesLength; + var vertices = map.vertices; + if (verticesLength == vertices.length) { + var scaledVertices = spine.Utils.toFloatArray(vertices); + if (scale != 1) { + for (var i = 0, n = vertices.length; i < n; i++) + scaledVertices[i] *= scale; + } + attachment.vertices = scaledVertices; + return; + } + var weights = new Array(); + var bones = new Array(); + for (var i = 0, n = vertices.length; i < n;) { + var boneCount = vertices[i++]; + bones.push(boneCount); + for (var nn = i + boneCount * 4; i < nn; i += 4) { + bones.push(vertices[i]); + weights.push(vertices[i + 1] * scale); + weights.push(vertices[i + 2] * scale); + weights.push(vertices[i + 3]); + } + } + attachment.bones = bones; + attachment.vertices = spine.Utils.toFloatArray(weights); + }; + SkeletonJson.prototype.readAnimation = function (map, name, skeletonData) { + var scale = this.scale; + var timelines = new Array(); + var duration = 0; + if (map.slots) { + for (var slotName in map.slots) { + var slotMap = map.slots[slotName]; + var slotIndex = skeletonData.findSlotIndex(slotName); + if (slotIndex == -1) + throw new Error("Slot not found: " + slotName); + for (var timelineName in slotMap) { + var timelineMap = slotMap[timelineName]; + if (timelineName == "attachment") { + var timeline = new spine.AttachmentTimeline(timelineMap.length); + timeline.slotIndex = slotIndex; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + timeline.setFrame(frameIndex++, valueMap.time, valueMap.name); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + else if (timelineName == "color") { + var timeline = new spine.ColorTimeline(timelineMap.length); + timeline.slotIndex = slotIndex; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + var color = new spine.Color(); + color.setFromString(valueMap.color); + timeline.setFrame(frameIndex, valueMap.time, color.r, color.g, color.b, color.a); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.ColorTimeline.ENTRIES]); + } + else if (timelineName == "twoColor") { + var timeline = new spine.TwoColorTimeline(timelineMap.length); + timeline.slotIndex = slotIndex; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + var light = new spine.Color(); + var dark = new spine.Color(); + light.setFromString(valueMap.light); + dark.setFromString(valueMap.dark); + timeline.setFrame(frameIndex, valueMap.time, light.r, light.g, light.b, light.a, dark.r, dark.g, dark.b); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.TwoColorTimeline.ENTRIES]); + } + else + throw new Error("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"); + } + } + } + if (map.bones) { + for (var boneName in map.bones) { + var boneMap = map.bones[boneName]; + var boneIndex = skeletonData.findBoneIndex(boneName); + if (boneIndex == -1) + throw new Error("Bone not found: " + boneName); + for (var timelineName in boneMap) { + var timelineMap = boneMap[timelineName]; + if (timelineName === "rotate") { + var timeline = new spine.RotateTimeline(timelineMap.length); + timeline.boneIndex = boneIndex; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + timeline.setFrame(frameIndex, valueMap.time, valueMap.angle); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.RotateTimeline.ENTRIES]); + } + else if (timelineName === "translate" || timelineName === "scale" || timelineName === "shear") { + var timeline = null; + var timelineScale = 1; + if (timelineName === "scale") + timeline = new spine.ScaleTimeline(timelineMap.length); + else if (timelineName === "shear") + timeline = new spine.ShearTimeline(timelineMap.length); + else { + timeline = new spine.TranslateTimeline(timelineMap.length); + timelineScale = scale; + } + timeline.boneIndex = boneIndex; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + var x = this.getValue(valueMap, "x", 0), y = this.getValue(valueMap, "y", 0); + timeline.setFrame(frameIndex, valueMap.time, x * timelineScale, y * timelineScale); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.TranslateTimeline.ENTRIES]); + } + else + throw new Error("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"); + } + } + } + if (map.ik) { + for (var constraintName in map.ik) { + var constraintMap = map.ik[constraintName]; + var constraint = skeletonData.findIkConstraint(constraintName); + var timeline = new spine.IkConstraintTimeline(constraintMap.length); + timeline.ikConstraintIndex = skeletonData.ikConstraints.indexOf(constraint); + var frameIndex = 0; + for (var i = 0; i < constraintMap.length; i++) { + var valueMap = constraintMap[i]; + timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false)); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.IkConstraintTimeline.ENTRIES]); + } + } + if (map.transform) { + for (var constraintName in map.transform) { + var constraintMap = map.transform[constraintName]; + var constraint = skeletonData.findTransformConstraint(constraintName); + var timeline = new spine.TransformConstraintTimeline(constraintMap.length); + timeline.transformConstraintIndex = skeletonData.transformConstraints.indexOf(constraint); + var frameIndex = 0; + for (var i = 0; i < constraintMap.length; i++) { + var valueMap = constraintMap[i]; + timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, "rotateMix", 1), this.getValue(valueMap, "translateMix", 1), this.getValue(valueMap, "scaleMix", 1), this.getValue(valueMap, "shearMix", 1)); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.TransformConstraintTimeline.ENTRIES]); + } + } + if (map.paths) { + for (var constraintName in map.paths) { + var constraintMap = map.paths[constraintName]; + var index = skeletonData.findPathConstraintIndex(constraintName); + if (index == -1) + throw new Error("Path constraint not found: " + constraintName); + var data = skeletonData.pathConstraints[index]; + for (var timelineName in constraintMap) { + var timelineMap = constraintMap[timelineName]; + if (timelineName === "position" || timelineName === "spacing") { + var timeline = null; + var timelineScale = 1; + if (timelineName === "spacing") { + timeline = new spine.PathConstraintSpacingTimeline(timelineMap.length); + if (data.spacingMode == spine.SpacingMode.Length || data.spacingMode == spine.SpacingMode.Fixed) + timelineScale = scale; + } + else { + timeline = new spine.PathConstraintPositionTimeline(timelineMap.length); + if (data.positionMode == spine.PositionMode.Fixed) + timelineScale = scale; + } + timeline.pathConstraintIndex = index; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, timelineName, 0) * timelineScale); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.PathConstraintPositionTimeline.ENTRIES]); + } + else if (timelineName === "mix") { + var timeline = new spine.PathConstraintMixTimeline(timelineMap.length); + timeline.pathConstraintIndex = index; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, "rotateMix", 1), this.getValue(valueMap, "translateMix", 1)); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.PathConstraintMixTimeline.ENTRIES]); + } + } + } + } + if (map.deform) { + for (var deformName in map.deform) { + var deformMap = map.deform[deformName]; + var skin = skeletonData.findSkin(deformName); + if (skin == null) + throw new Error("Skin not found: " + deformName); + for (var slotName in deformMap) { + var slotMap = deformMap[slotName]; + var slotIndex = skeletonData.findSlotIndex(slotName); + if (slotIndex == -1) + throw new Error("Slot not found: " + slotMap.name); + for (var timelineName in slotMap) { + var timelineMap = slotMap[timelineName]; + var attachment = skin.getAttachment(slotIndex, timelineName); + if (attachment == null) + throw new Error("Deform attachment not found: " + timelineMap.name); + var weighted = attachment.bones != null; + var vertices = attachment.vertices; + var deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + var timeline = new spine.DeformTimeline(timelineMap.length); + timeline.slotIndex = slotIndex; + timeline.attachment = attachment; + var frameIndex = 0; + for (var j = 0; j < timelineMap.length; j++) { + var valueMap = timelineMap[j]; + var deform = void 0; + var verticesValue = this.getValue(valueMap, "vertices", null); + if (verticesValue == null) + deform = weighted ? spine.Utils.newFloatArray(deformLength) : vertices; + else { + deform = spine.Utils.newFloatArray(deformLength); + var start = this.getValue(valueMap, "offset", 0); + spine.Utils.arrayCopy(verticesValue, 0, deform, start, verticesValue.length); + if (scale != 1) { + for (var i = start, n = i + verticesValue.length; i < n; i++) + deform[i] *= scale; + } + if (!weighted) { + for (var i = 0; i < deformLength; i++) + deform[i] += vertices[i]; + } + } + timeline.setFrame(frameIndex, valueMap.time, deform); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + } + } + } + var drawOrderNode = map.drawOrder; + if (drawOrderNode == null) + drawOrderNode = map.draworder; + if (drawOrderNode != null) { + var timeline = new spine.DrawOrderTimeline(drawOrderNode.length); + var slotCount = skeletonData.slots.length; + var frameIndex = 0; + for (var j = 0; j < drawOrderNode.length; j++) { + var drawOrderMap = drawOrderNode[j]; + var drawOrder = null; + var offsets = this.getValue(drawOrderMap, "offsets", null); + if (offsets != null) { + drawOrder = spine.Utils.newArray(slotCount, -1); + var unchanged = spine.Utils.newArray(slotCount - offsets.length, 0); + var originalIndex = 0, unchangedIndex = 0; + for (var i = 0; i < offsets.length; i++) { + var offsetMap = offsets[i]; + var slotIndex = skeletonData.findSlotIndex(offsetMap.slot); + if (slotIndex == -1) + throw new Error("Slot not found: " + offsetMap.slot); + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + drawOrder[originalIndex + offsetMap.offset] = originalIndex++; + } + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + for (var i = slotCount - 1; i >= 0; i--) + if (drawOrder[i] == -1) + drawOrder[i] = unchanged[--unchangedIndex]; + } + timeline.setFrame(frameIndex++, drawOrderMap.time, drawOrder); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + if (map.events) { + var timeline = new spine.EventTimeline(map.events.length); + var frameIndex = 0; + for (var i = 0; i < map.events.length; i++) { + var eventMap = map.events[i]; + var eventData = skeletonData.findEvent(eventMap.name); + if (eventData == null) + throw new Error("Event not found: " + eventMap.name); + var event_5 = new spine.Event(spine.Utils.toSinglePrecision(eventMap.time), eventData); + event_5.intValue = this.getValue(eventMap, "int", eventData.intValue); + event_5.floatValue = this.getValue(eventMap, "float", eventData.floatValue); + event_5.stringValue = this.getValue(eventMap, "string", eventData.stringValue); + if (event_5.data.audioPath != null) { + event_5.volume = this.getValue(eventMap, "volume", 1); + event_5.balance = this.getValue(eventMap, "balance", 0); + } + timeline.setFrame(frameIndex++, event_5); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + if (isNaN(duration)) { + throw new Error("Error while parsing animation, duration is NaN"); + } + skeletonData.animations.push(new spine.Animation(name, timelines, duration)); + }; + SkeletonJson.prototype.readCurve = function (map, timeline, frameIndex) { + if (!map.curve) + return; + if (map.curve === "stepped") + timeline.setStepped(frameIndex); + else if (Object.prototype.toString.call(map.curve) === '[object Array]') { + var curve = map.curve; + timeline.setCurve(frameIndex, curve[0], curve[1], curve[2], curve[3]); + } + }; + SkeletonJson.prototype.getValue = function (map, prop, defaultValue) { + return map[prop] !== undefined ? map[prop] : defaultValue; + }; + SkeletonJson.blendModeFromString = function (str) { + str = str.toLowerCase(); + if (str == "normal") + return spine.BlendMode.Normal; + if (str == "additive") + return spine.BlendMode.Additive; + if (str == "multiply") + return spine.BlendMode.Multiply; + if (str == "screen") + return spine.BlendMode.Screen; + throw new Error("Unknown blend mode: " + str); + }; + SkeletonJson.positionModeFromString = function (str) { + str = str.toLowerCase(); + if (str == "fixed") + return spine.PositionMode.Fixed; + if (str == "percent") + return spine.PositionMode.Percent; + throw new Error("Unknown position mode: " + str); + }; + SkeletonJson.spacingModeFromString = function (str) { + str = str.toLowerCase(); + if (str == "length") + return spine.SpacingMode.Length; + if (str == "fixed") + return spine.SpacingMode.Fixed; + if (str == "percent") + return spine.SpacingMode.Percent; + throw new Error("Unknown position mode: " + str); + }; + SkeletonJson.rotateModeFromString = function (str) { + str = str.toLowerCase(); + if (str == "tangent") + return spine.RotateMode.Tangent; + if (str == "chain") + return spine.RotateMode.Chain; + if (str == "chainscale") + return spine.RotateMode.ChainScale; + throw new Error("Unknown rotate mode: " + str); + }; + SkeletonJson.transformModeFromString = function (str) { + str = str.toLowerCase(); + if (str == "normal") + return spine.TransformMode.Normal; + if (str == "onlytranslation") + return spine.TransformMode.OnlyTranslation; + if (str == "norotationorreflection") + return spine.TransformMode.NoRotationOrReflection; + if (str == "noscale") + return spine.TransformMode.NoScale; + if (str == "noscaleorreflection") + return spine.TransformMode.NoScaleOrReflection; + throw new Error("Unknown transform mode: " + str); + }; + return SkeletonJson; + }()); + spine.SkeletonJson = SkeletonJson; + var LinkedMesh = (function () { + function LinkedMesh(mesh, skin, slotIndex, parent) { + this.mesh = mesh; + this.skin = skin; + this.slotIndex = slotIndex; + this.parent = parent; + } + return LinkedMesh; + }()); +})(spine || (spine = {})); +var spine; +(function (spine) { + var Skin = (function () { + function Skin(name) { + this.attachments = new Array(); + if (name == null) + throw new Error("name cannot be null."); + this.name = name; + } + Skin.prototype.addAttachment = function (slotIndex, name, attachment) { + if (attachment == null) + throw new Error("attachment cannot be null."); + var attachments = this.attachments; + if (slotIndex >= attachments.length) + attachments.length = slotIndex + 1; + if (!attachments[slotIndex]) + attachments[slotIndex] = {}; + attachments[slotIndex][name] = attachment; + }; + Skin.prototype.getAttachment = function (slotIndex, name) { + var dictionary = this.attachments[slotIndex]; + return dictionary ? dictionary[name] : null; + }; + Skin.prototype.attachAll = function (skeleton, oldSkin) { + var slotIndex = 0; + for (var i = 0; i < skeleton.slots.length; i++) { + var slot = skeleton.slots[i]; + var slotAttachment = slot.getAttachment(); + if (slotAttachment && slotIndex < oldSkin.attachments.length) { + var dictionary = oldSkin.attachments[slotIndex]; + for (var key in dictionary) { + var skinAttachment = dictionary[key]; + if (slotAttachment == skinAttachment) { + var attachment = this.getAttachment(slotIndex, key); + if (attachment != null) + slot.setAttachment(attachment); + break; + } + } + } + slotIndex++; + } + }; + return Skin; + }()); + spine.Skin = Skin; +})(spine || (spine = {})); +var spine; +(function (spine) { + var Slot = (function () { + function Slot(data, bone) { + this.attachmentVertices = new Array(); + if (data == null) + throw new Error("data cannot be null."); + if (bone == null) + throw new Error("bone cannot be null."); + this.data = data; + this.bone = bone; + this.color = new spine.Color(); + this.darkColor = data.darkColor == null ? null : new spine.Color(); + this.setToSetupPose(); + } + Slot.prototype.getAttachment = function () { + return this.attachment; + }; + Slot.prototype.setAttachment = function (attachment) { + if (this.attachment == attachment) + return; + this.attachment = attachment; + this.attachmentTime = this.bone.skeleton.time; + this.attachmentVertices.length = 0; + }; + Slot.prototype.setAttachmentTime = function (time) { + this.attachmentTime = this.bone.skeleton.time - time; + }; + Slot.prototype.getAttachmentTime = function () { + return this.bone.skeleton.time - this.attachmentTime; + }; + Slot.prototype.setToSetupPose = function () { + this.color.setFromColor(this.data.color); + if (this.darkColor != null) + this.darkColor.setFromColor(this.data.darkColor); + if (this.data.attachmentName == null) + this.attachment = null; + else { + this.attachment = null; + this.setAttachment(this.bone.skeleton.getAttachment(this.data.index, this.data.attachmentName)); + } + }; + return Slot; + }()); + spine.Slot = Slot; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SlotData = (function () { + function SlotData(index, name, boneData) { + this.color = new spine.Color(1, 1, 1, 1); + if (index < 0) + throw new Error("index must be >= 0."); + if (name == null) + throw new Error("name cannot be null."); + if (boneData == null) + throw new Error("boneData cannot be null."); + this.index = index; + this.name = name; + this.boneData = boneData; + } + return SlotData; + }()); + spine.SlotData = SlotData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var Texture = (function () { + function Texture(image) { + this._image = image; + } + Texture.prototype.getImage = function () { + return this._image; + }; + Texture.filterFromString = function (text) { + switch (text.toLowerCase()) { + case "nearest": return TextureFilter.Nearest; + case "linear": return TextureFilter.Linear; + case "mipmap": return TextureFilter.MipMap; + case "mipmapnearestnearest": return TextureFilter.MipMapNearestNearest; + case "mipmaplinearnearest": return TextureFilter.MipMapLinearNearest; + case "mipmapnearestlinear": return TextureFilter.MipMapNearestLinear; + case "mipmaplinearlinear": return TextureFilter.MipMapLinearLinear; + default: throw new Error("Unknown texture filter " + text); + } + }; + Texture.wrapFromString = function (text) { + switch (text.toLowerCase()) { + case "mirroredtepeat": return TextureWrap.MirroredRepeat; + case "clamptoedge": return TextureWrap.ClampToEdge; + case "repeat": return TextureWrap.Repeat; + default: throw new Error("Unknown texture wrap " + text); + } + }; + return Texture; + }()); + spine.Texture = Texture; + var TextureFilter; + (function (TextureFilter) { + TextureFilter[TextureFilter["Nearest"] = 9728] = "Nearest"; + TextureFilter[TextureFilter["Linear"] = 9729] = "Linear"; + TextureFilter[TextureFilter["MipMap"] = 9987] = "MipMap"; + TextureFilter[TextureFilter["MipMapNearestNearest"] = 9984] = "MipMapNearestNearest"; + TextureFilter[TextureFilter["MipMapLinearNearest"] = 9985] = "MipMapLinearNearest"; + TextureFilter[TextureFilter["MipMapNearestLinear"] = 9986] = "MipMapNearestLinear"; + TextureFilter[TextureFilter["MipMapLinearLinear"] = 9987] = "MipMapLinearLinear"; + })(TextureFilter = spine.TextureFilter || (spine.TextureFilter = {})); + var TextureWrap; + (function (TextureWrap) { + TextureWrap[TextureWrap["MirroredRepeat"] = 33648] = "MirroredRepeat"; + TextureWrap[TextureWrap["ClampToEdge"] = 33071] = "ClampToEdge"; + TextureWrap[TextureWrap["Repeat"] = 10497] = "Repeat"; + })(TextureWrap = spine.TextureWrap || (spine.TextureWrap = {})); + var TextureRegion = (function () { + function TextureRegion() { + this.u = 0; + this.v = 0; + this.u2 = 0; + this.v2 = 0; + this.width = 0; + this.height = 0; + this.rotate = false; + this.offsetX = 0; + this.offsetY = 0; + this.originalWidth = 0; + this.originalHeight = 0; + } + return TextureRegion; + }()); + spine.TextureRegion = TextureRegion; + var FakeTexture = (function (_super) { + __extends(FakeTexture, _super); + function FakeTexture() { + return _super !== null && _super.apply(this, arguments) || this; + } + FakeTexture.prototype.setFilters = function (minFilter, magFilter) { }; + FakeTexture.prototype.setWraps = function (uWrap, vWrap) { }; + FakeTexture.prototype.dispose = function () { }; + return FakeTexture; + }(Texture)); + spine.FakeTexture = FakeTexture; +})(spine || (spine = {})); +var spine; +(function (spine) { + var TextureAtlas = (function () { + function TextureAtlas(atlasText, textureLoader) { + this.pages = new Array(); + this.regions = new Array(); + this.load(atlasText, textureLoader); + } + TextureAtlas.prototype.load = function (atlasText, textureLoader) { + if (textureLoader == null) + throw new Error("textureLoader cannot be null."); + var reader = new TextureAtlasReader(atlasText); + var tuple = new Array(4); + var page = null; + while (true) { + var line = reader.readLine(); + if (line == null) + break; + line = line.trim(); + if (line.length == 0) + page = null; + else if (!page) { + page = new TextureAtlasPage(); + page.name = line; + if (reader.readTuple(tuple) == 2) { + page.width = parseInt(tuple[0]); + page.height = parseInt(tuple[1]); + reader.readTuple(tuple); + } + reader.readTuple(tuple); + page.minFilter = spine.Texture.filterFromString(tuple[0]); + page.magFilter = spine.Texture.filterFromString(tuple[1]); + var direction = reader.readValue(); + page.uWrap = spine.TextureWrap.ClampToEdge; + page.vWrap = spine.TextureWrap.ClampToEdge; + if (direction == "x") + page.uWrap = spine.TextureWrap.Repeat; + else if (direction == "y") + page.vWrap = spine.TextureWrap.Repeat; + else if (direction == "xy") + page.uWrap = page.vWrap = spine.TextureWrap.Repeat; + page.texture = textureLoader(line); + page.texture.setFilters(page.minFilter, page.magFilter); + page.texture.setWraps(page.uWrap, page.vWrap); + page.width = page.texture.getImage().width; + page.height = page.texture.getImage().height; + this.pages.push(page); + } + else { + var region = new TextureAtlasRegion(); + region.name = line; + region.page = page; + region.rotate = reader.readValue() == "true"; + reader.readTuple(tuple); + var x = parseInt(tuple[0]); + var y = parseInt(tuple[1]); + reader.readTuple(tuple); + var width = parseInt(tuple[0]); + var height = parseInt(tuple[1]); + region.u = x / page.width; + region.v = y / page.height; + if (region.rotate) { + region.u2 = (x + height) / page.width; + region.v2 = (y + width) / page.height; + } + else { + region.u2 = (x + width) / page.width; + region.v2 = (y + height) / page.height; + } + region.x = x; + region.y = y; + region.width = Math.abs(width); + region.height = Math.abs(height); + if (reader.readTuple(tuple) == 4) { + if (reader.readTuple(tuple) == 4) { + reader.readTuple(tuple); + } + } + region.originalWidth = parseInt(tuple[0]); + region.originalHeight = parseInt(tuple[1]); + reader.readTuple(tuple); + region.offsetX = parseInt(tuple[0]); + region.offsetY = parseInt(tuple[1]); + region.index = parseInt(reader.readValue()); + region.texture = page.texture; + this.regions.push(region); + } + } + }; + TextureAtlas.prototype.findRegion = function (name) { + for (var i = 0; i < this.regions.length; i++) { + if (this.regions[i].name == name) { + return this.regions[i]; + } + } + return null; + }; + TextureAtlas.prototype.dispose = function () { + for (var i = 0; i < this.pages.length; i++) { + this.pages[i].texture.dispose(); + } + }; + return TextureAtlas; + }()); + spine.TextureAtlas = TextureAtlas; + var TextureAtlasReader = (function () { + function TextureAtlasReader(text) { + this.index = 0; + this.lines = text.split(/\r\n|\r|\n/); + } + TextureAtlasReader.prototype.readLine = function () { + if (this.index >= this.lines.length) + return null; + return this.lines[this.index++]; + }; + TextureAtlasReader.prototype.readValue = function () { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) + throw new Error("Invalid line: " + line); + return line.substring(colon + 1).trim(); + }; + TextureAtlasReader.prototype.readTuple = function (tuple) { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) + throw new Error("Invalid line: " + line); + var i = 0, lastMatch = colon + 1; + for (; i < 3; i++) { + var comma = line.indexOf(",", lastMatch); + if (comma == -1) + break; + tuple[i] = line.substr(lastMatch, comma - lastMatch).trim(); + lastMatch = comma + 1; + } + tuple[i] = line.substring(lastMatch).trim(); + return i + 1; + }; + return TextureAtlasReader; + }()); + var TextureAtlasPage = (function () { + function TextureAtlasPage() { + } + return TextureAtlasPage; + }()); + spine.TextureAtlasPage = TextureAtlasPage; + var TextureAtlasRegion = (function (_super) { + __extends(TextureAtlasRegion, _super); + function TextureAtlasRegion() { + return _super !== null && _super.apply(this, arguments) || this; + } + return TextureAtlasRegion; + }(spine.TextureRegion)); + spine.TextureAtlasRegion = TextureAtlasRegion; +})(spine || (spine = {})); +var spine; +(function (spine) { + var TransformConstraint = (function () { + function TransformConstraint(data, skeleton) { + this.rotateMix = 0; + this.translateMix = 0; + this.scaleMix = 0; + this.shearMix = 0; + this.temp = new spine.Vector2(); + if (data == null) + throw new Error("data cannot be null."); + if (skeleton == null) + throw new Error("skeleton cannot be null."); + this.data = data; + this.rotateMix = data.rotateMix; + this.translateMix = data.translateMix; + this.scaleMix = data.scaleMix; + this.shearMix = data.shearMix; + this.bones = new Array(); + for (var i = 0; i < data.bones.length; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findBone(data.target.name); + } + TransformConstraint.prototype.apply = function () { + this.update(); + }; + TransformConstraint.prototype.update = function () { + if (this.data.local) { + if (this.data.relative) + this.applyRelativeLocal(); + else + this.applyAbsoluteLocal(); + } + else { + if (this.data.relative) + this.applyRelativeWorld(); + else + this.applyAbsoluteWorld(); + } + }; + TransformConstraint.prototype.applyAbsoluteWorld = function () { + var rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; + var target = this.target; + var ta = target.a, tb = target.b, tc = target.c, td = target.d; + var degRadReflect = ta * td - tb * tc > 0 ? spine.MathUtils.degRad : -spine.MathUtils.degRad; + var offsetRotation = this.data.offsetRotation * degRadReflect; + var offsetShearY = this.data.offsetShearY * degRadReflect; + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + var modified = false; + if (rotateMix != 0) { + var a = bone.a, b = bone.b, c = bone.c, d = bone.d; + var r = Math.atan2(tc, ta) - Math.atan2(c, a) + offsetRotation; + if (r > spine.MathUtils.PI) + r -= spine.MathUtils.PI2; + else if (r < -spine.MathUtils.PI) + r += spine.MathUtils.PI2; + r *= rotateMix; + var cos = Math.cos(r), sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + modified = true; + } + if (translateMix != 0) { + var temp = this.temp; + target.localToWorld(temp.set(this.data.offsetX, this.data.offsetY)); + bone.worldX += (temp.x - bone.worldX) * translateMix; + bone.worldY += (temp.y - bone.worldY) * translateMix; + modified = true; + } + if (scaleMix > 0) { + var s = Math.sqrt(bone.a * bone.a + bone.c * bone.c); + var ts = Math.sqrt(ta * ta + tc * tc); + if (s > 0.00001) + s = (s + (ts - s + this.data.offsetScaleX) * scaleMix) / s; + bone.a *= s; + bone.c *= s; + s = Math.sqrt(bone.b * bone.b + bone.d * bone.d); + ts = Math.sqrt(tb * tb + td * td); + if (s > 0.00001) + s = (s + (ts - s + this.data.offsetScaleY) * scaleMix) / s; + bone.b *= s; + bone.d *= s; + modified = true; + } + if (shearMix > 0) { + var b = bone.b, d = bone.d; + var by = Math.atan2(d, b); + var r = Math.atan2(td, tb) - Math.atan2(tc, ta) - (by - Math.atan2(bone.c, bone.a)); + if (r > spine.MathUtils.PI) + r -= spine.MathUtils.PI2; + else if (r < -spine.MathUtils.PI) + r += spine.MathUtils.PI2; + r = by + (r + offsetShearY) * shearMix; + var s = Math.sqrt(b * b + d * d); + bone.b = Math.cos(r) * s; + bone.d = Math.sin(r) * s; + modified = true; + } + if (modified) + bone.appliedValid = false; + } + }; + TransformConstraint.prototype.applyRelativeWorld = function () { + var rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; + var target = this.target; + var ta = target.a, tb = target.b, tc = target.c, td = target.d; + var degRadReflect = ta * td - tb * tc > 0 ? spine.MathUtils.degRad : -spine.MathUtils.degRad; + var offsetRotation = this.data.offsetRotation * degRadReflect, offsetShearY = this.data.offsetShearY * degRadReflect; + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + var modified = false; + if (rotateMix != 0) { + var a = bone.a, b = bone.b, c = bone.c, d = bone.d; + var r = Math.atan2(tc, ta) + offsetRotation; + if (r > spine.MathUtils.PI) + r -= spine.MathUtils.PI2; + else if (r < -spine.MathUtils.PI) + r += spine.MathUtils.PI2; + r *= rotateMix; + var cos = Math.cos(r), sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + modified = true; + } + if (translateMix != 0) { + var temp = this.temp; + target.localToWorld(temp.set(this.data.offsetX, this.data.offsetY)); + bone.worldX += temp.x * translateMix; + bone.worldY += temp.y * translateMix; + modified = true; + } + if (scaleMix > 0) { + var s = (Math.sqrt(ta * ta + tc * tc) - 1 + this.data.offsetScaleX) * scaleMix + 1; + bone.a *= s; + bone.c *= s; + s = (Math.sqrt(tb * tb + td * td) - 1 + this.data.offsetScaleY) * scaleMix + 1; + bone.b *= s; + bone.d *= s; + modified = true; + } + if (shearMix > 0) { + var r = Math.atan2(td, tb) - Math.atan2(tc, ta); + if (r > spine.MathUtils.PI) + r -= spine.MathUtils.PI2; + else if (r < -spine.MathUtils.PI) + r += spine.MathUtils.PI2; + var b = bone.b, d = bone.d; + r = Math.atan2(d, b) + (r - spine.MathUtils.PI / 2 + offsetShearY) * shearMix; + var s = Math.sqrt(b * b + d * d); + bone.b = Math.cos(r) * s; + bone.d = Math.sin(r) * s; + modified = true; + } + if (modified) + bone.appliedValid = false; + } + }; + TransformConstraint.prototype.applyAbsoluteLocal = function () { + var rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; + var target = this.target; + if (!target.appliedValid) + target.updateAppliedTransform(); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + if (!bone.appliedValid) + bone.updateAppliedTransform(); + var rotation = bone.arotation; + if (rotateMix != 0) { + var r = target.arotation - rotation + this.data.offsetRotation; + r -= (16384 - ((16384.499999999996 - r / 360) | 0)) * 360; + rotation += r * rotateMix; + } + var x = bone.ax, y = bone.ay; + if (translateMix != 0) { + x += (target.ax - x + this.data.offsetX) * translateMix; + y += (target.ay - y + this.data.offsetY) * translateMix; + } + var scaleX = bone.ascaleX, scaleY = bone.ascaleY; + if (scaleMix != 0) { + if (scaleX > 0.00001) + scaleX = (scaleX + (target.ascaleX - scaleX + this.data.offsetScaleX) * scaleMix) / scaleX; + if (scaleY > 0.00001) + scaleY = (scaleY + (target.ascaleY - scaleY + this.data.offsetScaleY) * scaleMix) / scaleY; + } + var shearY = bone.ashearY; + if (shearMix != 0) { + var r = target.ashearY - shearY + this.data.offsetShearY; + r -= (16384 - ((16384.499999999996 - r / 360) | 0)) * 360; + bone.shearY += r * shearMix; + } + bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY); + } + }; + TransformConstraint.prototype.applyRelativeLocal = function () { + var rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; + var target = this.target; + if (!target.appliedValid) + target.updateAppliedTransform(); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + if (!bone.appliedValid) + bone.updateAppliedTransform(); + var rotation = bone.arotation; + if (rotateMix != 0) + rotation += (target.arotation + this.data.offsetRotation) * rotateMix; + var x = bone.ax, y = bone.ay; + if (translateMix != 0) { + x += (target.ax + this.data.offsetX) * translateMix; + y += (target.ay + this.data.offsetY) * translateMix; + } + var scaleX = bone.ascaleX, scaleY = bone.ascaleY; + if (scaleMix != 0) { + if (scaleX > 0.00001) + scaleX *= ((target.ascaleX - 1 + this.data.offsetScaleX) * scaleMix) + 1; + if (scaleY > 0.00001) + scaleY *= ((target.ascaleY - 1 + this.data.offsetScaleY) * scaleMix) + 1; + } + var shearY = bone.ashearY; + if (shearMix != 0) + shearY += (target.ashearY + this.data.offsetShearY) * shearMix; + bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY); + } + }; + TransformConstraint.prototype.getOrder = function () { + return this.data.order; + }; + return TransformConstraint; + }()); + spine.TransformConstraint = TransformConstraint; +})(spine || (spine = {})); +var spine; +(function (spine) { + var TransformConstraintData = (function () { + function TransformConstraintData(name) { + this.order = 0; + this.bones = new Array(); + this.rotateMix = 0; + this.translateMix = 0; + this.scaleMix = 0; + this.shearMix = 0; + this.offsetRotation = 0; + this.offsetX = 0; + this.offsetY = 0; + this.offsetScaleX = 0; + this.offsetScaleY = 0; + this.offsetShearY = 0; + this.relative = false; + this.local = false; + if (name == null) + throw new Error("name cannot be null."); + this.name = name; + } + return TransformConstraintData; + }()); + spine.TransformConstraintData = TransformConstraintData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var Triangulator = (function () { + function Triangulator() { + this.convexPolygons = new Array(); + this.convexPolygonsIndices = new Array(); + this.indicesArray = new Array(); + this.isConcaveArray = new Array(); + this.triangles = new Array(); + this.polygonPool = new spine.Pool(function () { + return new Array(); + }); + this.polygonIndicesPool = new spine.Pool(function () { + return new Array(); + }); + } + Triangulator.prototype.triangulate = function (verticesArray) { + var vertices = verticesArray; + var vertexCount = verticesArray.length >> 1; + var indices = this.indicesArray; + indices.length = 0; + for (var i = 0; i < vertexCount; i++) + indices[i] = i; + var isConcave = this.isConcaveArray; + isConcave.length = 0; + for (var i = 0, n = vertexCount; i < n; ++i) + isConcave[i] = Triangulator.isConcave(i, vertexCount, vertices, indices); + var triangles = this.triangles; + triangles.length = 0; + while (vertexCount > 3) { + var previous = vertexCount - 1, i = 0, next = 1; + while (true) { + outer: if (!isConcave[i]) { + var p1 = indices[previous] << 1, p2 = indices[i] << 1, p3 = indices[next] << 1; + var p1x = vertices[p1], p1y = vertices[p1 + 1]; + var p2x = vertices[p2], p2y = vertices[p2 + 1]; + var p3x = vertices[p3], p3y = vertices[p3 + 1]; + for (var ii = (next + 1) % vertexCount; ii != previous; ii = (ii + 1) % vertexCount) { + if (!isConcave[ii]) + continue; + var v = indices[ii] << 1; + var vx = vertices[v], vy = vertices[v + 1]; + if (Triangulator.positiveArea(p3x, p3y, p1x, p1y, vx, vy)) { + if (Triangulator.positiveArea(p1x, p1y, p2x, p2y, vx, vy)) { + if (Triangulator.positiveArea(p2x, p2y, p3x, p3y, vx, vy)) + break outer; + } + } + } + break; + } + if (next == 0) { + do { + if (!isConcave[i]) + break; + i--; + } while (i > 0); + break; + } + previous = i; + i = next; + next = (next + 1) % vertexCount; + } + triangles.push(indices[(vertexCount + i - 1) % vertexCount]); + triangles.push(indices[i]); + triangles.push(indices[(i + 1) % vertexCount]); + indices.splice(i, 1); + isConcave.splice(i, 1); + vertexCount--; + var previousIndex = (vertexCount + i - 1) % vertexCount; + var nextIndex = i == vertexCount ? 0 : i; + isConcave[previousIndex] = Triangulator.isConcave(previousIndex, vertexCount, vertices, indices); + isConcave[nextIndex] = Triangulator.isConcave(nextIndex, vertexCount, vertices, indices); + } + if (vertexCount == 3) { + triangles.push(indices[2]); + triangles.push(indices[0]); + triangles.push(indices[1]); + } + return triangles; + }; + Triangulator.prototype.decompose = function (verticesArray, triangles) { + var vertices = verticesArray; + var convexPolygons = this.convexPolygons; + this.polygonPool.freeAll(convexPolygons); + convexPolygons.length = 0; + var convexPolygonsIndices = this.convexPolygonsIndices; + this.polygonIndicesPool.freeAll(convexPolygonsIndices); + convexPolygonsIndices.length = 0; + var polygonIndices = this.polygonIndicesPool.obtain(); + polygonIndices.length = 0; + var polygon = this.polygonPool.obtain(); + polygon.length = 0; + var fanBaseIndex = -1, lastWinding = 0; + for (var i = 0, n = triangles.length; i < n; i += 3) { + var t1 = triangles[i] << 1, t2 = triangles[i + 1] << 1, t3 = triangles[i + 2] << 1; + var x1 = vertices[t1], y1 = vertices[t1 + 1]; + var x2 = vertices[t2], y2 = vertices[t2 + 1]; + var x3 = vertices[t3], y3 = vertices[t3 + 1]; + var merged = false; + if (fanBaseIndex == t1) { + var o = polygon.length - 4; + var winding1 = Triangulator.winding(polygon[o], polygon[o + 1], polygon[o + 2], polygon[o + 3], x3, y3); + var winding2 = Triangulator.winding(x3, y3, polygon[0], polygon[1], polygon[2], polygon[3]); + if (winding1 == lastWinding && winding2 == lastWinding) { + polygon.push(x3); + polygon.push(y3); + polygonIndices.push(t3); + merged = true; + } + } + if (!merged) { + if (polygon.length > 0) { + convexPolygons.push(polygon); + convexPolygonsIndices.push(polygonIndices); + } + else { + this.polygonPool.free(polygon); + this.polygonIndicesPool.free(polygonIndices); + } + polygon = this.polygonPool.obtain(); + polygon.length = 0; + polygon.push(x1); + polygon.push(y1); + polygon.push(x2); + polygon.push(y2); + polygon.push(x3); + polygon.push(y3); + polygonIndices = this.polygonIndicesPool.obtain(); + polygonIndices.length = 0; + polygonIndices.push(t1); + polygonIndices.push(t2); + polygonIndices.push(t3); + lastWinding = Triangulator.winding(x1, y1, x2, y2, x3, y3); + fanBaseIndex = t1; + } + } + if (polygon.length > 0) { + convexPolygons.push(polygon); + convexPolygonsIndices.push(polygonIndices); + } + for (var i = 0, n = convexPolygons.length; i < n; i++) { + polygonIndices = convexPolygonsIndices[i]; + if (polygonIndices.length == 0) + continue; + var firstIndex = polygonIndices[0]; + var lastIndex = polygonIndices[polygonIndices.length - 1]; + polygon = convexPolygons[i]; + var o = polygon.length - 4; + var prevPrevX = polygon[o], prevPrevY = polygon[o + 1]; + var prevX = polygon[o + 2], prevY = polygon[o + 3]; + var firstX = polygon[0], firstY = polygon[1]; + var secondX = polygon[2], secondY = polygon[3]; + var winding = Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, firstX, firstY); + for (var ii = 0; ii < n; ii++) { + if (ii == i) + continue; + var otherIndices = convexPolygonsIndices[ii]; + if (otherIndices.length != 3) + continue; + var otherFirstIndex = otherIndices[0]; + var otherSecondIndex = otherIndices[1]; + var otherLastIndex = otherIndices[2]; + var otherPoly = convexPolygons[ii]; + var x3 = otherPoly[otherPoly.length - 2], y3 = otherPoly[otherPoly.length - 1]; + if (otherFirstIndex != firstIndex || otherSecondIndex != lastIndex) + continue; + var winding1 = Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, x3, y3); + var winding2 = Triangulator.winding(x3, y3, firstX, firstY, secondX, secondY); + if (winding1 == winding && winding2 == winding) { + otherPoly.length = 0; + otherIndices.length = 0; + polygon.push(x3); + polygon.push(y3); + polygonIndices.push(otherLastIndex); + prevPrevX = prevX; + prevPrevY = prevY; + prevX = x3; + prevY = y3; + ii = 0; + } + } + } + for (var i = convexPolygons.length - 1; i >= 0; i--) { + polygon = convexPolygons[i]; + if (polygon.length == 0) { + convexPolygons.splice(i, 1); + this.polygonPool.free(polygon); + polygonIndices = convexPolygonsIndices[i]; + convexPolygonsIndices.splice(i, 1); + this.polygonIndicesPool.free(polygonIndices); + } + } + return convexPolygons; + }; + Triangulator.isConcave = function (index, vertexCount, vertices, indices) { + var previous = indices[(vertexCount + index - 1) % vertexCount] << 1; + var current = indices[index] << 1; + var next = indices[(index + 1) % vertexCount] << 1; + return !this.positiveArea(vertices[previous], vertices[previous + 1], vertices[current], vertices[current + 1], vertices[next], vertices[next + 1]); + }; + Triangulator.positiveArea = function (p1x, p1y, p2x, p2y, p3x, p3y) { + return p1x * (p3y - p2y) + p2x * (p1y - p3y) + p3x * (p2y - p1y) >= 0; + }; + Triangulator.winding = function (p1x, p1y, p2x, p2y, p3x, p3y) { + var px = p2x - p1x, py = p2y - p1y; + return p3x * py - p3y * px + px * p1y - p1x * py >= 0 ? 1 : -1; + }; + return Triangulator; + }()); + spine.Triangulator = Triangulator; +})(spine || (spine = {})); +var spine; +(function (spine) { + var IntSet = (function () { + function IntSet() { + this.array = new Array(); + } + IntSet.prototype.add = function (value) { + var contains = this.contains(value); + this.array[value | 0] = value | 0; + return !contains; + }; + IntSet.prototype.contains = function (value) { + return this.array[value | 0] != undefined; + }; + IntSet.prototype.remove = function (value) { + this.array[value | 0] = undefined; + }; + IntSet.prototype.clear = function () { + this.array.length = 0; + }; + return IntSet; + }()); + spine.IntSet = IntSet; + var Color = (function () { + function Color(r, g, b, a) { + if (r === void 0) { r = 0; } + if (g === void 0) { g = 0; } + if (b === void 0) { b = 0; } + if (a === void 0) { a = 0; } + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + Color.prototype.set = function (r, g, b, a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + this.clamp(); + return this; + }; + Color.prototype.setFromColor = function (c) { + this.r = c.r; + this.g = c.g; + this.b = c.b; + this.a = c.a; + return this; + }; + Color.prototype.setFromString = function (hex) { + hex = hex.charAt(0) == '#' ? hex.substr(1) : hex; + this.r = parseInt(hex.substr(0, 2), 16) / 255.0; + this.g = parseInt(hex.substr(2, 2), 16) / 255.0; + this.b = parseInt(hex.substr(4, 2), 16) / 255.0; + this.a = (hex.length != 8 ? 255 : parseInt(hex.substr(6, 2), 16)) / 255.0; + return this; + }; + Color.prototype.add = function (r, g, b, a) { + this.r += r; + this.g += g; + this.b += b; + this.a += a; + this.clamp(); + return this; + }; + Color.prototype.clamp = function () { + if (this.r < 0) + this.r = 0; + else if (this.r > 1) + this.r = 1; + if (this.g < 0) + this.g = 0; + else if (this.g > 1) + this.g = 1; + if (this.b < 0) + this.b = 0; + else if (this.b > 1) + this.b = 1; + if (this.a < 0) + this.a = 0; + else if (this.a > 1) + this.a = 1; + return this; + }; + Color.WHITE = new Color(1, 1, 1, 1); + Color.RED = new Color(1, 0, 0, 1); + Color.GREEN = new Color(0, 1, 0, 1); + Color.BLUE = new Color(0, 0, 1, 1); + Color.MAGENTA = new Color(1, 0, 1, 1); + return Color; + }()); + spine.Color = Color; + var MathUtils = (function () { + function MathUtils() { + } + MathUtils.clamp = function (value, min, max) { + if (value < min) + return min; + if (value > max) + return max; + return value; + }; + MathUtils.cosDeg = function (degrees) { + return Math.cos(degrees * MathUtils.degRad); + }; + MathUtils.sinDeg = function (degrees) { + return Math.sin(degrees * MathUtils.degRad); + }; + MathUtils.signum = function (value) { + return value > 0 ? 1 : value < 0 ? -1 : 0; + }; + MathUtils.toInt = function (x) { + return x > 0 ? Math.floor(x) : Math.ceil(x); + }; + MathUtils.cbrt = function (x) { + var y = Math.pow(Math.abs(x), 1 / 3); + return x < 0 ? -y : y; + }; + MathUtils.randomTriangular = function (min, max) { + return MathUtils.randomTriangularWith(min, max, (min + max) * 0.5); + }; + MathUtils.randomTriangularWith = function (min, max, mode) { + var u = Math.random(); + var d = max - min; + if (u <= (mode - min) / d) + return min + Math.sqrt(u * d * (mode - min)); + return max - Math.sqrt((1 - u) * d * (max - mode)); + }; + MathUtils.PI = 3.1415927; + MathUtils.PI2 = MathUtils.PI * 2; + MathUtils.radiansToDegrees = 180 / MathUtils.PI; + MathUtils.radDeg = MathUtils.radiansToDegrees; + MathUtils.degreesToRadians = MathUtils.PI / 180; + MathUtils.degRad = MathUtils.degreesToRadians; + return MathUtils; + }()); + spine.MathUtils = MathUtils; + var Interpolation = (function () { + function Interpolation() { + } + Interpolation.prototype.apply = function (start, end, a) { + return start + (end - start) * this.applyInternal(a); + }; + return Interpolation; + }()); + spine.Interpolation = Interpolation; + var Pow = (function (_super) { + __extends(Pow, _super); + function Pow(power) { + var _this = _super.call(this) || this; + _this.power = 2; + _this.power = power; + return _this; + } + Pow.prototype.applyInternal = function (a) { + if (a <= 0.5) + return Math.pow(a * 2, this.power) / 2; + return Math.pow((a - 1) * 2, this.power) / (this.power % 2 == 0 ? -2 : 2) + 1; + }; + return Pow; + }(Interpolation)); + spine.Pow = Pow; + var PowOut = (function (_super) { + __extends(PowOut, _super); + function PowOut(power) { + return _super.call(this, power) || this; + } + PowOut.prototype.applyInternal = function (a) { + return Math.pow(a - 1, this.power) * (this.power % 2 == 0 ? -1 : 1) + 1; + }; + return PowOut; + }(Pow)); + spine.PowOut = PowOut; + var Utils = (function () { + function Utils() { + } + Utils.arrayCopy = function (source, sourceStart, dest, destStart, numElements) { + for (var i = sourceStart, j = destStart; i < sourceStart + numElements; i++, j++) { + dest[j] = source[i]; + } + }; + Utils.setArraySize = function (array, size, value) { + if (value === void 0) { value = 0; } + var oldSize = array.length; + if (oldSize == size) + return array; + array.length = size; + if (oldSize < size) { + for (var i = oldSize; i < size; i++) + array[i] = value; + } + return array; + }; + Utils.ensureArrayCapacity = function (array, size, value) { + if (value === void 0) { value = 0; } + if (array.length >= size) + return array; + return Utils.setArraySize(array, size, value); + }; + Utils.newArray = function (size, defaultValue) { + var array = new Array(size); + for (var i = 0; i < size; i++) + array[i] = defaultValue; + return array; + }; + Utils.newFloatArray = function (size) { + if (Utils.SUPPORTS_TYPED_ARRAYS) { + return new Float32Array(size); + } + else { + var array = new Array(size); + for (var i = 0; i < array.length; i++) + array[i] = 0; + return array; + } + }; + Utils.newShortArray = function (size) { + if (Utils.SUPPORTS_TYPED_ARRAYS) { + return new Int16Array(size); + } + else { + var array = new Array(size); + for (var i = 0; i < array.length; i++) + array[i] = 0; + return array; + } + }; + Utils.toFloatArray = function (array) { + return Utils.SUPPORTS_TYPED_ARRAYS ? new Float32Array(array) : array; + }; + Utils.toSinglePrecision = function (value) { + return Utils.SUPPORTS_TYPED_ARRAYS ? Math.fround(value) : value; + }; + Utils.webkit602BugfixHelper = function (alpha, blend) { + }; + Utils.SUPPORTS_TYPED_ARRAYS = typeof (Float32Array) !== "undefined"; + return Utils; + }()); + spine.Utils = Utils; + var DebugUtils = (function () { + function DebugUtils() { + } + DebugUtils.logBones = function (skeleton) { + for (var i = 0; i < skeleton.bones.length; i++) { + var bone = skeleton.bones[i]; + console.log(bone.data.name + ", " + bone.a + ", " + bone.b + ", " + bone.c + ", " + bone.d + ", " + bone.worldX + ", " + bone.worldY); + } + }; + return DebugUtils; + }()); + spine.DebugUtils = DebugUtils; + var Pool = (function () { + function Pool(instantiator) { + this.items = new Array(); + this.instantiator = instantiator; + } + Pool.prototype.obtain = function () { + return this.items.length > 0 ? this.items.pop() : this.instantiator(); + }; + Pool.prototype.free = function (item) { + if (item.reset) + item.reset(); + this.items.push(item); + }; + Pool.prototype.freeAll = function (items) { + for (var i = 0; i < items.length; i++) { + if (items[i].reset) + items[i].reset(); + this.items[i] = items[i]; + } + }; + Pool.prototype.clear = function () { + this.items.length = 0; + }; + return Pool; + }()); + spine.Pool = Pool; + var Vector2 = (function () { + function Vector2(x, y) { + if (x === void 0) { x = 0; } + if (y === void 0) { y = 0; } + this.x = x; + this.y = y; + } + Vector2.prototype.set = function (x, y) { + this.x = x; + this.y = y; + return this; + }; + Vector2.prototype.length = function () { + var x = this.x; + var y = this.y; + return Math.sqrt(x * x + y * y); + }; + Vector2.prototype.normalize = function () { + var len = this.length(); + if (len != 0) { + this.x /= len; + this.y /= len; + } + return this; + }; + return Vector2; + }()); + spine.Vector2 = Vector2; + var TimeKeeper = (function () { + function TimeKeeper() { + this.maxDelta = 0.064; + this.framesPerSecond = 0; + this.delta = 0; + this.totalTime = 0; + this.lastTime = Date.now() / 1000; + this.frameCount = 0; + this.frameTime = 0; + } + TimeKeeper.prototype.update = function () { + var now = Date.now() / 1000; + this.delta = now - this.lastTime; + this.frameTime += this.delta; + this.totalTime += this.delta; + if (this.delta > this.maxDelta) + this.delta = this.maxDelta; + this.lastTime = now; + this.frameCount++; + if (this.frameTime > 1) { + this.framesPerSecond = this.frameCount / this.frameTime; + this.frameTime = 0; + this.frameCount = 0; + } + }; + return TimeKeeper; + }()); + spine.TimeKeeper = TimeKeeper; + var WindowedMean = (function () { + function WindowedMean(windowSize) { + if (windowSize === void 0) { windowSize = 32; } + this.addedValues = 0; + this.lastValue = 0; + this.mean = 0; + this.dirty = true; + this.values = new Array(windowSize); + } + WindowedMean.prototype.hasEnoughData = function () { + return this.addedValues >= this.values.length; + }; + WindowedMean.prototype.addValue = function (value) { + if (this.addedValues < this.values.length) + this.addedValues++; + this.values[this.lastValue++] = value; + if (this.lastValue > this.values.length - 1) + this.lastValue = 0; + this.dirty = true; + }; + WindowedMean.prototype.getMean = function () { + if (this.hasEnoughData()) { + if (this.dirty) { + var mean = 0; + for (var i = 0; i < this.values.length; i++) { + mean += this.values[i]; + } + this.mean = mean / this.values.length; + this.dirty = false; + } + return this.mean; + } + else { + return 0; + } + }; + return WindowedMean; + }()); + spine.WindowedMean = WindowedMean; +})(spine || (spine = {})); +(function () { + if (!Math.fround) { + Math.fround = (function (array) { + return function (x) { + return array[0] = x, array[0]; + }; + })(new Float32Array(1)); + } +})(); +var spine; +(function (spine) { + var Attachment = (function () { + function Attachment(name) { + if (name == null) + throw new Error("name cannot be null."); + this.name = name; + } + return Attachment; + }()); + spine.Attachment = Attachment; + var VertexAttachment = (function (_super) { + __extends(VertexAttachment, _super); + function VertexAttachment(name) { + var _this = _super.call(this, name) || this; + _this.id = (VertexAttachment.nextID++ & 65535) << 11; + _this.worldVerticesLength = 0; + return _this; + } + VertexAttachment.prototype.computeWorldVertices = function (slot, start, count, worldVertices, offset, stride) { + count = offset + (count >> 1) * stride; + var skeleton = slot.bone.skeleton; + var deformArray = slot.attachmentVertices; + var vertices = this.vertices; + var bones = this.bones; + if (bones == null) { + if (deformArray.length > 0) + vertices = deformArray; + var bone = slot.bone; + var x = bone.worldX; + var y = bone.worldY; + var a = bone.a, b = bone.b, c = bone.c, d = bone.d; + for (var v_1 = start, w = offset; w < count; v_1 += 2, w += stride) { + var vx = vertices[v_1], vy = vertices[v_1 + 1]; + worldVertices[w] = vx * a + vy * b + x; + worldVertices[w + 1] = vx * c + vy * d + y; + } + return; + } + var v = 0, skip = 0; + for (var i = 0; i < start; i += 2) { + var n = bones[v]; + v += n + 1; + skip += n; + } + var skeletonBones = skeleton.bones; + if (deformArray.length == 0) { + for (var w = offset, b = skip * 3; w < count; w += stride) { + var wx = 0, wy = 0; + var n = bones[v++]; + n += v; + for (; v < n; v++, b += 3) { + var bone = skeletonBones[bones[v]]; + var vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } + else { + var deform = deformArray; + for (var w = offset, b = skip * 3, f = skip << 1; w < count; w += stride) { + var wx = 0, wy = 0; + var n = bones[v++]; + n += v; + for (; v < n; v++, b += 3, f += 2) { + var bone = skeletonBones[bones[v]]; + var vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } + }; + VertexAttachment.prototype.applyDeform = function (sourceAttachment) { + return this == sourceAttachment; + }; + VertexAttachment.nextID = 0; + return VertexAttachment; + }(Attachment)); + spine.VertexAttachment = VertexAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var AttachmentType; + (function (AttachmentType) { + AttachmentType[AttachmentType["Region"] = 0] = "Region"; + AttachmentType[AttachmentType["BoundingBox"] = 1] = "BoundingBox"; + AttachmentType[AttachmentType["Mesh"] = 2] = "Mesh"; + AttachmentType[AttachmentType["LinkedMesh"] = 3] = "LinkedMesh"; + AttachmentType[AttachmentType["Path"] = 4] = "Path"; + AttachmentType[AttachmentType["Point"] = 5] = "Point"; + })(AttachmentType = spine.AttachmentType || (spine.AttachmentType = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var BoundingBoxAttachment = (function (_super) { + __extends(BoundingBoxAttachment, _super); + function BoundingBoxAttachment(name) { + var _this = _super.call(this, name) || this; + _this.color = new spine.Color(1, 1, 1, 1); + return _this; + } + return BoundingBoxAttachment; + }(spine.VertexAttachment)); + spine.BoundingBoxAttachment = BoundingBoxAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var ClippingAttachment = (function (_super) { + __extends(ClippingAttachment, _super); + function ClippingAttachment(name) { + var _this = _super.call(this, name) || this; + _this.color = new spine.Color(0.2275, 0.2275, 0.8078, 1); + return _this; + } + return ClippingAttachment; + }(spine.VertexAttachment)); + spine.ClippingAttachment = ClippingAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var MeshAttachment = (function (_super) { + __extends(MeshAttachment, _super); + function MeshAttachment(name) { + var _this = _super.call(this, name) || this; + _this.color = new spine.Color(1, 1, 1, 1); + _this.inheritDeform = false; + _this.tempColor = new spine.Color(0, 0, 0, 0); + return _this; + } + MeshAttachment.prototype.updateUVs = function () { + var regionUVs = this.regionUVs; + if (this.uvs == null || this.uvs.length != regionUVs.length) + this.uvs = spine.Utils.newFloatArray(regionUVs.length); + var uvs = this.uvs; + var u = 0, v = 0, width = 0, height = 0; + if (this.region instanceof spine.TextureAtlasRegion) { + var region = this.region; + var textureWidth = region.texture.getImage().width, textureHeight = region.texture.getImage().height; + if (region.rotate) { + u = region.u - (region.originalHeight - region.offsetY - region.height) / textureWidth; + v = region.v - (region.originalWidth - region.offsetX - region.width) / textureHeight; + width = region.originalHeight / textureWidth; + height = region.originalWidth / textureHeight; + for (var i = 0, n = uvs.length; i < n; i += 2) { + uvs[i] = u + regionUVs[i + 1] * width; + uvs[i + 1] = v + height - regionUVs[i] * height; + } + return; + } + u = region.u - region.offsetX / textureWidth; + v = region.v - (region.originalHeight - region.offsetY - region.height) / textureHeight; + width = region.originalWidth / textureWidth; + height = region.originalHeight / textureHeight; + } + else if (this.region == null) { + u = v = 0; + width = height = 1; + } + else { + u = this.region.u; + v = this.region.v; + width = this.region.u2 - u; + height = this.region.v2 - v; + } + for (var i = 0, n = uvs.length; i < n; i += 2) { + uvs[i] = u + regionUVs[i] * width; + uvs[i + 1] = v + regionUVs[i + 1] * height; + } + }; + MeshAttachment.prototype.applyDeform = function (sourceAttachment) { + return this == sourceAttachment || (this.inheritDeform && this.parentMesh == sourceAttachment); + }; + MeshAttachment.prototype.getParentMesh = function () { + return this.parentMesh; + }; + MeshAttachment.prototype.setParentMesh = function (parentMesh) { + this.parentMesh = parentMesh; + if (parentMesh != null) { + this.bones = parentMesh.bones; + this.vertices = parentMesh.vertices; + this.worldVerticesLength = parentMesh.worldVerticesLength; + this.regionUVs = parentMesh.regionUVs; + this.triangles = parentMesh.triangles; + this.hullLength = parentMesh.hullLength; + this.worldVerticesLength = parentMesh.worldVerticesLength; + } + }; + return MeshAttachment; + }(spine.VertexAttachment)); + spine.MeshAttachment = MeshAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var PathAttachment = (function (_super) { + __extends(PathAttachment, _super); + function PathAttachment(name) { + var _this = _super.call(this, name) || this; + _this.closed = false; + _this.constantSpeed = false; + _this.color = new spine.Color(1, 1, 1, 1); + return _this; + } + return PathAttachment; + }(spine.VertexAttachment)); + spine.PathAttachment = PathAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var PointAttachment = (function (_super) { + __extends(PointAttachment, _super); + function PointAttachment(name) { + var _this = _super.call(this, name) || this; + _this.color = new spine.Color(0.38, 0.94, 0, 1); + return _this; + } + PointAttachment.prototype.computeWorldPosition = function (bone, point) { + point.x = this.x * bone.a + this.y * bone.b + bone.worldX; + point.y = this.x * bone.c + this.y * bone.d + bone.worldY; + return point; + }; + PointAttachment.prototype.computeWorldRotation = function (bone) { + var cos = spine.MathUtils.cosDeg(this.rotation), sin = spine.MathUtils.sinDeg(this.rotation); + var x = cos * bone.a + sin * bone.b; + var y = cos * bone.c + sin * bone.d; + return Math.atan2(y, x) * spine.MathUtils.radDeg; + }; + return PointAttachment; + }(spine.VertexAttachment)); + spine.PointAttachment = PointAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var RegionAttachment = (function (_super) { + __extends(RegionAttachment, _super); + function RegionAttachment(name) { + var _this = _super.call(this, name) || this; + _this.x = 0; + _this.y = 0; + _this.scaleX = 1; + _this.scaleY = 1; + _this.rotation = 0; + _this.width = 0; + _this.height = 0; + _this.color = new spine.Color(1, 1, 1, 1); + _this.offset = spine.Utils.newFloatArray(8); + _this.uvs = spine.Utils.newFloatArray(8); + _this.tempColor = new spine.Color(1, 1, 1, 1); + return _this; + } + RegionAttachment.prototype.updateOffset = function () { + var regionScaleX = this.width / this.region.originalWidth * this.scaleX; + var regionScaleY = this.height / this.region.originalHeight * this.scaleY; + var localX = -this.width / 2 * this.scaleX + this.region.offsetX * regionScaleX; + var localY = -this.height / 2 * this.scaleY + this.region.offsetY * regionScaleY; + var localX2 = localX + this.region.width * regionScaleX; + var localY2 = localY + this.region.height * regionScaleY; + var radians = this.rotation * Math.PI / 180; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + var localXCos = localX * cos + this.x; + var localXSin = localX * sin; + var localYCos = localY * cos + this.y; + var localYSin = localY * sin; + var localX2Cos = localX2 * cos + this.x; + var localX2Sin = localX2 * sin; + var localY2Cos = localY2 * cos + this.y; + var localY2Sin = localY2 * sin; + var offset = this.offset; + offset[RegionAttachment.OX1] = localXCos - localYSin; + offset[RegionAttachment.OY1] = localYCos + localXSin; + offset[RegionAttachment.OX2] = localXCos - localY2Sin; + offset[RegionAttachment.OY2] = localY2Cos + localXSin; + offset[RegionAttachment.OX3] = localX2Cos - localY2Sin; + offset[RegionAttachment.OY3] = localY2Cos + localX2Sin; + offset[RegionAttachment.OX4] = localX2Cos - localYSin; + offset[RegionAttachment.OY4] = localYCos + localX2Sin; + }; + RegionAttachment.prototype.setRegion = function (region) { + this.region = region; + var uvs = this.uvs; + if (region.rotate) { + uvs[2] = region.u; + uvs[3] = region.v2; + uvs[4] = region.u; + uvs[5] = region.v; + uvs[6] = region.u2; + uvs[7] = region.v; + uvs[0] = region.u2; + uvs[1] = region.v2; + } + else { + uvs[0] = region.u; + uvs[1] = region.v2; + uvs[2] = region.u; + uvs[3] = region.v; + uvs[4] = region.u2; + uvs[5] = region.v; + uvs[6] = region.u2; + uvs[7] = region.v2; + } + }; + RegionAttachment.prototype.computeWorldVertices = function (bone, worldVertices, offset, stride) { + var vertexOffset = this.offset; + var x = bone.worldX, y = bone.worldY; + var a = bone.a, b = bone.b, c = bone.c, d = bone.d; + var offsetX = 0, offsetY = 0; + offsetX = vertexOffset[RegionAttachment.OX1]; + offsetY = vertexOffset[RegionAttachment.OY1]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[RegionAttachment.OX2]; + offsetY = vertexOffset[RegionAttachment.OY2]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[RegionAttachment.OX3]; + offsetY = vertexOffset[RegionAttachment.OY3]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[RegionAttachment.OX4]; + offsetY = vertexOffset[RegionAttachment.OY4]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + }; + RegionAttachment.OX1 = 0; + RegionAttachment.OY1 = 1; + RegionAttachment.OX2 = 2; + RegionAttachment.OY2 = 3; + RegionAttachment.OX3 = 4; + RegionAttachment.OY3 = 5; + RegionAttachment.OX4 = 6; + RegionAttachment.OY4 = 7; + RegionAttachment.X1 = 0; + RegionAttachment.Y1 = 1; + RegionAttachment.C1R = 2; + RegionAttachment.C1G = 3; + RegionAttachment.C1B = 4; + RegionAttachment.C1A = 5; + RegionAttachment.U1 = 6; + RegionAttachment.V1 = 7; + RegionAttachment.X2 = 8; + RegionAttachment.Y2 = 9; + RegionAttachment.C2R = 10; + RegionAttachment.C2G = 11; + RegionAttachment.C2B = 12; + RegionAttachment.C2A = 13; + RegionAttachment.U2 = 14; + RegionAttachment.V2 = 15; + RegionAttachment.X3 = 16; + RegionAttachment.Y3 = 17; + RegionAttachment.C3R = 18; + RegionAttachment.C3G = 19; + RegionAttachment.C3B = 20; + RegionAttachment.C3A = 21; + RegionAttachment.U3 = 22; + RegionAttachment.V3 = 23; + RegionAttachment.X4 = 24; + RegionAttachment.Y4 = 25; + RegionAttachment.C4R = 26; + RegionAttachment.C4G = 27; + RegionAttachment.C4B = 28; + RegionAttachment.C4A = 29; + RegionAttachment.U4 = 30; + RegionAttachment.V4 = 31; + return RegionAttachment; + }(spine.Attachment)); + spine.RegionAttachment = RegionAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var JitterEffect = (function () { + function JitterEffect(jitterX, jitterY) { + this.jitterX = 0; + this.jitterY = 0; + this.jitterX = jitterX; + this.jitterY = jitterY; + } + JitterEffect.prototype.begin = function (skeleton) { + }; + JitterEffect.prototype.transform = function (position, uv, light, dark) { + position.x += spine.MathUtils.randomTriangular(-this.jitterX, this.jitterY); + position.y += spine.MathUtils.randomTriangular(-this.jitterX, this.jitterY); + }; + JitterEffect.prototype.end = function () { + }; + return JitterEffect; + }()); + spine.JitterEffect = JitterEffect; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SwirlEffect = (function () { + function SwirlEffect(radius) { + this.centerX = 0; + this.centerY = 0; + this.radius = 0; + this.angle = 0; + this.worldX = 0; + this.worldY = 0; + this.radius = radius; + } + SwirlEffect.prototype.begin = function (skeleton) { + this.worldX = skeleton.x + this.centerX; + this.worldY = skeleton.y + this.centerY; + }; + SwirlEffect.prototype.transform = function (position, uv, light, dark) { + var radAngle = this.angle * spine.MathUtils.degreesToRadians; + var x = position.x - this.worldX; + var y = position.y - this.worldY; + var dist = Math.sqrt(x * x + y * y); + if (dist < this.radius) { + var theta = SwirlEffect.interpolation.apply(0, radAngle, (this.radius - dist) / this.radius); + var cos = Math.cos(theta); + var sin = Math.sin(theta); + position.x = cos * x - sin * y + this.worldX; + position.y = sin * x + cos * y + this.worldY; + } + }; + SwirlEffect.prototype.end = function () { + }; + SwirlEffect.interpolation = new spine.PowOut(2); + return SwirlEffect; + }()); + spine.SwirlEffect = SwirlEffect; +})(spine || (spine = {})); +var spine; +(function (spine) { + var canvas; + (function (canvas) { + var AssetManager = (function (_super) { + __extends(AssetManager, _super); + function AssetManager(pathPrefix) { + if (pathPrefix === void 0) { pathPrefix = ""; } + return _super.call(this, function (image) { return new spine.canvas.CanvasTexture(image); }, pathPrefix) || this; + } + return AssetManager; + }(spine.AssetManager)); + canvas.AssetManager = AssetManager; + })(canvas = spine.canvas || (spine.canvas = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var canvas; + (function (canvas) { + var CanvasTexture = (function (_super) { + __extends(CanvasTexture, _super); + function CanvasTexture(image) { + return _super.call(this, image) || this; + } + CanvasTexture.prototype.setFilters = function (minFilter, magFilter) { }; + CanvasTexture.prototype.setWraps = function (uWrap, vWrap) { }; + CanvasTexture.prototype.dispose = function () { }; + return CanvasTexture; + }(spine.Texture)); + canvas.CanvasTexture = CanvasTexture; + })(canvas = spine.canvas || (spine.canvas = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var canvas; + (function (canvas) { + var SkeletonRenderer = (function () { + function SkeletonRenderer(context) { + this.triangleRendering = false; + this.debugRendering = false; + this.vertices = spine.Utils.newFloatArray(8 * 1024); + this.tempColor = new spine.Color(); + this.ctx = context; + } + SkeletonRenderer.prototype.draw = function (skeleton) { + if (this.triangleRendering) + this.drawTriangles(skeleton); + else + this.drawImages(skeleton); + }; + SkeletonRenderer.prototype.drawImages = function (skeleton) { + var ctx = this.ctx; + var drawOrder = skeleton.drawOrder; + if (this.debugRendering) + ctx.strokeStyle = "green"; + ctx.save(); + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.getAttachment(); + var regionAttachment = null; + var region = null; + var image = null; + if (attachment instanceof spine.RegionAttachment) { + regionAttachment = attachment; + region = regionAttachment.region; + image = region.texture.getImage(); + } + else + continue; + var skeleton_1 = slot.bone.skeleton; + var skeletonColor = skeleton_1.color; + var slotColor = slot.color; + var regionColor = regionAttachment.color; + var alpha = skeletonColor.a * slotColor.a * regionColor.a; + var color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * regionColor.r, skeletonColor.g * slotColor.g * regionColor.g, skeletonColor.b * slotColor.b * regionColor.b, alpha); + var att = attachment; + var bone = slot.bone; + var w = region.width; + var h = region.height; + ctx.save(); + ctx.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY); + ctx.translate(attachment.offset[0], attachment.offset[1]); + ctx.rotate(attachment.rotation * Math.PI / 180); + var atlasScale = att.width / w; + ctx.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY); + ctx.translate(w / 2, h / 2); + if (attachment.region.rotate) { + var t = w; + w = h; + h = t; + ctx.rotate(-Math.PI / 2); + } + ctx.scale(1, -1); + ctx.translate(-w / 2, -h / 2); + if (color.r != 1 || color.g != 1 || color.b != 1 || color.a != 1) { + ctx.globalAlpha = color.a; + } + ctx.drawImage(image, region.x, region.y, w, h, 0, 0, w, h); + if (this.debugRendering) + ctx.strokeRect(0, 0, w, h); + ctx.restore(); + } + ctx.restore(); + }; + SkeletonRenderer.prototype.drawTriangles = function (skeleton) { + var blendMode = null; + var vertices = this.vertices; + var triangles = null; + var drawOrder = skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.getAttachment(); + var texture = null; + var region = null; + if (attachment instanceof spine.RegionAttachment) { + var regionAttachment = attachment; + vertices = this.computeRegionVertices(slot, regionAttachment, false); + triangles = SkeletonRenderer.QUAD_TRIANGLES; + region = regionAttachment.region; + texture = region.texture.getImage(); + } + else if (attachment instanceof spine.MeshAttachment) { + var mesh = attachment; + vertices = this.computeMeshVertices(slot, mesh, false); + triangles = mesh.triangles; + texture = mesh.region.renderObject.texture.getImage(); + } + else + continue; + if (texture != null) { + var slotBlendMode = slot.data.blendMode; + if (slotBlendMode != blendMode) { + blendMode = slotBlendMode; + } + var skeleton_2 = slot.bone.skeleton; + var skeletonColor = skeleton_2.color; + var slotColor = slot.color; + var attachmentColor = attachment.color; + var alpha = skeletonColor.a * slotColor.a * attachmentColor.a; + var color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * attachmentColor.r, skeletonColor.g * slotColor.g * attachmentColor.g, skeletonColor.b * slotColor.b * attachmentColor.b, alpha); + var ctx = this.ctx; + if (color.r != 1 || color.g != 1 || color.b != 1 || color.a != 1) { + ctx.globalAlpha = color.a; + } + for (var j = 0; j < triangles.length; j += 3) { + var t1 = triangles[j] * 8, t2 = triangles[j + 1] * 8, t3 = triangles[j + 2] * 8; + var x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7]; + var x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7]; + var x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7]; + this.drawTriangle(texture, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2); + if (this.debugRendering) { + ctx.strokeStyle = "green"; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.lineTo(x0, y0); + ctx.stroke(); + } + } + } + } + this.ctx.globalAlpha = 1; + }; + SkeletonRenderer.prototype.drawTriangle = function (img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2) { + var ctx = this.ctx; + u0 *= img.width; + v0 *= img.height; + u1 *= img.width; + v1 *= img.height; + u2 *= img.width; + v2 *= img.height; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.closePath(); + x1 -= x0; + y1 -= y0; + x2 -= x0; + y2 -= y0; + u1 -= u0; + v1 -= v0; + u2 -= u0; + v2 -= v0; + var det = 1 / (u1 * v2 - u2 * v1), a = (v2 * x1 - v1 * x2) * det, b = (v2 * y1 - v1 * y2) * det, c = (u1 * x2 - u2 * x1) * det, d = (u1 * y2 - u2 * y1) * det, e = x0 - a * u0 - c * v0, f = y0 - b * u0 - d * v0; + ctx.save(); + ctx.transform(a, b, c, d, e, f); + ctx.clip(); + ctx.drawImage(img, 0, 0); + ctx.restore(); + }; + SkeletonRenderer.prototype.computeRegionVertices = function (slot, region, pma) { + var skeleton = slot.bone.skeleton; + var skeletonColor = skeleton.color; + var slotColor = slot.color; + var regionColor = region.color; + var alpha = skeletonColor.a * slotColor.a * regionColor.a; + var multiplier = pma ? alpha : 1; + var color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier, skeletonColor.g * slotColor.g * regionColor.g * multiplier, skeletonColor.b * slotColor.b * regionColor.b * multiplier, alpha); + region.computeWorldVertices(slot.bone, this.vertices, 0, SkeletonRenderer.VERTEX_SIZE); + var vertices = this.vertices; + var uvs = region.uvs; + vertices[spine.RegionAttachment.C1R] = color.r; + vertices[spine.RegionAttachment.C1G] = color.g; + vertices[spine.RegionAttachment.C1B] = color.b; + vertices[spine.RegionAttachment.C1A] = color.a; + vertices[spine.RegionAttachment.U1] = uvs[0]; + vertices[spine.RegionAttachment.V1] = uvs[1]; + vertices[spine.RegionAttachment.C2R] = color.r; + vertices[spine.RegionAttachment.C2G] = color.g; + vertices[spine.RegionAttachment.C2B] = color.b; + vertices[spine.RegionAttachment.C2A] = color.a; + vertices[spine.RegionAttachment.U2] = uvs[2]; + vertices[spine.RegionAttachment.V2] = uvs[3]; + vertices[spine.RegionAttachment.C3R] = color.r; + vertices[spine.RegionAttachment.C3G] = color.g; + vertices[spine.RegionAttachment.C3B] = color.b; + vertices[spine.RegionAttachment.C3A] = color.a; + vertices[spine.RegionAttachment.U3] = uvs[4]; + vertices[spine.RegionAttachment.V3] = uvs[5]; + vertices[spine.RegionAttachment.C4R] = color.r; + vertices[spine.RegionAttachment.C4G] = color.g; + vertices[spine.RegionAttachment.C4B] = color.b; + vertices[spine.RegionAttachment.C4A] = color.a; + vertices[spine.RegionAttachment.U4] = uvs[6]; + vertices[spine.RegionAttachment.V4] = uvs[7]; + return vertices; + }; + SkeletonRenderer.prototype.computeMeshVertices = function (slot, mesh, pma) { + var skeleton = slot.bone.skeleton; + var skeletonColor = skeleton.color; + var slotColor = slot.color; + var regionColor = mesh.color; + var alpha = skeletonColor.a * slotColor.a * regionColor.a; + var multiplier = pma ? alpha : 1; + var color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier, skeletonColor.g * slotColor.g * regionColor.g * multiplier, skeletonColor.b * slotColor.b * regionColor.b * multiplier, alpha); + var numVertices = mesh.worldVerticesLength / 2; + if (this.vertices.length < mesh.worldVerticesLength) { + this.vertices = spine.Utils.newFloatArray(mesh.worldVerticesLength); + } + var vertices = this.vertices; + mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, SkeletonRenderer.VERTEX_SIZE); + var uvs = mesh.uvs; + for (var i = 0, n = numVertices, u = 0, v = 2; i < n; i++) { + vertices[v++] = color.r; + vertices[v++] = color.g; + vertices[v++] = color.b; + vertices[v++] = color.a; + vertices[v++] = uvs[u++]; + vertices[v++] = uvs[u++]; + v += 2; + } + return vertices; + }; + SkeletonRenderer.QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; + SkeletonRenderer.VERTEX_SIZE = 2 + 2 + 4; + return SkeletonRenderer; + }()); + canvas.SkeletonRenderer = SkeletonRenderer; + })(canvas = spine.canvas || (spine.canvas = {})); +})(spine || (spine = {})); +//# sourceMappingURL=spine-canvas.js.map \ No newline at end of file diff --git a/lib/3.8/spine-canvas.js b/lib/3.8/spine-canvas.js new file mode 100644 index 0000000..033550c --- /dev/null +++ b/lib/3.8/spine-canvas.js @@ -0,0 +1,8472 @@ +var __extends = (this && this.__extends) || (function () { + var extendStatics = function (d, b) { + extendStatics = Object.setPrototypeOf || + ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || + function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; + return extendStatics(d, b); + }; + return function (d, b) { + if (typeof b !== "function" && b !== null) + throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); + extendStatics(d, b); + function __() { this.constructor = d; } + d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); + }; +})(); +var spine; +(function (spine) { + var Animation = (function () { + function Animation(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; + } + Animation.prototype.hasTimeline = function (id) { + return this.timelineIds[id] == true; + }; + Animation.prototype.apply = function (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; + } + var timelines = this.timelines; + for (var i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, lastTime, time, events, alpha, blend, direction); + }; + Animation.binarySearch = function (values, target, step) { + if (step === void 0) { step = 1; } + var low = 0; + var high = values.length / step - 2; + if (high == 0) + return step; + var 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; + } + }; + Animation.linearSearch = function (values, target, step) { + for (var i = 0, last = values.length - step; i <= last; i += step) + if (values[i] > target) + return i; + return -1; + }; + return Animation; + }()); + spine.Animation = Animation; + var MixBlend; + (function (MixBlend) { + MixBlend[MixBlend["setup"] = 0] = "setup"; + MixBlend[MixBlend["first"] = 1] = "first"; + MixBlend[MixBlend["replace"] = 2] = "replace"; + MixBlend[MixBlend["add"] = 3] = "add"; + })(MixBlend = spine.MixBlend || (spine.MixBlend = {})); + var MixDirection; + (function (MixDirection) { + MixDirection[MixDirection["mixIn"] = 0] = "mixIn"; + MixDirection[MixDirection["mixOut"] = 1] = "mixOut"; + })(MixDirection = spine.MixDirection || (spine.MixDirection = {})); + var TimelineType; + (function (TimelineType) { + TimelineType[TimelineType["rotate"] = 0] = "rotate"; + TimelineType[TimelineType["translate"] = 1] = "translate"; + TimelineType[TimelineType["scale"] = 2] = "scale"; + TimelineType[TimelineType["shear"] = 3] = "shear"; + TimelineType[TimelineType["attachment"] = 4] = "attachment"; + TimelineType[TimelineType["color"] = 5] = "color"; + TimelineType[TimelineType["deform"] = 6] = "deform"; + TimelineType[TimelineType["event"] = 7] = "event"; + TimelineType[TimelineType["drawOrder"] = 8] = "drawOrder"; + TimelineType[TimelineType["ikConstraint"] = 9] = "ikConstraint"; + TimelineType[TimelineType["transformConstraint"] = 10] = "transformConstraint"; + TimelineType[TimelineType["pathConstraintPosition"] = 11] = "pathConstraintPosition"; + TimelineType[TimelineType["pathConstraintSpacing"] = 12] = "pathConstraintSpacing"; + TimelineType[TimelineType["pathConstraintMix"] = 13] = "pathConstraintMix"; + TimelineType[TimelineType["twoColor"] = 14] = "twoColor"; + })(TimelineType = spine.TimelineType || (spine.TimelineType = {})); + var CurveTimeline = (function () { + function CurveTimeline(frameCount) { + if (frameCount <= 0) + throw new Error("frameCount must be > 0: " + frameCount); + this.curves = spine.Utils.newFloatArray((frameCount - 1) * CurveTimeline.BEZIER_SIZE); + } + CurveTimeline.prototype.getFrameCount = function () { + return this.curves.length / CurveTimeline.BEZIER_SIZE + 1; + }; + CurveTimeline.prototype.setLinear = function (frameIndex) { + this.curves[frameIndex * CurveTimeline.BEZIER_SIZE] = CurveTimeline.LINEAR; + }; + CurveTimeline.prototype.setStepped = function (frameIndex) { + this.curves[frameIndex * CurveTimeline.BEZIER_SIZE] = CurveTimeline.STEPPED; + }; + CurveTimeline.prototype.getCurveType = function (frameIndex) { + var index = frameIndex * CurveTimeline.BEZIER_SIZE; + if (index == this.curves.length) + return CurveTimeline.LINEAR; + var type = this.curves[index]; + if (type == CurveTimeline.LINEAR) + return CurveTimeline.LINEAR; + if (type == CurveTimeline.STEPPED) + return CurveTimeline.STEPPED; + return CurveTimeline.BEZIER; + }; + CurveTimeline.prototype.setCurve = function (frameIndex, cx1, cy1, cx2, cy2) { + var tmpx = (-cx1 * 2 + cx2) * 0.03, tmpy = (-cy1 * 2 + cy2) * 0.03; + var dddfx = ((cx1 - cx2) * 3 + 1) * 0.006, dddfy = ((cy1 - cy2) * 3 + 1) * 0.006; + var ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy; + var dfx = cx1 * 0.3 + tmpx + dddfx * 0.16666667, dfy = cy1 * 0.3 + tmpy + dddfy * 0.16666667; + var i = frameIndex * CurveTimeline.BEZIER_SIZE; + var curves = this.curves; + curves[i++] = CurveTimeline.BEZIER; + var x = dfx, y = dfy; + for (var 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; + } + }; + CurveTimeline.prototype.getCurvePercent = function (frameIndex, percent) { + percent = spine.MathUtils.clamp(percent, 0, 1); + var curves = this.curves; + var i = frameIndex * CurveTimeline.BEZIER_SIZE; + var type = curves[i]; + if (type == CurveTimeline.LINEAR) + return percent; + if (type == CurveTimeline.STEPPED) + return 0; + i++; + var x = 0; + for (var start = i, n = i + CurveTimeline.BEZIER_SIZE - 1; i < n; i += 2) { + x = curves[i]; + if (x >= percent) { + var prevX = void 0, prevY = void 0; + 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); + } + } + var y = curves[i - 1]; + return y + (1 - y) * (percent - x) / (1 - x); + }; + CurveTimeline.LINEAR = 0; + CurveTimeline.STEPPED = 1; + CurveTimeline.BEZIER = 2; + CurveTimeline.BEZIER_SIZE = 10 * 2 - 1; + return CurveTimeline; + }()); + spine.CurveTimeline = CurveTimeline; + var RotateTimeline = (function (_super) { + __extends(RotateTimeline, _super); + function RotateTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount << 1); + return _this; + } + RotateTimeline.prototype.getPropertyId = function () { + return (TimelineType.rotate << 24) + this.boneIndex; + }; + RotateTimeline.prototype.setFrame = function (frameIndex, time, degrees) { + frameIndex <<= 1; + this.frames[frameIndex] = time; + this.frames[frameIndex + RotateTimeline.ROTATION] = degrees; + }; + RotateTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { + var frames = this.frames; + var 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: + var r_1 = bone.data.rotation - bone.rotation; + bone.rotation += (r_1 - (16384 - ((16384.499999999996 - r_1 / 360) | 0)) * 360) * alpha; + } + return; + } + if (time >= frames[frames.length - RotateTimeline.ENTRIES]) { + var r_2 = frames[frames.length + RotateTimeline.PREV_ROTATION]; + switch (blend) { + case MixBlend.setup: + bone.rotation = bone.data.rotation + r_2 * alpha; + break; + case MixBlend.first: + case MixBlend.replace: + r_2 += bone.data.rotation - bone.rotation; + r_2 -= (16384 - ((16384.499999999996 - r_2 / 360) | 0)) * 360; + case MixBlend.add: + bone.rotation += r_2 * alpha; + } + return; + } + var frame = Animation.binarySearch(frames, time, RotateTimeline.ENTRIES); + var prevRotation = frames[frame + RotateTimeline.PREV_ROTATION]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + RotateTimeline.PREV_TIME] - frameTime)); + var 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; + return RotateTimeline; + }(CurveTimeline)); + spine.RotateTimeline = RotateTimeline; + var TranslateTimeline = (function (_super) { + __extends(TranslateTimeline, _super); + function TranslateTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * TranslateTimeline.ENTRIES); + return _this; + } + TranslateTimeline.prototype.getPropertyId = function () { + return (TimelineType.translate << 24) + this.boneIndex; + }; + TranslateTimeline.prototype.setFrame = function (frameIndex, time, x, y) { + frameIndex *= TranslateTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + TranslateTimeline.X] = x; + this.frames[frameIndex + TranslateTimeline.Y] = y; + }; + TranslateTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { + var frames = this.frames; + var 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; + } + var x = 0, y = 0; + if (time >= frames[frames.length - TranslateTimeline.ENTRIES]) { + x = frames[frames.length + TranslateTimeline.PREV_X]; + y = frames[frames.length + TranslateTimeline.PREV_Y]; + } + else { + var frame = Animation.binarySearch(frames, time, TranslateTimeline.ENTRIES); + x = frames[frame + TranslateTimeline.PREV_X]; + y = frames[frame + TranslateTimeline.PREV_Y]; + var frameTime = frames[frame]; + var 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; + return TranslateTimeline; + }(CurveTimeline)); + spine.TranslateTimeline = TranslateTimeline; + var ScaleTimeline = (function (_super) { + __extends(ScaleTimeline, _super); + function ScaleTimeline(frameCount) { + return _super.call(this, frameCount) || this; + } + ScaleTimeline.prototype.getPropertyId = function () { + return (TimelineType.scale << 24) + this.boneIndex; + }; + ScaleTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { + var frames = this.frames; + var 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; + } + var x = 0, y = 0; + if (time >= frames[frames.length - ScaleTimeline.ENTRIES]) { + x = frames[frames.length + ScaleTimeline.PREV_X] * bone.data.scaleX; + y = frames[frames.length + ScaleTimeline.PREV_Y] * bone.data.scaleY; + } + else { + var frame = Animation.binarySearch(frames, time, ScaleTimeline.ENTRIES); + x = frames[frame + ScaleTimeline.PREV_X]; + y = frames[frame + ScaleTimeline.PREV_Y]; + var frameTime = frames[frame]; + var 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 { + var bx = 0, 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) * spine.MathUtils.signum(bx) - bx) * alpha; + bone.scaleY = by + (Math.abs(y) * spine.MathUtils.signum(by) - by) * alpha; + break; + case MixBlend.first: + case MixBlend.replace: + bx = bone.scaleX; + by = bone.scaleY; + bone.scaleX = bx + (Math.abs(x) * spine.MathUtils.signum(bx) - bx) * alpha; + bone.scaleY = by + (Math.abs(y) * spine.MathUtils.signum(by) - by) * alpha; + break; + case MixBlend.add: + bx = bone.scaleX; + by = bone.scaleY; + bone.scaleX = bx + (Math.abs(x) * spine.MathUtils.signum(bx) - bone.data.scaleX) * alpha; + bone.scaleY = by + (Math.abs(y) * spine.MathUtils.signum(by) - bone.data.scaleY) * alpha; + } + } + else { + switch (blend) { + case MixBlend.setup: + bx = Math.abs(bone.data.scaleX) * spine.MathUtils.signum(x); + by = Math.abs(bone.data.scaleY) * spine.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) * spine.MathUtils.signum(x); + by = Math.abs(bone.scaleY) * spine.MathUtils.signum(y); + bone.scaleX = bx + (x - bx) * alpha; + bone.scaleY = by + (y - by) * alpha; + break; + case MixBlend.add: + bx = spine.MathUtils.signum(x); + by = spine.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; + } + } + } + }; + return ScaleTimeline; + }(TranslateTimeline)); + spine.ScaleTimeline = ScaleTimeline; + var ShearTimeline = (function (_super) { + __extends(ShearTimeline, _super); + function ShearTimeline(frameCount) { + return _super.call(this, frameCount) || this; + } + ShearTimeline.prototype.getPropertyId = function () { + return (TimelineType.shear << 24) + this.boneIndex; + }; + ShearTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { + var frames = this.frames; + var 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; + } + var x = 0, y = 0; + if (time >= frames[frames.length - ShearTimeline.ENTRIES]) { + x = frames[frames.length + ShearTimeline.PREV_X]; + y = frames[frames.length + ShearTimeline.PREV_Y]; + } + else { + var frame = Animation.binarySearch(frames, time, ShearTimeline.ENTRIES); + x = frames[frame + ShearTimeline.PREV_X]; + y = frames[frame + ShearTimeline.PREV_Y]; + var frameTime = frames[frame]; + var 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; + } + }; + return ShearTimeline; + }(TranslateTimeline)); + spine.ShearTimeline = ShearTimeline; + var ColorTimeline = (function (_super) { + __extends(ColorTimeline, _super); + function ColorTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * ColorTimeline.ENTRIES); + return _this; + } + ColorTimeline.prototype.getPropertyId = function () { + return (TimelineType.color << 24) + this.slotIndex; + }; + ColorTimeline.prototype.setFrame = function (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; + }; + ColorTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { + var slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + var frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case MixBlend.setup: + slot.color.setFromColor(slot.data.color); + return; + case MixBlend.first: + var color = slot.color, 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; + } + var r = 0, g = 0, b = 0, a = 0; + if (time >= frames[frames.length - ColorTimeline.ENTRIES]) { + var 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 { + var 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]; + var frameTime = frames[frame]; + var 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 { + var 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; + return ColorTimeline; + }(CurveTimeline)); + spine.ColorTimeline = ColorTimeline; + var TwoColorTimeline = (function (_super) { + __extends(TwoColorTimeline, _super); + function TwoColorTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * TwoColorTimeline.ENTRIES); + return _this; + } + TwoColorTimeline.prototype.getPropertyId = function () { + return (TimelineType.twoColor << 24) + this.slotIndex; + }; + TwoColorTimeline.prototype.setFrame = function (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; + }; + TwoColorTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { + var slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + var 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: + var light = slot.color, dark = slot.darkColor, setupLight = slot.data.color, 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; + } + var r = 0, g = 0, b = 0, a = 0, r2 = 0, g2 = 0, b2 = 0; + if (time >= frames[frames.length - TwoColorTimeline.ENTRIES]) { + var 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 { + var 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]; + var frameTime = frames[frame]; + var 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 { + var light = slot.color, 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; + return TwoColorTimeline; + }(CurveTimeline)); + spine.TwoColorTimeline = TwoColorTimeline; + var AttachmentTimeline = (function () { + function AttachmentTimeline(frameCount) { + this.frames = spine.Utils.newFloatArray(frameCount); + this.attachmentNames = new Array(frameCount); + } + AttachmentTimeline.prototype.getPropertyId = function () { + return (TimelineType.attachment << 24) + this.slotIndex; + }; + AttachmentTimeline.prototype.getFrameCount = function () { + return this.frames.length; + }; + AttachmentTimeline.prototype.setFrame = function (frameIndex, time, attachmentName) { + this.frames[frameIndex] = time; + this.attachmentNames[frameIndex] = attachmentName; + }; + AttachmentTimeline.prototype.apply = function (skeleton, lastTime, time, events, alpha, blend, direction) { + var slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + if (direction == MixDirection.mixOut) { + if (blend == MixBlend.setup) + this.setAttachment(skeleton, slot, slot.data.attachmentName); + return; + } + var frames = this.frames; + if (time < frames[0]) { + if (blend == MixBlend.setup || blend == MixBlend.first) + this.setAttachment(skeleton, slot, slot.data.attachmentName); + return; + } + var frameIndex = 0; + if (time >= frames[frames.length - 1]) + frameIndex = frames.length - 1; + else + frameIndex = Animation.binarySearch(frames, time, 1) - 1; + var attachmentName = this.attachmentNames[frameIndex]; + skeleton.slots[this.slotIndex] + .setAttachment(attachmentName == null ? null : skeleton.getAttachment(this.slotIndex, attachmentName)); + }; + AttachmentTimeline.prototype.setAttachment = function (skeleton, slot, attachmentName) { + slot.setAttachment(attachmentName == null ? null : skeleton.getAttachment(this.slotIndex, attachmentName)); + }; + return AttachmentTimeline; + }()); + spine.AttachmentTimeline = AttachmentTimeline; + var zeros = null; + var DeformTimeline = (function (_super) { + __extends(DeformTimeline, _super); + function DeformTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount); + _this.frameVertices = new Array(frameCount); + if (zeros == null) + zeros = spine.Utils.newFloatArray(64); + return _this; + } + DeformTimeline.prototype.getPropertyId = function () { + return (TimelineType.deform << 27) + +this.attachment.id + this.slotIndex; + }; + DeformTimeline.prototype.setFrame = function (frameIndex, time, vertices) { + this.frames[frameIndex] = time; + this.frameVertices[frameIndex] = vertices; + }; + DeformTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + var slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + var slotAttachment = slot.getAttachment(); + if (!(slotAttachment instanceof spine.VertexAttachment) || !(slotAttachment.deformAttachment == this.attachment)) + return; + var deformArray = slot.deform; + if (deformArray.length == 0) + blend = MixBlend.setup; + var frameVertices = this.frameVertices; + var vertexCount = frameVertices[0].length; + var frames = this.frames; + if (time < frames[0]) { + var vertexAttachment = slotAttachment; + switch (blend) { + case MixBlend.setup: + deformArray.length = 0; + return; + case MixBlend.first: + if (alpha == 1) { + deformArray.length = 0; + break; + } + var deform_1 = spine.Utils.setArraySize(deformArray, vertexCount); + if (vertexAttachment.bones == null) { + var setupVertices = vertexAttachment.vertices; + for (var i = 0; i < vertexCount; i++) + deform_1[i] += (setupVertices[i] - deform_1[i]) * alpha; + } + else { + alpha = 1 - alpha; + for (var i = 0; i < vertexCount; i++) + deform_1[i] *= alpha; + } + } + return; + } + var deform = spine.Utils.setArraySize(deformArray, vertexCount); + if (time >= frames[frames.length - 1]) { + var lastVertices = frameVertices[frames.length - 1]; + if (alpha == 1) { + if (blend == MixBlend.add) { + var vertexAttachment = slotAttachment; + if (vertexAttachment.bones == null) { + var setupVertices = vertexAttachment.vertices; + for (var i_1 = 0; i_1 < vertexCount; i_1++) { + deform[i_1] += lastVertices[i_1] - setupVertices[i_1]; + } + } + else { + for (var i_2 = 0; i_2 < vertexCount; i_2++) + deform[i_2] += lastVertices[i_2]; + } + } + else { + spine.Utils.arrayCopy(lastVertices, 0, deform, 0, vertexCount); + } + } + else { + switch (blend) { + case MixBlend.setup: { + var vertexAttachment_1 = slotAttachment; + if (vertexAttachment_1.bones == null) { + var setupVertices = vertexAttachment_1.vertices; + for (var i_3 = 0; i_3 < vertexCount; i_3++) { + var setup = setupVertices[i_3]; + deform[i_3] = setup + (lastVertices[i_3] - setup) * alpha; + } + } + else { + for (var i_4 = 0; i_4 < vertexCount; i_4++) + deform[i_4] = lastVertices[i_4] * alpha; + } + break; + } + case MixBlend.first: + case MixBlend.replace: + for (var i_5 = 0; i_5 < vertexCount; i_5++) + deform[i_5] += (lastVertices[i_5] - deform[i_5]) * alpha; + break; + case MixBlend.add: + var vertexAttachment = slotAttachment; + if (vertexAttachment.bones == null) { + var setupVertices = vertexAttachment.vertices; + for (var i_6 = 0; i_6 < vertexCount; i_6++) { + deform[i_6] += (lastVertices[i_6] - setupVertices[i_6]) * alpha; + } + } + else { + for (var i_7 = 0; i_7 < vertexCount; i_7++) + deform[i_7] += lastVertices[i_7] * alpha; + } + } + } + return; + } + var frame = Animation.binarySearch(frames, time); + var prevVertices = frameVertices[frame - 1]; + var nextVertices = frameVertices[frame]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime)); + if (alpha == 1) { + if (blend == MixBlend.add) { + var vertexAttachment = slotAttachment; + if (vertexAttachment.bones == null) { + var setupVertices = vertexAttachment.vertices; + for (var i_8 = 0; i_8 < vertexCount; i_8++) { + var prev = prevVertices[i_8]; + deform[i_8] += prev + (nextVertices[i_8] - prev) * percent - setupVertices[i_8]; + } + } + else { + for (var i_9 = 0; i_9 < vertexCount; i_9++) { + var prev = prevVertices[i_9]; + deform[i_9] += prev + (nextVertices[i_9] - prev) * percent; + } + } + } + else { + for (var i_10 = 0; i_10 < vertexCount; i_10++) { + var prev = prevVertices[i_10]; + deform[i_10] = prev + (nextVertices[i_10] - prev) * percent; + } + } + } + else { + switch (blend) { + case MixBlend.setup: { + var vertexAttachment_2 = slotAttachment; + if (vertexAttachment_2.bones == null) { + var setupVertices = vertexAttachment_2.vertices; + for (var i_11 = 0; i_11 < vertexCount; i_11++) { + var prev = prevVertices[i_11], setup = setupVertices[i_11]; + deform[i_11] = setup + (prev + (nextVertices[i_11] - prev) * percent - setup) * alpha; + } + } + else { + for (var i_12 = 0; i_12 < vertexCount; i_12++) { + var prev = prevVertices[i_12]; + deform[i_12] = (prev + (nextVertices[i_12] - prev) * percent) * alpha; + } + } + break; + } + case MixBlend.first: + case MixBlend.replace: + for (var i_13 = 0; i_13 < vertexCount; i_13++) { + var prev = prevVertices[i_13]; + deform[i_13] += (prev + (nextVertices[i_13] - prev) * percent - deform[i_13]) * alpha; + } + break; + case MixBlend.add: + var vertexAttachment = slotAttachment; + if (vertexAttachment.bones == null) { + var setupVertices = vertexAttachment.vertices; + for (var i_14 = 0; i_14 < vertexCount; i_14++) { + var prev = prevVertices[i_14]; + deform[i_14] += (prev + (nextVertices[i_14] - prev) * percent - setupVertices[i_14]) * alpha; + } + } + else { + for (var i_15 = 0; i_15 < vertexCount; i_15++) { + var prev = prevVertices[i_15]; + deform[i_15] += (prev + (nextVertices[i_15] - prev) * percent) * alpha; + } + } + } + } + }; + return DeformTimeline; + }(CurveTimeline)); + spine.DeformTimeline = DeformTimeline; + var EventTimeline = (function () { + function EventTimeline(frameCount) { + this.frames = spine.Utils.newFloatArray(frameCount); + this.events = new Array(frameCount); + } + EventTimeline.prototype.getPropertyId = function () { + return TimelineType.event << 24; + }; + EventTimeline.prototype.getFrameCount = function () { + return this.frames.length; + }; + EventTimeline.prototype.setFrame = function (frameIndex, event) { + this.frames[frameIndex] = event.time; + this.events[frameIndex] = event; + }; + EventTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + if (firedEvents == null) + return; + var frames = this.frames; + var frameCount = this.frames.length; + if (lastTime > time) { + this.apply(skeleton, lastTime, Number.MAX_VALUE, firedEvents, alpha, blend, direction); + lastTime = -1; + } + else if (lastTime >= frames[frameCount - 1]) + return; + if (time < frames[0]) + return; + var frame = 0; + if (lastTime < frames[0]) + frame = 0; + else { + frame = Animation.binarySearch(frames, lastTime); + var frameTime = frames[frame]; + while (frame > 0) { + if (frames[frame - 1] != frameTime) + break; + frame--; + } + } + for (; frame < frameCount && time >= frames[frame]; frame++) + firedEvents.push(this.events[frame]); + }; + return EventTimeline; + }()); + spine.EventTimeline = EventTimeline; + var DrawOrderTimeline = (function () { + function DrawOrderTimeline(frameCount) { + this.frames = spine.Utils.newFloatArray(frameCount); + this.drawOrders = new Array(frameCount); + } + DrawOrderTimeline.prototype.getPropertyId = function () { + return TimelineType.drawOrder << 24; + }; + DrawOrderTimeline.prototype.getFrameCount = function () { + return this.frames.length; + }; + DrawOrderTimeline.prototype.setFrame = function (frameIndex, time, drawOrder) { + this.frames[frameIndex] = time; + this.drawOrders[frameIndex] = drawOrder; + }; + DrawOrderTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + var drawOrder = skeleton.drawOrder; + var slots = skeleton.slots; + if (direction == MixDirection.mixOut) { + if (blend == MixBlend.setup) + spine.Utils.arrayCopy(skeleton.slots, 0, skeleton.drawOrder, 0, skeleton.slots.length); + return; + } + var frames = this.frames; + if (time < frames[0]) { + if (blend == MixBlend.setup || blend == MixBlend.first) + spine.Utils.arrayCopy(skeleton.slots, 0, skeleton.drawOrder, 0, skeleton.slots.length); + return; + } + var frame = 0; + if (time >= frames[frames.length - 1]) + frame = frames.length - 1; + else + frame = Animation.binarySearch(frames, time) - 1; + var drawOrderToSetupIndex = this.drawOrders[frame]; + if (drawOrderToSetupIndex == null) + spine.Utils.arrayCopy(slots, 0, drawOrder, 0, slots.length); + else { + for (var i = 0, n = drawOrderToSetupIndex.length; i < n; i++) + drawOrder[i] = slots[drawOrderToSetupIndex[i]]; + } + }; + return DrawOrderTimeline; + }()); + spine.DrawOrderTimeline = DrawOrderTimeline; + var IkConstraintTimeline = (function (_super) { + __extends(IkConstraintTimeline, _super); + function IkConstraintTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * IkConstraintTimeline.ENTRIES); + return _this; + } + IkConstraintTimeline.prototype.getPropertyId = function () { + return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex; + }; + IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, softness, bendDirection, compress, stretch) { + frameIndex *= IkConstraintTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + IkConstraintTimeline.MIX] = mix; + this.frames[frameIndex + IkConstraintTimeline.SOFTNESS] = softness; + this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection; + this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0; + this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0; + }; + IkConstraintTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + var frames = this.frames; + var constraint = skeleton.ikConstraints[this.ikConstraintIndex]; + if (!constraint.active) + return; + if (time < frames[0]) { + switch (blend) { + case MixBlend.setup: + constraint.mix = constraint.data.mix; + constraint.softness = constraint.data.softness; + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + return; + case MixBlend.first: + constraint.mix += (constraint.data.mix - constraint.mix) * alpha; + constraint.softness += (constraint.data.softness - constraint.softness) * alpha; + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } + return; + } + if (time >= frames[frames.length - IkConstraintTimeline.ENTRIES]) { + if (blend == MixBlend.setup) { + constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha; + constraint.softness = constraint.data.softness + + (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.data.softness) * alpha; + if (direction == MixDirection.mixOut) { + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } + else { + constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION]; + constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0; + constraint.stretch = frames[frames.length + IkConstraintTimeline.PREV_STRETCH] != 0; + } + } + else { + constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha; + constraint.softness += (frames[frames.length + IkConstraintTimeline.PREV_SOFTNESS] - constraint.softness) * alpha; + if (direction == MixDirection.mixIn) { + constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION]; + constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0; + constraint.stretch = frames[frames.length + IkConstraintTimeline.PREV_STRETCH] != 0; + } + } + return; + } + var frame = Animation.binarySearch(frames, time, IkConstraintTimeline.ENTRIES); + var mix = frames[frame + IkConstraintTimeline.PREV_MIX]; + var softness = frames[frame + IkConstraintTimeline.PREV_SOFTNESS]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame / IkConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + IkConstraintTimeline.PREV_TIME] - frameTime)); + if (blend == MixBlend.setup) { + constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha; + constraint.softness = constraint.data.softness + + (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.data.softness) * alpha; + if (direction == MixDirection.mixOut) { + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } + else { + constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION]; + constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0; + constraint.stretch = frames[frame + IkConstraintTimeline.PREV_STRETCH] != 0; + } + } + else { + constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha; + constraint.softness += (softness + (frames[frame + IkConstraintTimeline.SOFTNESS] - softness) * percent - constraint.softness) * alpha; + if (direction == MixDirection.mixIn) { + constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION]; + constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0; + constraint.stretch = frames[frame + IkConstraintTimeline.PREV_STRETCH] != 0; + } + } + }; + IkConstraintTimeline.ENTRIES = 6; + IkConstraintTimeline.PREV_TIME = -6; + IkConstraintTimeline.PREV_MIX = -5; + IkConstraintTimeline.PREV_SOFTNESS = -4; + IkConstraintTimeline.PREV_BEND_DIRECTION = -3; + IkConstraintTimeline.PREV_COMPRESS = -2; + IkConstraintTimeline.PREV_STRETCH = -1; + IkConstraintTimeline.MIX = 1; + IkConstraintTimeline.SOFTNESS = 2; + IkConstraintTimeline.BEND_DIRECTION = 3; + IkConstraintTimeline.COMPRESS = 4; + IkConstraintTimeline.STRETCH = 5; + return IkConstraintTimeline; + }(CurveTimeline)); + spine.IkConstraintTimeline = IkConstraintTimeline; + var TransformConstraintTimeline = (function (_super) { + __extends(TransformConstraintTimeline, _super); + function TransformConstraintTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * TransformConstraintTimeline.ENTRIES); + return _this; + } + TransformConstraintTimeline.prototype.getPropertyId = function () { + return (TimelineType.transformConstraint << 24) + this.transformConstraintIndex; + }; + TransformConstraintTimeline.prototype.setFrame = function (frameIndex, time, rotateMix, translateMix, scaleMix, shearMix) { + frameIndex *= TransformConstraintTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + TransformConstraintTimeline.ROTATE] = rotateMix; + this.frames[frameIndex + TransformConstraintTimeline.TRANSLATE] = translateMix; + this.frames[frameIndex + TransformConstraintTimeline.SCALE] = scaleMix; + this.frames[frameIndex + TransformConstraintTimeline.SHEAR] = shearMix; + }; + TransformConstraintTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + var frames = this.frames; + var constraint = skeleton.transformConstraints[this.transformConstraintIndex]; + if (!constraint.active) + return; + if (time < frames[0]) { + var data = constraint.data; + switch (blend) { + case MixBlend.setup: + constraint.rotateMix = data.rotateMix; + constraint.translateMix = data.translateMix; + constraint.scaleMix = data.scaleMix; + constraint.shearMix = data.shearMix; + return; + case MixBlend.first: + constraint.rotateMix += (data.rotateMix - constraint.rotateMix) * alpha; + constraint.translateMix += (data.translateMix - constraint.translateMix) * alpha; + constraint.scaleMix += (data.scaleMix - constraint.scaleMix) * alpha; + constraint.shearMix += (data.shearMix - constraint.shearMix) * alpha; + } + return; + } + var rotate = 0, translate = 0, scale = 0, shear = 0; + if (time >= frames[frames.length - TransformConstraintTimeline.ENTRIES]) { + var i = frames.length; + rotate = frames[i + TransformConstraintTimeline.PREV_ROTATE]; + translate = frames[i + TransformConstraintTimeline.PREV_TRANSLATE]; + scale = frames[i + TransformConstraintTimeline.PREV_SCALE]; + shear = frames[i + TransformConstraintTimeline.PREV_SHEAR]; + } + else { + var frame = Animation.binarySearch(frames, time, TransformConstraintTimeline.ENTRIES); + rotate = frames[frame + TransformConstraintTimeline.PREV_ROTATE]; + translate = frames[frame + TransformConstraintTimeline.PREV_TRANSLATE]; + scale = frames[frame + TransformConstraintTimeline.PREV_SCALE]; + shear = frames[frame + TransformConstraintTimeline.PREV_SHEAR]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame / TransformConstraintTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + TransformConstraintTimeline.PREV_TIME] - frameTime)); + rotate += (frames[frame + TransformConstraintTimeline.ROTATE] - rotate) * percent; + translate += (frames[frame + TransformConstraintTimeline.TRANSLATE] - translate) * percent; + scale += (frames[frame + TransformConstraintTimeline.SCALE] - scale) * percent; + shear += (frames[frame + TransformConstraintTimeline.SHEAR] - shear) * percent; + } + if (blend == MixBlend.setup) { + var data = constraint.data; + constraint.rotateMix = data.rotateMix + (rotate - data.rotateMix) * alpha; + constraint.translateMix = data.translateMix + (translate - data.translateMix) * alpha; + constraint.scaleMix = data.scaleMix + (scale - data.scaleMix) * alpha; + constraint.shearMix = data.shearMix + (shear - data.shearMix) * alpha; + } + else { + constraint.rotateMix += (rotate - constraint.rotateMix) * alpha; + constraint.translateMix += (translate - constraint.translateMix) * alpha; + constraint.scaleMix += (scale - constraint.scaleMix) * alpha; + constraint.shearMix += (shear - constraint.shearMix) * alpha; + } + }; + TransformConstraintTimeline.ENTRIES = 5; + TransformConstraintTimeline.PREV_TIME = -5; + TransformConstraintTimeline.PREV_ROTATE = -4; + TransformConstraintTimeline.PREV_TRANSLATE = -3; + TransformConstraintTimeline.PREV_SCALE = -2; + TransformConstraintTimeline.PREV_SHEAR = -1; + TransformConstraintTimeline.ROTATE = 1; + TransformConstraintTimeline.TRANSLATE = 2; + TransformConstraintTimeline.SCALE = 3; + TransformConstraintTimeline.SHEAR = 4; + return TransformConstraintTimeline; + }(CurveTimeline)); + spine.TransformConstraintTimeline = TransformConstraintTimeline; + var PathConstraintPositionTimeline = (function (_super) { + __extends(PathConstraintPositionTimeline, _super); + function PathConstraintPositionTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * PathConstraintPositionTimeline.ENTRIES); + return _this; + } + PathConstraintPositionTimeline.prototype.getPropertyId = function () { + return (TimelineType.pathConstraintPosition << 24) + this.pathConstraintIndex; + }; + PathConstraintPositionTimeline.prototype.setFrame = function (frameIndex, time, value) { + frameIndex *= PathConstraintPositionTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + PathConstraintPositionTimeline.VALUE] = value; + }; + PathConstraintPositionTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + var frames = this.frames; + var constraint = skeleton.pathConstraints[this.pathConstraintIndex]; + if (!constraint.active) + return; + if (time < frames[0]) { + switch (blend) { + case MixBlend.setup: + constraint.position = constraint.data.position; + return; + case MixBlend.first: + constraint.position += (constraint.data.position - constraint.position) * alpha; + } + return; + } + var position = 0; + if (time >= frames[frames.length - PathConstraintPositionTimeline.ENTRIES]) + position = frames[frames.length + PathConstraintPositionTimeline.PREV_VALUE]; + else { + var frame = Animation.binarySearch(frames, time, PathConstraintPositionTimeline.ENTRIES); + position = frames[frame + PathConstraintPositionTimeline.PREV_VALUE]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame / PathConstraintPositionTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PathConstraintPositionTimeline.PREV_TIME] - frameTime)); + position += (frames[frame + PathConstraintPositionTimeline.VALUE] - position) * percent; + } + if (blend == MixBlend.setup) + constraint.position = constraint.data.position + (position - constraint.data.position) * alpha; + else + constraint.position += (position - constraint.position) * alpha; + }; + PathConstraintPositionTimeline.ENTRIES = 2; + PathConstraintPositionTimeline.PREV_TIME = -2; + PathConstraintPositionTimeline.PREV_VALUE = -1; + PathConstraintPositionTimeline.VALUE = 1; + return PathConstraintPositionTimeline; + }(CurveTimeline)); + spine.PathConstraintPositionTimeline = PathConstraintPositionTimeline; + var PathConstraintSpacingTimeline = (function (_super) { + __extends(PathConstraintSpacingTimeline, _super); + function PathConstraintSpacingTimeline(frameCount) { + return _super.call(this, frameCount) || this; + } + PathConstraintSpacingTimeline.prototype.getPropertyId = function () { + return (TimelineType.pathConstraintSpacing << 24) + this.pathConstraintIndex; + }; + PathConstraintSpacingTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + var frames = this.frames; + var constraint = skeleton.pathConstraints[this.pathConstraintIndex]; + if (!constraint.active) + return; + if (time < frames[0]) { + switch (blend) { + case MixBlend.setup: + constraint.spacing = constraint.data.spacing; + return; + case MixBlend.first: + constraint.spacing += (constraint.data.spacing - constraint.spacing) * alpha; + } + return; + } + var spacing = 0; + if (time >= frames[frames.length - PathConstraintSpacingTimeline.ENTRIES]) + spacing = frames[frames.length + PathConstraintSpacingTimeline.PREV_VALUE]; + else { + var frame = Animation.binarySearch(frames, time, PathConstraintSpacingTimeline.ENTRIES); + spacing = frames[frame + PathConstraintSpacingTimeline.PREV_VALUE]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame / PathConstraintSpacingTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PathConstraintSpacingTimeline.PREV_TIME] - frameTime)); + spacing += (frames[frame + PathConstraintSpacingTimeline.VALUE] - spacing) * percent; + } + if (blend == MixBlend.setup) + constraint.spacing = constraint.data.spacing + (spacing - constraint.data.spacing) * alpha; + else + constraint.spacing += (spacing - constraint.spacing) * alpha; + }; + return PathConstraintSpacingTimeline; + }(PathConstraintPositionTimeline)); + spine.PathConstraintSpacingTimeline = PathConstraintSpacingTimeline; + var PathConstraintMixTimeline = (function (_super) { + __extends(PathConstraintMixTimeline, _super); + function PathConstraintMixTimeline(frameCount) { + var _this = _super.call(this, frameCount) || this; + _this.frames = spine.Utils.newFloatArray(frameCount * PathConstraintMixTimeline.ENTRIES); + return _this; + } + PathConstraintMixTimeline.prototype.getPropertyId = function () { + return (TimelineType.pathConstraintMix << 24) + this.pathConstraintIndex; + }; + PathConstraintMixTimeline.prototype.setFrame = function (frameIndex, time, rotateMix, translateMix) { + frameIndex *= PathConstraintMixTimeline.ENTRIES; + this.frames[frameIndex] = time; + this.frames[frameIndex + PathConstraintMixTimeline.ROTATE] = rotateMix; + this.frames[frameIndex + PathConstraintMixTimeline.TRANSLATE] = translateMix; + }; + PathConstraintMixTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + var frames = this.frames; + var constraint = skeleton.pathConstraints[this.pathConstraintIndex]; + if (!constraint.active) + return; + if (time < frames[0]) { + switch (blend) { + case MixBlend.setup: + constraint.rotateMix = constraint.data.rotateMix; + constraint.translateMix = constraint.data.translateMix; + return; + case MixBlend.first: + constraint.rotateMix += (constraint.data.rotateMix - constraint.rotateMix) * alpha; + constraint.translateMix += (constraint.data.translateMix - constraint.translateMix) * alpha; + } + return; + } + var rotate = 0, translate = 0; + if (time >= frames[frames.length - PathConstraintMixTimeline.ENTRIES]) { + rotate = frames[frames.length + PathConstraintMixTimeline.PREV_ROTATE]; + translate = frames[frames.length + PathConstraintMixTimeline.PREV_TRANSLATE]; + } + else { + var frame = Animation.binarySearch(frames, time, PathConstraintMixTimeline.ENTRIES); + rotate = frames[frame + PathConstraintMixTimeline.PREV_ROTATE]; + translate = frames[frame + PathConstraintMixTimeline.PREV_TRANSLATE]; + var frameTime = frames[frame]; + var percent = this.getCurvePercent(frame / PathConstraintMixTimeline.ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PathConstraintMixTimeline.PREV_TIME] - frameTime)); + rotate += (frames[frame + PathConstraintMixTimeline.ROTATE] - rotate) * percent; + translate += (frames[frame + PathConstraintMixTimeline.TRANSLATE] - translate) * percent; + } + if (blend == MixBlend.setup) { + constraint.rotateMix = constraint.data.rotateMix + (rotate - constraint.data.rotateMix) * alpha; + constraint.translateMix = constraint.data.translateMix + (translate - constraint.data.translateMix) * alpha; + } + else { + constraint.rotateMix += (rotate - constraint.rotateMix) * alpha; + constraint.translateMix += (translate - constraint.translateMix) * alpha; + } + }; + PathConstraintMixTimeline.ENTRIES = 3; + PathConstraintMixTimeline.PREV_TIME = -3; + PathConstraintMixTimeline.PREV_ROTATE = -2; + PathConstraintMixTimeline.PREV_TRANSLATE = -1; + PathConstraintMixTimeline.ROTATE = 1; + PathConstraintMixTimeline.TRANSLATE = 2; + return PathConstraintMixTimeline; + }(CurveTimeline)); + spine.PathConstraintMixTimeline = PathConstraintMixTimeline; +})(spine || (spine = {})); +var spine; +(function (spine) { + var AnimationState = (function () { + function AnimationState(data) { + this.tracks = new Array(); + this.timeScale = 1; + this.unkeyedState = 0; + this.events = new Array(); + this.listeners = new Array(); + this.queue = new EventQueue(this); + this.propertyIDs = new spine.IntSet(); + this.animationsChanged = false; + this.trackEntryPool = new spine.Pool(function () { return new TrackEntry(); }); + this.data = data; + } + AnimationState.prototype.update = function (delta) { + delta *= this.timeScale; + var tracks = this.tracks; + for (var i = 0, n = tracks.length; i < n; i++) { + var current = tracks[i]; + if (current == null) + continue; + current.animationLast = current.nextAnimationLast; + current.trackLast = current.nextTrackLast; + var currentDelta = delta * current.timeScale; + if (current.delay > 0) { + current.delay -= currentDelta; + if (current.delay > 0) + continue; + currentDelta = -current.delay; + current.delay = 0; + } + var next = current.next; + if (next != null) { + 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)) { + 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(); + }; + AnimationState.prototype.updateMixingFrom = function (to, delta) { + var from = to.mixingFrom; + if (from == null) + return true; + var finished = this.updateMixingFrom(from, delta); + from.animationLast = from.nextAnimationLast; + from.trackLast = from.nextTrackLast; + if (to.mixTime > 0 && to.mixTime >= to.mixDuration) { + 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; + }; + AnimationState.prototype.apply = function (skeleton) { + if (skeleton == null) + throw new Error("skeleton cannot be null."); + if (this.animationsChanged) + this._animationsChanged(); + var events = this.events; + var tracks = this.tracks; + var applied = false; + for (var i_16 = 0, n_1 = tracks.length; i_16 < n_1; i_16++) { + var current = tracks[i_16]; + if (current == null || current.delay > 0) + continue; + applied = true; + var blend = i_16 == 0 ? spine.MixBlend.first : current.mixBlend; + 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; + var animationLast = current.animationLast, animationTime = current.getAnimationTime(); + var timelineCount = current.animation.timelines.length; + var timelines = current.animation.timelines; + if ((i_16 == 0 && mix == 1) || blend == spine.MixBlend.add) { + for (var ii = 0; ii < timelineCount; ii++) { + spine.Utils.webkit602BugfixHelper(mix, blend); + var timeline = timelines[ii]; + if (timeline instanceof spine.AttachmentTimeline) + this.applyAttachmentTimeline(timeline, skeleton, animationTime, blend, true); + else + timeline.apply(skeleton, animationLast, animationTime, events, mix, blend, spine.MixDirection.mixIn); + } + } + else { + var timelineMode = current.timelineMode; + var firstFrame = current.timelinesRotation.length == 0; + if (firstFrame) + spine.Utils.setArraySize(current.timelinesRotation, timelineCount << 1, null); + var timelinesRotation = current.timelinesRotation; + for (var ii = 0; ii < timelineCount; ii++) { + var timeline_1 = timelines[ii]; + var timelineBlend = timelineMode[ii] == AnimationState.SUBSEQUENT ? blend : spine.MixBlend.setup; + if (timeline_1 instanceof spine.RotateTimeline) { + this.applyRotateTimeline(timeline_1, skeleton, animationTime, mix, timelineBlend, timelinesRotation, ii << 1, firstFrame); + } + else if (timeline_1 instanceof spine.AttachmentTimeline) { + this.applyAttachmentTimeline(timeline_1, skeleton, animationTime, blend, true); + } + else { + spine.Utils.webkit602BugfixHelper(mix, blend); + timeline_1.apply(skeleton, animationLast, animationTime, events, mix, timelineBlend, spine.MixDirection.mixIn); + } + } + } + this.queueEvents(current, animationTime); + events.length = 0; + current.nextAnimationLast = animationTime; + current.nextTrackLast = current.trackTime; + } + var setupState = this.unkeyedState + AnimationState.SETUP; + var slots = skeleton.slots; + for (var i = 0, n = skeleton.slots.length; i < n; i++) { + var slot = slots[i]; + if (slot.attachmentState == setupState) { + var attachmentName = slot.data.attachmentName; + slot.setAttachment(attachmentName == null ? null : skeleton.getAttachment(slot.data.index, attachmentName)); + } + } + this.unkeyedState += 2; + this.queue.drain(); + return applied; + }; + AnimationState.prototype.applyMixingFrom = function (to, skeleton, blend) { + var from = to.mixingFrom; + if (from.mixingFrom != null) + this.applyMixingFrom(from, skeleton, blend); + var mix = 0; + if (to.mixDuration == 0) { + mix = 1; + if (blend == spine.MixBlend.first) + blend = spine.MixBlend.setup; + } + else { + mix = to.mixTime / to.mixDuration; + if (mix > 1) + mix = 1; + if (blend != spine.MixBlend.first) + blend = from.mixBlend; + } + var events = mix < from.eventThreshold ? this.events : null; + var attachments = mix < from.attachmentThreshold, drawOrder = mix < from.drawOrderThreshold; + var animationLast = from.animationLast, animationTime = from.getAnimationTime(); + var timelineCount = from.animation.timelines.length; + var timelines = from.animation.timelines; + var alphaHold = from.alpha * to.interruptAlpha, alphaMix = alphaHold * (1 - mix); + if (blend == spine.MixBlend.add) { + for (var i = 0; i < timelineCount; i++) + timelines[i].apply(skeleton, animationLast, animationTime, events, alphaMix, blend, spine.MixDirection.mixOut); + } + else { + var timelineMode = from.timelineMode; + var timelineHoldMix = from.timelineHoldMix; + var firstFrame = from.timelinesRotation.length == 0; + if (firstFrame) + spine.Utils.setArraySize(from.timelinesRotation, timelineCount << 1, null); + var timelinesRotation = from.timelinesRotation; + from.totalAlpha = 0; + for (var i = 0; i < timelineCount; i++) { + var timeline = timelines[i]; + var direction = spine.MixDirection.mixOut; + var timelineBlend = void 0; + var alpha = 0; + switch (timelineMode[i]) { + case AnimationState.SUBSEQUENT: + if (!drawOrder && timeline instanceof spine.DrawOrderTimeline) + continue; + timelineBlend = blend; + alpha = alphaMix; + break; + case AnimationState.FIRST: + timelineBlend = spine.MixBlend.setup; + alpha = alphaMix; + break; + case AnimationState.HOLD_SUBSEQUENT: + timelineBlend = blend; + alpha = alphaHold; + break; + case AnimationState.HOLD_FIRST: + timelineBlend = spine.MixBlend.setup; + alpha = alphaHold; + break; + default: + timelineBlend = spine.MixBlend.setup; + var holdMix = timelineHoldMix[i]; + alpha = alphaHold * Math.max(0, 1 - holdMix.mixTime / holdMix.mixDuration); + break; + } + from.totalAlpha += alpha; + if (timeline instanceof spine.RotateTimeline) + this.applyRotateTimeline(timeline, skeleton, animationTime, alpha, timelineBlend, timelinesRotation, i << 1, firstFrame); + else if (timeline instanceof spine.AttachmentTimeline) + this.applyAttachmentTimeline(timeline, skeleton, animationTime, timelineBlend, attachments); + else { + spine.Utils.webkit602BugfixHelper(alpha, blend); + if (drawOrder && timeline instanceof spine.DrawOrderTimeline && timelineBlend == spine.MixBlend.setup) + direction = spine.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; + }; + AnimationState.prototype.applyAttachmentTimeline = function (timeline, skeleton, time, blend, attachments) { + var slot = skeleton.slots[timeline.slotIndex]; + if (!slot.bone.active) + return; + var frames = timeline.frames; + if (time < frames[0]) { + if (blend == spine.MixBlend.setup || blend == spine.MixBlend.first) + this.setAttachment(skeleton, slot, slot.data.attachmentName, attachments); + } + else { + var frameIndex; + if (time >= frames[frames.length - 1]) + frameIndex = frames.length - 1; + else + frameIndex = spine.Animation.binarySearch(frames, time) - 1; + this.setAttachment(skeleton, slot, timeline.attachmentNames[frameIndex], attachments); + } + if (slot.attachmentState <= this.unkeyedState) + slot.attachmentState = this.unkeyedState + AnimationState.SETUP; + }; + AnimationState.prototype.setAttachment = function (skeleton, slot, attachmentName, attachments) { + slot.setAttachment(attachmentName == null ? null : skeleton.getAttachment(slot.data.index, attachmentName)); + if (attachments) + slot.attachmentState = this.unkeyedState + AnimationState.CURRENT; + }; + AnimationState.prototype.applyRotateTimeline = 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, spine.MixDirection.mixIn); + return; + } + var rotateTimeline = timeline; + var frames = rotateTimeline.frames; + var bone = skeleton.bones[rotateTimeline.boneIndex]; + if (!bone.active) + return; + var r1 = 0, r2 = 0; + if (time < frames[0]) { + switch (blend) { + case spine.MixBlend.setup: + bone.rotation = bone.data.rotation; + default: + return; + case spine.MixBlend.first: + r1 = bone.rotation; + r2 = bone.data.rotation; + } + } + else { + r1 = blend == spine.MixBlend.setup ? bone.data.rotation : bone.rotation; + if (time >= frames[frames.length - spine.RotateTimeline.ENTRIES]) + r2 = bone.data.rotation + frames[frames.length + spine.RotateTimeline.PREV_ROTATION]; + else { + var frame = spine.Animation.binarySearch(frames, time, spine.RotateTimeline.ENTRIES); + var prevRotation = frames[frame + spine.RotateTimeline.PREV_ROTATION]; + var frameTime = frames[frame]; + var percent = rotateTimeline.getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + spine.RotateTimeline.PREV_TIME] - frameTime)); + r2 = frames[frame + spine.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; + } + } + var total = 0, diff = r2 - r1; + diff -= (16384 - ((16384.499999999996 - diff / 360) | 0)) * 360; + if (diff == 0) { + total = timelinesRotation[i]; + } + else { + var lastTotal = 0, lastDiff = 0; + if (firstFrame) { + lastTotal = 0; + lastDiff = diff; + } + else { + lastTotal = timelinesRotation[i]; + lastDiff = timelinesRotation[i + 1]; + } + var current = diff > 0, dir = lastTotal >= 0; + if (spine.MathUtils.signum(lastDiff) != spine.MathUtils.signum(diff) && Math.abs(lastDiff) <= 90) { + if (Math.abs(lastTotal) > 180) + lastTotal += 360 * spine.MathUtils.signum(lastTotal); + dir = current; + } + total = diff + lastTotal - lastTotal % 360; + if (dir != current) + total += 360 * spine.MathUtils.signum(lastTotal); + timelinesRotation[i] = total; + } + timelinesRotation[i + 1] = diff; + r1 += total * alpha; + bone.rotation = r1 - (16384 - ((16384.499999999996 - r1 / 360) | 0)) * 360; + }; + AnimationState.prototype.queueEvents = function (entry, animationTime) { + var animationStart = entry.animationStart, animationEnd = entry.animationEnd; + var duration = animationEnd - animationStart; + var trackLastWrapped = entry.trackLast % duration; + var events = this.events; + var i = 0, n = events.length; + for (; i < n; i++) { + var event_1 = events[i]; + if (event_1.time < trackLastWrapped) + break; + if (event_1.time > animationEnd) + continue; + this.queue.event(entry, event_1); + } + 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); + for (; i < n; i++) { + var event_2 = events[i]; + if (event_2.time < animationStart) + continue; + this.queue.event(entry, events[i]); + } + }; + AnimationState.prototype.clearTracks = function () { + 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(); + }; + AnimationState.prototype.clearTrack = function (trackIndex) { + if (trackIndex >= this.tracks.length) + return; + var current = this.tracks[trackIndex]; + if (current == null) + return; + this.queue.end(current); + this.disposeNext(current); + var entry = current; + while (true) { + 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(); + }; + AnimationState.prototype.setCurrent = function (index, current, interrupt) { + 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; + if (from.mixingFrom != null && from.mixDuration > 0) + current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration); + from.timelinesRotation.length = 0; + } + this.queue.start(current); + }; + AnimationState.prototype.setAnimation = function (trackIndex, animationName, loop) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (animation == null) + throw new Error("Animation not found: " + animationName); + return this.setAnimationWith(trackIndex, animation, loop); + }; + AnimationState.prototype.setAnimationWith = function (trackIndex, animation, loop) { + if (animation == null) + throw new Error("animation cannot be null."); + var interrupt = true; + var current = this.expandToIndex(trackIndex); + if (current != null) { + if (current.nextTrackLast == -1) { + 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); + } + var entry = this.trackEntry(trackIndex, animation, loop, current); + this.setCurrent(trackIndex, entry, interrupt); + this.queue.drain(); + return entry; + }; + AnimationState.prototype.addAnimation = function (trackIndex, animationName, loop, delay) { + var animation = this.data.skeletonData.findAnimation(animationName); + if (animation == null) + throw new Error("Animation not found: " + animationName); + return this.addAnimationWith(trackIndex, animation, loop, delay); + }; + AnimationState.prototype.addAnimationWith = function (trackIndex, animation, loop, delay) { + if (animation == null) + throw new Error("animation cannot be null."); + var last = this.expandToIndex(trackIndex); + if (last != null) { + while (last.next != null) + last = last.next; + } + 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) { + 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; + }; + AnimationState.prototype.setEmptyAnimation = function (trackIndex, mixDuration) { + var entry = this.setAnimationWith(trackIndex, AnimationState.emptyAnimation, false); + entry.mixDuration = mixDuration; + entry.trackEnd = mixDuration; + return entry; + }; + AnimationState.prototype.addEmptyAnimation = function (trackIndex, mixDuration, delay) { + if (delay <= 0) + delay -= mixDuration; + var entry = this.addAnimationWith(trackIndex, AnimationState.emptyAnimation, false, delay); + entry.mixDuration = mixDuration; + entry.trackEnd = mixDuration; + return entry; + }; + AnimationState.prototype.setEmptyAnimations = function (mixDuration) { + var oldDrainDisabled = this.queue.drainDisabled; + this.queue.drainDisabled = true; + for (var i = 0, n = this.tracks.length; i < n; i++) { + var current = this.tracks[i]; + if (current != null) + this.setEmptyAnimation(current.trackIndex, mixDuration); + } + this.queue.drainDisabled = oldDrainDisabled; + this.queue.drain(); + }; + AnimationState.prototype.expandToIndex = function (index) { + if (index < this.tracks.length) + return this.tracks[index]; + spine.Utils.ensureArrayCapacity(this.tracks, index + 1, null); + this.tracks.length = index + 1; + return null; + }; + AnimationState.prototype.trackEntry = function (trackIndex, animation, loop, last) { + 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); + entry.mixBlend = spine.MixBlend.replace; + return entry; + }; + AnimationState.prototype.disposeNext = function (entry) { + var next = entry.next; + while (next != null) { + this.queue.dispose(next); + next = next.next; + } + entry.next = null; + }; + AnimationState.prototype._animationsChanged = function () { + this.animationsChanged = false; + this.propertyIDs.clear(); + for (var i = 0, n = this.tracks.length; i < n; i++) { + var entry = this.tracks[i]; + if (entry == null) + continue; + while (entry.mixingFrom != null) + entry = entry.mixingFrom; + do { + if (entry.mixingFrom == null || entry.mixBlend != spine.MixBlend.add) + this.computeHold(entry); + entry = entry.mixingTo; + } while (entry != null); + } + }; + AnimationState.prototype.computeHold = function (entry) { + var to = entry.mixingTo; + var timelines = entry.animation.timelines; + var timelinesCount = entry.animation.timelines.length; + var timelineMode = spine.Utils.setArraySize(entry.timelineMode, timelinesCount); + entry.timelineHoldMix.length = 0; + var timelineDipMix = spine.Utils.setArraySize(entry.timelineHoldMix, timelinesCount); + var propertyIDs = this.propertyIDs; + if (to != null && to.holdPrevious) { + for (var i = 0; i < timelinesCount; i++) { + timelineMode[i] = propertyIDs.add(timelines[i].getPropertyId()) ? AnimationState.HOLD_FIRST : AnimationState.HOLD_SUBSEQUENT; + } + return; + } + outer: for (var i = 0; i < timelinesCount; i++) { + var timeline = timelines[i]; + var id = timeline.getPropertyId(); + if (!propertyIDs.add(id)) + timelineMode[i] = AnimationState.SUBSEQUENT; + else if (to == null || timeline instanceof spine.AttachmentTimeline || timeline instanceof spine.DrawOrderTimeline + || timeline instanceof spine.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_FIRST; + } + } + }; + AnimationState.prototype.getCurrent = function (trackIndex) { + if (trackIndex >= this.tracks.length) + return null; + return this.tracks[trackIndex]; + }; + AnimationState.prototype.addListener = function (listener) { + if (listener == null) + throw new Error("listener cannot be null."); + this.listeners.push(listener); + }; + AnimationState.prototype.removeListener = function (listener) { + var index = this.listeners.indexOf(listener); + if (index >= 0) + this.listeners.splice(index, 1); + }; + AnimationState.prototype.clearListeners = function () { + this.listeners.length = 0; + }; + AnimationState.prototype.clearListenerNotifications = function () { + this.queue.clear(); + }; + AnimationState.emptyAnimation = new spine.Animation("", [], 0); + AnimationState.SUBSEQUENT = 0; + AnimationState.FIRST = 1; + AnimationState.HOLD_SUBSEQUENT = 2; + AnimationState.HOLD_FIRST = 3; + AnimationState.HOLD_MIX = 4; + AnimationState.SETUP = 1; + AnimationState.CURRENT = 2; + return AnimationState; + }()); + spine.AnimationState = AnimationState; + var TrackEntry = (function () { + function TrackEntry() { + this.mixBlend = spine.MixBlend.replace; + this.timelineMode = new Array(); + this.timelineHoldMix = new Array(); + this.timelinesRotation = new Array(); + } + TrackEntry.prototype.reset = 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; + }; + TrackEntry.prototype.getAnimationTime = function () { + if (this.loop) { + 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); + }; + TrackEntry.prototype.setAnimationLast = function (animationLast) { + this.animationLast = animationLast; + this.nextAnimationLast = animationLast; + }; + TrackEntry.prototype.isComplete = function () { + return this.trackTime >= this.animationEnd - this.animationStart; + }; + TrackEntry.prototype.resetRotationDirections = function () { + this.timelinesRotation.length = 0; + }; + return TrackEntry; + }()); + spine.TrackEntry = TrackEntry; + var EventQueue = (function () { + function EventQueue(animState) { + this.objects = []; + this.drainDisabled = false; + this.animState = animState; + } + EventQueue.prototype.start = function (entry) { + this.objects.push(EventType.start); + this.objects.push(entry); + this.animState.animationsChanged = true; + }; + EventQueue.prototype.interrupt = function (entry) { + this.objects.push(EventType.interrupt); + this.objects.push(entry); + }; + EventQueue.prototype.end = function (entry) { + this.objects.push(EventType.end); + this.objects.push(entry); + this.animState.animationsChanged = true; + }; + EventQueue.prototype.dispose = function (entry) { + this.objects.push(EventType.dispose); + this.objects.push(entry); + }; + EventQueue.prototype.complete = function (entry) { + this.objects.push(EventType.complete); + this.objects.push(entry); + }; + EventQueue.prototype.event = function (entry, event) { + this.objects.push(EventType.event); + this.objects.push(entry); + this.objects.push(event); + }; + EventQueue.prototype.drain = function () { + if (this.drainDisabled) + return; + this.drainDisabled = true; + var objects = this.objects; + var listeners = this.animState.listeners; + for (var i = 0; i < objects.length; i += 2) { + var type = objects[i]; + var entry = 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); + 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: + var event_3 = 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; + }; + EventQueue.prototype.clear = function () { + this.objects.length = 0; + }; + return EventQueue; + }()); + spine.EventQueue = EventQueue; + var EventType; + (function (EventType) { + EventType[EventType["start"] = 0] = "start"; + EventType[EventType["interrupt"] = 1] = "interrupt"; + EventType[EventType["end"] = 2] = "end"; + EventType[EventType["dispose"] = 3] = "dispose"; + EventType[EventType["complete"] = 4] = "complete"; + EventType[EventType["event"] = 5] = "event"; + })(EventType = spine.EventType || (spine.EventType = {})); + var AnimationStateAdapter = (function () { + function AnimationStateAdapter() { + } + AnimationStateAdapter.prototype.start = function (entry) { + }; + AnimationStateAdapter.prototype.interrupt = function (entry) { + }; + AnimationStateAdapter.prototype.end = function (entry) { + }; + AnimationStateAdapter.prototype.dispose = function (entry) { + }; + AnimationStateAdapter.prototype.complete = function (entry) { + }; + AnimationStateAdapter.prototype.event = function (entry, event) { + }; + return AnimationStateAdapter; + }()); + spine.AnimationStateAdapter = AnimationStateAdapter; +})(spine || (spine = {})); +var spine; +(function (spine) { + var AnimationStateData = (function () { + function AnimationStateData(skeletonData) { + this.animationToMixTime = {}; + this.defaultMix = 0; + if (skeletonData == null) + throw new Error("skeletonData cannot be null."); + this.skeletonData = skeletonData; + } + AnimationStateData.prototype.setMix = function (fromName, toName, duration) { + var from = this.skeletonData.findAnimation(fromName); + if (from == null) + throw new Error("Animation not found: " + fromName); + var to = this.skeletonData.findAnimation(toName); + if (to == null) + throw new Error("Animation not found: " + toName); + this.setMixWith(from, to, duration); + }; + AnimationStateData.prototype.setMixWith = function (from, to, duration) { + if (from == null) + throw new Error("from cannot be null."); + if (to == null) + throw new Error("to cannot be null."); + var key = from.name + "." + to.name; + this.animationToMixTime[key] = duration; + }; + AnimationStateData.prototype.getMix = function (from, to) { + var key = from.name + "." + to.name; + var value = this.animationToMixTime[key]; + return value === undefined ? this.defaultMix : value; + }; + return AnimationStateData; + }()); + spine.AnimationStateData = AnimationStateData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var AssetManager = (function () { + function AssetManager(textureLoader, pathPrefix) { + if (pathPrefix === void 0) { pathPrefix = ""; } + this.assets = {}; + this.errors = {}; + this.toLoad = 0; + this.loaded = 0; + this.rawDataUris = {}; + this.textureLoader = textureLoader; + this.pathPrefix = pathPrefix; + } + AssetManager.prototype.downloadText = function (url, success, error) { + var request = new XMLHttpRequest(); + request.overrideMimeType("text/html"); + if (this.rawDataUris[url]) + url = this.rawDataUris[url]; + request.open("GET", url, true); + request.onload = function () { + if (request.status == 200) { + success(request.responseText); + } + else { + error(request.status, request.responseText); + } + }; + request.onerror = function () { + error(request.status, request.responseText); + }; + request.send(); + }; + AssetManager.prototype.downloadBinary = function (url, success, error) { + var request = new XMLHttpRequest(); + if (this.rawDataUris[url]) + url = this.rawDataUris[url]; + request.open("GET", url, true); + request.responseType = "arraybuffer"; + request.onload = function () { + if (request.status == 200) { + success(new Uint8Array(request.response)); + } + else { + error(request.status, request.responseText); + } + }; + request.onerror = function () { + error(request.status, request.responseText); + }; + request.send(); + }; + AssetManager.prototype.setRawDataURI = function (path, data) { + this.rawDataUris[this.pathPrefix + path] = data; + }; + AssetManager.prototype.loadBinary = function (path, success, error) { + var _this = this; + if (success === void 0) { success = null; } + if (error === void 0) { error = null; } + path = this.pathPrefix + path; + this.toLoad++; + this.downloadBinary(path, function (data) { + _this.assets[path] = data; + if (success) + success(path, data); + _this.toLoad--; + _this.loaded++; + }, function (state, responseText) { + _this.errors[path] = "Couldn't load binary " + path + ": status " + status + ", " + responseText; + if (error) + error(path, "Couldn't load binary " + path + ": status " + status + ", " + responseText); + _this.toLoad--; + _this.loaded++; + }); + }; + AssetManager.prototype.loadText = function (path, success, error) { + var _this = this; + if (success === void 0) { success = null; } + if (error === void 0) { error = null; } + path = this.pathPrefix + path; + this.toLoad++; + this.downloadText(path, function (data) { + _this.assets[path] = data; + if (success) + success(path, data); + _this.toLoad--; + _this.loaded++; + }, function (state, responseText) { + _this.errors[path] = "Couldn't load text " + path + ": status " + status + ", " + responseText; + if (error) + error(path, "Couldn't load text " + path + ": status " + status + ", " + responseText); + _this.toLoad--; + _this.loaded++; + }); + }; + AssetManager.prototype.loadTexture = function (path, success, error) { + var _this = this; + if (success === void 0) { success = null; } + if (error === void 0) { error = null; } + path = this.pathPrefix + path; + var storagePath = path; + this.toLoad++; + var img = new Image(); + img.crossOrigin = "anonymous"; + img.onload = function (ev) { + var texture = _this.textureLoader(img); + _this.assets[storagePath] = texture; + _this.toLoad--; + _this.loaded++; + if (success) + success(path, img); + }; + img.onerror = function (ev) { + _this.errors[path] = "Couldn't load image " + path; + _this.toLoad--; + _this.loaded++; + if (error) + error(path, "Couldn't load image " + path); + }; + if (this.rawDataUris[path]) + path = this.rawDataUris[path]; + img.src = path; + }; + AssetManager.prototype.loadTextureAtlas = function (path, success, error) { + var _this = this; + if (success === void 0) { success = null; } + if (error === void 0) { error = null; } + var parent = path.lastIndexOf("/") >= 0 ? path.substring(0, path.lastIndexOf("/")) : ""; + path = this.pathPrefix + path; + this.toLoad++; + this.downloadText(path, function (atlasData) { + var pagesLoaded = { count: 0 }; + var atlasPages = new Array(); + try { + var atlas = new spine.TextureAtlas(atlasData, function (path) { + atlasPages.push(parent == "" ? path : parent + "/" + path); + var image = document.createElement("img"); + image.width = 16; + image.height = 16; + return new spine.FakeTexture(image); + }); + } + catch (e) { + var ex = e; + _this.errors[path] = "Couldn't load texture atlas " + path + ": " + ex.message; + if (error) + error(path, "Couldn't load texture atlas " + path + ": " + ex.message); + _this.toLoad--; + _this.loaded++; + return; + } + var _loop_1 = function (atlasPage) { + var pageLoadError = false; + _this.loadTexture(atlasPage, function (imagePath, image) { + pagesLoaded.count++; + if (pagesLoaded.count == atlasPages.length) { + if (!pageLoadError) { + try { + var atlas = new spine.TextureAtlas(atlasData, function (path) { + return _this.get(parent == "" ? path : parent + "/" + path); + }); + _this.assets[path] = atlas; + if (success) + success(path, atlas); + _this.toLoad--; + _this.loaded++; + } + catch (e) { + var ex = e; + _this.errors[path] = "Couldn't load texture atlas " + path + ": " + ex.message; + if (error) + error(path, "Couldn't load texture atlas " + path + ": " + ex.message); + _this.toLoad--; + _this.loaded++; + } + } + else { + _this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path; + if (error) + error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path); + _this.toLoad--; + _this.loaded++; + } + } + }, function (imagePath, errorMessage) { + pageLoadError = true; + pagesLoaded.count++; + if (pagesLoaded.count == atlasPages.length) { + _this.errors[path] = "Couldn't load texture atlas page " + imagePath + "} of atlas " + path; + if (error) + error(path, "Couldn't load texture atlas page " + imagePath + " of atlas " + path); + _this.toLoad--; + _this.loaded++; + } + }); + }; + for (var _i = 0, atlasPages_1 = atlasPages; _i < atlasPages_1.length; _i++) { + var atlasPage = atlasPages_1[_i]; + _loop_1(atlasPage); + } + }, function (state, responseText) { + _this.errors[path] = "Couldn't load texture atlas " + path + ": status " + status + ", " + responseText; + if (error) + error(path, "Couldn't load texture atlas " + path + ": status " + status + ", " + responseText); + _this.toLoad--; + _this.loaded++; + }); + }; + AssetManager.prototype.get = function (path) { + path = this.pathPrefix + path; + return this.assets[path]; + }; + AssetManager.prototype.remove = function (path) { + path = this.pathPrefix + path; + var asset = this.assets[path]; + if (asset.dispose) + asset.dispose(); + this.assets[path] = null; + }; + AssetManager.prototype.removeAll = function () { + for (var key in this.assets) { + var asset = this.assets[key]; + if (asset.dispose) + asset.dispose(); + } + this.assets = {}; + }; + AssetManager.prototype.isLoadingComplete = function () { + return this.toLoad == 0; + }; + AssetManager.prototype.getToLoad = function () { + return this.toLoad; + }; + AssetManager.prototype.getLoaded = function () { + return this.loaded; + }; + AssetManager.prototype.dispose = function () { + this.removeAll(); + }; + AssetManager.prototype.hasErrors = function () { + return Object.keys(this.errors).length > 0; + }; + AssetManager.prototype.getErrors = function () { + return this.errors; + }; + return AssetManager; + }()); + spine.AssetManager = AssetManager; +})(spine || (spine = {})); +var spine; +(function (spine) { + var AtlasAttachmentLoader = (function () { + function AtlasAttachmentLoader(atlas) { + this.atlas = atlas; + } + AtlasAttachmentLoader.prototype.newRegionAttachment = function (skin, name, path) { + var region = this.atlas.findRegion(path); + if (region == null) + throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")"); + region.renderObject = region; + var attachment = new spine.RegionAttachment(name); + attachment.setRegion(region); + return attachment; + }; + AtlasAttachmentLoader.prototype.newMeshAttachment = function (skin, name, path) { + var region = this.atlas.findRegion(path); + if (region == null) + throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); + region.renderObject = region; + var attachment = new spine.MeshAttachment(name); + attachment.region = region; + return attachment; + }; + AtlasAttachmentLoader.prototype.newBoundingBoxAttachment = function (skin, name) { + return new spine.BoundingBoxAttachment(name); + }; + AtlasAttachmentLoader.prototype.newPathAttachment = function (skin, name) { + return new spine.PathAttachment(name); + }; + AtlasAttachmentLoader.prototype.newPointAttachment = function (skin, name) { + return new spine.PointAttachment(name); + }; + AtlasAttachmentLoader.prototype.newClippingAttachment = function (skin, name) { + return new spine.ClippingAttachment(name); + }; + return AtlasAttachmentLoader; + }()); + spine.AtlasAttachmentLoader = AtlasAttachmentLoader; +})(spine || (spine = {})); +var spine; +(function (spine) { + var BlendMode; + (function (BlendMode) { + BlendMode[BlendMode["Normal"] = 0] = "Normal"; + BlendMode[BlendMode["Additive"] = 1] = "Additive"; + BlendMode[BlendMode["Multiply"] = 2] = "Multiply"; + BlendMode[BlendMode["Screen"] = 3] = "Screen"; + })(BlendMode = spine.BlendMode || (spine.BlendMode = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var Bone = (function () { + function Bone(data, skeleton, parent) { + this.children = new Array(); + this.x = 0; + this.y = 0; + this.rotation = 0; + this.scaleX = 0; + this.scaleY = 0; + this.shearX = 0; + this.shearY = 0; + this.ax = 0; + this.ay = 0; + this.arotation = 0; + this.ascaleX = 0; + this.ascaleY = 0; + this.ashearX = 0; + this.ashearY = 0; + this.appliedValid = false; + this.a = 0; + this.b = 0; + this.c = 0; + this.d = 0; + this.worldY = 0; + this.worldX = 0; + this.sorted = false; + this.active = false; + if (data == null) + throw new Error("data cannot be null."); + if (skeleton == null) + throw new Error("skeleton cannot be null."); + this.data = data; + this.skeleton = skeleton; + this.parent = parent; + this.setToSetupPose(); + } + Bone.prototype.isActive = function () { + return this.active; + }; + Bone.prototype.update = function () { + this.updateWorldTransformWith(this.x, this.y, this.rotation, this.scaleX, this.scaleY, this.shearX, this.shearY); + }; + Bone.prototype.updateWorldTransform = function () { + this.updateWorldTransformWith(this.x, this.y, this.rotation, this.scaleX, this.scaleY, this.shearX, this.shearY); + }; + Bone.prototype.updateWorldTransformWith = function (x, y, rotation, scaleX, scaleY, shearX, shearY) { + this.ax = x; + this.ay = y; + this.arotation = rotation; + this.ascaleX = scaleX; + this.ascaleY = scaleY; + this.ashearX = shearX; + this.ashearY = shearY; + this.appliedValid = true; + var parent = this.parent; + if (parent == null) { + var skeleton = this.skeleton; + var rotationY = rotation + 90 + shearY; + var sx = skeleton.scaleX; + var sy = skeleton.scaleY; + this.a = spine.MathUtils.cosDeg(rotation + shearX) * scaleX * sx; + this.b = spine.MathUtils.cosDeg(rotationY) * scaleY * sx; + this.c = spine.MathUtils.sinDeg(rotation + shearX) * scaleX * sy; + this.d = spine.MathUtils.sinDeg(rotationY) * scaleY * sy; + this.worldX = x * sx + skeleton.x; + this.worldY = y * sy + skeleton.y; + return; + } + var pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + this.worldX = pa * x + pb * y + parent.worldX; + this.worldY = pc * x + pd * y + parent.worldY; + switch (this.data.transformMode) { + case spine.TransformMode.Normal: { + var rotationY = rotation + 90 + shearY; + var la = spine.MathUtils.cosDeg(rotation + shearX) * scaleX; + var lb = spine.MathUtils.cosDeg(rotationY) * scaleY; + var lc = spine.MathUtils.sinDeg(rotation + shearX) * scaleX; + var ld = spine.MathUtils.sinDeg(rotationY) * scaleY; + this.a = pa * la + pb * lc; + this.b = pa * lb + pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + return; + } + case spine.TransformMode.OnlyTranslation: { + var rotationY = rotation + 90 + shearY; + this.a = spine.MathUtils.cosDeg(rotation + shearX) * scaleX; + this.b = spine.MathUtils.cosDeg(rotationY) * scaleY; + this.c = spine.MathUtils.sinDeg(rotation + shearX) * scaleX; + this.d = spine.MathUtils.sinDeg(rotationY) * scaleY; + break; + } + case spine.TransformMode.NoRotationOrReflection: { + var s = pa * pa + pc * pc; + var prx = 0; + if (s > 0.0001) { + s = Math.abs(pa * pd - pb * pc) / s; + pa /= this.skeleton.scaleX; + pc /= this.skeleton.scaleY; + pb = pc * s; + pd = pa * s; + prx = Math.atan2(pc, pa) * spine.MathUtils.radDeg; + } + else { + pa = 0; + pc = 0; + prx = 90 - Math.atan2(pd, pb) * spine.MathUtils.radDeg; + } + var rx = rotation + shearX - prx; + var ry = rotation + shearY - prx + 90; + var la = spine.MathUtils.cosDeg(rx) * scaleX; + var lb = spine.MathUtils.cosDeg(ry) * scaleY; + var lc = spine.MathUtils.sinDeg(rx) * scaleX; + var ld = spine.MathUtils.sinDeg(ry) * scaleY; + this.a = pa * la - pb * lc; + this.b = pa * lb - pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + break; + } + case spine.TransformMode.NoScale: + case spine.TransformMode.NoScaleOrReflection: { + var cos = spine.MathUtils.cosDeg(rotation); + var sin = spine.MathUtils.sinDeg(rotation); + var za = (pa * cos + pb * sin) / this.skeleton.scaleX; + var zc = (pc * cos + pd * sin) / this.skeleton.scaleY; + var s = Math.sqrt(za * za + zc * zc); + if (s > 0.00001) + s = 1 / s; + za *= s; + zc *= s; + s = Math.sqrt(za * za + zc * zc); + if (this.data.transformMode == spine.TransformMode.NoScale + && (pa * pd - pb * pc < 0) != (this.skeleton.scaleX < 0 != this.skeleton.scaleY < 0)) + s = -s; + var r = Math.PI / 2 + Math.atan2(zc, za); + var zb = Math.cos(r) * s; + var zd = Math.sin(r) * s; + var la = spine.MathUtils.cosDeg(shearX) * scaleX; + var lb = spine.MathUtils.cosDeg(90 + shearY) * scaleY; + var lc = spine.MathUtils.sinDeg(shearX) * scaleX; + var ld = spine.MathUtils.sinDeg(90 + shearY) * scaleY; + this.a = za * la + zb * lc; + this.b = za * lb + zb * ld; + this.c = zc * la + zd * lc; + this.d = zc * lb + zd * ld; + break; + } + } + this.a *= this.skeleton.scaleX; + this.b *= this.skeleton.scaleX; + this.c *= this.skeleton.scaleY; + this.d *= this.skeleton.scaleY; + }; + Bone.prototype.setToSetupPose = function () { + var data = this.data; + this.x = data.x; + this.y = data.y; + this.rotation = data.rotation; + this.scaleX = data.scaleX; + this.scaleY = data.scaleY; + this.shearX = data.shearX; + this.shearY = data.shearY; + }; + Bone.prototype.getWorldRotationX = function () { + return Math.atan2(this.c, this.a) * spine.MathUtils.radDeg; + }; + Bone.prototype.getWorldRotationY = function () { + return Math.atan2(this.d, this.b) * spine.MathUtils.radDeg; + }; + Bone.prototype.getWorldScaleX = function () { + return Math.sqrt(this.a * this.a + this.c * this.c); + }; + Bone.prototype.getWorldScaleY = function () { + return Math.sqrt(this.b * this.b + this.d * this.d); + }; + Bone.prototype.updateAppliedTransform = function () { + this.appliedValid = true; + var parent = this.parent; + if (parent == null) { + this.ax = this.worldX; + this.ay = this.worldY; + this.arotation = Math.atan2(this.c, this.a) * spine.MathUtils.radDeg; + this.ascaleX = Math.sqrt(this.a * this.a + this.c * this.c); + this.ascaleY = Math.sqrt(this.b * this.b + this.d * this.d); + this.ashearX = 0; + this.ashearY = Math.atan2(this.a * this.b + this.c * this.d, this.a * this.d - this.b * this.c) * spine.MathUtils.radDeg; + return; + } + var pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + var pid = 1 / (pa * pd - pb * pc); + var dx = this.worldX - parent.worldX, dy = this.worldY - parent.worldY; + this.ax = (dx * pd * pid - dy * pb * pid); + this.ay = (dy * pa * pid - dx * pc * pid); + var ia = pid * pd; + var id = pid * pa; + var ib = pid * pb; + var ic = pid * pc; + var ra = ia * this.a - ib * this.c; + var rb = ia * this.b - ib * this.d; + var rc = id * this.c - ic * this.a; + var rd = id * this.d - ic * this.b; + this.ashearX = 0; + this.ascaleX = Math.sqrt(ra * ra + rc * rc); + if (this.ascaleX > 0.0001) { + var det = ra * rd - rb * rc; + this.ascaleY = det / this.ascaleX; + this.ashearY = Math.atan2(ra * rb + rc * rd, det) * spine.MathUtils.radDeg; + this.arotation = Math.atan2(rc, ra) * spine.MathUtils.radDeg; + } + else { + this.ascaleX = 0; + this.ascaleY = Math.sqrt(rb * rb + rd * rd); + this.ashearY = 0; + this.arotation = 90 - Math.atan2(rd, rb) * spine.MathUtils.radDeg; + } + }; + Bone.prototype.worldToLocal = function (world) { + var a = this.a, b = this.b, c = this.c, d = this.d; + var invDet = 1 / (a * d - b * c); + var x = world.x - this.worldX, y = world.y - this.worldY; + world.x = (x * d * invDet - y * b * invDet); + world.y = (y * a * invDet - x * c * invDet); + return world; + }; + Bone.prototype.localToWorld = function (local) { + var x = local.x, y = local.y; + local.x = x * this.a + y * this.b + this.worldX; + local.y = x * this.c + y * this.d + this.worldY; + return local; + }; + Bone.prototype.worldToLocalRotation = function (worldRotation) { + var sin = spine.MathUtils.sinDeg(worldRotation), cos = spine.MathUtils.cosDeg(worldRotation); + return Math.atan2(this.a * sin - this.c * cos, this.d * cos - this.b * sin) * spine.MathUtils.radDeg + this.rotation - this.shearX; + }; + Bone.prototype.localToWorldRotation = function (localRotation) { + localRotation -= this.rotation - this.shearX; + var sin = spine.MathUtils.sinDeg(localRotation), cos = spine.MathUtils.cosDeg(localRotation); + return Math.atan2(cos * this.c + sin * this.d, cos * this.a + sin * this.b) * spine.MathUtils.radDeg; + }; + Bone.prototype.rotateWorld = function (degrees) { + var a = this.a, b = this.b, c = this.c, d = this.d; + var cos = spine.MathUtils.cosDeg(degrees), sin = spine.MathUtils.sinDeg(degrees); + this.a = cos * a - sin * c; + this.b = cos * b - sin * d; + this.c = sin * a + cos * c; + this.d = sin * b + cos * d; + this.appliedValid = false; + }; + return Bone; + }()); + spine.Bone = Bone; +})(spine || (spine = {})); +var spine; +(function (spine) { + var BoneData = (function () { + function BoneData(index, name, parent) { + this.x = 0; + this.y = 0; + this.rotation = 0; + this.scaleX = 1; + this.scaleY = 1; + this.shearX = 0; + this.shearY = 0; + this.transformMode = TransformMode.Normal; + this.skinRequired = false; + this.color = new spine.Color(); + if (index < 0) + throw new Error("index must be >= 0."); + if (name == null) + throw new Error("name cannot be null."); + this.index = index; + this.name = name; + this.parent = parent; + } + return BoneData; + }()); + spine.BoneData = BoneData; + var TransformMode; + (function (TransformMode) { + TransformMode[TransformMode["Normal"] = 0] = "Normal"; + TransformMode[TransformMode["OnlyTranslation"] = 1] = "OnlyTranslation"; + TransformMode[TransformMode["NoRotationOrReflection"] = 2] = "NoRotationOrReflection"; + TransformMode[TransformMode["NoScale"] = 3] = "NoScale"; + TransformMode[TransformMode["NoScaleOrReflection"] = 4] = "NoScaleOrReflection"; + })(TransformMode = spine.TransformMode || (spine.TransformMode = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var ConstraintData = (function () { + function ConstraintData(name, order, skinRequired) { + this.name = name; + this.order = order; + this.skinRequired = skinRequired; + } + return ConstraintData; + }()); + spine.ConstraintData = ConstraintData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var Event = (function () { + function Event(time, data) { + if (data == null) + throw new Error("data cannot be null."); + this.time = time; + this.data = data; + } + return Event; + }()); + spine.Event = Event; +})(spine || (spine = {})); +var spine; +(function (spine) { + var EventData = (function () { + function EventData(name) { + this.name = name; + } + return EventData; + }()); + spine.EventData = EventData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var IkConstraint = (function () { + function IkConstraint(data, skeleton) { + this.bendDirection = 0; + this.compress = false; + this.stretch = false; + this.mix = 1; + this.softness = 0; + this.active = false; + if (data == null) + throw new Error("data cannot be null."); + if (skeleton == null) + throw new Error("skeleton cannot be null."); + this.data = data; + this.mix = data.mix; + this.softness = data.softness; + this.bendDirection = data.bendDirection; + this.compress = data.compress; + this.stretch = data.stretch; + this.bones = new Array(); + for (var i = 0; i < data.bones.length; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findBone(data.target.name); + } + IkConstraint.prototype.isActive = function () { + return this.active; + }; + IkConstraint.prototype.apply = function () { + this.update(); + }; + IkConstraint.prototype.update = function () { + var target = this.target; + var bones = this.bones; + switch (bones.length) { + case 1: + this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix); + break; + case 2: + this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.softness, this.mix); + break; + } + }; + IkConstraint.prototype.apply1 = function (bone, targetX, targetY, compress, stretch, uniform, alpha) { + if (!bone.appliedValid) + bone.updateAppliedTransform(); + var p = bone.parent; + var pa = p.a, pb = p.b, pc = p.c, pd = p.d; + var rotationIK = -bone.ashearX - bone.arotation, tx = 0, ty = 0; + switch (bone.data.transformMode) { + case spine.TransformMode.OnlyTranslation: + tx = targetX - bone.worldX; + ty = targetY - bone.worldY; + break; + case spine.TransformMode.NoRotationOrReflection: + var s = Math.abs(pa * pd - pb * pc) / (pa * pa + pc * pc); + var sa = pa / bone.skeleton.scaleX; + var sc = pc / bone.skeleton.scaleY; + pb = -sc * s * bone.skeleton.scaleX; + pd = sa * s * bone.skeleton.scaleY; + rotationIK += Math.atan2(sc, sa) * spine.MathUtils.radDeg; + default: + var x = targetX - p.worldX, y = targetY - p.worldY; + var d = pa * pd - pb * pc; + tx = (x * pd - y * pb) / d - bone.ax; + ty = (y * pa - x * pc) / d - bone.ay; + } + rotationIK += Math.atan2(ty, tx) * spine.MathUtils.radDeg; + if (bone.ascaleX < 0) + rotationIK += 180; + if (rotationIK > 180) + rotationIK -= 360; + else if (rotationIK < -180) + rotationIK += 360; + var sx = bone.ascaleX, sy = bone.ascaleY; + if (compress || stretch) { + switch (bone.data.transformMode) { + case spine.TransformMode.NoScale: + case spine.TransformMode.NoScaleOrReflection: + tx = targetX - bone.worldX; + ty = targetY - bone.worldY; + } + var b = bone.data.length * sx, dd = Math.sqrt(tx * tx + ty * ty); + if ((compress && dd < b) || (stretch && dd > b) && b > 0.0001) { + var s = (dd / b - 1) * alpha + 1; + sx *= s; + if (uniform) + sy *= s; + } + } + bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY); + }; + IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, softness, alpha) { + if (alpha == 0) { + child.updateWorldTransform(); + return; + } + if (!parent.appliedValid) + parent.updateAppliedTransform(); + if (!child.appliedValid) + child.updateAppliedTransform(); + var px = parent.ax, py = parent.ay, psx = parent.ascaleX, sx = psx, psy = parent.ascaleY, csx = child.ascaleX; + var os1 = 0, os2 = 0, s2 = 0; + if (psx < 0) { + psx = -psx; + os1 = 180; + s2 = -1; + } + else { + os1 = 0; + s2 = 1; + } + if (psy < 0) { + psy = -psy; + s2 = -s2; + } + if (csx < 0) { + csx = -csx; + os2 = 180; + } + else + os2 = 0; + var cx = child.ax, cy = 0, cwx = 0, cwy = 0, a = parent.a, b = parent.b, c = parent.c, d = parent.d; + var u = Math.abs(psx - psy) <= 0.0001; + if (!u) { + cy = 0; + cwx = a * cx + parent.worldX; + cwy = c * cx + parent.worldY; + } + else { + cy = child.ay; + cwx = a * cx + b * cy + parent.worldX; + cwy = c * cx + d * cy + parent.worldY; + } + var pp = parent.parent; + a = pp.a; + b = pp.b; + c = pp.c; + d = pp.d; + var id = 1 / (a * d - b * c), x = cwx - pp.worldX, y = cwy - pp.worldY; + var dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; + var l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2; + if (l1 < 0.0001) { + this.apply1(parent, targetX, targetY, false, stretch, false, alpha); + child.updateWorldTransformWith(cx, cy, 0, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY); + return; + } + x = targetX - pp.worldX; + y = targetY - pp.worldY; + var tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py; + var dd = tx * tx + ty * ty; + if (softness != 0) { + softness *= psx * (csx + 1) / 2; + var td = Math.sqrt(dd), sd = td - l1 - l2 * psx + softness; + if (sd > 0) { + var p = Math.min(1, sd / (softness * 2)) - 1; + p = (sd - softness * (1 - p * p)) / td; + tx -= p * tx; + ty -= p * ty; + dd = tx * tx + ty * ty; + } + } + outer: if (u) { + l2 *= psx; + var cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2); + if (cos < -1) + cos = -1; + else if (cos > 1) { + cos = 1; + if (stretch) + sx *= (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1; + } + a2 = Math.acos(cos) * bendDir; + a = l1 + l2 * cos; + b = l2 * Math.sin(a2); + a1 = Math.atan2(ty * a - tx * b, tx * a + ty * b); + } + else { + a = psx * l2; + b = psy * l2; + var aa = a * a, bb = b * b, ta = Math.atan2(ty, tx); + c = bb * l1 * l1 + aa * dd - aa * bb; + var c1 = -2 * bb * l1, c2 = bb - aa; + d = c1 * c1 - 4 * c2 * c; + if (d >= 0) { + var q = Math.sqrt(d); + if (c1 < 0) + q = -q; + q = -(c1 + q) / 2; + var r0 = q / c2, r1 = c / q; + var r = Math.abs(r0) < Math.abs(r1) ? r0 : r1; + if (r * r <= dd) { + y = Math.sqrt(dd - r * r) * bendDir; + a1 = ta - Math.atan2(y, r); + a2 = Math.atan2(y / psy, (r - l1) / psx); + break outer; + } + } + var minAngle = spine.MathUtils.PI, minX = l1 - a, minDist = minX * minX, minY = 0; + var maxAngle = 0, maxX = l1 + a, maxDist = maxX * maxX, maxY = 0; + c = -a * l1 / (aa - bb); + if (c >= -1 && c <= 1) { + c = Math.acos(c); + x = a * Math.cos(c) + l1; + y = b * Math.sin(c); + d = x * x + y * y; + if (d < minDist) { + minAngle = c; + minDist = d; + minX = x; + minY = y; + } + if (d > maxDist) { + maxAngle = c; + maxDist = d; + maxX = x; + maxY = y; + } + } + if (dd <= (minDist + maxDist) / 2) { + a1 = ta - Math.atan2(minY * bendDir, minX); + a2 = minAngle * bendDir; + } + else { + a1 = ta - Math.atan2(maxY * bendDir, maxX); + a2 = maxAngle * bendDir; + } + } + var os = Math.atan2(cy, cx) * s2; + var rotation = parent.arotation; + a1 = (a1 - os) * spine.MathUtils.radDeg + os1 - rotation; + if (a1 > 180) + a1 -= 360; + else if (a1 < -180) + a1 += 360; + parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, sx, parent.ascaleY, 0, 0); + rotation = child.arotation; + a2 = ((a2 + os) * spine.MathUtils.radDeg - child.ashearX) * s2 + os2 - rotation; + if (a2 > 180) + a2 -= 360; + else if (a2 < -180) + a2 += 360; + child.updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY); + }; + return IkConstraint; + }()); + spine.IkConstraint = IkConstraint; +})(spine || (spine = {})); +var spine; +(function (spine) { + var IkConstraintData = (function (_super) { + __extends(IkConstraintData, _super); + function IkConstraintData(name) { + var _this = _super.call(this, name, 0, false) || this; + _this.bones = new Array(); + _this.bendDirection = 1; + _this.compress = false; + _this.stretch = false; + _this.uniform = false; + _this.mix = 1; + _this.softness = 0; + return _this; + } + return IkConstraintData; + }(spine.ConstraintData)); + spine.IkConstraintData = IkConstraintData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var PathConstraint = (function () { + function PathConstraint(data, skeleton) { + this.position = 0; + this.spacing = 0; + this.rotateMix = 0; + this.translateMix = 0; + this.spaces = new Array(); + this.positions = new Array(); + this.world = new Array(); + this.curves = new Array(); + this.lengths = new Array(); + this.segments = new Array(); + this.active = false; + if (data == null) + throw new Error("data cannot be null."); + if (skeleton == null) + throw new Error("skeleton cannot be null."); + this.data = data; + this.bones = new Array(); + for (var i = 0, n = data.bones.length; i < n; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findSlot(data.target.name); + this.position = data.position; + this.spacing = data.spacing; + this.rotateMix = data.rotateMix; + this.translateMix = data.translateMix; + } + PathConstraint.prototype.isActive = function () { + return this.active; + }; + PathConstraint.prototype.apply = function () { + this.update(); + }; + PathConstraint.prototype.update = function () { + var attachment = this.target.getAttachment(); + if (!(attachment instanceof spine.PathAttachment)) + return; + var rotateMix = this.rotateMix, translateMix = this.translateMix; + var translate = translateMix > 0, rotate = rotateMix > 0; + if (!translate && !rotate) + return; + var data = this.data; + var percentSpacing = data.spacingMode == spine.SpacingMode.Percent; + var rotateMode = data.rotateMode; + var tangents = rotateMode == spine.RotateMode.Tangent, scale = rotateMode == spine.RotateMode.ChainScale; + var boneCount = this.bones.length, spacesCount = tangents ? boneCount : boneCount + 1; + var bones = this.bones; + var spaces = spine.Utils.setArraySize(this.spaces, spacesCount), lengths = null; + var spacing = this.spacing; + if (scale || !percentSpacing) { + if (scale) + lengths = spine.Utils.setArraySize(this.lengths, boneCount); + var lengthSpacing = data.spacingMode == spine.SpacingMode.Length; + for (var i = 0, n = spacesCount - 1; i < n;) { + var bone = bones[i]; + var setupLength = bone.data.length; + if (setupLength < PathConstraint.epsilon) { + if (scale) + lengths[i] = 0; + spaces[++i] = 0; + } + else if (percentSpacing) { + if (scale) { + var x = setupLength * bone.a, y = setupLength * bone.c; + var length_1 = Math.sqrt(x * x + y * y); + lengths[i] = length_1; + } + spaces[++i] = spacing; + } + else { + var x = setupLength * bone.a, y = setupLength * bone.c; + var length_2 = Math.sqrt(x * x + y * y); + if (scale) + lengths[i] = length_2; + spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length_2 / setupLength; + } + } + } + else { + for (var i = 1; i < spacesCount; i++) + spaces[i] = spacing; + } + var positions = this.computeWorldPositions(attachment, spacesCount, tangents, data.positionMode == spine.PositionMode.Percent, percentSpacing); + var boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation; + var tip = false; + if (offsetRotation == 0) + tip = rotateMode == spine.RotateMode.Chain; + else { + tip = false; + var p = this.target.bone; + offsetRotation *= p.a * p.d - p.b * p.c > 0 ? spine.MathUtils.degRad : -spine.MathUtils.degRad; + } + for (var i = 0, p = 3; i < boneCount; i++, p += 3) { + var bone = bones[i]; + bone.worldX += (boneX - bone.worldX) * translateMix; + bone.worldY += (boneY - bone.worldY) * translateMix; + var x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY; + if (scale) { + var length_3 = lengths[i]; + if (length_3 != 0) { + var s = (Math.sqrt(dx * dx + dy * dy) / length_3 - 1) * rotateMix + 1; + bone.a *= s; + bone.c *= s; + } + } + boneX = x; + boneY = y; + if (rotate) { + var a = bone.a, b = bone.b, c = bone.c, d = bone.d, r = 0, cos = 0, sin = 0; + if (tangents) + r = positions[p - 1]; + else if (spaces[i + 1] == 0) + r = positions[p + 2]; + else + r = Math.atan2(dy, dx); + r -= Math.atan2(c, a); + if (tip) { + cos = Math.cos(r); + sin = Math.sin(r); + var length_4 = bone.data.length; + boneX += (length_4 * (cos * a - sin * c) - dx) * rotateMix; + boneY += (length_4 * (sin * a + cos * c) - dy) * rotateMix; + } + else { + r += offsetRotation; + } + if (r > spine.MathUtils.PI) + r -= spine.MathUtils.PI2; + else if (r < -spine.MathUtils.PI) + r += spine.MathUtils.PI2; + r *= rotateMix; + cos = Math.cos(r); + sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + bone.appliedValid = false; + } + }; + PathConstraint.prototype.computeWorldPositions = function (path, spacesCount, tangents, percentPosition, percentSpacing) { + var target = this.target; + var position = this.position; + var spaces = this.spaces, out = spine.Utils.setArraySize(this.positions, spacesCount * 3 + 2), world = null; + var closed = path.closed; + var verticesLength = path.worldVerticesLength, curveCount = verticesLength / 6, prevCurve = PathConstraint.NONE; + if (!path.constantSpeed) { + var lengths = path.lengths; + curveCount -= closed ? 1 : 2; + var pathLength_1 = lengths[curveCount]; + if (percentPosition) + position *= pathLength_1; + if (percentSpacing) { + for (var i = 1; i < spacesCount; i++) + spaces[i] *= pathLength_1; + } + world = spine.Utils.setArraySize(this.world, 8); + for (var i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { + var space = spaces[i]; + position += space; + var p = position; + if (closed) { + p %= pathLength_1; + if (p < 0) + p += pathLength_1; + curve = 0; + } + else if (p < 0) { + if (prevCurve != PathConstraint.BEFORE) { + prevCurve = PathConstraint.BEFORE; + path.computeWorldVertices(target, 2, 4, world, 0, 2); + } + this.addBeforePosition(p, world, 0, out, o); + continue; + } + else if (p > pathLength_1) { + if (prevCurve != PathConstraint.AFTER) { + prevCurve = PathConstraint.AFTER; + path.computeWorldVertices(target, verticesLength - 6, 4, world, 0, 2); + } + this.addAfterPosition(p - pathLength_1, world, 0, out, o); + continue; + } + for (;; curve++) { + var length_5 = lengths[curve]; + if (p > length_5) + continue; + if (curve == 0) + p /= length_5; + else { + var prev = lengths[curve - 1]; + p = (p - prev) / (length_5 - prev); + } + break; + } + if (curve != prevCurve) { + prevCurve = curve; + if (closed && curve == curveCount) { + path.computeWorldVertices(target, verticesLength - 4, 4, world, 0, 2); + path.computeWorldVertices(target, 0, 4, world, 4, 2); + } + else + path.computeWorldVertices(target, curve * 6 + 2, 8, world, 0, 2); + } + this.addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], out, o, tangents || (i > 0 && space == 0)); + } + return out; + } + if (closed) { + verticesLength += 2; + world = spine.Utils.setArraySize(this.world, verticesLength); + path.computeWorldVertices(target, 2, verticesLength - 4, world, 0, 2); + path.computeWorldVertices(target, 0, 2, world, verticesLength - 4, 2); + world[verticesLength - 2] = world[0]; + world[verticesLength - 1] = world[1]; + } + else { + curveCount--; + verticesLength -= 4; + world = spine.Utils.setArraySize(this.world, verticesLength); + path.computeWorldVertices(target, 2, verticesLength, world, 0, 2); + } + var curves = spine.Utils.setArraySize(this.curves, curveCount); + var pathLength = 0; + var x1 = world[0], y1 = world[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0; + var tmpx = 0, tmpy = 0, dddfx = 0, dddfy = 0, ddfx = 0, ddfy = 0, dfx = 0, dfy = 0; + for (var i = 0, w = 2; i < curveCount; i++, w += 6) { + cx1 = world[w]; + cy1 = world[w + 1]; + cx2 = world[w + 2]; + cy2 = world[w + 3]; + x2 = world[w + 4]; + y2 = world[w + 5]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.1875; + tmpy = (y1 - cy1 * 2 + cy2) * 0.1875; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + curves[i] = pathLength; + x1 = x2; + y1 = y2; + } + if (percentPosition) + position *= pathLength; + else + position *= pathLength / path.lengths[curveCount - 1]; + if (percentSpacing) { + for (var i = 1; i < spacesCount; i++) + spaces[i] *= pathLength; + } + var segments = this.segments; + var curveLength = 0; + for (var i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { + var space = spaces[i]; + position += space; + var p = position; + if (closed) { + p %= pathLength; + if (p < 0) + p += pathLength; + curve = 0; + } + else if (p < 0) { + this.addBeforePosition(p, world, 0, out, o); + continue; + } + else if (p > pathLength) { + this.addAfterPosition(p - pathLength, world, verticesLength - 4, out, o); + continue; + } + for (;; curve++) { + var length_6 = curves[curve]; + if (p > length_6) + continue; + if (curve == 0) + p /= length_6; + else { + var prev = curves[curve - 1]; + p = (p - prev) / (length_6 - prev); + } + break; + } + if (curve != prevCurve) { + prevCurve = curve; + var ii = curve * 6; + x1 = world[ii]; + y1 = world[ii + 1]; + cx1 = world[ii + 2]; + cy1 = world[ii + 3]; + cx2 = world[ii + 4]; + cy2 = world[ii + 5]; + x2 = world[ii + 6]; + y2 = world[ii + 7]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.03; + tmpy = (y1 - cy1 * 2 + cy2) * 0.03; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667; + curveLength = Math.sqrt(dfx * dfx + dfy * dfy); + segments[0] = curveLength; + for (ii = 1; ii < 8; ii++) { + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[ii] = curveLength; + } + dfx += ddfx; + dfy += ddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[8] = curveLength; + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[9] = curveLength; + segment = 0; + } + p *= curveLength; + for (;; segment++) { + var length_7 = segments[segment]; + if (p > length_7) + continue; + if (segment == 0) + p /= length_7; + else { + var prev = segments[segment - 1]; + p = segment + (p - prev) / (length_7 - prev); + } + break; + } + this.addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || (i > 0 && space == 0)); + } + return out; + }; + PathConstraint.prototype.addBeforePosition = function (p, temp, i, out, o) { + var x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + }; + PathConstraint.prototype.addAfterPosition = function (p, temp, i, out, o) { + var x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + }; + PathConstraint.prototype.addCurvePosition = function (p, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents) { + if (p == 0 || isNaN(p)) { + out[o] = x1; + out[o + 1] = y1; + out[o + 2] = Math.atan2(cy1 - y1, cx1 - x1); + return; + } + var tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u; + var ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p; + var x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; + out[o] = x; + out[o + 1] = y; + if (tangents) { + if (p < 0.001) + out[o + 2] = Math.atan2(cy1 - y1, cx1 - x1); + else + out[o + 2] = Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); + } + }; + PathConstraint.NONE = -1; + PathConstraint.BEFORE = -2; + PathConstraint.AFTER = -3; + PathConstraint.epsilon = 0.00001; + return PathConstraint; + }()); + spine.PathConstraint = PathConstraint; +})(spine || (spine = {})); +var spine; +(function (spine) { + var PathConstraintData = (function (_super) { + __extends(PathConstraintData, _super); + function PathConstraintData(name) { + var _this = _super.call(this, name, 0, false) || this; + _this.bones = new Array(); + return _this; + } + return PathConstraintData; + }(spine.ConstraintData)); + spine.PathConstraintData = PathConstraintData; + var PositionMode; + (function (PositionMode) { + PositionMode[PositionMode["Fixed"] = 0] = "Fixed"; + PositionMode[PositionMode["Percent"] = 1] = "Percent"; + })(PositionMode = spine.PositionMode || (spine.PositionMode = {})); + var SpacingMode; + (function (SpacingMode) { + SpacingMode[SpacingMode["Length"] = 0] = "Length"; + SpacingMode[SpacingMode["Fixed"] = 1] = "Fixed"; + SpacingMode[SpacingMode["Percent"] = 2] = "Percent"; + })(SpacingMode = spine.SpacingMode || (spine.SpacingMode = {})); + var RotateMode; + (function (RotateMode) { + RotateMode[RotateMode["Tangent"] = 0] = "Tangent"; + RotateMode[RotateMode["Chain"] = 1] = "Chain"; + RotateMode[RotateMode["ChainScale"] = 2] = "ChainScale"; + })(RotateMode = spine.RotateMode || (spine.RotateMode = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var Assets = (function () { + function Assets(clientId) { + this.toLoad = new Array(); + this.assets = {}; + this.clientId = clientId; + } + Assets.prototype.loaded = function () { + var i = 0; + for (var v in this.assets) + i++; + return i; + }; + return Assets; + }()); + var SharedAssetManager = (function () { + function SharedAssetManager(pathPrefix) { + if (pathPrefix === void 0) { pathPrefix = ""; } + this.clientAssets = {}; + this.queuedAssets = {}; + this.rawAssets = {}; + this.errors = {}; + this.pathPrefix = pathPrefix; + } + SharedAssetManager.prototype.queueAsset = function (clientId, textureLoader, path) { + var clientAssets = this.clientAssets[clientId]; + if (clientAssets === null || clientAssets === undefined) { + clientAssets = new Assets(clientId); + this.clientAssets[clientId] = clientAssets; + } + if (textureLoader !== null) + clientAssets.textureLoader = textureLoader; + clientAssets.toLoad.push(path); + if (this.queuedAssets[path] === path) { + return false; + } + else { + this.queuedAssets[path] = path; + return true; + } + }; + SharedAssetManager.prototype.loadText = function (clientId, path) { + var _this = this; + path = this.pathPrefix + path; + if (!this.queueAsset(clientId, null, path)) + return; + var request = new XMLHttpRequest(); + request.overrideMimeType("text/html"); + request.onreadystatechange = function () { + if (request.readyState == XMLHttpRequest.DONE) { + if (request.status >= 200 && request.status < 300) { + _this.rawAssets[path] = request.responseText; + } + else { + _this.errors[path] = "Couldn't load text " + path + ": status " + request.status + ", " + request.responseText; + } + } + }; + request.open("GET", path, true); + request.send(); + }; + SharedAssetManager.prototype.loadJson = function (clientId, path) { + var _this = this; + path = this.pathPrefix + path; + if (!this.queueAsset(clientId, null, path)) + return; + var request = new XMLHttpRequest(); + request.overrideMimeType("text/html"); + request.onreadystatechange = function () { + if (request.readyState == XMLHttpRequest.DONE) { + if (request.status >= 200 && request.status < 300) { + _this.rawAssets[path] = JSON.parse(request.responseText); + } + else { + _this.errors[path] = "Couldn't load text " + path + ": status " + request.status + ", " + request.responseText; + } + } + }; + request.open("GET", path, true); + request.send(); + }; + SharedAssetManager.prototype.loadTexture = function (clientId, textureLoader, path) { + var _this = this; + path = this.pathPrefix + path; + if (!this.queueAsset(clientId, textureLoader, path)) + return; + var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document); + var isWebWorker = !isBrowser && typeof importScripts !== 'undefined'; + if (isWebWorker) { + var options = { mode: "cors" }; + fetch(path, options).then(function (response) { + if (!response.ok) { + _this.errors[path] = "Couldn't load image " + path; + } + return response.blob(); + }).then(function (blob) { + return createImageBitmap(blob, { + premultiplyAlpha: 'none', + colorSpaceConversion: 'none' + }); + }).then(function (bitmap) { + _this.rawAssets[path] = bitmap; + }); + } + else { + var img_1 = new Image(); + img_1.crossOrigin = "anonymous"; + img_1.onload = function (ev) { + _this.rawAssets[path] = img_1; + }; + img_1.onerror = function (ev) { + _this.errors[path] = "Couldn't load image " + path; + }; + img_1.src = path; + } + }; + SharedAssetManager.prototype.get = function (clientId, path) { + path = this.pathPrefix + path; + var clientAssets = this.clientAssets[clientId]; + if (clientAssets === null || clientAssets === undefined) + return true; + return clientAssets.assets[path]; + }; + SharedAssetManager.prototype.updateClientAssets = function (clientAssets) { + var isBrowser = !!(typeof window !== 'undefined' && typeof navigator !== 'undefined' && window.document); + var isWebWorker = !isBrowser && typeof importScripts !== 'undefined'; + for (var i = 0; i < clientAssets.toLoad.length; i++) { + var path = clientAssets.toLoad[i]; + var asset = clientAssets.assets[path]; + if (asset === null || asset === undefined) { + var rawAsset = this.rawAssets[path]; + if (rawAsset === null || rawAsset === undefined) + continue; + if (isWebWorker) { + if (rawAsset instanceof ImageBitmap) { + clientAssets.assets[path] = clientAssets.textureLoader(rawAsset); + } + else { + clientAssets.assets[path] = rawAsset; + } + } + else { + if (rawAsset instanceof HTMLImageElement) { + clientAssets.assets[path] = clientAssets.textureLoader(rawAsset); + } + else { + clientAssets.assets[path] = rawAsset; + } + } + } + } + }; + SharedAssetManager.prototype.isLoadingComplete = function (clientId) { + var clientAssets = this.clientAssets[clientId]; + if (clientAssets === null || clientAssets === undefined) + return true; + this.updateClientAssets(clientAssets); + return clientAssets.toLoad.length == clientAssets.loaded(); + }; + SharedAssetManager.prototype.dispose = function () { + }; + SharedAssetManager.prototype.hasErrors = function () { + return Object.keys(this.errors).length > 0; + }; + SharedAssetManager.prototype.getErrors = function () { + return this.errors; + }; + return SharedAssetManager; + }()); + spine.SharedAssetManager = SharedAssetManager; +})(spine || (spine = {})); +var spine; +(function (spine) { + var Skeleton = (function () { + function Skeleton(data) { + this._updateCache = new Array(); + this.updateCacheReset = new Array(); + this.time = 0; + this.scaleX = 1; + this.scaleY = 1; + this.x = 0; + this.y = 0; + if (data == null) + throw new Error("data cannot be null."); + this.data = data; + this.bones = new Array(); + for (var i = 0; i < data.bones.length; i++) { + var boneData = data.bones[i]; + var bone = void 0; + if (boneData.parent == null) + bone = new spine.Bone(boneData, this, null); + else { + var parent_1 = this.bones[boneData.parent.index]; + bone = new spine.Bone(boneData, this, parent_1); + parent_1.children.push(bone); + } + this.bones.push(bone); + } + this.slots = new Array(); + this.drawOrder = new Array(); + for (var i = 0; i < data.slots.length; i++) { + var slotData = data.slots[i]; + var bone = this.bones[slotData.boneData.index]; + var slot = new spine.Slot(slotData, bone); + this.slots.push(slot); + this.drawOrder.push(slot); + } + this.ikConstraints = new Array(); + for (var i = 0; i < data.ikConstraints.length; i++) { + var ikConstraintData = data.ikConstraints[i]; + this.ikConstraints.push(new spine.IkConstraint(ikConstraintData, this)); + } + this.transformConstraints = new Array(); + for (var i = 0; i < data.transformConstraints.length; i++) { + var transformConstraintData = data.transformConstraints[i]; + this.transformConstraints.push(new spine.TransformConstraint(transformConstraintData, this)); + } + this.pathConstraints = new Array(); + for (var i = 0; i < data.pathConstraints.length; i++) { + var pathConstraintData = data.pathConstraints[i]; + this.pathConstraints.push(new spine.PathConstraint(pathConstraintData, this)); + } + this.color = new spine.Color(1, 1, 1, 1); + this.updateCache(); + } + Skeleton.prototype.updateCache = function () { + var updateCache = this._updateCache; + updateCache.length = 0; + this.updateCacheReset.length = 0; + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + bone.sorted = bone.data.skinRequired; + bone.active = !bone.sorted; + } + if (this.skin != null) { + var skinBones = this.skin.bones; + for (var i = 0, n = this.skin.bones.length; i < n; i++) { + var bone = this.bones[skinBones[i].index]; + do { + bone.sorted = false; + bone.active = true; + bone = bone.parent; + } while (bone != null); + } + } + var ikConstraints = this.ikConstraints; + var transformConstraints = this.transformConstraints; + var pathConstraints = this.pathConstraints; + var ikCount = ikConstraints.length, transformCount = transformConstraints.length, pathCount = pathConstraints.length; + var constraintCount = ikCount + transformCount + pathCount; + outer: for (var i = 0; i < constraintCount; i++) { + for (var ii = 0; ii < ikCount; ii++) { + var constraint = ikConstraints[ii]; + if (constraint.data.order == i) { + this.sortIkConstraint(constraint); + continue outer; + } + } + for (var ii = 0; ii < transformCount; ii++) { + var constraint = transformConstraints[ii]; + if (constraint.data.order == i) { + this.sortTransformConstraint(constraint); + continue outer; + } + } + for (var ii = 0; ii < pathCount; ii++) { + var constraint = pathConstraints[ii]; + if (constraint.data.order == i) { + this.sortPathConstraint(constraint); + continue outer; + } + } + } + for (var i = 0, n = bones.length; i < n; i++) + this.sortBone(bones[i]); + }; + Skeleton.prototype.sortIkConstraint = function (constraint) { + constraint.active = constraint.target.isActive() && (!constraint.data.skinRequired || (this.skin != null && spine.Utils.contains(this.skin.constraints, constraint.data, true))); + if (!constraint.active) + return; + var target = constraint.target; + this.sortBone(target); + var constrained = constraint.bones; + var parent = constrained[0]; + this.sortBone(parent); + if (constrained.length > 1) { + var child = constrained[constrained.length - 1]; + if (!(this._updateCache.indexOf(child) > -1)) + this.updateCacheReset.push(child); + } + this._updateCache.push(constraint); + this.sortReset(parent.children); + constrained[constrained.length - 1].sorted = true; + }; + Skeleton.prototype.sortPathConstraint = function (constraint) { + constraint.active = constraint.target.bone.isActive() && (!constraint.data.skinRequired || (this.skin != null && spine.Utils.contains(this.skin.constraints, constraint.data, true))); + if (!constraint.active) + return; + var slot = constraint.target; + var slotIndex = slot.data.index; + var slotBone = slot.bone; + if (this.skin != null) + this.sortPathConstraintAttachment(this.skin, slotIndex, slotBone); + if (this.data.defaultSkin != null && this.data.defaultSkin != this.skin) + this.sortPathConstraintAttachment(this.data.defaultSkin, slotIndex, slotBone); + for (var i = 0, n = this.data.skins.length; i < n; i++) + this.sortPathConstraintAttachment(this.data.skins[i], slotIndex, slotBone); + var attachment = slot.getAttachment(); + if (attachment instanceof spine.PathAttachment) + this.sortPathConstraintAttachmentWith(attachment, slotBone); + var constrained = constraint.bones; + var boneCount = constrained.length; + for (var i = 0; i < boneCount; i++) + this.sortBone(constrained[i]); + this._updateCache.push(constraint); + for (var i = 0; i < boneCount; i++) + this.sortReset(constrained[i].children); + for (var i = 0; i < boneCount; i++) + constrained[i].sorted = true; + }; + Skeleton.prototype.sortTransformConstraint = function (constraint) { + constraint.active = constraint.target.isActive() && (!constraint.data.skinRequired || (this.skin != null && spine.Utils.contains(this.skin.constraints, constraint.data, true))); + if (!constraint.active) + return; + this.sortBone(constraint.target); + var constrained = constraint.bones; + var boneCount = constrained.length; + if (constraint.data.local) { + for (var i = 0; i < boneCount; i++) { + var child = constrained[i]; + this.sortBone(child.parent); + if (!(this._updateCache.indexOf(child) > -1)) + this.updateCacheReset.push(child); + } + } + else { + for (var i = 0; i < boneCount; i++) { + this.sortBone(constrained[i]); + } + } + this._updateCache.push(constraint); + for (var ii = 0; ii < boneCount; ii++) + this.sortReset(constrained[ii].children); + for (var ii = 0; ii < boneCount; ii++) + constrained[ii].sorted = true; + }; + Skeleton.prototype.sortPathConstraintAttachment = function (skin, slotIndex, slotBone) { + var attachments = skin.attachments[slotIndex]; + if (!attachments) + return; + for (var key in attachments) { + this.sortPathConstraintAttachmentWith(attachments[key], slotBone); + } + }; + Skeleton.prototype.sortPathConstraintAttachmentWith = function (attachment, slotBone) { + if (!(attachment instanceof spine.PathAttachment)) + return; + var pathBones = attachment.bones; + if (pathBones == null) + this.sortBone(slotBone); + else { + var bones = this.bones; + var i = 0; + while (i < pathBones.length) { + var boneCount = pathBones[i++]; + for (var n = i + boneCount; i < n; i++) { + var boneIndex = pathBones[i]; + this.sortBone(bones[boneIndex]); + } + } + } + }; + Skeleton.prototype.sortBone = function (bone) { + if (bone.sorted) + return; + var parent = bone.parent; + if (parent != null) + this.sortBone(parent); + bone.sorted = true; + this._updateCache.push(bone); + }; + Skeleton.prototype.sortReset = function (bones) { + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + if (!bone.active) + continue; + if (bone.sorted) + this.sortReset(bone.children); + bone.sorted = false; + } + }; + Skeleton.prototype.updateWorldTransform = function () { + var updateCacheReset = this.updateCacheReset; + for (var i = 0, n = updateCacheReset.length; i < n; i++) { + var bone = updateCacheReset[i]; + bone.ax = bone.x; + bone.ay = bone.y; + bone.arotation = bone.rotation; + bone.ascaleX = bone.scaleX; + bone.ascaleY = bone.scaleY; + bone.ashearX = bone.shearX; + bone.ashearY = bone.shearY; + bone.appliedValid = true; + } + var updateCache = this._updateCache; + for (var i = 0, n = updateCache.length; i < n; i++) + updateCache[i].update(); + }; + Skeleton.prototype.setToSetupPose = function () { + this.setBonesToSetupPose(); + this.setSlotsToSetupPose(); + }; + Skeleton.prototype.setBonesToSetupPose = function () { + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + bones[i].setToSetupPose(); + var ikConstraints = this.ikConstraints; + for (var i = 0, n = ikConstraints.length; i < n; i++) { + var constraint = ikConstraints[i]; + constraint.mix = constraint.data.mix; + constraint.softness = constraint.data.softness; + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } + var transformConstraints = this.transformConstraints; + for (var i = 0, n = transformConstraints.length; i < n; i++) { + var constraint = transformConstraints[i]; + var data = constraint.data; + constraint.rotateMix = data.rotateMix; + constraint.translateMix = data.translateMix; + constraint.scaleMix = data.scaleMix; + constraint.shearMix = data.shearMix; + } + var pathConstraints = this.pathConstraints; + for (var i = 0, n = pathConstraints.length; i < n; i++) { + var constraint = pathConstraints[i]; + var data = constraint.data; + constraint.position = data.position; + constraint.spacing = data.spacing; + constraint.rotateMix = data.rotateMix; + constraint.translateMix = data.translateMix; + } + }; + Skeleton.prototype.setSlotsToSetupPose = function () { + var slots = this.slots; + spine.Utils.arrayCopy(slots, 0, this.drawOrder, 0, slots.length); + for (var i = 0, n = slots.length; i < n; i++) + slots[i].setToSetupPose(); + }; + Skeleton.prototype.getRootBone = function () { + if (this.bones.length == 0) + return null; + return this.bones[0]; + }; + Skeleton.prototype.findBone = function (boneName) { + if (boneName == null) + throw new Error("boneName cannot be null."); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + if (bone.data.name == boneName) + return bone; + } + return null; + }; + Skeleton.prototype.findBoneIndex = function (boneName) { + if (boneName == null) + throw new Error("boneName cannot be null."); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].data.name == boneName) + return i; + return -1; + }; + Skeleton.prototype.findSlot = function (slotName) { + if (slotName == null) + throw new Error("slotName cannot be null."); + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + var slot = slots[i]; + if (slot.data.name == slotName) + return slot; + } + return null; + }; + Skeleton.prototype.findSlotIndex = function (slotName) { + if (slotName == null) + throw new Error("slotName cannot be null."); + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].data.name == slotName) + return i; + return -1; + }; + Skeleton.prototype.setSkinByName = function (skinName) { + var skin = this.data.findSkin(skinName); + if (skin == null) + throw new Error("Skin not found: " + skinName); + this.setSkin(skin); + }; + Skeleton.prototype.setSkin = function (newSkin) { + if (newSkin == this.skin) + return; + if (newSkin != null) { + if (this.skin != null) + newSkin.attachAll(this, this.skin); + else { + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + var slot = slots[i]; + var name_1 = slot.data.attachmentName; + if (name_1 != null) { + var attachment = newSkin.getAttachment(i, name_1); + if (attachment != null) + slot.setAttachment(attachment); + } + } + } + } + this.skin = newSkin; + this.updateCache(); + }; + Skeleton.prototype.getAttachmentByName = function (slotName, attachmentName) { + return this.getAttachment(this.data.findSlotIndex(slotName), attachmentName); + }; + Skeleton.prototype.getAttachment = function (slotIndex, attachmentName) { + if (attachmentName == null) + throw new Error("attachmentName cannot be null."); + if (this.skin != null) { + var attachment = this.skin.getAttachment(slotIndex, attachmentName); + if (attachment != null) + return attachment; + } + if (this.data.defaultSkin != null) + return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); + return null; + }; + Skeleton.prototype.setAttachment = function (slotName, attachmentName) { + if (slotName == null) + throw new Error("slotName cannot be null."); + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + var slot = slots[i]; + if (slot.data.name == slotName) { + var attachment = null; + if (attachmentName != null) { + attachment = this.getAttachment(i, attachmentName); + if (attachment == null) + throw new Error("Attachment not found: " + attachmentName + ", for slot: " + slotName); + } + slot.setAttachment(attachment); + return; + } + } + throw new Error("Slot not found: " + slotName); + }; + Skeleton.prototype.findIkConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var ikConstraints = this.ikConstraints; + for (var i = 0, n = ikConstraints.length; i < n; i++) { + var ikConstraint = ikConstraints[i]; + if (ikConstraint.data.name == constraintName) + return ikConstraint; + } + return null; + }; + Skeleton.prototype.findTransformConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var transformConstraints = this.transformConstraints; + for (var i = 0, n = transformConstraints.length; i < n; i++) { + var constraint = transformConstraints[i]; + if (constraint.data.name == constraintName) + return constraint; + } + return null; + }; + Skeleton.prototype.findPathConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var pathConstraints = this.pathConstraints; + for (var i = 0, n = pathConstraints.length; i < n; i++) { + var constraint = pathConstraints[i]; + if (constraint.data.name == constraintName) + return constraint; + } + return null; + }; + Skeleton.prototype.getBounds = function (offset, size, temp) { + if (temp === void 0) { temp = new Array(2); } + if (offset == null) + throw new Error("offset cannot be null."); + if (size == null) + throw new Error("size cannot be null."); + var drawOrder = this.drawOrder; + var minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + if (!slot.bone.active) + continue; + var verticesLength = 0; + var vertices = null; + var attachment = slot.getAttachment(); + if (attachment instanceof spine.RegionAttachment) { + verticesLength = 8; + vertices = spine.Utils.setArraySize(temp, verticesLength, 0); + attachment.computeWorldVertices(slot.bone, vertices, 0, 2); + } + else if (attachment instanceof spine.MeshAttachment) { + var mesh = attachment; + verticesLength = mesh.worldVerticesLength; + vertices = spine.Utils.setArraySize(temp, verticesLength, 0); + mesh.computeWorldVertices(slot, 0, verticesLength, vertices, 0, 2); + } + if (vertices != null) { + for (var ii = 0, nn = vertices.length; ii < nn; ii += 2) { + var x = vertices[ii], y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + } + offset.set(minX, minY); + size.set(maxX - minX, maxY - minY); + }; + Skeleton.prototype.update = function (delta) { + this.time += delta; + }; + return Skeleton; + }()); + spine.Skeleton = Skeleton; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SkeletonBinary = (function () { + function SkeletonBinary(attachmentLoader) { + this.scale = 1; + this.linkedMeshes = new Array(); + this.attachmentLoader = attachmentLoader; + } + SkeletonBinary.prototype.readSkeletonData = function (binary) { + var scale = this.scale; + var skeletonData = new spine.SkeletonData(); + skeletonData.name = ""; + var input = new BinaryInput(binary); + skeletonData.hash = input.readString(); + skeletonData.version = input.readString(); + if ("3.8.75" == skeletonData.version) + throw new Error("Unsupported skeleton data, please export with a newer version of Spine."); + skeletonData.x = input.readFloat(); + skeletonData.y = input.readFloat(); + skeletonData.width = input.readFloat(); + skeletonData.height = input.readFloat(); + var nonessential = input.readBoolean(); + if (nonessential) { + skeletonData.fps = input.readFloat(); + skeletonData.imagesPath = input.readString(); + skeletonData.audioPath = input.readString(); + } + var n = 0; + n = input.readInt(true); + for (var i = 0; i < n; i++) + input.strings.push(input.readString()); + n = input.readInt(true); + for (var i = 0; i < n; i++) { + var name_2 = input.readString(); + var parent_2 = i == 0 ? null : skeletonData.bones[input.readInt(true)]; + var data = new spine.BoneData(i, name_2, parent_2); + data.rotation = input.readFloat(); + data.x = input.readFloat() * scale; + data.y = input.readFloat() * scale; + data.scaleX = input.readFloat(); + data.scaleY = input.readFloat(); + data.shearX = input.readFloat(); + data.shearY = input.readFloat(); + data.length = input.readFloat() * scale; + data.transformMode = SkeletonBinary.TransformModeValues[input.readInt(true)]; + data.skinRequired = input.readBoolean(); + if (nonessential) + spine.Color.rgba8888ToColor(data.color, input.readInt32()); + skeletonData.bones.push(data); + } + n = input.readInt(true); + for (var i = 0; i < n; i++) { + var slotName = input.readString(); + var boneData = skeletonData.bones[input.readInt(true)]; + var data = new spine.SlotData(i, slotName, boneData); + spine.Color.rgba8888ToColor(data.color, input.readInt32()); + var darkColor = input.readInt32(); + if (darkColor != -1) + spine.Color.rgb888ToColor(data.darkColor = new spine.Color(), darkColor); + data.attachmentName = input.readStringRef(); + data.blendMode = SkeletonBinary.BlendModeValues[input.readInt(true)]; + skeletonData.slots.push(data); + } + n = input.readInt(true); + for (var i = 0, nn = void 0; i < n; i++) { + var data = new spine.IkConstraintData(input.readString()); + data.order = input.readInt(true); + data.skinRequired = input.readBoolean(); + nn = input.readInt(true); + for (var ii = 0; ii < nn; ii++) + data.bones.push(skeletonData.bones[input.readInt(true)]); + data.target = skeletonData.bones[input.readInt(true)]; + data.mix = input.readFloat(); + data.softness = input.readFloat() * scale; + data.bendDirection = input.readByte(); + data.compress = input.readBoolean(); + data.stretch = input.readBoolean(); + data.uniform = input.readBoolean(); + skeletonData.ikConstraints.push(data); + } + n = input.readInt(true); + for (var i = 0, nn = void 0; i < n; i++) { + var data = new spine.TransformConstraintData(input.readString()); + data.order = input.readInt(true); + data.skinRequired = input.readBoolean(); + nn = input.readInt(true); + for (var ii = 0; ii < nn; ii++) + data.bones.push(skeletonData.bones[input.readInt(true)]); + data.target = skeletonData.bones[input.readInt(true)]; + data.local = input.readBoolean(); + data.relative = input.readBoolean(); + data.offsetRotation = input.readFloat(); + data.offsetX = input.readFloat() * scale; + data.offsetY = input.readFloat() * scale; + data.offsetScaleX = input.readFloat(); + data.offsetScaleY = input.readFloat(); + data.offsetShearY = input.readFloat(); + data.rotateMix = input.readFloat(); + data.translateMix = input.readFloat(); + data.scaleMix = input.readFloat(); + data.shearMix = input.readFloat(); + skeletonData.transformConstraints.push(data); + } + n = input.readInt(true); + for (var i = 0, nn = void 0; i < n; i++) { + var data = new spine.PathConstraintData(input.readString()); + data.order = input.readInt(true); + data.skinRequired = input.readBoolean(); + nn = input.readInt(true); + for (var ii = 0; ii < nn; ii++) + data.bones.push(skeletonData.bones[input.readInt(true)]); + data.target = skeletonData.slots[input.readInt(true)]; + data.positionMode = SkeletonBinary.PositionModeValues[input.readInt(true)]; + data.spacingMode = SkeletonBinary.SpacingModeValues[input.readInt(true)]; + data.rotateMode = SkeletonBinary.RotateModeValues[input.readInt(true)]; + data.offsetRotation = input.readFloat(); + data.position = input.readFloat(); + if (data.positionMode == spine.PositionMode.Fixed) + data.position *= scale; + data.spacing = input.readFloat(); + if (data.spacingMode == spine.SpacingMode.Length || data.spacingMode == spine.SpacingMode.Fixed) + data.spacing *= scale; + data.rotateMix = input.readFloat(); + data.translateMix = input.readFloat(); + skeletonData.pathConstraints.push(data); + } + var defaultSkin = this.readSkin(input, skeletonData, true, nonessential); + if (defaultSkin != null) { + skeletonData.defaultSkin = defaultSkin; + skeletonData.skins.push(defaultSkin); + } + { + var i = skeletonData.skins.length; + spine.Utils.setArraySize(skeletonData.skins, n = i + input.readInt(true)); + for (; i < n; i++) + skeletonData.skins[i] = this.readSkin(input, skeletonData, false, nonessential); + } + n = this.linkedMeshes.length; + for (var i = 0; i < n; i++) { + var linkedMesh = this.linkedMeshes[i]; + var skin = linkedMesh.skin == null ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin); + if (skin == null) + throw new Error("Skin not found: " + linkedMesh.skin); + var parent_3 = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); + if (parent_3 == null) + throw new Error("Parent mesh not found: " + linkedMesh.parent); + linkedMesh.mesh.deformAttachment = linkedMesh.inheritDeform ? parent_3 : linkedMesh.mesh; + linkedMesh.mesh.setParentMesh(parent_3); + linkedMesh.mesh.updateUVs(); + } + this.linkedMeshes.length = 0; + n = input.readInt(true); + for (var i = 0; i < n; i++) { + var data = new spine.EventData(input.readStringRef()); + data.intValue = input.readInt(false); + data.floatValue = input.readFloat(); + data.stringValue = input.readString(); + data.audioPath = input.readString(); + if (data.audioPath != null) { + data.volume = input.readFloat(); + data.balance = input.readFloat(); + } + skeletonData.events.push(data); + } + n = input.readInt(true); + for (var i = 0; i < n; i++) + skeletonData.animations.push(this.readAnimation(input, input.readString(), skeletonData)); + return skeletonData; + }; + SkeletonBinary.prototype.readSkin = function (input, skeletonData, defaultSkin, nonessential) { + var skin = null; + var slotCount = 0; + if (defaultSkin) { + slotCount = input.readInt(true); + if (slotCount == 0) + return null; + skin = new spine.Skin("default"); + } + else { + skin = new spine.Skin(input.readStringRef()); + skin.bones.length = input.readInt(true); + for (var i = 0, n = skin.bones.length; i < n; i++) + skin.bones[i] = skeletonData.bones[input.readInt(true)]; + for (var i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.push(skeletonData.ikConstraints[input.readInt(true)]); + for (var i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.push(skeletonData.transformConstraints[input.readInt(true)]); + for (var i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.push(skeletonData.pathConstraints[input.readInt(true)]); + slotCount = input.readInt(true); + } + for (var i = 0; i < slotCount; i++) { + var slotIndex = input.readInt(true); + for (var ii = 0, nn = input.readInt(true); ii < nn; ii++) { + var name_3 = input.readStringRef(); + var attachment = this.readAttachment(input, skeletonData, skin, slotIndex, name_3, nonessential); + if (attachment != null) + skin.setAttachment(slotIndex, name_3, attachment); + } + } + return skin; + }; + SkeletonBinary.prototype.readAttachment = function (input, skeletonData, skin, slotIndex, attachmentName, nonessential) { + var scale = this.scale; + var name = input.readStringRef(); + if (name == null) + name = attachmentName; + var typeIndex = input.readByte(); + var type = SkeletonBinary.AttachmentTypeValues[typeIndex]; + switch (type) { + case spine.AttachmentType.Region: { + var path = input.readStringRef(); + var rotation = input.readFloat(); + var x = input.readFloat(); + var y = input.readFloat(); + var scaleX = input.readFloat(); + var scaleY = input.readFloat(); + var width = input.readFloat(); + var height = input.readFloat(); + var color = input.readInt32(); + if (path == null) + path = name; + var region = this.attachmentLoader.newRegionAttachment(skin, name, path); + if (region == null) + return null; + region.path = path; + region.x = x * scale; + region.y = y * scale; + region.scaleX = scaleX; + region.scaleY = scaleY; + region.rotation = rotation; + region.width = width * scale; + region.height = height * scale; + spine.Color.rgba8888ToColor(region.color, color); + region.updateOffset(); + return region; + } + case spine.AttachmentType.BoundingBox: { + var vertexCount = input.readInt(true); + var vertices = this.readVertices(input, vertexCount); + var color = nonessential ? input.readInt32() : 0; + var box = this.attachmentLoader.newBoundingBoxAttachment(skin, name); + if (box == null) + return null; + box.worldVerticesLength = vertexCount << 1; + box.vertices = vertices.vertices; + box.bones = vertices.bones; + if (nonessential) + spine.Color.rgba8888ToColor(box.color, color); + return box; + } + case spine.AttachmentType.Mesh: { + var path = input.readStringRef(); + var color = input.readInt32(); + var vertexCount = input.readInt(true); + var uvs = this.readFloatArray(input, vertexCount << 1, 1); + var triangles = this.readShortArray(input); + var vertices = this.readVertices(input, vertexCount); + var hullLength = input.readInt(true); + var edges = null; + var width = 0, height = 0; + if (nonessential) { + edges = this.readShortArray(input); + width = input.readFloat(); + height = input.readFloat(); + } + if (path == null) + path = name; + var mesh = this.attachmentLoader.newMeshAttachment(skin, name, path); + if (mesh == null) + return null; + mesh.path = path; + spine.Color.rgba8888ToColor(mesh.color, color); + mesh.bones = vertices.bones; + mesh.vertices = vertices.vertices; + mesh.worldVerticesLength = vertexCount << 1; + mesh.triangles = triangles; + mesh.regionUVs = uvs; + mesh.updateUVs(); + mesh.hullLength = hullLength << 1; + if (nonessential) { + mesh.edges = edges; + mesh.width = width * scale; + mesh.height = height * scale; + } + return mesh; + } + case spine.AttachmentType.LinkedMesh: { + var path = input.readStringRef(); + var color = input.readInt32(); + var skinName = input.readStringRef(); + var parent_4 = input.readStringRef(); + var inheritDeform = input.readBoolean(); + var width = 0, height = 0; + if (nonessential) { + width = input.readFloat(); + height = input.readFloat(); + } + if (path == null) + path = name; + var mesh = this.attachmentLoader.newMeshAttachment(skin, name, path); + if (mesh == null) + return null; + mesh.path = path; + spine.Color.rgba8888ToColor(mesh.color, color); + if (nonessential) { + mesh.width = width * scale; + mesh.height = height * scale; + } + this.linkedMeshes.push(new LinkedMesh(mesh, skinName, slotIndex, parent_4, inheritDeform)); + return mesh; + } + case spine.AttachmentType.Path: { + var closed_1 = input.readBoolean(); + var constantSpeed = input.readBoolean(); + var vertexCount = input.readInt(true); + var vertices = this.readVertices(input, vertexCount); + var lengths = spine.Utils.newArray(vertexCount / 3, 0); + for (var i = 0, n = lengths.length; i < n; i++) + lengths[i] = input.readFloat() * scale; + var color = nonessential ? input.readInt32() : 0; + var path = this.attachmentLoader.newPathAttachment(skin, name); + if (path == null) + return null; + path.closed = closed_1; + path.constantSpeed = constantSpeed; + path.worldVerticesLength = vertexCount << 1; + path.vertices = vertices.vertices; + path.bones = vertices.bones; + path.lengths = lengths; + if (nonessential) + spine.Color.rgba8888ToColor(path.color, color); + return path; + } + case spine.AttachmentType.Point: { + var rotation = input.readFloat(); + var x = input.readFloat(); + var y = input.readFloat(); + var color = nonessential ? input.readInt32() : 0; + var point = this.attachmentLoader.newPointAttachment(skin, name); + if (point == null) + return null; + point.x = x * scale; + point.y = y * scale; + point.rotation = rotation; + if (nonessential) + spine.Color.rgba8888ToColor(point.color, color); + return point; + } + case spine.AttachmentType.Clipping: { + var endSlotIndex = input.readInt(true); + var vertexCount = input.readInt(true); + var vertices = this.readVertices(input, vertexCount); + var color = nonessential ? input.readInt32() : 0; + var clip = this.attachmentLoader.newClippingAttachment(skin, name); + if (clip == null) + return null; + clip.endSlot = skeletonData.slots[endSlotIndex]; + clip.worldVerticesLength = vertexCount << 1; + clip.vertices = vertices.vertices; + clip.bones = vertices.bones; + if (nonessential) + spine.Color.rgba8888ToColor(clip.color, color); + return clip; + } + } + return null; + }; + SkeletonBinary.prototype.readVertices = function (input, vertexCount) { + var verticesLength = vertexCount << 1; + var vertices = new Vertices(); + var scale = this.scale; + if (!input.readBoolean()) { + vertices.vertices = this.readFloatArray(input, verticesLength, scale); + return vertices; + } + var weights = new Array(); + var bonesArray = new Array(); + for (var i = 0; i < vertexCount; i++) { + var boneCount = input.readInt(true); + bonesArray.push(boneCount); + for (var ii = 0; ii < boneCount; ii++) { + bonesArray.push(input.readInt(true)); + weights.push(input.readFloat() * scale); + weights.push(input.readFloat() * scale); + weights.push(input.readFloat()); + } + } + vertices.vertices = spine.Utils.toFloatArray(weights); + vertices.bones = bonesArray; + return vertices; + }; + SkeletonBinary.prototype.readFloatArray = function (input, n, scale) { + var array = new Array(n); + if (scale == 1) { + for (var i = 0; i < n; i++) + array[i] = input.readFloat(); + } + else { + for (var i = 0; i < n; i++) + array[i] = input.readFloat() * scale; + } + return array; + }; + SkeletonBinary.prototype.readShortArray = function (input) { + var n = input.readInt(true); + var array = new Array(n); + for (var i = 0; i < n; i++) + array[i] = input.readShort(); + return array; + }; + SkeletonBinary.prototype.readAnimation = function (input, name, skeletonData) { + var timelines = new Array(); + var scale = this.scale; + var duration = 0; + var tempColor1 = new spine.Color(); + var tempColor2 = new spine.Color(); + for (var i = 0, n = input.readInt(true); i < n; i++) { + var slotIndex = input.readInt(true); + for (var ii = 0, nn = input.readInt(true); ii < nn; ii++) { + var timelineType = input.readByte(); + var frameCount = input.readInt(true); + switch (timelineType) { + case SkeletonBinary.SLOT_ATTACHMENT: { + var timeline = new spine.AttachmentTimeline(frameCount); + timeline.slotIndex = slotIndex; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) + timeline.setFrame(frameIndex, input.readFloat(), input.readStringRef()); + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[frameCount - 1]); + break; + } + case SkeletonBinary.SLOT_COLOR: { + var timeline = new spine.ColorTimeline(frameCount); + timeline.slotIndex = slotIndex; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + var time = input.readFloat(); + spine.Color.rgba8888ToColor(tempColor1, input.readInt32()); + timeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.ColorTimeline.ENTRIES]); + break; + } + case SkeletonBinary.SLOT_TWO_COLOR: { + var timeline = new spine.TwoColorTimeline(frameCount); + timeline.slotIndex = slotIndex; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + var time = input.readFloat(); + spine.Color.rgba8888ToColor(tempColor1, input.readInt32()); + spine.Color.rgb888ToColor(tempColor2, input.readInt32()); + timeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a, tempColor2.r, tempColor2.g, tempColor2.b); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.TwoColorTimeline.ENTRIES]); + break; + } + } + } + } + for (var i = 0, n = input.readInt(true); i < n; i++) { + var boneIndex = input.readInt(true); + for (var ii = 0, nn = input.readInt(true); ii < nn; ii++) { + var timelineType = input.readByte(); + var frameCount = input.readInt(true); + switch (timelineType) { + case SkeletonBinary.BONE_ROTATE: { + var timeline = new spine.RotateTimeline(frameCount); + timeline.boneIndex = boneIndex; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat()); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.RotateTimeline.ENTRIES]); + break; + } + case SkeletonBinary.BONE_TRANSLATE: + case SkeletonBinary.BONE_SCALE: + case SkeletonBinary.BONE_SHEAR: { + var timeline = void 0; + var timelineScale = 1; + if (timelineType == SkeletonBinary.BONE_SCALE) + timeline = new spine.ScaleTimeline(frameCount); + else if (timelineType == SkeletonBinary.BONE_SHEAR) + timeline = new spine.ShearTimeline(frameCount); + else { + timeline = new spine.TranslateTimeline(frameCount); + timelineScale = scale; + } + timeline.boneIndex = boneIndex; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale, input.readFloat() * timelineScale); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.TranslateTimeline.ENTRIES]); + break; + } + } + } + } + for (var i = 0, n = input.readInt(true); i < n; i++) { + var index = input.readInt(true); + var frameCount = input.readInt(true); + var timeline = new spine.IkConstraintTimeline(frameCount); + timeline.ikConstraintIndex = index; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat() * scale, input.readByte(), input.readBoolean(), input.readBoolean()); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.IkConstraintTimeline.ENTRIES]); + } + for (var i = 0, n = input.readInt(true); i < n; i++) { + var index = input.readInt(true); + var frameCount = input.readInt(true); + var timeline = new spine.TransformConstraintTimeline(frameCount); + timeline.transformConstraintIndex = index; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat()); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.TransformConstraintTimeline.ENTRIES]); + } + for (var i = 0, n = input.readInt(true); i < n; i++) { + var index = input.readInt(true); + var data = skeletonData.pathConstraints[index]; + for (var ii = 0, nn = input.readInt(true); ii < nn; ii++) { + var timelineType = input.readByte(); + var frameCount = input.readInt(true); + switch (timelineType) { + case SkeletonBinary.PATH_POSITION: + case SkeletonBinary.PATH_SPACING: { + var timeline = void 0; + var timelineScale = 1; + if (timelineType == SkeletonBinary.PATH_SPACING) { + timeline = new spine.PathConstraintSpacingTimeline(frameCount); + if (data.spacingMode == spine.SpacingMode.Length || data.spacingMode == spine.SpacingMode.Fixed) + timelineScale = scale; + } + else { + timeline = new spine.PathConstraintPositionTimeline(frameCount); + if (data.positionMode == spine.PositionMode.Fixed) + timelineScale = scale; + } + timeline.pathConstraintIndex = index; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.PathConstraintPositionTimeline.ENTRIES]); + break; + } + case SkeletonBinary.PATH_MIX: { + var timeline = new spine.PathConstraintMixTimeline(frameCount); + timeline.pathConstraintIndex = index; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + timeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat()); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(frameCount - 1) * spine.PathConstraintMixTimeline.ENTRIES]); + break; + } + } + } + } + for (var i = 0, n = input.readInt(true); i < n; i++) { + var skin = skeletonData.skins[input.readInt(true)]; + for (var ii = 0, nn = input.readInt(true); ii < nn; ii++) { + var slotIndex = input.readInt(true); + for (var iii = 0, nnn = input.readInt(true); iii < nnn; iii++) { + var attachment = skin.getAttachment(slotIndex, input.readStringRef()); + var weighted = attachment.bones != null; + var vertices = attachment.vertices; + var deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + var frameCount = input.readInt(true); + var timeline = new spine.DeformTimeline(frameCount); + timeline.slotIndex = slotIndex; + timeline.attachment = attachment; + for (var frameIndex = 0; frameIndex < frameCount; frameIndex++) { + var time = input.readFloat(); + var deform = void 0; + var end = input.readInt(true); + if (end == 0) + deform = weighted ? spine.Utils.newFloatArray(deformLength) : vertices; + else { + deform = spine.Utils.newFloatArray(deformLength); + var start = input.readInt(true); + end += start; + if (scale == 1) { + for (var v = start; v < end; v++) + deform[v] = input.readFloat(); + } + else { + for (var v = start; v < end; v++) + deform[v] = input.readFloat() * scale; + } + if (!weighted) { + for (var v = 0, vn = deform.length; v < vn; v++) + deform[v] += vertices[v]; + } + } + timeline.setFrame(frameIndex, time, deform); + if (frameIndex < frameCount - 1) + this.readCurve(input, frameIndex, timeline); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[frameCount - 1]); + } + } + } + var drawOrderCount = input.readInt(true); + if (drawOrderCount > 0) { + var timeline = new spine.DrawOrderTimeline(drawOrderCount); + var slotCount = skeletonData.slots.length; + for (var i = 0; i < drawOrderCount; i++) { + var time = input.readFloat(); + var offsetCount = input.readInt(true); + var drawOrder = spine.Utils.newArray(slotCount, 0); + for (var ii = slotCount - 1; ii >= 0; ii--) + drawOrder[ii] = -1; + var unchanged = spine.Utils.newArray(slotCount - offsetCount, 0); + var originalIndex = 0, unchangedIndex = 0; + for (var ii = 0; ii < offsetCount; ii++) { + var slotIndex = input.readInt(true); + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + drawOrder[originalIndex + input.readInt(true)] = originalIndex++; + } + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + for (var ii = slotCount - 1; ii >= 0; ii--) + if (drawOrder[ii] == -1) + drawOrder[ii] = unchanged[--unchangedIndex]; + timeline.setFrame(i, time, drawOrder); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[drawOrderCount - 1]); + } + var eventCount = input.readInt(true); + if (eventCount > 0) { + var timeline = new spine.EventTimeline(eventCount); + for (var i = 0; i < eventCount; i++) { + var time = input.readFloat(); + var eventData = skeletonData.events[input.readInt(true)]; + var event_4 = new spine.Event(time, eventData); + event_4.intValue = input.readInt(false); + event_4.floatValue = input.readFloat(); + event_4.stringValue = input.readBoolean() ? input.readString() : eventData.stringValue; + if (event_4.data.audioPath != null) { + event_4.volume = input.readFloat(); + event_4.balance = input.readFloat(); + } + timeline.setFrame(i, event_4); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[eventCount - 1]); + } + return new spine.Animation(name, timelines, duration); + }; + SkeletonBinary.prototype.readCurve = function (input, frameIndex, timeline) { + switch (input.readByte()) { + case SkeletonBinary.CURVE_STEPPED: + timeline.setStepped(frameIndex); + break; + case SkeletonBinary.CURVE_BEZIER: + this.setCurve(timeline, frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat()); + break; + } + }; + SkeletonBinary.prototype.setCurve = function (timeline, frameIndex, cx1, cy1, cx2, cy2) { + timeline.setCurve(frameIndex, cx1, cy1, cx2, cy2); + }; + SkeletonBinary.AttachmentTypeValues = [0, 1, 2, 3, 4, 5, 6]; + SkeletonBinary.TransformModeValues = [spine.TransformMode.Normal, spine.TransformMode.OnlyTranslation, spine.TransformMode.NoRotationOrReflection, spine.TransformMode.NoScale, spine.TransformMode.NoScaleOrReflection]; + SkeletonBinary.PositionModeValues = [spine.PositionMode.Fixed, spine.PositionMode.Percent]; + SkeletonBinary.SpacingModeValues = [spine.SpacingMode.Length, spine.SpacingMode.Fixed, spine.SpacingMode.Percent]; + SkeletonBinary.RotateModeValues = [spine.RotateMode.Tangent, spine.RotateMode.Chain, spine.RotateMode.ChainScale]; + SkeletonBinary.BlendModeValues = [spine.BlendMode.Normal, spine.BlendMode.Additive, spine.BlendMode.Multiply, spine.BlendMode.Screen]; + SkeletonBinary.BONE_ROTATE = 0; + SkeletonBinary.BONE_TRANSLATE = 1; + SkeletonBinary.BONE_SCALE = 2; + SkeletonBinary.BONE_SHEAR = 3; + SkeletonBinary.SLOT_ATTACHMENT = 0; + SkeletonBinary.SLOT_COLOR = 1; + SkeletonBinary.SLOT_TWO_COLOR = 2; + SkeletonBinary.PATH_POSITION = 0; + SkeletonBinary.PATH_SPACING = 1; + SkeletonBinary.PATH_MIX = 2; + SkeletonBinary.CURVE_LINEAR = 0; + SkeletonBinary.CURVE_STEPPED = 1; + SkeletonBinary.CURVE_BEZIER = 2; + return SkeletonBinary; + }()); + spine.SkeletonBinary = SkeletonBinary; + var BinaryInput = (function () { + function BinaryInput(data, strings, index, buffer) { + if (strings === void 0) { strings = new Array(); } + if (index === void 0) { index = 0; } + if (buffer === void 0) { buffer = new DataView(data.buffer); } + this.strings = strings; + this.index = index; + this.buffer = buffer; + } + BinaryInput.prototype.readByte = function () { + return this.buffer.getInt8(this.index++); + }; + BinaryInput.prototype.readShort = function () { + var value = this.buffer.getInt16(this.index); + this.index += 2; + return value; + }; + BinaryInput.prototype.readInt32 = function () { + var value = this.buffer.getInt32(this.index); + this.index += 4; + return value; + }; + BinaryInput.prototype.readInt = function (optimizePositive) { + var b = this.readByte(); + var result = b & 0x7F; + if ((b & 0x80) != 0) { + b = this.readByte(); + result |= (b & 0x7F) << 7; + if ((b & 0x80) != 0) { + b = this.readByte(); + result |= (b & 0x7F) << 14; + if ((b & 0x80) != 0) { + b = this.readByte(); + result |= (b & 0x7F) << 21; + if ((b & 0x80) != 0) { + b = this.readByte(); + result |= (b & 0x7F) << 28; + } + } + } + } + return optimizePositive ? result : ((result >>> 1) ^ -(result & 1)); + }; + BinaryInput.prototype.readStringRef = function () { + var index = this.readInt(true); + return index == 0 ? null : this.strings[index - 1]; + }; + BinaryInput.prototype.readString = function () { + var byteCount = this.readInt(true); + switch (byteCount) { + case 0: + return null; + case 1: + return ""; + } + byteCount--; + var chars = ""; + var charCount = 0; + for (var i = 0; i < byteCount;) { + var b = this.readByte(); + switch (b >> 4) { + case 12: + case 13: + chars += String.fromCharCode(((b & 0x1F) << 6 | this.readByte() & 0x3F)); + i += 2; + break; + case 14: + chars += String.fromCharCode(((b & 0x0F) << 12 | (this.readByte() & 0x3F) << 6 | this.readByte() & 0x3F)); + i += 3; + break; + default: + chars += String.fromCharCode(b); + i++; + } + } + return chars; + }; + BinaryInput.prototype.readFloat = function () { + var value = this.buffer.getFloat32(this.index); + this.index += 4; + return value; + }; + BinaryInput.prototype.readBoolean = function () { + return this.readByte() != 0; + }; + return BinaryInput; + }()); + var LinkedMesh = (function () { + function LinkedMesh(mesh, skin, slotIndex, parent, inheritDeform) { + this.mesh = mesh; + this.skin = skin; + this.slotIndex = slotIndex; + this.parent = parent; + this.inheritDeform = inheritDeform; + } + return LinkedMesh; + }()); + var Vertices = (function () { + function Vertices(bones, vertices) { + if (bones === void 0) { bones = null; } + if (vertices === void 0) { vertices = null; } + this.bones = bones; + this.vertices = vertices; + } + return Vertices; + }()); +})(spine || (spine = {})); +var spine; +(function (spine) { + var SkeletonBounds = (function () { + function SkeletonBounds() { + this.minX = 0; + this.minY = 0; + this.maxX = 0; + this.maxY = 0; + this.boundingBoxes = new Array(); + this.polygons = new Array(); + this.polygonPool = new spine.Pool(function () { + return spine.Utils.newFloatArray(16); + }); + } + SkeletonBounds.prototype.update = function (skeleton, updateAabb) { + if (skeleton == null) + throw new Error("skeleton cannot be null."); + var boundingBoxes = this.boundingBoxes; + var polygons = this.polygons; + var polygonPool = this.polygonPool; + var slots = skeleton.slots; + var slotCount = slots.length; + boundingBoxes.length = 0; + polygonPool.freeAll(polygons); + polygons.length = 0; + for (var i = 0; i < slotCount; i++) { + var slot = slots[i]; + if (!slot.bone.active) + continue; + var attachment = slot.getAttachment(); + if (attachment instanceof spine.BoundingBoxAttachment) { + var boundingBox = attachment; + boundingBoxes.push(boundingBox); + var polygon = polygonPool.obtain(); + if (polygon.length != boundingBox.worldVerticesLength) { + polygon = spine.Utils.newFloatArray(boundingBox.worldVerticesLength); + } + polygons.push(polygon); + boundingBox.computeWorldVertices(slot, 0, boundingBox.worldVerticesLength, polygon, 0, 2); + } + } + if (updateAabb) { + this.aabbCompute(); + } + else { + this.minX = Number.POSITIVE_INFINITY; + this.minY = Number.POSITIVE_INFINITY; + this.maxX = Number.NEGATIVE_INFINITY; + this.maxY = Number.NEGATIVE_INFINITY; + } + }; + SkeletonBounds.prototype.aabbCompute = function () { + var minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + var polygons = this.polygons; + for (var i = 0, n = polygons.length; i < n; i++) { + var polygon = polygons[i]; + var vertices = polygon; + for (var ii = 0, nn = polygon.length; ii < nn; ii += 2) { + var x = vertices[ii]; + var y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + }; + SkeletonBounds.prototype.aabbContainsPoint = function (x, y) { + return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY; + }; + SkeletonBounds.prototype.aabbIntersectsSegment = function (x1, y1, x2, y2) { + var minX = this.minX; + var minY = this.minY; + var maxX = this.maxX; + var maxY = this.maxY; + if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY)) + return false; + var m = (y2 - y1) / (x2 - x1); + var y = m * (minX - x1) + y1; + if (y > minY && y < maxY) + return true; + y = m * (maxX - x1) + y1; + if (y > minY && y < maxY) + return true; + var x = (minY - y1) / m + x1; + if (x > minX && x < maxX) + return true; + x = (maxY - y1) / m + x1; + if (x > minX && x < maxX) + return true; + return false; + }; + SkeletonBounds.prototype.aabbIntersectsSkeleton = function (bounds) { + return this.minX < bounds.maxX && this.maxX > bounds.minX && this.minY < bounds.maxY && this.maxY > bounds.minY; + }; + SkeletonBounds.prototype.containsPoint = function (x, y) { + var polygons = this.polygons; + for (var i = 0, n = polygons.length; i < n; i++) + if (this.containsPointPolygon(polygons[i], x, y)) + return this.boundingBoxes[i]; + return null; + }; + SkeletonBounds.prototype.containsPointPolygon = function (polygon, x, y) { + var vertices = polygon; + var nn = polygon.length; + var prevIndex = nn - 2; + var inside = false; + for (var ii = 0; ii < nn; ii += 2) { + var vertexY = vertices[ii + 1]; + var prevY = vertices[prevIndex + 1]; + if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) { + var vertexX = vertices[ii]; + if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) + inside = !inside; + } + prevIndex = ii; + } + return inside; + }; + SkeletonBounds.prototype.intersectsSegment = function (x1, y1, x2, y2) { + var polygons = this.polygons; + for (var i = 0, n = polygons.length; i < n; i++) + if (this.intersectsSegmentPolygon(polygons[i], x1, y1, x2, y2)) + return this.boundingBoxes[i]; + return null; + }; + SkeletonBounds.prototype.intersectsSegmentPolygon = function (polygon, x1, y1, x2, y2) { + var vertices = polygon; + var nn = polygon.length; + var width12 = x1 - x2, height12 = y1 - y2; + var det1 = x1 * y2 - y1 * x2; + var x3 = vertices[nn - 2], y3 = vertices[nn - 1]; + for (var ii = 0; ii < nn; ii += 2) { + var x4 = vertices[ii], y4 = vertices[ii + 1]; + var det2 = x3 * y4 - y3 * x4; + var width34 = x3 - x4, height34 = y3 - y4; + var det3 = width12 * height34 - height12 * width34; + var x = (det1 * width34 - width12 * det2) / det3; + if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) { + var y = (det1 * height34 - height12 * det2) / det3; + if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) + return true; + } + x3 = x4; + y3 = y4; + } + return false; + }; + SkeletonBounds.prototype.getPolygon = function (boundingBox) { + if (boundingBox == null) + throw new Error("boundingBox cannot be null."); + var index = this.boundingBoxes.indexOf(boundingBox); + return index == -1 ? null : this.polygons[index]; + }; + SkeletonBounds.prototype.getWidth = function () { + return this.maxX - this.minX; + }; + SkeletonBounds.prototype.getHeight = function () { + return this.maxY - this.minY; + }; + return SkeletonBounds; + }()); + spine.SkeletonBounds = SkeletonBounds; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SkeletonClipping = (function () { + function SkeletonClipping() { + this.triangulator = new spine.Triangulator(); + this.clippingPolygon = new Array(); + this.clipOutput = new Array(); + this.clippedVertices = new Array(); + this.clippedTriangles = new Array(); + this.scratch = new Array(); + } + SkeletonClipping.prototype.clipStart = function (slot, clip) { + if (this.clipAttachment != null) + return 0; + this.clipAttachment = clip; + var n = clip.worldVerticesLength; + var vertices = spine.Utils.setArraySize(this.clippingPolygon, n); + clip.computeWorldVertices(slot, 0, n, vertices, 0, 2); + var clippingPolygon = this.clippingPolygon; + SkeletonClipping.makeClockwise(clippingPolygon); + var clippingPolygons = this.clippingPolygons = this.triangulator.decompose(clippingPolygon, this.triangulator.triangulate(clippingPolygon)); + for (var i = 0, n_2 = clippingPolygons.length; i < n_2; i++) { + var polygon = clippingPolygons[i]; + SkeletonClipping.makeClockwise(polygon); + polygon.push(polygon[0]); + polygon.push(polygon[1]); + } + return clippingPolygons.length; + }; + SkeletonClipping.prototype.clipEndWithSlot = function (slot) { + if (this.clipAttachment != null && this.clipAttachment.endSlot == slot.data) + this.clipEnd(); + }; + SkeletonClipping.prototype.clipEnd = function () { + if (this.clipAttachment == null) + return; + this.clipAttachment = null; + this.clippingPolygons = null; + this.clippedVertices.length = 0; + this.clippedTriangles.length = 0; + this.clippingPolygon.length = 0; + }; + SkeletonClipping.prototype.isClipping = function () { + return this.clipAttachment != null; + }; + SkeletonClipping.prototype.clipTriangles = function (vertices, verticesLength, triangles, trianglesLength, uvs, light, dark, twoColor) { + var clipOutput = this.clipOutput, clippedVertices = this.clippedVertices; + var clippedTriangles = this.clippedTriangles; + var polygons = this.clippingPolygons; + var polygonsCount = this.clippingPolygons.length; + var vertexSize = twoColor ? 12 : 8; + var index = 0; + clippedVertices.length = 0; + clippedTriangles.length = 0; + outer: for (var i = 0; i < trianglesLength; i += 3) { + var vertexOffset = triangles[i] << 1; + var x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1]; + var u1 = uvs[vertexOffset], v1 = uvs[vertexOffset + 1]; + vertexOffset = triangles[i + 1] << 1; + var x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1]; + var u2 = uvs[vertexOffset], v2 = uvs[vertexOffset + 1]; + vertexOffset = triangles[i + 2] << 1; + var x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1]; + var u3 = uvs[vertexOffset], v3 = uvs[vertexOffset + 1]; + for (var p = 0; p < polygonsCount; p++) { + var s = clippedVertices.length; + if (this.clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) { + var clipOutputLength = clipOutput.length; + if (clipOutputLength == 0) + continue; + var d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1; + var d = 1 / (d0 * d2 + d1 * (y1 - y3)); + var clipOutputCount = clipOutputLength >> 1; + var clipOutputItems = this.clipOutput; + var clippedVerticesItems = spine.Utils.setArraySize(clippedVertices, s + clipOutputCount * vertexSize); + for (var ii = 0; ii < clipOutputLength; ii += 2) { + var x = clipOutputItems[ii], y = clipOutputItems[ii + 1]; + clippedVerticesItems[s] = x; + clippedVerticesItems[s + 1] = y; + clippedVerticesItems[s + 2] = light.r; + clippedVerticesItems[s + 3] = light.g; + clippedVerticesItems[s + 4] = light.b; + clippedVerticesItems[s + 5] = light.a; + var c0 = x - x3, c1 = y - y3; + var a = (d0 * c0 + d1 * c1) * d; + var b = (d4 * c0 + d2 * c1) * d; + var c = 1 - a - b; + clippedVerticesItems[s + 6] = u1 * a + u2 * b + u3 * c; + clippedVerticesItems[s + 7] = v1 * a + v2 * b + v3 * c; + if (twoColor) { + clippedVerticesItems[s + 8] = dark.r; + clippedVerticesItems[s + 9] = dark.g; + clippedVerticesItems[s + 10] = dark.b; + clippedVerticesItems[s + 11] = dark.a; + } + s += vertexSize; + } + s = clippedTriangles.length; + var clippedTrianglesItems = spine.Utils.setArraySize(clippedTriangles, s + 3 * (clipOutputCount - 2)); + clipOutputCount--; + for (var ii = 1; ii < clipOutputCount; ii++) { + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = (index + ii); + clippedTrianglesItems[s + 2] = (index + ii + 1); + s += 3; + } + index += clipOutputCount + 1; + } + else { + var clippedVerticesItems = spine.Utils.setArraySize(clippedVertices, s + 3 * vertexSize); + clippedVerticesItems[s] = x1; + clippedVerticesItems[s + 1] = y1; + clippedVerticesItems[s + 2] = light.r; + clippedVerticesItems[s + 3] = light.g; + clippedVerticesItems[s + 4] = light.b; + clippedVerticesItems[s + 5] = light.a; + if (!twoColor) { + clippedVerticesItems[s + 6] = u1; + clippedVerticesItems[s + 7] = v1; + clippedVerticesItems[s + 8] = x2; + clippedVerticesItems[s + 9] = y2; + clippedVerticesItems[s + 10] = light.r; + clippedVerticesItems[s + 11] = light.g; + clippedVerticesItems[s + 12] = light.b; + clippedVerticesItems[s + 13] = light.a; + clippedVerticesItems[s + 14] = u2; + clippedVerticesItems[s + 15] = v2; + clippedVerticesItems[s + 16] = x3; + clippedVerticesItems[s + 17] = y3; + clippedVerticesItems[s + 18] = light.r; + clippedVerticesItems[s + 19] = light.g; + clippedVerticesItems[s + 20] = light.b; + clippedVerticesItems[s + 21] = light.a; + clippedVerticesItems[s + 22] = u3; + clippedVerticesItems[s + 23] = v3; + } + else { + clippedVerticesItems[s + 6] = u1; + clippedVerticesItems[s + 7] = v1; + clippedVerticesItems[s + 8] = dark.r; + clippedVerticesItems[s + 9] = dark.g; + clippedVerticesItems[s + 10] = dark.b; + clippedVerticesItems[s + 11] = dark.a; + clippedVerticesItems[s + 12] = x2; + clippedVerticesItems[s + 13] = y2; + clippedVerticesItems[s + 14] = light.r; + clippedVerticesItems[s + 15] = light.g; + clippedVerticesItems[s + 16] = light.b; + clippedVerticesItems[s + 17] = light.a; + clippedVerticesItems[s + 18] = u2; + clippedVerticesItems[s + 19] = v2; + clippedVerticesItems[s + 20] = dark.r; + clippedVerticesItems[s + 21] = dark.g; + clippedVerticesItems[s + 22] = dark.b; + clippedVerticesItems[s + 23] = dark.a; + clippedVerticesItems[s + 24] = x3; + clippedVerticesItems[s + 25] = y3; + clippedVerticesItems[s + 26] = light.r; + clippedVerticesItems[s + 27] = light.g; + clippedVerticesItems[s + 28] = light.b; + clippedVerticesItems[s + 29] = light.a; + clippedVerticesItems[s + 30] = u3; + clippedVerticesItems[s + 31] = v3; + clippedVerticesItems[s + 32] = dark.r; + clippedVerticesItems[s + 33] = dark.g; + clippedVerticesItems[s + 34] = dark.b; + clippedVerticesItems[s + 35] = dark.a; + } + s = clippedTriangles.length; + var clippedTrianglesItems = spine.Utils.setArraySize(clippedTriangles, s + 3); + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = (index + 1); + clippedTrianglesItems[s + 2] = (index + 2); + index += 3; + continue outer; + } + } + } + }; + SkeletonClipping.prototype.clip = function (x1, y1, x2, y2, x3, y3, clippingArea, output) { + var originalOutput = output; + var clipped = false; + var input = null; + if (clippingArea.length % 4 >= 2) { + input = output; + output = this.scratch; + } + else + input = this.scratch; + input.length = 0; + input.push(x1); + input.push(y1); + input.push(x2); + input.push(y2); + input.push(x3); + input.push(y3); + input.push(x1); + input.push(y1); + output.length = 0; + var clippingVertices = clippingArea; + var clippingVerticesLast = clippingArea.length - 4; + for (var i = 0;; i += 2) { + var edgeX = clippingVertices[i], edgeY = clippingVertices[i + 1]; + var edgeX2 = clippingVertices[i + 2], edgeY2 = clippingVertices[i + 3]; + var deltaX = edgeX - edgeX2, deltaY = edgeY - edgeY2; + var inputVertices = input; + var inputVerticesLength = input.length - 2, outputStart = output.length; + for (var ii = 0; ii < inputVerticesLength; ii += 2) { + var inputX = inputVertices[ii], inputY = inputVertices[ii + 1]; + var inputX2 = inputVertices[ii + 2], inputY2 = inputVertices[ii + 3]; + var side2 = deltaX * (inputY2 - edgeY2) - deltaY * (inputX2 - edgeX2) > 0; + if (deltaX * (inputY - edgeY2) - deltaY * (inputX - edgeX2) > 0) { + if (side2) { + output.push(inputX2); + output.push(inputY2); + continue; + } + var c0 = inputY2 - inputY, c2 = inputX2 - inputX; + var s = c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY); + if (Math.abs(s) > 0.000001) { + var ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / s; + output.push(edgeX + (edgeX2 - edgeX) * ua); + output.push(edgeY + (edgeY2 - edgeY) * ua); + } + else { + output.push(edgeX); + output.push(edgeY); + } + } + else if (side2) { + var c0 = inputY2 - inputY, c2 = inputX2 - inputX; + var s = c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY); + if (Math.abs(s) > 0.000001) { + var ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / s; + output.push(edgeX + (edgeX2 - edgeX) * ua); + output.push(edgeY + (edgeY2 - edgeY) * ua); + } + else { + output.push(edgeX); + output.push(edgeY); + } + output.push(inputX2); + output.push(inputY2); + } + clipped = true; + } + if (outputStart == output.length) { + originalOutput.length = 0; + return true; + } + output.push(output[0]); + output.push(output[1]); + if (i == clippingVerticesLast) + break; + var temp = output; + output = input; + output.length = 0; + input = temp; + } + if (originalOutput != output) { + originalOutput.length = 0; + for (var i = 0, n = output.length - 2; i < n; i++) + originalOutput[i] = output[i]; + } + else + originalOutput.length = originalOutput.length - 2; + return clipped; + }; + SkeletonClipping.makeClockwise = function (polygon) { + var vertices = polygon; + var verticeslength = polygon.length; + var area = vertices[verticeslength - 2] * vertices[1] - vertices[0] * vertices[verticeslength - 1], p1x = 0, p1y = 0, p2x = 0, p2y = 0; + for (var i = 0, n = verticeslength - 3; i < n; i += 2) { + p1x = vertices[i]; + p1y = vertices[i + 1]; + p2x = vertices[i + 2]; + p2y = vertices[i + 3]; + area += p1x * p2y - p2x * p1y; + } + if (area < 0) + return; + for (var i = 0, lastX = verticeslength - 2, n = verticeslength >> 1; i < n; i += 2) { + var x = vertices[i], y = vertices[i + 1]; + var other = lastX - i; + vertices[i] = vertices[other]; + vertices[i + 1] = vertices[other + 1]; + vertices[other] = x; + vertices[other + 1] = y; + } + }; + return SkeletonClipping; + }()); + spine.SkeletonClipping = SkeletonClipping; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SkeletonData = (function () { + function SkeletonData() { + this.bones = new Array(); + this.slots = new Array(); + this.skins = new Array(); + this.events = new Array(); + this.animations = new Array(); + this.ikConstraints = new Array(); + this.transformConstraints = new Array(); + this.pathConstraints = new Array(); + this.fps = 0; + } + SkeletonData.prototype.findBone = function (boneName) { + if (boneName == null) + throw new Error("boneName cannot be null."); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + if (bone.name == boneName) + return bone; + } + return null; + }; + SkeletonData.prototype.findBoneIndex = function (boneName) { + if (boneName == null) + throw new Error("boneName cannot be null."); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) + if (bones[i].name == boneName) + return i; + return -1; + }; + SkeletonData.prototype.findSlot = function (slotName) { + if (slotName == null) + throw new Error("slotName cannot be null."); + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) { + var slot = slots[i]; + if (slot.name == slotName) + return slot; + } + return null; + }; + SkeletonData.prototype.findSlotIndex = function (slotName) { + if (slotName == null) + throw new Error("slotName cannot be null."); + var slots = this.slots; + for (var i = 0, n = slots.length; i < n; i++) + if (slots[i].name == slotName) + return i; + return -1; + }; + SkeletonData.prototype.findSkin = function (skinName) { + if (skinName == null) + throw new Error("skinName cannot be null."); + var skins = this.skins; + for (var i = 0, n = skins.length; i < n; i++) { + var skin = skins[i]; + if (skin.name == skinName) + return skin; + } + return null; + }; + SkeletonData.prototype.findEvent = function (eventDataName) { + if (eventDataName == null) + throw new Error("eventDataName cannot be null."); + var events = this.events; + for (var i = 0, n = events.length; i < n; i++) { + var event_5 = events[i]; + if (event_5.name == eventDataName) + return event_5; + } + return null; + }; + SkeletonData.prototype.findAnimation = function (animationName) { + if (animationName == null) + throw new Error("animationName cannot be null."); + var animations = this.animations; + for (var i = 0, n = animations.length; i < n; i++) { + var animation = animations[i]; + if (animation.name == animationName) + return animation; + } + return null; + }; + SkeletonData.prototype.findIkConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var ikConstraints = this.ikConstraints; + for (var i = 0, n = ikConstraints.length; i < n; i++) { + var constraint = ikConstraints[i]; + if (constraint.name == constraintName) + return constraint; + } + return null; + }; + SkeletonData.prototype.findTransformConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var transformConstraints = this.transformConstraints; + for (var i = 0, n = transformConstraints.length; i < n; i++) { + var constraint = transformConstraints[i]; + if (constraint.name == constraintName) + return constraint; + } + return null; + }; + SkeletonData.prototype.findPathConstraint = function (constraintName) { + if (constraintName == null) + throw new Error("constraintName cannot be null."); + var pathConstraints = this.pathConstraints; + for (var i = 0, n = pathConstraints.length; i < n; i++) { + var constraint = pathConstraints[i]; + if (constraint.name == constraintName) + return constraint; + } + return null; + }; + SkeletonData.prototype.findPathConstraintIndex = function (pathConstraintName) { + if (pathConstraintName == null) + throw new Error("pathConstraintName cannot be null."); + var pathConstraints = this.pathConstraints; + for (var i = 0, n = pathConstraints.length; i < n; i++) + if (pathConstraints[i].name == pathConstraintName) + return i; + return -1; + }; + return SkeletonData; + }()); + spine.SkeletonData = SkeletonData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SkeletonJson = (function () { + function SkeletonJson(attachmentLoader) { + this.scale = 1; + this.linkedMeshes = new Array(); + this.attachmentLoader = attachmentLoader; + } + SkeletonJson.prototype.readSkeletonData = function (json) { + var scale = this.scale; + var skeletonData = new spine.SkeletonData(); + var root = typeof (json) === "string" ? JSON.parse(json) : json; + var skeletonMap = root.skeleton; + if (skeletonMap != null) { + skeletonData.hash = skeletonMap.hash; + skeletonData.version = skeletonMap.spine; + if ("3.8.75" == skeletonData.version) + throw new Error("Unsupported skeleton data, please export with a newer version of Spine."); + skeletonData.x = skeletonMap.x; + skeletonData.y = skeletonMap.y; + skeletonData.width = skeletonMap.width; + skeletonData.height = skeletonMap.height; + skeletonData.fps = skeletonMap.fps; + skeletonData.imagesPath = skeletonMap.images; + } + if (root.bones) { + for (var i = 0; i < root.bones.length; i++) { + var boneMap = root.bones[i]; + var parent_5 = null; + var parentName = this.getValue(boneMap, "parent", null); + if (parentName != null) { + parent_5 = skeletonData.findBone(parentName); + if (parent_5 == null) + throw new Error("Parent bone not found: " + parentName); + } + var data = new spine.BoneData(skeletonData.bones.length, boneMap.name, parent_5); + data.length = this.getValue(boneMap, "length", 0) * scale; + data.x = this.getValue(boneMap, "x", 0) * scale; + data.y = this.getValue(boneMap, "y", 0) * scale; + data.rotation = this.getValue(boneMap, "rotation", 0); + data.scaleX = this.getValue(boneMap, "scaleX", 1); + data.scaleY = this.getValue(boneMap, "scaleY", 1); + data.shearX = this.getValue(boneMap, "shearX", 0); + data.shearY = this.getValue(boneMap, "shearY", 0); + data.transformMode = SkeletonJson.transformModeFromString(this.getValue(boneMap, "transform", "normal")); + data.skinRequired = this.getValue(boneMap, "skin", false); + skeletonData.bones.push(data); + } + } + if (root.slots) { + for (var i = 0; i < root.slots.length; i++) { + var slotMap = root.slots[i]; + var slotName = slotMap.name; + var boneName = slotMap.bone; + var boneData = skeletonData.findBone(boneName); + if (boneData == null) + throw new Error("Slot bone not found: " + boneName); + var data = new spine.SlotData(skeletonData.slots.length, slotName, boneData); + var color = this.getValue(slotMap, "color", null); + if (color != null) + data.color.setFromString(color); + var dark = this.getValue(slotMap, "dark", null); + if (dark != null) { + data.darkColor = new spine.Color(1, 1, 1, 1); + data.darkColor.setFromString(dark); + } + data.attachmentName = this.getValue(slotMap, "attachment", null); + data.blendMode = SkeletonJson.blendModeFromString(this.getValue(slotMap, "blend", "normal")); + skeletonData.slots.push(data); + } + } + if (root.ik) { + for (var i = 0; i < root.ik.length; i++) { + var constraintMap = root.ik[i]; + var data = new spine.IkConstraintData(constraintMap.name); + data.order = this.getValue(constraintMap, "order", 0); + data.skinRequired = this.getValue(constraintMap, "skin", false); + for (var j = 0; j < constraintMap.bones.length; j++) { + var boneName = constraintMap.bones[j]; + var bone = skeletonData.findBone(boneName); + if (bone == null) + throw new Error("IK bone not found: " + boneName); + data.bones.push(bone); + } + var targetName = constraintMap.target; + data.target = skeletonData.findBone(targetName); + if (data.target == null) + throw new Error("IK target bone not found: " + targetName); + data.mix = this.getValue(constraintMap, "mix", 1); + data.softness = this.getValue(constraintMap, "softness", 0) * scale; + data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1; + data.compress = this.getValue(constraintMap, "compress", false); + data.stretch = this.getValue(constraintMap, "stretch", false); + data.uniform = this.getValue(constraintMap, "uniform", false); + skeletonData.ikConstraints.push(data); + } + } + if (root.transform) { + for (var i = 0; i < root.transform.length; i++) { + var constraintMap = root.transform[i]; + var data = new spine.TransformConstraintData(constraintMap.name); + data.order = this.getValue(constraintMap, "order", 0); + data.skinRequired = this.getValue(constraintMap, "skin", false); + for (var j = 0; j < constraintMap.bones.length; j++) { + var boneName = constraintMap.bones[j]; + var bone = skeletonData.findBone(boneName); + if (bone == null) + throw new Error("Transform constraint bone not found: " + boneName); + data.bones.push(bone); + } + var targetName = constraintMap.target; + data.target = skeletonData.findBone(targetName); + if (data.target == null) + throw new Error("Transform constraint target bone not found: " + targetName); + data.local = this.getValue(constraintMap, "local", false); + data.relative = this.getValue(constraintMap, "relative", false); + data.offsetRotation = this.getValue(constraintMap, "rotation", 0); + data.offsetX = this.getValue(constraintMap, "x", 0) * scale; + data.offsetY = this.getValue(constraintMap, "y", 0) * scale; + data.offsetScaleX = this.getValue(constraintMap, "scaleX", 0); + data.offsetScaleY = this.getValue(constraintMap, "scaleY", 0); + data.offsetShearY = this.getValue(constraintMap, "shearY", 0); + data.rotateMix = this.getValue(constraintMap, "rotateMix", 1); + data.translateMix = this.getValue(constraintMap, "translateMix", 1); + data.scaleMix = this.getValue(constraintMap, "scaleMix", 1); + data.shearMix = this.getValue(constraintMap, "shearMix", 1); + skeletonData.transformConstraints.push(data); + } + } + if (root.path) { + for (var i = 0; i < root.path.length; i++) { + var constraintMap = root.path[i]; + var data = new spine.PathConstraintData(constraintMap.name); + data.order = this.getValue(constraintMap, "order", 0); + data.skinRequired = this.getValue(constraintMap, "skin", false); + for (var j = 0; j < constraintMap.bones.length; j++) { + var boneName = constraintMap.bones[j]; + var bone = skeletonData.findBone(boneName); + if (bone == null) + throw new Error("Transform constraint bone not found: " + boneName); + data.bones.push(bone); + } + var targetName = constraintMap.target; + data.target = skeletonData.findSlot(targetName); + if (data.target == null) + throw new Error("Path target slot not found: " + targetName); + data.positionMode = SkeletonJson.positionModeFromString(this.getValue(constraintMap, "positionMode", "percent")); + data.spacingMode = SkeletonJson.spacingModeFromString(this.getValue(constraintMap, "spacingMode", "length")); + data.rotateMode = SkeletonJson.rotateModeFromString(this.getValue(constraintMap, "rotateMode", "tangent")); + data.offsetRotation = this.getValue(constraintMap, "rotation", 0); + data.position = this.getValue(constraintMap, "position", 0); + if (data.positionMode == spine.PositionMode.Fixed) + data.position *= scale; + data.spacing = this.getValue(constraintMap, "spacing", 0); + if (data.spacingMode == spine.SpacingMode.Length || data.spacingMode == spine.SpacingMode.Fixed) + data.spacing *= scale; + data.rotateMix = this.getValue(constraintMap, "rotateMix", 1); + data.translateMix = this.getValue(constraintMap, "translateMix", 1); + skeletonData.pathConstraints.push(data); + } + } + if (root.skins) { + for (var i = 0; i < root.skins.length; i++) { + var skinMap = root.skins[i]; + var skin = new spine.Skin(skinMap.name); + if (skinMap.bones) { + for (var ii = 0; ii < skinMap.bones.length; ii++) { + var bone = skeletonData.findBone(skinMap.bones[ii]); + if (bone == null) + throw new Error("Skin bone not found: " + skinMap.bones[i]); + skin.bones.push(bone); + } + } + if (skinMap.ik) { + for (var ii = 0; ii < skinMap.ik.length; ii++) { + var constraint = skeletonData.findIkConstraint(skinMap.ik[ii]); + if (constraint == null) + throw new Error("Skin IK constraint not found: " + skinMap.ik[i]); + skin.constraints.push(constraint); + } + } + if (skinMap.transform) { + for (var ii = 0; ii < skinMap.transform.length; ii++) { + var constraint = skeletonData.findTransformConstraint(skinMap.transform[ii]); + if (constraint == null) + throw new Error("Skin transform constraint not found: " + skinMap.transform[i]); + skin.constraints.push(constraint); + } + } + if (skinMap.path) { + for (var ii = 0; ii < skinMap.path.length; ii++) { + var constraint = skeletonData.findPathConstraint(skinMap.path[ii]); + if (constraint == null) + throw new Error("Skin path constraint not found: " + skinMap.path[i]); + skin.constraints.push(constraint); + } + } + for (var slotName in skinMap.attachments) { + var slot = skeletonData.findSlot(slotName); + if (slot == null) + throw new Error("Slot not found: " + slotName); + var slotMap = skinMap.attachments[slotName]; + for (var entryName in slotMap) { + var attachment = this.readAttachment(slotMap[entryName], skin, slot.index, entryName, skeletonData); + if (attachment != null) + skin.setAttachment(slot.index, entryName, attachment); + } + } + skeletonData.skins.push(skin); + if (skin.name == "default") + skeletonData.defaultSkin = skin; + } + } + for (var i = 0, n = this.linkedMeshes.length; i < n; i++) { + var linkedMesh = this.linkedMeshes[i]; + var skin = linkedMesh.skin == null ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin); + if (skin == null) + throw new Error("Skin not found: " + linkedMesh.skin); + var parent_6 = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); + if (parent_6 == null) + throw new Error("Parent mesh not found: " + linkedMesh.parent); + linkedMesh.mesh.deformAttachment = linkedMesh.inheritDeform ? parent_6 : linkedMesh.mesh; + linkedMesh.mesh.setParentMesh(parent_6); + linkedMesh.mesh.updateUVs(); + } + this.linkedMeshes.length = 0; + if (root.events) { + for (var eventName in root.events) { + var eventMap = root.events[eventName]; + var data = new spine.EventData(eventName); + data.intValue = this.getValue(eventMap, "int", 0); + data.floatValue = this.getValue(eventMap, "float", 0); + data.stringValue = this.getValue(eventMap, "string", ""); + data.audioPath = this.getValue(eventMap, "audio", null); + if (data.audioPath != null) { + data.volume = this.getValue(eventMap, "volume", 1); + data.balance = this.getValue(eventMap, "balance", 0); + } + skeletonData.events.push(data); + } + } + if (root.animations) { + for (var animationName in root.animations) { + var animationMap = root.animations[animationName]; + this.readAnimation(animationMap, animationName, skeletonData); + } + } + return skeletonData; + }; + SkeletonJson.prototype.readAttachment = function (map, skin, slotIndex, name, skeletonData) { + var scale = this.scale; + name = this.getValue(map, "name", name); + var type = this.getValue(map, "type", "region"); + switch (type) { + case "region": { + var path = this.getValue(map, "path", name); + var region = this.attachmentLoader.newRegionAttachment(skin, name, path); + if (region == null) + return null; + region.path = path; + region.x = this.getValue(map, "x", 0) * scale; + region.y = this.getValue(map, "y", 0) * scale; + region.scaleX = this.getValue(map, "scaleX", 1); + region.scaleY = this.getValue(map, "scaleY", 1); + region.rotation = this.getValue(map, "rotation", 0); + region.width = map.width * scale; + region.height = map.height * scale; + var color = this.getValue(map, "color", null); + if (color != null) + region.color.setFromString(color); + region.updateOffset(); + return region; + } + case "boundingbox": { + var box = this.attachmentLoader.newBoundingBoxAttachment(skin, name); + if (box == null) + return null; + this.readVertices(map, box, map.vertexCount << 1); + var color = this.getValue(map, "color", null); + if (color != null) + box.color.setFromString(color); + return box; + } + case "mesh": + case "linkedmesh": { + var path = this.getValue(map, "path", name); + var mesh = this.attachmentLoader.newMeshAttachment(skin, name, path); + if (mesh == null) + return null; + mesh.path = path; + var color = this.getValue(map, "color", null); + if (color != null) + mesh.color.setFromString(color); + mesh.width = this.getValue(map, "width", 0) * scale; + mesh.height = this.getValue(map, "height", 0) * scale; + var parent_7 = this.getValue(map, "parent", null); + if (parent_7 != null) { + this.linkedMeshes.push(new LinkedMesh(mesh, this.getValue(map, "skin", null), slotIndex, parent_7, this.getValue(map, "deform", true))); + return mesh; + } + var uvs = map.uvs; + this.readVertices(map, mesh, uvs.length); + mesh.triangles = map.triangles; + mesh.regionUVs = uvs; + mesh.updateUVs(); + mesh.edges = this.getValue(map, "edges", null); + mesh.hullLength = this.getValue(map, "hull", 0) * 2; + return mesh; + } + case "path": { + var path = this.attachmentLoader.newPathAttachment(skin, name); + if (path == null) + return null; + path.closed = this.getValue(map, "closed", false); + path.constantSpeed = this.getValue(map, "constantSpeed", true); + var vertexCount = map.vertexCount; + this.readVertices(map, path, vertexCount << 1); + var lengths = spine.Utils.newArray(vertexCount / 3, 0); + for (var i = 0; i < map.lengths.length; i++) + lengths[i] = map.lengths[i] * scale; + path.lengths = lengths; + var color = this.getValue(map, "color", null); + if (color != null) + path.color.setFromString(color); + return path; + } + case "point": { + var point = this.attachmentLoader.newPointAttachment(skin, name); + if (point == null) + return null; + point.x = this.getValue(map, "x", 0) * scale; + point.y = this.getValue(map, "y", 0) * scale; + point.rotation = this.getValue(map, "rotation", 0); + var color = this.getValue(map, "color", null); + if (color != null) + point.color.setFromString(color); + return point; + } + case "clipping": { + var clip = this.attachmentLoader.newClippingAttachment(skin, name); + if (clip == null) + return null; + var end = this.getValue(map, "end", null); + if (end != null) { + var slot = skeletonData.findSlot(end); + if (slot == null) + throw new Error("Clipping end slot not found: " + end); + clip.endSlot = slot; + } + var vertexCount = map.vertexCount; + this.readVertices(map, clip, vertexCount << 1); + var color = this.getValue(map, "color", null); + if (color != null) + clip.color.setFromString(color); + return clip; + } + } + return null; + }; + SkeletonJson.prototype.readVertices = function (map, attachment, verticesLength) { + var scale = this.scale; + attachment.worldVerticesLength = verticesLength; + var vertices = map.vertices; + if (verticesLength == vertices.length) { + var scaledVertices = spine.Utils.toFloatArray(vertices); + if (scale != 1) { + for (var i = 0, n = vertices.length; i < n; i++) + scaledVertices[i] *= scale; + } + attachment.vertices = scaledVertices; + return; + } + var weights = new Array(); + var bones = new Array(); + for (var i = 0, n = vertices.length; i < n;) { + var boneCount = vertices[i++]; + bones.push(boneCount); + for (var nn = i + boneCount * 4; i < nn; i += 4) { + bones.push(vertices[i]); + weights.push(vertices[i + 1] * scale); + weights.push(vertices[i + 2] * scale); + weights.push(vertices[i + 3]); + } + } + attachment.bones = bones; + attachment.vertices = spine.Utils.toFloatArray(weights); + }; + SkeletonJson.prototype.readAnimation = function (map, name, skeletonData) { + var scale = this.scale; + var timelines = new Array(); + var duration = 0; + if (map.slots) { + for (var slotName in map.slots) { + var slotMap = map.slots[slotName]; + var slotIndex = skeletonData.findSlotIndex(slotName); + if (slotIndex == -1) + throw new Error("Slot not found: " + slotName); + for (var timelineName in slotMap) { + var timelineMap = slotMap[timelineName]; + if (timelineName == "attachment") { + var timeline = new spine.AttachmentTimeline(timelineMap.length); + timeline.slotIndex = slotIndex; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + timeline.setFrame(frameIndex++, this.getValue(valueMap, "time", 0), valueMap.name); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + else if (timelineName == "color") { + var timeline = new spine.ColorTimeline(timelineMap.length); + timeline.slotIndex = slotIndex; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + var color = new spine.Color(); + color.setFromString(valueMap.color); + timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), color.r, color.g, color.b, color.a); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.ColorTimeline.ENTRIES]); + } + else if (timelineName == "twoColor") { + var timeline = new spine.TwoColorTimeline(timelineMap.length); + timeline.slotIndex = slotIndex; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + var light = new spine.Color(); + var dark = new spine.Color(); + light.setFromString(valueMap.light); + dark.setFromString(valueMap.dark); + timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), light.r, light.g, light.b, light.a, dark.r, dark.g, dark.b); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.TwoColorTimeline.ENTRIES]); + } + else + throw new Error("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"); + } + } + } + if (map.bones) { + for (var boneName in map.bones) { + var boneMap = map.bones[boneName]; + var boneIndex = skeletonData.findBoneIndex(boneName); + if (boneIndex == -1) + throw new Error("Bone not found: " + boneName); + for (var timelineName in boneMap) { + var timelineMap = boneMap[timelineName]; + if (timelineName === "rotate") { + var timeline = new spine.RotateTimeline(timelineMap.length); + timeline.boneIndex = boneIndex; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "angle", 0)); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.RotateTimeline.ENTRIES]); + } + else if (timelineName === "translate" || timelineName === "scale" || timelineName === "shear") { + var timeline = null; + var timelineScale = 1, defaultValue = 0; + if (timelineName === "scale") { + timeline = new spine.ScaleTimeline(timelineMap.length); + defaultValue = 1; + } + else if (timelineName === "shear") + timeline = new spine.ShearTimeline(timelineMap.length); + else { + timeline = new spine.TranslateTimeline(timelineMap.length); + timelineScale = scale; + } + timeline.boneIndex = boneIndex; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + var x = this.getValue(valueMap, "x", defaultValue), y = this.getValue(valueMap, "y", defaultValue); + timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), x * timelineScale, y * timelineScale); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.TranslateTimeline.ENTRIES]); + } + else + throw new Error("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"); + } + } + } + if (map.ik) { + for (var constraintName in map.ik) { + var constraintMap = map.ik[constraintName]; + var constraint = skeletonData.findIkConstraint(constraintName); + var timeline = new spine.IkConstraintTimeline(constraintMap.length); + timeline.ikConstraintIndex = skeletonData.ikConstraints.indexOf(constraint); + var frameIndex = 0; + for (var i = 0; i < constraintMap.length; i++) { + var valueMap = constraintMap[i]; + timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "softness", 0) * scale, this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false)); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.IkConstraintTimeline.ENTRIES]); + } + } + if (map.transform) { + for (var constraintName in map.transform) { + var constraintMap = map.transform[constraintName]; + var constraint = skeletonData.findTransformConstraint(constraintName); + var timeline = new spine.TransformConstraintTimeline(constraintMap.length); + timeline.transformConstraintIndex = skeletonData.transformConstraints.indexOf(constraint); + var frameIndex = 0; + for (var i = 0; i < constraintMap.length; i++) { + var valueMap = constraintMap[i]; + timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "rotateMix", 1), this.getValue(valueMap, "translateMix", 1), this.getValue(valueMap, "scaleMix", 1), this.getValue(valueMap, "shearMix", 1)); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.TransformConstraintTimeline.ENTRIES]); + } + } + if (map.path) { + for (var constraintName in map.path) { + var constraintMap = map.path[constraintName]; + var index = skeletonData.findPathConstraintIndex(constraintName); + if (index == -1) + throw new Error("Path constraint not found: " + constraintName); + var data = skeletonData.pathConstraints[index]; + for (var timelineName in constraintMap) { + var timelineMap = constraintMap[timelineName]; + if (timelineName === "position" || timelineName === "spacing") { + var timeline = null; + var timelineScale = 1; + if (timelineName === "spacing") { + timeline = new spine.PathConstraintSpacingTimeline(timelineMap.length); + if (data.spacingMode == spine.SpacingMode.Length || data.spacingMode == spine.SpacingMode.Fixed) + timelineScale = scale; + } + else { + timeline = new spine.PathConstraintPositionTimeline(timelineMap.length); + if (data.positionMode == spine.PositionMode.Fixed) + timelineScale = scale; + } + timeline.pathConstraintIndex = index; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, timelineName, 0) * timelineScale); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.PathConstraintPositionTimeline.ENTRIES]); + } + else if (timelineName === "mix") { + var timeline = new spine.PathConstraintMixTimeline(timelineMap.length); + timeline.pathConstraintIndex = index; + var frameIndex = 0; + for (var i = 0; i < timelineMap.length; i++) { + var valueMap = timelineMap[i]; + timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), this.getValue(valueMap, "rotateMix", 1), this.getValue(valueMap, "translateMix", 1)); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[(timeline.getFrameCount() - 1) * spine.PathConstraintMixTimeline.ENTRIES]); + } + } + } + } + if (map.deform) { + for (var deformName in map.deform) { + var deformMap = map.deform[deformName]; + var skin = skeletonData.findSkin(deformName); + if (skin == null) + throw new Error("Skin not found: " + deformName); + for (var slotName in deformMap) { + var slotMap = deformMap[slotName]; + var slotIndex = skeletonData.findSlotIndex(slotName); + if (slotIndex == -1) + throw new Error("Slot not found: " + slotMap.name); + for (var timelineName in slotMap) { + var timelineMap = slotMap[timelineName]; + var attachment = skin.getAttachment(slotIndex, timelineName); + if (attachment == null) + throw new Error("Deform attachment not found: " + timelineMap.name); + var weighted = attachment.bones != null; + var vertices = attachment.vertices; + var deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + var timeline = new spine.DeformTimeline(timelineMap.length); + timeline.slotIndex = slotIndex; + timeline.attachment = attachment; + var frameIndex = 0; + for (var j = 0; j < timelineMap.length; j++) { + var valueMap = timelineMap[j]; + var deform = void 0; + var verticesValue = this.getValue(valueMap, "vertices", null); + if (verticesValue == null) + deform = weighted ? spine.Utils.newFloatArray(deformLength) : vertices; + else { + deform = spine.Utils.newFloatArray(deformLength); + var start = this.getValue(valueMap, "offset", 0); + spine.Utils.arrayCopy(verticesValue, 0, deform, start, verticesValue.length); + if (scale != 1) { + for (var i = start, n = i + verticesValue.length; i < n; i++) + deform[i] *= scale; + } + if (!weighted) { + for (var i = 0; i < deformLength; i++) + deform[i] += vertices[i]; + } + } + timeline.setFrame(frameIndex, this.getValue(valueMap, "time", 0), deform); + this.readCurve(valueMap, timeline, frameIndex); + frameIndex++; + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + } + } + } + var drawOrderNode = map.drawOrder; + if (drawOrderNode == null) + drawOrderNode = map.draworder; + if (drawOrderNode != null) { + var timeline = new spine.DrawOrderTimeline(drawOrderNode.length); + var slotCount = skeletonData.slots.length; + var frameIndex = 0; + for (var j = 0; j < drawOrderNode.length; j++) { + var drawOrderMap = drawOrderNode[j]; + var drawOrder = null; + var offsets = this.getValue(drawOrderMap, "offsets", null); + if (offsets != null) { + drawOrder = spine.Utils.newArray(slotCount, -1); + var unchanged = spine.Utils.newArray(slotCount - offsets.length, 0); + var originalIndex = 0, unchangedIndex = 0; + for (var i = 0; i < offsets.length; i++) { + var offsetMap = offsets[i]; + var slotIndex = skeletonData.findSlotIndex(offsetMap.slot); + if (slotIndex == -1) + throw new Error("Slot not found: " + offsetMap.slot); + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + drawOrder[originalIndex + offsetMap.offset] = originalIndex++; + } + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + for (var i = slotCount - 1; i >= 0; i--) + if (drawOrder[i] == -1) + drawOrder[i] = unchanged[--unchangedIndex]; + } + timeline.setFrame(frameIndex++, this.getValue(drawOrderMap, "time", 0), drawOrder); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + if (map.events) { + var timeline = new spine.EventTimeline(map.events.length); + var frameIndex = 0; + for (var i = 0; i < map.events.length; i++) { + var eventMap = map.events[i]; + var eventData = skeletonData.findEvent(eventMap.name); + if (eventData == null) + throw new Error("Event not found: " + eventMap.name); + var event_6 = new spine.Event(spine.Utils.toSinglePrecision(this.getValue(eventMap, "time", 0)), eventData); + event_6.intValue = this.getValue(eventMap, "int", eventData.intValue); + event_6.floatValue = this.getValue(eventMap, "float", eventData.floatValue); + event_6.stringValue = this.getValue(eventMap, "string", eventData.stringValue); + if (event_6.data.audioPath != null) { + event_6.volume = this.getValue(eventMap, "volume", 1); + event_6.balance = this.getValue(eventMap, "balance", 0); + } + timeline.setFrame(frameIndex++, event_6); + } + timelines.push(timeline); + duration = Math.max(duration, timeline.frames[timeline.getFrameCount() - 1]); + } + if (isNaN(duration)) { + throw new Error("Error while parsing animation, duration is NaN"); + } + skeletonData.animations.push(new spine.Animation(name, timelines, duration)); + }; + SkeletonJson.prototype.readCurve = function (map, timeline, frameIndex) { + if (!map.hasOwnProperty("curve")) + return; + if (map.curve == "stepped") + timeline.setStepped(frameIndex); + else { + var curve = map.curve; + timeline.setCurve(frameIndex, curve, this.getValue(map, "c2", 0), this.getValue(map, "c3", 1), this.getValue(map, "c4", 1)); + } + }; + SkeletonJson.prototype.getValue = function (map, prop, defaultValue) { + return map[prop] !== undefined ? map[prop] : defaultValue; + }; + SkeletonJson.blendModeFromString = function (str) { + str = str.toLowerCase(); + if (str == "normal") + return spine.BlendMode.Normal; + if (str == "additive") + return spine.BlendMode.Additive; + if (str == "multiply") + return spine.BlendMode.Multiply; + if (str == "screen") + return spine.BlendMode.Screen; + throw new Error("Unknown blend mode: " + str); + }; + SkeletonJson.positionModeFromString = function (str) { + str = str.toLowerCase(); + if (str == "fixed") + return spine.PositionMode.Fixed; + if (str == "percent") + return spine.PositionMode.Percent; + throw new Error("Unknown position mode: " + str); + }; + SkeletonJson.spacingModeFromString = function (str) { + str = str.toLowerCase(); + if (str == "length") + return spine.SpacingMode.Length; + if (str == "fixed") + return spine.SpacingMode.Fixed; + if (str == "percent") + return spine.SpacingMode.Percent; + throw new Error("Unknown position mode: " + str); + }; + SkeletonJson.rotateModeFromString = function (str) { + str = str.toLowerCase(); + if (str == "tangent") + return spine.RotateMode.Tangent; + if (str == "chain") + return spine.RotateMode.Chain; + if (str == "chainscale") + return spine.RotateMode.ChainScale; + throw new Error("Unknown rotate mode: " + str); + }; + SkeletonJson.transformModeFromString = function (str) { + str = str.toLowerCase(); + if (str == "normal") + return spine.TransformMode.Normal; + if (str == "onlytranslation") + return spine.TransformMode.OnlyTranslation; + if (str == "norotationorreflection") + return spine.TransformMode.NoRotationOrReflection; + if (str == "noscale") + return spine.TransformMode.NoScale; + if (str == "noscaleorreflection") + return spine.TransformMode.NoScaleOrReflection; + throw new Error("Unknown transform mode: " + str); + }; + return SkeletonJson; + }()); + spine.SkeletonJson = SkeletonJson; + var LinkedMesh = (function () { + function LinkedMesh(mesh, skin, slotIndex, parent, inheritDeform) { + this.mesh = mesh; + this.skin = skin; + this.slotIndex = slotIndex; + this.parent = parent; + this.inheritDeform = inheritDeform; + } + return LinkedMesh; + }()); +})(spine || (spine = {})); +var spine; +(function (spine) { + var SkinEntry = (function () { + function SkinEntry(slotIndex, name, attachment) { + this.slotIndex = slotIndex; + this.name = name; + this.attachment = attachment; + } + return SkinEntry; + }()); + spine.SkinEntry = SkinEntry; + var Skin = (function () { + function Skin(name) { + this.attachments = new Array(); + this.bones = Array(); + this.constraints = new Array(); + if (name == null) + throw new Error("name cannot be null."); + this.name = name; + } + Skin.prototype.setAttachment = function (slotIndex, name, attachment) { + if (attachment == null) + throw new Error("attachment cannot be null."); + var attachments = this.attachments; + if (slotIndex >= attachments.length) + attachments.length = slotIndex + 1; + if (!attachments[slotIndex]) + attachments[slotIndex] = {}; + attachments[slotIndex][name] = attachment; + }; + Skin.prototype.addSkin = function (skin) { + for (var i = 0; i < skin.bones.length; i++) { + var bone = skin.bones[i]; + var contained = false; + for (var j = 0; j < this.bones.length; j++) { + if (this.bones[j] == bone) { + contained = true; + break; + } + } + if (!contained) + this.bones.push(bone); + } + for (var i = 0; i < skin.constraints.length; i++) { + var constraint = skin.constraints[i]; + var contained = false; + for (var j = 0; j < this.constraints.length; j++) { + if (this.constraints[j] == constraint) { + contained = true; + break; + } + } + if (!contained) + this.constraints.push(constraint); + } + var attachments = skin.getAttachments(); + for (var i = 0; i < attachments.length; i++) { + var attachment = attachments[i]; + this.setAttachment(attachment.slotIndex, attachment.name, attachment.attachment); + } + }; + Skin.prototype.copySkin = function (skin) { + for (var i = 0; i < skin.bones.length; i++) { + var bone = skin.bones[i]; + var contained = false; + for (var j = 0; j < this.bones.length; j++) { + if (this.bones[j] == bone) { + contained = true; + break; + } + } + if (!contained) + this.bones.push(bone); + } + for (var i = 0; i < skin.constraints.length; i++) { + var constraint = skin.constraints[i]; + var contained = false; + for (var j = 0; j < this.constraints.length; j++) { + if (this.constraints[j] == constraint) { + contained = true; + break; + } + } + if (!contained) + this.constraints.push(constraint); + } + var attachments = skin.getAttachments(); + for (var i = 0; i < attachments.length; i++) { + var attachment = attachments[i]; + if (attachment.attachment == null) + continue; + if (attachment.attachment instanceof spine.MeshAttachment) { + attachment.attachment = attachment.attachment.newLinkedMesh(); + this.setAttachment(attachment.slotIndex, attachment.name, attachment.attachment); + } + else { + attachment.attachment = attachment.attachment.copy(); + this.setAttachment(attachment.slotIndex, attachment.name, attachment.attachment); + } + } + }; + Skin.prototype.getAttachment = function (slotIndex, name) { + var dictionary = this.attachments[slotIndex]; + return dictionary ? dictionary[name] : null; + }; + Skin.prototype.removeAttachment = function (slotIndex, name) { + var dictionary = this.attachments[slotIndex]; + if (dictionary) + dictionary[name] = null; + }; + Skin.prototype.getAttachments = function () { + var entries = new Array(); + for (var i = 0; i < this.attachments.length; i++) { + var slotAttachments = this.attachments[i]; + if (slotAttachments) { + for (var name_4 in slotAttachments) { + var attachment = slotAttachments[name_4]; + if (attachment) + entries.push(new SkinEntry(i, name_4, attachment)); + } + } + } + return entries; + }; + Skin.prototype.getAttachmentsForSlot = function (slotIndex, attachments) { + var slotAttachments = this.attachments[slotIndex]; + if (slotAttachments) { + for (var name_5 in slotAttachments) { + var attachment = slotAttachments[name_5]; + if (attachment) + attachments.push(new SkinEntry(slotIndex, name_5, attachment)); + } + } + }; + Skin.prototype.clear = function () { + this.attachments.length = 0; + this.bones.length = 0; + this.constraints.length = 0; + }; + Skin.prototype.attachAll = function (skeleton, oldSkin) { + var slotIndex = 0; + for (var i = 0; i < skeleton.slots.length; i++) { + var slot = skeleton.slots[i]; + var slotAttachment = slot.getAttachment(); + if (slotAttachment && slotIndex < oldSkin.attachments.length) { + var dictionary = oldSkin.attachments[slotIndex]; + for (var key in dictionary) { + var skinAttachment = dictionary[key]; + if (slotAttachment == skinAttachment) { + var attachment = this.getAttachment(slotIndex, key); + if (attachment != null) + slot.setAttachment(attachment); + break; + } + } + } + slotIndex++; + } + }; + return Skin; + }()); + spine.Skin = Skin; +})(spine || (spine = {})); +var spine; +(function (spine) { + var Slot = (function () { + function Slot(data, bone) { + this.deform = new Array(); + if (data == null) + throw new Error("data cannot be null."); + if (bone == null) + throw new Error("bone cannot be null."); + this.data = data; + this.bone = bone; + this.color = new spine.Color(); + this.darkColor = data.darkColor == null ? null : new spine.Color(); + this.setToSetupPose(); + } + Slot.prototype.getSkeleton = function () { + return this.bone.skeleton; + }; + Slot.prototype.getAttachment = function () { + return this.attachment; + }; + Slot.prototype.setAttachment = function (attachment) { + if (this.attachment == attachment) + return; + this.attachment = attachment; + this.attachmentTime = this.bone.skeleton.time; + this.deform.length = 0; + }; + Slot.prototype.setAttachmentTime = function (time) { + this.attachmentTime = this.bone.skeleton.time - time; + }; + Slot.prototype.getAttachmentTime = function () { + return this.bone.skeleton.time - this.attachmentTime; + }; + Slot.prototype.setToSetupPose = function () { + this.color.setFromColor(this.data.color); + if (this.darkColor != null) + this.darkColor.setFromColor(this.data.darkColor); + if (this.data.attachmentName == null) + this.attachment = null; + else { + this.attachment = null; + this.setAttachment(this.bone.skeleton.getAttachment(this.data.index, this.data.attachmentName)); + } + }; + return Slot; + }()); + spine.Slot = Slot; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SlotData = (function () { + function SlotData(index, name, boneData) { + this.color = new spine.Color(1, 1, 1, 1); + if (index < 0) + throw new Error("index must be >= 0."); + if (name == null) + throw new Error("name cannot be null."); + if (boneData == null) + throw new Error("boneData cannot be null."); + this.index = index; + this.name = name; + this.boneData = boneData; + } + return SlotData; + }()); + spine.SlotData = SlotData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var Texture = (function () { + function Texture(image) { + this._image = image; + } + Texture.prototype.getImage = function () { + return this._image; + }; + Texture.filterFromString = function (text) { + switch (text.toLowerCase()) { + case "nearest": return TextureFilter.Nearest; + case "linear": return TextureFilter.Linear; + case "mipmap": return TextureFilter.MipMap; + case "mipmapnearestnearest": return TextureFilter.MipMapNearestNearest; + case "mipmaplinearnearest": return TextureFilter.MipMapLinearNearest; + case "mipmapnearestlinear": return TextureFilter.MipMapNearestLinear; + case "mipmaplinearlinear": return TextureFilter.MipMapLinearLinear; + default: throw new Error("Unknown texture filter " + text); + } + }; + Texture.wrapFromString = function (text) { + switch (text.toLowerCase()) { + case "mirroredtepeat": return TextureWrap.MirroredRepeat; + case "clamptoedge": return TextureWrap.ClampToEdge; + case "repeat": return TextureWrap.Repeat; + default: throw new Error("Unknown texture wrap " + text); + } + }; + return Texture; + }()); + spine.Texture = Texture; + var TextureFilter; + (function (TextureFilter) { + TextureFilter[TextureFilter["Nearest"] = 9728] = "Nearest"; + TextureFilter[TextureFilter["Linear"] = 9729] = "Linear"; + TextureFilter[TextureFilter["MipMap"] = 9987] = "MipMap"; + TextureFilter[TextureFilter["MipMapNearestNearest"] = 9984] = "MipMapNearestNearest"; + TextureFilter[TextureFilter["MipMapLinearNearest"] = 9985] = "MipMapLinearNearest"; + TextureFilter[TextureFilter["MipMapNearestLinear"] = 9986] = "MipMapNearestLinear"; + TextureFilter[TextureFilter["MipMapLinearLinear"] = 9987] = "MipMapLinearLinear"; + })(TextureFilter = spine.TextureFilter || (spine.TextureFilter = {})); + var TextureWrap; + (function (TextureWrap) { + TextureWrap[TextureWrap["MirroredRepeat"] = 33648] = "MirroredRepeat"; + TextureWrap[TextureWrap["ClampToEdge"] = 33071] = "ClampToEdge"; + TextureWrap[TextureWrap["Repeat"] = 10497] = "Repeat"; + })(TextureWrap = spine.TextureWrap || (spine.TextureWrap = {})); + var TextureRegion = (function () { + function TextureRegion() { + this.u = 0; + this.v = 0; + this.u2 = 0; + this.v2 = 0; + this.width = 0; + this.height = 0; + this.rotate = false; + this.offsetX = 0; + this.offsetY = 0; + this.originalWidth = 0; + this.originalHeight = 0; + } + return TextureRegion; + }()); + spine.TextureRegion = TextureRegion; + var FakeTexture = (function (_super) { + __extends(FakeTexture, _super); + function FakeTexture() { + return _super !== null && _super.apply(this, arguments) || this; + } + FakeTexture.prototype.setFilters = function (minFilter, magFilter) { }; + FakeTexture.prototype.setWraps = function (uWrap, vWrap) { }; + FakeTexture.prototype.dispose = function () { }; + return FakeTexture; + }(Texture)); + spine.FakeTexture = FakeTexture; +})(spine || (spine = {})); +var spine; +(function (spine) { + var TextureAtlas = (function () { + function TextureAtlas(atlasText, textureLoader) { + this.pages = new Array(); + this.regions = new Array(); + this.load(atlasText, textureLoader); + } + TextureAtlas.prototype.load = function (atlasText, textureLoader) { + if (textureLoader == null) + throw new Error("textureLoader cannot be null."); + var reader = new TextureAtlasReader(atlasText); + var tuple = new Array(4); + var page = null; + while (true) { + var line = reader.readLine(); + if (line == null) + break; + line = line.trim(); + if (line.length == 0) + page = null; + else if (!page) { + page = new TextureAtlasPage(); + page.name = line; + if (reader.readTuple(tuple) == 2) { + page.width = parseInt(tuple[0]); + page.height = parseInt(tuple[1]); + reader.readTuple(tuple); + } + reader.readTuple(tuple); + page.minFilter = spine.Texture.filterFromString(tuple[0]); + page.magFilter = spine.Texture.filterFromString(tuple[1]); + var direction = reader.readValue(); + page.uWrap = spine.TextureWrap.ClampToEdge; + page.vWrap = spine.TextureWrap.ClampToEdge; + if (direction == "x") + page.uWrap = spine.TextureWrap.Repeat; + else if (direction == "y") + page.vWrap = spine.TextureWrap.Repeat; + else if (direction == "xy") + page.uWrap = page.vWrap = spine.TextureWrap.Repeat; + page.texture = textureLoader(line); + page.texture.setFilters(page.minFilter, page.magFilter); + page.texture.setWraps(page.uWrap, page.vWrap); + page.width = page.texture.getImage().width; + page.height = page.texture.getImage().height; + this.pages.push(page); + } + else { + var region = new TextureAtlasRegion(); + region.name = line; + region.page = page; + var rotateValue = reader.readValue(); + if (rotateValue.toLocaleLowerCase() == "true") { + region.degrees = 90; + } + else if (rotateValue.toLocaleLowerCase() == "false") { + region.degrees = 0; + } + else { + region.degrees = parseFloat(rotateValue); + } + region.rotate = region.degrees == 90; + reader.readTuple(tuple); + var x = parseInt(tuple[0]); + var y = parseInt(tuple[1]); + reader.readTuple(tuple); + var width = parseInt(tuple[0]); + var height = parseInt(tuple[1]); + region.u = x / page.width; + region.v = y / page.height; + if (region.rotate) { + region.u2 = (x + height) / page.width; + region.v2 = (y + width) / page.height; + } + else { + region.u2 = (x + width) / page.width; + region.v2 = (y + height) / page.height; + } + region.x = x; + region.y = y; + region.width = Math.abs(width); + region.height = Math.abs(height); + if (reader.readTuple(tuple) == 4) { + if (reader.readTuple(tuple) == 4) { + reader.readTuple(tuple); + } + } + region.originalWidth = parseInt(tuple[0]); + region.originalHeight = parseInt(tuple[1]); + reader.readTuple(tuple); + region.offsetX = parseInt(tuple[0]); + region.offsetY = parseInt(tuple[1]); + region.index = parseInt(reader.readValue()); + region.texture = page.texture; + this.regions.push(region); + } + } + }; + TextureAtlas.prototype.findRegion = function (name) { + for (var i = 0; i < this.regions.length; i++) { + if (this.regions[i].name == name) { + return this.regions[i]; + } + } + return null; + }; + TextureAtlas.prototype.dispose = function () { + for (var i = 0; i < this.pages.length; i++) { + this.pages[i].texture.dispose(); + } + }; + return TextureAtlas; + }()); + spine.TextureAtlas = TextureAtlas; + var TextureAtlasReader = (function () { + function TextureAtlasReader(text) { + this.index = 0; + this.lines = text.split(/\r\n|\r|\n/); + } + TextureAtlasReader.prototype.readLine = function () { + if (this.index >= this.lines.length) + return null; + return this.lines[this.index++]; + }; + TextureAtlasReader.prototype.readValue = function () { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) + throw new Error("Invalid line: " + line); + return line.substring(colon + 1).trim(); + }; + TextureAtlasReader.prototype.readTuple = function (tuple) { + var line = this.readLine(); + var colon = line.indexOf(":"); + if (colon == -1) + throw new Error("Invalid line: " + line); + var i = 0, lastMatch = colon + 1; + for (; i < 3; i++) { + var comma = line.indexOf(",", lastMatch); + if (comma == -1) + break; + tuple[i] = line.substr(lastMatch, comma - lastMatch).trim(); + lastMatch = comma + 1; + } + tuple[i] = line.substring(lastMatch).trim(); + return i + 1; + }; + return TextureAtlasReader; + }()); + var TextureAtlasPage = (function () { + function TextureAtlasPage() { + } + return TextureAtlasPage; + }()); + spine.TextureAtlasPage = TextureAtlasPage; + var TextureAtlasRegion = (function (_super) { + __extends(TextureAtlasRegion, _super); + function TextureAtlasRegion() { + return _super !== null && _super.apply(this, arguments) || this; + } + return TextureAtlasRegion; + }(spine.TextureRegion)); + spine.TextureAtlasRegion = TextureAtlasRegion; +})(spine || (spine = {})); +var spine; +(function (spine) { + var TransformConstraint = (function () { + function TransformConstraint(data, skeleton) { + this.rotateMix = 0; + this.translateMix = 0; + this.scaleMix = 0; + this.shearMix = 0; + this.temp = new spine.Vector2(); + this.active = false; + if (data == null) + throw new Error("data cannot be null."); + if (skeleton == null) + throw new Error("skeleton cannot be null."); + this.data = data; + this.rotateMix = data.rotateMix; + this.translateMix = data.translateMix; + this.scaleMix = data.scaleMix; + this.shearMix = data.shearMix; + this.bones = new Array(); + for (var i = 0; i < data.bones.length; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findBone(data.target.name); + } + TransformConstraint.prototype.isActive = function () { + return this.active; + }; + TransformConstraint.prototype.apply = function () { + this.update(); + }; + TransformConstraint.prototype.update = function () { + if (this.data.local) { + if (this.data.relative) + this.applyRelativeLocal(); + else + this.applyAbsoluteLocal(); + } + else { + if (this.data.relative) + this.applyRelativeWorld(); + else + this.applyAbsoluteWorld(); + } + }; + TransformConstraint.prototype.applyAbsoluteWorld = function () { + var rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; + var target = this.target; + var ta = target.a, tb = target.b, tc = target.c, td = target.d; + var degRadReflect = ta * td - tb * tc > 0 ? spine.MathUtils.degRad : -spine.MathUtils.degRad; + var offsetRotation = this.data.offsetRotation * degRadReflect; + var offsetShearY = this.data.offsetShearY * degRadReflect; + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + var modified = false; + if (rotateMix != 0) { + var a = bone.a, b = bone.b, c = bone.c, d = bone.d; + var r = Math.atan2(tc, ta) - Math.atan2(c, a) + offsetRotation; + if (r > spine.MathUtils.PI) + r -= spine.MathUtils.PI2; + else if (r < -spine.MathUtils.PI) + r += spine.MathUtils.PI2; + r *= rotateMix; + var cos = Math.cos(r), sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + modified = true; + } + if (translateMix != 0) { + var temp = this.temp; + target.localToWorld(temp.set(this.data.offsetX, this.data.offsetY)); + bone.worldX += (temp.x - bone.worldX) * translateMix; + bone.worldY += (temp.y - bone.worldY) * translateMix; + modified = true; + } + if (scaleMix > 0) { + var s = Math.sqrt(bone.a * bone.a + bone.c * bone.c); + var ts = Math.sqrt(ta * ta + tc * tc); + if (s > 0.00001) + s = (s + (ts - s + this.data.offsetScaleX) * scaleMix) / s; + bone.a *= s; + bone.c *= s; + s = Math.sqrt(bone.b * bone.b + bone.d * bone.d); + ts = Math.sqrt(tb * tb + td * td); + if (s > 0.00001) + s = (s + (ts - s + this.data.offsetScaleY) * scaleMix) / s; + bone.b *= s; + bone.d *= s; + modified = true; + } + if (shearMix > 0) { + var b = bone.b, d = bone.d; + var by = Math.atan2(d, b); + var r = Math.atan2(td, tb) - Math.atan2(tc, ta) - (by - Math.atan2(bone.c, bone.a)); + if (r > spine.MathUtils.PI) + r -= spine.MathUtils.PI2; + else if (r < -spine.MathUtils.PI) + r += spine.MathUtils.PI2; + r = by + (r + offsetShearY) * shearMix; + var s = Math.sqrt(b * b + d * d); + bone.b = Math.cos(r) * s; + bone.d = Math.sin(r) * s; + modified = true; + } + if (modified) + bone.appliedValid = false; + } + }; + TransformConstraint.prototype.applyRelativeWorld = function () { + var rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; + var target = this.target; + var ta = target.a, tb = target.b, tc = target.c, td = target.d; + var degRadReflect = ta * td - tb * tc > 0 ? spine.MathUtils.degRad : -spine.MathUtils.degRad; + var offsetRotation = this.data.offsetRotation * degRadReflect, offsetShearY = this.data.offsetShearY * degRadReflect; + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + var modified = false; + if (rotateMix != 0) { + var a = bone.a, b = bone.b, c = bone.c, d = bone.d; + var r = Math.atan2(tc, ta) + offsetRotation; + if (r > spine.MathUtils.PI) + r -= spine.MathUtils.PI2; + else if (r < -spine.MathUtils.PI) + r += spine.MathUtils.PI2; + r *= rotateMix; + var cos = Math.cos(r), sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + modified = true; + } + if (translateMix != 0) { + var temp = this.temp; + target.localToWorld(temp.set(this.data.offsetX, this.data.offsetY)); + bone.worldX += temp.x * translateMix; + bone.worldY += temp.y * translateMix; + modified = true; + } + if (scaleMix > 0) { + var s = (Math.sqrt(ta * ta + tc * tc) - 1 + this.data.offsetScaleX) * scaleMix + 1; + bone.a *= s; + bone.c *= s; + s = (Math.sqrt(tb * tb + td * td) - 1 + this.data.offsetScaleY) * scaleMix + 1; + bone.b *= s; + bone.d *= s; + modified = true; + } + if (shearMix > 0) { + var r = Math.atan2(td, tb) - Math.atan2(tc, ta); + if (r > spine.MathUtils.PI) + r -= spine.MathUtils.PI2; + else if (r < -spine.MathUtils.PI) + r += spine.MathUtils.PI2; + var b = bone.b, d = bone.d; + r = Math.atan2(d, b) + (r - spine.MathUtils.PI / 2 + offsetShearY) * shearMix; + var s = Math.sqrt(b * b + d * d); + bone.b = Math.cos(r) * s; + bone.d = Math.sin(r) * s; + modified = true; + } + if (modified) + bone.appliedValid = false; + } + }; + TransformConstraint.prototype.applyAbsoluteLocal = function () { + var rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; + var target = this.target; + if (!target.appliedValid) + target.updateAppliedTransform(); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + if (!bone.appliedValid) + bone.updateAppliedTransform(); + var rotation = bone.arotation; + if (rotateMix != 0) { + var r = target.arotation - rotation + this.data.offsetRotation; + r -= (16384 - ((16384.499999999996 - r / 360) | 0)) * 360; + rotation += r * rotateMix; + } + var x = bone.ax, y = bone.ay; + if (translateMix != 0) { + x += (target.ax - x + this.data.offsetX) * translateMix; + y += (target.ay - y + this.data.offsetY) * translateMix; + } + var scaleX = bone.ascaleX, scaleY = bone.ascaleY; + if (scaleMix != 0) { + if (scaleX > 0.00001) + scaleX = (scaleX + (target.ascaleX - scaleX + this.data.offsetScaleX) * scaleMix) / scaleX; + if (scaleY > 0.00001) + scaleY = (scaleY + (target.ascaleY - scaleY + this.data.offsetScaleY) * scaleMix) / scaleY; + } + var shearY = bone.ashearY; + if (shearMix != 0) { + var r = target.ashearY - shearY + this.data.offsetShearY; + r -= (16384 - ((16384.499999999996 - r / 360) | 0)) * 360; + bone.shearY += r * shearMix; + } + bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY); + } + }; + TransformConstraint.prototype.applyRelativeLocal = function () { + var rotateMix = this.rotateMix, translateMix = this.translateMix, scaleMix = this.scaleMix, shearMix = this.shearMix; + var target = this.target; + if (!target.appliedValid) + target.updateAppliedTransform(); + var bones = this.bones; + for (var i = 0, n = bones.length; i < n; i++) { + var bone = bones[i]; + if (!bone.appliedValid) + bone.updateAppliedTransform(); + var rotation = bone.arotation; + if (rotateMix != 0) + rotation += (target.arotation + this.data.offsetRotation) * rotateMix; + var x = bone.ax, y = bone.ay; + if (translateMix != 0) { + x += (target.ax + this.data.offsetX) * translateMix; + y += (target.ay + this.data.offsetY) * translateMix; + } + var scaleX = bone.ascaleX, scaleY = bone.ascaleY; + if (scaleMix != 0) { + if (scaleX > 0.00001) + scaleX *= ((target.ascaleX - 1 + this.data.offsetScaleX) * scaleMix) + 1; + if (scaleY > 0.00001) + scaleY *= ((target.ascaleY - 1 + this.data.offsetScaleY) * scaleMix) + 1; + } + var shearY = bone.ashearY; + if (shearMix != 0) + shearY += (target.ashearY + this.data.offsetShearY) * shearMix; + bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY); + } + }; + return TransformConstraint; + }()); + spine.TransformConstraint = TransformConstraint; +})(spine || (spine = {})); +var spine; +(function (spine) { + var TransformConstraintData = (function (_super) { + __extends(TransformConstraintData, _super); + function TransformConstraintData(name) { + var _this = _super.call(this, name, 0, false) || this; + _this.bones = new Array(); + _this.rotateMix = 0; + _this.translateMix = 0; + _this.scaleMix = 0; + _this.shearMix = 0; + _this.offsetRotation = 0; + _this.offsetX = 0; + _this.offsetY = 0; + _this.offsetScaleX = 0; + _this.offsetScaleY = 0; + _this.offsetShearY = 0; + _this.relative = false; + _this.local = false; + return _this; + } + return TransformConstraintData; + }(spine.ConstraintData)); + spine.TransformConstraintData = TransformConstraintData; +})(spine || (spine = {})); +var spine; +(function (spine) { + var Triangulator = (function () { + function Triangulator() { + this.convexPolygons = new Array(); + this.convexPolygonsIndices = new Array(); + this.indicesArray = new Array(); + this.isConcaveArray = new Array(); + this.triangles = new Array(); + this.polygonPool = new spine.Pool(function () { + return new Array(); + }); + this.polygonIndicesPool = new spine.Pool(function () { + return new Array(); + }); + } + Triangulator.prototype.triangulate = function (verticesArray) { + var vertices = verticesArray; + var vertexCount = verticesArray.length >> 1; + var indices = this.indicesArray; + indices.length = 0; + for (var i = 0; i < vertexCount; i++) + indices[i] = i; + var isConcave = this.isConcaveArray; + isConcave.length = 0; + for (var i = 0, n = vertexCount; i < n; ++i) + isConcave[i] = Triangulator.isConcave(i, vertexCount, vertices, indices); + var triangles = this.triangles; + triangles.length = 0; + while (vertexCount > 3) { + var previous = vertexCount - 1, i = 0, next = 1; + while (true) { + outer: if (!isConcave[i]) { + var p1 = indices[previous] << 1, p2 = indices[i] << 1, p3 = indices[next] << 1; + var p1x = vertices[p1], p1y = vertices[p1 + 1]; + var p2x = vertices[p2], p2y = vertices[p2 + 1]; + var p3x = vertices[p3], p3y = vertices[p3 + 1]; + for (var ii = (next + 1) % vertexCount; ii != previous; ii = (ii + 1) % vertexCount) { + if (!isConcave[ii]) + continue; + var v = indices[ii] << 1; + var vx = vertices[v], vy = vertices[v + 1]; + if (Triangulator.positiveArea(p3x, p3y, p1x, p1y, vx, vy)) { + if (Triangulator.positiveArea(p1x, p1y, p2x, p2y, vx, vy)) { + if (Triangulator.positiveArea(p2x, p2y, p3x, p3y, vx, vy)) + break outer; + } + } + } + break; + } + if (next == 0) { + do { + if (!isConcave[i]) + break; + i--; + } while (i > 0); + break; + } + previous = i; + i = next; + next = (next + 1) % vertexCount; + } + triangles.push(indices[(vertexCount + i - 1) % vertexCount]); + triangles.push(indices[i]); + triangles.push(indices[(i + 1) % vertexCount]); + indices.splice(i, 1); + isConcave.splice(i, 1); + vertexCount--; + var previousIndex = (vertexCount + i - 1) % vertexCount; + var nextIndex = i == vertexCount ? 0 : i; + isConcave[previousIndex] = Triangulator.isConcave(previousIndex, vertexCount, vertices, indices); + isConcave[nextIndex] = Triangulator.isConcave(nextIndex, vertexCount, vertices, indices); + } + if (vertexCount == 3) { + triangles.push(indices[2]); + triangles.push(indices[0]); + triangles.push(indices[1]); + } + return triangles; + }; + Triangulator.prototype.decompose = function (verticesArray, triangles) { + var vertices = verticesArray; + var convexPolygons = this.convexPolygons; + this.polygonPool.freeAll(convexPolygons); + convexPolygons.length = 0; + var convexPolygonsIndices = this.convexPolygonsIndices; + this.polygonIndicesPool.freeAll(convexPolygonsIndices); + convexPolygonsIndices.length = 0; + var polygonIndices = this.polygonIndicesPool.obtain(); + polygonIndices.length = 0; + var polygon = this.polygonPool.obtain(); + polygon.length = 0; + var fanBaseIndex = -1, lastWinding = 0; + for (var i = 0, n = triangles.length; i < n; i += 3) { + var t1 = triangles[i] << 1, t2 = triangles[i + 1] << 1, t3 = triangles[i + 2] << 1; + var x1 = vertices[t1], y1 = vertices[t1 + 1]; + var x2 = vertices[t2], y2 = vertices[t2 + 1]; + var x3 = vertices[t3], y3 = vertices[t3 + 1]; + var merged = false; + if (fanBaseIndex == t1) { + var o = polygon.length - 4; + var winding1 = Triangulator.winding(polygon[o], polygon[o + 1], polygon[o + 2], polygon[o + 3], x3, y3); + var winding2 = Triangulator.winding(x3, y3, polygon[0], polygon[1], polygon[2], polygon[3]); + if (winding1 == lastWinding && winding2 == lastWinding) { + polygon.push(x3); + polygon.push(y3); + polygonIndices.push(t3); + merged = true; + } + } + if (!merged) { + if (polygon.length > 0) { + convexPolygons.push(polygon); + convexPolygonsIndices.push(polygonIndices); + } + else { + this.polygonPool.free(polygon); + this.polygonIndicesPool.free(polygonIndices); + } + polygon = this.polygonPool.obtain(); + polygon.length = 0; + polygon.push(x1); + polygon.push(y1); + polygon.push(x2); + polygon.push(y2); + polygon.push(x3); + polygon.push(y3); + polygonIndices = this.polygonIndicesPool.obtain(); + polygonIndices.length = 0; + polygonIndices.push(t1); + polygonIndices.push(t2); + polygonIndices.push(t3); + lastWinding = Triangulator.winding(x1, y1, x2, y2, x3, y3); + fanBaseIndex = t1; + } + } + if (polygon.length > 0) { + convexPolygons.push(polygon); + convexPolygonsIndices.push(polygonIndices); + } + for (var i = 0, n = convexPolygons.length; i < n; i++) { + polygonIndices = convexPolygonsIndices[i]; + if (polygonIndices.length == 0) + continue; + var firstIndex = polygonIndices[0]; + var lastIndex = polygonIndices[polygonIndices.length - 1]; + polygon = convexPolygons[i]; + var o = polygon.length - 4; + var prevPrevX = polygon[o], prevPrevY = polygon[o + 1]; + var prevX = polygon[o + 2], prevY = polygon[o + 3]; + var firstX = polygon[0], firstY = polygon[1]; + var secondX = polygon[2], secondY = polygon[3]; + var winding = Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, firstX, firstY); + for (var ii = 0; ii < n; ii++) { + if (ii == i) + continue; + var otherIndices = convexPolygonsIndices[ii]; + if (otherIndices.length != 3) + continue; + var otherFirstIndex = otherIndices[0]; + var otherSecondIndex = otherIndices[1]; + var otherLastIndex = otherIndices[2]; + var otherPoly = convexPolygons[ii]; + var x3 = otherPoly[otherPoly.length - 2], y3 = otherPoly[otherPoly.length - 1]; + if (otherFirstIndex != firstIndex || otherSecondIndex != lastIndex) + continue; + var winding1 = Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, x3, y3); + var winding2 = Triangulator.winding(x3, y3, firstX, firstY, secondX, secondY); + if (winding1 == winding && winding2 == winding) { + otherPoly.length = 0; + otherIndices.length = 0; + polygon.push(x3); + polygon.push(y3); + polygonIndices.push(otherLastIndex); + prevPrevX = prevX; + prevPrevY = prevY; + prevX = x3; + prevY = y3; + ii = 0; + } + } + } + for (var i = convexPolygons.length - 1; i >= 0; i--) { + polygon = convexPolygons[i]; + if (polygon.length == 0) { + convexPolygons.splice(i, 1); + this.polygonPool.free(polygon); + polygonIndices = convexPolygonsIndices[i]; + convexPolygonsIndices.splice(i, 1); + this.polygonIndicesPool.free(polygonIndices); + } + } + return convexPolygons; + }; + Triangulator.isConcave = function (index, vertexCount, vertices, indices) { + var previous = indices[(vertexCount + index - 1) % vertexCount] << 1; + var current = indices[index] << 1; + var next = indices[(index + 1) % vertexCount] << 1; + return !this.positiveArea(vertices[previous], vertices[previous + 1], vertices[current], vertices[current + 1], vertices[next], vertices[next + 1]); + }; + Triangulator.positiveArea = function (p1x, p1y, p2x, p2y, p3x, p3y) { + return p1x * (p3y - p2y) + p2x * (p1y - p3y) + p3x * (p2y - p1y) >= 0; + }; + Triangulator.winding = function (p1x, p1y, p2x, p2y, p3x, p3y) { + var px = p2x - p1x, py = p2y - p1y; + return p3x * py - p3y * px + px * p1y - p1x * py >= 0 ? 1 : -1; + }; + return Triangulator; + }()); + spine.Triangulator = Triangulator; +})(spine || (spine = {})); +var spine; +(function (spine) { + var IntSet = (function () { + function IntSet() { + this.array = new Array(); + } + IntSet.prototype.add = function (value) { + var contains = this.contains(value); + this.array[value | 0] = value | 0; + return !contains; + }; + IntSet.prototype.contains = function (value) { + return this.array[value | 0] != undefined; + }; + IntSet.prototype.remove = function (value) { + this.array[value | 0] = undefined; + }; + IntSet.prototype.clear = function () { + this.array.length = 0; + }; + return IntSet; + }()); + spine.IntSet = IntSet; + var Color = (function () { + function Color(r, g, b, a) { + if (r === void 0) { r = 0; } + if (g === void 0) { g = 0; } + if (b === void 0) { b = 0; } + if (a === void 0) { a = 0; } + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + Color.prototype.set = function (r, g, b, a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + this.clamp(); + return this; + }; + Color.prototype.setFromColor = function (c) { + this.r = c.r; + this.g = c.g; + this.b = c.b; + this.a = c.a; + return this; + }; + Color.prototype.setFromString = function (hex) { + hex = hex.charAt(0) == '#' ? hex.substr(1) : hex; + this.r = parseInt(hex.substr(0, 2), 16) / 255.0; + this.g = parseInt(hex.substr(2, 2), 16) / 255.0; + this.b = parseInt(hex.substr(4, 2), 16) / 255.0; + this.a = (hex.length != 8 ? 255 : parseInt(hex.substr(6, 2), 16)) / 255.0; + return this; + }; + Color.prototype.add = function (r, g, b, a) { + this.r += r; + this.g += g; + this.b += b; + this.a += a; + this.clamp(); + return this; + }; + Color.prototype.clamp = function () { + if (this.r < 0) + this.r = 0; + else if (this.r > 1) + this.r = 1; + if (this.g < 0) + this.g = 0; + else if (this.g > 1) + this.g = 1; + if (this.b < 0) + this.b = 0; + else if (this.b > 1) + this.b = 1; + if (this.a < 0) + this.a = 0; + else if (this.a > 1) + this.a = 1; + return this; + }; + Color.rgba8888ToColor = function (color, value) { + color.r = ((value & 0xff000000) >>> 24) / 255; + color.g = ((value & 0x00ff0000) >>> 16) / 255; + color.b = ((value & 0x0000ff00) >>> 8) / 255; + color.a = ((value & 0x000000ff)) / 255; + }; + Color.rgb888ToColor = function (color, value) { + color.r = ((value & 0x00ff0000) >>> 16) / 255; + color.g = ((value & 0x0000ff00) >>> 8) / 255; + color.b = ((value & 0x000000ff)) / 255; + }; + Color.WHITE = new Color(1, 1, 1, 1); + Color.RED = new Color(1, 0, 0, 1); + Color.GREEN = new Color(0, 1, 0, 1); + Color.BLUE = new Color(0, 0, 1, 1); + Color.MAGENTA = new Color(1, 0, 1, 1); + return Color; + }()); + spine.Color = Color; + var MathUtils = (function () { + function MathUtils() { + } + MathUtils.clamp = function (value, min, max) { + if (value < min) + return min; + if (value > max) + return max; + return value; + }; + MathUtils.cosDeg = function (degrees) { + return Math.cos(degrees * MathUtils.degRad); + }; + MathUtils.sinDeg = function (degrees) { + return Math.sin(degrees * MathUtils.degRad); + }; + MathUtils.signum = function (value) { + return value > 0 ? 1 : value < 0 ? -1 : 0; + }; + MathUtils.toInt = function (x) { + return x > 0 ? Math.floor(x) : Math.ceil(x); + }; + MathUtils.cbrt = function (x) { + var y = Math.pow(Math.abs(x), 1 / 3); + return x < 0 ? -y : y; + }; + MathUtils.randomTriangular = function (min, max) { + return MathUtils.randomTriangularWith(min, max, (min + max) * 0.5); + }; + MathUtils.randomTriangularWith = function (min, max, mode) { + var u = Math.random(); + var d = max - min; + if (u <= (mode - min) / d) + return min + Math.sqrt(u * d * (mode - min)); + return max - Math.sqrt((1 - u) * d * (max - mode)); + }; + MathUtils.PI = 3.1415927; + MathUtils.PI2 = MathUtils.PI * 2; + MathUtils.radiansToDegrees = 180 / MathUtils.PI; + MathUtils.radDeg = MathUtils.radiansToDegrees; + MathUtils.degreesToRadians = MathUtils.PI / 180; + MathUtils.degRad = MathUtils.degreesToRadians; + return MathUtils; + }()); + spine.MathUtils = MathUtils; + var Interpolation = (function () { + function Interpolation() { + } + Interpolation.prototype.apply = function (start, end, a) { + return start + (end - start) * this.applyInternal(a); + }; + return Interpolation; + }()); + spine.Interpolation = Interpolation; + var Pow = (function (_super) { + __extends(Pow, _super); + function Pow(power) { + var _this = _super.call(this) || this; + _this.power = 2; + _this.power = power; + return _this; + } + Pow.prototype.applyInternal = function (a) { + if (a <= 0.5) + return Math.pow(a * 2, this.power) / 2; + return Math.pow((a - 1) * 2, this.power) / (this.power % 2 == 0 ? -2 : 2) + 1; + }; + return Pow; + }(Interpolation)); + spine.Pow = Pow; + var PowOut = (function (_super) { + __extends(PowOut, _super); + function PowOut(power) { + return _super.call(this, power) || this; + } + PowOut.prototype.applyInternal = function (a) { + return Math.pow(a - 1, this.power) * (this.power % 2 == 0 ? -1 : 1) + 1; + }; + return PowOut; + }(Pow)); + spine.PowOut = PowOut; + var Utils = (function () { + function Utils() { + } + Utils.arrayCopy = function (source, sourceStart, dest, destStart, numElements) { + for (var i = sourceStart, j = destStart; i < sourceStart + numElements; i++, j++) { + dest[j] = source[i]; + } + }; + Utils.setArraySize = function (array, size, value) { + if (value === void 0) { value = 0; } + var oldSize = array.length; + if (oldSize == size) + return array; + array.length = size; + if (oldSize < size) { + for (var i = oldSize; i < size; i++) + array[i] = value; + } + return array; + }; + Utils.ensureArrayCapacity = function (array, size, value) { + if (value === void 0) { value = 0; } + if (array.length >= size) + return array; + return Utils.setArraySize(array, size, value); + }; + Utils.newArray = function (size, defaultValue) { + var array = new Array(size); + for (var i = 0; i < size; i++) + array[i] = defaultValue; + return array; + }; + Utils.newFloatArray = function (size) { + if (Utils.SUPPORTS_TYPED_ARRAYS) { + return new Float32Array(size); + } + else { + var array = new Array(size); + for (var i = 0; i < array.length; i++) + array[i] = 0; + return array; + } + }; + Utils.newShortArray = function (size) { + if (Utils.SUPPORTS_TYPED_ARRAYS) { + return new Int16Array(size); + } + else { + var array = new Array(size); + for (var i = 0; i < array.length; i++) + array[i] = 0; + return array; + } + }; + Utils.toFloatArray = function (array) { + return Utils.SUPPORTS_TYPED_ARRAYS ? new Float32Array(array) : array; + }; + Utils.toSinglePrecision = function (value) { + return Utils.SUPPORTS_TYPED_ARRAYS ? Math.fround(value) : value; + }; + Utils.webkit602BugfixHelper = function (alpha, blend) { + }; + Utils.contains = function (array, element, identity) { + if (identity === void 0) { identity = true; } + for (var i = 0; i < array.length; i++) { + if (array[i] == element) + return true; + } + return false; + }; + Utils.SUPPORTS_TYPED_ARRAYS = typeof (Float32Array) !== "undefined"; + return Utils; + }()); + spine.Utils = Utils; + var DebugUtils = (function () { + function DebugUtils() { + } + DebugUtils.logBones = function (skeleton) { + for (var i = 0; i < skeleton.bones.length; i++) { + var bone = skeleton.bones[i]; + console.log(bone.data.name + ", " + bone.a + ", " + bone.b + ", " + bone.c + ", " + bone.d + ", " + bone.worldX + ", " + bone.worldY); + } + }; + return DebugUtils; + }()); + spine.DebugUtils = DebugUtils; + var Pool = (function () { + function Pool(instantiator) { + this.items = new Array(); + this.instantiator = instantiator; + } + Pool.prototype.obtain = function () { + return this.items.length > 0 ? this.items.pop() : this.instantiator(); + }; + Pool.prototype.free = function (item) { + if (item.reset) + item.reset(); + this.items.push(item); + }; + Pool.prototype.freeAll = function (items) { + for (var i = 0; i < items.length; i++) { + this.free(items[i]); + } + }; + Pool.prototype.clear = function () { + this.items.length = 0; + }; + return Pool; + }()); + spine.Pool = Pool; + var Vector2 = (function () { + function Vector2(x, y) { + if (x === void 0) { x = 0; } + if (y === void 0) { y = 0; } + this.x = x; + this.y = y; + } + Vector2.prototype.set = function (x, y) { + this.x = x; + this.y = y; + return this; + }; + Vector2.prototype.length = function () { + var x = this.x; + var y = this.y; + return Math.sqrt(x * x + y * y); + }; + Vector2.prototype.normalize = function () { + var len = this.length(); + if (len != 0) { + this.x /= len; + this.y /= len; + } + return this; + }; + return Vector2; + }()); + spine.Vector2 = Vector2; + var TimeKeeper = (function () { + function TimeKeeper() { + this.maxDelta = 0.064; + this.framesPerSecond = 0; + this.delta = 0; + this.totalTime = 0; + this.lastTime = Date.now() / 1000; + this.frameCount = 0; + this.frameTime = 0; + } + TimeKeeper.prototype.update = function () { + var now = Date.now() / 1000; + this.delta = now - this.lastTime; + this.frameTime += this.delta; + this.totalTime += this.delta; + if (this.delta > this.maxDelta) + this.delta = this.maxDelta; + this.lastTime = now; + this.frameCount++; + if (this.frameTime > 1) { + this.framesPerSecond = this.frameCount / this.frameTime; + this.frameTime = 0; + this.frameCount = 0; + } + }; + return TimeKeeper; + }()); + spine.TimeKeeper = TimeKeeper; + var WindowedMean = (function () { + function WindowedMean(windowSize) { + if (windowSize === void 0) { windowSize = 32; } + this.addedValues = 0; + this.lastValue = 0; + this.mean = 0; + this.dirty = true; + this.values = new Array(windowSize); + } + WindowedMean.prototype.hasEnoughData = function () { + return this.addedValues >= this.values.length; + }; + WindowedMean.prototype.addValue = function (value) { + if (this.addedValues < this.values.length) + this.addedValues++; + this.values[this.lastValue++] = value; + if (this.lastValue > this.values.length - 1) + this.lastValue = 0; + this.dirty = true; + }; + WindowedMean.prototype.getMean = function () { + if (this.hasEnoughData()) { + if (this.dirty) { + var mean = 0; + for (var i = 0; i < this.values.length; i++) { + mean += this.values[i]; + } + this.mean = mean / this.values.length; + this.dirty = false; + } + return this.mean; + } + else { + return 0; + } + }; + return WindowedMean; + }()); + spine.WindowedMean = WindowedMean; +})(spine || (spine = {})); +(function () { + if (!Math.fround) { + Math.fround = (function (array) { + return function (x) { + return array[0] = x, array[0]; + }; + })(new Float32Array(1)); + } +})(); +var spine; +(function (spine) { + var Attachment = (function () { + function Attachment(name) { + if (name == null) + throw new Error("name cannot be null."); + this.name = name; + } + return Attachment; + }()); + spine.Attachment = Attachment; + var VertexAttachment = (function (_super) { + __extends(VertexAttachment, _super); + function VertexAttachment(name) { + var _this = _super.call(this, name) || this; + _this.id = (VertexAttachment.nextID++ & 65535) << 11; + _this.worldVerticesLength = 0; + _this.deformAttachment = _this; + return _this; + } + VertexAttachment.prototype.computeWorldVertices = function (slot, start, count, worldVertices, offset, stride) { + count = offset + (count >> 1) * stride; + var skeleton = slot.bone.skeleton; + var deformArray = slot.deform; + var vertices = this.vertices; + var bones = this.bones; + if (bones == null) { + if (deformArray.length > 0) + vertices = deformArray; + var bone = slot.bone; + var x = bone.worldX; + var y = bone.worldY; + var a = bone.a, b = bone.b, c = bone.c, d = bone.d; + for (var v_1 = start, w = offset; w < count; v_1 += 2, w += stride) { + var vx = vertices[v_1], vy = vertices[v_1 + 1]; + worldVertices[w] = vx * a + vy * b + x; + worldVertices[w + 1] = vx * c + vy * d + y; + } + return; + } + var v = 0, skip = 0; + for (var i = 0; i < start; i += 2) { + var n = bones[v]; + v += n + 1; + skip += n; + } + var skeletonBones = skeleton.bones; + if (deformArray.length == 0) { + for (var w = offset, b = skip * 3; w < count; w += stride) { + var wx = 0, wy = 0; + var n = bones[v++]; + n += v; + for (; v < n; v++, b += 3) { + var bone = skeletonBones[bones[v]]; + var vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } + else { + var deform = deformArray; + for (var w = offset, b = skip * 3, f = skip << 1; w < count; w += stride) { + var wx = 0, wy = 0; + var n = bones[v++]; + n += v; + for (; v < n; v++, b += 3, f += 2) { + var bone = skeletonBones[bones[v]]; + var vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } + }; + VertexAttachment.prototype.copyTo = function (attachment) { + if (this.bones != null) { + attachment.bones = new Array(this.bones.length); + spine.Utils.arrayCopy(this.bones, 0, attachment.bones, 0, this.bones.length); + } + else + attachment.bones = null; + if (this.vertices != null) { + attachment.vertices = spine.Utils.newFloatArray(this.vertices.length); + spine.Utils.arrayCopy(this.vertices, 0, attachment.vertices, 0, this.vertices.length); + } + else + attachment.vertices = null; + attachment.worldVerticesLength = this.worldVerticesLength; + attachment.deformAttachment = this.deformAttachment; + }; + VertexAttachment.nextID = 0; + return VertexAttachment; + }(Attachment)); + spine.VertexAttachment = VertexAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var AttachmentType; + (function (AttachmentType) { + AttachmentType[AttachmentType["Region"] = 0] = "Region"; + AttachmentType[AttachmentType["BoundingBox"] = 1] = "BoundingBox"; + AttachmentType[AttachmentType["Mesh"] = 2] = "Mesh"; + AttachmentType[AttachmentType["LinkedMesh"] = 3] = "LinkedMesh"; + AttachmentType[AttachmentType["Path"] = 4] = "Path"; + AttachmentType[AttachmentType["Point"] = 5] = "Point"; + AttachmentType[AttachmentType["Clipping"] = 6] = "Clipping"; + })(AttachmentType = spine.AttachmentType || (spine.AttachmentType = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var BoundingBoxAttachment = (function (_super) { + __extends(BoundingBoxAttachment, _super); + function BoundingBoxAttachment(name) { + var _this = _super.call(this, name) || this; + _this.color = new spine.Color(1, 1, 1, 1); + return _this; + } + BoundingBoxAttachment.prototype.copy = function () { + var copy = new BoundingBoxAttachment(this.name); + this.copyTo(copy); + copy.color.setFromColor(this.color); + return copy; + }; + return BoundingBoxAttachment; + }(spine.VertexAttachment)); + spine.BoundingBoxAttachment = BoundingBoxAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var ClippingAttachment = (function (_super) { + __extends(ClippingAttachment, _super); + function ClippingAttachment(name) { + var _this = _super.call(this, name) || this; + _this.color = new spine.Color(0.2275, 0.2275, 0.8078, 1); + return _this; + } + ClippingAttachment.prototype.copy = function () { + var copy = new ClippingAttachment(this.name); + this.copyTo(copy); + copy.endSlot = this.endSlot; + copy.color.setFromColor(this.color); + return copy; + }; + return ClippingAttachment; + }(spine.VertexAttachment)); + spine.ClippingAttachment = ClippingAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var MeshAttachment = (function (_super) { + __extends(MeshAttachment, _super); + function MeshAttachment(name) { + var _this = _super.call(this, name) || this; + _this.color = new spine.Color(1, 1, 1, 1); + _this.tempColor = new spine.Color(0, 0, 0, 0); + return _this; + } + MeshAttachment.prototype.updateUVs = function () { + var regionUVs = this.regionUVs; + if (this.uvs == null || this.uvs.length != regionUVs.length) + this.uvs = spine.Utils.newFloatArray(regionUVs.length); + var uvs = this.uvs; + var n = this.uvs.length; + var u = this.region.u, v = this.region.v, width = 0, height = 0; + if (this.region instanceof spine.TextureAtlasRegion) { + var region = this.region; + var textureWidth = region.texture.getImage().width, textureHeight = region.texture.getImage().height; + switch (region.degrees) { + case 90: + u -= (region.originalHeight - region.offsetY - region.height) / textureWidth; + v -= (region.originalWidth - region.offsetX - region.width) / textureHeight; + width = region.originalHeight / textureWidth; + height = region.originalWidth / textureHeight; + for (var i = 0; i < n; i += 2) { + uvs[i] = u + regionUVs[i + 1] * width; + uvs[i + 1] = v + (1 - regionUVs[i]) * height; + } + return; + case 180: + u -= (region.originalWidth - region.offsetX - region.width) / textureWidth; + v -= region.offsetY / textureHeight; + width = region.originalWidth / textureWidth; + height = region.originalHeight / textureHeight; + for (var i = 0; i < n; i += 2) { + uvs[i] = u + (1 - regionUVs[i]) * width; + uvs[i + 1] = v + (1 - regionUVs[i + 1]) * height; + } + return; + case 270: + u -= region.offsetY / textureWidth; + v -= region.offsetX / textureHeight; + width = region.originalHeight / textureWidth; + height = region.originalWidth / textureHeight; + for (var i = 0; i < n; i += 2) { + uvs[i] = u + (1 - regionUVs[i + 1]) * width; + uvs[i + 1] = v + regionUVs[i] * height; + } + return; + } + u -= region.offsetX / textureWidth; + v -= (region.originalHeight - region.offsetY - region.height) / textureHeight; + width = region.originalWidth / textureWidth; + height = region.originalHeight / textureHeight; + } + else if (this.region == null) { + u = v = 0; + width = height = 1; + } + else { + width = this.region.u2 - u; + height = this.region.v2 - v; + } + for (var i = 0; i < n; i += 2) { + uvs[i] = u + regionUVs[i] * width; + uvs[i + 1] = v + regionUVs[i + 1] * height; + } + }; + MeshAttachment.prototype.getParentMesh = function () { + return this.parentMesh; + }; + MeshAttachment.prototype.setParentMesh = function (parentMesh) { + this.parentMesh = parentMesh; + if (parentMesh != null) { + this.bones = parentMesh.bones; + this.vertices = parentMesh.vertices; + this.worldVerticesLength = parentMesh.worldVerticesLength; + this.regionUVs = parentMesh.regionUVs; + this.triangles = parentMesh.triangles; + this.hullLength = parentMesh.hullLength; + this.worldVerticesLength = parentMesh.worldVerticesLength; + } + }; + MeshAttachment.prototype.copy = function () { + if (this.parentMesh != null) + return this.newLinkedMesh(); + var copy = new MeshAttachment(this.name); + copy.region = this.region; + copy.path = this.path; + copy.color.setFromColor(this.color); + this.copyTo(copy); + copy.regionUVs = new Array(this.regionUVs.length); + spine.Utils.arrayCopy(this.regionUVs, 0, copy.regionUVs, 0, this.regionUVs.length); + copy.uvs = new Array(this.uvs.length); + spine.Utils.arrayCopy(this.uvs, 0, copy.uvs, 0, this.uvs.length); + copy.triangles = new Array(this.triangles.length); + spine.Utils.arrayCopy(this.triangles, 0, copy.triangles, 0, this.triangles.length); + copy.hullLength = this.hullLength; + if (this.edges != null) { + copy.edges = new Array(this.edges.length); + spine.Utils.arrayCopy(this.edges, 0, copy.edges, 0, this.edges.length); + } + copy.width = this.width; + copy.height = this.height; + return copy; + }; + MeshAttachment.prototype.newLinkedMesh = function () { + var copy = new MeshAttachment(this.name); + copy.region = this.region; + copy.path = this.path; + copy.color.setFromColor(this.color); + copy.deformAttachment = this.deformAttachment; + copy.setParentMesh(this.parentMesh != null ? this.parentMesh : this); + copy.updateUVs(); + return copy; + }; + return MeshAttachment; + }(spine.VertexAttachment)); + spine.MeshAttachment = MeshAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var PathAttachment = (function (_super) { + __extends(PathAttachment, _super); + function PathAttachment(name) { + var _this = _super.call(this, name) || this; + _this.closed = false; + _this.constantSpeed = false; + _this.color = new spine.Color(1, 1, 1, 1); + return _this; + } + PathAttachment.prototype.copy = function () { + var copy = new PathAttachment(this.name); + this.copyTo(copy); + copy.lengths = new Array(this.lengths.length); + spine.Utils.arrayCopy(this.lengths, 0, copy.lengths, 0, this.lengths.length); + copy.closed = closed; + copy.constantSpeed = this.constantSpeed; + copy.color.setFromColor(this.color); + return copy; + }; + return PathAttachment; + }(spine.VertexAttachment)); + spine.PathAttachment = PathAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var PointAttachment = (function (_super) { + __extends(PointAttachment, _super); + function PointAttachment(name) { + var _this = _super.call(this, name) || this; + _this.color = new spine.Color(0.38, 0.94, 0, 1); + return _this; + } + PointAttachment.prototype.computeWorldPosition = function (bone, point) { + point.x = this.x * bone.a + this.y * bone.b + bone.worldX; + point.y = this.x * bone.c + this.y * bone.d + bone.worldY; + return point; + }; + PointAttachment.prototype.computeWorldRotation = function (bone) { + var cos = spine.MathUtils.cosDeg(this.rotation), sin = spine.MathUtils.sinDeg(this.rotation); + var x = cos * bone.a + sin * bone.b; + var y = cos * bone.c + sin * bone.d; + return Math.atan2(y, x) * spine.MathUtils.radDeg; + }; + PointAttachment.prototype.copy = function () { + var copy = new PointAttachment(this.name); + copy.x = this.x; + copy.y = this.y; + copy.rotation = this.rotation; + copy.color.setFromColor(this.color); + return copy; + }; + return PointAttachment; + }(spine.VertexAttachment)); + spine.PointAttachment = PointAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var RegionAttachment = (function (_super) { + __extends(RegionAttachment, _super); + function RegionAttachment(name) { + var _this = _super.call(this, name) || this; + _this.x = 0; + _this.y = 0; + _this.scaleX = 1; + _this.scaleY = 1; + _this.rotation = 0; + _this.width = 0; + _this.height = 0; + _this.color = new spine.Color(1, 1, 1, 1); + _this.offset = spine.Utils.newFloatArray(8); + _this.uvs = spine.Utils.newFloatArray(8); + _this.tempColor = new spine.Color(1, 1, 1, 1); + return _this; + } + RegionAttachment.prototype.updateOffset = function () { + var regionScaleX = this.width / this.region.originalWidth * this.scaleX; + var regionScaleY = this.height / this.region.originalHeight * this.scaleY; + var localX = -this.width / 2 * this.scaleX + this.region.offsetX * regionScaleX; + var localY = -this.height / 2 * this.scaleY + this.region.offsetY * regionScaleY; + var localX2 = localX + this.region.width * regionScaleX; + var localY2 = localY + this.region.height * regionScaleY; + var radians = this.rotation * Math.PI / 180; + var cos = Math.cos(radians); + var sin = Math.sin(radians); + var localXCos = localX * cos + this.x; + var localXSin = localX * sin; + var localYCos = localY * cos + this.y; + var localYSin = localY * sin; + var localX2Cos = localX2 * cos + this.x; + var localX2Sin = localX2 * sin; + var localY2Cos = localY2 * cos + this.y; + var localY2Sin = localY2 * sin; + var offset = this.offset; + offset[RegionAttachment.OX1] = localXCos - localYSin; + offset[RegionAttachment.OY1] = localYCos + localXSin; + offset[RegionAttachment.OX2] = localXCos - localY2Sin; + offset[RegionAttachment.OY2] = localY2Cos + localXSin; + offset[RegionAttachment.OX3] = localX2Cos - localY2Sin; + offset[RegionAttachment.OY3] = localY2Cos + localX2Sin; + offset[RegionAttachment.OX4] = localX2Cos - localYSin; + offset[RegionAttachment.OY4] = localYCos + localX2Sin; + }; + RegionAttachment.prototype.setRegion = function (region) { + this.region = region; + var uvs = this.uvs; + if (region.rotate) { + uvs[2] = region.u; + uvs[3] = region.v2; + uvs[4] = region.u; + uvs[5] = region.v; + uvs[6] = region.u2; + uvs[7] = region.v; + uvs[0] = region.u2; + uvs[1] = region.v2; + } + else { + uvs[0] = region.u; + uvs[1] = region.v2; + uvs[2] = region.u; + uvs[3] = region.v; + uvs[4] = region.u2; + uvs[5] = region.v; + uvs[6] = region.u2; + uvs[7] = region.v2; + } + }; + RegionAttachment.prototype.computeWorldVertices = function (bone, worldVertices, offset, stride) { + var vertexOffset = this.offset; + var x = bone.worldX, y = bone.worldY; + var a = bone.a, b = bone.b, c = bone.c, d = bone.d; + var offsetX = 0, offsetY = 0; + offsetX = vertexOffset[RegionAttachment.OX1]; + offsetY = vertexOffset[RegionAttachment.OY1]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[RegionAttachment.OX2]; + offsetY = vertexOffset[RegionAttachment.OY2]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[RegionAttachment.OX3]; + offsetY = vertexOffset[RegionAttachment.OY3]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[RegionAttachment.OX4]; + offsetY = vertexOffset[RegionAttachment.OY4]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + }; + RegionAttachment.prototype.copy = function () { + var copy = new RegionAttachment(this.name); + copy.region = this.region; + copy.rendererObject = this.rendererObject; + copy.path = this.path; + copy.x = this.x; + copy.y = this.y; + copy.scaleX = this.scaleX; + copy.scaleY = this.scaleY; + copy.rotation = this.rotation; + copy.width = this.width; + copy.height = this.height; + spine.Utils.arrayCopy(this.uvs, 0, copy.uvs, 0, 8); + spine.Utils.arrayCopy(this.offset, 0, copy.offset, 0, 8); + copy.color.setFromColor(this.color); + return copy; + }; + RegionAttachment.OX1 = 0; + RegionAttachment.OY1 = 1; + RegionAttachment.OX2 = 2; + RegionAttachment.OY2 = 3; + RegionAttachment.OX3 = 4; + RegionAttachment.OY3 = 5; + RegionAttachment.OX4 = 6; + RegionAttachment.OY4 = 7; + RegionAttachment.X1 = 0; + RegionAttachment.Y1 = 1; + RegionAttachment.C1R = 2; + RegionAttachment.C1G = 3; + RegionAttachment.C1B = 4; + RegionAttachment.C1A = 5; + RegionAttachment.U1 = 6; + RegionAttachment.V1 = 7; + RegionAttachment.X2 = 8; + RegionAttachment.Y2 = 9; + RegionAttachment.C2R = 10; + RegionAttachment.C2G = 11; + RegionAttachment.C2B = 12; + RegionAttachment.C2A = 13; + RegionAttachment.U2 = 14; + RegionAttachment.V2 = 15; + RegionAttachment.X3 = 16; + RegionAttachment.Y3 = 17; + RegionAttachment.C3R = 18; + RegionAttachment.C3G = 19; + RegionAttachment.C3B = 20; + RegionAttachment.C3A = 21; + RegionAttachment.U3 = 22; + RegionAttachment.V3 = 23; + RegionAttachment.X4 = 24; + RegionAttachment.Y4 = 25; + RegionAttachment.C4R = 26; + RegionAttachment.C4G = 27; + RegionAttachment.C4B = 28; + RegionAttachment.C4A = 29; + RegionAttachment.U4 = 30; + RegionAttachment.V4 = 31; + return RegionAttachment; + }(spine.Attachment)); + spine.RegionAttachment = RegionAttachment; +})(spine || (spine = {})); +var spine; +(function (spine) { + var JitterEffect = (function () { + function JitterEffect(jitterX, jitterY) { + this.jitterX = 0; + this.jitterY = 0; + this.jitterX = jitterX; + this.jitterY = jitterY; + } + JitterEffect.prototype.begin = function (skeleton) { + }; + JitterEffect.prototype.transform = function (position, uv, light, dark) { + position.x += spine.MathUtils.randomTriangular(-this.jitterX, this.jitterY); + position.y += spine.MathUtils.randomTriangular(-this.jitterX, this.jitterY); + }; + JitterEffect.prototype.end = function () { + }; + return JitterEffect; + }()); + spine.JitterEffect = JitterEffect; +})(spine || (spine = {})); +var spine; +(function (spine) { + var SwirlEffect = (function () { + function SwirlEffect(radius) { + this.centerX = 0; + this.centerY = 0; + this.radius = 0; + this.angle = 0; + this.worldX = 0; + this.worldY = 0; + this.radius = radius; + } + SwirlEffect.prototype.begin = function (skeleton) { + this.worldX = skeleton.x + this.centerX; + this.worldY = skeleton.y + this.centerY; + }; + SwirlEffect.prototype.transform = function (position, uv, light, dark) { + var radAngle = this.angle * spine.MathUtils.degreesToRadians; + var x = position.x - this.worldX; + var y = position.y - this.worldY; + var dist = Math.sqrt(x * x + y * y); + if (dist < this.radius) { + var theta = SwirlEffect.interpolation.apply(0, radAngle, (this.radius - dist) / this.radius); + var cos = Math.cos(theta); + var sin = Math.sin(theta); + position.x = cos * x - sin * y + this.worldX; + position.y = sin * x + cos * y + this.worldY; + } + }; + SwirlEffect.prototype.end = function () { + }; + SwirlEffect.interpolation = new spine.PowOut(2); + return SwirlEffect; + }()); + spine.SwirlEffect = SwirlEffect; +})(spine || (spine = {})); +var spine; +(function (spine) { + var canvas; + (function (canvas) { + var AssetManager = (function (_super) { + __extends(AssetManager, _super); + function AssetManager(pathPrefix) { + if (pathPrefix === void 0) { pathPrefix = ""; } + return _super.call(this, function (image) { return new spine.canvas.CanvasTexture(image); }, pathPrefix) || this; + } + return AssetManager; + }(spine.AssetManager)); + canvas.AssetManager = AssetManager; + })(canvas = spine.canvas || (spine.canvas = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var canvas; + (function (canvas) { + var CanvasTexture = (function (_super) { + __extends(CanvasTexture, _super); + function CanvasTexture(image) { + return _super.call(this, image) || this; + } + CanvasTexture.prototype.setFilters = function (minFilter, magFilter) { }; + CanvasTexture.prototype.setWraps = function (uWrap, vWrap) { }; + CanvasTexture.prototype.dispose = function () { }; + return CanvasTexture; + }(spine.Texture)); + canvas.CanvasTexture = CanvasTexture; + })(canvas = spine.canvas || (spine.canvas = {})); +})(spine || (spine = {})); +var spine; +(function (spine) { + var canvas; + (function (canvas) { + var SkeletonRenderer = (function () { + function SkeletonRenderer(context) { + this.triangleRendering = false; + this.debugRendering = false; + this.vertices = spine.Utils.newFloatArray(8 * 1024); + this.tempColor = new spine.Color(); + this.ctx = context; + } + SkeletonRenderer.prototype.draw = function (skeleton) { + if (this.triangleRendering) + this.drawTriangles(skeleton); + else + this.drawImages(skeleton); + }; + SkeletonRenderer.prototype.drawImages = function (skeleton) { + var ctx = this.ctx; + var drawOrder = skeleton.drawOrder; + if (this.debugRendering) + ctx.strokeStyle = "green"; + ctx.save(); + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + if (!slot.bone.active) + continue; + var attachment = slot.getAttachment(); + var regionAttachment = null; + var region = null; + var image = null; + if (attachment instanceof spine.RegionAttachment) { + regionAttachment = attachment; + region = regionAttachment.region; + image = region.texture.getImage(); + } + else + continue; + var skeleton_1 = slot.bone.skeleton; + var skeletonColor = skeleton_1.color; + var slotColor = slot.color; + var regionColor = regionAttachment.color; + var alpha = skeletonColor.a * slotColor.a * regionColor.a; + var color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * regionColor.r, skeletonColor.g * slotColor.g * regionColor.g, skeletonColor.b * slotColor.b * regionColor.b, alpha); + var att = attachment; + var bone = slot.bone; + var w = region.width; + var h = region.height; + ctx.save(); + ctx.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY); + ctx.translate(attachment.offset[0], attachment.offset[1]); + ctx.rotate(attachment.rotation * Math.PI / 180); + var atlasScale = att.width / w; + ctx.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY); + ctx.translate(w / 2, h / 2); + if (attachment.region.rotate) { + var t = w; + w = h; + h = t; + ctx.rotate(-Math.PI / 2); + } + ctx.scale(1, -1); + ctx.translate(-w / 2, -h / 2); + ctx.globalAlpha = color.a; + ctx.drawImage(image, region.x, region.y, w, h, 0, 0, w, h); + if (this.debugRendering) + ctx.strokeRect(0, 0, w, h); + ctx.restore(); + } + ctx.restore(); + }; + SkeletonRenderer.prototype.drawTriangles = function (skeleton) { + var blendMode = null; + var vertices = this.vertices; + var triangles = null; + var drawOrder = skeleton.drawOrder; + for (var i = 0, n = drawOrder.length; i < n; i++) { + var slot = drawOrder[i]; + var attachment = slot.getAttachment(); + var texture = null; + var region = null; + if (attachment instanceof spine.RegionAttachment) { + var regionAttachment = attachment; + vertices = this.computeRegionVertices(slot, regionAttachment, false); + triangles = SkeletonRenderer.QUAD_TRIANGLES; + region = regionAttachment.region; + texture = region.texture.getImage(); + } + else if (attachment instanceof spine.MeshAttachment) { + var mesh = attachment; + vertices = this.computeMeshVertices(slot, mesh, false); + triangles = mesh.triangles; + texture = mesh.region.renderObject.texture.getImage(); + } + else + continue; + if (texture != null) { + var slotBlendMode = slot.data.blendMode; + if (slotBlendMode != blendMode) { + blendMode = slotBlendMode; + } + var skeleton_2 = slot.bone.skeleton; + var skeletonColor = skeleton_2.color; + var slotColor = slot.color; + var attachmentColor = attachment.color; + var alpha = skeletonColor.a * slotColor.a * attachmentColor.a; + var color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * attachmentColor.r, skeletonColor.g * slotColor.g * attachmentColor.g, skeletonColor.b * slotColor.b * attachmentColor.b, alpha); + var ctx = this.ctx; + ctx.globalAlpha = color.a; + for (var j = 0; j < triangles.length; j += 3) { + var t1 = triangles[j] * 8, t2 = triangles[j + 1] * 8, t3 = triangles[j + 2] * 8; + var x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7]; + var x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7]; + var x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7]; + this.drawTriangle(texture, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2); + if (this.debugRendering) { + ctx.strokeStyle = "green"; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.lineTo(x0, y0); + ctx.stroke(); + } + } + } + } + this.ctx.globalAlpha = 1; + }; + SkeletonRenderer.prototype.drawTriangle = function (img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2) { + var ctx = this.ctx; + u0 *= img.width; + v0 *= img.height; + u1 *= img.width; + v1 *= img.height; + u2 *= img.width; + v2 *= img.height; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.closePath(); + x1 -= x0; + y1 -= y0; + x2 -= x0; + y2 -= y0; + u1 -= u0; + v1 -= v0; + u2 -= u0; + v2 -= v0; + var det = 1 / (u1 * v2 - u2 * v1), a = (v2 * x1 - v1 * x2) * det, b = (v2 * y1 - v1 * y2) * det, c = (u1 * x2 - u2 * x1) * det, d = (u1 * y2 - u2 * y1) * det, e = x0 - a * u0 - c * v0, f = y0 - b * u0 - d * v0; + ctx.save(); + ctx.transform(a, b, c, d, e, f); + ctx.clip(); + ctx.drawImage(img, 0, 0); + ctx.restore(); + }; + SkeletonRenderer.prototype.computeRegionVertices = function (slot, region, pma) { + var skeleton = slot.bone.skeleton; + var skeletonColor = skeleton.color; + var slotColor = slot.color; + var regionColor = region.color; + var alpha = skeletonColor.a * slotColor.a * regionColor.a; + var multiplier = pma ? alpha : 1; + var color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier, skeletonColor.g * slotColor.g * regionColor.g * multiplier, skeletonColor.b * slotColor.b * regionColor.b * multiplier, alpha); + region.computeWorldVertices(slot.bone, this.vertices, 0, SkeletonRenderer.VERTEX_SIZE); + var vertices = this.vertices; + var uvs = region.uvs; + vertices[spine.RegionAttachment.C1R] = color.r; + vertices[spine.RegionAttachment.C1G] = color.g; + vertices[spine.RegionAttachment.C1B] = color.b; + vertices[spine.RegionAttachment.C1A] = color.a; + vertices[spine.RegionAttachment.U1] = uvs[0]; + vertices[spine.RegionAttachment.V1] = uvs[1]; + vertices[spine.RegionAttachment.C2R] = color.r; + vertices[spine.RegionAttachment.C2G] = color.g; + vertices[spine.RegionAttachment.C2B] = color.b; + vertices[spine.RegionAttachment.C2A] = color.a; + vertices[spine.RegionAttachment.U2] = uvs[2]; + vertices[spine.RegionAttachment.V2] = uvs[3]; + vertices[spine.RegionAttachment.C3R] = color.r; + vertices[spine.RegionAttachment.C3G] = color.g; + vertices[spine.RegionAttachment.C3B] = color.b; + vertices[spine.RegionAttachment.C3A] = color.a; + vertices[spine.RegionAttachment.U3] = uvs[4]; + vertices[spine.RegionAttachment.V3] = uvs[5]; + vertices[spine.RegionAttachment.C4R] = color.r; + vertices[spine.RegionAttachment.C4G] = color.g; + vertices[spine.RegionAttachment.C4B] = color.b; + vertices[spine.RegionAttachment.C4A] = color.a; + vertices[spine.RegionAttachment.U4] = uvs[6]; + vertices[spine.RegionAttachment.V4] = uvs[7]; + return vertices; + }; + SkeletonRenderer.prototype.computeMeshVertices = function (slot, mesh, pma) { + var skeleton = slot.bone.skeleton; + var skeletonColor = skeleton.color; + var slotColor = slot.color; + var regionColor = mesh.color; + var alpha = skeletonColor.a * slotColor.a * regionColor.a; + var multiplier = pma ? alpha : 1; + var color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier, skeletonColor.g * slotColor.g * regionColor.g * multiplier, skeletonColor.b * slotColor.b * regionColor.b * multiplier, alpha); + var numVertices = mesh.worldVerticesLength / 2; + if (this.vertices.length < mesh.worldVerticesLength) { + this.vertices = spine.Utils.newFloatArray(mesh.worldVerticesLength); + } + var vertices = this.vertices; + mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, SkeletonRenderer.VERTEX_SIZE); + var uvs = mesh.uvs; + for (var i = 0, n = numVertices, u = 0, v = 2; i < n; i++) { + vertices[v++] = color.r; + vertices[v++] = color.g; + vertices[v++] = color.b; + vertices[v++] = color.a; + vertices[v++] = uvs[u++]; + vertices[v++] = uvs[u++]; + v += 2; + } + return vertices; + }; + SkeletonRenderer.QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; + SkeletonRenderer.VERTEX_SIZE = 2 + 2 + 4; + return SkeletonRenderer; + }()); + canvas.SkeletonRenderer = SkeletonRenderer; + })(canvas = spine.canvas || (spine.canvas = {})); +})(spine || (spine = {})); +//# sourceMappingURL=spine-canvas.js.map \ No newline at end of file diff --git a/lib/4.0/spine-canvas.js b/lib/4.0/spine-canvas.js new file mode 100644 index 0000000..a62bb5f --- /dev/null +++ b/lib/4.0/spine-canvas.js @@ -0,0 +1,9066 @@ +var spine = (() => { + var __defProp = Object.defineProperty; + var __markAsModule = (target) => __defProp(target, "__esModule", { value: true }); + var __export = (target, all) => { + __markAsModule(target); + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); + }; + + // spine-canvas/src/index.ts + var src_exports = {}; + __export(src_exports, { + AlphaTimeline: () => AlphaTimeline, + Animation: () => Animation, + AnimationState: () => AnimationState, + AnimationStateAdapter: () => AnimationStateAdapter, + AnimationStateData: () => AnimationStateData, + AssetManager: () => AssetManager, + AssetManagerBase: () => AssetManagerBase, + AtlasAttachmentLoader: () => AtlasAttachmentLoader, + Attachment: () => Attachment, + AttachmentTimeline: () => AttachmentTimeline, + BinaryInput: () => BinaryInput, + BlendMode: () => BlendMode, + Bone: () => Bone, + BoneData: () => BoneData, + BoundingBoxAttachment: () => BoundingBoxAttachment, + CURRENT: () => CURRENT, + CanvasTexture: () => CanvasTexture, + ClippingAttachment: () => ClippingAttachment, + Color: () => Color, + ConstraintData: () => ConstraintData, + CurveTimeline: () => CurveTimeline, + CurveTimeline1: () => CurveTimeline1, + CurveTimeline2: () => CurveTimeline2, + DebugUtils: () => DebugUtils, + DeformTimeline: () => DeformTimeline, + Downloader: () => Downloader, + DrawOrderTimeline: () => DrawOrderTimeline, + Event: () => Event, + EventData: () => EventData, + EventQueue: () => EventQueue, + EventTimeline: () => EventTimeline, + EventType: () => EventType, + FIRST: () => FIRST, + FakeTexture: () => FakeTexture, + HOLD_FIRST: () => HOLD_FIRST, + HOLD_MIX: () => HOLD_MIX, + HOLD_SUBSEQUENT: () => HOLD_SUBSEQUENT, + IkConstraint: () => IkConstraint, + IkConstraintData: () => IkConstraintData, + IkConstraintTimeline: () => IkConstraintTimeline, + IntSet: () => IntSet, + Interpolation: () => Interpolation, + JitterEffect: () => JitterEffect, + MathUtils: () => MathUtils, + MeshAttachment: () => MeshAttachment, + MixBlend: () => MixBlend, + MixDirection: () => MixDirection, + PathAttachment: () => PathAttachment, + PathConstraint: () => PathConstraint, + PathConstraintData: () => PathConstraintData, + PathConstraintMixTimeline: () => PathConstraintMixTimeline, + PathConstraintPositionTimeline: () => PathConstraintPositionTimeline, + PathConstraintSpacingTimeline: () => PathConstraintSpacingTimeline, + PointAttachment: () => PointAttachment, + Pool: () => Pool, + PositionMode: () => PositionMode, + Pow: () => Pow, + PowOut: () => PowOut, + RGB2Timeline: () => RGB2Timeline, + RGBA2Timeline: () => RGBA2Timeline, + RGBATimeline: () => RGBATimeline, + RGBTimeline: () => RGBTimeline, + RegionAttachment: () => RegionAttachment, + RotateMode: () => RotateMode, + RotateTimeline: () => RotateTimeline, + SETUP: () => SETUP, + SUBSEQUENT: () => SUBSEQUENT, + ScaleTimeline: () => ScaleTimeline, + ScaleXTimeline: () => ScaleXTimeline, + ScaleYTimeline: () => ScaleYTimeline, + ShearTimeline: () => ShearTimeline, + ShearXTimeline: () => ShearXTimeline, + ShearYTimeline: () => ShearYTimeline, + Skeleton: () => Skeleton, + SkeletonBinary: () => SkeletonBinary, + SkeletonBounds: () => SkeletonBounds, + SkeletonClipping: () => SkeletonClipping, + SkeletonData: () => SkeletonData, + SkeletonJson: () => SkeletonJson, + SkeletonRenderer: () => SkeletonRenderer, + Skin: () => Skin, + SkinEntry: () => SkinEntry, + Slot: () => Slot, + SlotData: () => SlotData, + SpacingMode: () => SpacingMode, + StringSet: () => StringSet, + SwirlEffect: () => SwirlEffect, + Texture: () => Texture, + TextureAtlas: () => TextureAtlas, + TextureAtlasPage: () => TextureAtlasPage, + TextureAtlasRegion: () => TextureAtlasRegion, + TextureFilter: () => TextureFilter, + TextureRegion: () => TextureRegion, + TextureWrap: () => TextureWrap, + TimeKeeper: () => TimeKeeper, + Timeline: () => Timeline, + TrackEntry: () => TrackEntry, + TransformConstraint: () => TransformConstraint, + TransformConstraintData: () => TransformConstraintData, + TransformConstraintTimeline: () => TransformConstraintTimeline, + TransformMode: () => TransformMode, + TranslateTimeline: () => TranslateTimeline, + TranslateXTimeline: () => TranslateXTimeline, + TranslateYTimeline: () => TranslateYTimeline, + Triangulator: () => Triangulator, + Utils: () => Utils, + Vector2: () => Vector2, + VertexAttachment: () => VertexAttachment, + WindowedMean: () => WindowedMean + }); + + // spine-core/src/Utils.ts + var IntSet = class { + constructor() { + this.array = new Array(); + } + add(value) { + let contains = this.contains(value); + this.array[value | 0] = value | 0; + return !contains; + } + contains(value) { + return this.array[value | 0] != void 0; + } + remove(value) { + this.array[value | 0] = void 0; + } + clear() { + this.array.length = 0; + } + }; + var StringSet = class { + constructor() { + this.entries = {}; + this.size = 0; + } + add(value) { + let contains = this.entries[value]; + this.entries[value] = true; + if (!contains) { + this.size++; + return true; + } + return false; + } + addAll(values) { + let oldSize = this.size; + for (var i = 0, n = values.length; i < n; i++) + this.add(values[i]); + return oldSize != this.size; + } + contains(value) { + return this.entries[value]; + } + clear() { + this.entries = {}; + this.size = 0; + } + }; + var _Color = class { + constructor(r = 0, g = 0, b = 0, a = 0) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + set(r, g, b, a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + return this.clamp(); + } + setFromColor(c) { + this.r = c.r; + this.g = c.g; + this.b = c.b; + this.a = c.a; + return this; + } + setFromString(hex) { + hex = hex.charAt(0) == "#" ? hex.substr(1) : hex; + this.r = parseInt(hex.substr(0, 2), 16) / 255; + this.g = parseInt(hex.substr(2, 2), 16) / 255; + this.b = parseInt(hex.substr(4, 2), 16) / 255; + this.a = hex.length != 8 ? 1 : parseInt(hex.substr(6, 2), 16) / 255; + return this; + } + add(r, g, b, a) { + this.r += r; + this.g += g; + this.b += b; + this.a += a; + return this.clamp(); + } + clamp() { + if (this.r < 0) + this.r = 0; + else if (this.r > 1) + this.r = 1; + if (this.g < 0) + this.g = 0; + else if (this.g > 1) + this.g = 1; + if (this.b < 0) + this.b = 0; + else if (this.b > 1) + this.b = 1; + if (this.a < 0) + this.a = 0; + else if (this.a > 1) + this.a = 1; + return this; + } + static rgba8888ToColor(color, value) { + color.r = ((value & 4278190080) >>> 24) / 255; + color.g = ((value & 16711680) >>> 16) / 255; + color.b = ((value & 65280) >>> 8) / 255; + color.a = (value & 255) / 255; + } + static rgb888ToColor(color, value) { + color.r = ((value & 16711680) >>> 16) / 255; + color.g = ((value & 65280) >>> 8) / 255; + color.b = (value & 255) / 255; + } + static fromString(hex) { + return new _Color().setFromString(hex); + } + }; + var Color = _Color; + Color.WHITE = new _Color(1, 1, 1, 1); + Color.RED = new _Color(1, 0, 0, 1); + Color.GREEN = new _Color(0, 1, 0, 1); + Color.BLUE = new _Color(0, 0, 1, 1); + Color.MAGENTA = new _Color(1, 0, 1, 1); + var _MathUtils = class { + static clamp(value, min, max) { + if (value < min) + return min; + if (value > max) + return max; + return value; + } + static cosDeg(degrees) { + return Math.cos(degrees * _MathUtils.degRad); + } + static sinDeg(degrees) { + return Math.sin(degrees * _MathUtils.degRad); + } + static signum(value) { + return value > 0 ? 1 : value < 0 ? -1 : 0; + } + static toInt(x) { + return x > 0 ? Math.floor(x) : Math.ceil(x); + } + static cbrt(x) { + let y = Math.pow(Math.abs(x), 1 / 3); + return x < 0 ? -y : y; + } + static randomTriangular(min, max) { + return _MathUtils.randomTriangularWith(min, max, (min + max) * 0.5); + } + static randomTriangularWith(min, max, mode) { + let u = Math.random(); + let d = max - min; + if (u <= (mode - min) / d) + return min + Math.sqrt(u * d * (mode - min)); + return max - Math.sqrt((1 - u) * d * (max - mode)); + } + static isPowerOfTwo(value) { + return value && (value & value - 1) === 0; + } + }; + var MathUtils = _MathUtils; + MathUtils.PI = 3.1415927; + MathUtils.PI2 = _MathUtils.PI * 2; + MathUtils.radiansToDegrees = 180 / _MathUtils.PI; + MathUtils.radDeg = _MathUtils.radiansToDegrees; + MathUtils.degreesToRadians = _MathUtils.PI / 180; + MathUtils.degRad = _MathUtils.degreesToRadians; + var Interpolation = class { + apply(start, end, a) { + return start + (end - start) * this.applyInternal(a); + } + }; + var Pow = class extends Interpolation { + constructor(power) { + super(); + this.power = 2; + this.power = power; + } + applyInternal(a) { + if (a <= 0.5) + return Math.pow(a * 2, this.power) / 2; + return Math.pow((a - 1) * 2, this.power) / (this.power % 2 == 0 ? -2 : 2) + 1; + } + }; + var PowOut = class extends Pow { + constructor(power) { + super(power); + } + applyInternal(a) { + return Math.pow(a - 1, this.power) * (this.power % 2 == 0 ? -1 : 1) + 1; + } + }; + var _Utils = class { + static arrayCopy(source, sourceStart, dest, destStart, numElements) { + for (let i = sourceStart, j = destStart; i < sourceStart + numElements; i++, j++) { + dest[j] = source[i]; + } + } + static arrayFill(array, fromIndex, toIndex, value) { + for (let i = fromIndex; i < toIndex; i++) + array[i] = value; + } + static setArraySize(array, size, value = 0) { + let oldSize = array.length; + if (oldSize == size) + return array; + array.length = size; + if (oldSize < size) { + for (let i = oldSize; i < size; i++) + array[i] = value; + } + return array; + } + static ensureArrayCapacity(array, size, value = 0) { + if (array.length >= size) + return array; + return _Utils.setArraySize(array, size, value); + } + static newArray(size, defaultValue) { + let array = new Array(size); + for (let i = 0; i < size; i++) + array[i] = defaultValue; + return array; + } + static newFloatArray(size) { + if (_Utils.SUPPORTS_TYPED_ARRAYS) + return new Float32Array(size); + else { + let array = new Array(size); + for (let i = 0; i < array.length; i++) + array[i] = 0; + return array; + } + } + static newShortArray(size) { + if (_Utils.SUPPORTS_TYPED_ARRAYS) + return new Int16Array(size); + else { + let array = new Array(size); + for (let i = 0; i < array.length; i++) + array[i] = 0; + return array; + } + } + static toFloatArray(array) { + return _Utils.SUPPORTS_TYPED_ARRAYS ? new Float32Array(array) : array; + } + static toSinglePrecision(value) { + return _Utils.SUPPORTS_TYPED_ARRAYS ? Math.fround(value) : value; + } + static webkit602BugfixHelper(alpha, blend) { + } + static contains(array, element, identity = true) { + for (var i = 0; i < array.length; i++) + if (array[i] == element) + return true; + return false; + } + static enumValue(type, name) { + return type[name[0].toUpperCase() + name.slice(1)]; + } + }; + var Utils = _Utils; + Utils.SUPPORTS_TYPED_ARRAYS = typeof Float32Array !== "undefined"; + var DebugUtils = class { + static logBones(skeleton) { + for (let i = 0; i < skeleton.bones.length; i++) { + let bone = skeleton.bones[i]; + console.log(bone.data.name + ", " + bone.a + ", " + bone.b + ", " + bone.c + ", " + bone.d + ", " + bone.worldX + ", " + bone.worldY); + } + } + }; + var Pool = class { + constructor(instantiator) { + this.items = new Array(); + this.instantiator = instantiator; + } + obtain() { + return this.items.length > 0 ? this.items.pop() : this.instantiator(); + } + free(item) { + if (item.reset) + item.reset(); + this.items.push(item); + } + freeAll(items) { + for (let i = 0; i < items.length; i++) + this.free(items[i]); + } + clear() { + this.items.length = 0; + } + }; + var Vector2 = class { + constructor(x = 0, y = 0) { + this.x = x; + this.y = y; + } + set(x, y) { + this.x = x; + this.y = y; + return this; + } + length() { + let x = this.x; + let y = this.y; + return Math.sqrt(x * x + y * y); + } + normalize() { + let len = this.length(); + if (len != 0) { + this.x /= len; + this.y /= len; + } + return this; + } + }; + var TimeKeeper = class { + constructor() { + this.maxDelta = 0.064; + this.framesPerSecond = 0; + this.delta = 0; + this.totalTime = 0; + this.lastTime = Date.now() / 1e3; + this.frameCount = 0; + this.frameTime = 0; + } + update() { + let now = Date.now() / 1e3; + this.delta = now - this.lastTime; + this.frameTime += this.delta; + this.totalTime += this.delta; + if (this.delta > this.maxDelta) + this.delta = this.maxDelta; + this.lastTime = now; + this.frameCount++; + if (this.frameTime > 1) { + this.framesPerSecond = this.frameCount / this.frameTime; + this.frameTime = 0; + this.frameCount = 0; + } + } + }; + var WindowedMean = class { + constructor(windowSize = 32) { + this.addedValues = 0; + this.lastValue = 0; + this.mean = 0; + this.dirty = true; + this.values = new Array(windowSize); + } + hasEnoughData() { + return this.addedValues >= this.values.length; + } + addValue(value) { + if (this.addedValues < this.values.length) + this.addedValues++; + this.values[this.lastValue++] = value; + if (this.lastValue > this.values.length - 1) + this.lastValue = 0; + this.dirty = true; + } + getMean() { + if (this.hasEnoughData()) { + if (this.dirty) { + let mean = 0; + for (let i = 0; i < this.values.length; i++) + mean += this.values[i]; + this.mean = mean / this.values.length; + this.dirty = false; + } + return this.mean; + } + return 0; + } + }; + + // spine-core/src/attachments/Attachment.ts + var Attachment = class { + constructor(name) { + if (!name) + throw new Error("name cannot be null."); + this.name = name; + } + }; + var _VertexAttachment = class extends Attachment { + constructor(name) { + super(name); + this.id = _VertexAttachment.nextID++; + this.bones = null; + this.vertices = null; + this.worldVerticesLength = 0; + this.deformAttachment = this; + } + computeWorldVertices(slot, start, count, worldVertices, offset, stride) { + count = offset + (count >> 1) * stride; + let skeleton = slot.bone.skeleton; + let deformArray = slot.deform; + let vertices = this.vertices; + let bones = this.bones; + if (!bones) { + if (deformArray.length > 0) + vertices = deformArray; + let bone = slot.bone; + let x = bone.worldX; + let y = bone.worldY; + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + for (let v2 = start, w = offset; w < count; v2 += 2, w += stride) { + let vx = vertices[v2], vy = vertices[v2 + 1]; + worldVertices[w] = vx * a + vy * b + x; + worldVertices[w + 1] = vx * c + vy * d + y; + } + return; + } + let v = 0, skip = 0; + for (let i = 0; i < start; i += 2) { + let n = bones[v]; + v += n + 1; + skip += n; + } + let skeletonBones = skeleton.bones; + if (deformArray.length == 0) { + for (let w = offset, b = skip * 3; w < count; w += stride) { + let wx = 0, wy = 0; + let n = bones[v++]; + n += v; + for (; v < n; v++, b += 3) { + let bone = skeletonBones[bones[v]]; + let vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } else { + let deform = deformArray; + for (let w = offset, b = skip * 3, f = skip << 1; w < count; w += stride) { + let wx = 0, wy = 0; + let n = bones[v++]; + n += v; + for (; v < n; v++, b += 3, f += 2) { + let bone = skeletonBones[bones[v]]; + let vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices[w] = wx; + worldVertices[w + 1] = wy; + } + } + } + copyTo(attachment) { + if (this.bones) { + attachment.bones = new Array(this.bones.length); + Utils.arrayCopy(this.bones, 0, attachment.bones, 0, this.bones.length); + } else + attachment.bones = null; + if (this.vertices) { + attachment.vertices = Utils.newFloatArray(this.vertices.length); + Utils.arrayCopy(this.vertices, 0, attachment.vertices, 0, this.vertices.length); + } else + attachment.vertices = null; + attachment.worldVerticesLength = this.worldVerticesLength; + attachment.deformAttachment = this.deformAttachment; + } + }; + var VertexAttachment = _VertexAttachment; + VertexAttachment.nextID = 0; + + // spine-core/src/Animation.ts + var Animation = class { + constructor(name, timelines, duration) { + this.timelines = null; + this.timelineIds = null; + if (!name) + throw new Error("name cannot be null."); + this.name = name; + this.setTimelines(timelines); + this.duration = duration; + } + setTimelines(timelines) { + if (!timelines) + throw new Error("timelines cannot be null."); + this.timelines = timelines; + this.timelineIds = new StringSet(); + for (var i = 0; i < timelines.length; i++) + this.timelineIds.addAll(timelines[i].getPropertyIds()); + } + hasTimeline(ids) { + for (let i = 0; i < ids.length; i++) + if (this.timelineIds.contains(ids[i])) + return true; + return false; + } + apply(skeleton, lastTime, time, loop, events, alpha, blend, direction) { + if (!skeleton) + throw new Error("skeleton cannot be null."); + if (loop && this.duration != 0) { + time %= this.duration; + if (lastTime > 0) + lastTime %= this.duration; + } + let timelines = this.timelines; + for (let i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, lastTime, time, events, alpha, blend, direction); + } + }; + var MixBlend; + (function(MixBlend2) { + MixBlend2[MixBlend2["setup"] = 0] = "setup"; + MixBlend2[MixBlend2["first"] = 1] = "first"; + MixBlend2[MixBlend2["replace"] = 2] = "replace"; + MixBlend2[MixBlend2["add"] = 3] = "add"; + })(MixBlend || (MixBlend = {})); + var MixDirection; + (function(MixDirection2) { + MixDirection2[MixDirection2["mixIn"] = 0] = "mixIn"; + MixDirection2[MixDirection2["mixOut"] = 1] = "mixOut"; + })(MixDirection || (MixDirection = {})); + var Property = { + rotate: 0, + x: 1, + y: 2, + scaleX: 3, + scaleY: 4, + shearX: 5, + shearY: 6, + rgb: 7, + alpha: 8, + rgb2: 9, + attachment: 10, + deform: 11, + event: 12, + drawOrder: 13, + ikConstraint: 14, + transformConstraint: 15, + pathConstraintPosition: 16, + pathConstraintSpacing: 17, + pathConstraintMix: 18 + }; + var Timeline = class { + constructor(frameCount, propertyIds) { + this.propertyIds = null; + this.frames = null; + this.propertyIds = propertyIds; + this.frames = Utils.newFloatArray(frameCount * this.getFrameEntries()); + } + getPropertyIds() { + return this.propertyIds; + } + getFrameEntries() { + return 1; + } + getFrameCount() { + return this.frames.length / this.getFrameEntries(); + } + getDuration() { + return this.frames[this.frames.length - this.getFrameEntries()]; + } + static search1(frames, time) { + let n = frames.length; + for (let i = 1; i < n; i++) + if (frames[i] > time) + return i - 1; + return n - 1; + } + static search(frames, time, step) { + let n = frames.length; + for (let i = step; i < n; i += step) + if (frames[i] > time) + return i - step; + return n - step; + } + }; + var CurveTimeline = class extends Timeline { + constructor(frameCount, bezierCount, propertyIds) { + super(frameCount, propertyIds); + this.curves = null; + this.curves = Utils.newFloatArray(frameCount + bezierCount * 18); + this.curves[frameCount - 1] = 1; + } + setLinear(frame) { + this.curves[frame] = 0; + } + setStepped(frame) { + this.curves[frame] = 1; + } + shrink(bezierCount) { + let size = this.getFrameCount() + bezierCount * 18; + if (this.curves.length > size) { + let newCurves = Utils.newFloatArray(size); + Utils.arrayCopy(this.curves, 0, newCurves, 0, size); + this.curves = newCurves; + } + } + setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2) { + let curves = this.curves; + let i = this.getFrameCount() + bezier * 18; + if (value == 0) + curves[frame] = 2 + i; + let tmpx = (time1 - cx1 * 2 + cx2) * 0.03, tmpy = (value1 - cy1 * 2 + cy2) * 0.03; + let dddx = ((cx1 - cx2) * 3 - time1 + time2) * 6e-3, dddy = ((cy1 - cy2) * 3 - value1 + value2) * 6e-3; + let ddx = tmpx * 2 + dddx, ddy = tmpy * 2 + dddy; + let dx = (cx1 - time1) * 0.3 + tmpx + dddx * 0.16666667, dy = (cy1 - value1) * 0.3 + tmpy + dddy * 0.16666667; + let x = time1 + dx, y = value1 + dy; + for (let n = i + 18; i < n; i += 2) { + curves[i] = x; + curves[i + 1] = y; + dx += ddx; + dy += ddy; + ddx += dddx; + ddy += dddy; + x += dx; + y += dy; + } + } + getBezierValue(time, frameIndex, valueOffset, i) { + let curves = this.curves; + if (curves[i] > time) { + let x2 = this.frames[frameIndex], y2 = this.frames[frameIndex + valueOffset]; + return y2 + (time - x2) / (curves[i] - x2) * (curves[i + 1] - y2); + } + let n = i + 18; + for (i += 2; i < n; i += 2) { + if (curves[i] >= time) { + let x2 = curves[i - 2], y2 = curves[i - 1]; + return y2 + (time - x2) / (curves[i] - x2) * (curves[i + 1] - y2); + } + } + frameIndex += this.getFrameEntries(); + let x = curves[n - 2], y = curves[n - 1]; + return y + (time - x) / (this.frames[frameIndex] - x) * (this.frames[frameIndex + valueOffset] - y); + } + }; + var CurveTimeline1 = class extends CurveTimeline { + constructor(frameCount, bezierCount, propertyId) { + super(frameCount, bezierCount, [propertyId]); + } + getFrameEntries() { + return 2; + } + setFrame(frame, time, value) { + frame <<= 1; + this.frames[frame] = time; + this.frames[frame + 1] = value; + } + getCurveValue(time) { + let frames = this.frames; + let i = frames.length - 2; + for (let ii = 2; ii <= i; ii += 2) { + if (frames[ii] > time) { + i = ii - 2; + break; + } + } + let curveType = this.curves[i >> 1]; + switch (curveType) { + case 0: + let before = frames[i], value = frames[i + 1]; + return value + (time - before) / (frames[i + 2] - before) * (frames[i + 2 + 1] - value); + case 1: + return frames[i + 1]; + } + return this.getBezierValue(time, i, 1, curveType - 2); + } + }; + var CurveTimeline2 = class extends CurveTimeline { + constructor(frameCount, bezierCount, propertyId1, propertyId2) { + super(frameCount, bezierCount, [propertyId1, propertyId2]); + } + getFrameEntries() { + return 3; + } + setFrame(frame, time, value1, value2) { + frame *= 3; + this.frames[frame] = time; + this.frames[frame + 1] = value1; + this.frames[frame + 2] = value2; + } + }; + var RotateTimeline = class extends CurveTimeline1 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.rotate + "|" + boneIndex); + this.boneIndex = 0; + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0: + bone.rotation = bone.data.rotation; + return; + case 1: + bone.rotation += (bone.data.rotation - bone.rotation) * alpha; + } + return; + } + let r = this.getCurveValue(time); + switch (blend) { + case 0: + bone.rotation = bone.data.rotation + r * alpha; + break; + case 1: + case 2: + r += bone.data.rotation - bone.rotation; + case 3: + bone.rotation += r * alpha; + } + } + }; + var TranslateTimeline = class extends CurveTimeline2 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.x + "|" + boneIndex, Property.y + "|" + boneIndex); + this.boneIndex = 0; + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0: + bone.x = bone.data.x; + bone.y = bone.data.y; + return; + case 1: + bone.x += (bone.data.x - bone.x) * alpha; + bone.y += (bone.data.y - bone.y) * alpha; + } + return; + } + let x = 0, y = 0; + let i = Timeline.search(frames, time, 3); + let curveType = this.curves[i / 3]; + switch (curveType) { + case 0: + let before = frames[i]; + x = frames[i + 1]; + y = frames[i + 2]; + let t = (time - before) / (frames[i + 3] - before); + x += (frames[i + 3 + 1] - x) * t; + y += (frames[i + 3 + 2] - y) * t; + break; + case 1: + x = frames[i + 1]; + y = frames[i + 2]; + break; + default: + x = this.getBezierValue(time, i, 1, curveType - 2); + y = this.getBezierValue(time, i, 2, curveType + 18 - 2); + } + switch (blend) { + case 0: + bone.x = bone.data.x + x * alpha; + bone.y = bone.data.y + y * alpha; + break; + case 1: + case 2: + bone.x += (bone.data.x + x - bone.x) * alpha; + bone.y += (bone.data.y + y - bone.y) * alpha; + break; + case 3: + bone.x += x * alpha; + bone.y += y * alpha; + } + } + }; + var TranslateXTimeline = class extends CurveTimeline1 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.x + "|" + boneIndex); + this.boneIndex = 0; + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0: + bone.x = bone.data.x; + return; + case 1: + bone.x += (bone.data.x - bone.x) * alpha; + } + return; + } + let x = this.getCurveValue(time); + switch (blend) { + case 0: + bone.x = bone.data.x + x * alpha; + break; + case 1: + case 2: + bone.x += (bone.data.x + x - bone.x) * alpha; + break; + case 3: + bone.x += x * alpha; + } + } + }; + var TranslateYTimeline = class extends CurveTimeline1 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.y + "|" + boneIndex); + this.boneIndex = 0; + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0: + bone.y = bone.data.y; + return; + case 1: + bone.y += (bone.data.y - bone.y) * alpha; + } + return; + } + let y = this.getCurveValue(time); + switch (blend) { + case 0: + bone.y = bone.data.y + y * alpha; + break; + case 1: + case 2: + bone.y += (bone.data.y + y - bone.y) * alpha; + break; + case 3: + bone.y += y * alpha; + } + } + }; + var ScaleTimeline = class extends CurveTimeline2 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.scaleX + "|" + boneIndex, Property.scaleY + "|" + boneIndex); + this.boneIndex = 0; + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0: + bone.scaleX = bone.data.scaleX; + bone.scaleY = bone.data.scaleY; + return; + case 1: + bone.scaleX += (bone.data.scaleX - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY - bone.scaleY) * alpha; + } + return; + } + let x, y; + let i = Timeline.search(frames, time, 3); + let curveType = this.curves[i / 3]; + switch (curveType) { + case 0: + let before = frames[i]; + x = frames[i + 1]; + y = frames[i + 2]; + let t = (time - before) / (frames[i + 3] - before); + x += (frames[i + 3 + 1] - x) * t; + y += (frames[i + 3 + 2] - y) * t; + break; + case 1: + x = frames[i + 1]; + y = frames[i + 2]; + break; + default: + x = this.getBezierValue(time, i, 1, curveType - 2); + y = this.getBezierValue(time, i, 2, curveType + 18 - 2); + } + x *= bone.data.scaleX; + y *= bone.data.scaleY; + if (alpha == 1) { + if (blend == 3) { + bone.scaleX += x - bone.data.scaleX; + bone.scaleY += y - bone.data.scaleY; + } else { + bone.scaleX = x; + bone.scaleY = y; + } + } else { + let bx = 0, by = 0; + if (direction == 1) { + switch (blend) { + case 0: + 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 1: + case 2: + 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 3: + bone.scaleX += (x - bone.data.scaleX) * alpha; + bone.scaleY += (y - bone.data.scaleY) * alpha; + } + } else { + switch (blend) { + case 0: + 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 1: + case 2: + 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 3: + bone.scaleX += (x - bone.data.scaleX) * alpha; + bone.scaleY += (y - bone.data.scaleY) * alpha; + } + } + } + } + }; + var ScaleXTimeline = class extends CurveTimeline1 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.scaleX + "|" + boneIndex); + this.boneIndex = 0; + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0: + bone.scaleX = bone.data.scaleX; + return; + case 1: + bone.scaleX += (bone.data.scaleX - bone.scaleX) * alpha; + } + return; + } + let x = this.getCurveValue(time) * bone.data.scaleX; + if (alpha == 1) { + if (blend == 3) + bone.scaleX += x - bone.data.scaleX; + else + bone.scaleX = x; + } else { + let bx = 0; + if (direction == 1) { + switch (blend) { + case 0: + bx = bone.data.scaleX; + bone.scaleX = bx + (Math.abs(x) * MathUtils.signum(bx) - bx) * alpha; + break; + case 1: + case 2: + bx = bone.scaleX; + bone.scaleX = bx + (Math.abs(x) * MathUtils.signum(bx) - bx) * alpha; + break; + case 3: + bone.scaleX += (x - bone.data.scaleX) * alpha; + } + } else { + switch (blend) { + case 0: + bx = Math.abs(bone.data.scaleX) * MathUtils.signum(x); + bone.scaleX = bx + (x - bx) * alpha; + break; + case 1: + case 2: + bx = Math.abs(bone.scaleX) * MathUtils.signum(x); + bone.scaleX = bx + (x - bx) * alpha; + break; + case 3: + bone.scaleX += (x - bone.data.scaleX) * alpha; + } + } + } + } + }; + var ScaleYTimeline = class extends CurveTimeline1 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.scaleY + "|" + boneIndex); + this.boneIndex = 0; + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0: + bone.scaleY = bone.data.scaleY; + return; + case 1: + bone.scaleY += (bone.data.scaleY - bone.scaleY) * alpha; + } + return; + } + let y = this.getCurveValue(time) * bone.data.scaleY; + if (alpha == 1) { + if (blend == 3) + bone.scaleY += y - bone.data.scaleY; + else + bone.scaleY = y; + } else { + let by = 0; + if (direction == 1) { + switch (blend) { + case 0: + by = bone.data.scaleY; + bone.scaleY = by + (Math.abs(y) * MathUtils.signum(by) - by) * alpha; + break; + case 1: + case 2: + by = bone.scaleY; + bone.scaleY = by + (Math.abs(y) * MathUtils.signum(by) - by) * alpha; + break; + case 3: + bone.scaleY += (y - bone.data.scaleY) * alpha; + } + } else { + switch (blend) { + case 0: + by = Math.abs(bone.data.scaleY) * MathUtils.signum(y); + bone.scaleY = by + (y - by) * alpha; + break; + case 1: + case 2: + by = Math.abs(bone.scaleY) * MathUtils.signum(y); + bone.scaleY = by + (y - by) * alpha; + break; + case 3: + bone.scaleY += (y - bone.data.scaleY) * alpha; + } + } + } + } + }; + var ShearTimeline = class extends CurveTimeline2 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.shearX + "|" + boneIndex, Property.shearY + "|" + boneIndex); + this.boneIndex = 0; + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0: + bone.shearX = bone.data.shearX; + bone.shearY = bone.data.shearY; + return; + case 1: + bone.shearX += (bone.data.shearX - bone.shearX) * alpha; + bone.shearY += (bone.data.shearY - bone.shearY) * alpha; + } + return; + } + let x = 0, y = 0; + let i = Timeline.search(frames, time, 3); + let curveType = this.curves[i / 3]; + switch (curveType) { + case 0: + let before = frames[i]; + x = frames[i + 1]; + y = frames[i + 2]; + let t = (time - before) / (frames[i + 3] - before); + x += (frames[i + 3 + 1] - x) * t; + y += (frames[i + 3 + 2] - y) * t; + break; + case 1: + x = frames[i + 1]; + y = frames[i + 2]; + break; + default: + x = this.getBezierValue(time, i, 1, curveType - 2); + y = this.getBezierValue(time, i, 2, curveType + 18 - 2); + } + switch (blend) { + case 0: + bone.shearX = bone.data.shearX + x * alpha; + bone.shearY = bone.data.shearY + y * alpha; + break; + case 1: + case 2: + bone.shearX += (bone.data.shearX + x - bone.shearX) * alpha; + bone.shearY += (bone.data.shearY + y - bone.shearY) * alpha; + break; + case 3: + bone.shearX += x * alpha; + bone.shearY += y * alpha; + } + } + }; + var ShearXTimeline = class extends CurveTimeline1 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.shearX + "|" + boneIndex); + this.boneIndex = 0; + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0: + bone.shearX = bone.data.shearX; + return; + case 1: + bone.shearX += (bone.data.shearX - bone.shearX) * alpha; + } + return; + } + let x = this.getCurveValue(time); + switch (blend) { + case 0: + bone.shearX = bone.data.shearX + x * alpha; + break; + case 1: + case 2: + bone.shearX += (bone.data.shearX + x - bone.shearX) * alpha; + break; + case 3: + bone.shearX += x * alpha; + } + } + }; + var ShearYTimeline = class extends CurveTimeline1 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.shearY + "|" + boneIndex); + this.boneIndex = 0; + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0: + bone.shearY = bone.data.shearY; + return; + case 1: + bone.shearY += (bone.data.shearY - bone.shearY) * alpha; + } + return; + } + let y = this.getCurveValue(time); + switch (blend) { + case 0: + bone.shearY = bone.data.shearY + y * alpha; + break; + case 1: + case 2: + bone.shearY += (bone.data.shearY + y - bone.shearY) * alpha; + break; + case 3: + bone.shearY += y * alpha; + } + } + }; + var RGBATimeline = class extends CurveTimeline { + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, [ + Property.rgb + "|" + slotIndex, + Property.alpha + "|" + slotIndex + ]); + this.slotIndex = 0; + this.slotIndex = slotIndex; + } + getFrameEntries() { + return 5; + } + setFrame(frame, time, r, g, b, a) { + frame *= 5; + this.frames[frame] = time; + this.frames[frame + 1] = r; + this.frames[frame + 2] = g; + this.frames[frame + 3] = b; + this.frames[frame + 4] = a; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + let frames = this.frames; + let color = slot.color; + if (time < frames[0]) { + let setup = slot.data.color; + switch (blend) { + case 0: + color.setFromColor(setup); + return; + case 1: + color.add((setup.r - color.r) * alpha, (setup.g - color.g) * alpha, (setup.b - color.b) * alpha, (setup.a - color.a) * alpha); + } + return; + } + let r = 0, g = 0, b = 0, a = 0; + let i = Timeline.search(frames, time, 5); + let curveType = this.curves[i / 5]; + switch (curveType) { + case 0: + let before = frames[i]; + r = frames[i + 1]; + g = frames[i + 2]; + b = frames[i + 3]; + a = frames[i + 4]; + let t = (time - before) / (frames[i + 5] - before); + r += (frames[i + 5 + 1] - r) * t; + g += (frames[i + 5 + 2] - g) * t; + b += (frames[i + 5 + 3] - b) * t; + a += (frames[i + 5 + 4] - a) * t; + break; + case 1: + r = frames[i + 1]; + g = frames[i + 2]; + b = frames[i + 3]; + a = frames[i + 4]; + break; + default: + r = this.getBezierValue(time, i, 1, curveType - 2); + g = this.getBezierValue(time, i, 2, curveType + 18 - 2); + b = this.getBezierValue(time, i, 3, curveType + 18 * 2 - 2); + a = this.getBezierValue(time, i, 4, curveType + 18 * 3 - 2); + } + if (alpha == 1) + color.set(r, g, b, a); + else { + if (blend == 0) + color.setFromColor(slot.data.color); + color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha); + } + } + }; + var RGBTimeline = class extends CurveTimeline { + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, [ + Property.rgb + "|" + slotIndex + ]); + this.slotIndex = 0; + this.slotIndex = slotIndex; + } + getFrameEntries() { + return 4; + } + setFrame(frame, time, r, g, b) { + frame <<= 2; + this.frames[frame] = time; + this.frames[frame + 1] = r; + this.frames[frame + 2] = g; + this.frames[frame + 3] = b; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + let frames = this.frames; + let color = slot.color; + if (time < frames[0]) { + let setup = slot.data.color; + switch (blend) { + case 0: + color.r = setup.r; + color.g = setup.g; + color.b = setup.b; + return; + case 1: + color.r += (setup.r - color.r) * alpha; + color.g += (setup.g - color.g) * alpha; + color.b += (setup.b - color.b) * alpha; + } + return; + } + let r = 0, g = 0, b = 0; + let i = Timeline.search(frames, time, 4); + let curveType = this.curves[i >> 2]; + switch (curveType) { + case 0: + let before = frames[i]; + r = frames[i + 1]; + g = frames[i + 2]; + b = frames[i + 3]; + let t = (time - before) / (frames[i + 4] - before); + r += (frames[i + 4 + 1] - r) * t; + g += (frames[i + 4 + 2] - g) * t; + b += (frames[i + 4 + 3] - b) * t; + break; + case 1: + r = frames[i + 1]; + g = frames[i + 2]; + b = frames[i + 3]; + break; + default: + r = this.getBezierValue(time, i, 1, curveType - 2); + g = this.getBezierValue(time, i, 2, curveType + 18 - 2); + b = this.getBezierValue(time, i, 3, curveType + 18 * 2 - 2); + } + if (alpha == 1) { + color.r = r; + color.g = g; + color.b = b; + } else { + if (blend == 0) { + let setup = slot.data.color; + color.r = setup.r; + color.g = setup.g; + color.b = setup.b; + } + color.r += (r - color.r) * alpha; + color.g += (g - color.g) * alpha; + color.b += (b - color.b) * alpha; + } + } + }; + var AlphaTimeline = class extends CurveTimeline1 { + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, Property.alpha + "|" + slotIndex); + this.slotIndex = 0; + this.slotIndex = slotIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + let color = slot.color; + if (time < this.frames[0]) { + let setup = slot.data.color; + switch (blend) { + case 0: + color.a = setup.a; + return; + case 1: + color.a += (setup.a - color.a) * alpha; + } + return; + } + let a = this.getCurveValue(time); + if (alpha == 1) + color.a = a; + else { + if (blend == 0) + color.a = slot.data.color.a; + color.a += (a - color.a) * alpha; + } + } + }; + var RGBA2Timeline = class extends CurveTimeline { + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, [ + Property.rgb + "|" + slotIndex, + Property.alpha + "|" + slotIndex, + Property.rgb2 + "|" + slotIndex + ]); + this.slotIndex = 0; + this.slotIndex = slotIndex; + } + getFrameEntries() { + return 8; + } + setFrame(frame, time, r, g, b, a, r2, g2, b2) { + frame <<= 3; + this.frames[frame] = time; + this.frames[frame + 1] = r; + this.frames[frame + 2] = g; + this.frames[frame + 3] = b; + this.frames[frame + 4] = a; + this.frames[frame + 5] = r2; + this.frames[frame + 6] = g2; + this.frames[frame + 7] = b2; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + let frames = this.frames; + let light = slot.color, dark = slot.darkColor; + if (time < frames[0]) { + let setupLight = slot.data.color, setupDark = slot.data.darkColor; + switch (blend) { + case 0: + light.setFromColor(setupLight); + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; + return; + case 1: + light.add((setupLight.r - light.r) * alpha, (setupLight.g - light.g) * alpha, (setupLight.b - light.b) * alpha, (setupLight.a - light.a) * alpha); + dark.r += (setupDark.r - dark.r) * alpha; + dark.g += (setupDark.g - dark.g) * alpha; + dark.b += (setupDark.b - dark.b) * alpha; + } + return; + } + let r = 0, g = 0, b = 0, a = 0, r2 = 0, g2 = 0, b2 = 0; + let i = Timeline.search(frames, time, 8); + let curveType = this.curves[i >> 3]; + switch (curveType) { + case 0: + let before = frames[i]; + r = frames[i + 1]; + g = frames[i + 2]; + b = frames[i + 3]; + a = frames[i + 4]; + r2 = frames[i + 5]; + g2 = frames[i + 6]; + b2 = frames[i + 7]; + let t = (time - before) / (frames[i + 8] - before); + r += (frames[i + 8 + 1] - r) * t; + g += (frames[i + 8 + 2] - g) * t; + b += (frames[i + 8 + 3] - b) * t; + a += (frames[i + 8 + 4] - a) * t; + r2 += (frames[i + 8 + 5] - r2) * t; + g2 += (frames[i + 8 + 6] - g2) * t; + b2 += (frames[i + 8 + 7] - b2) * t; + break; + case 1: + r = frames[i + 1]; + g = frames[i + 2]; + b = frames[i + 3]; + a = frames[i + 4]; + r2 = frames[i + 5]; + g2 = frames[i + 6]; + b2 = frames[i + 7]; + break; + default: + r = this.getBezierValue(time, i, 1, curveType - 2); + g = this.getBezierValue(time, i, 2, curveType + 18 - 2); + b = this.getBezierValue(time, i, 3, curveType + 18 * 2 - 2); + a = this.getBezierValue(time, i, 4, curveType + 18 * 3 - 2); + r2 = this.getBezierValue(time, i, 5, curveType + 18 * 4 - 2); + g2 = this.getBezierValue(time, i, 6, curveType + 18 * 5 - 2); + b2 = this.getBezierValue(time, i, 7, curveType + 18 * 6 - 2); + } + if (alpha == 1) { + light.set(r, g, b, a); + dark.r = r2; + dark.g = g2; + dark.b = b2; + } else { + if (blend == 0) { + light.setFromColor(slot.data.color); + let setupDark = slot.data.darkColor; + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; + } + light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha); + dark.r += (r2 - dark.r) * alpha; + dark.g += (g2 - dark.g) * alpha; + dark.b += (b2 - dark.b) * alpha; + } + } + }; + var RGB2Timeline = class extends CurveTimeline { + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, [ + Property.rgb + "|" + slotIndex, + Property.rgb2 + "|" + slotIndex + ]); + this.slotIndex = 0; + this.slotIndex = slotIndex; + } + getFrameEntries() { + return 7; + } + setFrame(frame, time, r, g, b, r2, g2, b2) { + frame *= 7; + this.frames[frame] = time; + this.frames[frame + 1] = r; + this.frames[frame + 2] = g; + this.frames[frame + 3] = b; + this.frames[frame + 4] = r2; + this.frames[frame + 5] = g2; + this.frames[frame + 6] = b2; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + let frames = this.frames; + let light = slot.color, dark = slot.darkColor; + if (time < frames[0]) { + let setupLight = slot.data.color, setupDark = slot.data.darkColor; + switch (blend) { + case 0: + light.r = setupLight.r; + light.g = setupLight.g; + light.b = setupLight.b; + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; + return; + case 1: + light.r += (setupLight.r - light.r) * alpha; + light.g += (setupLight.g - light.g) * alpha; + light.b += (setupLight.b - light.b) * alpha; + dark.r += (setupDark.r - dark.r) * alpha; + dark.g += (setupDark.g - dark.g) * alpha; + dark.b += (setupDark.b - dark.b) * alpha; + } + return; + } + let r = 0, g = 0, b = 0, a = 0, r2 = 0, g2 = 0, b2 = 0; + let i = Timeline.search(frames, time, 7); + let curveType = this.curves[i / 7]; + switch (curveType) { + case 0: + let before = frames[i]; + r = frames[i + 1]; + g = frames[i + 2]; + b = frames[i + 3]; + r2 = frames[i + 4]; + g2 = frames[i + 5]; + b2 = frames[i + 6]; + let t = (time - before) / (frames[i + 7] - before); + r += (frames[i + 7 + 1] - r) * t; + g += (frames[i + 7 + 2] - g) * t; + b += (frames[i + 7 + 3] - b) * t; + r2 += (frames[i + 7 + 4] - r2) * t; + g2 += (frames[i + 7 + 5] - g2) * t; + b2 += (frames[i + 7 + 6] - b2) * t; + break; + case 1: + r = frames[i + 1]; + g = frames[i + 2]; + b = frames[i + 3]; + r2 = frames[i + 4]; + g2 = frames[i + 5]; + b2 = frames[i + 6]; + break; + default: + r = this.getBezierValue(time, i, 1, curveType - 2); + g = this.getBezierValue(time, i, 2, curveType + 18 - 2); + b = this.getBezierValue(time, i, 3, curveType + 18 * 2 - 2); + r2 = this.getBezierValue(time, i, 4, curveType + 18 * 3 - 2); + g2 = this.getBezierValue(time, i, 5, curveType + 18 * 4 - 2); + b2 = this.getBezierValue(time, i, 6, curveType + 18 * 5 - 2); + } + if (alpha == 1) { + light.r = r; + light.g = g; + light.b = b; + dark.r = r2; + dark.g = g2; + dark.b = b2; + } else { + if (blend == 0) { + let setupLight = slot.data.color, setupDark = slot.data.darkColor; + light.r = setupLight.r; + light.g = setupLight.g; + light.b = setupLight.b; + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; + } + light.r += (r - light.r) * alpha; + light.g += (g - light.g) * alpha; + light.b += (b - light.b) * alpha; + dark.r += (r2 - dark.r) * alpha; + dark.g += (g2 - dark.g) * alpha; + dark.b += (b2 - dark.b) * alpha; + } + } + }; + var AttachmentTimeline = class extends Timeline { + constructor(frameCount, slotIndex) { + super(frameCount, [ + Property.attachment + "|" + slotIndex + ]); + this.slotIndex = 0; + this.slotIndex = slotIndex; + this.attachmentNames = new Array(frameCount); + } + getFrameCount() { + return this.frames.length; + } + setFrame(frame, time, attachmentName) { + this.frames[frame] = time; + this.attachmentNames[frame] = attachmentName; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + if (direction == 1) { + if (blend == 0) + this.setAttachment(skeleton, slot, slot.data.attachmentName); + return; + } + if (time < this.frames[0]) { + if (blend == 0 || blend == 1) + this.setAttachment(skeleton, slot, slot.data.attachmentName); + return; + } + this.setAttachment(skeleton, slot, this.attachmentNames[Timeline.search1(this.frames, time)]); + } + setAttachment(skeleton, slot, attachmentName) { + slot.setAttachment(!attachmentName ? null : skeleton.getAttachment(this.slotIndex, attachmentName)); + } + }; + var DeformTimeline = class extends CurveTimeline { + constructor(frameCount, bezierCount, slotIndex, attachment) { + super(frameCount, bezierCount, [ + Property.deform + "|" + slotIndex + "|" + attachment.id + ]); + this.slotIndex = 0; + this.attachment = null; + this.vertices = null; + this.slotIndex = slotIndex; + this.attachment = attachment; + this.vertices = new Array(frameCount); + } + getFrameCount() { + return this.frames.length; + } + setFrame(frame, time, vertices) { + this.frames[frame] = time; + this.vertices[frame] = vertices; + } + setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2) { + let curves = this.curves; + let i = this.getFrameCount() + bezier * 18; + if (value == 0) + curves[frame] = 2 + i; + let tmpx = (time1 - cx1 * 2 + cx2) * 0.03, tmpy = cy2 * 0.03 - cy1 * 0.06; + let dddx = ((cx1 - cx2) * 3 - time1 + time2) * 6e-3, dddy = (cy1 - cy2 + 0.33333333) * 0.018; + let ddx = tmpx * 2 + dddx, ddy = tmpy * 2 + dddy; + let dx = (cx1 - time1) * 0.3 + tmpx + dddx * 0.16666667, dy = cy1 * 0.3 + tmpy + dddy * 0.16666667; + let x = time1 + dx, y = dy; + for (let n = i + 18; i < n; i += 2) { + curves[i] = x; + curves[i + 1] = y; + dx += ddx; + dy += ddy; + ddx += dddx; + ddy += dddy; + x += dx; + y += dy; + } + } + getCurvePercent(time, frame) { + let curves = this.curves; + let i = curves[frame]; + switch (i) { + case 0: + let x2 = this.frames[frame]; + return (time - x2) / (this.frames[frame + this.getFrameEntries()] - x2); + case 1: + return 0; + } + i -= 2; + if (curves[i] > time) { + let x2 = this.frames[frame]; + return curves[i + 1] * (time - x2) / (curves[i] - x2); + } + let n = i + 18; + for (i += 2; i < n; i += 2) { + if (curves[i] >= time) { + let x2 = curves[i - 2], y2 = curves[i - 1]; + return y2 + (time - x2) / (curves[i] - x2) * (curves[i + 1] - y2); + } + } + let x = curves[n - 2], y = curves[n - 1]; + return y + (1 - y) * (time - x) / (this.frames[frame + this.getFrameEntries()] - x); + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + let slotAttachment = slot.getAttachment(); + if (!(slotAttachment instanceof VertexAttachment) || slotAttachment.deformAttachment != this.attachment) + return; + let deform = slot.deform; + if (deform.length == 0) + blend = 0; + let vertices = this.vertices; + let vertexCount = vertices[0].length; + let frames = this.frames; + if (time < frames[0]) { + let vertexAttachment = slotAttachment; + switch (blend) { + case 0: + deform.length = 0; + return; + case 1: + if (alpha == 1) { + deform.length = 0; + return; + } + deform.length = vertexCount; + if (!vertexAttachment.bones) { + let setupVertices = vertexAttachment.vertices; + for (var i = 0; i < vertexCount; i++) + deform[i] += (setupVertices[i] - deform[i]) * alpha; + } else { + alpha = 1 - alpha; + for (var i = 0; i < vertexCount; i++) + deform[i] *= alpha; + } + } + return; + } + deform.length = vertexCount; + if (time >= frames[frames.length - 1]) { + let lastVertices = vertices[frames.length - 1]; + if (alpha == 1) { + if (blend == 3) { + let vertexAttachment = slotAttachment; + if (!vertexAttachment.bones) { + let setupVertices = vertexAttachment.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] += lastVertices[i2] - setupVertices[i2]; + } else { + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] += lastVertices[i2]; + } + } else + Utils.arrayCopy(lastVertices, 0, deform, 0, vertexCount); + } else { + switch (blend) { + case 0: { + let vertexAttachment2 = slotAttachment; + if (!vertexAttachment2.bones) { + let setupVertices = vertexAttachment2.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) { + let setup = setupVertices[i2]; + deform[i2] = setup + (lastVertices[i2] - setup) * alpha; + } + } else { + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] = lastVertices[i2] * alpha; + } + break; + } + case 1: + case 2: + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] += (lastVertices[i2] - deform[i2]) * alpha; + break; + case 3: + let vertexAttachment = slotAttachment; + if (!vertexAttachment.bones) { + let setupVertices = vertexAttachment.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] += (lastVertices[i2] - setupVertices[i2]) * alpha; + } else { + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] += lastVertices[i2] * alpha; + } + } + } + return; + } + let frame = Timeline.search1(frames, time); + let percent = this.getCurvePercent(time, frame); + let prevVertices = vertices[frame]; + let nextVertices = vertices[frame + 1]; + if (alpha == 1) { + if (blend == 3) { + let vertexAttachment = slotAttachment; + if (!vertexAttachment.bones) { + let setupVertices = vertexAttachment.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] += prev + (nextVertices[i2] - prev) * percent - setupVertices[i2]; + } + } else { + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] += prev + (nextVertices[i2] - prev) * percent; + } + } + } else { + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] = prev + (nextVertices[i2] - prev) * percent; + } + } + } else { + switch (blend) { + case 0: { + let vertexAttachment2 = slotAttachment; + if (!vertexAttachment2.bones) { + let setupVertices = vertexAttachment2.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2], setup = setupVertices[i2]; + deform[i2] = setup + (prev + (nextVertices[i2] - prev) * percent - setup) * alpha; + } + } else { + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] = (prev + (nextVertices[i2] - prev) * percent) * alpha; + } + } + break; + } + case 1: + case 2: + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] += (prev + (nextVertices[i2] - prev) * percent - deform[i2]) * alpha; + } + break; + case 3: + let vertexAttachment = slotAttachment; + if (!vertexAttachment.bones) { + let setupVertices = vertexAttachment.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] += (prev + (nextVertices[i2] - prev) * percent - setupVertices[i2]) * alpha; + } + } else { + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] += (prev + (nextVertices[i2] - prev) * percent) * alpha; + } + } + } + } + } + }; + var _EventTimeline = class extends Timeline { + constructor(frameCount) { + super(frameCount, _EventTimeline.propertyIds); + this.events = null; + this.events = new Array(frameCount); + } + getFrameCount() { + return this.frames.length; + } + setFrame(frame, event) { + this.frames[frame] = event.time; + this.events[frame] = event; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + if (!firedEvents) + return; + let frames = this.frames; + let frameCount = this.frames.length; + if (lastTime > time) { + this.apply(skeleton, lastTime, Number.MAX_VALUE, firedEvents, alpha, blend, direction); + lastTime = -1; + } else if (lastTime >= frames[frameCount - 1]) + return; + if (time < frames[0]) + return; + let i = 0; + if (lastTime < frames[0]) + i = 0; + else { + i = Timeline.search1(frames, lastTime) + 1; + let frameTime = frames[i]; + while (i > 0) { + if (frames[i - 1] != frameTime) + break; + i--; + } + } + for (; i < frameCount && time >= frames[i]; i++) + firedEvents.push(this.events[i]); + } + }; + var EventTimeline = _EventTimeline; + EventTimeline.propertyIds = ["" + Property.event]; + var _DrawOrderTimeline = class extends Timeline { + constructor(frameCount) { + super(frameCount, _DrawOrderTimeline.propertyIds); + this.drawOrders = null; + this.drawOrders = new Array(frameCount); + } + getFrameCount() { + return this.frames.length; + } + setFrame(frame, time, drawOrder) { + this.frames[frame] = time; + this.drawOrders[frame] = drawOrder; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + if (direction == 1) { + if (blend == 0) + Utils.arrayCopy(skeleton.slots, 0, skeleton.drawOrder, 0, skeleton.slots.length); + return; + } + if (time < this.frames[0]) { + if (blend == 0 || blend == 1) + Utils.arrayCopy(skeleton.slots, 0, skeleton.drawOrder, 0, skeleton.slots.length); + return; + } + let drawOrderToSetupIndex = this.drawOrders[Timeline.search1(this.frames, time)]; + if (!drawOrderToSetupIndex) + Utils.arrayCopy(skeleton.slots, 0, skeleton.drawOrder, 0, skeleton.slots.length); + else { + let drawOrder = skeleton.drawOrder; + let slots = skeleton.slots; + for (let i = 0, n = drawOrderToSetupIndex.length; i < n; i++) + drawOrder[i] = slots[drawOrderToSetupIndex[i]]; + } + } + }; + var DrawOrderTimeline = _DrawOrderTimeline; + DrawOrderTimeline.propertyIds = ["" + Property.drawOrder]; + var IkConstraintTimeline = class extends CurveTimeline { + constructor(frameCount, bezierCount, ikConstraintIndex) { + super(frameCount, bezierCount, [ + Property.ikConstraint + "|" + ikConstraintIndex + ]); + this.ikConstraintIndex = 0; + this.ikConstraintIndex = ikConstraintIndex; + } + getFrameEntries() { + return 6; + } + setFrame(frame, time, mix, softness, bendDirection, compress, stretch) { + frame *= 6; + this.frames[frame] = time; + this.frames[frame + 1] = mix; + this.frames[frame + 2] = softness; + this.frames[frame + 3] = bendDirection; + this.frames[frame + 4] = compress ? 1 : 0; + this.frames[frame + 5] = stretch ? 1 : 0; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint = skeleton.ikConstraints[this.ikConstraintIndex]; + if (!constraint.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0: + constraint.mix = constraint.data.mix; + constraint.softness = constraint.data.softness; + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + return; + case 1: + constraint.mix += (constraint.data.mix - constraint.mix) * alpha; + constraint.softness += (constraint.data.softness - constraint.softness) * alpha; + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } + return; + } + let mix = 0, softness = 0; + let i = Timeline.search(frames, time, 6); + let curveType = this.curves[i / 6]; + switch (curveType) { + case 0: + let before = frames[i]; + mix = frames[i + 1]; + softness = frames[i + 2]; + let t = (time - before) / (frames[i + 6] - before); + mix += (frames[i + 6 + 1] - mix) * t; + softness += (frames[i + 6 + 2] - softness) * t; + break; + case 1: + mix = frames[i + 1]; + softness = frames[i + 2]; + break; + default: + mix = this.getBezierValue(time, i, 1, curveType - 2); + softness = this.getBezierValue(time, i, 2, curveType + 18 - 2); + } + if (blend == 0) { + constraint.mix = constraint.data.mix + (mix - constraint.data.mix) * alpha; + constraint.softness = constraint.data.softness + (softness - constraint.data.softness) * alpha; + if (direction == 1) { + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } else { + constraint.bendDirection = frames[i + 3]; + constraint.compress = frames[i + 4] != 0; + constraint.stretch = frames[i + 5] != 0; + } + } else { + constraint.mix += (mix - constraint.mix) * alpha; + constraint.softness += (softness - constraint.softness) * alpha; + if (direction == 0) { + constraint.bendDirection = frames[i + 3]; + constraint.compress = frames[i + 4] != 0; + constraint.stretch = frames[i + 5] != 0; + } + } + } + }; + var TransformConstraintTimeline = class extends CurveTimeline { + constructor(frameCount, bezierCount, transformConstraintIndex) { + super(frameCount, bezierCount, [ + Property.transformConstraint + "|" + transformConstraintIndex + ]); + this.transformConstraintIndex = 0; + this.transformConstraintIndex = transformConstraintIndex; + } + getFrameEntries() { + return 7; + } + setFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY) { + let frames = this.frames; + frame *= 7; + frames[frame] = time; + frames[frame + 1] = mixRotate; + frames[frame + 2] = mixX; + frames[frame + 3] = mixY; + frames[frame + 4] = mixScaleX; + frames[frame + 5] = mixScaleY; + frames[frame + 6] = mixShearY; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint = skeleton.transformConstraints[this.transformConstraintIndex]; + if (!constraint.active) + return; + let frames = this.frames; + if (time < frames[0]) { + let data = constraint.data; + switch (blend) { + case 0: + constraint.mixRotate = data.mixRotate; + constraint.mixX = data.mixX; + constraint.mixY = data.mixY; + constraint.mixScaleX = data.mixScaleX; + constraint.mixScaleY = data.mixScaleY; + constraint.mixShearY = data.mixShearY; + return; + case 1: + constraint.mixRotate += (data.mixRotate - constraint.mixRotate) * alpha; + constraint.mixX += (data.mixX - constraint.mixX) * alpha; + constraint.mixY += (data.mixY - constraint.mixY) * alpha; + constraint.mixScaleX += (data.mixScaleX - constraint.mixScaleX) * alpha; + constraint.mixScaleY += (data.mixScaleY - constraint.mixScaleY) * alpha; + constraint.mixShearY += (data.mixShearY - constraint.mixShearY) * alpha; + } + return; + } + let rotate, x, y, scaleX, scaleY, shearY; + let i = Timeline.search(frames, time, 7); + let curveType = this.curves[i / 7]; + switch (curveType) { + case 0: + let before = frames[i]; + rotate = frames[i + 1]; + x = frames[i + 2]; + y = frames[i + 3]; + scaleX = frames[i + 4]; + scaleY = frames[i + 5]; + shearY = frames[i + 6]; + let t = (time - before) / (frames[i + 7] - before); + rotate += (frames[i + 7 + 1] - rotate) * t; + x += (frames[i + 7 + 2] - x) * t; + y += (frames[i + 7 + 3] - y) * t; + scaleX += (frames[i + 7 + 4] - scaleX) * t; + scaleY += (frames[i + 7 + 5] - scaleY) * t; + shearY += (frames[i + 7 + 6] - shearY) * t; + break; + case 1: + rotate = frames[i + 1]; + x = frames[i + 2]; + y = frames[i + 3]; + scaleX = frames[i + 4]; + scaleY = frames[i + 5]; + shearY = frames[i + 6]; + break; + default: + rotate = this.getBezierValue(time, i, 1, curveType - 2); + x = this.getBezierValue(time, i, 2, curveType + 18 - 2); + y = this.getBezierValue(time, i, 3, curveType + 18 * 2 - 2); + scaleX = this.getBezierValue(time, i, 4, curveType + 18 * 3 - 2); + scaleY = this.getBezierValue(time, i, 5, curveType + 18 * 4 - 2); + shearY = this.getBezierValue(time, i, 6, curveType + 18 * 5 - 2); + } + if (blend == 0) { + let data = constraint.data; + constraint.mixRotate = data.mixRotate + (rotate - data.mixRotate) * alpha; + constraint.mixX = data.mixX + (x - data.mixX) * alpha; + constraint.mixY = data.mixY + (y - data.mixY) * alpha; + constraint.mixScaleX = data.mixScaleX + (scaleX - data.mixScaleX) * alpha; + constraint.mixScaleY = data.mixScaleY + (scaleY - data.mixScaleY) * alpha; + constraint.mixShearY = data.mixShearY + (shearY - data.mixShearY) * alpha; + } else { + constraint.mixRotate += (rotate - constraint.mixRotate) * alpha; + constraint.mixX += (x - constraint.mixX) * alpha; + constraint.mixY += (y - constraint.mixY) * alpha; + constraint.mixScaleX += (scaleX - constraint.mixScaleX) * alpha; + constraint.mixScaleY += (scaleY - constraint.mixScaleY) * alpha; + constraint.mixShearY += (shearY - constraint.mixShearY) * alpha; + } + } + }; + var PathConstraintPositionTimeline = class extends CurveTimeline1 { + constructor(frameCount, bezierCount, pathConstraintIndex) { + super(frameCount, bezierCount, Property.pathConstraintPosition + "|" + pathConstraintIndex); + this.pathConstraintIndex = 0; + this.pathConstraintIndex = pathConstraintIndex; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint = skeleton.pathConstraints[this.pathConstraintIndex]; + if (!constraint.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0: + constraint.position = constraint.data.position; + return; + case 1: + constraint.position += (constraint.data.position - constraint.position) * alpha; + } + return; + } + let position = this.getCurveValue(time); + if (blend == 0) + constraint.position = constraint.data.position + (position - constraint.data.position) * alpha; + else + constraint.position += (position - constraint.position) * alpha; + } + }; + var PathConstraintSpacingTimeline = class extends CurveTimeline1 { + constructor(frameCount, bezierCount, pathConstraintIndex) { + super(frameCount, bezierCount, Property.pathConstraintSpacing + "|" + pathConstraintIndex); + this.pathConstraintIndex = 0; + this.pathConstraintIndex = pathConstraintIndex; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint = skeleton.pathConstraints[this.pathConstraintIndex]; + if (!constraint.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0: + constraint.spacing = constraint.data.spacing; + return; + case 1: + constraint.spacing += (constraint.data.spacing - constraint.spacing) * alpha; + } + return; + } + let spacing = this.getCurveValue(time); + if (blend == 0) + constraint.spacing = constraint.data.spacing + (spacing - constraint.data.spacing) * alpha; + else + constraint.spacing += (spacing - constraint.spacing) * alpha; + } + }; + var PathConstraintMixTimeline = class extends CurveTimeline { + constructor(frameCount, bezierCount, pathConstraintIndex) { + super(frameCount, bezierCount, [ + Property.pathConstraintMix + "|" + pathConstraintIndex + ]); + this.pathConstraintIndex = 0; + this.pathConstraintIndex = pathConstraintIndex; + } + getFrameEntries() { + return 4; + } + setFrame(frame, time, mixRotate, mixX, mixY) { + let frames = this.frames; + frame <<= 2; + frames[frame] = time; + frames[frame + 1] = mixRotate; + frames[frame + 2] = mixX; + frames[frame + 3] = mixY; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint = skeleton.pathConstraints[this.pathConstraintIndex]; + if (!constraint.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0: + constraint.mixRotate = constraint.data.mixRotate; + constraint.mixX = constraint.data.mixX; + constraint.mixY = constraint.data.mixY; + return; + case 1: + constraint.mixRotate += (constraint.data.mixRotate - constraint.mixRotate) * alpha; + constraint.mixX += (constraint.data.mixX - constraint.mixX) * alpha; + constraint.mixY += (constraint.data.mixY - constraint.mixY) * alpha; + } + return; + } + let rotate, x, y; + let i = Timeline.search(frames, time, 4); + let curveType = this.curves[i >> 2]; + switch (curveType) { + case 0: + let before = frames[i]; + rotate = frames[i + 1]; + x = frames[i + 2]; + y = frames[i + 3]; + let t = (time - before) / (frames[i + 4] - before); + rotate += (frames[i + 4 + 1] - rotate) * t; + x += (frames[i + 4 + 2] - x) * t; + y += (frames[i + 4 + 3] - y) * t; + break; + case 1: + rotate = frames[i + 1]; + x = frames[i + 2]; + y = frames[i + 3]; + break; + default: + rotate = this.getBezierValue(time, i, 1, curveType - 2); + x = this.getBezierValue(time, i, 2, curveType + 18 - 2); + y = this.getBezierValue(time, i, 3, curveType + 18 * 2 - 2); + } + if (blend == 0) { + let data = constraint.data; + constraint.mixRotate = data.mixRotate + (rotate - data.mixRotate) * alpha; + constraint.mixX = data.mixX + (x - data.mixX) * alpha; + constraint.mixY = data.mixY + (y - data.mixY) * alpha; + } else { + constraint.mixRotate += (rotate - constraint.mixRotate) * alpha; + constraint.mixX += (x - constraint.mixX) * alpha; + constraint.mixY += (y - constraint.mixY) * alpha; + } + } + }; + + // spine-core/src/AnimationState.ts + var AnimationState = class { + constructor(data) { + this.data = null; + this.tracks = new Array(); + this.timeScale = 1; + this.unkeyedState = 0; + this.events = new Array(); + this.listeners = new Array(); + this.queue = new EventQueue(this); + this.propertyIDs = new StringSet(); + this.animationsChanged = false; + this.trackEntryPool = new Pool(() => new TrackEntry()); + this.data = data; + } + static emptyAnimation() { + if (!_emptyAnimation) + _emptyAnimation = new Animation("", [], 0); + return _emptyAnimation; + } + update(delta) { + delta *= this.timeScale; + let tracks = this.tracks; + for (let i = 0, n = tracks.length; i < n; i++) { + let current = tracks[i]; + if (!current) + continue; + current.animationLast = current.nextAnimationLast; + current.trackLast = current.nextTrackLast; + let currentDelta = delta * current.timeScale; + if (current.delay > 0) { + current.delay -= currentDelta; + if (current.delay > 0) + continue; + currentDelta = -current.delay; + current.delay = 0; + } + let next = current.next; + if (next) { + let 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) { + next.mixTime += delta; + next = next.mixingFrom; + } + continue; + } + } else if (current.trackLast >= current.trackEnd && !current.mixingFrom) { + tracks[i] = null; + this.queue.end(current); + this.clearNext(current); + continue; + } + if (current.mixingFrom && this.updateMixingFrom(current, delta)) { + let from = current.mixingFrom; + current.mixingFrom = null; + if (from) + from.mixingTo = null; + while (from) { + this.queue.end(from); + from = from.mixingFrom; + } + } + current.trackTime += currentDelta; + } + this.queue.drain(); + } + updateMixingFrom(to, delta) { + let from = to.mixingFrom; + if (!from) + return true; + let finished = this.updateMixingFrom(from, delta); + from.animationLast = from.nextAnimationLast; + from.trackLast = from.nextTrackLast; + if (to.mixTime > 0 && to.mixTime >= to.mixDuration) { + if (from.totalAlpha == 0 || to.mixDuration == 0) { + to.mixingFrom = from.mixingFrom; + if (from.mixingFrom) + from.mixingFrom.mixingTo = to; + to.interruptAlpha = from.interruptAlpha; + this.queue.end(from); + } + return finished; + } + from.trackTime += delta * from.timeScale; + to.mixTime += delta; + return false; + } + apply(skeleton) { + if (!skeleton) + throw new Error("skeleton cannot be null."); + if (this.animationsChanged) + this._animationsChanged(); + let events = this.events; + let tracks = this.tracks; + let applied = false; + for (let i2 = 0, n2 = tracks.length; i2 < n2; i2++) { + let current = tracks[i2]; + if (!current || current.delay > 0) + continue; + applied = true; + let blend = i2 == 0 ? MixBlend.first : current.mixBlend; + let mix = current.alpha; + if (current.mixingFrom) + mix *= this.applyMixingFrom(current, skeleton, blend); + else if (current.trackTime >= current.trackEnd && !current.next) + mix = 0; + let animationLast = current.animationLast, animationTime = current.getAnimationTime(), applyTime = animationTime; + let applyEvents = events; + if (current.reverse) { + applyTime = current.animation.duration - applyTime; + applyEvents = null; + } + let timelines = current.animation.timelines; + let timelineCount = timelines.length; + if (i2 == 0 && mix == 1 || blend == MixBlend.add) { + for (let ii = 0; ii < timelineCount; ii++) { + Utils.webkit602BugfixHelper(mix, blend); + var timeline = timelines[ii]; + if (timeline instanceof AttachmentTimeline) + this.applyAttachmentTimeline(timeline, skeleton, applyTime, blend, true); + else + timeline.apply(skeleton, animationLast, applyTime, applyEvents, mix, blend, MixDirection.mixIn); + } + } else { + let timelineMode = current.timelineMode; + let firstFrame = current.timelinesRotation.length != timelineCount << 1; + if (firstFrame) + current.timelinesRotation.length = timelineCount << 1; + for (let ii = 0; ii < timelineCount; ii++) { + let timeline2 = timelines[ii]; + let timelineBlend = timelineMode[ii] == SUBSEQUENT ? blend : MixBlend.setup; + if (timeline2 instanceof RotateTimeline) { + this.applyRotateTimeline(timeline2, skeleton, applyTime, mix, timelineBlend, current.timelinesRotation, ii << 1, firstFrame); + } else if (timeline2 instanceof AttachmentTimeline) { + this.applyAttachmentTimeline(timeline2, skeleton, applyTime, blend, true); + } else { + Utils.webkit602BugfixHelper(mix, blend); + timeline2.apply(skeleton, animationLast, applyTime, applyEvents, mix, timelineBlend, MixDirection.mixIn); + } + } + } + this.queueEvents(current, animationTime); + events.length = 0; + current.nextAnimationLast = animationTime; + current.nextTrackLast = current.trackTime; + } + var setupState = this.unkeyedState + SETUP; + var slots = skeleton.slots; + for (var i = 0, n = skeleton.slots.length; i < n; i++) { + var slot = slots[i]; + if (slot.attachmentState == setupState) { + var attachmentName = slot.data.attachmentName; + slot.setAttachment(!attachmentName ? null : skeleton.getAttachment(slot.data.index, attachmentName)); + } + } + this.unkeyedState += 2; + this.queue.drain(); + return applied; + } + applyMixingFrom(to, skeleton, blend) { + let from = to.mixingFrom; + if (from.mixingFrom) + this.applyMixingFrom(from, skeleton, blend); + let mix = 0; + if (to.mixDuration == 0) { + 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; + } + let attachments = mix < from.attachmentThreshold, drawOrder = mix < from.drawOrderThreshold; + let timelines = from.animation.timelines; + let timelineCount = timelines.length; + let alphaHold = from.alpha * to.interruptAlpha, alphaMix = alphaHold * (1 - mix); + let animationLast = from.animationLast, animationTime = from.getAnimationTime(), applyTime = animationTime; + let events = null; + if (from.reverse) + applyTime = from.animation.duration - applyTime; + else if (mix < from.eventThreshold) + events = this.events; + if (blend == MixBlend.add) { + for (let i = 0; i < timelineCount; i++) + timelines[i].apply(skeleton, animationLast, applyTime, events, alphaMix, blend, MixDirection.mixOut); + } else { + let timelineMode = from.timelineMode; + let timelineHoldMix = from.timelineHoldMix; + let firstFrame = from.timelinesRotation.length != timelineCount << 1; + if (firstFrame) + from.timelinesRotation.length = timelineCount << 1; + from.totalAlpha = 0; + for (let i = 0; i < timelineCount; i++) { + let timeline = timelines[i]; + let direction = MixDirection.mixOut; + let timelineBlend; + let alpha = 0; + switch (timelineMode[i]) { + case SUBSEQUENT: + if (!drawOrder && timeline instanceof DrawOrderTimeline) + continue; + timelineBlend = blend; + alpha = alphaMix; + break; + case FIRST: + timelineBlend = MixBlend.setup; + alpha = alphaMix; + break; + case HOLD_SUBSEQUENT: + timelineBlend = blend; + alpha = alphaHold; + break; + case HOLD_FIRST: + timelineBlend = MixBlend.setup; + alpha = alphaHold; + break; + default: + timelineBlend = MixBlend.setup; + let 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, applyTime, alpha, timelineBlend, from.timelinesRotation, i << 1, firstFrame); + else if (timeline instanceof AttachmentTimeline) + this.applyAttachmentTimeline(timeline, skeleton, applyTime, timelineBlend, attachments); + else { + Utils.webkit602BugfixHelper(alpha, blend); + if (drawOrder && timeline instanceof DrawOrderTimeline && timelineBlend == MixBlend.setup) + direction = MixDirection.mixIn; + timeline.apply(skeleton, animationLast, applyTime, 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; + } + applyAttachmentTimeline(timeline, skeleton, time, blend, attachments) { + var slot = skeleton.slots[timeline.slotIndex]; + if (!slot.bone.active) + return; + if (time < timeline.frames[0]) { + if (blend == MixBlend.setup || blend == MixBlend.first) + this.setAttachment(skeleton, slot, slot.data.attachmentName, attachments); + } else + this.setAttachment(skeleton, slot, timeline.attachmentNames[Timeline.search1(timeline.frames, time)], attachments); + if (slot.attachmentState <= this.unkeyedState) + slot.attachmentState = this.unkeyedState + SETUP; + } + setAttachment(skeleton, slot, attachmentName, attachments) { + slot.setAttachment(!attachmentName ? null : skeleton.getAttachment(slot.data.index, attachmentName)); + if (attachments) + slot.attachmentState = this.unkeyedState + CURRENT; + } + applyRotateTimeline(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; + } + let bone = skeleton.bones[timeline.boneIndex]; + if (!bone.active) + return; + let frames = timeline.frames; + let r1 = 0, 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; + r2 = bone.data.rotation + timeline.getCurveValue(time); + } + let total = 0, diff = r2 - r1; + diff -= (16384 - (16384.499999999996 - diff / 360 | 0)) * 360; + if (diff == 0) { + total = timelinesRotation[i]; + } else { + let lastTotal = 0, lastDiff = 0; + if (firstFrame) { + lastTotal = 0; + lastDiff = diff; + } else { + lastTotal = timelinesRotation[i]; + lastDiff = timelinesRotation[i + 1]; + } + let current = diff > 0, dir = lastTotal >= 0; + if (MathUtils.signum(lastDiff) != MathUtils.signum(diff) && Math.abs(lastDiff) <= 90) { + if (Math.abs(lastTotal) > 180) + lastTotal += 360 * MathUtils.signum(lastTotal); + dir = current; + } + total = diff + lastTotal - lastTotal % 360; + if (dir != current) + total += 360 * MathUtils.signum(lastTotal); + timelinesRotation[i] = total; + } + timelinesRotation[i + 1] = diff; + bone.rotation = r1 + total * alpha; + } + queueEvents(entry, animationTime) { + let animationStart = entry.animationStart, animationEnd = entry.animationEnd; + let duration = animationEnd - animationStart; + let trackLastWrapped = entry.trackLast % duration; + let events = this.events; + let i = 0, n = events.length; + for (; i < n; i++) { + let event = events[i]; + if (event.time < trackLastWrapped) + break; + if (event.time > animationEnd) + continue; + this.queue.event(entry, event); + } + let 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); + for (; i < n; i++) { + let event = events[i]; + if (event.time < animationStart) + continue; + this.queue.event(entry, event); + } + } + clearTracks() { + let oldDrainDisabled = this.queue.drainDisabled; + this.queue.drainDisabled = true; + for (let i = 0, n = this.tracks.length; i < n; i++) + this.clearTrack(i); + this.tracks.length = 0; + this.queue.drainDisabled = oldDrainDisabled; + this.queue.drain(); + } + clearTrack(trackIndex) { + if (trackIndex >= this.tracks.length) + return; + let current = this.tracks[trackIndex]; + if (!current) + return; + this.queue.end(current); + this.clearNext(current); + let entry = current; + while (true) { + let from = entry.mixingFrom; + if (!from) + break; + this.queue.end(from); + entry.mixingFrom = null; + entry.mixingTo = null; + entry = from; + } + this.tracks[current.trackIndex] = null; + this.queue.drain(); + } + setCurrent(index, current, interrupt) { + let from = this.expandToIndex(index); + this.tracks[index] = current; + current.previous = null; + if (from) { + if (interrupt) + this.queue.interrupt(from); + current.mixingFrom = from; + from.mixingTo = current; + current.mixTime = 0; + if (from.mixingFrom && from.mixDuration > 0) + current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration); + from.timelinesRotation.length = 0; + } + this.queue.start(current); + } + setAnimation(trackIndex, animationName, loop = false) { + let animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) + throw new Error("Animation not found: " + animationName); + return this.setAnimationWith(trackIndex, animation, loop); + } + setAnimationWith(trackIndex, animation, loop = false) { + if (!animation) + throw new Error("animation cannot be null."); + let interrupt = true; + let current = this.expandToIndex(trackIndex); + if (current) { + if (current.nextTrackLast == -1) { + this.tracks[trackIndex] = current.mixingFrom; + this.queue.interrupt(current); + this.queue.end(current); + this.clearNext(current); + current = current.mixingFrom; + interrupt = false; + } else + this.clearNext(current); + } + let entry = this.trackEntry(trackIndex, animation, loop, current); + this.setCurrent(trackIndex, entry, interrupt); + this.queue.drain(); + return entry; + } + addAnimation(trackIndex, animationName, loop = false, delay = 0) { + let animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) + throw new Error("Animation not found: " + animationName); + return this.addAnimationWith(trackIndex, animation, loop, delay); + } + addAnimationWith(trackIndex, animation, loop = false, delay = 0) { + if (!animation) + throw new Error("animation cannot be null."); + let last = this.expandToIndex(trackIndex); + if (last) { + while (last.next) + last = last.next; + } + let entry = this.trackEntry(trackIndex, animation, loop, last); + if (!last) { + this.setCurrent(trackIndex, entry, true); + this.queue.drain(); + } else { + last.next = entry; + entry.previous = last; + if (delay <= 0) + delay += last.getTrackComplete() - entry.mixDuration; + } + entry.delay = delay; + return entry; + } + setEmptyAnimation(trackIndex, mixDuration = 0) { + let entry = this.setAnimationWith(trackIndex, AnimationState.emptyAnimation(), false); + entry.mixDuration = mixDuration; + entry.trackEnd = mixDuration; + return entry; + } + addEmptyAnimation(trackIndex, mixDuration = 0, delay = 0) { + let entry = this.addAnimationWith(trackIndex, AnimationState.emptyAnimation(), false, delay); + if (delay <= 0) + entry.delay += entry.mixDuration - mixDuration; + entry.mixDuration = mixDuration; + entry.trackEnd = mixDuration; + return entry; + } + setEmptyAnimations(mixDuration = 0) { + let oldDrainDisabled = this.queue.drainDisabled; + this.queue.drainDisabled = true; + for (let i = 0, n = this.tracks.length; i < n; i++) { + let current = this.tracks[i]; + if (current) + this.setEmptyAnimation(current.trackIndex, mixDuration); + } + this.queue.drainDisabled = oldDrainDisabled; + this.queue.drain(); + } + expandToIndex(index) { + if (index < this.tracks.length) + return this.tracks[index]; + Utils.ensureArrayCapacity(this.tracks, index + 1, null); + this.tracks.length = index + 1; + return null; + } + trackEntry(trackIndex, animation, loop, last) { + let entry = this.trackEntryPool.obtain(); + entry.reset(); + 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 ? 0 : this.data.getMix(last.animation, animation); + entry.mixBlend = MixBlend.replace; + return entry; + } + clearNext(entry) { + let next = entry.next; + while (next) { + this.queue.dispose(next); + next = next.next; + } + entry.next = null; + } + _animationsChanged() { + this.animationsChanged = false; + this.propertyIDs.clear(); + let tracks = this.tracks; + for (let i = 0, n = tracks.length; i < n; i++) { + let entry = tracks[i]; + if (!entry) + continue; + while (entry.mixingFrom) + entry = entry.mixingFrom; + do { + if (!entry.mixingTo || entry.mixBlend != MixBlend.add) + this.computeHold(entry); + entry = entry.mixingTo; + } while (entry); + } + } + computeHold(entry) { + let to = entry.mixingTo; + let timelines = entry.animation.timelines; + let timelinesCount = entry.animation.timelines.length; + let timelineMode = entry.timelineMode; + timelineMode.length = timelinesCount; + let timelineHoldMix = entry.timelineHoldMix; + timelineHoldMix.length = 0; + let propertyIDs = this.propertyIDs; + if (to && to.holdPrevious) { + for (let i = 0; i < timelinesCount; i++) + timelineMode[i] = propertyIDs.addAll(timelines[i].getPropertyIds()) ? HOLD_FIRST : HOLD_SUBSEQUENT; + return; + } + outer: + for (let i = 0; i < timelinesCount; i++) { + let timeline = timelines[i]; + let ids = timeline.getPropertyIds(); + if (!propertyIDs.addAll(ids)) + timelineMode[i] = SUBSEQUENT; + else if (!to || timeline instanceof AttachmentTimeline || timeline instanceof DrawOrderTimeline || timeline instanceof EventTimeline || !to.animation.hasTimeline(ids)) { + timelineMode[i] = FIRST; + } else { + for (let next = to.mixingTo; next; next = next.mixingTo) { + if (next.animation.hasTimeline(ids)) + continue; + if (entry.mixDuration > 0) { + timelineMode[i] = HOLD_MIX; + timelineHoldMix[i] = next; + continue outer; + } + break; + } + timelineMode[i] = HOLD_FIRST; + } + } + } + getCurrent(trackIndex) { + if (trackIndex >= this.tracks.length) + return null; + return this.tracks[trackIndex]; + } + addListener(listener) { + if (!listener) + throw new Error("listener cannot be null."); + this.listeners.push(listener); + } + removeListener(listener) { + let index = this.listeners.indexOf(listener); + if (index >= 0) + this.listeners.splice(index, 1); + } + clearListeners() { + this.listeners.length = 0; + } + clearListenerNotifications() { + this.queue.clear(); + } + }; + var TrackEntry = class { + constructor() { + this.animation = null; + this.previous = null; + this.next = null; + this.mixingFrom = null; + this.mixingTo = null; + this.listener = null; + this.trackIndex = 0; + this.loop = false; + this.holdPrevious = false; + this.reverse = false; + this.eventThreshold = 0; + this.attachmentThreshold = 0; + this.drawOrderThreshold = 0; + this.animationStart = 0; + this.animationEnd = 0; + this.animationLast = 0; + this.nextAnimationLast = 0; + this.delay = 0; + this.trackTime = 0; + this.trackLast = 0; + this.nextTrackLast = 0; + this.trackEnd = 0; + this.timeScale = 0; + this.alpha = 0; + this.mixTime = 0; + this.mixDuration = 0; + this.interruptAlpha = 0; + this.totalAlpha = 0; + this.mixBlend = MixBlend.replace; + this.timelineMode = new Array(); + this.timelineHoldMix = new Array(); + this.timelinesRotation = new Array(); + } + reset() { + this.next = null; + this.previous = 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; + } + getAnimationTime() { + if (this.loop) { + let 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); + } + setAnimationLast(animationLast) { + this.animationLast = animationLast; + this.nextAnimationLast = animationLast; + } + isComplete() { + return this.trackTime >= this.animationEnd - this.animationStart; + } + resetRotationDirections() { + this.timelinesRotation.length = 0; + } + getTrackComplete() { + let duration = this.animationEnd - this.animationStart; + if (duration != 0) { + if (this.loop) + return duration * (1 + (this.trackTime / duration | 0)); + if (this.trackTime < duration) + return duration; + } + return this.trackTime; + } + }; + var EventQueue = class { + constructor(animState) { + this.objects = []; + this.drainDisabled = false; + this.animState = null; + this.animState = animState; + } + start(entry) { + this.objects.push(EventType.start); + this.objects.push(entry); + this.animState.animationsChanged = true; + } + interrupt(entry) { + this.objects.push(EventType.interrupt); + this.objects.push(entry); + } + end(entry) { + this.objects.push(EventType.end); + this.objects.push(entry); + this.animState.animationsChanged = true; + } + dispose(entry) { + this.objects.push(EventType.dispose); + this.objects.push(entry); + } + complete(entry) { + this.objects.push(EventType.complete); + this.objects.push(entry); + } + event(entry, event) { + this.objects.push(EventType.event); + this.objects.push(entry); + this.objects.push(event); + } + drain() { + if (this.drainDisabled) + return; + this.drainDisabled = true; + let objects = this.objects; + let listeners = this.animState.listeners; + for (let i = 0; i < objects.length; i += 2) { + let type = objects[i]; + let entry = objects[i + 1]; + switch (type) { + case EventType.start: + if (entry.listener && entry.listener.start) + entry.listener.start(entry); + for (let ii = 0; ii < listeners.length; ii++) + if (listeners[ii].start) + listeners[ii].start(entry); + break; + case EventType.interrupt: + if (entry.listener && entry.listener.interrupt) + entry.listener.interrupt(entry); + for (let ii = 0; ii < listeners.length; ii++) + if (listeners[ii].interrupt) + listeners[ii].interrupt(entry); + break; + case EventType.end: + if (entry.listener && entry.listener.end) + entry.listener.end(entry); + for (let ii = 0; ii < listeners.length; ii++) + if (listeners[ii].end) + listeners[ii].end(entry); + case EventType.dispose: + if (entry.listener && entry.listener.dispose) + entry.listener.dispose(entry); + for (let 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 && entry.listener.complete) + entry.listener.complete(entry); + for (let ii = 0; ii < listeners.length; ii++) + if (listeners[ii].complete) + listeners[ii].complete(entry); + break; + case EventType.event: + let event = objects[i++ + 2]; + if (entry.listener && entry.listener.event) + entry.listener.event(entry, event); + for (let ii = 0; ii < listeners.length; ii++) + if (listeners[ii].event) + listeners[ii].event(entry, event); + break; + } + } + this.clear(); + this.drainDisabled = false; + } + clear() { + this.objects.length = 0; + } + }; + var EventType; + (function(EventType2) { + EventType2[EventType2["start"] = 0] = "start"; + EventType2[EventType2["interrupt"] = 1] = "interrupt"; + EventType2[EventType2["end"] = 2] = "end"; + EventType2[EventType2["dispose"] = 3] = "dispose"; + EventType2[EventType2["complete"] = 4] = "complete"; + EventType2[EventType2["event"] = 5] = "event"; + })(EventType || (EventType = {})); + var AnimationStateAdapter = class { + start(entry) { + } + interrupt(entry) { + } + end(entry) { + } + dispose(entry) { + } + complete(entry) { + } + event(entry, event) { + } + }; + var SUBSEQUENT = 0; + var FIRST = 1; + var HOLD_SUBSEQUENT = 2; + var HOLD_FIRST = 3; + var HOLD_MIX = 4; + var SETUP = 1; + var CURRENT = 2; + var _emptyAnimation = null; + + // spine-core/src/AnimationStateData.ts + var AnimationStateData = class { + constructor(skeletonData) { + this.skeletonData = null; + this.animationToMixTime = {}; + this.defaultMix = 0; + if (!skeletonData) + throw new Error("skeletonData cannot be null."); + this.skeletonData = skeletonData; + } + setMix(fromName, toName, duration) { + let from = this.skeletonData.findAnimation(fromName); + if (!from) + throw new Error("Animation not found: " + fromName); + let to = this.skeletonData.findAnimation(toName); + if (!to) + throw new Error("Animation not found: " + toName); + this.setMixWith(from, to, duration); + } + setMixWith(from, to, duration) { + if (!from) + throw new Error("from cannot be null."); + if (!to) + throw new Error("to cannot be null."); + let key = from.name + "." + to.name; + this.animationToMixTime[key] = duration; + } + getMix(from, to) { + let key = from.name + "." + to.name; + let value = this.animationToMixTime[key]; + return value === void 0 ? this.defaultMix : value; + } + }; + + // spine-core/src/attachments/BoundingBoxAttachment.ts + var BoundingBoxAttachment = class extends VertexAttachment { + constructor(name) { + super(name); + this.color = new Color(1, 1, 1, 1); + } + copy() { + let copy = new BoundingBoxAttachment(this.name); + this.copyTo(copy); + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/attachments/ClippingAttachment.ts + var ClippingAttachment = class extends VertexAttachment { + constructor(name) { + super(name); + this.endSlot = null; + this.color = new Color(0.2275, 0.2275, 0.8078, 1); + } + copy() { + let copy = new ClippingAttachment(this.name); + this.copyTo(copy); + copy.endSlot = this.endSlot; + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/Texture.ts + var Texture = class { + constructor(image) { + this._image = image; + } + getImage() { + return this._image; + } + }; + var TextureFilter; + (function(TextureFilter3) { + TextureFilter3[TextureFilter3["Nearest"] = 9728] = "Nearest"; + TextureFilter3[TextureFilter3["Linear"] = 9729] = "Linear"; + TextureFilter3[TextureFilter3["MipMap"] = 9987] = "MipMap"; + TextureFilter3[TextureFilter3["MipMapNearestNearest"] = 9984] = "MipMapNearestNearest"; + TextureFilter3[TextureFilter3["MipMapLinearNearest"] = 9985] = "MipMapLinearNearest"; + TextureFilter3[TextureFilter3["MipMapNearestLinear"] = 9986] = "MipMapNearestLinear"; + TextureFilter3[TextureFilter3["MipMapLinearLinear"] = 9987] = "MipMapLinearLinear"; + })(TextureFilter || (TextureFilter = {})); + var TextureWrap; + (function(TextureWrap3) { + TextureWrap3[TextureWrap3["MirroredRepeat"] = 33648] = "MirroredRepeat"; + TextureWrap3[TextureWrap3["ClampToEdge"] = 33071] = "ClampToEdge"; + TextureWrap3[TextureWrap3["Repeat"] = 10497] = "Repeat"; + })(TextureWrap || (TextureWrap = {})); + var TextureRegion = class { + constructor() { + this.u = 0; + this.v = 0; + this.u2 = 0; + this.v2 = 0; + this.width = 0; + this.height = 0; + this.degrees = 0; + this.offsetX = 0; + this.offsetY = 0; + this.originalWidth = 0; + this.originalHeight = 0; + } + }; + var FakeTexture = class extends Texture { + setFilters(minFilter, magFilter) { + } + setWraps(uWrap, vWrap) { + } + dispose() { + } + }; + + // spine-core/src/TextureAtlas.ts + var TextureAtlas = class { + constructor(atlasText) { + this.pages = new Array(); + this.regions = new Array(); + let reader = new TextureAtlasReader(atlasText); + let entry = new Array(4); + let page = null; + let region = null; + let pageFields = {}; + pageFields["size"] = () => { + page.width = parseInt(entry[1]); + page.height = parseInt(entry[2]); + }; + pageFields["format"] = () => { + }; + pageFields["filter"] = () => { + page.minFilter = Utils.enumValue(TextureFilter, entry[1]); + page.magFilter = Utils.enumValue(TextureFilter, entry[2]); + }; + pageFields["repeat"] = () => { + if (entry[1].indexOf("x") != -1) + page.uWrap = TextureWrap.Repeat; + if (entry[1].indexOf("y") != -1) + page.vWrap = TextureWrap.Repeat; + }; + pageFields["pma"] = () => { + page.pma = entry[1] == "true"; + }; + var regionFields = {}; + regionFields["xy"] = () => { + region.x = parseInt(entry[1]); + region.y = parseInt(entry[2]); + }; + regionFields["size"] = () => { + region.width = parseInt(entry[1]); + region.height = parseInt(entry[2]); + }; + regionFields["bounds"] = () => { + region.x = parseInt(entry[1]); + region.y = parseInt(entry[2]); + region.width = parseInt(entry[3]); + region.height = parseInt(entry[4]); + }; + regionFields["offset"] = () => { + region.offsetX = parseInt(entry[1]); + region.offsetY = parseInt(entry[2]); + }; + regionFields["orig"] = () => { + region.originalWidth = parseInt(entry[1]); + region.originalHeight = parseInt(entry[2]); + }; + regionFields["offsets"] = () => { + region.offsetX = parseInt(entry[1]); + region.offsetY = parseInt(entry[2]); + region.originalWidth = parseInt(entry[3]); + region.originalHeight = parseInt(entry[4]); + }; + regionFields["rotate"] = () => { + let value = entry[1]; + if (value == "true") + region.degrees = 90; + else if (value != "false") + region.degrees = parseInt(value); + }; + regionFields["index"] = () => { + region.index = parseInt(entry[1]); + }; + let line = reader.readLine(); + while (line && line.trim().length == 0) + line = reader.readLine(); + while (true) { + if (!line || line.trim().length == 0) + break; + if (reader.readEntry(entry, line) == 0) + break; + line = reader.readLine(); + } + let names = null; + let values = null; + while (true) { + if (line === null) + break; + if (line.trim().length == 0) { + page = null; + line = reader.readLine(); + } else if (!page) { + page = new TextureAtlasPage(); + page.name = line.trim(); + while (true) { + if (reader.readEntry(entry, line = reader.readLine()) == 0) + break; + let field = pageFields[entry[0]]; + if (field) + field(); + } + this.pages.push(page); + } else { + region = new TextureAtlasRegion(); + region.page = page; + region.name = line; + while (true) { + let count = reader.readEntry(entry, line = reader.readLine()); + if (count == 0) + break; + let field = regionFields[entry[0]]; + if (field) + field(); + else { + if (!names) { + names = []; + values = []; + } + names.push(entry[0]); + let entryValues = []; + for (let i = 0; i < count; i++) + entryValues.push(parseInt(entry[i + 1])); + values.push(entryValues); + } + } + if (region.originalWidth == 0 && region.originalHeight == 0) { + region.originalWidth = region.width; + region.originalHeight = region.height; + } + if (names && names.length > 0) { + region.names = names; + region.values = values; + names = null; + values = null; + } + region.u = region.x / page.width; + region.v = region.y / page.height; + if (region.degrees == 90) { + region.u2 = (region.x + region.height) / page.width; + region.v2 = (region.y + region.width) / page.height; + } else { + region.u2 = (region.x + region.width) / page.width; + region.v2 = (region.y + region.height) / page.height; + } + this.regions.push(region); + } + } + } + findRegion(name) { + for (let i = 0; i < this.regions.length; i++) { + if (this.regions[i].name == name) { + return this.regions[i]; + } + } + return null; + } + setTextures(assetManager, pathPrefix = "") { + for (let page of this.pages) + page.setTexture(assetManager.get(pathPrefix + page.name)); + } + dispose() { + for (let i = 0; i < this.pages.length; i++) { + this.pages[i].texture.dispose(); + } + } + }; + var TextureAtlasReader = class { + constructor(text) { + this.lines = null; + this.index = 0; + this.lines = text.split(/\r\n|\r|\n/); + } + readLine() { + if (this.index >= this.lines.length) + return null; + return this.lines[this.index++]; + } + readEntry(entry, line) { + if (!line) + return 0; + line = line.trim(); + if (line.length == 0) + return 0; + let colon = line.indexOf(":"); + if (colon == -1) + return 0; + entry[0] = line.substr(0, colon).trim(); + for (let i = 1, lastMatch = colon + 1; ; i++) { + let comma = line.indexOf(",", lastMatch); + if (comma == -1) { + entry[i] = line.substr(lastMatch).trim(); + return i; + } + entry[i] = line.substr(lastMatch, comma - lastMatch).trim(); + lastMatch = comma + 1; + if (i == 4) + return 4; + } + } + }; + var TextureAtlasPage = class { + constructor() { + this.name = null; + this.minFilter = TextureFilter.Nearest; + this.magFilter = TextureFilter.Nearest; + this.uWrap = TextureWrap.ClampToEdge; + this.vWrap = TextureWrap.ClampToEdge; + this.texture = null; + this.width = 0; + this.height = 0; + this.pma = false; + } + setTexture(texture) { + this.texture = texture; + texture.setFilters(this.minFilter, this.magFilter); + texture.setWraps(this.uWrap, this.vWrap); + } + }; + var TextureAtlasRegion = class extends TextureRegion { + constructor() { + super(...arguments); + this.page = null; + this.name = null; + this.x = 0; + this.y = 0; + this.offsetX = 0; + this.offsetY = 0; + this.originalWidth = 0; + this.originalHeight = 0; + this.index = 0; + this.degrees = 0; + this.names = null; + this.values = null; + } + }; + + // spine-core/src/attachments/MeshAttachment.ts + var MeshAttachment = class extends VertexAttachment { + constructor(name) { + super(name); + this.region = null; + this.path = null; + this.regionUVs = null; + this.uvs = null; + this.triangles = null; + this.color = new Color(1, 1, 1, 1); + this.width = 0; + this.height = 0; + this.hullLength = 0; + this.edges = null; + this.parentMesh = null; + this.tempColor = new Color(0, 0, 0, 0); + } + updateUVs() { + let regionUVs = this.regionUVs; + if (!this.uvs || this.uvs.length != regionUVs.length) + this.uvs = Utils.newFloatArray(regionUVs.length); + let uvs = this.uvs; + let n = this.uvs.length; + let u = this.region.u, v = this.region.v, width = 0, height = 0; + if (this.region instanceof TextureAtlasRegion) { + let region = this.region, image = region.page.texture.getImage(); + let textureWidth = image.width, textureHeight = image.height; + switch (region.degrees) { + case 90: + u -= (region.originalHeight - region.offsetY - region.height) / textureWidth; + v -= (region.originalWidth - region.offsetX - region.width) / textureHeight; + width = region.originalHeight / textureWidth; + height = region.originalWidth / textureHeight; + for (let i = 0; i < n; i += 2) { + uvs[i] = u + regionUVs[i + 1] * width; + uvs[i + 1] = v + (1 - regionUVs[i]) * height; + } + return; + case 180: + u -= (region.originalWidth - region.offsetX - region.width) / textureWidth; + v -= region.offsetY / textureHeight; + width = region.originalWidth / textureWidth; + height = region.originalHeight / textureHeight; + for (let i = 0; i < n; i += 2) { + uvs[i] = u + (1 - regionUVs[i]) * width; + uvs[i + 1] = v + (1 - regionUVs[i + 1]) * height; + } + return; + case 270: + u -= region.offsetY / textureWidth; + v -= region.offsetX / textureHeight; + width = region.originalHeight / textureWidth; + height = region.originalWidth / textureHeight; + for (let i = 0; i < n; i += 2) { + uvs[i] = u + (1 - regionUVs[i + 1]) * width; + uvs[i + 1] = v + regionUVs[i] * height; + } + return; + } + u -= region.offsetX / textureWidth; + v -= (region.originalHeight - region.offsetY - region.height) / textureHeight; + width = region.originalWidth / textureWidth; + height = region.originalHeight / textureHeight; + } else if (!this.region) { + u = v = 0; + width = height = 1; + } else { + width = this.region.u2 - u; + height = this.region.v2 - v; + } + for (let i = 0; i < n; i += 2) { + uvs[i] = u + regionUVs[i] * width; + uvs[i + 1] = v + regionUVs[i + 1] * height; + } + } + getParentMesh() { + return this.parentMesh; + } + setParentMesh(parentMesh) { + this.parentMesh = parentMesh; + if (parentMesh) { + this.bones = parentMesh.bones; + this.vertices = parentMesh.vertices; + this.worldVerticesLength = parentMesh.worldVerticesLength; + this.regionUVs = parentMesh.regionUVs; + this.triangles = parentMesh.triangles; + this.hullLength = parentMesh.hullLength; + this.worldVerticesLength = parentMesh.worldVerticesLength; + } + } + copy() { + if (this.parentMesh) + return this.newLinkedMesh(); + let copy = new MeshAttachment(this.name); + copy.region = this.region; + copy.path = this.path; + copy.color.setFromColor(this.color); + this.copyTo(copy); + copy.regionUVs = new Array(this.regionUVs.length); + Utils.arrayCopy(this.regionUVs, 0, copy.regionUVs, 0, this.regionUVs.length); + copy.uvs = new Array(this.uvs.length); + Utils.arrayCopy(this.uvs, 0, copy.uvs, 0, this.uvs.length); + copy.triangles = new Array(this.triangles.length); + Utils.arrayCopy(this.triangles, 0, copy.triangles, 0, this.triangles.length); + copy.hullLength = this.hullLength; + if (this.edges) { + copy.edges = new Array(this.edges.length); + Utils.arrayCopy(this.edges, 0, copy.edges, 0, this.edges.length); + } + copy.width = this.width; + copy.height = this.height; + return copy; + } + newLinkedMesh() { + let copy = new MeshAttachment(this.name); + copy.region = this.region; + copy.path = this.path; + copy.color.setFromColor(this.color); + copy.deformAttachment = this.deformAttachment; + copy.setParentMesh(this.parentMesh ? this.parentMesh : this); + copy.updateUVs(); + return copy; + } + }; + + // spine-core/src/attachments/PathAttachment.ts + var PathAttachment = class extends VertexAttachment { + constructor(name) { + super(name); + this.lengths = null; + this.closed = false; + this.constantSpeed = false; + this.color = new Color(1, 1, 1, 1); + } + copy() { + let copy = new PathAttachment(this.name); + this.copyTo(copy); + copy.lengths = new Array(this.lengths.length); + Utils.arrayCopy(this.lengths, 0, copy.lengths, 0, this.lengths.length); + copy.closed = closed; + copy.constantSpeed = this.constantSpeed; + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/attachments/PointAttachment.ts + var PointAttachment = class extends VertexAttachment { + constructor(name) { + super(name); + this.x = 0; + this.y = 0; + this.rotation = 0; + this.color = new Color(0.38, 0.94, 0, 1); + } + computeWorldPosition(bone, point) { + point.x = this.x * bone.a + this.y * bone.b + bone.worldX; + point.y = this.x * bone.c + this.y * bone.d + bone.worldY; + return point; + } + computeWorldRotation(bone) { + let cos = MathUtils.cosDeg(this.rotation), sin = MathUtils.sinDeg(this.rotation); + let x = cos * bone.a + sin * bone.b; + let y = cos * bone.c + sin * bone.d; + return Math.atan2(y, x) * MathUtils.radDeg; + } + copy() { + let copy = new PointAttachment(this.name); + copy.x = this.x; + copy.y = this.y; + copy.rotation = this.rotation; + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/attachments/RegionAttachment.ts + var _RegionAttachment = class extends Attachment { + constructor(name) { + super(name); + this.x = 0; + this.y = 0; + this.scaleX = 1; + this.scaleY = 1; + this.rotation = 0; + this.width = 0; + this.height = 0; + this.color = new Color(1, 1, 1, 1); + this.path = null; + this.rendererObject = null; + this.region = null; + this.offset = Utils.newFloatArray(8); + this.uvs = Utils.newFloatArray(8); + this.tempColor = new Color(1, 1, 1, 1); + } + updateOffset() { + let region = this.region; + let regionScaleX = this.width / this.region.originalWidth * this.scaleX; + let regionScaleY = this.height / this.region.originalHeight * this.scaleY; + let localX = -this.width / 2 * this.scaleX + this.region.offsetX * regionScaleX; + let localY = -this.height / 2 * this.scaleY + this.region.offsetY * regionScaleY; + let localX2 = localX + this.region.width * regionScaleX; + let localY2 = localY + this.region.height * regionScaleY; + let radians = this.rotation * Math.PI / 180; + let cos = Math.cos(radians); + let sin = Math.sin(radians); + let x = this.x, y = this.y; + let localXCos = localX * cos + x; + let localXSin = localX * sin; + let localYCos = localY * cos + y; + let localYSin = localY * sin; + let localX2Cos = localX2 * cos + x; + let localX2Sin = localX2 * sin; + let localY2Cos = localY2 * cos + y; + let localY2Sin = localY2 * sin; + let offset = this.offset; + offset[0] = localXCos - localYSin; + offset[1] = localYCos + localXSin; + offset[2] = localXCos - localY2Sin; + offset[3] = localY2Cos + localXSin; + offset[4] = localX2Cos - localY2Sin; + offset[5] = localY2Cos + localX2Sin; + offset[6] = localX2Cos - localYSin; + offset[7] = localYCos + localX2Sin; + } + setRegion(region) { + this.region = region; + let uvs = this.uvs; + if (region.degrees == 90) { + uvs[2] = region.u; + uvs[3] = region.v2; + uvs[4] = region.u; + uvs[5] = region.v; + uvs[6] = region.u2; + uvs[7] = region.v; + uvs[0] = region.u2; + uvs[1] = region.v2; + } else { + uvs[0] = region.u; + uvs[1] = region.v2; + uvs[2] = region.u; + uvs[3] = region.v; + uvs[4] = region.u2; + uvs[5] = region.v; + uvs[6] = region.u2; + uvs[7] = region.v2; + } + } + computeWorldVertices(bone, worldVertices, offset, stride) { + let vertexOffset = this.offset; + let x = bone.worldX, y = bone.worldY; + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + let offsetX = 0, offsetY = 0; + offsetX = vertexOffset[0]; + offsetY = vertexOffset[1]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[2]; + offsetY = vertexOffset[3]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[4]; + offsetY = vertexOffset[5]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[6]; + offsetY = vertexOffset[7]; + worldVertices[offset] = offsetX * a + offsetY * b + x; + worldVertices[offset + 1] = offsetX * c + offsetY * d + y; + } + copy() { + let copy = new _RegionAttachment(this.name); + copy.region = this.region; + copy.rendererObject = this.rendererObject; + copy.path = this.path; + copy.x = this.x; + copy.y = this.y; + copy.scaleX = this.scaleX; + copy.scaleY = this.scaleY; + copy.rotation = this.rotation; + copy.width = this.width; + copy.height = this.height; + Utils.arrayCopy(this.uvs, 0, copy.uvs, 0, 8); + Utils.arrayCopy(this.offset, 0, copy.offset, 0, 8); + copy.color.setFromColor(this.color); + return copy; + } + }; + var RegionAttachment = _RegionAttachment; + RegionAttachment.X1 = 0; + RegionAttachment.Y1 = 1; + RegionAttachment.C1R = 2; + RegionAttachment.C1G = 3; + RegionAttachment.C1B = 4; + RegionAttachment.C1A = 5; + RegionAttachment.U1 = 6; + RegionAttachment.V1 = 7; + RegionAttachment.X2 = 8; + RegionAttachment.Y2 = 9; + RegionAttachment.C2R = 10; + RegionAttachment.C2G = 11; + RegionAttachment.C2B = 12; + RegionAttachment.C2A = 13; + RegionAttachment.U2 = 14; + RegionAttachment.V2 = 15; + RegionAttachment.X3 = 16; + RegionAttachment.Y3 = 17; + RegionAttachment.C3R = 18; + RegionAttachment.C3G = 19; + RegionAttachment.C3B = 20; + RegionAttachment.C3A = 21; + RegionAttachment.U3 = 22; + RegionAttachment.V3 = 23; + RegionAttachment.X4 = 24; + RegionAttachment.Y4 = 25; + RegionAttachment.C4R = 26; + RegionAttachment.C4G = 27; + RegionAttachment.C4B = 28; + RegionAttachment.C4A = 29; + RegionAttachment.U4 = 30; + RegionAttachment.V4 = 31; + + // spine-core/src/AtlasAttachmentLoader.ts + var AtlasAttachmentLoader = class { + constructor(atlas) { + this.atlas = null; + this.atlas = atlas; + } + newRegionAttachment(skin, name, path) { + let region = this.atlas.findRegion(path); + if (!region) + throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")"); + region.renderObject = region; + let attachment = new RegionAttachment(name); + attachment.setRegion(region); + return attachment; + } + newMeshAttachment(skin, name, path) { + let region = this.atlas.findRegion(path); + if (!region) + throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); + region.renderObject = region; + let attachment = new MeshAttachment(name); + attachment.region = region; + return attachment; + } + newBoundingBoxAttachment(skin, name) { + return new BoundingBoxAttachment(name); + } + newPathAttachment(skin, name) { + return new PathAttachment(name); + } + newPointAttachment(skin, name) { + return new PointAttachment(name); + } + newClippingAttachment(skin, name) { + return new ClippingAttachment(name); + } + }; + + // spine-core/src/BoneData.ts + var BoneData = class { + constructor(index, name, parent) { + this.index = 0; + this.name = null; + this.parent = null; + this.length = 0; + this.x = 0; + this.y = 0; + this.rotation = 0; + this.scaleX = 1; + this.scaleY = 1; + this.shearX = 0; + this.shearY = 0; + this.transformMode = TransformMode.Normal; + this.skinRequired = false; + this.color = new Color(); + if (index < 0) + throw new Error("index must be >= 0."); + if (!name) + throw new Error("name cannot be null."); + this.index = index; + this.name = name; + this.parent = parent; + } + }; + var TransformMode; + (function(TransformMode2) { + TransformMode2[TransformMode2["Normal"] = 0] = "Normal"; + TransformMode2[TransformMode2["OnlyTranslation"] = 1] = "OnlyTranslation"; + TransformMode2[TransformMode2["NoRotationOrReflection"] = 2] = "NoRotationOrReflection"; + TransformMode2[TransformMode2["NoScale"] = 3] = "NoScale"; + TransformMode2[TransformMode2["NoScaleOrReflection"] = 4] = "NoScaleOrReflection"; + })(TransformMode || (TransformMode = {})); + + // spine-core/src/Bone.ts + var Bone = class { + constructor(data, skeleton, parent) { + this.data = null; + this.skeleton = null; + this.parent = null; + this.children = new Array(); + this.x = 0; + this.y = 0; + this.rotation = 0; + this.scaleX = 0; + this.scaleY = 0; + this.shearX = 0; + this.shearY = 0; + this.ax = 0; + this.ay = 0; + this.arotation = 0; + this.ascaleX = 0; + this.ascaleY = 0; + this.ashearX = 0; + this.ashearY = 0; + this.a = 0; + this.b = 0; + this.c = 0; + this.d = 0; + this.worldY = 0; + this.worldX = 0; + this.sorted = false; + this.active = false; + if (!data) + throw new Error("data cannot be null."); + if (!skeleton) + throw new Error("skeleton cannot be null."); + this.data = data; + this.skeleton = skeleton; + this.parent = parent; + this.setToSetupPose(); + } + isActive() { + return this.active; + } + update() { + this.updateWorldTransformWith(this.ax, this.ay, this.arotation, this.ascaleX, this.ascaleY, this.ashearX, this.ashearY); + } + updateWorldTransform() { + this.updateWorldTransformWith(this.x, this.y, this.rotation, this.scaleX, this.scaleY, this.shearX, this.shearY); + } + updateWorldTransformWith(x, y, rotation, scaleX, scaleY, shearX, shearY) { + this.ax = x; + this.ay = y; + this.arotation = rotation; + this.ascaleX = scaleX; + this.ascaleY = scaleY; + this.ashearX = shearX; + this.ashearY = shearY; + let parent = this.parent; + if (!parent) { + let skeleton = this.skeleton; + let rotationY = rotation + 90 + shearY; + let sx = skeleton.scaleX; + let sy = skeleton.scaleY; + this.a = MathUtils.cosDeg(rotation + shearX) * scaleX * sx; + this.b = MathUtils.cosDeg(rotationY) * scaleY * sx; + this.c = MathUtils.sinDeg(rotation + shearX) * scaleX * sy; + this.d = MathUtils.sinDeg(rotationY) * scaleY * sy; + this.worldX = x * sx + skeleton.x; + this.worldY = y * sy + skeleton.y; + return; + } + let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + this.worldX = pa * x + pb * y + parent.worldX; + this.worldY = pc * x + pd * y + parent.worldY; + switch (this.data.transformMode) { + case TransformMode.Normal: { + let rotationY = rotation + 90 + shearY; + let la = MathUtils.cosDeg(rotation + shearX) * scaleX; + let lb = MathUtils.cosDeg(rotationY) * scaleY; + let lc = MathUtils.sinDeg(rotation + shearX) * scaleX; + let ld = MathUtils.sinDeg(rotationY) * scaleY; + this.a = pa * la + pb * lc; + this.b = pa * lb + pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + return; + } + case TransformMode.OnlyTranslation: { + let rotationY = rotation + 90 + shearY; + this.a = MathUtils.cosDeg(rotation + shearX) * scaleX; + this.b = MathUtils.cosDeg(rotationY) * scaleY; + this.c = MathUtils.sinDeg(rotation + shearX) * scaleX; + this.d = MathUtils.sinDeg(rotationY) * scaleY; + break; + } + case TransformMode.NoRotationOrReflection: { + let s = pa * pa + pc * pc; + let prx = 0; + if (s > 1e-4) { + s = Math.abs(pa * pd - pb * pc) / s; + pa /= this.skeleton.scaleX; + pc /= this.skeleton.scaleY; + pb = pc * s; + pd = pa * s; + prx = Math.atan2(pc, pa) * MathUtils.radDeg; + } else { + pa = 0; + pc = 0; + prx = 90 - Math.atan2(pd, pb) * MathUtils.radDeg; + } + let rx = rotation + shearX - prx; + let ry = rotation + shearY - prx + 90; + let la = MathUtils.cosDeg(rx) * scaleX; + let lb = MathUtils.cosDeg(ry) * scaleY; + let lc = MathUtils.sinDeg(rx) * scaleX; + let ld = MathUtils.sinDeg(ry) * scaleY; + this.a = pa * la - pb * lc; + this.b = pa * lb - pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + break; + } + case TransformMode.NoScale: + case TransformMode.NoScaleOrReflection: { + let cos = MathUtils.cosDeg(rotation); + let sin = MathUtils.sinDeg(rotation); + let za = (pa * cos + pb * sin) / this.skeleton.scaleX; + let zc = (pc * cos + pd * sin) / this.skeleton.scaleY; + let s = Math.sqrt(za * za + zc * zc); + if (s > 1e-5) + s = 1 / s; + za *= s; + zc *= s; + s = Math.sqrt(za * za + zc * zc); + if (this.data.transformMode == TransformMode.NoScale && pa * pd - pb * pc < 0 != (this.skeleton.scaleX < 0 != this.skeleton.scaleY < 0)) + s = -s; + let r = Math.PI / 2 + Math.atan2(zc, za); + let zb = Math.cos(r) * s; + let zd = Math.sin(r) * s; + let la = MathUtils.cosDeg(shearX) * scaleX; + let lb = MathUtils.cosDeg(90 + shearY) * scaleY; + let lc = MathUtils.sinDeg(shearX) * scaleX; + let ld = MathUtils.sinDeg(90 + shearY) * scaleY; + this.a = za * la + zb * lc; + this.b = za * lb + zb * ld; + this.c = zc * la + zd * lc; + this.d = zc * lb + zd * ld; + break; + } + } + this.a *= this.skeleton.scaleX; + this.b *= this.skeleton.scaleX; + this.c *= this.skeleton.scaleY; + this.d *= this.skeleton.scaleY; + } + setToSetupPose() { + let data = this.data; + this.x = data.x; + this.y = data.y; + this.rotation = data.rotation; + this.scaleX = data.scaleX; + this.scaleY = data.scaleY; + this.shearX = data.shearX; + this.shearY = data.shearY; + } + getWorldRotationX() { + return Math.atan2(this.c, this.a) * MathUtils.radDeg; + } + getWorldRotationY() { + return Math.atan2(this.d, this.b) * MathUtils.radDeg; + } + getWorldScaleX() { + return Math.sqrt(this.a * this.a + this.c * this.c); + } + getWorldScaleY() { + return Math.sqrt(this.b * this.b + this.d * this.d); + } + updateAppliedTransform() { + let parent = this.parent; + if (!parent) { + this.ax = this.worldX - this.skeleton.x; + this.ay = this.worldY - this.skeleton.y; + this.arotation = Math.atan2(this.c, this.a) * MathUtils.radDeg; + this.ascaleX = Math.sqrt(this.a * this.a + this.c * this.c); + this.ascaleY = Math.sqrt(this.b * this.b + this.d * this.d); + this.ashearX = 0; + this.ashearY = Math.atan2(this.a * this.b + this.c * this.d, this.a * this.d - this.b * this.c) * MathUtils.radDeg; + return; + } + let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + let pid = 1 / (pa * pd - pb * pc); + let dx = this.worldX - parent.worldX, dy = this.worldY - parent.worldY; + this.ax = dx * pd * pid - dy * pb * pid; + this.ay = dy * pa * pid - dx * pc * pid; + let ia = pid * pd; + let id = pid * pa; + let ib = pid * pb; + let ic = pid * pc; + let ra = ia * this.a - ib * this.c; + let rb = ia * this.b - ib * this.d; + let rc = id * this.c - ic * this.a; + let rd = id * this.d - ic * this.b; + this.ashearX = 0; + this.ascaleX = Math.sqrt(ra * ra + rc * rc); + if (this.ascaleX > 1e-4) { + let det = ra * rd - rb * rc; + this.ascaleY = det / this.ascaleX; + this.ashearY = Math.atan2(ra * rb + rc * rd, det) * MathUtils.radDeg; + this.arotation = Math.atan2(rc, ra) * MathUtils.radDeg; + } else { + this.ascaleX = 0; + this.ascaleY = Math.sqrt(rb * rb + rd * rd); + this.ashearY = 0; + this.arotation = 90 - Math.atan2(rd, rb) * MathUtils.radDeg; + } + } + worldToLocal(world) { + let invDet = 1 / (this.a * this.d - this.b * this.c); + let x = world.x - this.worldX, y = world.y - this.worldY; + world.x = x * this.d * invDet - y * this.b * invDet; + world.y = y * this.a * invDet - x * this.c * invDet; + return world; + } + localToWorld(local) { + let x = local.x, y = local.y; + local.x = x * this.a + y * this.b + this.worldX; + local.y = x * this.c + y * this.d + this.worldY; + return local; + } + worldToLocalRotation(worldRotation) { + let sin = MathUtils.sinDeg(worldRotation), cos = MathUtils.cosDeg(worldRotation); + return Math.atan2(this.a * sin - this.c * cos, this.d * cos - this.b * sin) * MathUtils.radDeg + this.rotation - this.shearX; + } + localToWorldRotation(localRotation) { + localRotation -= this.rotation - this.shearX; + let sin = MathUtils.sinDeg(localRotation), cos = MathUtils.cosDeg(localRotation); + return Math.atan2(cos * this.c + sin * this.d, cos * this.a + sin * this.b) * MathUtils.radDeg; + } + rotateWorld(degrees) { + let a = this.a, b = this.b, c = this.c, d = this.d; + let cos = MathUtils.cosDeg(degrees), sin = MathUtils.sinDeg(degrees); + this.a = cos * a - sin * c; + this.b = cos * b - sin * d; + this.c = sin * a + cos * c; + this.d = sin * b + cos * d; + } + }; + + // spine-core/src/ConstraintData.ts + var ConstraintData = class { + constructor(name, order, skinRequired) { + this.name = name; + this.order = order; + this.skinRequired = skinRequired; + } + }; + + // spine-core/src/AssetManagerBase.ts + var AssetManagerBase = class { + constructor(textureLoader, pathPrefix = "", downloader = null) { + this.pathPrefix = null; + this.assets = {}; + this.errors = {}; + this.toLoad = 0; + this.loaded = 0; + this.textureLoader = textureLoader; + this.pathPrefix = pathPrefix; + this.downloader = downloader || new Downloader(); + } + start(path) { + this.toLoad++; + return this.pathPrefix + path; + } + success(callback, path, asset) { + this.toLoad--; + this.loaded++; + this.assets[path] = asset; + if (callback) + callback(path, asset); + } + error(callback, path, message) { + this.toLoad--; + this.loaded++; + this.errors[path] = message; + if (callback) + callback(path, message); + } + loadAll() { + let promise = new Promise((resolve, reject) => { + let check = () => { + if (this.isLoadingComplete()) { + if (this.hasErrors()) + reject(this.errors); + else + resolve(this); + return; + } + requestAnimationFrame(check); + }; + requestAnimationFrame(check); + }); + return promise; + } + setRawDataURI(path, data) { + this.downloader.rawDataUris[this.pathPrefix + path] = data; + } + loadBinary(path, success = null, error = null) { + path = this.start(path); + this.downloader.downloadBinary(path, (data) => { + this.success(success, path, data); + }, (status, responseText) => { + this.error(error, path, `Couldn't load binary ${path}: status ${status}, ${responseText}`); + }); + } + loadText(path, success = null, error = null) { + path = this.start(path); + this.downloader.downloadText(path, (data) => { + this.success(success, path, data); + }, (status, responseText) => { + this.error(error, path, `Couldn't load text ${path}: status ${status}, ${responseText}`); + }); + } + loadJson(path, success = null, error = null) { + path = this.start(path); + this.downloader.downloadJson(path, (data) => { + this.success(success, path, data); + }, (status, responseText) => { + this.error(error, path, `Couldn't load JSON ${path}: status ${status}, ${responseText}`); + }); + } + loadTexture(path, success = null, error = null) { + path = this.start(path); + let isBrowser = !!(typeof window !== "undefined" && typeof navigator !== "undefined" && window.document); + let isWebWorker = !isBrowser; + if (isWebWorker) { + fetch(path, { mode: "cors" }).then((response) => { + if (response.ok) + return response.blob(); + this.error(error, path, `Couldn't load image: ${path}`); + return null; + }).then((blob) => { + return blob ? createImageBitmap(blob, { premultiplyAlpha: "none", colorSpaceConversion: "none" }) : null; + }).then((bitmap) => { + if (bitmap) + this.success(success, path, this.textureLoader(bitmap)); + }); + } else { + let image = new Image(); + image.crossOrigin = "anonymous"; + image.onload = () => { + this.success(success, path, this.textureLoader(image)); + }; + image.onerror = () => { + this.error(error, path, `Couldn't load image: ${path}`); + }; + if (this.downloader.rawDataUris[path]) + path = this.downloader.rawDataUris[path]; + image.src = path; + } + } + loadTextureAtlas(path, success = null, error = null, fileAlias = null) { + let index = path.lastIndexOf("/"); + let parent = index >= 0 ? path.substring(0, index + 1) : ""; + path = this.start(path); + this.downloader.downloadText(path, (atlasText) => { + try { + let atlas = new TextureAtlas(atlasText); + let toLoad = atlas.pages.length, abort = false; + for (let page of atlas.pages) { + this.loadTexture(fileAlias == null ? parent + page.name : fileAlias[page.name], (imagePath, texture) => { + if (!abort) { + page.setTexture(texture); + if (--toLoad == 0) + this.success(success, path, atlas); + } + }, (imagePath, message) => { + if (!abort) + this.error(error, path, `Couldn't load texture atlas ${path} page image: ${imagePath}`); + abort = true; + }); + } + } catch (e) { + this.error(error, path, `Couldn't parse texture atlas ${path}: ${e.message}`); + } + }, (status, responseText) => { + this.error(error, path, `Couldn't load texture atlas ${path}: status ${status}, ${responseText}`); + }); + } + get(path) { + return this.assets[this.pathPrefix + path]; + } + require(path) { + path = this.pathPrefix + path; + let asset = this.assets[path]; + if (asset) + return asset; + let error = this.errors[path]; + throw Error("Asset not found: " + path + (error ? "\n" + error : "")); + } + remove(path) { + path = this.pathPrefix + path; + let asset = this.assets[path]; + if (asset.dispose) + asset.dispose(); + delete this.assets[path]; + return asset; + } + removeAll() { + for (let key in this.assets) { + let asset = this.assets[key]; + if (asset.dispose) + asset.dispose(); + } + this.assets = {}; + } + isLoadingComplete() { + return this.toLoad == 0; + } + getToLoad() { + return this.toLoad; + } + getLoaded() { + return this.loaded; + } + dispose() { + this.removeAll(); + } + hasErrors() { + return Object.keys(this.errors).length > 0; + } + getErrors() { + return this.errors; + } + }; + var Downloader = class { + constructor() { + this.callbacks = {}; + this.rawDataUris = {}; + } + dataUriToString(dataUri) { + if (!dataUri.startsWith("data:")) { + throw new Error("Not a data URI."); + } + let base64Idx = dataUri.indexOf("base64,"); + if (base64Idx != -1) { + base64Idx += "base64,".length; + return atob(dataUri.substr(base64Idx)); + } else { + return dataUri.substr(dataUri.indexOf(",") + 1); + } + } + base64ToUint8Array(base64) { + var binary_string = window.atob(base64); + var len = binary_string.length; + var bytes = new Uint8Array(len); + for (var i = 0; i < len; i++) { + bytes[i] = binary_string.charCodeAt(i); + } + return bytes; + } + dataUriToUint8Array(dataUri) { + if (!dataUri.startsWith("data:")) { + throw new Error("Not a data URI."); + } + let base64Idx = dataUri.indexOf("base64,"); + if (base64Idx == -1) + throw new Error("Not a binary data URI."); + base64Idx += "base64,".length; + return this.base64ToUint8Array(dataUri.substr(base64Idx)); + } + downloadText(url, success, error) { + if (this.start(url, success, error)) + return; + if (this.rawDataUris[url]) { + try { + let dataUri = this.rawDataUris[url]; + this.finish(url, 200, this.dataUriToString(dataUri)); + } catch (e) { + this.finish(url, 400, JSON.stringify(e)); + } + return; + } + let request = new XMLHttpRequest(); + request.overrideMimeType("text/html"); + request.open("GET", url, true); + let done = () => { + this.finish(url, request.status, request.responseText); + }; + request.onload = done; + request.onerror = done; + request.send(); + } + downloadJson(url, success, error) { + this.downloadText(url, (data) => { + success(JSON.parse(data)); + }, error); + } + downloadBinary(url, success, error) { + if (this.start(url, success, error)) + return; + if (this.rawDataUris[url]) { + try { + let dataUri = this.rawDataUris[url]; + this.finish(url, 200, this.dataUriToUint8Array(dataUri)); + } catch (e) { + this.finish(url, 400, JSON.stringify(e)); + } + return; + } + let request = new XMLHttpRequest(); + request.open("GET", url, true); + request.responseType = "arraybuffer"; + let onerror = () => { + this.finish(url, request.status, request.response); + }; + request.onload = () => { + if (request.status == 200 || request.status == 0) + this.finish(url, 200, new Uint8Array(request.response)); + else + onerror(); + }; + request.onerror = onerror; + request.send(); + } + start(url, success, error) { + let callbacks = this.callbacks[url]; + try { + if (callbacks) + return true; + this.callbacks[url] = callbacks = []; + } finally { + callbacks.push(success, error); + } + } + finish(url, status, data) { + let callbacks = this.callbacks[url]; + delete this.callbacks[url]; + let args = status == 200 || status == 0 ? [data] : [status, data]; + for (let i = args.length - 1, n = callbacks.length; i < n; i += 2) + callbacks[i].apply(null, args); + } + }; + + // spine-core/src/Event.ts + var Event = class { + constructor(time, data) { + this.data = null; + this.intValue = 0; + this.floatValue = 0; + this.stringValue = null; + this.time = 0; + this.volume = 0; + this.balance = 0; + if (!data) + throw new Error("data cannot be null."); + this.time = time; + this.data = data; + } + }; + + // spine-core/src/EventData.ts + var EventData = class { + constructor(name) { + this.name = null; + this.intValue = 0; + this.floatValue = 0; + this.stringValue = null; + this.audioPath = null; + this.volume = 0; + this.balance = 0; + this.name = name; + } + }; + + // spine-core/src/IkConstraint.ts + var IkConstraint = class { + constructor(data, skeleton) { + this.data = null; + this.bones = null; + this.target = null; + this.bendDirection = 0; + this.compress = false; + this.stretch = false; + this.mix = 1; + this.softness = 0; + this.active = false; + if (!data) + throw new Error("data cannot be null."); + if (!skeleton) + throw new Error("skeleton cannot be null."); + this.data = data; + this.mix = data.mix; + this.softness = data.softness; + this.bendDirection = data.bendDirection; + this.compress = data.compress; + this.stretch = data.stretch; + this.bones = new Array(); + for (let i = 0; i < data.bones.length; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findBone(data.target.name); + } + isActive() { + return this.active; + } + update() { + if (this.mix == 0) + return; + let target = this.target; + let bones = this.bones; + switch (bones.length) { + case 1: + this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix); + break; + case 2: + this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.data.uniform, this.softness, this.mix); + break; + } + } + apply1(bone, targetX, targetY, compress, stretch, uniform, alpha) { + let p = bone.parent; + let pa = p.a, pb = p.b, pc = p.c, pd = p.d; + let rotationIK = -bone.ashearX - bone.arotation, tx = 0, ty = 0; + switch (bone.data.transformMode) { + case TransformMode.OnlyTranslation: + tx = targetX - bone.worldX; + ty = targetY - bone.worldY; + break; + case TransformMode.NoRotationOrReflection: + let s = Math.abs(pa * pd - pb * pc) / (pa * pa + pc * pc); + let sa = pa / bone.skeleton.scaleX; + let sc = pc / bone.skeleton.scaleY; + pb = -sc * s * bone.skeleton.scaleX; + pd = sa * s * bone.skeleton.scaleY; + rotationIK += Math.atan2(sc, sa) * MathUtils.radDeg; + default: + let x = targetX - p.worldX, y = targetY - p.worldY; + let d = pa * pd - pb * pc; + tx = (x * pd - y * pb) / d - bone.ax; + ty = (y * pa - x * pc) / d - bone.ay; + } + rotationIK += Math.atan2(ty, tx) * MathUtils.radDeg; + if (bone.ascaleX < 0) + rotationIK += 180; + if (rotationIK > 180) + rotationIK -= 360; + else if (rotationIK < -180) + rotationIK += 360; + let sx = bone.ascaleX, sy = bone.ascaleY; + if (compress || stretch) { + switch (bone.data.transformMode) { + case TransformMode.NoScale: + case TransformMode.NoScaleOrReflection: + tx = targetX - bone.worldX; + ty = targetY - bone.worldY; + } + let b = bone.data.length * sx, dd = Math.sqrt(tx * tx + ty * ty); + if (compress && dd < b || stretch && dd > b && b > 1e-4) { + let s = (dd / b - 1) * alpha + 1; + sx *= s; + if (uniform) + sy *= s; + } + } + bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY); + } + apply2(parent, child, targetX, targetY, bendDir, stretch, uniform, softness, alpha) { + let px = parent.ax, py = parent.ay, psx = parent.ascaleX, psy = parent.ascaleY, sx = psx, sy = psy, csx = child.ascaleX; + let os1 = 0, os2 = 0, s2 = 0; + if (psx < 0) { + psx = -psx; + os1 = 180; + s2 = -1; + } else { + os1 = 0; + s2 = 1; + } + if (psy < 0) { + psy = -psy; + s2 = -s2; + } + if (csx < 0) { + csx = -csx; + os2 = 180; + } else + os2 = 0; + let cx = child.ax, cy = 0, cwx = 0, cwy = 0, a = parent.a, b = parent.b, c = parent.c, d = parent.d; + let u = Math.abs(psx - psy) <= 1e-4; + if (!u || stretch) { + cy = 0; + cwx = a * cx + parent.worldX; + cwy = c * cx + parent.worldY; + } else { + cy = child.ay; + cwx = a * cx + b * cy + parent.worldX; + cwy = c * cx + d * cy + parent.worldY; + } + let pp = parent.parent; + a = pp.a; + b = pp.b; + c = pp.c; + d = pp.d; + let id = 1 / (a * d - b * c), x = cwx - pp.worldX, y = cwy - pp.worldY; + let dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; + let l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2; + if (l1 < 1e-4) { + this.apply1(parent, targetX, targetY, false, stretch, false, alpha); + child.updateWorldTransformWith(cx, cy, 0, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY); + return; + } + x = targetX - pp.worldX; + y = targetY - pp.worldY; + let tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py; + let dd = tx * tx + ty * ty; + if (softness != 0) { + softness *= psx * (csx + 1) * 0.5; + let td = Math.sqrt(dd), sd = td - l1 - l2 * psx + softness; + if (sd > 0) { + let p = Math.min(1, sd / (softness * 2)) - 1; + p = (sd - softness * (1 - p * p)) / td; + tx -= p * tx; + ty -= p * ty; + dd = tx * tx + ty * ty; + } + } + outer: + if (u) { + l2 *= psx; + let cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2); + if (cos < -1) { + cos = -1; + a2 = Math.PI * bendDir; + } else if (cos > 1) { + cos = 1; + a2 = 0; + if (stretch) { + a = (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1; + sx *= a; + if (uniform) + sy *= a; + } + } else + a2 = Math.acos(cos) * bendDir; + a = l1 + l2 * cos; + b = l2 * Math.sin(a2); + a1 = Math.atan2(ty * a - tx * b, tx * a + ty * b); + } else { + a = psx * l2; + b = psy * l2; + let aa = a * a, bb = b * b, ta = Math.atan2(ty, tx); + c = bb * l1 * l1 + aa * dd - aa * bb; + let c1 = -2 * bb * l1, c2 = bb - aa; + d = c1 * c1 - 4 * c2 * c; + if (d >= 0) { + let q = Math.sqrt(d); + if (c1 < 0) + q = -q; + q = -(c1 + q) * 0.5; + let r0 = q / c2, r1 = c / q; + let r = Math.abs(r0) < Math.abs(r1) ? r0 : r1; + if (r * r <= dd) { + y = Math.sqrt(dd - r * r) * bendDir; + a1 = ta - Math.atan2(y, r); + a2 = Math.atan2(y / psy, (r - l1) / psx); + break outer; + } + } + let minAngle = MathUtils.PI, minX = l1 - a, minDist = minX * minX, minY = 0; + let maxAngle = 0, maxX = l1 + a, maxDist = maxX * maxX, maxY = 0; + c = -a * l1 / (aa - bb); + if (c >= -1 && c <= 1) { + c = Math.acos(c); + x = a * Math.cos(c) + l1; + y = b * Math.sin(c); + d = x * x + y * y; + if (d < minDist) { + minAngle = c; + minDist = d; + minX = x; + minY = y; + } + if (d > maxDist) { + maxAngle = c; + maxDist = d; + maxX = x; + maxY = y; + } + } + if (dd <= (minDist + maxDist) * 0.5) { + a1 = ta - Math.atan2(minY * bendDir, minX); + a2 = minAngle * bendDir; + } else { + a1 = ta - Math.atan2(maxY * bendDir, maxX); + a2 = maxAngle * bendDir; + } + } + let os = Math.atan2(cy, cx) * s2; + let rotation = parent.arotation; + a1 = (a1 - os) * MathUtils.radDeg + os1 - rotation; + if (a1 > 180) + a1 -= 360; + else if (a1 < -180) + a1 += 360; + parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, sx, sy, 0, 0); + rotation = child.arotation; + a2 = ((a2 + os) * MathUtils.radDeg - child.ashearX) * s2 + os2 - rotation; + if (a2 > 180) + a2 -= 360; + else if (a2 < -180) + a2 += 360; + child.updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY); + } + }; + + // spine-core/src/IkConstraintData.ts + var IkConstraintData = class extends ConstraintData { + constructor(name) { + super(name, 0, false); + this.bones = new Array(); + this.target = null; + this.bendDirection = 1; + this.compress = false; + this.stretch = false; + this.uniform = false; + this.mix = 1; + this.softness = 0; + } + }; + + // spine-core/src/PathConstraintData.ts + var PathConstraintData = class extends ConstraintData { + constructor(name) { + super(name, 0, false); + this.bones = new Array(); + this.target = null; + this.positionMode = null; + this.spacingMode = null; + this.rotateMode = null; + this.offsetRotation = 0; + this.position = 0; + this.spacing = 0; + this.mixRotate = 0; + this.mixX = 0; + this.mixY = 0; + } + }; + var PositionMode; + (function(PositionMode2) { + PositionMode2[PositionMode2["Fixed"] = 0] = "Fixed"; + PositionMode2[PositionMode2["Percent"] = 1] = "Percent"; + })(PositionMode || (PositionMode = {})); + var SpacingMode; + (function(SpacingMode2) { + SpacingMode2[SpacingMode2["Length"] = 0] = "Length"; + SpacingMode2[SpacingMode2["Fixed"] = 1] = "Fixed"; + SpacingMode2[SpacingMode2["Percent"] = 2] = "Percent"; + SpacingMode2[SpacingMode2["Proportional"] = 3] = "Proportional"; + })(SpacingMode || (SpacingMode = {})); + var RotateMode; + (function(RotateMode2) { + RotateMode2[RotateMode2["Tangent"] = 0] = "Tangent"; + RotateMode2[RotateMode2["Chain"] = 1] = "Chain"; + RotateMode2[RotateMode2["ChainScale"] = 2] = "ChainScale"; + })(RotateMode || (RotateMode = {})); + + // spine-core/src/PathConstraint.ts + var _PathConstraint = class { + constructor(data, skeleton) { + this.data = null; + this.bones = null; + this.target = null; + this.position = 0; + this.spacing = 0; + this.mixRotate = 0; + this.mixX = 0; + this.mixY = 0; + this.spaces = new Array(); + this.positions = new Array(); + this.world = new Array(); + this.curves = new Array(); + this.lengths = new Array(); + this.segments = new Array(); + this.active = false; + if (!data) + throw new Error("data cannot be null."); + if (!skeleton) + throw new Error("skeleton cannot be null."); + this.data = data; + this.bones = new Array(); + for (let i = 0, n = data.bones.length; i < n; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findSlot(data.target.name); + this.position = data.position; + this.spacing = data.spacing; + this.mixRotate = data.mixRotate; + this.mixX = data.mixX; + this.mixY = data.mixY; + } + isActive() { + return this.active; + } + update() { + let attachment = this.target.getAttachment(); + if (!(attachment instanceof PathAttachment)) + return; + let mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY; + if (mixRotate == 0 && mixX == 0 && mixY == 0) + return; + let data = this.data; + let tangents = data.rotateMode == RotateMode.Tangent, scale = data.rotateMode == RotateMode.ChainScale; + let bones = this.bones; + let boneCount = bones.length, spacesCount = tangents ? boneCount : boneCount + 1; + let spaces = Utils.setArraySize(this.spaces, spacesCount), lengths = scale ? this.lengths = Utils.setArraySize(this.lengths, boneCount) : null; + let spacing = this.spacing; + switch (data.spacingMode) { + case SpacingMode.Percent: + if (scale) { + for (let i = 0, n = spacesCount - 1; i < n; i++) { + let bone = bones[i]; + let setupLength = bone.data.length; + if (setupLength < _PathConstraint.epsilon) + lengths[i] = 0; + else { + let x = setupLength * bone.a, y = setupLength * bone.c; + lengths[i] = Math.sqrt(x * x + y * y); + } + } + } + Utils.arrayFill(spaces, 1, spacesCount, spacing); + break; + case SpacingMode.Proportional: + let sum = 0; + for (let i = 0, n = spacesCount - 1; i < n; ) { + let bone = bones[i]; + let setupLength = bone.data.length; + if (setupLength < _PathConstraint.epsilon) { + if (scale) + lengths[i] = 0; + spaces[++i] = spacing; + } else { + let x = setupLength * bone.a, y = setupLength * bone.c; + let length = Math.sqrt(x * x + y * y); + if (scale) + lengths[i] = length; + spaces[++i] = length; + sum += length; + } + } + if (sum > 0) { + sum = spacesCount / sum * spacing; + for (let i = 1; i < spacesCount; i++) + spaces[i] *= sum; + } + break; + default: + let lengthSpacing = data.spacingMode == SpacingMode.Length; + for (let i = 0, n = spacesCount - 1; i < n; ) { + let bone = bones[i]; + let setupLength = bone.data.length; + if (setupLength < _PathConstraint.epsilon) { + if (scale) + lengths[i] = 0; + spaces[++i] = spacing; + } else { + let x = setupLength * bone.a, y = setupLength * bone.c; + let length = Math.sqrt(x * x + y * y); + if (scale) + lengths[i] = length; + spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength; + } + } + } + let positions = this.computeWorldPositions(attachment, spacesCount, tangents); + let boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation; + let tip = false; + if (offsetRotation == 0) + tip = data.rotateMode == RotateMode.Chain; + else { + tip = false; + let p = this.target.bone; + offsetRotation *= p.a * p.d - p.b * p.c > 0 ? MathUtils.degRad : -MathUtils.degRad; + } + for (let i = 0, p = 3; i < boneCount; i++, p += 3) { + let bone = bones[i]; + bone.worldX += (boneX - bone.worldX) * mixX; + bone.worldY += (boneY - bone.worldY) * mixY; + let x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY; + if (scale) { + let length = lengths[i]; + if (length != 0) { + let s = (Math.sqrt(dx * dx + dy * dy) / length - 1) * mixRotate + 1; + bone.a *= s; + bone.c *= s; + } + } + boneX = x; + boneY = y; + if (mixRotate > 0) { + let a = bone.a, b = bone.b, c = bone.c, d = bone.d, r = 0, cos = 0, sin = 0; + if (tangents) + r = positions[p - 1]; + else if (spaces[i + 1] == 0) + r = positions[p + 2]; + else + r = Math.atan2(dy, dx); + r -= Math.atan2(c, a); + if (tip) { + cos = Math.cos(r); + sin = Math.sin(r); + let length = bone.data.length; + boneX += (length * (cos * a - sin * c) - dx) * mixRotate; + boneY += (length * (sin * a + cos * c) - dy) * mixRotate; + } else { + r += offsetRotation; + } + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + r *= mixRotate; + cos = Math.cos(r); + sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + bone.updateAppliedTransform(); + } + } + computeWorldPositions(path, spacesCount, tangents) { + let target = this.target; + let position = this.position; + let spaces = this.spaces, out = Utils.setArraySize(this.positions, spacesCount * 3 + 2), world = null; + let closed2 = path.closed; + let verticesLength = path.worldVerticesLength, curveCount = verticesLength / 6, prevCurve = _PathConstraint.NONE; + if (!path.constantSpeed) { + let lengths = path.lengths; + curveCount -= closed2 ? 1 : 2; + let pathLength2 = lengths[curveCount]; + if (this.data.positionMode == PositionMode.Percent) + position *= pathLength2; + let multiplier2; + switch (this.data.spacingMode) { + case SpacingMode.Percent: + multiplier2 = pathLength2; + break; + case SpacingMode.Proportional: + multiplier2 = pathLength2 / spacesCount; + break; + default: + multiplier2 = 1; + } + world = Utils.setArraySize(this.world, 8); + for (let i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { + let space = spaces[i] * multiplier2; + position += space; + let p = position; + if (closed2) { + p %= pathLength2; + if (p < 0) + p += pathLength2; + curve = 0; + } else if (p < 0) { + if (prevCurve != _PathConstraint.BEFORE) { + prevCurve = _PathConstraint.BEFORE; + path.computeWorldVertices(target, 2, 4, world, 0, 2); + } + this.addBeforePosition(p, world, 0, out, o); + continue; + } else if (p > pathLength2) { + if (prevCurve != _PathConstraint.AFTER) { + prevCurve = _PathConstraint.AFTER; + path.computeWorldVertices(target, verticesLength - 6, 4, world, 0, 2); + } + this.addAfterPosition(p - pathLength2, world, 0, out, o); + continue; + } + for (; ; curve++) { + let length = lengths[curve]; + if (p > length) + continue; + if (curve == 0) + p /= length; + else { + let prev = lengths[curve - 1]; + p = (p - prev) / (length - prev); + } + break; + } + if (curve != prevCurve) { + prevCurve = curve; + if (closed2 && curve == curveCount) { + path.computeWorldVertices(target, verticesLength - 4, 4, world, 0, 2); + path.computeWorldVertices(target, 0, 4, world, 4, 2); + } else + path.computeWorldVertices(target, curve * 6 + 2, 8, world, 0, 2); + } + this.addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], out, o, tangents || i > 0 && space == 0); + } + return out; + } + if (closed2) { + verticesLength += 2; + world = Utils.setArraySize(this.world, verticesLength); + path.computeWorldVertices(target, 2, verticesLength - 4, world, 0, 2); + path.computeWorldVertices(target, 0, 2, world, verticesLength - 4, 2); + world[verticesLength - 2] = world[0]; + world[verticesLength - 1] = world[1]; + } else { + curveCount--; + verticesLength -= 4; + world = Utils.setArraySize(this.world, verticesLength); + path.computeWorldVertices(target, 2, verticesLength, world, 0, 2); + } + let curves = Utils.setArraySize(this.curves, curveCount); + let pathLength = 0; + let x1 = world[0], y1 = world[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0; + let tmpx = 0, tmpy = 0, dddfx = 0, dddfy = 0, ddfx = 0, ddfy = 0, dfx = 0, dfy = 0; + for (let i = 0, w = 2; i < curveCount; i++, w += 6) { + cx1 = world[w]; + cy1 = world[w + 1]; + cx2 = world[w + 2]; + cy2 = world[w + 3]; + x2 = world[w + 4]; + y2 = world[w + 5]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.1875; + tmpy = (y1 - cy1 * 2 + cy2) * 0.1875; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + curves[i] = pathLength; + x1 = x2; + y1 = y2; + } + if (this.data.positionMode == PositionMode.Percent) + position *= pathLength; + let multiplier; + switch (this.data.spacingMode) { + case SpacingMode.Percent: + multiplier = pathLength; + break; + case SpacingMode.Proportional: + multiplier = pathLength / spacesCount; + break; + default: + multiplier = 1; + } + let segments = this.segments; + let curveLength = 0; + for (let i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { + let space = spaces[i] * multiplier; + position += space; + let p = position; + if (closed2) { + p %= pathLength; + if (p < 0) + p += pathLength; + curve = 0; + } else if (p < 0) { + this.addBeforePosition(p, world, 0, out, o); + continue; + } else if (p > pathLength) { + this.addAfterPosition(p - pathLength, world, verticesLength - 4, out, o); + continue; + } + for (; ; curve++) { + let length = curves[curve]; + if (p > length) + continue; + if (curve == 0) + p /= length; + else { + let prev = curves[curve - 1]; + p = (p - prev) / (length - prev); + } + break; + } + if (curve != prevCurve) { + prevCurve = curve; + let ii = curve * 6; + x1 = world[ii]; + y1 = world[ii + 1]; + cx1 = world[ii + 2]; + cy1 = world[ii + 3]; + cx2 = world[ii + 4]; + cy2 = world[ii + 5]; + x2 = world[ii + 6]; + y2 = world[ii + 7]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.03; + tmpy = (y1 - cy1 * 2 + cy2) * 0.03; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 6e-3; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 6e-3; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667; + curveLength = Math.sqrt(dfx * dfx + dfy * dfy); + segments[0] = curveLength; + for (ii = 1; ii < 8; ii++) { + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[ii] = curveLength; + } + dfx += ddfx; + dfy += ddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[8] = curveLength; + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[9] = curveLength; + segment = 0; + } + p *= curveLength; + for (; ; segment++) { + let length = segments[segment]; + if (p > length) + continue; + if (segment == 0) + p /= length; + else { + let prev = segments[segment - 1]; + p = segment + (p - prev) / (length - prev); + } + break; + } + this.addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || i > 0 && space == 0); + } + return out; + } + addBeforePosition(p, temp, i, out, o) { + let x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + } + addAfterPosition(p, temp, i, out, o) { + let x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + } + addCurvePosition(p, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents) { + if (p == 0 || isNaN(p)) { + out[o] = x1; + out[o + 1] = y1; + out[o + 2] = Math.atan2(cy1 - y1, cx1 - x1); + return; + } + let tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u; + let ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p; + let x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; + out[o] = x; + out[o + 1] = y; + if (tangents) { + if (p < 1e-3) + out[o + 2] = Math.atan2(cy1 - y1, cx1 - x1); + else + out[o + 2] = Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); + } + } + }; + var PathConstraint = _PathConstraint; + PathConstraint.NONE = -1; + PathConstraint.BEFORE = -2; + PathConstraint.AFTER = -3; + PathConstraint.epsilon = 1e-5; + + // spine-core/src/Slot.ts + var Slot = class { + constructor(data, bone) { + this.data = null; + this.bone = null; + this.color = null; + this.darkColor = null; + this.attachment = null; + this.attachmentTime = 0; + this.attachmentState = 0; + this.deform = new Array(); + if (!data) + throw new Error("data cannot be null."); + if (!bone) + throw new Error("bone cannot be null."); + this.data = data; + this.bone = bone; + this.color = new Color(); + this.darkColor = !data.darkColor ? null : new Color(); + this.setToSetupPose(); + } + getSkeleton() { + return this.bone.skeleton; + } + getAttachment() { + return this.attachment; + } + setAttachment(attachment) { + if (this.attachment == attachment) + return; + if (!(attachment instanceof VertexAttachment) || !(this.attachment instanceof VertexAttachment) || attachment.deformAttachment != this.attachment.deformAttachment) { + this.deform.length = 0; + } + this.attachment = attachment; + this.attachmentTime = this.bone.skeleton.time; + } + setAttachmentTime(time) { + this.attachmentTime = this.bone.skeleton.time - time; + } + getAttachmentTime() { + return this.bone.skeleton.time - this.attachmentTime; + } + setToSetupPose() { + this.color.setFromColor(this.data.color); + if (this.darkColor) + this.darkColor.setFromColor(this.data.darkColor); + if (!this.data.attachmentName) + this.attachment = null; + else { + this.attachment = null; + this.setAttachment(this.bone.skeleton.getAttachment(this.data.index, this.data.attachmentName)); + } + } + }; + + // spine-core/src/TransformConstraint.ts + var TransformConstraint = class { + constructor(data, skeleton) { + this.data = null; + this.bones = null; + this.target = null; + this.mixRotate = 0; + this.mixX = 0; + this.mixY = 0; + this.mixScaleX = 0; + this.mixScaleY = 0; + this.mixShearY = 0; + this.temp = new Vector2(); + this.active = false; + if (!data) + throw new Error("data cannot be null."); + if (!skeleton) + throw new Error("skeleton cannot be null."); + this.data = data; + this.mixRotate = data.mixRotate; + this.mixX = data.mixX; + this.mixY = data.mixY; + this.mixScaleX = data.mixScaleX; + this.mixScaleY = data.mixScaleY; + this.mixShearY = data.mixShearY; + this.bones = new Array(); + for (let i = 0; i < data.bones.length; i++) + this.bones.push(skeleton.findBone(data.bones[i].name)); + this.target = skeleton.findBone(data.target.name); + } + isActive() { + return this.active; + } + update() { + if (this.mixRotate == 0 && this.mixX == 0 && this.mixY == 0 && this.mixScaleX == 0 && this.mixScaleX == 0 && this.mixShearY == 0) + return; + if (this.data.local) { + if (this.data.relative) + this.applyRelativeLocal(); + else + this.applyAbsoluteLocal(); + } else { + if (this.data.relative) + this.applyRelativeWorld(); + else + this.applyAbsoluteWorld(); + } + } + applyAbsoluteWorld() { + let mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX, mixScaleY = this.mixScaleY, mixShearY = this.mixShearY; + let translate = mixX != 0 || mixY != 0; + let target = this.target; + let ta = target.a, tb = target.b, tc = target.c, td = target.d; + let degRadReflect = ta * td - tb * tc > 0 ? MathUtils.degRad : -MathUtils.degRad; + let offsetRotation = this.data.offsetRotation * degRadReflect; + let offsetShearY = this.data.offsetShearY * degRadReflect; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (mixRotate != 0) { + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + let r = Math.atan2(tc, ta) - Math.atan2(c, a) + offsetRotation; + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + r *= mixRotate; + let cos = Math.cos(r), sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + if (translate) { + let temp = this.temp; + target.localToWorld(temp.set(this.data.offsetX, this.data.offsetY)); + bone.worldX += (temp.x - bone.worldX) * mixX; + bone.worldY += (temp.y - bone.worldY) * mixY; + } + if (mixScaleX != 0) { + let s = Math.sqrt(bone.a * bone.a + bone.c * bone.c); + if (s != 0) + s = (s + (Math.sqrt(ta * ta + tc * tc) - s + this.data.offsetScaleX) * mixScaleX) / s; + bone.a *= s; + bone.c *= s; + } + if (mixScaleY != 0) { + let s = Math.sqrt(bone.b * bone.b + bone.d * bone.d); + if (s != 0) + s = (s + (Math.sqrt(tb * tb + td * td) - s + this.data.offsetScaleY) * mixScaleY) / s; + bone.b *= s; + bone.d *= s; + } + if (mixShearY > 0) { + let b = bone.b, d = bone.d; + let by = Math.atan2(d, b); + let r = Math.atan2(td, tb) - Math.atan2(tc, ta) - (by - Math.atan2(bone.c, bone.a)); + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + r = by + (r + offsetShearY) * mixShearY; + let s = Math.sqrt(b * b + d * d); + bone.b = Math.cos(r) * s; + bone.d = Math.sin(r) * s; + } + bone.updateAppliedTransform(); + } + } + applyRelativeWorld() { + let mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX, mixScaleY = this.mixScaleY, mixShearY = this.mixShearY; + let translate = mixX != 0 || mixY != 0; + let target = this.target; + let ta = target.a, tb = target.b, tc = target.c, td = target.d; + let degRadReflect = ta * td - tb * tc > 0 ? MathUtils.degRad : -MathUtils.degRad; + let offsetRotation = this.data.offsetRotation * degRadReflect, offsetShearY = this.data.offsetShearY * degRadReflect; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (mixRotate != 0) { + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + let r = Math.atan2(tc, ta) + offsetRotation; + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + r *= mixRotate; + let cos = Math.cos(r), sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + if (translate) { + let temp = this.temp; + target.localToWorld(temp.set(this.data.offsetX, this.data.offsetY)); + bone.worldX += temp.x * mixX; + bone.worldY += temp.y * mixY; + } + if (mixScaleX != 0) { + let s = (Math.sqrt(ta * ta + tc * tc) - 1 + this.data.offsetScaleX) * mixScaleX + 1; + bone.a *= s; + bone.c *= s; + } + if (mixScaleY != 0) { + let s = (Math.sqrt(tb * tb + td * td) - 1 + this.data.offsetScaleY) * mixScaleY + 1; + bone.b *= s; + bone.d *= s; + } + if (mixShearY > 0) { + let r = Math.atan2(td, tb) - Math.atan2(tc, ta); + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + let b = bone.b, d = bone.d; + r = Math.atan2(d, b) + (r - MathUtils.PI / 2 + offsetShearY) * mixShearY; + let s = Math.sqrt(b * b + d * d); + bone.b = Math.cos(r) * s; + bone.d = Math.sin(r) * s; + } + bone.updateAppliedTransform(); + } + } + applyAbsoluteLocal() { + let mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX, mixScaleY = this.mixScaleY, mixShearY = this.mixShearY; + let target = this.target; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + let rotation = bone.arotation; + if (mixRotate != 0) { + let r = target.arotation - rotation + this.data.offsetRotation; + r -= (16384 - (16384.499999999996 - r / 360 | 0)) * 360; + rotation += r * mixRotate; + } + let x = bone.ax, y = bone.ay; + x += (target.ax - x + this.data.offsetX) * mixX; + y += (target.ay - y + this.data.offsetY) * mixY; + let scaleX = bone.ascaleX, scaleY = bone.ascaleY; + if (mixScaleX != 0 && scaleX != 0) + scaleX = (scaleX + (target.ascaleX - scaleX + this.data.offsetScaleX) * mixScaleX) / scaleX; + if (mixScaleY != 0 && scaleY != 0) + scaleY = (scaleY + (target.ascaleY - scaleY + this.data.offsetScaleY) * mixScaleY) / scaleY; + let shearY = bone.ashearY; + if (mixShearY != 0) { + let r = target.ashearY - shearY + this.data.offsetShearY; + r -= (16384 - (16384.499999999996 - r / 360 | 0)) * 360; + shearY += r * mixShearY; + } + bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY); + } + } + applyRelativeLocal() { + let mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX, mixScaleY = this.mixScaleY, mixShearY = this.mixShearY; + let target = this.target; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + let rotation = bone.arotation + (target.arotation + this.data.offsetRotation) * mixRotate; + let x = bone.ax + (target.ax + this.data.offsetX) * mixX; + let y = bone.ay + (target.ay + this.data.offsetY) * mixY; + let scaleX = bone.ascaleX * ((target.ascaleX - 1 + this.data.offsetScaleX) * mixScaleX + 1); + let scaleY = bone.ascaleY * ((target.ascaleY - 1 + this.data.offsetScaleY) * mixScaleY + 1); + let shearY = bone.ashearY + (target.ashearY + this.data.offsetShearY) * mixShearY; + bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY); + } + } + }; + + // spine-core/src/Skeleton.ts + var Skeleton = class { + constructor(data) { + this.data = null; + this.bones = null; + this.slots = null; + this.drawOrder = null; + this.ikConstraints = null; + this.transformConstraints = null; + this.pathConstraints = null; + this._updateCache = new Array(); + this.skin = null; + this.color = null; + this.time = 0; + this.scaleX = 1; + this.scaleY = 1; + this.x = 0; + this.y = 0; + if (!data) + throw new Error("data cannot be null."); + this.data = data; + this.bones = new Array(); + for (let i = 0; i < data.bones.length; i++) { + let boneData = data.bones[i]; + let bone; + if (!boneData.parent) + bone = new Bone(boneData, this, null); + else { + let parent = this.bones[boneData.parent.index]; + bone = new Bone(boneData, this, parent); + parent.children.push(bone); + } + this.bones.push(bone); + } + this.slots = new Array(); + this.drawOrder = new Array(); + for (let i = 0; i < data.slots.length; i++) { + let slotData = data.slots[i]; + let bone = this.bones[slotData.boneData.index]; + let slot = new Slot(slotData, bone); + this.slots.push(slot); + this.drawOrder.push(slot); + } + this.ikConstraints = new Array(); + for (let i = 0; i < data.ikConstraints.length; i++) { + let ikConstraintData = data.ikConstraints[i]; + this.ikConstraints.push(new IkConstraint(ikConstraintData, this)); + } + this.transformConstraints = new Array(); + for (let i = 0; i < data.transformConstraints.length; i++) { + let transformConstraintData = data.transformConstraints[i]; + this.transformConstraints.push(new TransformConstraint(transformConstraintData, this)); + } + this.pathConstraints = new Array(); + for (let i = 0; i < data.pathConstraints.length; i++) { + let pathConstraintData = data.pathConstraints[i]; + this.pathConstraints.push(new PathConstraint(pathConstraintData, this)); + } + this.color = new Color(1, 1, 1, 1); + this.updateCache(); + } + updateCache() { + let updateCache = this._updateCache; + updateCache.length = 0; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + bone.sorted = bone.data.skinRequired; + bone.active = !bone.sorted; + } + if (this.skin) { + let skinBones = this.skin.bones; + for (let i = 0, n = this.skin.bones.length; i < n; i++) { + let bone = this.bones[skinBones[i].index]; + do { + bone.sorted = false; + bone.active = true; + bone = bone.parent; + } while (bone); + } + } + let ikConstraints = this.ikConstraints; + let transformConstraints = this.transformConstraints; + let pathConstraints = this.pathConstraints; + let ikCount = ikConstraints.length, transformCount = transformConstraints.length, pathCount = pathConstraints.length; + let constraintCount = ikCount + transformCount + pathCount; + outer: + for (let i = 0; i < constraintCount; i++) { + for (let ii = 0; ii < ikCount; ii++) { + let constraint = ikConstraints[ii]; + if (constraint.data.order == i) { + this.sortIkConstraint(constraint); + continue outer; + } + } + for (let ii = 0; ii < transformCount; ii++) { + let constraint = transformConstraints[ii]; + if (constraint.data.order == i) { + this.sortTransformConstraint(constraint); + continue outer; + } + } + for (let ii = 0; ii < pathCount; ii++) { + let constraint = pathConstraints[ii]; + if (constraint.data.order == i) { + this.sortPathConstraint(constraint); + continue outer; + } + } + } + for (let i = 0, n = bones.length; i < n; i++) + this.sortBone(bones[i]); + } + sortIkConstraint(constraint) { + constraint.active = constraint.target.isActive() && (!constraint.data.skinRequired || this.skin && Utils.contains(this.skin.constraints, constraint.data, true)); + if (!constraint.active) + return; + let target = constraint.target; + this.sortBone(target); + let constrained = constraint.bones; + let parent = constrained[0]; + this.sortBone(parent); + if (constrained.length == 1) { + this._updateCache.push(constraint); + this.sortReset(parent.children); + } else { + let child = constrained[constrained.length - 1]; + this.sortBone(child); + this._updateCache.push(constraint); + this.sortReset(parent.children); + child.sorted = true; + } + } + sortPathConstraint(constraint) { + constraint.active = constraint.target.bone.isActive() && (!constraint.data.skinRequired || this.skin && Utils.contains(this.skin.constraints, constraint.data, true)); + if (!constraint.active) + return; + let slot = constraint.target; + let slotIndex = slot.data.index; + let slotBone = slot.bone; + if (this.skin) + this.sortPathConstraintAttachment(this.skin, slotIndex, slotBone); + if (this.data.defaultSkin && this.data.defaultSkin != this.skin) + this.sortPathConstraintAttachment(this.data.defaultSkin, slotIndex, slotBone); + for (let i = 0, n = this.data.skins.length; i < n; i++) + this.sortPathConstraintAttachment(this.data.skins[i], slotIndex, slotBone); + let attachment = slot.getAttachment(); + if (attachment instanceof PathAttachment) + this.sortPathConstraintAttachmentWith(attachment, slotBone); + let constrained = constraint.bones; + let boneCount = constrained.length; + for (let i = 0; i < boneCount; i++) + this.sortBone(constrained[i]); + this._updateCache.push(constraint); + for (let i = 0; i < boneCount; i++) + this.sortReset(constrained[i].children); + for (let i = 0; i < boneCount; i++) + constrained[i].sorted = true; + } + sortTransformConstraint(constraint) { + constraint.active = constraint.target.isActive() && (!constraint.data.skinRequired || this.skin && Utils.contains(this.skin.constraints, constraint.data, true)); + if (!constraint.active) + return; + this.sortBone(constraint.target); + let constrained = constraint.bones; + let boneCount = constrained.length; + if (constraint.data.local) { + for (let i = 0; i < boneCount; i++) { + let child = constrained[i]; + this.sortBone(child.parent); + this.sortBone(child); + } + } else { + for (let i = 0; i < boneCount; i++) { + this.sortBone(constrained[i]); + } + } + this._updateCache.push(constraint); + for (let i = 0; i < boneCount; i++) + this.sortReset(constrained[i].children); + for (let i = 0; i < boneCount; i++) + constrained[i].sorted = true; + } + sortPathConstraintAttachment(skin, slotIndex, slotBone) { + let attachments = skin.attachments[slotIndex]; + if (!attachments) + return; + for (let key in attachments) { + this.sortPathConstraintAttachmentWith(attachments[key], slotBone); + } + } + sortPathConstraintAttachmentWith(attachment, slotBone) { + if (!(attachment instanceof PathAttachment)) + return; + let pathBones = attachment.bones; + if (!pathBones) + this.sortBone(slotBone); + else { + let bones = this.bones; + for (let i = 0, n = pathBones.length; i < n; ) { + let nn = pathBones[i++]; + nn += i; + while (i < nn) + this.sortBone(bones[pathBones[i++]]); + } + } + } + sortBone(bone) { + if (bone.sorted) + return; + let parent = bone.parent; + if (parent) + this.sortBone(parent); + bone.sorted = true; + this._updateCache.push(bone); + } + sortReset(bones) { + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (!bone.active) + continue; + if (bone.sorted) + this.sortReset(bone.children); + bone.sorted = false; + } + } + updateWorldTransform() { + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + bone.ax = bone.x; + bone.ay = bone.y; + bone.arotation = bone.rotation; + bone.ascaleX = bone.scaleX; + bone.ascaleY = bone.scaleY; + bone.ashearX = bone.shearX; + bone.ashearY = bone.shearY; + } + let updateCache = this._updateCache; + for (let i = 0, n = updateCache.length; i < n; i++) + updateCache[i].update(); + } + updateWorldTransformWith(parent) { + let rootBone = this.getRootBone(); + let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + rootBone.worldX = pa * this.x + pb * this.y + parent.worldX; + rootBone.worldY = pc * this.x + pd * this.y + parent.worldY; + let rotationY = rootBone.rotation + 90 + rootBone.shearY; + let la = MathUtils.cosDeg(rootBone.rotation + rootBone.shearX) * rootBone.scaleX; + let lb = MathUtils.cosDeg(rotationY) * rootBone.scaleY; + let lc = MathUtils.sinDeg(rootBone.rotation + rootBone.shearX) * rootBone.scaleX; + let ld = MathUtils.sinDeg(rotationY) * rootBone.scaleY; + rootBone.a = (pa * la + pb * lc) * this.scaleX; + rootBone.b = (pa * lb + pb * ld) * this.scaleX; + rootBone.c = (pc * la + pd * lc) * this.scaleY; + rootBone.d = (pc * lb + pd * ld) * this.scaleY; + let updateCache = this._updateCache; + for (let i = 0, n = updateCache.length; i < n; i++) { + let updatable = updateCache[i]; + if (updatable != rootBone) + updatable.update(); + } + } + setToSetupPose() { + this.setBonesToSetupPose(); + this.setSlotsToSetupPose(); + } + setBonesToSetupPose() { + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) + bones[i].setToSetupPose(); + let ikConstraints = this.ikConstraints; + for (let i = 0, n = ikConstraints.length; i < n; i++) { + let constraint = ikConstraints[i]; + constraint.mix = constraint.data.mix; + constraint.softness = constraint.data.softness; + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } + let transformConstraints = this.transformConstraints; + for (let i = 0, n = transformConstraints.length; i < n; i++) { + let constraint = transformConstraints[i]; + let data = constraint.data; + constraint.mixRotate = data.mixRotate; + constraint.mixX = data.mixX; + constraint.mixY = data.mixY; + constraint.mixScaleX = data.mixScaleX; + constraint.mixScaleY = data.mixScaleY; + constraint.mixShearY = data.mixShearY; + } + let pathConstraints = this.pathConstraints; + for (let i = 0, n = pathConstraints.length; i < n; i++) { + let constraint = pathConstraints[i]; + let data = constraint.data; + constraint.position = data.position; + constraint.spacing = data.spacing; + constraint.mixRotate = data.mixRotate; + constraint.mixX = data.mixX; + constraint.mixY = data.mixY; + } + } + setSlotsToSetupPose() { + let slots = this.slots; + Utils.arrayCopy(slots, 0, this.drawOrder, 0, slots.length); + for (let i = 0, n = slots.length; i < n; i++) + slots[i].setToSetupPose(); + } + getRootBone() { + if (this.bones.length == 0) + return null; + return this.bones[0]; + } + findBone(boneName) { + if (!boneName) + throw new Error("boneName cannot be null."); + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (bone.data.name == boneName) + return bone; + } + return null; + } + findSlot(slotName) { + if (!slotName) + throw new Error("slotName cannot be null."); + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + if (slot.data.name == slotName) + return slot; + } + return null; + } + setSkinByName(skinName) { + let skin = this.data.findSkin(skinName); + if (!skin) + throw new Error("Skin not found: " + skinName); + this.setSkin(skin); + } + setSkin(newSkin) { + if (newSkin == this.skin) + return; + if (newSkin) { + if (this.skin) + newSkin.attachAll(this, this.skin); + else { + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + let name = slot.data.attachmentName; + if (name) { + let attachment = newSkin.getAttachment(i, name); + if (attachment) + slot.setAttachment(attachment); + } + } + } + } + this.skin = newSkin; + this.updateCache(); + } + getAttachmentByName(slotName, attachmentName) { + return this.getAttachment(this.data.findSlot(slotName).index, attachmentName); + } + getAttachment(slotIndex, attachmentName) { + if (!attachmentName) + throw new Error("attachmentName cannot be null."); + if (this.skin) { + let attachment = this.skin.getAttachment(slotIndex, attachmentName); + if (attachment) + return attachment; + } + if (this.data.defaultSkin) + return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); + return null; + } + setAttachment(slotName, attachmentName) { + if (!slotName) + throw new Error("slotName cannot be null."); + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + if (slot.data.name == slotName) { + let attachment = null; + if (attachmentName) { + attachment = this.getAttachment(i, attachmentName); + if (!attachment) + throw new Error("Attachment not found: " + attachmentName + ", for slot: " + slotName); + } + slot.setAttachment(attachment); + return; + } + } + throw new Error("Slot not found: " + slotName); + } + findIkConstraint(constraintName) { + if (!constraintName) + throw new Error("constraintName cannot be null."); + let ikConstraints = this.ikConstraints; + for (let i = 0, n = ikConstraints.length; i < n; i++) { + let ikConstraint = ikConstraints[i]; + if (ikConstraint.data.name == constraintName) + return ikConstraint; + } + return null; + } + findTransformConstraint(constraintName) { + if (!constraintName) + throw new Error("constraintName cannot be null."); + let transformConstraints = this.transformConstraints; + for (let i = 0, n = transformConstraints.length; i < n; i++) { + let constraint = transformConstraints[i]; + if (constraint.data.name == constraintName) + return constraint; + } + return null; + } + findPathConstraint(constraintName) { + if (!constraintName) + throw new Error("constraintName cannot be null."); + let pathConstraints = this.pathConstraints; + for (let i = 0, n = pathConstraints.length; i < n; i++) { + let constraint = pathConstraints[i]; + if (constraint.data.name == constraintName) + return constraint; + } + return null; + } + getBoundsRect() { + let offset = new Vector2(); + let size = new Vector2(); + this.getBounds(offset, size); + return { x: offset.x, y: offset.y, width: size.x, height: size.y }; + } + getBounds(offset, size, temp = new Array(2)) { + if (!offset) + throw new Error("offset cannot be null."); + if (!size) + throw new Error("size cannot be null."); + let drawOrder = this.drawOrder; + let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + for (let i = 0, n = drawOrder.length; i < n; i++) { + let slot = drawOrder[i]; + if (!slot.bone.active) + continue; + let verticesLength = 0; + let vertices = null; + let attachment = slot.getAttachment(); + if (attachment instanceof RegionAttachment) { + verticesLength = 8; + vertices = Utils.setArraySize(temp, verticesLength, 0); + attachment.computeWorldVertices(slot.bone, vertices, 0, 2); + } else if (attachment instanceof MeshAttachment) { + let mesh = attachment; + verticesLength = mesh.worldVerticesLength; + vertices = Utils.setArraySize(temp, verticesLength, 0); + mesh.computeWorldVertices(slot, 0, verticesLength, vertices, 0, 2); + } + if (vertices) { + for (let ii = 0, nn = vertices.length; ii < nn; ii += 2) { + let x = vertices[ii], y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + } + offset.set(minX, minY); + size.set(maxX - minX, maxY - minY); + } + update(delta) { + this.time += delta; + } + }; + + // spine-core/src/SkeletonData.ts + var SkeletonData = class { + constructor() { + this.name = null; + this.bones = new Array(); + this.slots = new Array(); + this.skins = new Array(); + this.defaultSkin = null; + this.events = new Array(); + this.animations = new Array(); + this.ikConstraints = new Array(); + this.transformConstraints = new Array(); + this.pathConstraints = new Array(); + this.x = 0; + this.y = 0; + this.width = 0; + this.height = 0; + this.version = null; + this.hash = null; + this.fps = 0; + this.imagesPath = null; + this.audioPath = null; + } + findBone(boneName) { + if (!boneName) + throw new Error("boneName cannot be null."); + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (bone.name == boneName) + return bone; + } + return null; + } + findSlot(slotName) { + if (!slotName) + throw new Error("slotName cannot be null."); + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + if (slot.name == slotName) + return slot; + } + return null; + } + findSkin(skinName) { + if (!skinName) + throw new Error("skinName cannot be null."); + let skins = this.skins; + for (let i = 0, n = skins.length; i < n; i++) { + let skin = skins[i]; + if (skin.name == skinName) + return skin; + } + return null; + } + findEvent(eventDataName) { + if (!eventDataName) + throw new Error("eventDataName cannot be null."); + let events = this.events; + for (let i = 0, n = events.length; i < n; i++) { + let event = events[i]; + if (event.name == eventDataName) + return event; + } + return null; + } + findAnimation(animationName) { + if (!animationName) + throw new Error("animationName cannot be null."); + let animations = this.animations; + for (let i = 0, n = animations.length; i < n; i++) { + let animation = animations[i]; + if (animation.name == animationName) + return animation; + } + return null; + } + findIkConstraint(constraintName) { + if (!constraintName) + throw new Error("constraintName cannot be null."); + let ikConstraints = this.ikConstraints; + for (let i = 0, n = ikConstraints.length; i < n; i++) { + let constraint = ikConstraints[i]; + if (constraint.name == constraintName) + return constraint; + } + return null; + } + findTransformConstraint(constraintName) { + if (!constraintName) + throw new Error("constraintName cannot be null."); + let transformConstraints = this.transformConstraints; + for (let i = 0, n = transformConstraints.length; i < n; i++) { + let constraint = transformConstraints[i]; + if (constraint.name == constraintName) + return constraint; + } + return null; + } + findPathConstraint(constraintName) { + if (!constraintName) + throw new Error("constraintName cannot be null."); + let pathConstraints = this.pathConstraints; + for (let i = 0, n = pathConstraints.length; i < n; i++) { + let constraint = pathConstraints[i]; + if (constraint.name == constraintName) + return constraint; + } + return null; + } + }; + + // spine-core/src/Skin.ts + var SkinEntry = class { + constructor(slotIndex = 0, name = null, attachment = null) { + this.slotIndex = slotIndex; + this.name = name; + this.attachment = attachment; + } + }; + var Skin = class { + constructor(name) { + this.name = null; + this.attachments = new Array(); + this.bones = Array(); + this.constraints = new Array(); + if (!name) + throw new Error("name cannot be null."); + this.name = name; + } + setAttachment(slotIndex, name, attachment) { + if (!attachment) + throw new Error("attachment cannot be null."); + let attachments = this.attachments; + if (slotIndex >= attachments.length) + attachments.length = slotIndex + 1; + if (!attachments[slotIndex]) + attachments[slotIndex] = {}; + attachments[slotIndex][name] = attachment; + } + addSkin(skin) { + for (let i = 0; i < skin.bones.length; i++) { + let bone = skin.bones[i]; + let contained = false; + for (let ii = 0; ii < this.bones.length; ii++) { + if (this.bones[ii] == bone) { + contained = true; + break; + } + } + if (!contained) + this.bones.push(bone); + } + for (let i = 0; i < skin.constraints.length; i++) { + let constraint = skin.constraints[i]; + let contained = false; + for (let ii = 0; ii < this.constraints.length; ii++) { + if (this.constraints[ii] == constraint) { + contained = true; + break; + } + } + if (!contained) + this.constraints.push(constraint); + } + let attachments = skin.getAttachments(); + for (let i = 0; i < attachments.length; i++) { + var attachment = attachments[i]; + this.setAttachment(attachment.slotIndex, attachment.name, attachment.attachment); + } + } + copySkin(skin) { + for (let i = 0; i < skin.bones.length; i++) { + let bone = skin.bones[i]; + let contained = false; + for (let ii = 0; ii < this.bones.length; ii++) { + if (this.bones[ii] == bone) { + contained = true; + break; + } + } + if (!contained) + this.bones.push(bone); + } + for (let i = 0; i < skin.constraints.length; i++) { + let constraint = skin.constraints[i]; + let contained = false; + for (let ii = 0; ii < this.constraints.length; ii++) { + if (this.constraints[ii] == constraint) { + contained = true; + break; + } + } + if (!contained) + this.constraints.push(constraint); + } + let attachments = skin.getAttachments(); + for (let i = 0; i < attachments.length; i++) { + var attachment = attachments[i]; + if (!attachment.attachment) + continue; + if (attachment.attachment instanceof MeshAttachment) { + attachment.attachment = attachment.attachment.newLinkedMesh(); + this.setAttachment(attachment.slotIndex, attachment.name, attachment.attachment); + } else { + attachment.attachment = attachment.attachment.copy(); + this.setAttachment(attachment.slotIndex, attachment.name, attachment.attachment); + } + } + } + getAttachment(slotIndex, name) { + let dictionary = this.attachments[slotIndex]; + return dictionary ? dictionary[name] : null; + } + removeAttachment(slotIndex, name) { + let dictionary = this.attachments[slotIndex]; + if (dictionary) + dictionary[name] = null; + } + getAttachments() { + let entries = new Array(); + for (var i = 0; i < this.attachments.length; i++) { + let slotAttachments = this.attachments[i]; + if (slotAttachments) { + for (let name in slotAttachments) { + let attachment = slotAttachments[name]; + if (attachment) + entries.push(new SkinEntry(i, name, attachment)); + } + } + } + return entries; + } + getAttachmentsForSlot(slotIndex, attachments) { + let slotAttachments = this.attachments[slotIndex]; + if (slotAttachments) { + for (let name in slotAttachments) { + let attachment = slotAttachments[name]; + if (attachment) + attachments.push(new SkinEntry(slotIndex, name, attachment)); + } + } + } + clear() { + this.attachments.length = 0; + this.bones.length = 0; + this.constraints.length = 0; + } + attachAll(skeleton, oldSkin) { + let slotIndex = 0; + for (let i = 0; i < skeleton.slots.length; i++) { + let slot = skeleton.slots[i]; + let slotAttachment = slot.getAttachment(); + if (slotAttachment && slotIndex < oldSkin.attachments.length) { + let dictionary = oldSkin.attachments[slotIndex]; + for (let key in dictionary) { + let skinAttachment = dictionary[key]; + if (slotAttachment == skinAttachment) { + let attachment = this.getAttachment(slotIndex, key); + if (attachment) + slot.setAttachment(attachment); + break; + } + } + } + slotIndex++; + } + } + }; + + // spine-core/src/SlotData.ts + var SlotData = class { + constructor(index, name, boneData) { + this.index = 0; + this.name = null; + this.boneData = null; + this.color = new Color(1, 1, 1, 1); + this.darkColor = null; + this.attachmentName = null; + this.blendMode = null; + if (index < 0) + throw new Error("index must be >= 0."); + if (!name) + throw new Error("name cannot be null."); + if (!boneData) + throw new Error("boneData cannot be null."); + this.index = index; + this.name = name; + this.boneData = boneData; + } + }; + var BlendMode; + (function(BlendMode3) { + BlendMode3[BlendMode3["Normal"] = 0] = "Normal"; + BlendMode3[BlendMode3["Additive"] = 1] = "Additive"; + BlendMode3[BlendMode3["Multiply"] = 2] = "Multiply"; + BlendMode3[BlendMode3["Screen"] = 3] = "Screen"; + })(BlendMode || (BlendMode = {})); + + // spine-core/src/TransformConstraintData.ts + var TransformConstraintData = class extends ConstraintData { + constructor(name) { + super(name, 0, false); + this.bones = new Array(); + this.target = null; + this.mixRotate = 0; + this.mixX = 0; + this.mixY = 0; + this.mixScaleX = 0; + this.mixScaleY = 0; + this.mixShearY = 0; + this.offsetRotation = 0; + this.offsetX = 0; + this.offsetY = 0; + this.offsetScaleX = 0; + this.offsetScaleY = 0; + this.offsetShearY = 0; + this.relative = false; + this.local = false; + } + }; + + // spine-core/src/SkeletonBinary.ts + var SkeletonBinary = class { + constructor(attachmentLoader) { + this.scale = 1; + this.attachmentLoader = null; + this.linkedMeshes = new Array(); + this.attachmentLoader = attachmentLoader; + } + readSkeletonData(binary) { + let scale = this.scale; + let skeletonData = new SkeletonData(); + skeletonData.name = ""; + let input = new BinaryInput(binary); + let lowHash = input.readInt32(); + let highHash = input.readInt32(); + skeletonData.hash = highHash == 0 && lowHash == 0 ? null : highHash.toString(16) + lowHash.toString(16); + skeletonData.version = input.readString(); + skeletonData.x = input.readFloat(); + skeletonData.y = input.readFloat(); + skeletonData.width = input.readFloat(); + skeletonData.height = input.readFloat(); + let nonessential = input.readBoolean(); + if (nonessential) { + skeletonData.fps = input.readFloat(); + skeletonData.imagesPath = input.readString(); + skeletonData.audioPath = input.readString(); + } + let n = 0; + n = input.readInt(true); + for (let i = 0; i < n; i++) + input.strings.push(input.readString()); + n = input.readInt(true); + for (let i = 0; i < n; i++) { + let name = input.readString(); + let parent = i == 0 ? null : skeletonData.bones[input.readInt(true)]; + let data = new BoneData(i, name, parent); + data.rotation = input.readFloat(); + data.x = input.readFloat() * scale; + data.y = input.readFloat() * scale; + data.scaleX = input.readFloat(); + data.scaleY = input.readFloat(); + data.shearX = input.readFloat(); + data.shearY = input.readFloat(); + data.length = input.readFloat() * scale; + data.transformMode = input.readInt(true); + data.skinRequired = input.readBoolean(); + if (nonessential) + Color.rgba8888ToColor(data.color, input.readInt32()); + skeletonData.bones.push(data); + } + n = input.readInt(true); + for (let i = 0; i < n; i++) { + let slotName = input.readString(); + let boneData = skeletonData.bones[input.readInt(true)]; + let data = new SlotData(i, slotName, boneData); + Color.rgba8888ToColor(data.color, input.readInt32()); + let darkColor = input.readInt32(); + if (darkColor != -1) + Color.rgb888ToColor(data.darkColor = new Color(), darkColor); + data.attachmentName = input.readStringRef(); + data.blendMode = input.readInt(true); + skeletonData.slots.push(data); + } + n = input.readInt(true); + for (let i = 0, nn; i < n; i++) { + let data = new IkConstraintData(input.readString()); + data.order = input.readInt(true); + data.skinRequired = input.readBoolean(); + nn = input.readInt(true); + for (let ii = 0; ii < nn; ii++) + data.bones.push(skeletonData.bones[input.readInt(true)]); + data.target = skeletonData.bones[input.readInt(true)]; + data.mix = input.readFloat(); + data.softness = input.readFloat() * scale; + data.bendDirection = input.readByte(); + data.compress = input.readBoolean(); + data.stretch = input.readBoolean(); + data.uniform = input.readBoolean(); + skeletonData.ikConstraints.push(data); + } + n = input.readInt(true); + for (let i = 0, nn; i < n; i++) { + let data = new TransformConstraintData(input.readString()); + data.order = input.readInt(true); + data.skinRequired = input.readBoolean(); + nn = input.readInt(true); + for (let ii = 0; ii < nn; ii++) + data.bones.push(skeletonData.bones[input.readInt(true)]); + data.target = skeletonData.bones[input.readInt(true)]; + data.local = input.readBoolean(); + data.relative = input.readBoolean(); + data.offsetRotation = input.readFloat(); + data.offsetX = input.readFloat() * scale; + data.offsetY = input.readFloat() * scale; + data.offsetScaleX = input.readFloat(); + data.offsetScaleY = input.readFloat(); + data.offsetShearY = input.readFloat(); + data.mixRotate = input.readFloat(); + data.mixX = input.readFloat(); + data.mixY = input.readFloat(); + data.mixScaleX = input.readFloat(); + data.mixScaleY = input.readFloat(); + data.mixShearY = input.readFloat(); + skeletonData.transformConstraints.push(data); + } + n = input.readInt(true); + for (let i = 0, nn; i < n; i++) { + let data = new PathConstraintData(input.readString()); + data.order = input.readInt(true); + data.skinRequired = input.readBoolean(); + nn = input.readInt(true); + for (let ii = 0; ii < nn; ii++) + data.bones.push(skeletonData.bones[input.readInt(true)]); + data.target = skeletonData.slots[input.readInt(true)]; + data.positionMode = input.readInt(true); + data.spacingMode = input.readInt(true); + data.rotateMode = input.readInt(true); + data.offsetRotation = input.readFloat(); + data.position = input.readFloat(); + if (data.positionMode == PositionMode.Fixed) + data.position *= scale; + data.spacing = input.readFloat(); + if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) + data.spacing *= scale; + data.mixRotate = input.readFloat(); + data.mixX = input.readFloat(); + data.mixY = input.readFloat(); + skeletonData.pathConstraints.push(data); + } + let defaultSkin = this.readSkin(input, skeletonData, true, nonessential); + if (defaultSkin) { + skeletonData.defaultSkin = defaultSkin; + skeletonData.skins.push(defaultSkin); + } + { + let i = skeletonData.skins.length; + Utils.setArraySize(skeletonData.skins, n = i + input.readInt(true)); + for (; i < n; i++) + skeletonData.skins[i] = this.readSkin(input, skeletonData, false, nonessential); + } + n = this.linkedMeshes.length; + for (let i = 0; i < n; i++) { + let linkedMesh = this.linkedMeshes[i]; + let skin = !linkedMesh.skin ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin); + let parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); + linkedMesh.mesh.deformAttachment = linkedMesh.inheritDeform ? parent : linkedMesh.mesh; + linkedMesh.mesh.setParentMesh(parent); + linkedMesh.mesh.updateUVs(); + } + this.linkedMeshes.length = 0; + n = input.readInt(true); + for (let i = 0; i < n; i++) { + let data = new EventData(input.readStringRef()); + data.intValue = input.readInt(false); + data.floatValue = input.readFloat(); + data.stringValue = input.readString(); + data.audioPath = input.readString(); + if (data.audioPath) { + data.volume = input.readFloat(); + data.balance = input.readFloat(); + } + skeletonData.events.push(data); + } + n = input.readInt(true); + for (let i = 0; i < n; i++) + skeletonData.animations.push(this.readAnimation(input, input.readString(), skeletonData)); + return skeletonData; + } + readSkin(input, skeletonData, defaultSkin, nonessential) { + let skin = null; + let slotCount = 0; + if (defaultSkin) { + slotCount = input.readInt(true); + if (slotCount == 0) + return null; + skin = new Skin("default"); + } else { + skin = new Skin(input.readStringRef()); + skin.bones.length = input.readInt(true); + for (let i = 0, n = skin.bones.length; i < n; i++) + skin.bones[i] = skeletonData.bones[input.readInt(true)]; + for (let i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.push(skeletonData.ikConstraints[input.readInt(true)]); + for (let i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.push(skeletonData.transformConstraints[input.readInt(true)]); + for (let i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.push(skeletonData.pathConstraints[input.readInt(true)]); + slotCount = input.readInt(true); + } + for (let i = 0; i < slotCount; i++) { + let slotIndex = input.readInt(true); + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + let name = input.readStringRef(); + let attachment = this.readAttachment(input, skeletonData, skin, slotIndex, name, nonessential); + if (attachment) + skin.setAttachment(slotIndex, name, attachment); + } + } + return skin; + } + readAttachment(input, skeletonData, skin, slotIndex, attachmentName, nonessential) { + let scale = this.scale; + let name = input.readStringRef(); + if (!name) + name = attachmentName; + switch (input.readByte()) { + case AttachmentType.Region: { + let path = input.readStringRef(); + let rotation = input.readFloat(); + let x = input.readFloat(); + let y = input.readFloat(); + let scaleX = input.readFloat(); + let scaleY = input.readFloat(); + let width = input.readFloat(); + let height = input.readFloat(); + let color = input.readInt32(); + if (!path) + path = name; + let region = this.attachmentLoader.newRegionAttachment(skin, name, path); + if (!region) + return null; + region.path = path; + region.x = x * scale; + region.y = y * scale; + region.scaleX = scaleX; + region.scaleY = scaleY; + region.rotation = rotation; + region.width = width * scale; + region.height = height * scale; + Color.rgba8888ToColor(region.color, color); + region.updateOffset(); + return region; + } + case AttachmentType.BoundingBox: { + let vertexCount = input.readInt(true); + let vertices = this.readVertices(input, vertexCount); + let color = nonessential ? input.readInt32() : 0; + let box = this.attachmentLoader.newBoundingBoxAttachment(skin, name); + if (!box) + return null; + box.worldVerticesLength = vertexCount << 1; + box.vertices = vertices.vertices; + box.bones = vertices.bones; + if (nonessential) + Color.rgba8888ToColor(box.color, color); + return box; + } + case AttachmentType.Mesh: { + let path = input.readStringRef(); + let color = input.readInt32(); + let vertexCount = input.readInt(true); + let uvs = this.readFloatArray(input, vertexCount << 1, 1); + let triangles = this.readShortArray(input); + let vertices = this.readVertices(input, vertexCount); + let hullLength = input.readInt(true); + let edges = null; + let width = 0, height = 0; + if (nonessential) { + edges = this.readShortArray(input); + width = input.readFloat(); + height = input.readFloat(); + } + if (!path) + path = name; + let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path); + if (!mesh) + return null; + mesh.path = path; + Color.rgba8888ToColor(mesh.color, color); + mesh.bones = vertices.bones; + mesh.vertices = vertices.vertices; + mesh.worldVerticesLength = vertexCount << 1; + mesh.triangles = triangles; + mesh.regionUVs = uvs; + mesh.updateUVs(); + mesh.hullLength = hullLength << 1; + if (nonessential) { + mesh.edges = edges; + mesh.width = width * scale; + mesh.height = height * scale; + } + return mesh; + } + case AttachmentType.LinkedMesh: { + let path = input.readStringRef(); + let color = input.readInt32(); + let skinName = input.readStringRef(); + let parent = input.readStringRef(); + let inheritDeform = input.readBoolean(); + let width = 0, height = 0; + if (nonessential) { + width = input.readFloat(); + height = input.readFloat(); + } + if (!path) + path = name; + let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path); + if (!mesh) + return null; + mesh.path = path; + Color.rgba8888ToColor(mesh.color, color); + if (nonessential) { + mesh.width = width * scale; + mesh.height = height * scale; + } + this.linkedMeshes.push(new LinkedMesh(mesh, skinName, slotIndex, parent, inheritDeform)); + return mesh; + } + case AttachmentType.Path: { + let closed2 = input.readBoolean(); + let constantSpeed = input.readBoolean(); + let vertexCount = input.readInt(true); + let vertices = this.readVertices(input, vertexCount); + let lengths = Utils.newArray(vertexCount / 3, 0); + for (let i = 0, n = lengths.length; i < n; i++) + lengths[i] = input.readFloat() * scale; + let color = nonessential ? input.readInt32() : 0; + let path = this.attachmentLoader.newPathAttachment(skin, name); + if (!path) + return null; + path.closed = closed2; + path.constantSpeed = constantSpeed; + path.worldVerticesLength = vertexCount << 1; + path.vertices = vertices.vertices; + path.bones = vertices.bones; + path.lengths = lengths; + if (nonessential) + Color.rgba8888ToColor(path.color, color); + return path; + } + case AttachmentType.Point: { + let rotation = input.readFloat(); + let x = input.readFloat(); + let y = input.readFloat(); + let color = nonessential ? input.readInt32() : 0; + let point = this.attachmentLoader.newPointAttachment(skin, name); + if (!point) + return null; + point.x = x * scale; + point.y = y * scale; + point.rotation = rotation; + if (nonessential) + Color.rgba8888ToColor(point.color, color); + return point; + } + case AttachmentType.Clipping: { + let endSlotIndex = input.readInt(true); + let vertexCount = input.readInt(true); + let vertices = this.readVertices(input, vertexCount); + let color = nonessential ? input.readInt32() : 0; + let clip = this.attachmentLoader.newClippingAttachment(skin, name); + if (!clip) + return null; + clip.endSlot = skeletonData.slots[endSlotIndex]; + clip.worldVerticesLength = vertexCount << 1; + clip.vertices = vertices.vertices; + clip.bones = vertices.bones; + if (nonessential) + Color.rgba8888ToColor(clip.color, color); + return clip; + } + } + return null; + } + readVertices(input, vertexCount) { + let scale = this.scale; + let verticesLength = vertexCount << 1; + let vertices = new Vertices(); + if (!input.readBoolean()) { + vertices.vertices = this.readFloatArray(input, verticesLength, scale); + return vertices; + } + let weights = new Array(); + let bonesArray = new Array(); + for (let i = 0; i < vertexCount; i++) { + let boneCount = input.readInt(true); + bonesArray.push(boneCount); + for (let ii = 0; ii < boneCount; ii++) { + bonesArray.push(input.readInt(true)); + weights.push(input.readFloat() * scale); + weights.push(input.readFloat() * scale); + weights.push(input.readFloat()); + } + } + vertices.vertices = Utils.toFloatArray(weights); + vertices.bones = bonesArray; + return vertices; + } + readFloatArray(input, n, scale) { + let array = new Array(n); + if (scale == 1) { + for (let i = 0; i < n; i++) + array[i] = input.readFloat(); + } else { + for (let i = 0; i < n; i++) + array[i] = input.readFloat() * scale; + } + return array; + } + readShortArray(input) { + let n = input.readInt(true); + let array = new Array(n); + for (let i = 0; i < n; i++) + array[i] = input.readShort(); + return array; + } + readAnimation(input, name, skeletonData) { + input.readInt(true); + let timelines = new Array(); + let scale = this.scale; + let tempColor1 = new Color(); + let tempColor2 = new Color(); + for (let i = 0, n = input.readInt(true); i < n; i++) { + let slotIndex = input.readInt(true); + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + let timelineType = input.readByte(); + let frameCount = input.readInt(true); + let frameLast = frameCount - 1; + switch (timelineType) { + case SLOT_ATTACHMENT: { + let timeline = new AttachmentTimeline(frameCount, slotIndex); + for (let frame = 0; frame < frameCount; frame++) + timeline.setFrame(frame, input.readFloat(), input.readStringRef()); + timelines.push(timeline); + break; + } + case SLOT_RGBA: { + let bezierCount = input.readInt(true); + let timeline = new RGBATimeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + let a = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b, a); + if (frame == frameLast) + break; + let time2 = input.readFloat(); + let r2 = input.readUnsignedByte() / 255; + let g2 = input.readUnsignedByte() / 255; + let b2 = input.readUnsignedByte() / 255; + let a2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, r2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, g2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, b2, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, a, a2, 1); + } + time = time2; + r = r2; + g = g2; + b = b2; + a = a2; + } + timelines.push(timeline); + break; + } + case SLOT_RGB: { + let bezierCount = input.readInt(true); + let timeline = new RGBTimeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b); + if (frame == frameLast) + break; + let time2 = input.readFloat(); + let r2 = input.readUnsignedByte() / 255; + let g2 = input.readUnsignedByte() / 255; + let b2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, r2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, g2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, b2, 1); + } + time = time2; + r = r2; + g = g2; + b = b2; + } + timelines.push(timeline); + break; + } + case SLOT_RGBA2: { + let bezierCount = input.readInt(true); + let timeline = new RGBA2Timeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + let a = input.readUnsignedByte() / 255; + let r2 = input.readUnsignedByte() / 255; + let g2 = input.readUnsignedByte() / 255; + let b2 = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b, a, r2, g2, b2); + if (frame == frameLast) + break; + let time2 = input.readFloat(); + let nr = input.readUnsignedByte() / 255; + let ng = input.readUnsignedByte() / 255; + let nb = input.readUnsignedByte() / 255; + let na = input.readUnsignedByte() / 255; + let nr2 = input.readUnsignedByte() / 255; + let ng2 = input.readUnsignedByte() / 255; + let nb2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, nr, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, ng, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, nb, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, a, na, 1); + setBezier(input, timeline, bezier++, frame, 4, time, time2, r2, nr2, 1); + setBezier(input, timeline, bezier++, frame, 5, time, time2, g2, ng2, 1); + setBezier(input, timeline, bezier++, frame, 6, time, time2, b2, nb2, 1); + } + time = time2; + r = nr; + g = ng; + b = nb; + a = na; + r2 = nr2; + g2 = ng2; + b2 = nb2; + } + timelines.push(timeline); + break; + } + case SLOT_RGB2: { + let bezierCount = input.readInt(true); + let timeline = new RGB2Timeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + let r2 = input.readUnsignedByte() / 255; + let g2 = input.readUnsignedByte() / 255; + let b2 = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b, r2, g2, b2); + if (frame == frameLast) + break; + let time2 = input.readFloat(); + let nr = input.readUnsignedByte() / 255; + let ng = input.readUnsignedByte() / 255; + let nb = input.readUnsignedByte() / 255; + let nr2 = input.readUnsignedByte() / 255; + let ng2 = input.readUnsignedByte() / 255; + let nb2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, nr, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, ng, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, nb, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, r2, nr2, 1); + setBezier(input, timeline, bezier++, frame, 4, time, time2, g2, ng2, 1); + setBezier(input, timeline, bezier++, frame, 5, time, time2, b2, nb2, 1); + } + time = time2; + r = nr; + g = ng; + b = nb; + r2 = nr2; + g2 = ng2; + b2 = nb2; + } + timelines.push(timeline); + break; + } + case SLOT_ALPHA: { + let timeline = new AlphaTimeline(frameCount, input.readInt(true), slotIndex); + let time = input.readFloat(), a = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, a); + if (frame == frameLast) + break; + let time2 = input.readFloat(); + let a2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, a, a2, 1); + } + time = time2; + a = a2; + } + timelines.push(timeline); + break; + } + } + } + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + let boneIndex = input.readInt(true); + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + let type = input.readByte(), frameCount = input.readInt(true), bezierCount = input.readInt(true); + switch (type) { + case BONE_ROTATE: + timelines.push(readTimeline1(input, new RotateTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_TRANSLATE: + timelines.push(readTimeline2(input, new TranslateTimeline(frameCount, bezierCount, boneIndex), scale)); + break; + case BONE_TRANSLATEX: + timelines.push(readTimeline1(input, new TranslateXTimeline(frameCount, bezierCount, boneIndex), scale)); + break; + case BONE_TRANSLATEY: + timelines.push(readTimeline1(input, new TranslateYTimeline(frameCount, bezierCount, boneIndex), scale)); + break; + case BONE_SCALE: + timelines.push(readTimeline2(input, new ScaleTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_SCALEX: + timelines.push(readTimeline1(input, new ScaleXTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_SCALEY: + timelines.push(readTimeline1(input, new ScaleYTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_SHEAR: + timelines.push(readTimeline2(input, new ShearTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_SHEARX: + timelines.push(readTimeline1(input, new ShearXTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_SHEARY: + timelines.push(readTimeline1(input, new ShearYTimeline(frameCount, bezierCount, boneIndex), 1)); + } + } + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + let index = input.readInt(true), frameCount = input.readInt(true), frameLast = frameCount - 1; + let timeline = new IkConstraintTimeline(frameCount, input.readInt(true), index); + let time = input.readFloat(), mix = input.readFloat(), softness = input.readFloat() * scale; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mix, softness, input.readByte(), input.readBoolean(), input.readBoolean()); + if (frame == frameLast) + break; + let time2 = input.readFloat(), mix2 = input.readFloat(), softness2 = input.readFloat() * scale; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, mix, mix2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, softness, softness2, scale); + } + time = time2; + mix = mix2; + softness = softness2; + } + timelines.push(timeline); + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + let index = input.readInt(true), frameCount = input.readInt(true), frameLast = frameCount - 1; + let timeline = new TransformConstraintTimeline(frameCount, input.readInt(true), index); + let time = input.readFloat(), mixRotate = input.readFloat(), mixX = input.readFloat(), mixY = input.readFloat(), mixScaleX = input.readFloat(), mixScaleY = input.readFloat(), mixShearY = input.readFloat(); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY); + if (frame == frameLast) + break; + let time2 = input.readFloat(), mixRotate2 = input.readFloat(), mixX2 = input.readFloat(), mixY2 = input.readFloat(), mixScaleX2 = input.readFloat(), mixScaleY2 = input.readFloat(), mixShearY2 = input.readFloat(); + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, mixY, mixY2, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, mixScaleX, mixScaleX2, 1); + setBezier(input, timeline, bezier++, frame, 4, time, time2, mixScaleY, mixScaleY2, 1); + setBezier(input, timeline, bezier++, frame, 5, time, time2, mixShearY, mixShearY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + mixScaleX = mixScaleX2; + mixScaleY = mixScaleY2; + mixShearY = mixShearY2; + } + timelines.push(timeline); + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + let index = input.readInt(true); + let data = skeletonData.pathConstraints[index]; + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + switch (input.readByte()) { + case PATH_POSITION: + timelines.push(readTimeline1(input, new PathConstraintPositionTimeline(input.readInt(true), input.readInt(true), index), data.positionMode == PositionMode.Fixed ? scale : 1)); + break; + case PATH_SPACING: + timelines.push(readTimeline1(input, new PathConstraintSpacingTimeline(input.readInt(true), input.readInt(true), index), data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed ? scale : 1)); + break; + case PATH_MIX: + let timeline = new PathConstraintMixTimeline(input.readInt(true), input.readInt(true), index); + let time = input.readFloat(), mixRotate = input.readFloat(), mixX = input.readFloat(), mixY = input.readFloat(); + for (let frame = 0, bezier = 0, frameLast = timeline.getFrameCount() - 1; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY); + if (frame == frameLast) + break; + let time2 = input.readFloat(), mixRotate2 = input.readFloat(), mixX2 = input.readFloat(), mixY2 = input.readFloat(); + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, mixY, mixY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + } + timelines.push(timeline); + } + } + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + let skin = skeletonData.skins[input.readInt(true)]; + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + let slotIndex = input.readInt(true); + for (let iii = 0, nnn = input.readInt(true); iii < nnn; iii++) { + let attachmentName = input.readStringRef(); + let attachment = skin.getAttachment(slotIndex, attachmentName); + let weighted = attachment.bones; + let vertices = attachment.vertices; + let deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + let frameCount = input.readInt(true); + let frameLast = frameCount - 1; + let bezierCount = input.readInt(true); + let timeline = new DeformTimeline(frameCount, bezierCount, slotIndex, attachment); + let time = input.readFloat(); + for (let frame = 0, bezier = 0; ; frame++) { + let deform; + let end = input.readInt(true); + if (end == 0) + deform = weighted ? Utils.newFloatArray(deformLength) : vertices; + else { + deform = Utils.newFloatArray(deformLength); + let start = input.readInt(true); + end += start; + if (scale == 1) { + for (let v = start; v < end; v++) + deform[v] = input.readFloat(); + } else { + for (let v = start; v < end; v++) + deform[v] = input.readFloat() * scale; + } + if (!weighted) { + for (let v = 0, vn = deform.length; v < vn; v++) + deform[v] += vertices[v]; + } + } + timeline.setFrame(frame, time, deform); + if (frame == frameLast) + break; + let time2 = input.readFloat(); + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, 0, 1, 1); + } + time = time2; + } + timelines.push(timeline); + } + } + } + let drawOrderCount = input.readInt(true); + if (drawOrderCount > 0) { + let timeline = new DrawOrderTimeline(drawOrderCount); + let slotCount = skeletonData.slots.length; + for (let i = 0; i < drawOrderCount; i++) { + let time = input.readFloat(); + let offsetCount = input.readInt(true); + let drawOrder = Utils.newArray(slotCount, 0); + for (let ii = slotCount - 1; ii >= 0; ii--) + drawOrder[ii] = -1; + let unchanged = Utils.newArray(slotCount - offsetCount, 0); + let originalIndex = 0, unchangedIndex = 0; + for (let ii = 0; ii < offsetCount; ii++) { + let slotIndex = input.readInt(true); + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + drawOrder[originalIndex + input.readInt(true)] = originalIndex++; + } + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + for (let ii = slotCount - 1; ii >= 0; ii--) + if (drawOrder[ii] == -1) + drawOrder[ii] = unchanged[--unchangedIndex]; + timeline.setFrame(i, time, drawOrder); + } + timelines.push(timeline); + } + let eventCount = input.readInt(true); + if (eventCount > 0) { + let timeline = new EventTimeline(eventCount); + for (let i = 0; i < eventCount; i++) { + let time = input.readFloat(); + let eventData = skeletonData.events[input.readInt(true)]; + let event = new Event(time, eventData); + event.intValue = input.readInt(false); + event.floatValue = input.readFloat(); + event.stringValue = input.readBoolean() ? input.readString() : eventData.stringValue; + if (event.data.audioPath) { + event.volume = input.readFloat(); + event.balance = input.readFloat(); + } + timeline.setFrame(i, event); + } + timelines.push(timeline); + } + let duration = 0; + for (let i = 0, n = timelines.length; i < n; i++) + duration = Math.max(duration, timelines[i].getDuration()); + return new Animation(name, timelines, duration); + } + }; + var BinaryInput = class { + constructor(data, strings = new Array(), index = 0, buffer = new DataView(data.buffer)) { + this.strings = strings; + this.index = index; + this.buffer = buffer; + } + readByte() { + return this.buffer.getInt8(this.index++); + } + readUnsignedByte() { + return this.buffer.getUint8(this.index++); + } + readShort() { + let value = this.buffer.getInt16(this.index); + this.index += 2; + return value; + } + readInt32() { + let value = this.buffer.getInt32(this.index); + this.index += 4; + return value; + } + readInt(optimizePositive) { + let b = this.readByte(); + let result = b & 127; + if ((b & 128) != 0) { + b = this.readByte(); + result |= (b & 127) << 7; + if ((b & 128) != 0) { + b = this.readByte(); + result |= (b & 127) << 14; + if ((b & 128) != 0) { + b = this.readByte(); + result |= (b & 127) << 21; + if ((b & 128) != 0) { + b = this.readByte(); + result |= (b & 127) << 28; + } + } + } + } + return optimizePositive ? result : result >>> 1 ^ -(result & 1); + } + readStringRef() { + let index = this.readInt(true); + return index == 0 ? null : this.strings[index - 1]; + } + readString() { + let byteCount = this.readInt(true); + switch (byteCount) { + case 0: + return null; + case 1: + return ""; + } + byteCount--; + let chars = ""; + let charCount = 0; + for (let i = 0; i < byteCount; ) { + let b = this.readUnsignedByte(); + switch (b >> 4) { + case 12: + case 13: + chars += String.fromCharCode((b & 31) << 6 | this.readByte() & 63); + i += 2; + break; + case 14: + chars += String.fromCharCode((b & 15) << 12 | (this.readByte() & 63) << 6 | this.readByte() & 63); + i += 3; + break; + default: + chars += String.fromCharCode(b); + i++; + } + } + return chars; + } + readFloat() { + let value = this.buffer.getFloat32(this.index); + this.index += 4; + return value; + } + readBoolean() { + return this.readByte() != 0; + } + }; + var LinkedMesh = class { + constructor(mesh, skin, slotIndex, parent, inheritDeform) { + this.mesh = mesh; + this.skin = skin; + this.slotIndex = slotIndex; + this.parent = parent; + this.inheritDeform = inheritDeform; + } + }; + var Vertices = class { + constructor(bones = null, vertices = null) { + this.bones = bones; + this.vertices = vertices; + } + }; + var AttachmentType; + (function(AttachmentType2) { + AttachmentType2[AttachmentType2["Region"] = 0] = "Region"; + AttachmentType2[AttachmentType2["BoundingBox"] = 1] = "BoundingBox"; + AttachmentType2[AttachmentType2["Mesh"] = 2] = "Mesh"; + AttachmentType2[AttachmentType2["LinkedMesh"] = 3] = "LinkedMesh"; + AttachmentType2[AttachmentType2["Path"] = 4] = "Path"; + AttachmentType2[AttachmentType2["Point"] = 5] = "Point"; + AttachmentType2[AttachmentType2["Clipping"] = 6] = "Clipping"; + })(AttachmentType || (AttachmentType = {})); + function readTimeline1(input, timeline, scale) { + let time = input.readFloat(), value = input.readFloat() * scale; + for (let frame = 0, bezier = 0, frameLast = timeline.getFrameCount() - 1; ; frame++) { + timeline.setFrame(frame, time, value); + if (frame == frameLast) + break; + let time2 = input.readFloat(), value2 = input.readFloat() * scale; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, value, value2, scale); + } + time = time2; + value = value2; + } + return timeline; + } + function readTimeline2(input, timeline, scale) { + let time = input.readFloat(), value1 = input.readFloat() * scale, value2 = input.readFloat() * scale; + for (let frame = 0, bezier = 0, frameLast = timeline.getFrameCount() - 1; ; frame++) { + timeline.setFrame(frame, time, value1, value2); + if (frame == frameLast) + break; + let time2 = input.readFloat(), nvalue1 = input.readFloat() * scale, nvalue2 = input.readFloat() * scale; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, value1, nvalue1, scale); + setBezier(input, timeline, bezier++, frame, 1, time, time2, value2, nvalue2, scale); + } + time = time2; + value1 = nvalue1; + value2 = nvalue2; + } + return timeline; + } + function setBezier(input, timeline, bezier, frame, value, time1, time2, value1, value2, scale) { + timeline.setBezier(bezier, frame, value, time1, value1, input.readFloat(), input.readFloat() * scale, input.readFloat(), input.readFloat() * scale, time2, value2); + } + var BONE_ROTATE = 0; + var BONE_TRANSLATE = 1; + var BONE_TRANSLATEX = 2; + var BONE_TRANSLATEY = 3; + var BONE_SCALE = 4; + var BONE_SCALEX = 5; + var BONE_SCALEY = 6; + var BONE_SHEAR = 7; + var BONE_SHEARX = 8; + var BONE_SHEARY = 9; + var SLOT_ATTACHMENT = 0; + var SLOT_RGBA = 1; + var SLOT_RGB = 2; + var SLOT_RGBA2 = 3; + var SLOT_RGB2 = 4; + var SLOT_ALPHA = 5; + var PATH_POSITION = 0; + var PATH_SPACING = 1; + var PATH_MIX = 2; + var CURVE_STEPPED = 1; + var CURVE_BEZIER = 2; + + // spine-core/src/SkeletonBounds.ts + var SkeletonBounds = class { + constructor() { + this.minX = 0; + this.minY = 0; + this.maxX = 0; + this.maxY = 0; + this.boundingBoxes = new Array(); + this.polygons = new Array(); + this.polygonPool = new Pool(() => { + return Utils.newFloatArray(16); + }); + } + update(skeleton, updateAabb) { + if (!skeleton) + throw new Error("skeleton cannot be null."); + let boundingBoxes = this.boundingBoxes; + let polygons = this.polygons; + let polygonPool = this.polygonPool; + let slots = skeleton.slots; + let slotCount = slots.length; + boundingBoxes.length = 0; + polygonPool.freeAll(polygons); + polygons.length = 0; + for (let i = 0; i < slotCount; i++) { + let slot = slots[i]; + if (!slot.bone.active) + continue; + let attachment = slot.getAttachment(); + if (attachment instanceof BoundingBoxAttachment) { + let boundingBox = attachment; + boundingBoxes.push(boundingBox); + let polygon = polygonPool.obtain(); + if (polygon.length != boundingBox.worldVerticesLength) { + polygon = Utils.newFloatArray(boundingBox.worldVerticesLength); + } + polygons.push(polygon); + boundingBox.computeWorldVertices(slot, 0, boundingBox.worldVerticesLength, polygon, 0, 2); + } + } + if (updateAabb) { + this.aabbCompute(); + } else { + this.minX = Number.POSITIVE_INFINITY; + this.minY = Number.POSITIVE_INFINITY; + this.maxX = Number.NEGATIVE_INFINITY; + this.maxY = Number.NEGATIVE_INFINITY; + } + } + aabbCompute() { + let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + let polygons = this.polygons; + for (let i = 0, n = polygons.length; i < n; i++) { + let polygon = polygons[i]; + let vertices = polygon; + for (let ii = 0, nn = polygon.length; ii < nn; ii += 2) { + let x = vertices[ii]; + let y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + aabbContainsPoint(x, y) { + return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY; + } + aabbIntersectsSegment(x1, y1, x2, y2) { + let minX = this.minX; + let minY = this.minY; + let maxX = this.maxX; + let maxY = this.maxY; + if (x1 <= minX && x2 <= minX || y1 <= minY && y2 <= minY || x1 >= maxX && x2 >= maxX || y1 >= maxY && y2 >= maxY) + return false; + let m = (y2 - y1) / (x2 - x1); + let y = m * (minX - x1) + y1; + if (y > minY && y < maxY) + return true; + y = m * (maxX - x1) + y1; + if (y > minY && y < maxY) + return true; + let x = (minY - y1) / m + x1; + if (x > minX && x < maxX) + return true; + x = (maxY - y1) / m + x1; + if (x > minX && x < maxX) + return true; + return false; + } + aabbIntersectsSkeleton(bounds) { + return this.minX < bounds.maxX && this.maxX > bounds.minX && this.minY < bounds.maxY && this.maxY > bounds.minY; + } + containsPoint(x, y) { + let polygons = this.polygons; + for (let i = 0, n = polygons.length; i < n; i++) + if (this.containsPointPolygon(polygons[i], x, y)) + return this.boundingBoxes[i]; + return null; + } + containsPointPolygon(polygon, x, y) { + let vertices = polygon; + let nn = polygon.length; + let prevIndex = nn - 2; + let inside = false; + for (let ii = 0; ii < nn; ii += 2) { + let vertexY = vertices[ii + 1]; + let prevY = vertices[prevIndex + 1]; + if (vertexY < y && prevY >= y || prevY < y && vertexY >= y) { + let vertexX = vertices[ii]; + if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) + inside = !inside; + } + prevIndex = ii; + } + return inside; + } + intersectsSegment(x1, y1, x2, y2) { + let polygons = this.polygons; + for (let i = 0, n = polygons.length; i < n; i++) + if (this.intersectsSegmentPolygon(polygons[i], x1, y1, x2, y2)) + return this.boundingBoxes[i]; + return null; + } + intersectsSegmentPolygon(polygon, x1, y1, x2, y2) { + let vertices = polygon; + let nn = polygon.length; + let width12 = x1 - x2, height12 = y1 - y2; + let det1 = x1 * y2 - y1 * x2; + let x3 = vertices[nn - 2], y3 = vertices[nn - 1]; + for (let ii = 0; ii < nn; ii += 2) { + let x4 = vertices[ii], y4 = vertices[ii + 1]; + let det2 = x3 * y4 - y3 * x4; + let width34 = x3 - x4, height34 = y3 - y4; + let det3 = width12 * height34 - height12 * width34; + let x = (det1 * width34 - width12 * det2) / det3; + if ((x >= x3 && x <= x4 || x >= x4 && x <= x3) && (x >= x1 && x <= x2 || x >= x2 && x <= x1)) { + let y = (det1 * height34 - height12 * det2) / det3; + if ((y >= y3 && y <= y4 || y >= y4 && y <= y3) && (y >= y1 && y <= y2 || y >= y2 && y <= y1)) + return true; + } + x3 = x4; + y3 = y4; + } + return false; + } + getPolygon(boundingBox) { + if (!boundingBox) + throw new Error("boundingBox cannot be null."); + let index = this.boundingBoxes.indexOf(boundingBox); + return index == -1 ? null : this.polygons[index]; + } + getWidth() { + return this.maxX - this.minX; + } + getHeight() { + return this.maxY - this.minY; + } + }; + + // spine-core/src/Triangulator.ts + var Triangulator = class { + constructor() { + this.convexPolygons = new Array(); + this.convexPolygonsIndices = new Array(); + this.indicesArray = new Array(); + this.isConcaveArray = new Array(); + this.triangles = new Array(); + this.polygonPool = new Pool(() => { + return new Array(); + }); + this.polygonIndicesPool = new Pool(() => { + return new Array(); + }); + } + triangulate(verticesArray) { + let vertices = verticesArray; + let vertexCount = verticesArray.length >> 1; + let indices = this.indicesArray; + indices.length = 0; + for (let i = 0; i < vertexCount; i++) + indices[i] = i; + let isConcave = this.isConcaveArray; + isConcave.length = 0; + for (let i = 0, n = vertexCount; i < n; ++i) + isConcave[i] = Triangulator.isConcave(i, vertexCount, vertices, indices); + let triangles = this.triangles; + triangles.length = 0; + while (vertexCount > 3) { + let previous = vertexCount - 1, i = 0, next = 1; + while (true) { + outer: + if (!isConcave[i]) { + let p1 = indices[previous] << 1, p2 = indices[i] << 1, p3 = indices[next] << 1; + let p1x = vertices[p1], p1y = vertices[p1 + 1]; + let p2x = vertices[p2], p2y = vertices[p2 + 1]; + let p3x = vertices[p3], p3y = vertices[p3 + 1]; + for (let ii = (next + 1) % vertexCount; ii != previous; ii = (ii + 1) % vertexCount) { + if (!isConcave[ii]) + continue; + let v = indices[ii] << 1; + let vx = vertices[v], vy = vertices[v + 1]; + if (Triangulator.positiveArea(p3x, p3y, p1x, p1y, vx, vy)) { + if (Triangulator.positiveArea(p1x, p1y, p2x, p2y, vx, vy)) { + if (Triangulator.positiveArea(p2x, p2y, p3x, p3y, vx, vy)) + break outer; + } + } + } + break; + } + if (next == 0) { + do { + if (!isConcave[i]) + break; + i--; + } while (i > 0); + break; + } + previous = i; + i = next; + next = (next + 1) % vertexCount; + } + triangles.push(indices[(vertexCount + i - 1) % vertexCount]); + triangles.push(indices[i]); + triangles.push(indices[(i + 1) % vertexCount]); + indices.splice(i, 1); + isConcave.splice(i, 1); + vertexCount--; + let previousIndex = (vertexCount + i - 1) % vertexCount; + let nextIndex = i == vertexCount ? 0 : i; + isConcave[previousIndex] = Triangulator.isConcave(previousIndex, vertexCount, vertices, indices); + isConcave[nextIndex] = Triangulator.isConcave(nextIndex, vertexCount, vertices, indices); + } + if (vertexCount == 3) { + triangles.push(indices[2]); + triangles.push(indices[0]); + triangles.push(indices[1]); + } + return triangles; + } + decompose(verticesArray, triangles) { + let vertices = verticesArray; + let convexPolygons = this.convexPolygons; + this.polygonPool.freeAll(convexPolygons); + convexPolygons.length = 0; + let convexPolygonsIndices = this.convexPolygonsIndices; + this.polygonIndicesPool.freeAll(convexPolygonsIndices); + convexPolygonsIndices.length = 0; + let polygonIndices = this.polygonIndicesPool.obtain(); + polygonIndices.length = 0; + let polygon = this.polygonPool.obtain(); + polygon.length = 0; + let fanBaseIndex = -1, lastWinding = 0; + for (let i = 0, n = triangles.length; i < n; i += 3) { + let t1 = triangles[i] << 1, t2 = triangles[i + 1] << 1, t3 = triangles[i + 2] << 1; + let x1 = vertices[t1], y1 = vertices[t1 + 1]; + let x2 = vertices[t2], y2 = vertices[t2 + 1]; + let x3 = vertices[t3], y3 = vertices[t3 + 1]; + let merged = false; + if (fanBaseIndex == t1) { + let o = polygon.length - 4; + let winding1 = Triangulator.winding(polygon[o], polygon[o + 1], polygon[o + 2], polygon[o + 3], x3, y3); + let winding2 = Triangulator.winding(x3, y3, polygon[0], polygon[1], polygon[2], polygon[3]); + if (winding1 == lastWinding && winding2 == lastWinding) { + polygon.push(x3); + polygon.push(y3); + polygonIndices.push(t3); + merged = true; + } + } + if (!merged) { + if (polygon.length > 0) { + convexPolygons.push(polygon); + convexPolygonsIndices.push(polygonIndices); + } else { + this.polygonPool.free(polygon); + this.polygonIndicesPool.free(polygonIndices); + } + polygon = this.polygonPool.obtain(); + polygon.length = 0; + polygon.push(x1); + polygon.push(y1); + polygon.push(x2); + polygon.push(y2); + polygon.push(x3); + polygon.push(y3); + polygonIndices = this.polygonIndicesPool.obtain(); + polygonIndices.length = 0; + polygonIndices.push(t1); + polygonIndices.push(t2); + polygonIndices.push(t3); + lastWinding = Triangulator.winding(x1, y1, x2, y2, x3, y3); + fanBaseIndex = t1; + } + } + if (polygon.length > 0) { + convexPolygons.push(polygon); + convexPolygonsIndices.push(polygonIndices); + } + for (let i = 0, n = convexPolygons.length; i < n; i++) { + polygonIndices = convexPolygonsIndices[i]; + if (polygonIndices.length == 0) + continue; + let firstIndex = polygonIndices[0]; + let lastIndex = polygonIndices[polygonIndices.length - 1]; + polygon = convexPolygons[i]; + let o = polygon.length - 4; + let prevPrevX = polygon[o], prevPrevY = polygon[o + 1]; + let prevX = polygon[o + 2], prevY = polygon[o + 3]; + let firstX = polygon[0], firstY = polygon[1]; + let secondX = polygon[2], secondY = polygon[3]; + let winding = Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, firstX, firstY); + for (let ii = 0; ii < n; ii++) { + if (ii == i) + continue; + let otherIndices = convexPolygonsIndices[ii]; + if (otherIndices.length != 3) + continue; + let otherFirstIndex = otherIndices[0]; + let otherSecondIndex = otherIndices[1]; + let otherLastIndex = otherIndices[2]; + let otherPoly = convexPolygons[ii]; + let x3 = otherPoly[otherPoly.length - 2], y3 = otherPoly[otherPoly.length - 1]; + if (otherFirstIndex != firstIndex || otherSecondIndex != lastIndex) + continue; + let winding1 = Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, x3, y3); + let winding2 = Triangulator.winding(x3, y3, firstX, firstY, secondX, secondY); + if (winding1 == winding && winding2 == winding) { + otherPoly.length = 0; + otherIndices.length = 0; + polygon.push(x3); + polygon.push(y3); + polygonIndices.push(otherLastIndex); + prevPrevX = prevX; + prevPrevY = prevY; + prevX = x3; + prevY = y3; + ii = 0; + } + } + } + for (let i = convexPolygons.length - 1; i >= 0; i--) { + polygon = convexPolygons[i]; + if (polygon.length == 0) { + convexPolygons.splice(i, 1); + this.polygonPool.free(polygon); + polygonIndices = convexPolygonsIndices[i]; + convexPolygonsIndices.splice(i, 1); + this.polygonIndicesPool.free(polygonIndices); + } + } + return convexPolygons; + } + static isConcave(index, vertexCount, vertices, indices) { + let previous = indices[(vertexCount + index - 1) % vertexCount] << 1; + let current = indices[index] << 1; + let next = indices[(index + 1) % vertexCount] << 1; + return !this.positiveArea(vertices[previous], vertices[previous + 1], vertices[current], vertices[current + 1], vertices[next], vertices[next + 1]); + } + static positiveArea(p1x, p1y, p2x, p2y, p3x, p3y) { + return p1x * (p3y - p2y) + p2x * (p1y - p3y) + p3x * (p2y - p1y) >= 0; + } + static winding(p1x, p1y, p2x, p2y, p3x, p3y) { + let px = p2x - p1x, py = p2y - p1y; + return p3x * py - p3y * px + px * p1y - p1x * py >= 0 ? 1 : -1; + } + }; + + // spine-core/src/SkeletonClipping.ts + var SkeletonClipping = class { + constructor() { + this.triangulator = new Triangulator(); + this.clippingPolygon = new Array(); + this.clipOutput = new Array(); + this.clippedVertices = new Array(); + this.clippedTriangles = new Array(); + this.scratch = new Array(); + } + clipStart(slot, clip) { + if (this.clipAttachment) + return 0; + this.clipAttachment = clip; + let n = clip.worldVerticesLength; + let vertices = Utils.setArraySize(this.clippingPolygon, n); + clip.computeWorldVertices(slot, 0, n, vertices, 0, 2); + let clippingPolygon = this.clippingPolygon; + SkeletonClipping.makeClockwise(clippingPolygon); + let clippingPolygons = this.clippingPolygons = this.triangulator.decompose(clippingPolygon, this.triangulator.triangulate(clippingPolygon)); + for (let i = 0, n2 = clippingPolygons.length; i < n2; i++) { + let polygon = clippingPolygons[i]; + SkeletonClipping.makeClockwise(polygon); + polygon.push(polygon[0]); + polygon.push(polygon[1]); + } + return clippingPolygons.length; + } + clipEndWithSlot(slot) { + if (this.clipAttachment && this.clipAttachment.endSlot == slot.data) + this.clipEnd(); + } + clipEnd() { + if (!this.clipAttachment) + return; + this.clipAttachment = null; + this.clippingPolygons = null; + this.clippedVertices.length = 0; + this.clippedTriangles.length = 0; + this.clippingPolygon.length = 0; + } + isClipping() { + return this.clipAttachment != null; + } + clipTriangles(vertices, verticesLength, triangles, trianglesLength, uvs, light, dark, twoColor) { + let clipOutput = this.clipOutput, clippedVertices = this.clippedVertices; + let clippedTriangles = this.clippedTriangles; + let polygons = this.clippingPolygons; + let polygonsCount = this.clippingPolygons.length; + let vertexSize = twoColor ? 12 : 8; + let index = 0; + clippedVertices.length = 0; + clippedTriangles.length = 0; + outer: + for (let i = 0; i < trianglesLength; i += 3) { + let vertexOffset = triangles[i] << 1; + let x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1]; + let u1 = uvs[vertexOffset], v1 = uvs[vertexOffset + 1]; + vertexOffset = triangles[i + 1] << 1; + let x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1]; + let u2 = uvs[vertexOffset], v2 = uvs[vertexOffset + 1]; + vertexOffset = triangles[i + 2] << 1; + let x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1]; + let u3 = uvs[vertexOffset], v3 = uvs[vertexOffset + 1]; + for (let p = 0; p < polygonsCount; p++) { + let s = clippedVertices.length; + if (this.clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) { + let clipOutputLength = clipOutput.length; + if (clipOutputLength == 0) + continue; + let d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1; + let d = 1 / (d0 * d2 + d1 * (y1 - y3)); + let clipOutputCount = clipOutputLength >> 1; + let clipOutputItems = this.clipOutput; + let clippedVerticesItems = Utils.setArraySize(clippedVertices, s + clipOutputCount * vertexSize); + for (let ii = 0; ii < clipOutputLength; ii += 2) { + let x = clipOutputItems[ii], y = clipOutputItems[ii + 1]; + clippedVerticesItems[s] = x; + clippedVerticesItems[s + 1] = y; + clippedVerticesItems[s + 2] = light.r; + clippedVerticesItems[s + 3] = light.g; + clippedVerticesItems[s + 4] = light.b; + clippedVerticesItems[s + 5] = light.a; + let c0 = x - x3, c1 = y - y3; + let a = (d0 * c0 + d1 * c1) * d; + let b = (d4 * c0 + d2 * c1) * d; + let c = 1 - a - b; + clippedVerticesItems[s + 6] = u1 * a + u2 * b + u3 * c; + clippedVerticesItems[s + 7] = v1 * a + v2 * b + v3 * c; + if (twoColor) { + clippedVerticesItems[s + 8] = dark.r; + clippedVerticesItems[s + 9] = dark.g; + clippedVerticesItems[s + 10] = dark.b; + clippedVerticesItems[s + 11] = dark.a; + } + s += vertexSize; + } + s = clippedTriangles.length; + let clippedTrianglesItems = Utils.setArraySize(clippedTriangles, s + 3 * (clipOutputCount - 2)); + clipOutputCount--; + for (let ii = 1; ii < clipOutputCount; ii++) { + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = index + ii; + clippedTrianglesItems[s + 2] = index + ii + 1; + s += 3; + } + index += clipOutputCount + 1; + } else { + let clippedVerticesItems = Utils.setArraySize(clippedVertices, s + 3 * vertexSize); + clippedVerticesItems[s] = x1; + clippedVerticesItems[s + 1] = y1; + clippedVerticesItems[s + 2] = light.r; + clippedVerticesItems[s + 3] = light.g; + clippedVerticesItems[s + 4] = light.b; + clippedVerticesItems[s + 5] = light.a; + if (!twoColor) { + clippedVerticesItems[s + 6] = u1; + clippedVerticesItems[s + 7] = v1; + clippedVerticesItems[s + 8] = x2; + clippedVerticesItems[s + 9] = y2; + clippedVerticesItems[s + 10] = light.r; + clippedVerticesItems[s + 11] = light.g; + clippedVerticesItems[s + 12] = light.b; + clippedVerticesItems[s + 13] = light.a; + clippedVerticesItems[s + 14] = u2; + clippedVerticesItems[s + 15] = v2; + clippedVerticesItems[s + 16] = x3; + clippedVerticesItems[s + 17] = y3; + clippedVerticesItems[s + 18] = light.r; + clippedVerticesItems[s + 19] = light.g; + clippedVerticesItems[s + 20] = light.b; + clippedVerticesItems[s + 21] = light.a; + clippedVerticesItems[s + 22] = u3; + clippedVerticesItems[s + 23] = v3; + } else { + clippedVerticesItems[s + 6] = u1; + clippedVerticesItems[s + 7] = v1; + clippedVerticesItems[s + 8] = dark.r; + clippedVerticesItems[s + 9] = dark.g; + clippedVerticesItems[s + 10] = dark.b; + clippedVerticesItems[s + 11] = dark.a; + clippedVerticesItems[s + 12] = x2; + clippedVerticesItems[s + 13] = y2; + clippedVerticesItems[s + 14] = light.r; + clippedVerticesItems[s + 15] = light.g; + clippedVerticesItems[s + 16] = light.b; + clippedVerticesItems[s + 17] = light.a; + clippedVerticesItems[s + 18] = u2; + clippedVerticesItems[s + 19] = v2; + clippedVerticesItems[s + 20] = dark.r; + clippedVerticesItems[s + 21] = dark.g; + clippedVerticesItems[s + 22] = dark.b; + clippedVerticesItems[s + 23] = dark.a; + clippedVerticesItems[s + 24] = x3; + clippedVerticesItems[s + 25] = y3; + clippedVerticesItems[s + 26] = light.r; + clippedVerticesItems[s + 27] = light.g; + clippedVerticesItems[s + 28] = light.b; + clippedVerticesItems[s + 29] = light.a; + clippedVerticesItems[s + 30] = u3; + clippedVerticesItems[s + 31] = v3; + clippedVerticesItems[s + 32] = dark.r; + clippedVerticesItems[s + 33] = dark.g; + clippedVerticesItems[s + 34] = dark.b; + clippedVerticesItems[s + 35] = dark.a; + } + s = clippedTriangles.length; + let clippedTrianglesItems = Utils.setArraySize(clippedTriangles, s + 3); + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = index + 1; + clippedTrianglesItems[s + 2] = index + 2; + index += 3; + continue outer; + } + } + } + } + clip(x1, y1, x2, y2, x3, y3, clippingArea, output) { + let originalOutput = output; + let clipped = false; + let input = null; + if (clippingArea.length % 4 >= 2) { + input = output; + output = this.scratch; + } else + input = this.scratch; + input.length = 0; + input.push(x1); + input.push(y1); + input.push(x2); + input.push(y2); + input.push(x3); + input.push(y3); + input.push(x1); + input.push(y1); + output.length = 0; + let clippingVertices = clippingArea; + let clippingVerticesLast = clippingArea.length - 4; + for (let i = 0; ; i += 2) { + let edgeX = clippingVertices[i], edgeY = clippingVertices[i + 1]; + let edgeX2 = clippingVertices[i + 2], edgeY2 = clippingVertices[i + 3]; + let deltaX = edgeX - edgeX2, deltaY = edgeY - edgeY2; + let inputVertices = input; + let inputVerticesLength = input.length - 2, outputStart = output.length; + for (let ii = 0; ii < inputVerticesLength; ii += 2) { + let inputX = inputVertices[ii], inputY = inputVertices[ii + 1]; + let inputX2 = inputVertices[ii + 2], inputY2 = inputVertices[ii + 3]; + let side2 = deltaX * (inputY2 - edgeY2) - deltaY * (inputX2 - edgeX2) > 0; + if (deltaX * (inputY - edgeY2) - deltaY * (inputX - edgeX2) > 0) { + if (side2) { + output.push(inputX2); + output.push(inputY2); + continue; + } + let c0 = inputY2 - inputY, c2 = inputX2 - inputX; + let s = c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY); + if (Math.abs(s) > 1e-6) { + let ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / s; + output.push(edgeX + (edgeX2 - edgeX) * ua); + output.push(edgeY + (edgeY2 - edgeY) * ua); + } else { + output.push(edgeX); + output.push(edgeY); + } + } else if (side2) { + let c0 = inputY2 - inputY, c2 = inputX2 - inputX; + let s = c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY); + if (Math.abs(s) > 1e-6) { + let ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / s; + output.push(edgeX + (edgeX2 - edgeX) * ua); + output.push(edgeY + (edgeY2 - edgeY) * ua); + } else { + output.push(edgeX); + output.push(edgeY); + } + output.push(inputX2); + output.push(inputY2); + } + clipped = true; + } + if (outputStart == output.length) { + originalOutput.length = 0; + return true; + } + output.push(output[0]); + output.push(output[1]); + if (i == clippingVerticesLast) + break; + let temp = output; + output = input; + output.length = 0; + input = temp; + } + if (originalOutput != output) { + originalOutput.length = 0; + for (let i = 0, n = output.length - 2; i < n; i++) + originalOutput[i] = output[i]; + } else + originalOutput.length = originalOutput.length - 2; + return clipped; + } + static makeClockwise(polygon) { + let vertices = polygon; + let verticeslength = polygon.length; + let area = vertices[verticeslength - 2] * vertices[1] - vertices[0] * vertices[verticeslength - 1], p1x = 0, p1y = 0, p2x = 0, p2y = 0; + for (let i = 0, n = verticeslength - 3; i < n; i += 2) { + p1x = vertices[i]; + p1y = vertices[i + 1]; + p2x = vertices[i + 2]; + p2y = vertices[i + 3]; + area += p1x * p2y - p2x * p1y; + } + if (area < 0) + return; + for (let i = 0, lastX = verticeslength - 2, n = verticeslength >> 1; i < n; i += 2) { + let x = vertices[i], y = vertices[i + 1]; + let other = lastX - i; + vertices[i] = vertices[other]; + vertices[i + 1] = vertices[other + 1]; + vertices[other] = x; + vertices[other + 1] = y; + } + } + }; + + // spine-core/src/SkeletonJson.ts + var SkeletonJson = class { + constructor(attachmentLoader) { + this.attachmentLoader = null; + this.scale = 1; + this.linkedMeshes = new Array(); + this.attachmentLoader = attachmentLoader; + } + readSkeletonData(json) { + let scale = this.scale; + let skeletonData = new SkeletonData(); + let root = typeof json === "string" ? JSON.parse(json) : json; + let skeletonMap = root.skeleton; + if (skeletonMap) { + skeletonData.hash = skeletonMap.hash; + skeletonData.version = skeletonMap.spine; + skeletonData.x = skeletonMap.x; + skeletonData.y = skeletonMap.y; + skeletonData.width = skeletonMap.width; + skeletonData.height = skeletonMap.height; + skeletonData.fps = skeletonMap.fps; + skeletonData.imagesPath = skeletonMap.images; + } + if (root.bones) { + for (let i = 0; i < root.bones.length; i++) { + let boneMap = root.bones[i]; + let parent = null; + let parentName = getValue(boneMap, "parent", null); + if (parentName) + parent = skeletonData.findBone(parentName); + let data = new BoneData(skeletonData.bones.length, boneMap.name, parent); + data.length = getValue(boneMap, "length", 0) * scale; + data.x = getValue(boneMap, "x", 0) * scale; + data.y = getValue(boneMap, "y", 0) * scale; + data.rotation = getValue(boneMap, "rotation", 0); + data.scaleX = getValue(boneMap, "scaleX", 1); + data.scaleY = getValue(boneMap, "scaleY", 1); + data.shearX = getValue(boneMap, "shearX", 0); + data.shearY = getValue(boneMap, "shearY", 0); + data.transformMode = Utils.enumValue(TransformMode, getValue(boneMap, "transform", "Normal")); + data.skinRequired = getValue(boneMap, "skin", false); + let color = getValue(boneMap, "color", null); + if (color) + data.color.setFromString(color); + skeletonData.bones.push(data); + } + } + if (root.slots) { + for (let i = 0; i < root.slots.length; i++) { + let slotMap = root.slots[i]; + let boneData = skeletonData.findBone(slotMap.bone); + let data = new SlotData(skeletonData.slots.length, slotMap.name, boneData); + let color = getValue(slotMap, "color", null); + if (color) + data.color.setFromString(color); + let dark = getValue(slotMap, "dark", null); + if (dark) + data.darkColor = Color.fromString(dark); + data.attachmentName = getValue(slotMap, "attachment", null); + data.blendMode = Utils.enumValue(BlendMode, getValue(slotMap, "blend", "normal")); + skeletonData.slots.push(data); + } + } + if (root.ik) { + for (let i = 0; i < root.ik.length; i++) { + let constraintMap = root.ik[i]; + let data = new IkConstraintData(constraintMap.name); + data.order = getValue(constraintMap, "order", 0); + data.skinRequired = getValue(constraintMap, "skin", false); + for (let ii = 0; ii < constraintMap.bones.length; ii++) + data.bones.push(skeletonData.findBone(constraintMap.bones[ii])); + data.target = skeletonData.findBone(constraintMap.target); + data.mix = getValue(constraintMap, "mix", 1); + data.softness = getValue(constraintMap, "softness", 0) * scale; + data.bendDirection = getValue(constraintMap, "bendPositive", true) ? 1 : -1; + data.compress = getValue(constraintMap, "compress", false); + data.stretch = getValue(constraintMap, "stretch", false); + data.uniform = getValue(constraintMap, "uniform", false); + skeletonData.ikConstraints.push(data); + } + } + if (root.transform) { + for (let i = 0; i < root.transform.length; i++) { + let constraintMap = root.transform[i]; + let data = new TransformConstraintData(constraintMap.name); + data.order = getValue(constraintMap, "order", 0); + data.skinRequired = getValue(constraintMap, "skin", false); + for (let ii = 0; ii < constraintMap.bones.length; ii++) + data.bones.push(skeletonData.findBone(constraintMap.bones[ii])); + let targetName = constraintMap.target; + data.target = skeletonData.findBone(targetName); + data.local = getValue(constraintMap, "local", false); + data.relative = getValue(constraintMap, "relative", false); + data.offsetRotation = getValue(constraintMap, "rotation", 0); + data.offsetX = getValue(constraintMap, "x", 0) * scale; + data.offsetY = getValue(constraintMap, "y", 0) * scale; + data.offsetScaleX = getValue(constraintMap, "scaleX", 0); + data.offsetScaleY = getValue(constraintMap, "scaleY", 0); + data.offsetShearY = getValue(constraintMap, "shearY", 0); + data.mixRotate = getValue(constraintMap, "mixRotate", 1); + data.mixX = getValue(constraintMap, "mixX", 1); + data.mixY = getValue(constraintMap, "mixY", data.mixX); + data.mixScaleX = getValue(constraintMap, "mixScaleX", 1); + data.mixScaleY = getValue(constraintMap, "mixScaleY", data.mixScaleX); + data.mixShearY = getValue(constraintMap, "mixShearY", 1); + skeletonData.transformConstraints.push(data); + } + } + if (root.path) { + for (let i = 0; i < root.path.length; i++) { + let constraintMap = root.path[i]; + let data = new PathConstraintData(constraintMap.name); + data.order = getValue(constraintMap, "order", 0); + data.skinRequired = getValue(constraintMap, "skin", false); + for (let ii = 0; ii < constraintMap.bones.length; ii++) + data.bones.push(skeletonData.findBone(constraintMap.bones[ii])); + let targetName = constraintMap.target; + data.target = skeletonData.findSlot(targetName); + data.positionMode = Utils.enumValue(PositionMode, getValue(constraintMap, "positionMode", "Percent")); + data.spacingMode = Utils.enumValue(SpacingMode, getValue(constraintMap, "spacingMode", "Length")); + data.rotateMode = Utils.enumValue(RotateMode, getValue(constraintMap, "rotateMode", "Tangent")); + data.offsetRotation = getValue(constraintMap, "rotation", 0); + data.position = getValue(constraintMap, "position", 0); + if (data.positionMode == PositionMode.Fixed) + data.position *= scale; + data.spacing = getValue(constraintMap, "spacing", 0); + if (data.spacingMode == SpacingMode.Length || data.spacingMode == SpacingMode.Fixed) + data.spacing *= scale; + data.mixRotate = getValue(constraintMap, "mixRotate", 1); + data.mixX = getValue(constraintMap, "mixX", 1); + data.mixY = getValue(constraintMap, "mixY", data.mixX); + skeletonData.pathConstraints.push(data); + } + } + if (root.skins) { + for (let i = 0; i < root.skins.length; i++) { + let skinMap = root.skins[i]; + let skin = new Skin(skinMap.name); + if (skinMap.bones) { + for (let ii = 0; ii < skinMap.bones.length; ii++) + skin.bones.push(skeletonData.findBone(skinMap.bones[ii])); + } + if (skinMap.ik) { + for (let ii = 0; ii < skinMap.ik.length; ii++) + skin.constraints.push(skeletonData.findIkConstraint(skinMap.ik[ii])); + } + if (skinMap.transform) { + for (let ii = 0; ii < skinMap.transform.length; ii++) + skin.constraints.push(skeletonData.findTransformConstraint(skinMap.transform[ii])); + } + if (skinMap.path) { + for (let ii = 0; ii < skinMap.path.length; ii++) + skin.constraints.push(skeletonData.findPathConstraint(skinMap.path[ii])); + } + for (let slotName in skinMap.attachments) { + let slot = skeletonData.findSlot(slotName); + let slotMap = skinMap.attachments[slotName]; + for (let entryName in slotMap) { + let attachment = this.readAttachment(slotMap[entryName], skin, slot.index, entryName, skeletonData); + if (attachment) + skin.setAttachment(slot.index, entryName, attachment); + } + } + skeletonData.skins.push(skin); + if (skin.name == "default") + skeletonData.defaultSkin = skin; + } + } + for (let i = 0, n = this.linkedMeshes.length; i < n; i++) { + let linkedMesh = this.linkedMeshes[i]; + let skin = !linkedMesh.skin ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin); + let parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); + linkedMesh.mesh.deformAttachment = linkedMesh.inheritDeform ? parent : linkedMesh.mesh; + linkedMesh.mesh.setParentMesh(parent); + linkedMesh.mesh.updateUVs(); + } + this.linkedMeshes.length = 0; + if (root.events) { + for (let eventName in root.events) { + let eventMap = root.events[eventName]; + let data = new EventData(eventName); + data.intValue = getValue(eventMap, "int", 0); + data.floatValue = getValue(eventMap, "float", 0); + data.stringValue = getValue(eventMap, "string", ""); + data.audioPath = getValue(eventMap, "audio", null); + if (data.audioPath) { + data.volume = getValue(eventMap, "volume", 1); + data.balance = getValue(eventMap, "balance", 0); + } + skeletonData.events.push(data); + } + } + if (root.animations) { + for (let animationName in root.animations) { + let animationMap = root.animations[animationName]; + this.readAnimation(animationMap, animationName, skeletonData); + } + } + return skeletonData; + } + readAttachment(map, skin, slotIndex, name, skeletonData) { + let scale = this.scale; + name = getValue(map, "name", name); + switch (getValue(map, "type", "region")) { + case "region": { + let path = getValue(map, "path", name); + let region = this.attachmentLoader.newRegionAttachment(skin, name, path); + if (!region) + return null; + region.path = path; + region.x = getValue(map, "x", 0) * scale; + region.y = getValue(map, "y", 0) * scale; + region.scaleX = getValue(map, "scaleX", 1); + region.scaleY = getValue(map, "scaleY", 1); + region.rotation = getValue(map, "rotation", 0); + region.width = map.width * scale; + region.height = map.height * scale; + let color = getValue(map, "color", null); + if (color) + region.color.setFromString(color); + region.updateOffset(); + return region; + } + case "boundingbox": { + let box = this.attachmentLoader.newBoundingBoxAttachment(skin, name); + if (!box) + return null; + this.readVertices(map, box, map.vertexCount << 1); + let color = getValue(map, "color", null); + if (color) + box.color.setFromString(color); + return box; + } + case "mesh": + case "linkedmesh": { + let path = getValue(map, "path", name); + let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path); + if (!mesh) + return null; + mesh.path = path; + let color = getValue(map, "color", null); + if (color) + mesh.color.setFromString(color); + mesh.width = getValue(map, "width", 0) * scale; + mesh.height = getValue(map, "height", 0) * scale; + let parent = getValue(map, "parent", null); + if (parent) { + this.linkedMeshes.push(new LinkedMesh2(mesh, getValue(map, "skin", null), slotIndex, parent, getValue(map, "deform", true))); + return mesh; + } + let uvs = map.uvs; + this.readVertices(map, mesh, uvs.length); + mesh.triangles = map.triangles; + mesh.regionUVs = uvs; + mesh.updateUVs(); + mesh.edges = getValue(map, "edges", null); + mesh.hullLength = getValue(map, "hull", 0) * 2; + return mesh; + } + case "path": { + let path = this.attachmentLoader.newPathAttachment(skin, name); + if (!path) + return null; + path.closed = getValue(map, "closed", false); + path.constantSpeed = getValue(map, "constantSpeed", true); + let vertexCount = map.vertexCount; + this.readVertices(map, path, vertexCount << 1); + let lengths = Utils.newArray(vertexCount / 3, 0); + for (let i = 0; i < map.lengths.length; i++) + lengths[i] = map.lengths[i] * scale; + path.lengths = lengths; + let color = getValue(map, "color", null); + if (color) + path.color.setFromString(color); + return path; + } + case "point": { + let point = this.attachmentLoader.newPointAttachment(skin, name); + if (!point) + return null; + point.x = getValue(map, "x", 0) * scale; + point.y = getValue(map, "y", 0) * scale; + point.rotation = getValue(map, "rotation", 0); + let color = getValue(map, "color", null); + if (color) + point.color.setFromString(color); + return point; + } + case "clipping": { + let clip = this.attachmentLoader.newClippingAttachment(skin, name); + if (!clip) + return null; + let end = getValue(map, "end", null); + if (end) + clip.endSlot = skeletonData.findSlot(end); + let vertexCount = map.vertexCount; + this.readVertices(map, clip, vertexCount << 1); + let color = getValue(map, "color", null); + if (color) + clip.color.setFromString(color); + return clip; + } + } + return null; + } + readVertices(map, attachment, verticesLength) { + let scale = this.scale; + attachment.worldVerticesLength = verticesLength; + let vertices = map.vertices; + if (verticesLength == vertices.length) { + let scaledVertices = Utils.toFloatArray(vertices); + if (scale != 1) { + for (let i = 0, n = vertices.length; i < n; i++) + scaledVertices[i] *= scale; + } + attachment.vertices = scaledVertices; + return; + } + let weights = new Array(); + let bones = new Array(); + for (let i = 0, n = vertices.length; i < n; ) { + let boneCount = vertices[i++]; + bones.push(boneCount); + for (let nn = i + boneCount * 4; i < nn; i += 4) { + bones.push(vertices[i]); + weights.push(vertices[i + 1] * scale); + weights.push(vertices[i + 2] * scale); + weights.push(vertices[i + 3]); + } + } + attachment.bones = bones; + attachment.vertices = Utils.toFloatArray(weights); + } + readAnimation(map, name, skeletonData) { + let scale = this.scale; + let timelines = new Array(); + if (map.slots) { + for (let slotName in map.slots) { + let slotMap = map.slots[slotName]; + let slotIndex = skeletonData.findSlot(slotName).index; + for (let timelineName in slotMap) { + let timelineMap = slotMap[timelineName]; + if (!timelineMap) + continue; + let frames = timelineMap.length; + if (timelineName == "attachment") { + let timeline = new AttachmentTimeline(frames, slotIndex); + for (let frame = 0; frame < frames; frame++) { + let keyMap = timelineMap[frame]; + timeline.setFrame(frame, getValue(keyMap, "time", 0), keyMap.name); + } + timelines.push(timeline); + } else if (timelineName == "rgba") { + let timeline = new RGBATimeline(frames, frames << 2, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color = Color.fromString(keyMap.color); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color.r, color.g, color.b, color.a); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let newColor = Color.fromString(nextMap.color); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, color.a, newColor.a, 1); + } + time = time2; + color = newColor; + keyMap = nextMap; + } + timelines.push(timeline); + } else if (timelineName == "rgb") { + let timeline = new RGBTimeline(frames, frames * 3, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color = Color.fromString(keyMap.color); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color.r, color.g, color.b); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let newColor = Color.fromString(nextMap.color); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1); + } + time = time2; + color = newColor; + keyMap = nextMap; + } + timelines.push(timeline); + } else if (timelineName == "alpha") { + timelines.push(readTimeline12(timelineMap, new AlphaTimeline(frames, frames, slotIndex), 0, 1)); + } else if (timelineName == "rgba2") { + let timeline = new RGBA2Timeline(frames, frames * 7, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color = Color.fromString(keyMap.light); + let color2 = Color.fromString(keyMap.dark); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color.r, color.g, color.b, color.a, color2.r, color2.g, color2.b); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let newColor = Color.fromString(nextMap.light); + let newColor2 = Color.fromString(nextMap.dark); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, color.a, newColor.a, 1); + bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, color2.r, newColor2.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, color2.g, newColor2.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 6, time, time2, color2.b, newColor2.b, 1); + } + time = time2; + color = newColor; + color2 = newColor2; + keyMap = nextMap; + } + timelines.push(timeline); + } else if (timelineName == "rgb2") { + let timeline = new RGB2Timeline(frames, frames * 6, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color = Color.fromString(keyMap.light); + let color2 = Color.fromString(keyMap.dark); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color.r, color.g, color.b, color2.r, color2.g, color2.b); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let newColor = Color.fromString(nextMap.light); + let newColor2 = Color.fromString(nextMap.dark); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, color2.r, newColor2.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, color2.g, newColor2.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, color2.b, newColor2.b, 1); + } + time = time2; + color = newColor; + color2 = newColor2; + keyMap = nextMap; + } + timelines.push(timeline); + } + } + } + } + if (map.bones) { + for (let boneName in map.bones) { + let boneMap = map.bones[boneName]; + let boneIndex = skeletonData.findBone(boneName).index; + for (let timelineName in boneMap) { + let timelineMap = boneMap[timelineName]; + let frames = timelineMap.length; + if (frames == 0) + continue; + if (timelineName === "rotate") { + timelines.push(readTimeline12(timelineMap, new RotateTimeline(frames, frames, boneIndex), 0, 1)); + } else if (timelineName === "translate") { + let timeline = new TranslateTimeline(frames, frames << 1, boneIndex); + timelines.push(readTimeline22(timelineMap, timeline, "x", "y", 0, scale)); + } else if (timelineName === "translatex") { + let timeline = new TranslateXTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, scale)); + } else if (timelineName === "translatey") { + let timeline = new TranslateYTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, scale)); + } else if (timelineName === "scale") { + let timeline = new ScaleTimeline(frames, frames << 1, boneIndex); + timelines.push(readTimeline22(timelineMap, timeline, "x", "y", 1, 1)); + } else if (timelineName === "scalex") { + let timeline = new ScaleXTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 1, 1)); + } else if (timelineName === "scaley") { + let timeline = new ScaleYTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 1, 1)); + } else if (timelineName === "shear") { + let timeline = new ShearTimeline(frames, frames << 1, boneIndex); + timelines.push(readTimeline22(timelineMap, timeline, "x", "y", 0, 1)); + } else if (timelineName === "shearx") { + let timeline = new ShearXTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, 1)); + } else if (timelineName === "sheary") { + let timeline = new ShearYTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, 1)); + } + } + } + } + if (map.ik) { + for (let constraintName in map.ik) { + let constraintMap = map.ik[constraintName]; + let keyMap = constraintMap[0]; + if (!keyMap) + continue; + let constraint = skeletonData.findIkConstraint(constraintName); + let constraintIndex = skeletonData.ikConstraints.indexOf(constraint); + let timeline = new IkConstraintTimeline(constraintMap.length, constraintMap.length << 1, constraintIndex); + let time = getValue(keyMap, "time", 0); + let mix = getValue(keyMap, "mix", 1); + let softness = getValue(keyMap, "softness", 0) * scale; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mix, softness, getValue(keyMap, "bendPositive", true) ? 1 : -1, getValue(keyMap, "compress", false), getValue(keyMap, "stretch", false)); + let nextMap = constraintMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let mix2 = getValue(nextMap, "mix", 1); + let softness2 = getValue(nextMap, "softness", 0) * scale; + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mix, mix2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, softness, softness2, scale); + } + time = time2; + mix = mix2; + softness = softness2; + keyMap = nextMap; + } + timelines.push(timeline); + } + } + if (map.transform) { + for (let constraintName in map.transform) { + let timelineMap = map.transform[constraintName]; + let keyMap = timelineMap[0]; + if (!keyMap) + continue; + let constraint = skeletonData.findTransformConstraint(constraintName); + let constraintIndex = skeletonData.transformConstraints.indexOf(constraint); + let timeline = new TransformConstraintTimeline(timelineMap.length, timelineMap.length * 6, constraintIndex); + let time = getValue(keyMap, "time", 0); + let mixRotate = getValue(keyMap, "mixRotate", 1); + let mixX = getValue(keyMap, "mixX", 1); + let mixY = getValue(keyMap, "mixY", mixX); + let mixScaleX = getValue(keyMap, "mixScaleX", 1); + let mixScaleY = getValue(keyMap, "mixScaleY", mixScaleX); + let mixShearY = getValue(keyMap, "mixShearY", 1); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let mixRotate2 = getValue(nextMap, "mixRotate", 1); + let mixX2 = getValue(nextMap, "mixX", 1); + let mixY2 = getValue(nextMap, "mixY", mixX2); + let mixScaleX2 = getValue(nextMap, "mixScaleX", 1); + let mixScaleY2 = getValue(nextMap, "mixScaleY", mixScaleX2); + let mixShearY2 = getValue(nextMap, "mixShearY", 1); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mixRotate, mixRotate2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, mixX, mixX2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, mixY, mixY2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, mixScaleX, mixScaleX2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, mixScaleY, mixScaleY2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, mixShearY, mixShearY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + mixScaleX = mixScaleX2; + mixScaleY = mixScaleY2; + mixScaleX = mixScaleX2; + keyMap = nextMap; + } + timelines.push(timeline); + } + } + if (map.path) { + for (let constraintName in map.path) { + let constraintMap = map.path[constraintName]; + let constraint = skeletonData.findPathConstraint(constraintName); + let constraintIndex = skeletonData.pathConstraints.indexOf(constraint); + for (let timelineName in constraintMap) { + let timelineMap = constraintMap[timelineName]; + let keyMap = timelineMap[0]; + if (!keyMap) + continue; + let frames = timelineMap.length; + if (timelineName === "position") { + let timeline = new PathConstraintPositionTimeline(frames, frames, constraintIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, constraint.positionMode == PositionMode.Fixed ? scale : 1)); + } else if (timelineName === "spacing") { + let timeline = new PathConstraintSpacingTimeline(frames, frames, constraintIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, constraint.spacingMode == SpacingMode.Length || constraint.spacingMode == SpacingMode.Fixed ? scale : 1)); + } else if (timelineName === "mix") { + let timeline = new PathConstraintMixTimeline(frames, frames * 3, constraintIndex); + let time = getValue(keyMap, "time", 0); + let mixRotate = getValue(keyMap, "mixRotate", 1); + let mixX = getValue(keyMap, "mixX", 1); + let mixY = getValue(keyMap, "mixY", mixX); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let mixRotate2 = getValue(nextMap, "mixRotate", 1); + let mixX2 = getValue(nextMap, "mixX", 1); + let mixY2 = getValue(nextMap, "mixY", mixX2); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mixRotate, mixRotate2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, mixX, mixX2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, mixY, mixY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + keyMap = nextMap; + } + timelines.push(timeline); + } + } + } + } + if (map.deform) { + for (let deformName in map.deform) { + let deformMap = map.deform[deformName]; + let skin = skeletonData.findSkin(deformName); + for (let slotName in deformMap) { + let slotMap = deformMap[slotName]; + let slotIndex = skeletonData.findSlot(slotName).index; + for (let timelineName in slotMap) { + let timelineMap = slotMap[timelineName]; + let keyMap = timelineMap[0]; + if (!keyMap) + continue; + let attachment = skin.getAttachment(slotIndex, timelineName); + let weighted = attachment.bones; + let vertices = attachment.vertices; + let deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + let timeline = new DeformTimeline(timelineMap.length, timelineMap.length, slotIndex, attachment); + let time = getValue(keyMap, "time", 0); + for (let frame = 0, bezier = 0; ; frame++) { + let deform; + let verticesValue = getValue(keyMap, "vertices", null); + if (!verticesValue) + deform = weighted ? Utils.newFloatArray(deformLength) : vertices; + else { + deform = Utils.newFloatArray(deformLength); + let start = getValue(keyMap, "offset", 0); + Utils.arrayCopy(verticesValue, 0, deform, start, verticesValue.length); + if (scale != 1) { + for (let i = start, n = i + verticesValue.length; i < n; i++) + deform[i] *= scale; + } + if (!weighted) { + for (let i = 0; i < deformLength; i++) + deform[i] += vertices[i]; + } + } + timeline.setFrame(frame, time, deform); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let curve = keyMap.curve; + if (curve) + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, 0, 1, 1); + time = time2; + keyMap = nextMap; + } + timelines.push(timeline); + } + } + } + } + if (map.drawOrder) { + let timeline = new DrawOrderTimeline(map.drawOrder.length); + let slotCount = skeletonData.slots.length; + let frame = 0; + for (let i = 0; i < map.drawOrder.length; i++, frame++) { + let drawOrderMap = map.drawOrder[i]; + let drawOrder = null; + let offsets = getValue(drawOrderMap, "offsets", null); + if (offsets) { + drawOrder = Utils.newArray(slotCount, -1); + let unchanged = Utils.newArray(slotCount - offsets.length, 0); + let originalIndex = 0, unchangedIndex = 0; + for (let ii = 0; ii < offsets.length; ii++) { + let offsetMap = offsets[ii]; + let slotIndex = skeletonData.findSlot(offsetMap.slot).index; + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + drawOrder[originalIndex + offsetMap.offset] = originalIndex++; + } + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + for (let ii = slotCount - 1; ii >= 0; ii--) + if (drawOrder[ii] == -1) + drawOrder[ii] = unchanged[--unchangedIndex]; + } + timeline.setFrame(frame, getValue(drawOrderMap, "time", 0), drawOrder); + } + timelines.push(timeline); + } + if (map.events) { + let timeline = new EventTimeline(map.events.length); + let frame = 0; + for (let i = 0; i < map.events.length; i++, frame++) { + let eventMap = map.events[i]; + let eventData = skeletonData.findEvent(eventMap.name); + let event = new Event(Utils.toSinglePrecision(getValue(eventMap, "time", 0)), eventData); + event.intValue = getValue(eventMap, "int", eventData.intValue); + event.floatValue = getValue(eventMap, "float", eventData.floatValue); + event.stringValue = getValue(eventMap, "string", eventData.stringValue); + if (event.data.audioPath) { + event.volume = getValue(eventMap, "volume", 1); + event.balance = getValue(eventMap, "balance", 0); + } + timeline.setFrame(frame, event); + } + timelines.push(timeline); + } + let duration = 0; + for (let i = 0, n = timelines.length; i < n; i++) + duration = Math.max(duration, timelines[i].getDuration()); + skeletonData.animations.push(new Animation(name, timelines, duration)); + } + }; + var LinkedMesh2 = class { + constructor(mesh, skin, slotIndex, parent, inheritDeform) { + this.mesh = mesh; + this.skin = skin; + this.slotIndex = slotIndex; + this.parent = parent; + this.inheritDeform = inheritDeform; + } + }; + function readTimeline12(keys, timeline, defaultValue, scale) { + let keyMap = keys[0]; + let time = getValue(keyMap, "time", 0); + let value = getValue(keyMap, "value", defaultValue) * scale; + let bezier = 0; + for (let frame = 0; ; frame++) { + timeline.setFrame(frame, time, value); + let nextMap = keys[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + return timeline; + } + let time2 = getValue(nextMap, "time", 0); + let value2 = getValue(nextMap, "value", defaultValue) * scale; + if (keyMap.curve) + bezier = readCurve(keyMap.curve, timeline, bezier, frame, 0, time, time2, value, value2, scale); + time = time2; + value = value2; + keyMap = nextMap; + } + } + function readTimeline22(keys, timeline, name1, name2, defaultValue, scale) { + let keyMap = keys[0]; + let time = getValue(keyMap, "time", 0); + let value1 = getValue(keyMap, name1, defaultValue) * scale; + let value2 = getValue(keyMap, name2, defaultValue) * scale; + let bezier = 0; + for (let frame = 0; ; frame++) { + timeline.setFrame(frame, time, value1, value2); + let nextMap = keys[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + return timeline; + } + let time2 = getValue(nextMap, "time", 0); + let nvalue1 = getValue(nextMap, name1, defaultValue) * scale; + let nvalue2 = getValue(nextMap, name2, defaultValue) * scale; + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, value1, nvalue1, scale); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, value2, nvalue2, scale); + } + time = time2; + value1 = nvalue1; + value2 = nvalue2; + keyMap = nextMap; + } + } + function readCurve(curve, timeline, bezier, frame, value, time1, time2, value1, value2, scale) { + if (curve == "stepped") { + timeline.setStepped(frame); + return bezier; + } + let i = value << 2; + let cx1 = curve[i]; + let cy1 = curve[i + 1] * scale; + let cx2 = curve[i + 2]; + let cy2 = curve[i + 3] * scale; + timeline.setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2); + return bezier + 1; + } + function getValue(map, property, defaultValue) { + return map[property] !== void 0 ? map[property] : defaultValue; + } + + // spine-core/src/polyfills.ts + (() => { + if (typeof Math.fround === "undefined") { + Math.fround = function(array) { + return function(x) { + return array[0] = x, array[0]; + }; + }(new Float32Array(1)); + } + })(); + + // spine-core/src/vertexeffects/JitterEffect.ts + var JitterEffect = class { + constructor(jitterX, jitterY) { + this.jitterX = 0; + this.jitterY = 0; + this.jitterX = jitterX; + this.jitterY = jitterY; + } + begin(skeleton) { + } + transform(position, uv, light, dark) { + position.x += MathUtils.randomTriangular(-this.jitterX, this.jitterY); + position.y += MathUtils.randomTriangular(-this.jitterX, this.jitterY); + } + end() { + } + }; + + // spine-core/src/vertexeffects/SwirlEffect.ts + var _SwirlEffect = class { + constructor(radius) { + this.centerX = 0; + this.centerY = 0; + this.radius = 0; + this.angle = 0; + this.worldX = 0; + this.worldY = 0; + this.radius = radius; + } + begin(skeleton) { + this.worldX = skeleton.x + this.centerX; + this.worldY = skeleton.y + this.centerY; + } + transform(position, uv, light, dark) { + let radAngle = this.angle * MathUtils.degreesToRadians; + let x = position.x - this.worldX; + let y = position.y - this.worldY; + let dist = Math.sqrt(x * x + y * y); + if (dist < this.radius) { + let theta = _SwirlEffect.interpolation.apply(0, radAngle, (this.radius - dist) / this.radius); + let cos = Math.cos(theta); + let sin = Math.sin(theta); + position.x = cos * x - sin * y + this.worldX; + position.y = sin * x + cos * y + this.worldY; + } + } + end() { + } + }; + var SwirlEffect = _SwirlEffect; + SwirlEffect.interpolation = new PowOut(2); + + // spine-canvas/src/CanvasTexture.ts + var CanvasTexture = class extends Texture { + constructor(image) { + super(image); + } + setFilters(minFilter, magFilter) { + } + setWraps(uWrap, vWrap) { + } + dispose() { + } + }; + + // spine-canvas/src/AssetManager.ts + var AssetManager = class extends AssetManagerBase { + constructor(pathPrefix = "", downloader = null) { + super((image) => { + return new CanvasTexture(image); + }, pathPrefix, downloader); + } + }; + + // spine-canvas/src/SkeletonRenderer.ts + var _SkeletonRenderer = class { + constructor(context) { + this.triangleRendering = false; + this.debugRendering = false; + this.vertices = Utils.newFloatArray(8 * 1024); + this.tempColor = new Color(); + this.ctx = context; + } + draw(skeleton) { + if (this.triangleRendering) + this.drawTriangles(skeleton); + else + this.drawImages(skeleton); + } + drawImages(skeleton) { + let ctx = this.ctx; + let color = this.tempColor; + let skeletonColor = skeleton.color; + let drawOrder = skeleton.drawOrder; + if (this.debugRendering) + ctx.strokeStyle = "green"; + for (let i = 0, n = drawOrder.length; i < n; i++) { + let slot = drawOrder[i]; + let bone = slot.bone; + if (!bone.active) + continue; + let attachment = slot.getAttachment(); + if (!(attachment instanceof RegionAttachment)) + continue; + let region = attachment.region; + let image = region.page.texture.getImage(); + let slotColor = slot.color; + let regionColor = attachment.color; + color.set(skeletonColor.r * slotColor.r * regionColor.r, skeletonColor.g * slotColor.g * regionColor.g, skeletonColor.b * slotColor.b * regionColor.b, skeletonColor.a * slotColor.a * regionColor.a); + ctx.save(); + ctx.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY); + ctx.translate(attachment.offset[0], attachment.offset[1]); + ctx.rotate(attachment.rotation * Math.PI / 180); + let atlasScale = attachment.width / region.originalWidth; + ctx.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY); + let w = region.width, h = region.height; + ctx.translate(w / 2, h / 2); + if (attachment.region.degrees == 90) { + let t = w; + w = h; + h = t; + ctx.rotate(-Math.PI / 2); + } + ctx.scale(1, -1); + ctx.translate(-w / 2, -h / 2); + ctx.globalAlpha = color.a; + ctx.drawImage(image, region.x, region.y, w, h, 0, 0, w, h); + if (this.debugRendering) + ctx.strokeRect(0, 0, w, h); + ctx.restore(); + } + } + drawTriangles(skeleton) { + let ctx = this.ctx; + let color = this.tempColor; + let skeletonColor = skeleton.color; + let drawOrder = skeleton.drawOrder; + let blendMode = null; + let vertices = this.vertices; + let triangles = null; + for (let i = 0, n = drawOrder.length; i < n; i++) { + let slot = drawOrder[i]; + let attachment = slot.getAttachment(); + let texture; + let region; + if (attachment instanceof RegionAttachment) { + let regionAttachment = attachment; + vertices = this.computeRegionVertices(slot, regionAttachment, false); + triangles = _SkeletonRenderer.QUAD_TRIANGLES; + region = regionAttachment.region; + texture = region.page.texture.getImage(); + } else if (attachment instanceof MeshAttachment) { + let mesh = attachment; + vertices = this.computeMeshVertices(slot, mesh, false); + triangles = mesh.triangles; + texture = mesh.region.renderObject.page.texture.getImage(); + } else + continue; + if (texture) { + if (slot.data.blendMode != blendMode) + blendMode = slot.data.blendMode; + let slotColor = slot.color; + let attachmentColor = attachment.color; + color.set(skeletonColor.r * slotColor.r * attachmentColor.r, skeletonColor.g * slotColor.g * attachmentColor.g, skeletonColor.b * slotColor.b * attachmentColor.b, skeletonColor.a * slotColor.a * attachmentColor.a); + ctx.globalAlpha = color.a; + for (var j = 0; j < triangles.length; j += 3) { + let t1 = triangles[j] * 8, t2 = triangles[j + 1] * 8, t3 = triangles[j + 2] * 8; + let x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7]; + let x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7]; + let x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7]; + this.drawTriangle(texture, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2); + if (this.debugRendering) { + ctx.strokeStyle = "green"; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.lineTo(x0, y0); + ctx.stroke(); + } + } + } + } + this.ctx.globalAlpha = 1; + } + drawTriangle(img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2) { + let ctx = this.ctx; + u0 *= img.width; + v0 *= img.height; + u1 *= img.width; + v1 *= img.height; + u2 *= img.width; + v2 *= img.height; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.closePath(); + x1 -= x0; + y1 -= y0; + x2 -= x0; + y2 -= y0; + u1 -= u0; + v1 -= v0; + u2 -= u0; + v2 -= v0; + var det = 1 / (u1 * v2 - u2 * v1), a = (v2 * x1 - v1 * x2) * det, b = (v2 * y1 - v1 * y2) * det, c = (u1 * x2 - u2 * x1) * det, d = (u1 * y2 - u2 * y1) * det, e = x0 - a * u0 - c * v0, f = y0 - b * u0 - d * v0; + ctx.save(); + ctx.transform(a, b, c, d, e, f); + ctx.clip(); + ctx.drawImage(img, 0, 0); + ctx.restore(); + } + computeRegionVertices(slot, region, pma) { + let skeletonColor = slot.bone.skeleton.color; + let slotColor = slot.color; + let regionColor = region.color; + let alpha = skeletonColor.a * slotColor.a * regionColor.a; + let multiplier = pma ? alpha : 1; + let color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier, skeletonColor.g * slotColor.g * regionColor.g * multiplier, skeletonColor.b * slotColor.b * regionColor.b * multiplier, alpha); + region.computeWorldVertices(slot.bone, this.vertices, 0, _SkeletonRenderer.VERTEX_SIZE); + let vertices = this.vertices; + let uvs = region.uvs; + vertices[RegionAttachment.C1R] = color.r; + vertices[RegionAttachment.C1G] = color.g; + vertices[RegionAttachment.C1B] = color.b; + vertices[RegionAttachment.C1A] = color.a; + vertices[RegionAttachment.U1] = uvs[0]; + vertices[RegionAttachment.V1] = uvs[1]; + vertices[RegionAttachment.C2R] = color.r; + vertices[RegionAttachment.C2G] = color.g; + vertices[RegionAttachment.C2B] = color.b; + vertices[RegionAttachment.C2A] = color.a; + vertices[RegionAttachment.U2] = uvs[2]; + vertices[RegionAttachment.V2] = uvs[3]; + vertices[RegionAttachment.C3R] = color.r; + vertices[RegionAttachment.C3G] = color.g; + vertices[RegionAttachment.C3B] = color.b; + vertices[RegionAttachment.C3A] = color.a; + vertices[RegionAttachment.U3] = uvs[4]; + vertices[RegionAttachment.V3] = uvs[5]; + vertices[RegionAttachment.C4R] = color.r; + vertices[RegionAttachment.C4G] = color.g; + vertices[RegionAttachment.C4B] = color.b; + vertices[RegionAttachment.C4A] = color.a; + vertices[RegionAttachment.U4] = uvs[6]; + vertices[RegionAttachment.V4] = uvs[7]; + return vertices; + } + computeMeshVertices(slot, mesh, pma) { + let skeletonColor = slot.bone.skeleton.color; + let slotColor = slot.color; + let regionColor = mesh.color; + let alpha = skeletonColor.a * slotColor.a * regionColor.a; + let multiplier = pma ? alpha : 1; + let color = this.tempColor; + color.set(skeletonColor.r * slotColor.r * regionColor.r * multiplier, skeletonColor.g * slotColor.g * regionColor.g * multiplier, skeletonColor.b * slotColor.b * regionColor.b * multiplier, alpha); + let vertexCount = mesh.worldVerticesLength / 2; + let vertices = this.vertices; + if (vertices.length < mesh.worldVerticesLength) + this.vertices = vertices = Utils.newFloatArray(mesh.worldVerticesLength); + mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, _SkeletonRenderer.VERTEX_SIZE); + let uvs = mesh.uvs; + for (let i = 0, u = 0, v = 2; i < vertexCount; i++) { + vertices[v++] = color.r; + vertices[v++] = color.g; + vertices[v++] = color.b; + vertices[v++] = color.a; + vertices[v++] = uvs[u++]; + vertices[v++] = uvs[u++]; + v += 2; + } + return vertices; + } + }; + var SkeletonRenderer = _SkeletonRenderer; + SkeletonRenderer.QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; + SkeletonRenderer.VERTEX_SIZE = 2 + 2 + 4; + return src_exports; +})(); +//# sourceMappingURL=spine-canvas.js.map diff --git a/lib/4.1/spine-canvas.js b/lib/4.1/spine-canvas.js new file mode 100644 index 0000000..f2d3b6b --- /dev/null +++ b/lib/4.1/spine-canvas.js @@ -0,0 +1,11055 @@ +"use strict"; +var spine = (() => { + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; + var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + var __publicField = (obj, key, value) => { + __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); + return value; + }; + + // spine-canvas/src/index.ts + var src_exports = {}; + __export(src_exports, { + AlphaTimeline: () => AlphaTimeline, + Animation: () => Animation, + AnimationState: () => AnimationState, + AnimationStateAdapter: () => AnimationStateAdapter, + AnimationStateData: () => AnimationStateData, + AssetManager: () => AssetManager, + AssetManagerBase: () => AssetManagerBase, + AtlasAttachmentLoader: () => AtlasAttachmentLoader, + Attachment: () => Attachment, + AttachmentTimeline: () => AttachmentTimeline, + BinaryInput: () => BinaryInput, + BlendMode: () => BlendMode, + Bone: () => Bone, + BoneData: () => BoneData, + BoundingBoxAttachment: () => BoundingBoxAttachment, + CURRENT: () => CURRENT, + CanvasTexture: () => CanvasTexture, + ClippingAttachment: () => ClippingAttachment, + Color: () => Color, + ConstraintData: () => ConstraintData, + CurveTimeline: () => CurveTimeline, + CurveTimeline1: () => CurveTimeline1, + CurveTimeline2: () => CurveTimeline2, + DebugUtils: () => DebugUtils, + DeformTimeline: () => DeformTimeline, + Downloader: () => Downloader, + DrawOrderTimeline: () => DrawOrderTimeline, + Event: () => Event, + EventData: () => EventData, + EventQueue: () => EventQueue, + EventTimeline: () => EventTimeline, + EventType: () => EventType, + FIRST: () => FIRST, + FakeTexture: () => FakeTexture, + HOLD_FIRST: () => HOLD_FIRST, + HOLD_MIX: () => HOLD_MIX, + HOLD_SUBSEQUENT: () => HOLD_SUBSEQUENT, + IkConstraint: () => IkConstraint, + IkConstraintData: () => IkConstraintData, + IkConstraintTimeline: () => IkConstraintTimeline, + IntSet: () => IntSet, + Interpolation: () => Interpolation, + MathUtils: () => MathUtils, + MeshAttachment: () => MeshAttachment, + MixBlend: () => MixBlend, + MixDirection: () => MixDirection, + PathAttachment: () => PathAttachment, + PathConstraint: () => PathConstraint, + PathConstraintData: () => PathConstraintData, + PathConstraintMixTimeline: () => PathConstraintMixTimeline, + PathConstraintPositionTimeline: () => PathConstraintPositionTimeline, + PathConstraintSpacingTimeline: () => PathConstraintSpacingTimeline, + PointAttachment: () => PointAttachment, + Pool: () => Pool, + PositionMode: () => PositionMode, + Pow: () => Pow, + PowOut: () => PowOut, + RGB2Timeline: () => RGB2Timeline, + RGBA2Timeline: () => RGBA2Timeline, + RGBATimeline: () => RGBATimeline, + RGBTimeline: () => RGBTimeline, + RegionAttachment: () => RegionAttachment, + RotateMode: () => RotateMode, + RotateTimeline: () => RotateTimeline, + SETUP: () => SETUP, + SUBSEQUENT: () => SUBSEQUENT, + ScaleTimeline: () => ScaleTimeline, + ScaleXTimeline: () => ScaleXTimeline, + ScaleYTimeline: () => ScaleYTimeline, + SequenceTimeline: () => SequenceTimeline, + ShearTimeline: () => ShearTimeline, + ShearXTimeline: () => ShearXTimeline, + ShearYTimeline: () => ShearYTimeline, + Skeleton: () => Skeleton, + SkeletonBinary: () => SkeletonBinary, + SkeletonBounds: () => SkeletonBounds, + SkeletonClipping: () => SkeletonClipping, + SkeletonData: () => SkeletonData, + SkeletonJson: () => SkeletonJson, + SkeletonRenderer: () => SkeletonRenderer, + Skin: () => Skin, + SkinEntry: () => SkinEntry, + Slot: () => Slot, + SlotData: () => SlotData, + SpacingMode: () => SpacingMode, + StringSet: () => StringSet, + Texture: () => Texture, + TextureAtlas: () => TextureAtlas, + TextureAtlasPage: () => TextureAtlasPage, + TextureAtlasRegion: () => TextureAtlasRegion, + TextureFilter: () => TextureFilter, + TextureRegion: () => TextureRegion, + TextureWrap: () => TextureWrap, + TimeKeeper: () => TimeKeeper, + Timeline: () => Timeline, + TrackEntry: () => TrackEntry, + TransformConstraint: () => TransformConstraint, + TransformConstraintData: () => TransformConstraintData, + TransformConstraintTimeline: () => TransformConstraintTimeline, + TransformMode: () => TransformMode, + TranslateTimeline: () => TranslateTimeline, + TranslateXTimeline: () => TranslateXTimeline, + TranslateYTimeline: () => TranslateYTimeline, + Triangulator: () => Triangulator, + Utils: () => Utils, + Vector2: () => Vector2, + VertexAttachment: () => VertexAttachment, + WindowedMean: () => WindowedMean + }); + + // spine-core/src/Utils.ts + var IntSet = class { + array = new Array(); + add(value) { + let contains = this.contains(value); + this.array[value | 0] = value | 0; + return !contains; + } + contains(value) { + return this.array[value | 0] != void 0; + } + remove(value) { + this.array[value | 0] = void 0; + } + clear() { + this.array.length = 0; + } + }; + var StringSet = class { + entries = {}; + size = 0; + add(value) { + let contains = this.entries[value]; + this.entries[value] = true; + if (!contains) { + this.size++; + return true; + } + return false; + } + addAll(values) { + let oldSize = this.size; + for (var i = 0, n = values.length; i < n; i++) + this.add(values[i]); + return oldSize != this.size; + } + contains(value) { + return this.entries[value]; + } + clear() { + this.entries = {}; + this.size = 0; + } + }; + var _Color = class { + constructor(r = 0, g = 0, b = 0, a = 0) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + set(r, g, b, a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + return this.clamp(); + } + setFromColor(c) { + this.r = c.r; + this.g = c.g; + this.b = c.b; + this.a = c.a; + return this; + } + setFromString(hex) { + hex = hex.charAt(0) == "#" ? hex.substr(1) : hex; + this.r = parseInt(hex.substr(0, 2), 16) / 255; + this.g = parseInt(hex.substr(2, 2), 16) / 255; + this.b = parseInt(hex.substr(4, 2), 16) / 255; + this.a = hex.length != 8 ? 1 : parseInt(hex.substr(6, 2), 16) / 255; + return this; + } + add(r, g, b, a) { + this.r += r; + this.g += g; + this.b += b; + this.a += a; + return this.clamp(); + } + clamp() { + if (this.r < 0) + this.r = 0; + else if (this.r > 1) + this.r = 1; + if (this.g < 0) + this.g = 0; + else if (this.g > 1) + this.g = 1; + if (this.b < 0) + this.b = 0; + else if (this.b > 1) + this.b = 1; + if (this.a < 0) + this.a = 0; + else if (this.a > 1) + this.a = 1; + return this; + } + static rgba8888ToColor(color, value) { + color.r = ((value & 4278190080) >>> 24) / 255; + color.g = ((value & 16711680) >>> 16) / 255; + color.b = ((value & 65280) >>> 8) / 255; + color.a = (value & 255) / 255; + } + static rgb888ToColor(color, value) { + color.r = ((value & 16711680) >>> 16) / 255; + color.g = ((value & 65280) >>> 8) / 255; + color.b = (value & 255) / 255; + } + static fromString(hex) { + return new _Color().setFromString(hex); + } + }; + var Color = _Color; + __publicField(Color, "WHITE", new _Color(1, 1, 1, 1)); + __publicField(Color, "RED", new _Color(1, 0, 0, 1)); + __publicField(Color, "GREEN", new _Color(0, 1, 0, 1)); + __publicField(Color, "BLUE", new _Color(0, 0, 1, 1)); + __publicField(Color, "MAGENTA", new _Color(1, 0, 1, 1)); + var _MathUtils = class { + static clamp(value, min, max) { + if (value < min) + return min; + if (value > max) + return max; + return value; + } + static cosDeg(degrees) { + return Math.cos(degrees * _MathUtils.degRad); + } + static sinDeg(degrees) { + return Math.sin(degrees * _MathUtils.degRad); + } + static signum(value) { + return value > 0 ? 1 : value < 0 ? -1 : 0; + } + static toInt(x) { + return x > 0 ? Math.floor(x) : Math.ceil(x); + } + static cbrt(x) { + let y = Math.pow(Math.abs(x), 1 / 3); + return x < 0 ? -y : y; + } + static randomTriangular(min, max) { + return _MathUtils.randomTriangularWith(min, max, (min + max) * 0.5); + } + static randomTriangularWith(min, max, mode) { + let u = Math.random(); + let d = max - min; + if (u <= (mode - min) / d) + return min + Math.sqrt(u * d * (mode - min)); + return max - Math.sqrt((1 - u) * d * (max - mode)); + } + static isPowerOfTwo(value) { + return value && (value & value - 1) === 0; + } + }; + var MathUtils = _MathUtils; + __publicField(MathUtils, "PI", 3.1415927); + __publicField(MathUtils, "PI2", _MathUtils.PI * 2); + __publicField(MathUtils, "radiansToDegrees", 180 / _MathUtils.PI); + __publicField(MathUtils, "radDeg", _MathUtils.radiansToDegrees); + __publicField(MathUtils, "degreesToRadians", _MathUtils.PI / 180); + __publicField(MathUtils, "degRad", _MathUtils.degreesToRadians); + var Interpolation = class { + apply(start, end, a) { + return start + (end - start) * this.applyInternal(a); + } + }; + var Pow = class extends Interpolation { + power = 2; + constructor(power) { + super(); + this.power = power; + } + applyInternal(a) { + if (a <= 0.5) + return Math.pow(a * 2, this.power) / 2; + return Math.pow((a - 1) * 2, this.power) / (this.power % 2 == 0 ? -2 : 2) + 1; + } + }; + var PowOut = class extends Pow { + constructor(power) { + super(power); + } + applyInternal(a) { + return Math.pow(a - 1, this.power) * (this.power % 2 == 0 ? -1 : 1) + 1; + } + }; + var _Utils = class { + static arrayCopy(source, sourceStart, dest, destStart, numElements) { + for (let i = sourceStart, j = destStart; i < sourceStart + numElements; i++, j++) { + dest[j] = source[i]; + } + } + static arrayFill(array, fromIndex, toIndex, value) { + for (let i = fromIndex; i < toIndex; i++) + array[i] = value; + } + static setArraySize(array, size, value = 0) { + let oldSize = array.length; + if (oldSize == size) + return array; + array.length = size; + if (oldSize < size) { + for (let i = oldSize; i < size; i++) + array[i] = value; + } + return array; + } + static ensureArrayCapacity(array, size, value = 0) { + if (array.length >= size) + return array; + return _Utils.setArraySize(array, size, value); + } + static newArray(size, defaultValue) { + let array = new Array(size); + for (let i = 0; i < size; i++) + array[i] = defaultValue; + return array; + } + static newFloatArray(size) { + if (_Utils.SUPPORTS_TYPED_ARRAYS) + return new Float32Array(size); + else { + let array = new Array(size); + for (let i = 0; i < array.length; i++) + array[i] = 0; + return array; + } + } + static newShortArray(size) { + if (_Utils.SUPPORTS_TYPED_ARRAYS) + return new Int16Array(size); + else { + let array = new Array(size); + for (let i = 0; i < array.length; i++) + array[i] = 0; + return array; + } + } + static toFloatArray(array) { + return _Utils.SUPPORTS_TYPED_ARRAYS ? new Float32Array(array) : array; + } + static toSinglePrecision(value) { + return _Utils.SUPPORTS_TYPED_ARRAYS ? Math.fround(value) : value; + } + // This function is used to fix WebKit 602 specific issue described at http://esotericsoftware.com/forum/iOS-10-disappearing-graphics-10109 + static webkit602BugfixHelper(alpha, blend) { + } + static contains(array, element, identity = true) { + for (var i = 0; i < array.length; i++) + if (array[i] == element) + return true; + return false; + } + static enumValue(type, name) { + return type[name[0].toUpperCase() + name.slice(1)]; + } + }; + var Utils = _Utils; + __publicField(Utils, "SUPPORTS_TYPED_ARRAYS", typeof Float32Array !== "undefined"); + var DebugUtils = class { + static logBones(skeleton) { + for (let i = 0; i < skeleton.bones.length; i++) { + let bone = skeleton.bones[i]; + console.log(bone.data.name + ", " + bone.a + ", " + bone.b + ", " + bone.c + ", " + bone.d + ", " + bone.worldX + ", " + bone.worldY); + } + } + }; + var Pool = class { + items = new Array(); + instantiator; + constructor(instantiator) { + this.instantiator = instantiator; + } + obtain() { + return this.items.length > 0 ? this.items.pop() : this.instantiator(); + } + free(item) { + if (item.reset) + item.reset(); + this.items.push(item); + } + freeAll(items) { + for (let i = 0; i < items.length; i++) + this.free(items[i]); + } + clear() { + this.items.length = 0; + } + }; + var Vector2 = class { + constructor(x = 0, y = 0) { + this.x = x; + this.y = y; + } + set(x, y) { + this.x = x; + this.y = y; + return this; + } + length() { + let x = this.x; + let y = this.y; + return Math.sqrt(x * x + y * y); + } + normalize() { + let len = this.length(); + if (len != 0) { + this.x /= len; + this.y /= len; + } + return this; + } + }; + var TimeKeeper = class { + maxDelta = 0.064; + framesPerSecond = 0; + delta = 0; + totalTime = 0; + lastTime = Date.now() / 1e3; + frameCount = 0; + frameTime = 0; + update() { + let now = Date.now() / 1e3; + this.delta = now - this.lastTime; + this.frameTime += this.delta; + this.totalTime += this.delta; + if (this.delta > this.maxDelta) + this.delta = this.maxDelta; + this.lastTime = now; + this.frameCount++; + if (this.frameTime > 1) { + this.framesPerSecond = this.frameCount / this.frameTime; + this.frameTime = 0; + this.frameCount = 0; + } + } + }; + var WindowedMean = class { + values; + addedValues = 0; + lastValue = 0; + mean = 0; + dirty = true; + constructor(windowSize = 32) { + this.values = new Array(windowSize); + } + hasEnoughData() { + return this.addedValues >= this.values.length; + } + addValue(value) { + if (this.addedValues < this.values.length) + this.addedValues++; + this.values[this.lastValue++] = value; + if (this.lastValue > this.values.length - 1) + this.lastValue = 0; + this.dirty = true; + } + getMean() { + if (this.hasEnoughData()) { + if (this.dirty) { + let mean = 0; + for (let i = 0; i < this.values.length; i++) + mean += this.values[i]; + this.mean = mean / this.values.length; + this.dirty = false; + } + return this.mean; + } + return 0; + } + }; + + // spine-core/src/attachments/Attachment.ts + var Attachment = class { + name; + constructor(name) { + if (!name) + throw new Error("name cannot be null."); + this.name = name; + } + }; + var _VertexAttachment = class extends Attachment { + /** The unique ID for this attachment. */ + id = _VertexAttachment.nextID++; + /** The bones which affect the {@link #getVertices()}. The array entries are, for each vertex, the number of bones affecting + * the vertex followed by that many bone indices, which is the index of the bone in {@link Skeleton#bones}. Will be null + * if this attachment has no weights. */ + bones = null; + /** The vertex positions in the bone's coordinate system. For a non-weighted attachment, the values are `x,y` + * entries for each vertex. For a weighted attachment, the values are `x,y,weight` entries for each bone affecting + * each vertex. */ + vertices = []; + /** The maximum number of world vertex values that can be output by + * {@link #computeWorldVertices()} using the `count` parameter. */ + worldVerticesLength = 0; + /** Timelines for the timeline attachment are also applied to this attachment. + * May be null if no attachment-specific timelines should be applied. */ + timelineAttachment = this; + constructor(name) { + super(name); + } + /** Transforms the attachment's local {@link #vertices} to world coordinates. If the slot's {@link Slot#deform} is + * not empty, it is used to deform the vertices. + * + * See [World transforms](http://esotericsoftware.com/spine-runtime-skeletons#World-transforms) in the Spine + * Runtimes Guide. + * @param start The index of the first {@link #vertices} value to transform. Each vertex has 2 values, x and y. + * @param count The number of world vertex values to output. Must be <= {@link #worldVerticesLength} - `start`. + * @param worldVertices The output world vertices. Must have a length >= `offset` + `count` * + * `stride` / 2. + * @param offset The `worldVertices` index to begin writing values. + * @param stride The number of `worldVertices` entries between the value pairs written. */ + computeWorldVertices(slot, start, count, worldVertices2, offset, stride) { + count = offset + (count >> 1) * stride; + let skeleton = slot.bone.skeleton; + let deformArray = slot.deform; + let vertices = this.vertices; + let bones = this.bones; + if (!bones) { + if (deformArray.length > 0) + vertices = deformArray; + let bone = slot.bone; + let x = bone.worldX; + let y = bone.worldY; + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + for (let v2 = start, w = offset; w < count; v2 += 2, w += stride) { + let vx = vertices[v2], vy = vertices[v2 + 1]; + worldVertices2[w] = vx * a + vy * b + x; + worldVertices2[w + 1] = vx * c + vy * d + y; + } + return; + } + let v = 0, skip = 0; + for (let i = 0; i < start; i += 2) { + let n = bones[v]; + v += n + 1; + skip += n; + } + let skeletonBones = skeleton.bones; + if (deformArray.length == 0) { + for (let w = offset, b = skip * 3; w < count; w += stride) { + let wx = 0, wy = 0; + let n = bones[v++]; + n += v; + for (; v < n; v++, b += 3) { + let bone = skeletonBones[bones[v]]; + let vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices2[w] = wx; + worldVertices2[w + 1] = wy; + } + } else { + let deform = deformArray; + for (let w = offset, b = skip * 3, f = skip << 1; w < count; w += stride) { + let wx = 0, wy = 0; + let n = bones[v++]; + n += v; + for (; v < n; v++, b += 3, f += 2) { + let bone = skeletonBones[bones[v]]; + let vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices2[w] = wx; + worldVertices2[w + 1] = wy; + } + } + } + /** Does not copy id (generated) or name (set on construction). **/ + copyTo(attachment) { + if (this.bones) { + attachment.bones = new Array(this.bones.length); + Utils.arrayCopy(this.bones, 0, attachment.bones, 0, this.bones.length); + } else + attachment.bones = null; + if (this.vertices) { + attachment.vertices = Utils.newFloatArray(this.vertices.length); + Utils.arrayCopy(this.vertices, 0, attachment.vertices, 0, this.vertices.length); + } + attachment.worldVerticesLength = this.worldVerticesLength; + attachment.timelineAttachment = this.timelineAttachment; + } + }; + var VertexAttachment = _VertexAttachment; + __publicField(VertexAttachment, "nextID", 0); + + // spine-core/src/attachments/Sequence.ts + var _Sequence = class { + id = _Sequence.nextID(); + regions; + start = 0; + digits = 0; + /** The index of the region to show for the setup pose. */ + setupIndex = 0; + constructor(count) { + this.regions = new Array(count); + } + copy() { + let copy = new _Sequence(this.regions.length); + Utils.arrayCopy(this.regions, 0, copy.regions, 0, this.regions.length); + copy.start = this.start; + copy.digits = this.digits; + copy.setupIndex = this.setupIndex; + return copy; + } + apply(slot, attachment) { + let index = slot.sequenceIndex; + if (index == -1) + index = this.setupIndex; + if (index >= this.regions.length) + index = this.regions.length - 1; + let region = this.regions[index]; + if (attachment.region != region) { + attachment.region = region; + attachment.updateRegion(); + } + } + getPath(basePath, index) { + let result = basePath; + let frame = (this.start + index).toString(); + for (let i = this.digits - frame.length; i > 0; i--) + result += "0"; + result += frame; + return result; + } + static nextID() { + return _Sequence._nextID++; + } + }; + var Sequence = _Sequence; + __publicField(Sequence, "_nextID", 0); + var SequenceMode = /* @__PURE__ */ ((SequenceMode2) => { + SequenceMode2[SequenceMode2["hold"] = 0] = "hold"; + SequenceMode2[SequenceMode2["once"] = 1] = "once"; + SequenceMode2[SequenceMode2["loop"] = 2] = "loop"; + SequenceMode2[SequenceMode2["pingpong"] = 3] = "pingpong"; + SequenceMode2[SequenceMode2["onceReverse"] = 4] = "onceReverse"; + SequenceMode2[SequenceMode2["loopReverse"] = 5] = "loopReverse"; + SequenceMode2[SequenceMode2["pingpongReverse"] = 6] = "pingpongReverse"; + return SequenceMode2; + })(SequenceMode || {}); + var SequenceModeValues = [ + 0 /* hold */, + 1 /* once */, + 2 /* loop */, + 3 /* pingpong */, + 4 /* onceReverse */, + 5 /* loopReverse */, + 6 /* pingpongReverse */ + ]; + + // spine-core/src/Animation.ts + var Animation = class { + /** The animation's name, which is unique across all animations in the skeleton. */ + name; + timelines = []; + timelineIds = new StringSet(); + /** The duration of the animation in seconds, which is the highest time of all keys in the timeline. */ + duration; + constructor(name, timelines, duration) { + if (!name) + throw new Error("name cannot be null."); + this.name = name; + this.setTimelines(timelines); + this.duration = duration; + } + setTimelines(timelines) { + if (!timelines) + throw new Error("timelines cannot be null."); + this.timelines = timelines; + this.timelineIds.clear(); + for (var i = 0; i < timelines.length; i++) + this.timelineIds.addAll(timelines[i].getPropertyIds()); + } + hasTimeline(ids) { + for (let i = 0; i < ids.length; i++) + if (this.timelineIds.contains(ids[i])) + return true; + return false; + } + /** Applies all the animation's timelines to the specified skeleton. + * + * See Timeline {@link Timeline#apply(Skeleton, float, float, Array, float, MixBlend, MixDirection)}. + * @param loop If true, the animation repeats after {@link #getDuration()}. + * @param events May be null to ignore fired events. */ + apply(skeleton, lastTime, time, loop, events, alpha, blend, direction) { + if (!skeleton) + throw new Error("skeleton cannot be null."); + if (loop && this.duration != 0) { + time %= this.duration; + if (lastTime > 0) + lastTime %= this.duration; + } + let timelines = this.timelines; + for (let i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, lastTime, time, events, alpha, blend, direction); + } + }; + var MixBlend = /* @__PURE__ */ ((MixBlend2) => { + MixBlend2[MixBlend2["setup"] = 0] = "setup"; + MixBlend2[MixBlend2["first"] = 1] = "first"; + MixBlend2[MixBlend2["replace"] = 2] = "replace"; + MixBlend2[MixBlend2["add"] = 3] = "add"; + return MixBlend2; + })(MixBlend || {}); + var MixDirection = /* @__PURE__ */ ((MixDirection2) => { + MixDirection2[MixDirection2["mixIn"] = 0] = "mixIn"; + MixDirection2[MixDirection2["mixOut"] = 1] = "mixOut"; + return MixDirection2; + })(MixDirection || {}); + var Property = { + rotate: 0, + x: 1, + y: 2, + scaleX: 3, + scaleY: 4, + shearX: 5, + shearY: 6, + rgb: 7, + alpha: 8, + rgb2: 9, + attachment: 10, + deform: 11, + event: 12, + drawOrder: 13, + ikConstraint: 14, + transformConstraint: 15, + pathConstraintPosition: 16, + pathConstraintSpacing: 17, + pathConstraintMix: 18, + sequence: 19 + }; + var Timeline = class { + propertyIds; + frames; + constructor(frameCount, propertyIds) { + this.propertyIds = propertyIds; + this.frames = Utils.newFloatArray(frameCount * this.getFrameEntries()); + } + getPropertyIds() { + return this.propertyIds; + } + getFrameEntries() { + return 1; + } + getFrameCount() { + return this.frames.length / this.getFrameEntries(); + } + getDuration() { + return this.frames[this.frames.length - this.getFrameEntries()]; + } + static search1(frames, time) { + let n = frames.length; + for (let i = 1; i < n; i++) + if (frames[i] > time) + return i - 1; + return n - 1; + } + static search(frames, time, step) { + let n = frames.length; + for (let i = step; i < n; i += step) + if (frames[i] > time) + return i - step; + return n - step; + } + }; + var CurveTimeline = class extends Timeline { + curves; + // type, x, y, ... + constructor(frameCount, bezierCount, propertyIds) { + super(frameCount, propertyIds); + this.curves = Utils.newFloatArray( + frameCount + bezierCount * 18 + /*BEZIER_SIZE*/ + ); + this.curves[frameCount - 1] = 1; + } + /** Sets the specified key frame to linear interpolation. */ + setLinear(frame) { + this.curves[frame] = 0; + } + /** Sets the specified key frame to stepped interpolation. */ + setStepped(frame) { + this.curves[frame] = 1; + } + /** Shrinks the storage for Bezier curves, for use when bezierCount (specified in the constructor) was larger + * than the actual number of Bezier curves. */ + shrink(bezierCount) { + let size = this.getFrameCount() + bezierCount * 18; + if (this.curves.length > size) { + let newCurves = Utils.newFloatArray(size); + Utils.arrayCopy(this.curves, 0, newCurves, 0, size); + this.curves = newCurves; + } + } + /** Stores the segments for the specified Bezier curve. For timelines that modify multiple values, there may be more than + * one curve per frame. + * @param bezier The ordinal of this Bezier curve for this timeline, between 0 and bezierCount - 1 (specified + * in the constructor), inclusive. + * @param frame Between 0 and frameCount - 1, inclusive. + * @param value The index of the value for this frame that this curve is used for. + * @param time1 The time for the first key. + * @param value1 The value for the first key. + * @param cx1 The time for the first Bezier handle. + * @param cy1 The value for the first Bezier handle. + * @param cx2 The time of the second Bezier handle. + * @param cy2 The value for the second Bezier handle. + * @param time2 The time for the second key. + * @param value2 The value for the second key. */ + setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2) { + let curves = this.curves; + let i = this.getFrameCount() + bezier * 18; + if (value == 0) + curves[frame] = 2 + i; + let tmpx = (time1 - cx1 * 2 + cx2) * 0.03, tmpy = (value1 - cy1 * 2 + cy2) * 0.03; + let dddx = ((cx1 - cx2) * 3 - time1 + time2) * 6e-3, dddy = ((cy1 - cy2) * 3 - value1 + value2) * 6e-3; + let ddx = tmpx * 2 + dddx, ddy = tmpy * 2 + dddy; + let dx = (cx1 - time1) * 0.3 + tmpx + dddx * 0.16666667, dy = (cy1 - value1) * 0.3 + tmpy + dddy * 0.16666667; + let x = time1 + dx, y = value1 + dy; + for (let n = i + 18; i < n; i += 2) { + curves[i] = x; + curves[i + 1] = y; + dx += ddx; + dy += ddy; + ddx += dddx; + ddy += dddy; + x += dx; + y += dy; + } + } + /** Returns the Bezier interpolated value for the specified time. + * @param frameIndex The index into {@link #getFrames()} for the values of the frame before time. + * @param valueOffset The offset from frameIndex to the value this curve is used for. + * @param i The index of the Bezier segments. See {@link #getCurveType(int)}. */ + getBezierValue(time, frameIndex, valueOffset, i) { + let curves = this.curves; + if (curves[i] > time) { + let x2 = this.frames[frameIndex], y2 = this.frames[frameIndex + valueOffset]; + return y2 + (time - x2) / (curves[i] - x2) * (curves[i + 1] - y2); + } + let n = i + 18; + for (i += 2; i < n; i += 2) { + if (curves[i] >= time) { + let x2 = curves[i - 2], y2 = curves[i - 1]; + return y2 + (time - x2) / (curves[i] - x2) * (curves[i + 1] - y2); + } + } + frameIndex += this.getFrameEntries(); + let x = curves[n - 2], y = curves[n - 1]; + return y + (time - x) / (this.frames[frameIndex] - x) * (this.frames[frameIndex + valueOffset] - y); + } + }; + var CurveTimeline1 = class extends CurveTimeline { + constructor(frameCount, bezierCount, propertyId) { + super(frameCount, bezierCount, [propertyId]); + } + getFrameEntries() { + return 2; + } + /** Sets the time and value for the specified frame. + * @param frame Between 0 and frameCount, inclusive. + * @param time The frame time in seconds. */ + setFrame(frame, time, value) { + frame <<= 1; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*VALUE*/ + ] = value; + } + /** Returns the interpolated value for the specified time. */ + getCurveValue(time) { + let frames = this.frames; + let i = frames.length - 2; + for (let ii = 2; ii <= i; ii += 2) { + if (frames[ii] > time) { + i = ii - 2; + break; + } + } + let curveType = this.curves[i >> 1]; + switch (curveType) { + case 0: + let before = frames[i], value = frames[ + i + 1 + /*VALUE*/ + ]; + return value + (time - before) / (frames[ + i + 2 + /*ENTRIES*/ + ] - before) * (frames[ + i + 2 + 1 + /*VALUE*/ + ] - value); + case 1: + return frames[ + i + 1 + /*VALUE*/ + ]; + } + return this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + } + }; + var CurveTimeline2 = class extends CurveTimeline { + /** @param bezierCount The maximum number of Bezier curves. See {@link #shrink(int)}. + * @param propertyIds Unique identifiers for the properties the timeline modifies. */ + constructor(frameCount, bezierCount, propertyId1, propertyId2) { + super(frameCount, bezierCount, [propertyId1, propertyId2]); + } + getFrameEntries() { + return 3; + } + /** Sets the time and values for the specified frame. + * @param frame Between 0 and frameCount, inclusive. + * @param time The frame time in seconds. */ + setFrame(frame, time, value1, value2) { + frame *= 3; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*VALUE1*/ + ] = value1; + this.frames[ + frame + 2 + /*VALUE2*/ + ] = value2; + } + }; + var RotateTimeline = class extends CurveTimeline1 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.rotate + "|" + boneIndex); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + bone.rotation = bone.data.rotation; + return; + case 1 /* first */: + bone.rotation += (bone.data.rotation - bone.rotation) * alpha; + } + return; + } + let r = this.getCurveValue(time); + switch (blend) { + case 0 /* setup */: + bone.rotation = bone.data.rotation + r * alpha; + break; + case 1 /* first */: + case 2 /* replace */: + r += bone.data.rotation - bone.rotation; + case 3 /* add */: + bone.rotation += r * alpha; + } + } + }; + var TranslateTimeline = class extends CurveTimeline2 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super( + frameCount, + bezierCount, + Property.x + "|" + boneIndex, + Property.y + "|" + boneIndex + ); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + bone.x = bone.data.x; + bone.y = bone.data.y; + return; + case 1 /* first */: + bone.x += (bone.data.x - bone.x) * alpha; + bone.y += (bone.data.y - bone.y) * alpha; + } + return; + } + let x = 0, y = 0; + let i = Timeline.search( + frames, + time, + 3 + /*ENTRIES*/ + ); + let curveType = this.curves[ + i / 3 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: + let before = frames[i]; + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + let t = (time - before) / (frames[ + i + 3 + /*ENTRIES*/ + ] - before); + x += (frames[ + i + 3 + 1 + /*VALUE1*/ + ] - x) * t; + y += (frames[ + i + 3 + 2 + /*VALUE2*/ + ] - y) * t; + break; + case 1: + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + break; + default: + x = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + y = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + } + switch (blend) { + case 0 /* setup */: + bone.x = bone.data.x + x * alpha; + bone.y = bone.data.y + y * alpha; + break; + case 1 /* first */: + case 2 /* replace */: + bone.x += (bone.data.x + x - bone.x) * alpha; + bone.y += (bone.data.y + y - bone.y) * alpha; + break; + case 3 /* add */: + bone.x += x * alpha; + bone.y += y * alpha; + } + } + }; + var TranslateXTimeline = class extends CurveTimeline1 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.x + "|" + boneIndex); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + bone.x = bone.data.x; + return; + case 1 /* first */: + bone.x += (bone.data.x - bone.x) * alpha; + } + return; + } + let x = this.getCurveValue(time); + switch (blend) { + case 0 /* setup */: + bone.x = bone.data.x + x * alpha; + break; + case 1 /* first */: + case 2 /* replace */: + bone.x += (bone.data.x + x - bone.x) * alpha; + break; + case 3 /* add */: + bone.x += x * alpha; + } + } + }; + var TranslateYTimeline = class extends CurveTimeline1 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.y + "|" + boneIndex); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + bone.y = bone.data.y; + return; + case 1 /* first */: + bone.y += (bone.data.y - bone.y) * alpha; + } + return; + } + let y = this.getCurveValue(time); + switch (blend) { + case 0 /* setup */: + bone.y = bone.data.y + y * alpha; + break; + case 1 /* first */: + case 2 /* replace */: + bone.y += (bone.data.y + y - bone.y) * alpha; + break; + case 3 /* add */: + bone.y += y * alpha; + } + } + }; + var ScaleTimeline = class extends CurveTimeline2 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super( + frameCount, + bezierCount, + Property.scaleX + "|" + boneIndex, + Property.scaleY + "|" + boneIndex + ); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + bone.scaleX = bone.data.scaleX; + bone.scaleY = bone.data.scaleY; + return; + case 1 /* first */: + bone.scaleX += (bone.data.scaleX - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY - bone.scaleY) * alpha; + } + return; + } + let x, y; + let i = Timeline.search( + frames, + time, + 3 + /*ENTRIES*/ + ); + let curveType = this.curves[ + i / 3 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: + let before = frames[i]; + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + let t = (time - before) / (frames[ + i + 3 + /*ENTRIES*/ + ] - before); + x += (frames[ + i + 3 + 1 + /*VALUE1*/ + ] - x) * t; + y += (frames[ + i + 3 + 2 + /*VALUE2*/ + ] - y) * t; + break; + case 1: + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + break; + default: + x = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + y = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + } + x *= bone.data.scaleX; + y *= bone.data.scaleY; + if (alpha == 1) { + if (blend == 3 /* add */) { + bone.scaleX += x - bone.data.scaleX; + bone.scaleY += y - bone.data.scaleY; + } else { + bone.scaleX = x; + bone.scaleY = y; + } + } else { + let bx = 0, by = 0; + if (direction == 1 /* mixOut */) { + switch (blend) { + case 0 /* 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 1 /* first */: + case 2 /* 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 3 /* add */: + bone.scaleX += (x - bone.data.scaleX) * alpha; + bone.scaleY += (y - bone.data.scaleY) * alpha; + } + } else { + switch (blend) { + case 0 /* 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 1 /* first */: + case 2 /* 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 3 /* add */: + bone.scaleX += (x - bone.data.scaleX) * alpha; + bone.scaleY += (y - bone.data.scaleY) * alpha; + } + } + } + } + }; + var ScaleXTimeline = class extends CurveTimeline1 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.scaleX + "|" + boneIndex); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + bone.scaleX = bone.data.scaleX; + return; + case 1 /* first */: + bone.scaleX += (bone.data.scaleX - bone.scaleX) * alpha; + } + return; + } + let x = this.getCurveValue(time) * bone.data.scaleX; + if (alpha == 1) { + if (blend == 3 /* add */) + bone.scaleX += x - bone.data.scaleX; + else + bone.scaleX = x; + } else { + let bx = 0; + if (direction == 1 /* mixOut */) { + switch (blend) { + case 0 /* setup */: + bx = bone.data.scaleX; + bone.scaleX = bx + (Math.abs(x) * MathUtils.signum(bx) - bx) * alpha; + break; + case 1 /* first */: + case 2 /* replace */: + bx = bone.scaleX; + bone.scaleX = bx + (Math.abs(x) * MathUtils.signum(bx) - bx) * alpha; + break; + case 3 /* add */: + bone.scaleX += (x - bone.data.scaleX) * alpha; + } + } else { + switch (blend) { + case 0 /* setup */: + bx = Math.abs(bone.data.scaleX) * MathUtils.signum(x); + bone.scaleX = bx + (x - bx) * alpha; + break; + case 1 /* first */: + case 2 /* replace */: + bx = Math.abs(bone.scaleX) * MathUtils.signum(x); + bone.scaleX = bx + (x - bx) * alpha; + break; + case 3 /* add */: + bone.scaleX += (x - bone.data.scaleX) * alpha; + } + } + } + } + }; + var ScaleYTimeline = class extends CurveTimeline1 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.scaleY + "|" + boneIndex); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + bone.scaleY = bone.data.scaleY; + return; + case 1 /* first */: + bone.scaleY += (bone.data.scaleY - bone.scaleY) * alpha; + } + return; + } + let y = this.getCurveValue(time) * bone.data.scaleY; + if (alpha == 1) { + if (blend == 3 /* add */) + bone.scaleY += y - bone.data.scaleY; + else + bone.scaleY = y; + } else { + let by = 0; + if (direction == 1 /* mixOut */) { + switch (blend) { + case 0 /* setup */: + by = bone.data.scaleY; + bone.scaleY = by + (Math.abs(y) * MathUtils.signum(by) - by) * alpha; + break; + case 1 /* first */: + case 2 /* replace */: + by = bone.scaleY; + bone.scaleY = by + (Math.abs(y) * MathUtils.signum(by) - by) * alpha; + break; + case 3 /* add */: + bone.scaleY += (y - bone.data.scaleY) * alpha; + } + } else { + switch (blend) { + case 0 /* setup */: + by = Math.abs(bone.data.scaleY) * MathUtils.signum(y); + bone.scaleY = by + (y - by) * alpha; + break; + case 1 /* first */: + case 2 /* replace */: + by = Math.abs(bone.scaleY) * MathUtils.signum(y); + bone.scaleY = by + (y - by) * alpha; + break; + case 3 /* add */: + bone.scaleY += (y - bone.data.scaleY) * alpha; + } + } + } + } + }; + var ShearTimeline = class extends CurveTimeline2 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super( + frameCount, + bezierCount, + Property.shearX + "|" + boneIndex, + Property.shearY + "|" + boneIndex + ); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + bone.shearX = bone.data.shearX; + bone.shearY = bone.data.shearY; + return; + case 1 /* first */: + bone.shearX += (bone.data.shearX - bone.shearX) * alpha; + bone.shearY += (bone.data.shearY - bone.shearY) * alpha; + } + return; + } + let x = 0, y = 0; + let i = Timeline.search( + frames, + time, + 3 + /*ENTRIES*/ + ); + let curveType = this.curves[ + i / 3 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: + let before = frames[i]; + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + let t = (time - before) / (frames[ + i + 3 + /*ENTRIES*/ + ] - before); + x += (frames[ + i + 3 + 1 + /*VALUE1*/ + ] - x) * t; + y += (frames[ + i + 3 + 2 + /*VALUE2*/ + ] - y) * t; + break; + case 1: + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + break; + default: + x = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + y = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + } + switch (blend) { + case 0 /* setup */: + bone.shearX = bone.data.shearX + x * alpha; + bone.shearY = bone.data.shearY + y * alpha; + break; + case 1 /* first */: + case 2 /* replace */: + bone.shearX += (bone.data.shearX + x - bone.shearX) * alpha; + bone.shearY += (bone.data.shearY + y - bone.shearY) * alpha; + break; + case 3 /* add */: + bone.shearX += x * alpha; + bone.shearY += y * alpha; + } + } + }; + var ShearXTimeline = class extends CurveTimeline1 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.shearX + "|" + boneIndex); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + bone.shearX = bone.data.shearX; + return; + case 1 /* first */: + bone.shearX += (bone.data.shearX - bone.shearX) * alpha; + } + return; + } + let x = this.getCurveValue(time); + switch (blend) { + case 0 /* setup */: + bone.shearX = bone.data.shearX + x * alpha; + break; + case 1 /* first */: + case 2 /* replace */: + bone.shearX += (bone.data.shearX + x - bone.shearX) * alpha; + break; + case 3 /* add */: + bone.shearX += x * alpha; + } + } + }; + var ShearYTimeline = class extends CurveTimeline1 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.shearY + "|" + boneIndex); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + bone.shearY = bone.data.shearY; + return; + case 1 /* first */: + bone.shearY += (bone.data.shearY - bone.shearY) * alpha; + } + return; + } + let y = this.getCurveValue(time); + switch (blend) { + case 0 /* setup */: + bone.shearY = bone.data.shearY + y * alpha; + break; + case 1 /* first */: + case 2 /* replace */: + bone.shearY += (bone.data.shearY + y - bone.shearY) * alpha; + break; + case 3 /* add */: + bone.shearY += y * alpha; + } + } + }; + var RGBATimeline = class extends CurveTimeline { + slotIndex = 0; + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, [ + Property.rgb + "|" + slotIndex, + Property.alpha + "|" + slotIndex + ]); + this.slotIndex = slotIndex; + } + getFrameEntries() { + return 5; + } + /** Sets the time in seconds, red, green, blue, and alpha for the specified key frame. */ + setFrame(frame, time, r, g, b, a) { + frame *= 5; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*R*/ + ] = r; + this.frames[ + frame + 2 + /*G*/ + ] = g; + this.frames[ + frame + 3 + /*B*/ + ] = b; + this.frames[ + frame + 4 + /*A*/ + ] = a; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + let frames = this.frames; + let color = slot.color; + if (time < frames[0]) { + let setup = slot.data.color; + switch (blend) { + case 0 /* setup */: + color.setFromColor(setup); + return; + case 1 /* first */: + color.add( + (setup.r - color.r) * alpha, + (setup.g - color.g) * alpha, + (setup.b - color.b) * alpha, + (setup.a - color.a) * alpha + ); + } + return; + } + let r = 0, g = 0, b = 0, a = 0; + let i = Timeline.search( + frames, + time, + 5 + /*ENTRIES*/ + ); + let curveType = this.curves[ + i / 5 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: + let before = frames[i]; + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + a = frames[ + i + 4 + /*A*/ + ]; + let t = (time - before) / (frames[ + i + 5 + /*ENTRIES*/ + ] - before); + r += (frames[ + i + 5 + 1 + /*R*/ + ] - r) * t; + g += (frames[ + i + 5 + 2 + /*G*/ + ] - g) * t; + b += (frames[ + i + 5 + 3 + /*B*/ + ] - b) * t; + a += (frames[ + i + 5 + 4 + /*A*/ + ] - a) * t; + break; + case 1: + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + a = frames[ + i + 4 + /*A*/ + ]; + break; + default: + r = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + g = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + b = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + a = this.getBezierValue( + time, + i, + 4, + curveType + 18 * 3 - 2 + /*BEZIER*/ + ); + } + if (alpha == 1) + color.set(r, g, b, a); + else { + if (blend == 0 /* setup */) + color.setFromColor(slot.data.color); + color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha); + } + } + }; + var RGBTimeline = class extends CurveTimeline { + slotIndex = 0; + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, [ + Property.rgb + "|" + slotIndex + ]); + this.slotIndex = slotIndex; + } + getFrameEntries() { + return 4; + } + /** Sets the time in seconds, red, green, blue, and alpha for the specified key frame. */ + setFrame(frame, time, r, g, b) { + frame <<= 2; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*R*/ + ] = r; + this.frames[ + frame + 2 + /*G*/ + ] = g; + this.frames[ + frame + 3 + /*B*/ + ] = b; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + let frames = this.frames; + let color = slot.color; + if (time < frames[0]) { + let setup = slot.data.color; + switch (blend) { + case 0 /* setup */: + color.r = setup.r; + color.g = setup.g; + color.b = setup.b; + return; + case 1 /* first */: + color.r += (setup.r - color.r) * alpha; + color.g += (setup.g - color.g) * alpha; + color.b += (setup.b - color.b) * alpha; + } + return; + } + let r = 0, g = 0, b = 0; + let i = Timeline.search( + frames, + time, + 4 + /*ENTRIES*/ + ); + let curveType = this.curves[i >> 2]; + switch (curveType) { + case 0: + let before = frames[i]; + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + let t = (time - before) / (frames[ + i + 4 + /*ENTRIES*/ + ] - before); + r += (frames[ + i + 4 + 1 + /*R*/ + ] - r) * t; + g += (frames[ + i + 4 + 2 + /*G*/ + ] - g) * t; + b += (frames[ + i + 4 + 3 + /*B*/ + ] - b) * t; + break; + case 1: + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + break; + default: + r = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + g = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + b = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + } + if (alpha == 1) { + color.r = r; + color.g = g; + color.b = b; + } else { + if (blend == 0 /* setup */) { + let setup = slot.data.color; + color.r = setup.r; + color.g = setup.g; + color.b = setup.b; + } + color.r += (r - color.r) * alpha; + color.g += (g - color.g) * alpha; + color.b += (b - color.b) * alpha; + } + } + }; + var AlphaTimeline = class extends CurveTimeline1 { + slotIndex = 0; + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, Property.alpha + "|" + slotIndex); + this.slotIndex = slotIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + let color = slot.color; + if (time < this.frames[0]) { + let setup = slot.data.color; + switch (blend) { + case 0 /* setup */: + color.a = setup.a; + return; + case 1 /* first */: + color.a += (setup.a - color.a) * alpha; + } + return; + } + let a = this.getCurveValue(time); + if (alpha == 1) + color.a = a; + else { + if (blend == 0 /* setup */) + color.a = slot.data.color.a; + color.a += (a - color.a) * alpha; + } + } + }; + var RGBA2Timeline = class extends CurveTimeline { + slotIndex = 0; + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, [ + Property.rgb + "|" + slotIndex, + Property.alpha + "|" + slotIndex, + Property.rgb2 + "|" + slotIndex + ]); + this.slotIndex = slotIndex; + } + getFrameEntries() { + return 8; + } + /** Sets the time in seconds, light, and dark colors for the specified key frame. */ + setFrame(frame, time, r, g, b, a, r2, g2, b2) { + frame <<= 3; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*R*/ + ] = r; + this.frames[ + frame + 2 + /*G*/ + ] = g; + this.frames[ + frame + 3 + /*B*/ + ] = b; + this.frames[ + frame + 4 + /*A*/ + ] = a; + this.frames[ + frame + 5 + /*R2*/ + ] = r2; + this.frames[ + frame + 6 + /*G2*/ + ] = g2; + this.frames[ + frame + 7 + /*B2*/ + ] = b2; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + let frames = this.frames; + let light = slot.color, dark = slot.darkColor; + if (time < frames[0]) { + let setupLight = slot.data.color, setupDark = slot.data.darkColor; + switch (blend) { + case 0 /* setup */: + light.setFromColor(setupLight); + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; + return; + case 1 /* first */: + light.add( + (setupLight.r - light.r) * alpha, + (setupLight.g - light.g) * alpha, + (setupLight.b - light.b) * alpha, + (setupLight.a - light.a) * alpha + ); + dark.r += (setupDark.r - dark.r) * alpha; + dark.g += (setupDark.g - dark.g) * alpha; + dark.b += (setupDark.b - dark.b) * alpha; + } + return; + } + let r = 0, g = 0, b = 0, a = 0, r2 = 0, g2 = 0, b2 = 0; + let i = Timeline.search( + frames, + time, + 8 + /*ENTRIES*/ + ); + let curveType = this.curves[i >> 3]; + switch (curveType) { + case 0: + let before = frames[i]; + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + a = frames[ + i + 4 + /*A*/ + ]; + r2 = frames[ + i + 5 + /*R2*/ + ]; + g2 = frames[ + i + 6 + /*G2*/ + ]; + b2 = frames[ + i + 7 + /*B2*/ + ]; + let t = (time - before) / (frames[ + i + 8 + /*ENTRIES*/ + ] - before); + r += (frames[ + i + 8 + 1 + /*R*/ + ] - r) * t; + g += (frames[ + i + 8 + 2 + /*G*/ + ] - g) * t; + b += (frames[ + i + 8 + 3 + /*B*/ + ] - b) * t; + a += (frames[ + i + 8 + 4 + /*A*/ + ] - a) * t; + r2 += (frames[ + i + 8 + 5 + /*R2*/ + ] - r2) * t; + g2 += (frames[ + i + 8 + 6 + /*G2*/ + ] - g2) * t; + b2 += (frames[ + i + 8 + 7 + /*B2*/ + ] - b2) * t; + break; + case 1: + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + a = frames[ + i + 4 + /*A*/ + ]; + r2 = frames[ + i + 5 + /*R2*/ + ]; + g2 = frames[ + i + 6 + /*G2*/ + ]; + b2 = frames[ + i + 7 + /*B2*/ + ]; + break; + default: + r = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + g = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + b = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + a = this.getBezierValue( + time, + i, + 4, + curveType + 18 * 3 - 2 + /*BEZIER*/ + ); + r2 = this.getBezierValue( + time, + i, + 5, + curveType + 18 * 4 - 2 + /*BEZIER*/ + ); + g2 = this.getBezierValue( + time, + i, + 6, + curveType + 18 * 5 - 2 + /*BEZIER*/ + ); + b2 = this.getBezierValue( + time, + i, + 7, + curveType + 18 * 6 - 2 + /*BEZIER*/ + ); + } + if (alpha == 1) { + light.set(r, g, b, a); + dark.r = r2; + dark.g = g2; + dark.b = b2; + } else { + if (blend == 0 /* setup */) { + light.setFromColor(slot.data.color); + let setupDark = slot.data.darkColor; + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; + } + light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha); + dark.r += (r2 - dark.r) * alpha; + dark.g += (g2 - dark.g) * alpha; + dark.b += (b2 - dark.b) * alpha; + } + } + }; + var RGB2Timeline = class extends CurveTimeline { + slotIndex = 0; + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, [ + Property.rgb + "|" + slotIndex, + Property.rgb2 + "|" + slotIndex + ]); + this.slotIndex = slotIndex; + } + getFrameEntries() { + return 7; + } + /** Sets the time in seconds, light, and dark colors for the specified key frame. */ + setFrame(frame, time, r, g, b, r2, g2, b2) { + frame *= 7; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*R*/ + ] = r; + this.frames[ + frame + 2 + /*G*/ + ] = g; + this.frames[ + frame + 3 + /*B*/ + ] = b; + this.frames[ + frame + 4 + /*R2*/ + ] = r2; + this.frames[ + frame + 5 + /*G2*/ + ] = g2; + this.frames[ + frame + 6 + /*B2*/ + ] = b2; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + let frames = this.frames; + let light = slot.color, dark = slot.darkColor; + if (time < frames[0]) { + let setupLight = slot.data.color, setupDark = slot.data.darkColor; + switch (blend) { + case 0 /* setup */: + light.r = setupLight.r; + light.g = setupLight.g; + light.b = setupLight.b; + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; + return; + case 1 /* first */: + light.r += (setupLight.r - light.r) * alpha; + light.g += (setupLight.g - light.g) * alpha; + light.b += (setupLight.b - light.b) * alpha; + dark.r += (setupDark.r - dark.r) * alpha; + dark.g += (setupDark.g - dark.g) * alpha; + dark.b += (setupDark.b - dark.b) * alpha; + } + return; + } + let r = 0, g = 0, b = 0, a = 0, r2 = 0, g2 = 0, b2 = 0; + let i = Timeline.search( + frames, + time, + 7 + /*ENTRIES*/ + ); + let curveType = this.curves[ + i / 7 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: + let before = frames[i]; + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + r2 = frames[ + i + 4 + /*R2*/ + ]; + g2 = frames[ + i + 5 + /*G2*/ + ]; + b2 = frames[ + i + 6 + /*B2*/ + ]; + let t = (time - before) / (frames[ + i + 7 + /*ENTRIES*/ + ] - before); + r += (frames[ + i + 7 + 1 + /*R*/ + ] - r) * t; + g += (frames[ + i + 7 + 2 + /*G*/ + ] - g) * t; + b += (frames[ + i + 7 + 3 + /*B*/ + ] - b) * t; + r2 += (frames[ + i + 7 + 4 + /*R2*/ + ] - r2) * t; + g2 += (frames[ + i + 7 + 5 + /*G2*/ + ] - g2) * t; + b2 += (frames[ + i + 7 + 6 + /*B2*/ + ] - b2) * t; + break; + case 1: + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + r2 = frames[ + i + 4 + /*R2*/ + ]; + g2 = frames[ + i + 5 + /*G2*/ + ]; + b2 = frames[ + i + 6 + /*B2*/ + ]; + break; + default: + r = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + g = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + b = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + r2 = this.getBezierValue( + time, + i, + 4, + curveType + 18 * 3 - 2 + /*BEZIER*/ + ); + g2 = this.getBezierValue( + time, + i, + 5, + curveType + 18 * 4 - 2 + /*BEZIER*/ + ); + b2 = this.getBezierValue( + time, + i, + 6, + curveType + 18 * 5 - 2 + /*BEZIER*/ + ); + } + if (alpha == 1) { + light.r = r; + light.g = g; + light.b = b; + dark.r = r2; + dark.g = g2; + dark.b = b2; + } else { + if (blend == 0 /* setup */) { + let setupLight = slot.data.color, setupDark = slot.data.darkColor; + light.r = setupLight.r; + light.g = setupLight.g; + light.b = setupLight.b; + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; + } + light.r += (r - light.r) * alpha; + light.g += (g - light.g) * alpha; + light.b += (b - light.b) * alpha; + dark.r += (r2 - dark.r) * alpha; + dark.g += (g2 - dark.g) * alpha; + dark.b += (b2 - dark.b) * alpha; + } + } + }; + var AttachmentTimeline = class extends Timeline { + slotIndex = 0; + /** The attachment name for each key frame. May contain null values to clear the attachment. */ + attachmentNames; + constructor(frameCount, slotIndex) { + super(frameCount, [ + Property.attachment + "|" + slotIndex + ]); + this.slotIndex = slotIndex; + this.attachmentNames = new Array(frameCount); + } + getFrameCount() { + return this.frames.length; + } + /** Sets the time in seconds and the attachment name for the specified key frame. */ + setFrame(frame, time, attachmentName) { + this.frames[frame] = time; + this.attachmentNames[frame] = attachmentName; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + if (direction == 1 /* mixOut */) { + if (blend == 0 /* setup */) + this.setAttachment(skeleton, slot, slot.data.attachmentName); + return; + } + if (time < this.frames[0]) { + if (blend == 0 /* setup */ || blend == 1 /* first */) + this.setAttachment(skeleton, slot, slot.data.attachmentName); + return; + } + this.setAttachment(skeleton, slot, this.attachmentNames[Timeline.search1(this.frames, time)]); + } + setAttachment(skeleton, slot, attachmentName) { + slot.setAttachment(!attachmentName ? null : skeleton.getAttachment(this.slotIndex, attachmentName)); + } + }; + var DeformTimeline = class extends CurveTimeline { + slotIndex = 0; + /** The attachment that will be deformed. */ + attachment; + /** The vertices for each key frame. */ + vertices; + constructor(frameCount, bezierCount, slotIndex, attachment) { + super(frameCount, bezierCount, [ + Property.deform + "|" + slotIndex + "|" + attachment.id + ]); + this.slotIndex = slotIndex; + this.attachment = attachment; + this.vertices = new Array(frameCount); + } + getFrameCount() { + return this.frames.length; + } + /** Sets the time in seconds and the vertices for the specified key frame. + * @param vertices Vertex positions for an unweighted VertexAttachment, or deform offsets if it has weights. */ + setFrame(frame, time, vertices) { + this.frames[frame] = time; + this.vertices[frame] = vertices; + } + /** @param value1 Ignored (0 is used for a deform timeline). + * @param value2 Ignored (1 is used for a deform timeline). */ + setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2) { + let curves = this.curves; + let i = this.getFrameCount() + bezier * 18; + if (value == 0) + curves[frame] = 2 + i; + let tmpx = (time1 - cx1 * 2 + cx2) * 0.03, tmpy = cy2 * 0.03 - cy1 * 0.06; + let dddx = ((cx1 - cx2) * 3 - time1 + time2) * 6e-3, dddy = (cy1 - cy2 + 0.33333333) * 0.018; + let ddx = tmpx * 2 + dddx, ddy = tmpy * 2 + dddy; + let dx = (cx1 - time1) * 0.3 + tmpx + dddx * 0.16666667, dy = cy1 * 0.3 + tmpy + dddy * 0.16666667; + let x = time1 + dx, y = dy; + for (let n = i + 18; i < n; i += 2) { + curves[i] = x; + curves[i + 1] = y; + dx += ddx; + dy += ddy; + ddx += dddx; + ddy += dddy; + x += dx; + y += dy; + } + } + getCurvePercent(time, frame) { + let curves = this.curves; + let i = curves[frame]; + switch (i) { + case 0: + let x2 = this.frames[frame]; + return (time - x2) / (this.frames[frame + this.getFrameEntries()] - x2); + case 1: + return 0; + } + i -= 2; + if (curves[i] > time) { + let x2 = this.frames[frame]; + return curves[i + 1] * (time - x2) / (curves[i] - x2); + } + let n = i + 18; + for (i += 2; i < n; i += 2) { + if (curves[i] >= time) { + let x2 = curves[i - 2], y2 = curves[i - 1]; + return y2 + (time - x2) / (curves[i] - x2) * (curves[i + 1] - y2); + } + } + let x = curves[n - 2], y = curves[n - 1]; + return y + (1 - y) * (time - x) / (this.frames[frame + this.getFrameEntries()] - x); + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + let slotAttachment = slot.getAttachment(); + if (!slotAttachment) + return; + if (!(slotAttachment instanceof VertexAttachment) || slotAttachment.timelineAttachment != this.attachment) + return; + let deform = slot.deform; + if (deform.length == 0) + blend = 0 /* setup */; + let vertices = this.vertices; + let vertexCount = vertices[0].length; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + deform.length = 0; + return; + case 1 /* first */: + if (alpha == 1) { + deform.length = 0; + return; + } + deform.length = vertexCount; + let vertexAttachment = slotAttachment; + if (!vertexAttachment.bones) { + let setupVertices = vertexAttachment.vertices; + for (var i = 0; i < vertexCount; i++) + deform[i] += (setupVertices[i] - deform[i]) * alpha; + } else { + alpha = 1 - alpha; + for (var i = 0; i < vertexCount; i++) + deform[i] *= alpha; + } + } + return; + } + deform.length = vertexCount; + if (time >= frames[frames.length - 1]) { + let lastVertices = vertices[frames.length - 1]; + if (alpha == 1) { + if (blend == 3 /* add */) { + let vertexAttachment = slotAttachment; + if (!vertexAttachment.bones) { + let setupVertices = vertexAttachment.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] += lastVertices[i2] - setupVertices[i2]; + } else { + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] += lastVertices[i2]; + } + } else + Utils.arrayCopy(lastVertices, 0, deform, 0, vertexCount); + } else { + switch (blend) { + case 0 /* setup */: { + let vertexAttachment2 = slotAttachment; + if (!vertexAttachment2.bones) { + let setupVertices = vertexAttachment2.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) { + let setup = setupVertices[i2]; + deform[i2] = setup + (lastVertices[i2] - setup) * alpha; + } + } else { + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] = lastVertices[i2] * alpha; + } + break; + } + case 1 /* first */: + case 2 /* replace */: + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] += (lastVertices[i2] - deform[i2]) * alpha; + break; + case 3 /* add */: + let vertexAttachment = slotAttachment; + if (!vertexAttachment.bones) { + let setupVertices = vertexAttachment.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] += (lastVertices[i2] - setupVertices[i2]) * alpha; + } else { + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] += lastVertices[i2] * alpha; + } + } + } + return; + } + let frame = Timeline.search1(frames, time); + let percent = this.getCurvePercent(time, frame); + let prevVertices = vertices[frame]; + let nextVertices = vertices[frame + 1]; + if (alpha == 1) { + if (blend == 3 /* add */) { + let vertexAttachment = slotAttachment; + if (!vertexAttachment.bones) { + let setupVertices = vertexAttachment.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] += prev + (nextVertices[i2] - prev) * percent - setupVertices[i2]; + } + } else { + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] += prev + (nextVertices[i2] - prev) * percent; + } + } + } else { + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] = prev + (nextVertices[i2] - prev) * percent; + } + } + } else { + switch (blend) { + case 0 /* setup */: { + let vertexAttachment2 = slotAttachment; + if (!vertexAttachment2.bones) { + let setupVertices = vertexAttachment2.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2], setup = setupVertices[i2]; + deform[i2] = setup + (prev + (nextVertices[i2] - prev) * percent - setup) * alpha; + } + } else { + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] = (prev + (nextVertices[i2] - prev) * percent) * alpha; + } + } + break; + } + case 1 /* first */: + case 2 /* replace */: + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] += (prev + (nextVertices[i2] - prev) * percent - deform[i2]) * alpha; + } + break; + case 3 /* add */: + let vertexAttachment = slotAttachment; + if (!vertexAttachment.bones) { + let setupVertices = vertexAttachment.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] += (prev + (nextVertices[i2] - prev) * percent - setupVertices[i2]) * alpha; + } + } else { + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] += (prev + (nextVertices[i2] - prev) * percent) * alpha; + } + } + } + } + } + }; + var _EventTimeline = class extends Timeline { + /** The event for each key frame. */ + events; + constructor(frameCount) { + super(frameCount, _EventTimeline.propertyIds); + this.events = new Array(frameCount); + } + getFrameCount() { + return this.frames.length; + } + /** Sets the time in seconds and the event for the specified key frame. */ + setFrame(frame, event) { + this.frames[frame] = event.time; + this.events[frame] = event; + } + /** Fires events for frames > `lastTime` and <= `time`. */ + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + if (!firedEvents) + return; + let frames = this.frames; + let frameCount = this.frames.length; + if (lastTime > time) { + this.apply(skeleton, lastTime, Number.MAX_VALUE, firedEvents, alpha, blend, direction); + lastTime = -1; + } else if (lastTime >= frames[frameCount - 1]) + return; + if (time < frames[0]) + return; + let i = 0; + if (lastTime < frames[0]) + i = 0; + else { + i = Timeline.search1(frames, lastTime) + 1; + let frameTime = frames[i]; + while (i > 0) { + if (frames[i - 1] != frameTime) + break; + i--; + } + } + for (; i < frameCount && time >= frames[i]; i++) + firedEvents.push(this.events[i]); + } + }; + var EventTimeline = _EventTimeline; + __publicField(EventTimeline, "propertyIds", ["" + Property.event]); + var _DrawOrderTimeline = class extends Timeline { + /** The draw order for each key frame. See {@link #setFrame(int, float, int[])}. */ + drawOrders; + constructor(frameCount) { + super(frameCount, _DrawOrderTimeline.propertyIds); + this.drawOrders = new Array(frameCount); + } + getFrameCount() { + return this.frames.length; + } + /** Sets the time in seconds and the draw order for the specified key frame. + * @param drawOrder For each slot in {@link Skeleton#slots}, the index of the new draw order. May be null to use setup pose + * draw order. */ + setFrame(frame, time, drawOrder) { + this.frames[frame] = time; + this.drawOrders[frame] = drawOrder; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + if (direction == 1 /* mixOut */) { + if (blend == 0 /* setup */) + Utils.arrayCopy(skeleton.slots, 0, skeleton.drawOrder, 0, skeleton.slots.length); + return; + } + if (time < this.frames[0]) { + if (blend == 0 /* setup */ || blend == 1 /* first */) + Utils.arrayCopy(skeleton.slots, 0, skeleton.drawOrder, 0, skeleton.slots.length); + return; + } + let idx = Timeline.search1(this.frames, time); + let drawOrderToSetupIndex = this.drawOrders[idx]; + if (!drawOrderToSetupIndex) + Utils.arrayCopy(skeleton.slots, 0, skeleton.drawOrder, 0, skeleton.slots.length); + else { + let drawOrder = skeleton.drawOrder; + let slots = skeleton.slots; + for (let i = 0, n = drawOrderToSetupIndex.length; i < n; i++) + drawOrder[i] = slots[drawOrderToSetupIndex[i]]; + } + } + }; + var DrawOrderTimeline = _DrawOrderTimeline; + __publicField(DrawOrderTimeline, "propertyIds", ["" + Property.drawOrder]); + var IkConstraintTimeline = class extends CurveTimeline { + /** The index of the IK constraint slot in {@link Skeleton#ikConstraints} that will be changed. */ + ikConstraintIndex = 0; + constructor(frameCount, bezierCount, ikConstraintIndex) { + super(frameCount, bezierCount, [ + Property.ikConstraint + "|" + ikConstraintIndex + ]); + this.ikConstraintIndex = ikConstraintIndex; + } + getFrameEntries() { + return 6; + } + /** Sets the time in seconds, mix, softness, bend direction, compress, and stretch for the specified key frame. */ + setFrame(frame, time, mix, softness, bendDirection, compress, stretch) { + frame *= 6; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*MIX*/ + ] = mix; + this.frames[ + frame + 2 + /*SOFTNESS*/ + ] = softness; + this.frames[ + frame + 3 + /*BEND_DIRECTION*/ + ] = bendDirection; + this.frames[ + frame + 4 + /*COMPRESS*/ + ] = compress ? 1 : 0; + this.frames[ + frame + 5 + /*STRETCH*/ + ] = stretch ? 1 : 0; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint = skeleton.ikConstraints[this.ikConstraintIndex]; + if (!constraint.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + constraint.mix = constraint.data.mix; + constraint.softness = constraint.data.softness; + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + return; + case 1 /* first */: + constraint.mix += (constraint.data.mix - constraint.mix) * alpha; + constraint.softness += (constraint.data.softness - constraint.softness) * alpha; + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } + return; + } + let mix = 0, softness = 0; + let i = Timeline.search( + frames, + time, + 6 + /*ENTRIES*/ + ); + let curveType = this.curves[ + i / 6 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: + let before = frames[i]; + mix = frames[ + i + 1 + /*MIX*/ + ]; + softness = frames[ + i + 2 + /*SOFTNESS*/ + ]; + let t = (time - before) / (frames[ + i + 6 + /*ENTRIES*/ + ] - before); + mix += (frames[ + i + 6 + 1 + /*MIX*/ + ] - mix) * t; + softness += (frames[ + i + 6 + 2 + /*SOFTNESS*/ + ] - softness) * t; + break; + case 1: + mix = frames[ + i + 1 + /*MIX*/ + ]; + softness = frames[ + i + 2 + /*SOFTNESS*/ + ]; + break; + default: + mix = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + softness = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + } + if (blend == 0 /* setup */) { + constraint.mix = constraint.data.mix + (mix - constraint.data.mix) * alpha; + constraint.softness = constraint.data.softness + (softness - constraint.data.softness) * alpha; + if (direction == 1 /* mixOut */) { + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } else { + constraint.bendDirection = frames[ + i + 3 + /*BEND_DIRECTION*/ + ]; + constraint.compress = frames[ + i + 4 + /*COMPRESS*/ + ] != 0; + constraint.stretch = frames[ + i + 5 + /*STRETCH*/ + ] != 0; + } + } else { + constraint.mix += (mix - constraint.mix) * alpha; + constraint.softness += (softness - constraint.softness) * alpha; + if (direction == 0 /* mixIn */) { + constraint.bendDirection = frames[ + i + 3 + /*BEND_DIRECTION*/ + ]; + constraint.compress = frames[ + i + 4 + /*COMPRESS*/ + ] != 0; + constraint.stretch = frames[ + i + 5 + /*STRETCH*/ + ] != 0; + } + } + } + }; + var TransformConstraintTimeline = class extends CurveTimeline { + /** The index of the transform constraint slot in {@link Skeleton#transformConstraints} that will be changed. */ + transformConstraintIndex = 0; + constructor(frameCount, bezierCount, transformConstraintIndex) { + super(frameCount, bezierCount, [ + Property.transformConstraint + "|" + transformConstraintIndex + ]); + this.transformConstraintIndex = transformConstraintIndex; + } + getFrameEntries() { + return 7; + } + /** The time in seconds, rotate mix, translate mix, scale mix, and shear mix for the specified key frame. */ + setFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY) { + let frames = this.frames; + frame *= 7; + frames[frame] = time; + frames[ + frame + 1 + /*ROTATE*/ + ] = mixRotate; + frames[ + frame + 2 + /*X*/ + ] = mixX; + frames[ + frame + 3 + /*Y*/ + ] = mixY; + frames[ + frame + 4 + /*SCALEX*/ + ] = mixScaleX; + frames[ + frame + 5 + /*SCALEY*/ + ] = mixScaleY; + frames[ + frame + 6 + /*SHEARY*/ + ] = mixShearY; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint = skeleton.transformConstraints[this.transformConstraintIndex]; + if (!constraint.active) + return; + let frames = this.frames; + if (time < frames[0]) { + let data = constraint.data; + switch (blend) { + case 0 /* setup */: + constraint.mixRotate = data.mixRotate; + constraint.mixX = data.mixX; + constraint.mixY = data.mixY; + constraint.mixScaleX = data.mixScaleX; + constraint.mixScaleY = data.mixScaleY; + constraint.mixShearY = data.mixShearY; + return; + case 1 /* first */: + constraint.mixRotate += (data.mixRotate - constraint.mixRotate) * alpha; + constraint.mixX += (data.mixX - constraint.mixX) * alpha; + constraint.mixY += (data.mixY - constraint.mixY) * alpha; + constraint.mixScaleX += (data.mixScaleX - constraint.mixScaleX) * alpha; + constraint.mixScaleY += (data.mixScaleY - constraint.mixScaleY) * alpha; + constraint.mixShearY += (data.mixShearY - constraint.mixShearY) * alpha; + } + return; + } + let rotate, x, y, scaleX, scaleY, shearY; + let i = Timeline.search( + frames, + time, + 7 + /*ENTRIES*/ + ); + let curveType = this.curves[ + i / 7 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: + let before = frames[i]; + rotate = frames[ + i + 1 + /*ROTATE*/ + ]; + x = frames[ + i + 2 + /*X*/ + ]; + y = frames[ + i + 3 + /*Y*/ + ]; + scaleX = frames[ + i + 4 + /*SCALEX*/ + ]; + scaleY = frames[ + i + 5 + /*SCALEY*/ + ]; + shearY = frames[ + i + 6 + /*SHEARY*/ + ]; + let t = (time - before) / (frames[ + i + 7 + /*ENTRIES*/ + ] - before); + rotate += (frames[ + i + 7 + 1 + /*ROTATE*/ + ] - rotate) * t; + x += (frames[ + i + 7 + 2 + /*X*/ + ] - x) * t; + y += (frames[ + i + 7 + 3 + /*Y*/ + ] - y) * t; + scaleX += (frames[ + i + 7 + 4 + /*SCALEX*/ + ] - scaleX) * t; + scaleY += (frames[ + i + 7 + 5 + /*SCALEY*/ + ] - scaleY) * t; + shearY += (frames[ + i + 7 + 6 + /*SHEARY*/ + ] - shearY) * t; + break; + case 1: + rotate = frames[ + i + 1 + /*ROTATE*/ + ]; + x = frames[ + i + 2 + /*X*/ + ]; + y = frames[ + i + 3 + /*Y*/ + ]; + scaleX = frames[ + i + 4 + /*SCALEX*/ + ]; + scaleY = frames[ + i + 5 + /*SCALEY*/ + ]; + shearY = frames[ + i + 6 + /*SHEARY*/ + ]; + break; + default: + rotate = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + x = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + y = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + scaleX = this.getBezierValue( + time, + i, + 4, + curveType + 18 * 3 - 2 + /*BEZIER*/ + ); + scaleY = this.getBezierValue( + time, + i, + 5, + curveType + 18 * 4 - 2 + /*BEZIER*/ + ); + shearY = this.getBezierValue( + time, + i, + 6, + curveType + 18 * 5 - 2 + /*BEZIER*/ + ); + } + if (blend == 0 /* setup */) { + let data = constraint.data; + constraint.mixRotate = data.mixRotate + (rotate - data.mixRotate) * alpha; + constraint.mixX = data.mixX + (x - data.mixX) * alpha; + constraint.mixY = data.mixY + (y - data.mixY) * alpha; + constraint.mixScaleX = data.mixScaleX + (scaleX - data.mixScaleX) * alpha; + constraint.mixScaleY = data.mixScaleY + (scaleY - data.mixScaleY) * alpha; + constraint.mixShearY = data.mixShearY + (shearY - data.mixShearY) * alpha; + } else { + constraint.mixRotate += (rotate - constraint.mixRotate) * alpha; + constraint.mixX += (x - constraint.mixX) * alpha; + constraint.mixY += (y - constraint.mixY) * alpha; + constraint.mixScaleX += (scaleX - constraint.mixScaleX) * alpha; + constraint.mixScaleY += (scaleY - constraint.mixScaleY) * alpha; + constraint.mixShearY += (shearY - constraint.mixShearY) * alpha; + } + } + }; + var PathConstraintPositionTimeline = class extends CurveTimeline1 { + /** The index of the path constraint slot in {@link Skeleton#pathConstraints} that will be changed. */ + pathConstraintIndex = 0; + constructor(frameCount, bezierCount, pathConstraintIndex) { + super(frameCount, bezierCount, Property.pathConstraintPosition + "|" + pathConstraintIndex); + this.pathConstraintIndex = pathConstraintIndex; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint = skeleton.pathConstraints[this.pathConstraintIndex]; + if (!constraint.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + constraint.position = constraint.data.position; + return; + case 1 /* first */: + constraint.position += (constraint.data.position - constraint.position) * alpha; + } + return; + } + let position = this.getCurveValue(time); + if (blend == 0 /* setup */) + constraint.position = constraint.data.position + (position - constraint.data.position) * alpha; + else + constraint.position += (position - constraint.position) * alpha; + } + }; + var PathConstraintSpacingTimeline = class extends CurveTimeline1 { + /** The index of the path constraint slot in {@link Skeleton#getPathConstraints()} that will be changed. */ + pathConstraintIndex = 0; + constructor(frameCount, bezierCount, pathConstraintIndex) { + super(frameCount, bezierCount, Property.pathConstraintSpacing + "|" + pathConstraintIndex); + this.pathConstraintIndex = pathConstraintIndex; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint = skeleton.pathConstraints[this.pathConstraintIndex]; + if (!constraint.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + constraint.spacing = constraint.data.spacing; + return; + case 1 /* first */: + constraint.spacing += (constraint.data.spacing - constraint.spacing) * alpha; + } + return; + } + let spacing = this.getCurveValue(time); + if (blend == 0 /* setup */) + constraint.spacing = constraint.data.spacing + (spacing - constraint.data.spacing) * alpha; + else + constraint.spacing += (spacing - constraint.spacing) * alpha; + } + }; + var PathConstraintMixTimeline = class extends CurveTimeline { + /** The index of the path constraint slot in {@link Skeleton#getPathConstraints()} that will be changed. */ + pathConstraintIndex = 0; + constructor(frameCount, bezierCount, pathConstraintIndex) { + super(frameCount, bezierCount, [ + Property.pathConstraintMix + "|" + pathConstraintIndex + ]); + this.pathConstraintIndex = pathConstraintIndex; + } + getFrameEntries() { + return 4; + } + setFrame(frame, time, mixRotate, mixX, mixY) { + let frames = this.frames; + frame <<= 2; + frames[frame] = time; + frames[ + frame + 1 + /*ROTATE*/ + ] = mixRotate; + frames[ + frame + 2 + /*X*/ + ] = mixX; + frames[ + frame + 3 + /*Y*/ + ] = mixY; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint = skeleton.pathConstraints[this.pathConstraintIndex]; + if (!constraint.active) + return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + constraint.mixRotate = constraint.data.mixRotate; + constraint.mixX = constraint.data.mixX; + constraint.mixY = constraint.data.mixY; + return; + case 1 /* first */: + constraint.mixRotate += (constraint.data.mixRotate - constraint.mixRotate) * alpha; + constraint.mixX += (constraint.data.mixX - constraint.mixX) * alpha; + constraint.mixY += (constraint.data.mixY - constraint.mixY) * alpha; + } + return; + } + let rotate, x, y; + let i = Timeline.search( + frames, + time, + 4 + /*ENTRIES*/ + ); + let curveType = this.curves[i >> 2]; + switch (curveType) { + case 0: + let before = frames[i]; + rotate = frames[ + i + 1 + /*ROTATE*/ + ]; + x = frames[ + i + 2 + /*X*/ + ]; + y = frames[ + i + 3 + /*Y*/ + ]; + let t = (time - before) / (frames[ + i + 4 + /*ENTRIES*/ + ] - before); + rotate += (frames[ + i + 4 + 1 + /*ROTATE*/ + ] - rotate) * t; + x += (frames[ + i + 4 + 2 + /*X*/ + ] - x) * t; + y += (frames[ + i + 4 + 3 + /*Y*/ + ] - y) * t; + break; + case 1: + rotate = frames[ + i + 1 + /*ROTATE*/ + ]; + x = frames[ + i + 2 + /*X*/ + ]; + y = frames[ + i + 3 + /*Y*/ + ]; + break; + default: + rotate = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + x = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + y = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + } + if (blend == 0 /* setup */) { + let data = constraint.data; + constraint.mixRotate = data.mixRotate + (rotate - data.mixRotate) * alpha; + constraint.mixX = data.mixX + (x - data.mixX) * alpha; + constraint.mixY = data.mixY + (y - data.mixY) * alpha; + } else { + constraint.mixRotate += (rotate - constraint.mixRotate) * alpha; + constraint.mixX += (x - constraint.mixX) * alpha; + constraint.mixY += (y - constraint.mixY) * alpha; + } + } + }; + var _SequenceTimeline = class extends Timeline { + slotIndex; + attachment; + constructor(frameCount, slotIndex, attachment) { + super(frameCount, [ + Property.sequence + "|" + slotIndex + "|" + attachment.sequence.id + ]); + this.slotIndex = slotIndex; + this.attachment = attachment; + } + getFrameEntries() { + return _SequenceTimeline.ENTRIES; + } + getSlotIndex() { + return this.slotIndex; + } + getAttachment() { + return this.attachment; + } + /** Sets the time, mode, index, and frame time for the specified frame. + * @param frame Between 0 and frameCount, inclusive. + * @param time Seconds between frames. */ + setFrame(frame, time, mode, index, delay) { + let frames = this.frames; + frame *= _SequenceTimeline.ENTRIES; + frames[frame] = time; + frames[frame + _SequenceTimeline.MODE] = mode | index << 4; + frames[frame + _SequenceTimeline.DELAY] = delay; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) + return; + let slotAttachment = slot.attachment; + let attachment = this.attachment; + if (slotAttachment != attachment) { + if (!(slotAttachment instanceof VertexAttachment) || slotAttachment.timelineAttachment != attachment) + return; + } + let frames = this.frames; + if (time < frames[0]) { + if (blend == 0 /* setup */ || blend == 1 /* first */) + slot.sequenceIndex = -1; + return; + } + let i = Timeline.search(frames, time, _SequenceTimeline.ENTRIES); + let before = frames[i]; + let modeAndIndex = frames[i + _SequenceTimeline.MODE]; + let delay = frames[i + _SequenceTimeline.DELAY]; + if (!this.attachment.sequence) + return; + let index = modeAndIndex >> 4, count = this.attachment.sequence.regions.length; + let mode = SequenceModeValues[modeAndIndex & 15]; + if (mode != 0 /* hold */) { + index += (time - before) / delay + 1e-5 | 0; + switch (mode) { + case 1 /* once */: + index = Math.min(count - 1, index); + break; + case 2 /* loop */: + index %= count; + break; + case 3 /* pingpong */: { + let n = (count << 1) - 2; + index = n == 0 ? 0 : index % n; + if (index >= count) + index = n - index; + break; + } + case 4 /* onceReverse */: + index = Math.max(count - 1 - index, 0); + break; + case 5 /* loopReverse */: + index = count - 1 - index % count; + break; + case 6 /* pingpongReverse */: { + let n = (count << 1) - 2; + index = n == 0 ? 0 : (index + count - 1) % n; + if (index >= count) + index = n - index; + } + } + } + slot.sequenceIndex = index; + } + }; + var SequenceTimeline = _SequenceTimeline; + __publicField(SequenceTimeline, "ENTRIES", 3); + __publicField(SequenceTimeline, "MODE", 1); + __publicField(SequenceTimeline, "DELAY", 2); + + // spine-core/src/AnimationState.ts + var _AnimationState = class { + static emptyAnimation() { + return _AnimationState._emptyAnimation; + } + /** The AnimationStateData to look up mix durations. */ + data; + /** The list of tracks that currently have animations, which may contain null entries. */ + tracks = new Array(); + /** Multiplier for the delta time when the animation state is updated, causing time for all animations and mixes to play slower + * or faster. Defaults to 1. + * + * See TrackEntry {@link TrackEntry#timeScale} for affecting a single animation. */ + timeScale = 1; + unkeyedState = 0; + events = new Array(); + listeners = new Array(); + queue = new EventQueue(this); + propertyIDs = new StringSet(); + animationsChanged = false; + trackEntryPool = new Pool(() => new TrackEntry()); + constructor(data) { + this.data = data; + } + /** Increments each track entry {@link TrackEntry#trackTime()}, setting queued animations as current if needed. */ + update(delta) { + delta *= this.timeScale; + let tracks = this.tracks; + for (let i = 0, n = tracks.length; i < n; i++) { + let current = tracks[i]; + if (!current) + continue; + current.animationLast = current.nextAnimationLast; + current.trackLast = current.nextTrackLast; + let currentDelta = delta * current.timeScale; + if (current.delay > 0) { + current.delay -= currentDelta; + if (current.delay > 0) + continue; + currentDelta = -current.delay; + current.delay = 0; + } + let next = current.next; + if (next) { + let 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) { + next.mixTime += delta; + next = next.mixingFrom; + } + continue; + } + } else if (current.trackLast >= current.trackEnd && !current.mixingFrom) { + tracks[i] = null; + this.queue.end(current); + this.clearNext(current); + continue; + } + if (current.mixingFrom && this.updateMixingFrom(current, delta)) { + let from = current.mixingFrom; + current.mixingFrom = null; + if (from) + from.mixingTo = null; + while (from) { + this.queue.end(from); + from = from.mixingFrom; + } + } + current.trackTime += currentDelta; + } + this.queue.drain(); + } + /** Returns true when all mixing from entries are complete. */ + updateMixingFrom(to, delta) { + let from = to.mixingFrom; + if (!from) + return true; + let finished = this.updateMixingFrom(from, delta); + from.animationLast = from.nextAnimationLast; + from.trackLast = from.nextTrackLast; + if (to.mixTime > 0 && to.mixTime >= to.mixDuration) { + if (from.totalAlpha == 0 || to.mixDuration == 0) { + to.mixingFrom = from.mixingFrom; + if (from.mixingFrom) + from.mixingFrom.mixingTo = to; + to.interruptAlpha = from.interruptAlpha; + this.queue.end(from); + } + return finished; + } + from.trackTime += delta * from.timeScale; + to.mixTime += delta; + return false; + } + /** Poses the skeleton using the track entry animations. There are no side effects other than invoking listeners, so the + * animation state can be applied to multiple skeletons to pose them identically. + * @returns True if any animations were applied. */ + apply(skeleton) { + if (!skeleton) + throw new Error("skeleton cannot be null."); + if (this.animationsChanged) + this._animationsChanged(); + let events = this.events; + let tracks = this.tracks; + let applied = false; + for (let i2 = 0, n2 = tracks.length; i2 < n2; i2++) { + let current = tracks[i2]; + if (!current || current.delay > 0) + continue; + applied = true; + let blend = i2 == 0 ? 1 /* first */ : current.mixBlend; + let mix = current.alpha; + if (current.mixingFrom) + mix *= this.applyMixingFrom(current, skeleton, blend); + else if (current.trackTime >= current.trackEnd && !current.next) + mix = 0; + let animationLast = current.animationLast, animationTime = current.getAnimationTime(), applyTime = animationTime; + let applyEvents = events; + if (current.reverse) { + applyTime = current.animation.duration - applyTime; + applyEvents = null; + } + let timelines = current.animation.timelines; + let timelineCount = timelines.length; + if (i2 == 0 && mix == 1 || blend == 3 /* add */) { + for (let ii = 0; ii < timelineCount; ii++) { + Utils.webkit602BugfixHelper(mix, blend); + var timeline = timelines[ii]; + if (timeline instanceof AttachmentTimeline) + this.applyAttachmentTimeline(timeline, skeleton, applyTime, blend, true); + else + timeline.apply(skeleton, animationLast, applyTime, applyEvents, mix, blend, 0 /* mixIn */); + } + } else { + let timelineMode = current.timelineMode; + let shortestRotation = current.shortestRotation; + let firstFrame = !shortestRotation && current.timelinesRotation.length != timelineCount << 1; + if (firstFrame) + current.timelinesRotation.length = timelineCount << 1; + for (let ii = 0; ii < timelineCount; ii++) { + let timeline2 = timelines[ii]; + let timelineBlend = timelineMode[ii] == SUBSEQUENT ? blend : 0 /* setup */; + if (!shortestRotation && timeline2 instanceof RotateTimeline) { + this.applyRotateTimeline(timeline2, skeleton, applyTime, mix, timelineBlend, current.timelinesRotation, ii << 1, firstFrame); + } else if (timeline2 instanceof AttachmentTimeline) { + this.applyAttachmentTimeline(timeline2, skeleton, applyTime, blend, true); + } else { + Utils.webkit602BugfixHelper(mix, blend); + timeline2.apply(skeleton, animationLast, applyTime, applyEvents, mix, timelineBlend, 0 /* mixIn */); + } + } + } + this.queueEvents(current, animationTime); + events.length = 0; + current.nextAnimationLast = animationTime; + current.nextTrackLast = current.trackTime; + } + var setupState = this.unkeyedState + SETUP; + var slots = skeleton.slots; + for (var i = 0, n = skeleton.slots.length; i < n; i++) { + var slot = slots[i]; + if (slot.attachmentState == setupState) { + var attachmentName = slot.data.attachmentName; + slot.setAttachment(!attachmentName ? null : skeleton.getAttachment(slot.data.index, attachmentName)); + } + } + this.unkeyedState += 2; + this.queue.drain(); + return applied; + } + applyMixingFrom(to, skeleton, blend) { + let from = to.mixingFrom; + if (from.mixingFrom) + this.applyMixingFrom(from, skeleton, blend); + let mix = 0; + if (to.mixDuration == 0) { + mix = 1; + if (blend == 1 /* first */) + blend = 0 /* setup */; + } else { + mix = to.mixTime / to.mixDuration; + if (mix > 1) + mix = 1; + if (blend != 1 /* first */) + blend = from.mixBlend; + } + let attachments = mix < from.attachmentThreshold, drawOrder = mix < from.drawOrderThreshold; + let timelines = from.animation.timelines; + let timelineCount = timelines.length; + let alphaHold = from.alpha * to.interruptAlpha, alphaMix = alphaHold * (1 - mix); + let animationLast = from.animationLast, animationTime = from.getAnimationTime(), applyTime = animationTime; + let events = null; + if (from.reverse) + applyTime = from.animation.duration - applyTime; + else if (mix < from.eventThreshold) + events = this.events; + if (blend == 3 /* add */) { + for (let i = 0; i < timelineCount; i++) + timelines[i].apply(skeleton, animationLast, applyTime, events, alphaMix, blend, 1 /* mixOut */); + } else { + let timelineMode = from.timelineMode; + let timelineHoldMix = from.timelineHoldMix; + let shortestRotation = from.shortestRotation; + let firstFrame = !shortestRotation && from.timelinesRotation.length != timelineCount << 1; + if (firstFrame) + from.timelinesRotation.length = timelineCount << 1; + from.totalAlpha = 0; + for (let i = 0; i < timelineCount; i++) { + let timeline = timelines[i]; + let direction = 1 /* mixOut */; + let timelineBlend; + let alpha = 0; + switch (timelineMode[i]) { + case SUBSEQUENT: + if (!drawOrder && timeline instanceof DrawOrderTimeline) + continue; + timelineBlend = blend; + alpha = alphaMix; + break; + case FIRST: + timelineBlend = 0 /* setup */; + alpha = alphaMix; + break; + case HOLD_SUBSEQUENT: + timelineBlend = blend; + alpha = alphaHold; + break; + case HOLD_FIRST: + timelineBlend = 0 /* setup */; + alpha = alphaHold; + break; + default: + timelineBlend = 0 /* setup */; + let holdMix = timelineHoldMix[i]; + alpha = alphaHold * Math.max(0, 1 - holdMix.mixTime / holdMix.mixDuration); + break; + } + from.totalAlpha += alpha; + if (!shortestRotation && timeline instanceof RotateTimeline) + this.applyRotateTimeline(timeline, skeleton, applyTime, alpha, timelineBlend, from.timelinesRotation, i << 1, firstFrame); + else if (timeline instanceof AttachmentTimeline) + this.applyAttachmentTimeline(timeline, skeleton, applyTime, timelineBlend, attachments); + else { + Utils.webkit602BugfixHelper(alpha, blend); + if (drawOrder && timeline instanceof DrawOrderTimeline && timelineBlend == 0 /* setup */) + direction = 0 /* mixIn */; + timeline.apply(skeleton, animationLast, applyTime, 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; + } + applyAttachmentTimeline(timeline, skeleton, time, blend, attachments) { + var slot = skeleton.slots[timeline.slotIndex]; + if (!slot.bone.active) + return; + if (time < timeline.frames[0]) { + if (blend == 0 /* setup */ || blend == 1 /* first */) + this.setAttachment(skeleton, slot, slot.data.attachmentName, attachments); + } else + this.setAttachment(skeleton, slot, timeline.attachmentNames[Timeline.search1(timeline.frames, time)], attachments); + if (slot.attachmentState <= this.unkeyedState) + slot.attachmentState = this.unkeyedState + SETUP; + } + setAttachment(skeleton, slot, attachmentName, attachments) { + slot.setAttachment(!attachmentName ? null : skeleton.getAttachment(slot.data.index, attachmentName)); + if (attachments) + slot.attachmentState = this.unkeyedState + CURRENT; + } + applyRotateTimeline(timeline, skeleton, time, alpha, blend, timelinesRotation, i, firstFrame) { + if (firstFrame) + timelinesRotation[i] = 0; + if (alpha == 1) { + timeline.apply(skeleton, 0, time, null, 1, blend, 0 /* mixIn */); + return; + } + let bone = skeleton.bones[timeline.boneIndex]; + if (!bone.active) + return; + let frames = timeline.frames; + let r1 = 0, r2 = 0; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + bone.rotation = bone.data.rotation; + default: + return; + case 1 /* first */: + r1 = bone.rotation; + r2 = bone.data.rotation; + } + } else { + r1 = blend == 0 /* setup */ ? bone.data.rotation : bone.rotation; + r2 = bone.data.rotation + timeline.getCurveValue(time); + } + let total = 0, diff = r2 - r1; + diff -= (16384 - (16384.499999999996 - diff / 360 | 0)) * 360; + if (diff == 0) { + total = timelinesRotation[i]; + } else { + let lastTotal = 0, lastDiff = 0; + if (firstFrame) { + lastTotal = 0; + lastDiff = diff; + } else { + lastTotal = timelinesRotation[i]; + lastDiff = timelinesRotation[i + 1]; + } + let current = diff > 0, dir = lastTotal >= 0; + if (MathUtils.signum(lastDiff) != MathUtils.signum(diff) && Math.abs(lastDiff) <= 90) { + if (Math.abs(lastTotal) > 180) + lastTotal += 360 * MathUtils.signum(lastTotal); + dir = current; + } + total = diff + lastTotal - lastTotal % 360; + if (dir != current) + total += 360 * MathUtils.signum(lastTotal); + timelinesRotation[i] = total; + } + timelinesRotation[i + 1] = diff; + bone.rotation = r1 + total * alpha; + } + queueEvents(entry, animationTime) { + let animationStart = entry.animationStart, animationEnd = entry.animationEnd; + let duration = animationEnd - animationStart; + let trackLastWrapped = entry.trackLast % duration; + let events = this.events; + let i = 0, n = events.length; + for (; i < n; i++) { + let event = events[i]; + if (event.time < trackLastWrapped) + break; + if (event.time > animationEnd) + continue; + this.queue.event(entry, event); + } + let 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); + for (; i < n; i++) { + let event = events[i]; + if (event.time < animationStart) + continue; + this.queue.event(entry, event); + } + } + /** Removes all animations from all tracks, leaving skeletons in their current pose. + * + * It may be desired to use {@link AnimationState#setEmptyAnimation()} to mix the skeletons back to the setup pose, + * rather than leaving them in their current pose. */ + clearTracks() { + let oldDrainDisabled = this.queue.drainDisabled; + this.queue.drainDisabled = true; + for (let i = 0, n = this.tracks.length; i < n; i++) + this.clearTrack(i); + this.tracks.length = 0; + this.queue.drainDisabled = oldDrainDisabled; + this.queue.drain(); + } + /** Removes all animations from the track, leaving skeletons in their current pose. + * + * It may be desired to use {@link AnimationState#setEmptyAnimation()} to mix the skeletons back to the setup pose, + * rather than leaving them in their current pose. */ + clearTrack(trackIndex) { + if (trackIndex >= this.tracks.length) + return; + let current = this.tracks[trackIndex]; + if (!current) + return; + this.queue.end(current); + this.clearNext(current); + let entry = current; + while (true) { + let from = entry.mixingFrom; + if (!from) + break; + this.queue.end(from); + entry.mixingFrom = null; + entry.mixingTo = null; + entry = from; + } + this.tracks[current.trackIndex] = null; + this.queue.drain(); + } + setCurrent(index, current, interrupt) { + let from = this.expandToIndex(index); + this.tracks[index] = current; + current.previous = null; + if (from) { + if (interrupt) + this.queue.interrupt(from); + current.mixingFrom = from; + from.mixingTo = current; + current.mixTime = 0; + if (from.mixingFrom && from.mixDuration > 0) + current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration); + from.timelinesRotation.length = 0; + } + this.queue.start(current); + } + /** Sets an animation by name. + * + * See {@link #setAnimationWith()}. */ + setAnimation(trackIndex, animationName, loop = false) { + let animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) + throw new Error("Animation not found: " + animationName); + return this.setAnimationWith(trackIndex, animation, loop); + } + /** Sets the current animation for a track, discarding any queued animations. If the formerly current track entry was never + * applied to a skeleton, it is replaced (not mixed from). + * @param loop If true, the animation will repeat. If false it will not, instead its last frame is applied if played beyond its + * duration. In either case {@link TrackEntry#trackEnd} determines when the track is cleared. + * @returns A track entry to allow further customization of animation playback. References to the track entry must not be kept + * after the {@link AnimationStateListener#dispose()} event occurs. */ + setAnimationWith(trackIndex, animation, loop = false) { + if (!animation) + throw new Error("animation cannot be null."); + let interrupt = true; + let current = this.expandToIndex(trackIndex); + if (current) { + if (current.nextTrackLast == -1) { + this.tracks[trackIndex] = current.mixingFrom; + this.queue.interrupt(current); + this.queue.end(current); + this.clearNext(current); + current = current.mixingFrom; + interrupt = false; + } else + this.clearNext(current); + } + let entry = this.trackEntry(trackIndex, animation, loop, current); + this.setCurrent(trackIndex, entry, interrupt); + this.queue.drain(); + return entry; + } + /** Queues an animation by name. + * + * See {@link #addAnimationWith()}. */ + addAnimation(trackIndex, animationName, loop = false, delay = 0) { + let animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) + throw new Error("Animation not found: " + animationName); + return this.addAnimationWith(trackIndex, animation, loop, delay); + } + /** Adds an animation to be played after the current or last queued animation for a track. If the track is empty, it is + * equivalent to calling {@link #setAnimationWith()}. + * @param delay If > 0, sets {@link TrackEntry#delay}. If <= 0, the delay set is the duration of the previous track entry + * minus any mix duration (from the {@link AnimationStateData}) plus the specified `delay` (ie the mix + * ends at (`delay` = 0) or before (`delay` < 0) the previous track entry duration). If the + * previous entry is looping, its next loop completion is used instead of its duration. + * @returns A track entry to allow further customization of animation playback. References to the track entry must not be kept + * after the {@link AnimationStateListener#dispose()} event occurs. */ + addAnimationWith(trackIndex, animation, loop = false, delay = 0) { + if (!animation) + throw new Error("animation cannot be null."); + let last = this.expandToIndex(trackIndex); + if (last) { + while (last.next) + last = last.next; + } + let entry = this.trackEntry(trackIndex, animation, loop, last); + if (!last) { + this.setCurrent(trackIndex, entry, true); + this.queue.drain(); + } else { + last.next = entry; + entry.previous = last; + if (delay <= 0) + delay += last.getTrackComplete() - entry.mixDuration; + } + entry.delay = delay; + return entry; + } + /** Sets an empty animation for a track, discarding any queued animations, and sets the track entry's + * {@link TrackEntry#mixduration}. An empty animation has no timelines and serves as a placeholder for mixing in or out. + * + * Mixing out is done by setting an empty animation with a mix duration using either {@link #setEmptyAnimation()}, + * {@link #setEmptyAnimations()}, or {@link #addEmptyAnimation()}. Mixing to an empty animation causes + * the previous animation to be applied less and less over the mix duration. Properties keyed in the previous animation + * transition to the value from lower tracks or to the setup pose value if no lower tracks key the property. A mix duration of + * 0 still mixes out over one frame. + * + * Mixing in is done by first setting an empty animation, then adding an animation using + * {@link #addAnimation()} and on the returned track entry, set the + * {@link TrackEntry#setMixDuration()}. Mixing from an empty animation causes the new animation to be applied more and + * more over the mix duration. Properties keyed in the new animation transition from the value from lower tracks or from the + * setup pose value if no lower tracks key the property to the value keyed in the new animation. */ + setEmptyAnimation(trackIndex, mixDuration = 0) { + let entry = this.setAnimationWith(trackIndex, _AnimationState.emptyAnimation(), false); + entry.mixDuration = mixDuration; + entry.trackEnd = mixDuration; + return entry; + } + /** Adds an empty animation to be played after the current or last queued animation for a track, and sets the track entry's + * {@link TrackEntry#mixDuration}. If the track is empty, it is equivalent to calling + * {@link #setEmptyAnimation()}. + * + * See {@link #setEmptyAnimation()}. + * @param delay If > 0, sets {@link TrackEntry#delay}. If <= 0, the delay set is the duration of the previous track entry + * minus any mix duration plus the specified `delay` (ie the mix ends at (`delay` = 0) or + * before (`delay` < 0) the previous track entry duration). If the previous entry is looping, its next + * loop completion is used instead of its duration. + * @return A track entry to allow further customization of animation playback. References to the track entry must not be kept + * after the {@link AnimationStateListener#dispose()} event occurs. */ + addEmptyAnimation(trackIndex, mixDuration = 0, delay = 0) { + let entry = this.addAnimationWith(trackIndex, _AnimationState.emptyAnimation(), false, delay); + if (delay <= 0) + entry.delay += entry.mixDuration - mixDuration; + entry.mixDuration = mixDuration; + entry.trackEnd = mixDuration; + return entry; + } + /** Sets an empty animation for every track, discarding any queued animations, and mixes to it over the specified mix + * duration. */ + setEmptyAnimations(mixDuration = 0) { + let oldDrainDisabled = this.queue.drainDisabled; + this.queue.drainDisabled = true; + for (let i = 0, n = this.tracks.length; i < n; i++) { + let current = this.tracks[i]; + if (current) + this.setEmptyAnimation(current.trackIndex, mixDuration); + } + this.queue.drainDisabled = oldDrainDisabled; + this.queue.drain(); + } + expandToIndex(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 last May be null. */ + trackEntry(trackIndex, animation, loop, last) { + let entry = this.trackEntryPool.obtain(); + entry.reset(); + entry.trackIndex = trackIndex; + entry.animation = animation; + entry.loop = loop; + entry.holdPrevious = false; + entry.reverse = false; + entry.shortestRotation = 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.mixTime = 0; + entry.mixDuration = !last ? 0 : this.data.getMix(last.animation, animation); + entry.interruptAlpha = 1; + entry.totalAlpha = 0; + entry.mixBlend = 2 /* replace */; + return entry; + } + /** Removes the {@link TrackEntry#getNext() next entry} and all entries after it for the specified entry. */ + clearNext(entry) { + let next = entry.next; + while (next) { + this.queue.dispose(next); + next = next.next; + } + entry.next = null; + } + _animationsChanged() { + this.animationsChanged = false; + this.propertyIDs.clear(); + let tracks = this.tracks; + for (let i = 0, n = tracks.length; i < n; i++) { + let entry = tracks[i]; + if (!entry) + continue; + while (entry.mixingFrom) + entry = entry.mixingFrom; + do { + if (!entry.mixingTo || entry.mixBlend != 3 /* add */) + this.computeHold(entry); + entry = entry.mixingTo; + } while (entry); + } + } + computeHold(entry) { + let to = entry.mixingTo; + let timelines = entry.animation.timelines; + let timelinesCount = entry.animation.timelines.length; + let timelineMode = entry.timelineMode; + timelineMode.length = timelinesCount; + let timelineHoldMix = entry.timelineHoldMix; + timelineHoldMix.length = 0; + let propertyIDs = this.propertyIDs; + if (to && to.holdPrevious) { + for (let i = 0; i < timelinesCount; i++) + timelineMode[i] = propertyIDs.addAll(timelines[i].getPropertyIds()) ? HOLD_FIRST : HOLD_SUBSEQUENT; + return; + } + outer: + for (let i = 0; i < timelinesCount; i++) { + let timeline = timelines[i]; + let ids = timeline.getPropertyIds(); + if (!propertyIDs.addAll(ids)) + timelineMode[i] = SUBSEQUENT; + else if (!to || timeline instanceof AttachmentTimeline || timeline instanceof DrawOrderTimeline || timeline instanceof EventTimeline || !to.animation.hasTimeline(ids)) { + timelineMode[i] = FIRST; + } else { + for (let next = to.mixingTo; next; next = next.mixingTo) { + if (next.animation.hasTimeline(ids)) + continue; + if (entry.mixDuration > 0) { + timelineMode[i] = HOLD_MIX; + timelineHoldMix[i] = next; + continue outer; + } + break; + } + timelineMode[i] = HOLD_FIRST; + } + } + } + /** Returns the track entry for the animation currently playing on the track, or null if no animation is currently playing. */ + getCurrent(trackIndex) { + if (trackIndex >= this.tracks.length) + return null; + return this.tracks[trackIndex]; + } + /** Adds a listener to receive events for all track entries. */ + addListener(listener) { + if (!listener) + throw new Error("listener cannot be null."); + this.listeners.push(listener); + } + /** Removes the listener added with {@link #addListener()}. */ + removeListener(listener) { + let index = this.listeners.indexOf(listener); + if (index >= 0) + this.listeners.splice(index, 1); + } + /** Removes all listeners added with {@link #addListener()}. */ + clearListeners() { + this.listeners.length = 0; + } + /** Discards all listener notifications that have not yet been delivered. This can be useful to call from an + * {@link AnimationStateListener} when it is known that further notifications that may have been already queued for delivery + * are not wanted because new animations are being set. */ + clearListenerNotifications() { + this.queue.clear(); + } + }; + var AnimationState = _AnimationState; + __publicField(AnimationState, "_emptyAnimation", new Animation("", [], 0)); + var TrackEntry = class { + /** The animation to apply for this track entry. */ + animation = null; + previous = null; + /** The animation queued to start after this animation, or null. `next` makes up a linked list. */ + next = null; + /** The track entry for the previous animation when mixing from the previous animation to this animation, or null if no + * mixing is currently occuring. When mixing from multiple animations, `mixingFrom` makes up a linked list. */ + mixingFrom = null; + /** The track entry for the next animation when mixing from this animation to the next animation, or null if no mixing is + * currently occuring. When mixing to multiple animations, `mixingTo` makes up a linked list. */ + mixingTo = null; + /** The listener for events generated by this track entry, or null. + * + * A track entry returned from {@link AnimationState#setAnimation()} is already the current animation + * for the track, so the track entry listener {@link AnimationStateListener#start()} will not be called. */ + listener = null; + /** The index of the track where this track entry is either current or queued. + * + * See {@link AnimationState#getCurrent()}. */ + trackIndex = 0; + /** If true, the animation will repeat. If false it will not, instead its last frame is applied if played beyond its + * duration. */ + loop = false; + /** If true, when mixing from the previous animation to this animation, the previous animation is applied as normal instead + * of being mixed out. + * + * When mixing between animations that key the same property, if a lower track also keys that property then the value will + * briefly dip toward the lower track value during the mix. This happens because the first animation mixes from 100% to 0% + * while the second animation mixes from 0% to 100%. Setting `holdPrevious` to true applies the first animation + * at 100% during the mix so the lower track value is overwritten. Such dipping does not occur on the lowest track which + * keys the property, only when a higher track also keys the property. + * + * Snapping will occur if `holdPrevious` is true and this animation does not key all the same properties as the + * previous animation. */ + holdPrevious = false; + reverse = false; + shortestRotation = false; + /** When the mix percentage ({@link #mixTime} / {@link #mixDuration}) is less than the + * `eventThreshold`, event timelines are applied while this animation is being mixed out. Defaults to 0, so event + * timelines are not applied while this animation is being mixed out. */ + eventThreshold = 0; + /** When the mix percentage ({@link #mixtime} / {@link #mixDuration}) is less than the + * `attachmentThreshold`, attachment timelines are applied while this animation is being mixed out. Defaults to + * 0, so attachment timelines are not applied while this animation is being mixed out. */ + attachmentThreshold = 0; + /** When the mix percentage ({@link #mixTime} / {@link #mixDuration}) is less than the + * `drawOrderThreshold`, draw order timelines are applied while this animation is being mixed out. Defaults to 0, + * so draw order timelines are not applied while this animation is being mixed out. */ + drawOrderThreshold = 0; + /** Seconds when this animation starts, both initially and after looping. Defaults to 0. + * + * When changing the `animationStart` time, it often makes sense to set {@link #animationLast} to the same + * value to prevent timeline keys before the start time from triggering. */ + animationStart = 0; + /** Seconds for the last frame of this animation. Non-looping animations won't play past this time. Looping animations will + * loop back to {@link #animationStart} at this time. Defaults to the animation {@link Animation#duration}. */ + animationEnd = 0; + /** The time in seconds this animation was last applied. Some timelines use this for one-time triggers. Eg, when this + * animation is applied, event timelines will fire all events between the `animationLast` time (exclusive) and + * `animationTime` (inclusive). Defaults to -1 to ensure triggers on frame 0 happen the first time this animation + * is applied. */ + animationLast = 0; + nextAnimationLast = 0; + /** Seconds to postpone playing the animation. When this track entry is the current track entry, `delay` + * postpones incrementing the {@link #trackTime}. When this track entry is queued, `delay` is the time from + * the start of the previous animation to when this track entry will become the current track entry (ie when the previous + * track entry {@link TrackEntry#trackTime} >= this track entry's `delay`). + * + * {@link #timeScale} affects the delay. */ + delay = 0; + /** Current time in seconds this track entry has been the current track entry. The track time determines + * {@link #animationTime}. The track time can be set to start the animation at a time other than 0, without affecting + * looping. */ + trackTime = 0; + trackLast = 0; + nextTrackLast = 0; + /** The track time in seconds when this animation will be removed from the track. Defaults to the highest possible float + * value, meaning the animation will be applied until a new animation is set or the track is cleared. If the track end time + * is reached, no other animations are queued for playback, and mixing from any previous animations is complete, then the + * properties keyed by the animation are set to the setup pose and the track is cleared. + * + * It may be desired to use {@link AnimationState#addEmptyAnimation()} rather than have the animation + * abruptly cease being applied. */ + trackEnd = 0; + /** Multiplier for the delta time when this track entry is updated, causing time for this animation to pass slower or + * faster. Defaults to 1. + * + * {@link #mixTime} is not affected by track entry time scale, so {@link #mixDuration} may need to be adjusted to + * match the animation speed. + * + * When using {@link AnimationState#addAnimation()} with a `delay` <= 0, note the + * {@link #delay} is set using the mix duration from the {@link AnimationStateData}, assuming time scale to be 1. If + * the time scale is not 1, the delay may need to be adjusted. + * + * See AnimationState {@link AnimationState#timeScale} for affecting all animations. */ + timeScale = 0; + /** Values < 1 mix this animation with the skeleton's current pose (usually the pose resulting from lower tracks). Defaults + * to 1, which overwrites the skeleton's current pose with this animation. + * + * Typically track 0 is used to completely pose the skeleton, then alpha is used on higher tracks. It doesn't make sense to + * use alpha on track 0 if the skeleton pose is from the last frame render. */ + alpha = 0; + /** Seconds from 0 to the {@link #getMixDuration()} when mixing from the previous animation to this animation. May be + * slightly more than `mixDuration` when the mix is complete. */ + mixTime = 0; + /** Seconds for mixing from the previous animation to this animation. Defaults to the value provided by AnimationStateData + * {@link AnimationStateData#getMix()} based on the animation before this animation (if any). + * + * A mix duration of 0 still mixes out over one frame to provide the track entry being mixed out a chance to revert the + * properties it was animating. + * + * The `mixDuration` can be set manually rather than use the value from + * {@link AnimationStateData#getMix()}. In that case, the `mixDuration` can be set for a new + * track entry only before {@link AnimationState#update(float)} is first called. + * + * When using {@link AnimationState#addAnimation()} with a `delay` <= 0, note the + * {@link #delay} is set using the mix duration from the {@link AnimationStateData}, not a mix duration set + * afterward. */ + mixDuration = 0; + interruptAlpha = 0; + totalAlpha = 0; + /** Controls how properties keyed in the animation are mixed with lower tracks. Defaults to {@link MixBlend#replace}, which + * replaces the values from the lower tracks with the animation values. {@link MixBlend#add} adds the animation values to + * the values from the lower tracks. + * + * The `mixBlend` can be set for a new track entry only before {@link AnimationState#apply()} is first + * called. */ + mixBlend = 2 /* replace */; + timelineMode = new Array(); + timelineHoldMix = new Array(); + timelinesRotation = new Array(); + reset() { + this.next = null; + this.previous = 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; + } + /** Uses {@link #trackTime} to compute the `animationTime`, which is between {@link #animationStart} + * and {@link #animationEnd}. When the `trackTime` is 0, the `animationTime` is equal to the + * `animationStart` time. */ + getAnimationTime() { + if (this.loop) { + let 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); + } + setAnimationLast(animationLast) { + this.animationLast = animationLast; + this.nextAnimationLast = animationLast; + } + /** Returns true if at least one loop has been completed. + * + * See {@link AnimationStateListener#complete()}. */ + isComplete() { + return this.trackTime >= this.animationEnd - this.animationStart; + } + /** Resets the rotation directions for mixing this entry's rotate timelines. This can be useful to avoid bones rotating the + * long way around when using {@link #alpha} and starting animations on other tracks. + * + * Mixing with {@link MixBlend#replace} involves finding a rotation between two others, which has two possible solutions: + * the short way or the long way around. The two rotations likely change over time, so which direction is the short or long + * way also changes. If the short way was always chosen, bones would flip to the other side when that direction became the + * long way. TrackEntry chooses the short way the first time it is applied and remembers that direction. */ + resetRotationDirections() { + this.timelinesRotation.length = 0; + } + getTrackComplete() { + let duration = this.animationEnd - this.animationStart; + if (duration != 0) { + if (this.loop) + return duration * (1 + (this.trackTime / duration | 0)); + if (this.trackTime < duration) + return duration; + } + return this.trackTime; + } + }; + var EventQueue = class { + objects = []; + drainDisabled = false; + animState; + constructor(animState) { + this.animState = animState; + } + start(entry) { + this.objects.push(EventType.start); + this.objects.push(entry); + this.animState.animationsChanged = true; + } + interrupt(entry) { + this.objects.push(EventType.interrupt); + this.objects.push(entry); + } + end(entry) { + this.objects.push(EventType.end); + this.objects.push(entry); + this.animState.animationsChanged = true; + } + dispose(entry) { + this.objects.push(EventType.dispose); + this.objects.push(entry); + } + complete(entry) { + this.objects.push(EventType.complete); + this.objects.push(entry); + } + event(entry, event) { + this.objects.push(EventType.event); + this.objects.push(entry); + this.objects.push(event); + } + drain() { + if (this.drainDisabled) + return; + this.drainDisabled = true; + let objects = this.objects; + let listeners = this.animState.listeners; + for (let i = 0; i < objects.length; i += 2) { + let type = objects[i]; + let entry = objects[i + 1]; + switch (type) { + case EventType.start: + if (entry.listener && entry.listener.start) + entry.listener.start(entry); + for (let ii = 0; ii < listeners.length; ii++) { + let listener = listeners[ii]; + if (listener.start) + listener.start(entry); + } + break; + case EventType.interrupt: + if (entry.listener && entry.listener.interrupt) + entry.listener.interrupt(entry); + for (let ii = 0; ii < listeners.length; ii++) { + let listener = listeners[ii]; + if (listener.interrupt) + listener.interrupt(entry); + } + break; + case EventType.end: + if (entry.listener && entry.listener.end) + entry.listener.end(entry); + for (let ii = 0; ii < listeners.length; ii++) { + let listener = listeners[ii]; + if (listener.end) + listener.end(entry); + } + case EventType.dispose: + if (entry.listener && entry.listener.dispose) + entry.listener.dispose(entry); + for (let ii = 0; ii < listeners.length; ii++) { + let listener = listeners[ii]; + if (listener.dispose) + listener.dispose(entry); + } + this.animState.trackEntryPool.free(entry); + break; + case EventType.complete: + if (entry.listener && entry.listener.complete) + entry.listener.complete(entry); + for (let ii = 0; ii < listeners.length; ii++) { + let listener = listeners[ii]; + if (listener.complete) + listener.complete(entry); + } + break; + case EventType.event: + let event = objects[i++ + 2]; + if (entry.listener && entry.listener.event) + entry.listener.event(entry, event); + for (let ii = 0; ii < listeners.length; ii++) { + let listener = listeners[ii]; + if (listener.event) + listener.event(entry, event); + } + break; + } + } + this.clear(); + this.drainDisabled = false; + } + clear() { + this.objects.length = 0; + } + }; + var EventType = /* @__PURE__ */ ((EventType2) => { + EventType2[EventType2["start"] = 0] = "start"; + EventType2[EventType2["interrupt"] = 1] = "interrupt"; + EventType2[EventType2["end"] = 2] = "end"; + EventType2[EventType2["dispose"] = 3] = "dispose"; + EventType2[EventType2["complete"] = 4] = "complete"; + EventType2[EventType2["event"] = 5] = "event"; + return EventType2; + })(EventType || {}); + var AnimationStateAdapter = class { + start(entry) { + } + interrupt(entry) { + } + end(entry) { + } + dispose(entry) { + } + complete(entry) { + } + event(entry, event) { + } + }; + var SUBSEQUENT = 0; + var FIRST = 1; + var HOLD_SUBSEQUENT = 2; + var HOLD_FIRST = 3; + var HOLD_MIX = 4; + var SETUP = 1; + var CURRENT = 2; + + // spine-core/src/AnimationStateData.ts + var AnimationStateData = class { + /** The SkeletonData to look up animations when they are specified by name. */ + skeletonData; + animationToMixTime = {}; + /** The mix duration to use when no mix duration has been defined between two animations. */ + defaultMix = 0; + constructor(skeletonData) { + if (!skeletonData) + throw new Error("skeletonData cannot be null."); + this.skeletonData = skeletonData; + } + /** Sets a mix duration by animation name. + * + * See {@link #setMixWith()}. */ + setMix(fromName, toName, duration) { + let from = this.skeletonData.findAnimation(fromName); + if (!from) + throw new Error("Animation not found: " + fromName); + let to = this.skeletonData.findAnimation(toName); + if (!to) + throw new Error("Animation not found: " + toName); + this.setMixWith(from, to, duration); + } + /** Sets the mix duration when changing from the specified animation to the other. + * + * See {@link TrackEntry#mixDuration}. */ + setMixWith(from, to, duration) { + if (!from) + throw new Error("from cannot be null."); + if (!to) + throw new Error("to cannot be null."); + let key = from.name + "." + to.name; + this.animationToMixTime[key] = duration; + } + /** Returns the mix duration to use when changing from the specified animation to the other, or the {@link #defaultMix} if + * no mix duration has been set. */ + getMix(from, to) { + let key = from.name + "." + to.name; + let value = this.animationToMixTime[key]; + return value === void 0 ? this.defaultMix : value; + } + }; + + // spine-core/src/attachments/BoundingBoxAttachment.ts + var BoundingBoxAttachment = class extends VertexAttachment { + color = new Color(1, 1, 1, 1); + constructor(name) { + super(name); + } + copy() { + let copy = new BoundingBoxAttachment(this.name); + this.copyTo(copy); + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/attachments/ClippingAttachment.ts + var ClippingAttachment = class extends VertexAttachment { + /** Clipping is performed between the clipping polygon's slot and the end slot. Returns null if clipping is done until the end of + * the skeleton's rendering. */ + endSlot = null; + // Nonessential. + /** The color of the clipping polygon as it was in Spine. Available only when nonessential data was exported. Clipping polygons + * are not usually rendered at runtime. */ + color = new Color(0.2275, 0.2275, 0.8078, 1); + // ce3a3aff + constructor(name) { + super(name); + } + copy() { + let copy = new ClippingAttachment(this.name); + this.copyTo(copy); + copy.endSlot = this.endSlot; + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/Texture.ts + var Texture = class { + _image; + constructor(image) { + this._image = image; + } + getImage() { + return this._image; + } + }; + var TextureFilter = /* @__PURE__ */ ((TextureFilter3) => { + TextureFilter3[TextureFilter3["Nearest"] = 9728] = "Nearest"; + TextureFilter3[TextureFilter3["Linear"] = 9729] = "Linear"; + TextureFilter3[TextureFilter3["MipMap"] = 9987] = "MipMap"; + TextureFilter3[TextureFilter3["MipMapNearestNearest"] = 9984] = "MipMapNearestNearest"; + TextureFilter3[TextureFilter3["MipMapLinearNearest"] = 9985] = "MipMapLinearNearest"; + TextureFilter3[TextureFilter3["MipMapNearestLinear"] = 9986] = "MipMapNearestLinear"; + TextureFilter3[TextureFilter3["MipMapLinearLinear"] = 9987] = "MipMapLinearLinear"; + return TextureFilter3; + })(TextureFilter || {}); + var TextureWrap = /* @__PURE__ */ ((TextureWrap3) => { + TextureWrap3[TextureWrap3["MirroredRepeat"] = 33648] = "MirroredRepeat"; + TextureWrap3[TextureWrap3["ClampToEdge"] = 33071] = "ClampToEdge"; + TextureWrap3[TextureWrap3["Repeat"] = 10497] = "Repeat"; + return TextureWrap3; + })(TextureWrap || {}); + var TextureRegion = class { + texture; + u = 0; + v = 0; + u2 = 0; + v2 = 0; + width = 0; + height = 0; + degrees = 0; + offsetX = 0; + offsetY = 0; + originalWidth = 0; + originalHeight = 0; + }; + var FakeTexture = class extends Texture { + setFilters(minFilter, magFilter) { + } + setWraps(uWrap, vWrap) { + } + dispose() { + } + }; + + // spine-core/src/TextureAtlas.ts + var TextureAtlas = class { + pages = new Array(); + regions = new Array(); + constructor(atlasText) { + let reader = new TextureAtlasReader(atlasText); + let entry = new Array(4); + let pageFields = {}; + pageFields["size"] = (page2) => { + page2.width = parseInt(entry[1]); + page2.height = parseInt(entry[2]); + }; + pageFields["format"] = () => { + }; + pageFields["filter"] = (page2) => { + page2.minFilter = Utils.enumValue(TextureFilter, entry[1]); + page2.magFilter = Utils.enumValue(TextureFilter, entry[2]); + }; + pageFields["repeat"] = (page2) => { + if (entry[1].indexOf("x") != -1) + page2.uWrap = 10497 /* Repeat */; + if (entry[1].indexOf("y") != -1) + page2.vWrap = 10497 /* Repeat */; + }; + pageFields["pma"] = (page2) => { + page2.pma = entry[1] == "true"; + }; + var regionFields = {}; + regionFields["xy"] = (region) => { + region.x = parseInt(entry[1]); + region.y = parseInt(entry[2]); + }; + regionFields["size"] = (region) => { + region.width = parseInt(entry[1]); + region.height = parseInt(entry[2]); + }; + regionFields["bounds"] = (region) => { + region.x = parseInt(entry[1]); + region.y = parseInt(entry[2]); + region.width = parseInt(entry[3]); + region.height = parseInt(entry[4]); + }; + regionFields["offset"] = (region) => { + region.offsetX = parseInt(entry[1]); + region.offsetY = parseInt(entry[2]); + }; + regionFields["orig"] = (region) => { + region.originalWidth = parseInt(entry[1]); + region.originalHeight = parseInt(entry[2]); + }; + regionFields["offsets"] = (region) => { + region.offsetX = parseInt(entry[1]); + region.offsetY = parseInt(entry[2]); + region.originalWidth = parseInt(entry[3]); + region.originalHeight = parseInt(entry[4]); + }; + regionFields["rotate"] = (region) => { + let value = entry[1]; + if (value == "true") + region.degrees = 90; + else if (value != "false") + region.degrees = parseInt(value); + }; + regionFields["index"] = (region) => { + region.index = parseInt(entry[1]); + }; + let line = reader.readLine(); + while (line && line.trim().length == 0) + line = reader.readLine(); + while (true) { + if (!line || line.trim().length == 0) + break; + if (reader.readEntry(entry, line) == 0) + break; + line = reader.readLine(); + } + let page = null; + let names = null; + let values = null; + while (true) { + if (line === null) + break; + if (line.trim().length == 0) { + page = null; + line = reader.readLine(); + } else if (!page) { + page = new TextureAtlasPage(line.trim()); + while (true) { + if (reader.readEntry(entry, line = reader.readLine()) == 0) + break; + let field = pageFields[entry[0]]; + if (field) + field(page); + } + this.pages.push(page); + } else { + let region = new TextureAtlasRegion(page, line); + while (true) { + let count = reader.readEntry(entry, line = reader.readLine()); + if (count == 0) + break; + let field = regionFields[entry[0]]; + if (field) + field(region); + else { + if (!names) + names = []; + if (!values) + values = []; + names.push(entry[0]); + let entryValues = []; + for (let i = 0; i < count; i++) + entryValues.push(parseInt(entry[i + 1])); + values.push(entryValues); + } + } + if (region.originalWidth == 0 && region.originalHeight == 0) { + region.originalWidth = region.width; + region.originalHeight = region.height; + } + if (names && names.length > 0 && values && values.length > 0) { + region.names = names; + region.values = values; + names = null; + values = null; + } + region.u = region.x / page.width; + region.v = region.y / page.height; + if (region.degrees == 90) { + region.u2 = (region.x + region.height) / page.width; + region.v2 = (region.y + region.width) / page.height; + } else { + region.u2 = (region.x + region.width) / page.width; + region.v2 = (region.y + region.height) / page.height; + } + this.regions.push(region); + } + } + } + findRegion(name) { + for (let i = 0; i < this.regions.length; i++) { + if (this.regions[i].name == name) { + return this.regions[i]; + } + } + return null; + } + setTextures(assetManager, pathPrefix = "") { + for (let page of this.pages) + page.setTexture(assetManager.get(pathPrefix + page.name)); + } + dispose() { + for (let i = 0; i < this.pages.length; i++) { + this.pages[i].texture?.dispose(); + } + } + }; + var TextureAtlasReader = class { + lines; + index = 0; + constructor(text) { + this.lines = text.split(/\r\n|\r|\n/); + } + readLine() { + if (this.index >= this.lines.length) + return null; + return this.lines[this.index++]; + } + readEntry(entry, line) { + if (!line) + return 0; + line = line.trim(); + if (line.length == 0) + return 0; + let colon = line.indexOf(":"); + if (colon == -1) + return 0; + entry[0] = line.substr(0, colon).trim(); + for (let i = 1, lastMatch = colon + 1; ; i++) { + let comma = line.indexOf(",", lastMatch); + if (comma == -1) { + entry[i] = line.substr(lastMatch).trim(); + return i; + } + entry[i] = line.substr(lastMatch, comma - lastMatch).trim(); + lastMatch = comma + 1; + if (i == 4) + return 4; + } + } + }; + var TextureAtlasPage = class { + name; + minFilter = 9728 /* Nearest */; + magFilter = 9728 /* Nearest */; + uWrap = 33071 /* ClampToEdge */; + vWrap = 33071 /* ClampToEdge */; + texture = null; + width = 0; + height = 0; + pma = false; + regions = new Array(); + constructor(name) { + this.name = name; + } + setTexture(texture) { + this.texture = texture; + texture.setFilters(this.minFilter, this.magFilter); + texture.setWraps(this.uWrap, this.vWrap); + for (let region of this.regions) + region.texture = texture; + } + }; + var TextureAtlasRegion = class extends TextureRegion { + page; + name; + x = 0; + y = 0; + offsetX = 0; + offsetY = 0; + originalWidth = 0; + originalHeight = 0; + index = 0; + degrees = 0; + names = null; + values = null; + constructor(page, name) { + super(); + this.page = page; + this.name = name; + page.regions.push(this); + } + }; + + // spine-core/src/attachments/MeshAttachment.ts + var MeshAttachment = class extends VertexAttachment { + region = null; + /** The name of the texture region for this attachment. */ + path; + /** The UV pair for each vertex, normalized within the texture region. */ + regionUVs = []; + /** The UV pair for each vertex, normalized within the entire texture. + * + * See {@link #updateUVs}. */ + uvs = []; + /** Triplets of vertex indices which describe the mesh's triangulation. */ + triangles = []; + /** The color to tint the mesh. */ + color = new Color(1, 1, 1, 1); + /** The width of the mesh's image. Available only when nonessential data was exported. */ + width = 0; + /** The height of the mesh's image. Available only when nonessential data was exported. */ + height = 0; + /** The number of entries at the beginning of {@link #vertices} that make up the mesh hull. */ + hullLength = 0; + /** Vertex index pairs describing edges for controling triangulation. Mesh triangles will never cross edges. Only available if + * nonessential data was exported. Triangulation is not performed at runtime. */ + edges = []; + parentMesh = null; + sequence = null; + tempColor = new Color(0, 0, 0, 0); + constructor(name, path) { + super(name); + this.path = path; + } + /** Calculates {@link #uvs} using the {@link #regionUVs} and region. Must be called if the region, the region's properties, or + * the {@link #regionUVs} are changed. */ + updateRegion() { + if (!this.region) + throw new Error("Region not set."); + let regionUVs = this.regionUVs; + if (!this.uvs || this.uvs.length != regionUVs.length) + this.uvs = Utils.newFloatArray(regionUVs.length); + let uvs = this.uvs; + let n = this.uvs.length; + let u = this.region.u, v = this.region.v, width = 0, height = 0; + if (this.region instanceof TextureAtlasRegion) { + let region = this.region, image = region.page.texture.getImage(); + let textureWidth = image.width, textureHeight = image.height; + switch (region.degrees) { + case 90: + u -= (region.originalHeight - region.offsetY - region.height) / textureWidth; + v -= (region.originalWidth - region.offsetX - region.width) / textureHeight; + width = region.originalHeight / textureWidth; + height = region.originalWidth / textureHeight; + for (let i = 0; i < n; i += 2) { + uvs[i] = u + regionUVs[i + 1] * width; + uvs[i + 1] = v + (1 - regionUVs[i]) * height; + } + return; + case 180: + u -= (region.originalWidth - region.offsetX - region.width) / textureWidth; + v -= region.offsetY / textureHeight; + width = region.originalWidth / textureWidth; + height = region.originalHeight / textureHeight; + for (let i = 0; i < n; i += 2) { + uvs[i] = u + (1 - regionUVs[i]) * width; + uvs[i + 1] = v + (1 - regionUVs[i + 1]) * height; + } + return; + case 270: + u -= region.offsetY / textureWidth; + v -= region.offsetX / textureHeight; + width = region.originalHeight / textureWidth; + height = region.originalWidth / textureHeight; + for (let i = 0; i < n; i += 2) { + uvs[i] = u + (1 - regionUVs[i + 1]) * width; + uvs[i + 1] = v + regionUVs[i] * height; + } + return; + } + u -= region.offsetX / textureWidth; + v -= (region.originalHeight - region.offsetY - region.height) / textureHeight; + width = region.originalWidth / textureWidth; + height = region.originalHeight / textureHeight; + } else if (!this.region) { + u = v = 0; + width = height = 1; + } else { + width = this.region.u2 - u; + height = this.region.v2 - v; + } + for (let i = 0; i < n; i += 2) { + uvs[i] = u + regionUVs[i] * width; + uvs[i + 1] = v + regionUVs[i + 1] * height; + } + } + /** The parent mesh if this is a linked mesh, else null. A linked mesh shares the {@link #bones}, {@link #vertices}, + * {@link #regionUVs}, {@link #triangles}, {@link #hullLength}, {@link #edges}, {@link #width}, and {@link #height} with the + * parent mesh, but may have a different {@link #name} or {@link #path} (and therefore a different texture). */ + getParentMesh() { + return this.parentMesh; + } + /** @param parentMesh May be null. */ + setParentMesh(parentMesh) { + this.parentMesh = parentMesh; + if (parentMesh) { + this.bones = parentMesh.bones; + this.vertices = parentMesh.vertices; + this.worldVerticesLength = parentMesh.worldVerticesLength; + this.regionUVs = parentMesh.regionUVs; + this.triangles = parentMesh.triangles; + this.hullLength = parentMesh.hullLength; + this.worldVerticesLength = parentMesh.worldVerticesLength; + } + } + copy() { + if (this.parentMesh) + return this.newLinkedMesh(); + let copy = new MeshAttachment(this.name, this.path); + copy.region = this.region; + copy.color.setFromColor(this.color); + this.copyTo(copy); + copy.regionUVs = new Array(this.regionUVs.length); + Utils.arrayCopy(this.regionUVs, 0, copy.regionUVs, 0, this.regionUVs.length); + copy.uvs = new Array(this.uvs.length); + Utils.arrayCopy(this.uvs, 0, copy.uvs, 0, this.uvs.length); + copy.triangles = new Array(this.triangles.length); + Utils.arrayCopy(this.triangles, 0, copy.triangles, 0, this.triangles.length); + copy.hullLength = this.hullLength; + copy.sequence = this.sequence != null ? this.sequence.copy() : null; + if (this.edges) { + copy.edges = new Array(this.edges.length); + Utils.arrayCopy(this.edges, 0, copy.edges, 0, this.edges.length); + } + copy.width = this.width; + copy.height = this.height; + return copy; + } + computeWorldVertices(slot, start, count, worldVertices2, offset, stride) { + if (this.sequence != null) + this.sequence.apply(slot, this); + super.computeWorldVertices(slot, start, count, worldVertices2, offset, stride); + } + /** Returns a new mesh with the {@link #parentMesh} set to this mesh's parent mesh, if any, else to this mesh. **/ + newLinkedMesh() { + let copy = new MeshAttachment(this.name, this.path); + copy.region = this.region; + copy.color.setFromColor(this.color); + copy.timelineAttachment = this.timelineAttachment; + copy.setParentMesh(this.parentMesh ? this.parentMesh : this); + if (copy.region != null) + copy.updateRegion(); + return copy; + } + }; + + // spine-core/src/attachments/PathAttachment.ts + var PathAttachment = class extends VertexAttachment { + /** The lengths along the path in the setup pose from the start of the path to the end of each Bezier curve. */ + lengths = []; + /** If true, the start and end knots are connected. */ + closed = false; + /** If true, additional calculations are performed to make calculating positions along the path more accurate. If false, fewer + * calculations are performed but calculating positions along the path is less accurate. */ + constantSpeed = false; + /** The color of the path as it was in Spine. Available only when nonessential data was exported. Paths are not usually + * rendered at runtime. */ + color = new Color(1, 1, 1, 1); + constructor(name) { + super(name); + } + copy() { + let copy = new PathAttachment(this.name); + this.copyTo(copy); + copy.lengths = new Array(this.lengths.length); + Utils.arrayCopy(this.lengths, 0, copy.lengths, 0, this.lengths.length); + copy.closed = closed; + copy.constantSpeed = this.constantSpeed; + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/attachments/PointAttachment.ts + var PointAttachment = class extends VertexAttachment { + x = 0; + y = 0; + rotation = 0; + /** The color of the point attachment as it was in Spine. Available only when nonessential data was exported. Point attachments + * are not usually rendered at runtime. */ + color = new Color(0.38, 0.94, 0, 1); + constructor(name) { + super(name); + } + computeWorldPosition(bone, point) { + point.x = this.x * bone.a + this.y * bone.b + bone.worldX; + point.y = this.x * bone.c + this.y * bone.d + bone.worldY; + return point; + } + computeWorldRotation(bone) { + let cos = MathUtils.cosDeg(this.rotation), sin = MathUtils.sinDeg(this.rotation); + let x = cos * bone.a + sin * bone.b; + let y = cos * bone.c + sin * bone.d; + return Math.atan2(y, x) * MathUtils.radDeg; + } + copy() { + let copy = new PointAttachment(this.name); + copy.x = this.x; + copy.y = this.y; + copy.rotation = this.rotation; + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/attachments/RegionAttachment.ts + var _RegionAttachment = class extends Attachment { + /** The local x translation. */ + x = 0; + /** The local y translation. */ + y = 0; + /** The local scaleX. */ + scaleX = 1; + /** The local scaleY. */ + scaleY = 1; + /** The local rotation. */ + rotation = 0; + /** The width of the region attachment in Spine. */ + width = 0; + /** The height of the region attachment in Spine. */ + height = 0; + /** The color to tint the region attachment. */ + color = new Color(1, 1, 1, 1); + /** The name of the texture region for this attachment. */ + path; + region = null; + sequence = null; + /** For each of the 4 vertices, a pair of x,y values that is the local position of the vertex. + * + * See {@link #updateOffset()}. */ + offset = Utils.newFloatArray(8); + uvs = Utils.newFloatArray(8); + tempColor = new Color(1, 1, 1, 1); + constructor(name, path) { + super(name); + this.path = path; + } + /** Calculates the {@link #offset} using the region settings. Must be called after changing region settings. */ + updateRegion() { + if (!this.region) + throw new Error("Region not set."); + let region = this.region; + let uvs = this.uvs; + if (region == null) { + uvs[0] = 0; + uvs[1] = 0; + uvs[2] = 0; + uvs[3] = 1; + uvs[4] = 1; + uvs[5] = 1; + uvs[6] = 1; + uvs[7] = 0; + return; + } + let regionScaleX = this.width / this.region.originalWidth * this.scaleX; + let regionScaleY = this.height / this.region.originalHeight * this.scaleY; + let localX = -this.width / 2 * this.scaleX + this.region.offsetX * regionScaleX; + let localY = -this.height / 2 * this.scaleY + this.region.offsetY * regionScaleY; + let localX2 = localX + this.region.width * regionScaleX; + let localY2 = localY + this.region.height * regionScaleY; + let radians = this.rotation * Math.PI / 180; + let cos = Math.cos(radians); + let sin = Math.sin(radians); + let x = this.x, y = this.y; + let localXCos = localX * cos + x; + let localXSin = localX * sin; + let localYCos = localY * cos + y; + let localYSin = localY * sin; + let localX2Cos = localX2 * cos + x; + let localX2Sin = localX2 * sin; + let localY2Cos = localY2 * cos + y; + let localY2Sin = localY2 * sin; + let offset = this.offset; + offset[0] = localXCos - localYSin; + offset[1] = localYCos + localXSin; + offset[2] = localXCos - localY2Sin; + offset[3] = localY2Cos + localXSin; + offset[4] = localX2Cos - localY2Sin; + offset[5] = localY2Cos + localX2Sin; + offset[6] = localX2Cos - localYSin; + offset[7] = localYCos + localX2Sin; + if (region.degrees == 90) { + uvs[0] = region.u2; + uvs[1] = region.v2; + uvs[2] = region.u; + uvs[3] = region.v2; + uvs[4] = region.u; + uvs[5] = region.v; + uvs[6] = region.u2; + uvs[7] = region.v; + } else { + uvs[0] = region.u; + uvs[1] = region.v2; + uvs[2] = region.u; + uvs[3] = region.v; + uvs[4] = region.u2; + uvs[5] = region.v; + uvs[6] = region.u2; + uvs[7] = region.v2; + } + } + /** Transforms the attachment's four vertices to world coordinates. If the attachment has a {@link #sequence}, the region may + * be changed. + *

+ * See World transforms in the Spine + * Runtimes Guide. + * @param worldVertices The output world vertices. Must have a length >= offset + 8. + * @param offset The worldVertices index to begin writing values. + * @param stride The number of worldVertices entries between the value pairs written. */ + computeWorldVertices(slot, worldVertices2, offset, stride) { + if (this.sequence != null) + this.sequence.apply(slot, this); + let bone = slot.bone; + let vertexOffset = this.offset; + let x = bone.worldX, y = bone.worldY; + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + let offsetX = 0, offsetY = 0; + offsetX = vertexOffset[0]; + offsetY = vertexOffset[1]; + worldVertices2[offset] = offsetX * a + offsetY * b + x; + worldVertices2[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[2]; + offsetY = vertexOffset[3]; + worldVertices2[offset] = offsetX * a + offsetY * b + x; + worldVertices2[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[4]; + offsetY = vertexOffset[5]; + worldVertices2[offset] = offsetX * a + offsetY * b + x; + worldVertices2[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[6]; + offsetY = vertexOffset[7]; + worldVertices2[offset] = offsetX * a + offsetY * b + x; + worldVertices2[offset + 1] = offsetX * c + offsetY * d + y; + } + copy() { + let copy = new _RegionAttachment(this.name, this.path); + copy.region = this.region; + copy.x = this.x; + copy.y = this.y; + copy.scaleX = this.scaleX; + copy.scaleY = this.scaleY; + copy.rotation = this.rotation; + copy.width = this.width; + copy.height = this.height; + Utils.arrayCopy(this.uvs, 0, copy.uvs, 0, 8); + Utils.arrayCopy(this.offset, 0, copy.offset, 0, 8); + copy.color.setFromColor(this.color); + copy.sequence = this.sequence != null ? this.sequence.copy() : null; + return copy; + } + }; + var RegionAttachment = _RegionAttachment; + __publicField(RegionAttachment, "X1", 0); + __publicField(RegionAttachment, "Y1", 1); + __publicField(RegionAttachment, "C1R", 2); + __publicField(RegionAttachment, "C1G", 3); + __publicField(RegionAttachment, "C1B", 4); + __publicField(RegionAttachment, "C1A", 5); + __publicField(RegionAttachment, "U1", 6); + __publicField(RegionAttachment, "V1", 7); + __publicField(RegionAttachment, "X2", 8); + __publicField(RegionAttachment, "Y2", 9); + __publicField(RegionAttachment, "C2R", 10); + __publicField(RegionAttachment, "C2G", 11); + __publicField(RegionAttachment, "C2B", 12); + __publicField(RegionAttachment, "C2A", 13); + __publicField(RegionAttachment, "U2", 14); + __publicField(RegionAttachment, "V2", 15); + __publicField(RegionAttachment, "X3", 16); + __publicField(RegionAttachment, "Y3", 17); + __publicField(RegionAttachment, "C3R", 18); + __publicField(RegionAttachment, "C3G", 19); + __publicField(RegionAttachment, "C3B", 20); + __publicField(RegionAttachment, "C3A", 21); + __publicField(RegionAttachment, "U3", 22); + __publicField(RegionAttachment, "V3", 23); + __publicField(RegionAttachment, "X4", 24); + __publicField(RegionAttachment, "Y4", 25); + __publicField(RegionAttachment, "C4R", 26); + __publicField(RegionAttachment, "C4G", 27); + __publicField(RegionAttachment, "C4B", 28); + __publicField(RegionAttachment, "C4A", 29); + __publicField(RegionAttachment, "U4", 30); + __publicField(RegionAttachment, "V4", 31); + + // spine-core/src/AtlasAttachmentLoader.ts + var AtlasAttachmentLoader = class { + atlas; + constructor(atlas) { + this.atlas = atlas; + } + loadSequence(name, basePath, sequence) { + let regions = sequence.regions; + for (let i = 0, n = regions.length; i < n; i++) { + let path = sequence.getPath(basePath, i); + let region = this.atlas.findRegion(path); + if (region == null) + throw new Error("Region not found in atlas: " + path + " (sequence: " + name + ")"); + regions[i] = region; + } + } + newRegionAttachment(skin, name, path, sequence) { + let attachment = new RegionAttachment(name, path); + if (sequence != null) { + this.loadSequence(name, path, sequence); + } else { + let region = this.atlas.findRegion(path); + if (!region) + throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")"); + attachment.region = region; + } + return attachment; + } + newMeshAttachment(skin, name, path, sequence) { + let attachment = new MeshAttachment(name, path); + if (sequence != null) { + this.loadSequence(name, path, sequence); + } else { + let region = this.atlas.findRegion(path); + if (!region) + throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); + attachment.region = region; + } + return attachment; + } + newBoundingBoxAttachment(skin, name) { + return new BoundingBoxAttachment(name); + } + newPathAttachment(skin, name) { + return new PathAttachment(name); + } + newPointAttachment(skin, name) { + return new PointAttachment(name); + } + newClippingAttachment(skin, name) { + return new ClippingAttachment(name); + } + }; + + // spine-core/src/BoneData.ts + var BoneData = class { + /** The index of the bone in {@link Skeleton#getBones()}. */ + index = 0; + /** The name of the bone, which is unique across all bones in the skeleton. */ + name; + /** @returns May be null. */ + parent = null; + /** The bone's length. */ + length = 0; + /** The local x translation. */ + x = 0; + /** The local y translation. */ + y = 0; + /** The local rotation. */ + rotation = 0; + /** The local scaleX. */ + scaleX = 1; + /** The local scaleY. */ + scaleY = 1; + /** The local shearX. */ + shearX = 0; + /** The local shearX. */ + shearY = 0; + /** The transform mode for how parent world transforms affect this bone. */ + transformMode = TransformMode.Normal; + /** When true, {@link Skeleton#updateWorldTransform()} only updates this bone if the {@link Skeleton#skin} contains this + * bone. + * @see Skin#bones */ + skinRequired = false; + /** The color of the bone as it was in Spine. Available only when nonessential data was exported. Bones are not usually + * rendered at runtime. */ + color = new Color(); + constructor(index, name, parent) { + if (index < 0) + throw new Error("index must be >= 0."); + if (!name) + throw new Error("name cannot be null."); + this.index = index; + this.name = name; + this.parent = parent; + } + }; + var TransformMode = /* @__PURE__ */ ((TransformMode2) => { + TransformMode2[TransformMode2["Normal"] = 0] = "Normal"; + TransformMode2[TransformMode2["OnlyTranslation"] = 1] = "OnlyTranslation"; + TransformMode2[TransformMode2["NoRotationOrReflection"] = 2] = "NoRotationOrReflection"; + TransformMode2[TransformMode2["NoScale"] = 3] = "NoScale"; + TransformMode2[TransformMode2["NoScaleOrReflection"] = 4] = "NoScaleOrReflection"; + return TransformMode2; + })(TransformMode || {}); + + // spine-core/src/Bone.ts + var Bone = class { + /** The bone's setup pose data. */ + data; + /** The skeleton this bone belongs to. */ + skeleton; + /** The parent bone, or null if this is the root bone. */ + parent = null; + /** The immediate children of this bone. */ + children = new Array(); + /** The local x translation. */ + x = 0; + /** The local y translation. */ + y = 0; + /** The local rotation in degrees, counter clockwise. */ + rotation = 0; + /** The local scaleX. */ + scaleX = 0; + /** The local scaleY. */ + scaleY = 0; + /** The local shearX. */ + shearX = 0; + /** The local shearY. */ + shearY = 0; + /** The applied local x translation. */ + ax = 0; + /** The applied local y translation. */ + ay = 0; + /** The applied local rotation in degrees, counter clockwise. */ + arotation = 0; + /** The applied local scaleX. */ + ascaleX = 0; + /** The applied local scaleY. */ + ascaleY = 0; + /** The applied local shearX. */ + ashearX = 0; + /** The applied local shearY. */ + ashearY = 0; + /** Part of the world transform matrix for the X axis. If changed, {@link #updateAppliedTransform()} should be called. */ + a = 0; + /** Part of the world transform matrix for the Y axis. If changed, {@link #updateAppliedTransform()} should be called. */ + b = 0; + /** Part of the world transform matrix for the X axis. If changed, {@link #updateAppliedTransform()} should be called. */ + c = 0; + /** Part of the world transform matrix for the Y axis. If changed, {@link #updateAppliedTransform()} should be called. */ + d = 0; + /** The world X position. If changed, {@link #updateAppliedTransform()} should be called. */ + worldY = 0; + /** The world Y position. If changed, {@link #updateAppliedTransform()} should be called. */ + worldX = 0; + sorted = false; + active = false; + /** @param parent May be null. */ + constructor(data, skeleton, parent) { + if (!data) + throw new Error("data cannot be null."); + if (!skeleton) + throw new Error("skeleton cannot be null."); + this.data = data; + this.skeleton = skeleton; + this.parent = parent; + this.setToSetupPose(); + } + /** Returns false when the bone has not been computed because {@link BoneData#skinRequired} is true and the + * {@link Skeleton#skin active skin} does not {@link Skin#bones contain} this bone. */ + isActive() { + return this.active; + } + /** Computes the world transform using the parent bone and this bone's local applied transform. */ + update() { + this.updateWorldTransformWith(this.ax, this.ay, this.arotation, this.ascaleX, this.ascaleY, this.ashearX, this.ashearY); + } + /** Computes the world transform using the parent bone and this bone's local transform. + * + * See {@link #updateWorldTransformWith()}. */ + updateWorldTransform() { + this.updateWorldTransformWith(this.x, this.y, this.rotation, this.scaleX, this.scaleY, this.shearX, this.shearY); + } + /** Computes the world transform using the parent bone and the specified local transform. The applied transform is set to the + * specified local transform. Child bones are not updated. + * + * See [World transforms](http://esotericsoftware.com/spine-runtime-skeletons#World-transforms) in the Spine + * Runtimes Guide. */ + updateWorldTransformWith(x, y, rotation, scaleX, scaleY, shearX, shearY) { + this.ax = x; + this.ay = y; + this.arotation = rotation; + this.ascaleX = scaleX; + this.ascaleY = scaleY; + this.ashearX = shearX; + this.ashearY = shearY; + let parent = this.parent; + if (!parent) { + let skeleton = this.skeleton; + let rotationY = rotation + 90 + shearY; + let sx = skeleton.scaleX; + let sy = skeleton.scaleY; + this.a = MathUtils.cosDeg(rotation + shearX) * scaleX * sx; + this.b = MathUtils.cosDeg(rotationY) * scaleY * sx; + this.c = MathUtils.sinDeg(rotation + shearX) * scaleX * sy; + this.d = MathUtils.sinDeg(rotationY) * scaleY * sy; + this.worldX = x * sx + skeleton.x; + this.worldY = y * sy + skeleton.y; + return; + } + let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + this.worldX = pa * x + pb * y + parent.worldX; + this.worldY = pc * x + pd * y + parent.worldY; + switch (this.data.transformMode) { + case 0 /* Normal */: { + let rotationY = rotation + 90 + shearY; + let la = MathUtils.cosDeg(rotation + shearX) * scaleX; + let lb = MathUtils.cosDeg(rotationY) * scaleY; + let lc = MathUtils.sinDeg(rotation + shearX) * scaleX; + let ld = MathUtils.sinDeg(rotationY) * scaleY; + this.a = pa * la + pb * lc; + this.b = pa * lb + pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + return; + } + case 1 /* OnlyTranslation */: { + let rotationY = rotation + 90 + shearY; + this.a = MathUtils.cosDeg(rotation + shearX) * scaleX; + this.b = MathUtils.cosDeg(rotationY) * scaleY; + this.c = MathUtils.sinDeg(rotation + shearX) * scaleX; + this.d = MathUtils.sinDeg(rotationY) * scaleY; + break; + } + case 2 /* NoRotationOrReflection */: { + let s = pa * pa + pc * pc; + let prx = 0; + if (s > 1e-4) { + s = Math.abs(pa * pd - pb * pc) / s; + pa /= this.skeleton.scaleX; + pc /= this.skeleton.scaleY; + pb = pc * s; + pd = pa * s; + prx = Math.atan2(pc, pa) * MathUtils.radDeg; + } else { + pa = 0; + pc = 0; + prx = 90 - Math.atan2(pd, pb) * MathUtils.radDeg; + } + let rx = rotation + shearX - prx; + let ry = rotation + shearY - prx + 90; + let la = MathUtils.cosDeg(rx) * scaleX; + let lb = MathUtils.cosDeg(ry) * scaleY; + let lc = MathUtils.sinDeg(rx) * scaleX; + let ld = MathUtils.sinDeg(ry) * scaleY; + this.a = pa * la - pb * lc; + this.b = pa * lb - pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + break; + } + case 3 /* NoScale */: + case 4 /* NoScaleOrReflection */: { + let cos = MathUtils.cosDeg(rotation); + let sin = MathUtils.sinDeg(rotation); + let za = (pa * cos + pb * sin) / this.skeleton.scaleX; + let zc = (pc * cos + pd * sin) / this.skeleton.scaleY; + let s = Math.sqrt(za * za + zc * zc); + if (s > 1e-5) + s = 1 / s; + za *= s; + zc *= s; + s = Math.sqrt(za * za + zc * zc); + if (this.data.transformMode == 3 /* NoScale */ && pa * pd - pb * pc < 0 != (this.skeleton.scaleX < 0 != this.skeleton.scaleY < 0)) + s = -s; + let r = Math.PI / 2 + Math.atan2(zc, za); + let zb = Math.cos(r) * s; + let zd = Math.sin(r) * s; + let la = MathUtils.cosDeg(shearX) * scaleX; + let lb = MathUtils.cosDeg(90 + shearY) * scaleY; + let lc = MathUtils.sinDeg(shearX) * scaleX; + let ld = MathUtils.sinDeg(90 + shearY) * scaleY; + this.a = za * la + zb * lc; + this.b = za * lb + zb * ld; + this.c = zc * la + zd * lc; + this.d = zc * lb + zd * ld; + break; + } + } + this.a *= this.skeleton.scaleX; + this.b *= this.skeleton.scaleX; + this.c *= this.skeleton.scaleY; + this.d *= this.skeleton.scaleY; + } + /** Sets this bone's local transform to the setup pose. */ + setToSetupPose() { + let data = this.data; + this.x = data.x; + this.y = data.y; + this.rotation = data.rotation; + this.scaleX = data.scaleX; + this.scaleY = data.scaleY; + this.shearX = data.shearX; + this.shearY = data.shearY; + } + /** The world rotation for the X axis, calculated using {@link #a} and {@link #c}. */ + getWorldRotationX() { + return Math.atan2(this.c, this.a) * MathUtils.radDeg; + } + /** The world rotation for the Y axis, calculated using {@link #b} and {@link #d}. */ + getWorldRotationY() { + return Math.atan2(this.d, this.b) * MathUtils.radDeg; + } + /** The magnitude (always positive) of the world scale X, calculated using {@link #a} and {@link #c}. */ + getWorldScaleX() { + return Math.sqrt(this.a * this.a + this.c * this.c); + } + /** The magnitude (always positive) of the world scale Y, calculated using {@link #b} and {@link #d}. */ + getWorldScaleY() { + return Math.sqrt(this.b * this.b + this.d * this.d); + } + /** Computes the applied transform values from the world transform. + * + * If the world transform is modified (by a constraint, {@link #rotateWorld(float)}, etc) then this method should be called so + * the applied transform matches the world transform. The applied transform may be needed by other code (eg to apply other + * constraints). + * + * Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. The applied transform after + * calling this method is equivalent to the local transform used to compute the world transform, but may not be identical. */ + updateAppliedTransform() { + let parent = this.parent; + if (!parent) { + this.ax = this.worldX - this.skeleton.x; + this.ay = this.worldY - this.skeleton.y; + this.arotation = Math.atan2(this.c, this.a) * MathUtils.radDeg; + this.ascaleX = Math.sqrt(this.a * this.a + this.c * this.c); + this.ascaleY = Math.sqrt(this.b * this.b + this.d * this.d); + this.ashearX = 0; + this.ashearY = Math.atan2(this.a * this.b + this.c * this.d, this.a * this.d - this.b * this.c) * MathUtils.radDeg; + return; + } + let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + let pid = 1 / (pa * pd - pb * pc); + let dx = this.worldX - parent.worldX, dy = this.worldY - parent.worldY; + this.ax = dx * pd * pid - dy * pb * pid; + this.ay = dy * pa * pid - dx * pc * pid; + let ia = pid * pd; + let id = pid * pa; + let ib = pid * pb; + let ic = pid * pc; + let ra = ia * this.a - ib * this.c; + let rb = ia * this.b - ib * this.d; + let rc = id * this.c - ic * this.a; + let rd = id * this.d - ic * this.b; + this.ashearX = 0; + this.ascaleX = Math.sqrt(ra * ra + rc * rc); + if (this.ascaleX > 1e-4) { + let det = ra * rd - rb * rc; + this.ascaleY = det / this.ascaleX; + this.ashearY = Math.atan2(ra * rb + rc * rd, det) * MathUtils.radDeg; + this.arotation = Math.atan2(rc, ra) * MathUtils.radDeg; + } else { + this.ascaleX = 0; + this.ascaleY = Math.sqrt(rb * rb + rd * rd); + this.ashearY = 0; + this.arotation = 90 - Math.atan2(rd, rb) * MathUtils.radDeg; + } + } + /** Transforms a point from world coordinates to the bone's local coordinates. */ + worldToLocal(world) { + let invDet = 1 / (this.a * this.d - this.b * this.c); + let x = world.x - this.worldX, y = world.y - this.worldY; + world.x = x * this.d * invDet - y * this.b * invDet; + world.y = y * this.a * invDet - x * this.c * invDet; + return world; + } + /** Transforms a point from the bone's local coordinates to world coordinates. */ + localToWorld(local) { + let x = local.x, y = local.y; + local.x = x * this.a + y * this.b + this.worldX; + local.y = x * this.c + y * this.d + this.worldY; + return local; + } + /** Transforms a world rotation to a local rotation. */ + worldToLocalRotation(worldRotation) { + let sin = MathUtils.sinDeg(worldRotation), cos = MathUtils.cosDeg(worldRotation); + return Math.atan2(this.a * sin - this.c * cos, this.d * cos - this.b * sin) * MathUtils.radDeg + this.rotation - this.shearX; + } + /** Transforms a local rotation to a world rotation. */ + localToWorldRotation(localRotation) { + localRotation -= this.rotation - this.shearX; + let sin = MathUtils.sinDeg(localRotation), cos = MathUtils.cosDeg(localRotation); + return Math.atan2(cos * this.c + sin * this.d, cos * this.a + sin * this.b) * MathUtils.radDeg; + } + /** Rotates the world transform the specified amount. + *

+ * After changes are made to the world transform, {@link #updateAppliedTransform()} should be called and {@link #update()} will + * need to be called on any child bones, recursively. */ + rotateWorld(degrees) { + let a = this.a, b = this.b, c = this.c, d = this.d; + let cos = MathUtils.cosDeg(degrees), sin = MathUtils.sinDeg(degrees); + this.a = cos * a - sin * c; + this.b = cos * b - sin * d; + this.c = sin * a + cos * c; + this.d = sin * b + cos * d; + } + }; + + // spine-core/src/ConstraintData.ts + var ConstraintData = class { + constructor(name, order, skinRequired) { + this.name = name; + this.order = order; + this.skinRequired = skinRequired; + } + }; + + // spine-core/src/AssetManagerBase.ts + var AssetManagerBase = class { + pathPrefix = ""; + textureLoader; + downloader; + assets = {}; + errors = {}; + toLoad = 0; + loaded = 0; + constructor(textureLoader, pathPrefix = "", downloader = new Downloader()) { + this.textureLoader = textureLoader; + this.pathPrefix = pathPrefix; + this.downloader = downloader; + } + start(path) { + this.toLoad++; + return this.pathPrefix + path; + } + success(callback, path, asset) { + this.toLoad--; + this.loaded++; + this.assets[path] = asset; + if (callback) + callback(path, asset); + } + error(callback, path, message) { + this.toLoad--; + this.loaded++; + this.errors[path] = message; + if (callback) + callback(path, message); + } + loadAll() { + let promise = new Promise((resolve, reject) => { + let check = () => { + if (this.isLoadingComplete()) { + if (this.hasErrors()) + reject(this.errors); + else + resolve(this); + return; + } + requestAnimationFrame(check); + }; + requestAnimationFrame(check); + }); + return promise; + } + setRawDataURI(path, data) { + this.downloader.rawDataUris[this.pathPrefix + path] = data; + } + loadBinary(path, success = () => { + }, error = () => { + }) { + path = this.start(path); + this.downloader.downloadBinary(path, (data) => { + this.success(success, path, data); + }, (status, responseText) => { + this.error(error, path, `Couldn't load binary ${path}: status ${status}, ${responseText}`); + }); + } + loadText(path, success = () => { + }, error = () => { + }) { + path = this.start(path); + this.downloader.downloadText(path, (data) => { + this.success(success, path, data); + }, (status, responseText) => { + this.error(error, path, `Couldn't load text ${path}: status ${status}, ${responseText}`); + }); + } + loadJson(path, success = () => { + }, error = () => { + }) { + path = this.start(path); + this.downloader.downloadJson(path, (data) => { + this.success(success, path, data); + }, (status, responseText) => { + this.error(error, path, `Couldn't load JSON ${path}: status ${status}, ${responseText}`); + }); + } + loadTexture(path, success = () => { + }, error = () => { + }) { + path = this.start(path); + let isBrowser = !!(typeof window !== "undefined" && typeof navigator !== "undefined" && window.document); + let isWebWorker = !isBrowser; + if (isWebWorker) { + fetch(path, { mode: "cors" }).then((response) => { + if (response.ok) + return response.blob(); + this.error(error, path, `Couldn't load image: ${path}`); + return null; + }).then((blob) => { + return blob ? createImageBitmap(blob, { premultiplyAlpha: "none", colorSpaceConversion: "none" }) : null; + }).then((bitmap) => { + if (bitmap) + this.success(success, path, this.textureLoader(bitmap)); + }); + } else { + let image = new Image(); + image.crossOrigin = "anonymous"; + image.onload = () => { + this.success(success, path, this.textureLoader(image)); + }; + image.onerror = () => { + this.error(error, path, `Couldn't load image: ${path}`); + }; + if (this.downloader.rawDataUris[path]) + path = this.downloader.rawDataUris[path]; + image.src = path; + } + } + loadTextureAtlas(path, success = () => { + }, error = () => { + }, fileAlias) { + let index = path.lastIndexOf("/"); + let parent = index >= 0 ? path.substring(0, index + 1) : ""; + path = this.start(path); + this.downloader.downloadText(path, (atlasText) => { + try { + let atlas = new TextureAtlas(atlasText); + let toLoad = atlas.pages.length, abort = false; + for (let page of atlas.pages) { + this.loadTexture( + !fileAlias ? parent + page.name : fileAlias[page.name], + (imagePath, texture) => { + if (!abort) { + page.setTexture(texture); + if (--toLoad == 0) + this.success(success, path, atlas); + } + }, + (imagePath, message) => { + if (!abort) + this.error(error, path, `Couldn't load texture atlas ${path} page image: ${imagePath}`); + abort = true; + } + ); + } + } catch (e) { + this.error(error, path, `Couldn't parse texture atlas ${path}: ${e.message}`); + } + }, (status, responseText) => { + this.error(error, path, `Couldn't load texture atlas ${path}: status ${status}, ${responseText}`); + }); + } + get(path) { + return this.assets[this.pathPrefix + path]; + } + require(path) { + path = this.pathPrefix + path; + let asset = this.assets[path]; + if (asset) + return asset; + let error = this.errors[path]; + throw Error("Asset not found: " + path + (error ? "\n" + error : "")); + } + remove(path) { + path = this.pathPrefix + path; + let asset = this.assets[path]; + if (asset.dispose) + asset.dispose(); + delete this.assets[path]; + return asset; + } + removeAll() { + for (let key in this.assets) { + let asset = this.assets[key]; + if (asset.dispose) + asset.dispose(); + } + this.assets = {}; + } + isLoadingComplete() { + return this.toLoad == 0; + } + getToLoad() { + return this.toLoad; + } + getLoaded() { + return this.loaded; + } + dispose() { + this.removeAll(); + } + hasErrors() { + return Object.keys(this.errors).length > 0; + } + getErrors() { + return this.errors; + } + }; + var Downloader = class { + callbacks = {}; + rawDataUris = {}; + dataUriToString(dataUri) { + if (!dataUri.startsWith("data:")) { + throw new Error("Not a data URI."); + } + let base64Idx = dataUri.indexOf("base64,"); + if (base64Idx != -1) { + base64Idx += "base64,".length; + return atob(dataUri.substr(base64Idx)); + } else { + return dataUri.substr(dataUri.indexOf(",") + 1); + } + } + base64ToUint8Array(base64) { + var binary_string = window.atob(base64); + var len = binary_string.length; + var bytes = new Uint8Array(len); + for (var i = 0; i < len; i++) { + bytes[i] = binary_string.charCodeAt(i); + } + return bytes; + } + dataUriToUint8Array(dataUri) { + if (!dataUri.startsWith("data:")) { + throw new Error("Not a data URI."); + } + let base64Idx = dataUri.indexOf("base64,"); + if (base64Idx == -1) + throw new Error("Not a binary data URI."); + base64Idx += "base64,".length; + return this.base64ToUint8Array(dataUri.substr(base64Idx)); + } + downloadText(url, success, error) { + if (this.start(url, success, error)) + return; + if (this.rawDataUris[url]) { + try { + let dataUri = this.rawDataUris[url]; + this.finish(url, 200, this.dataUriToString(dataUri)); + } catch (e) { + this.finish(url, 400, JSON.stringify(e)); + } + return; + } + let request = new XMLHttpRequest(); + request.overrideMimeType("text/html"); + request.open("GET", url, true); + let done = () => { + this.finish(url, request.status, request.responseText); + }; + request.onload = done; + request.onerror = done; + request.send(); + } + downloadJson(url, success, error) { + this.downloadText(url, (data) => { + success(JSON.parse(data)); + }, error); + } + downloadBinary(url, success, error) { + if (this.start(url, success, error)) + return; + if (this.rawDataUris[url]) { + try { + let dataUri = this.rawDataUris[url]; + this.finish(url, 200, this.dataUriToUint8Array(dataUri)); + } catch (e) { + this.finish(url, 400, JSON.stringify(e)); + } + return; + } + let request = new XMLHttpRequest(); + request.open("GET", url, true); + request.responseType = "arraybuffer"; + let onerror = () => { + this.finish(url, request.status, request.response); + }; + request.onload = () => { + if (request.status == 200 || request.status == 0) + this.finish(url, 200, new Uint8Array(request.response)); + else + onerror(); + }; + request.onerror = onerror; + request.send(); + } + start(url, success, error) { + let callbacks = this.callbacks[url]; + try { + if (callbacks) + return true; + this.callbacks[url] = callbacks = []; + } finally { + callbacks.push(success, error); + } + } + finish(url, status, data) { + let callbacks = this.callbacks[url]; + delete this.callbacks[url]; + let args = status == 200 || status == 0 ? [data] : [status, data]; + for (let i = args.length - 1, n = callbacks.length; i < n; i += 2) + callbacks[i].apply(null, args); + } + }; + + // spine-core/src/Event.ts + var Event = class { + data; + intValue = 0; + floatValue = 0; + stringValue = null; + time = 0; + volume = 0; + balance = 0; + constructor(time, data) { + if (!data) + throw new Error("data cannot be null."); + this.time = time; + this.data = data; + } + }; + + // spine-core/src/EventData.ts + var EventData = class { + name; + intValue = 0; + floatValue = 0; + stringValue = null; + audioPath = null; + volume = 0; + balance = 0; + constructor(name) { + this.name = name; + } + }; + + // spine-core/src/IkConstraint.ts + var IkConstraint = class { + /** The IK constraint's setup pose data. */ + data; + /** The bones that will be modified by this IK constraint. */ + bones; + /** The bone that is the IK target. */ + target; + /** Controls the bend direction of the IK bones, either 1 or -1. */ + bendDirection = 0; + /** When true and only a single bone is being constrained, if the target is too close, the bone is scaled to reach it. */ + compress = false; + /** When true, if the target is out of range, the parent bone is scaled to reach it. If more than one bone is being constrained + * and the parent bone has local nonuniform scale, stretch is not applied. */ + stretch = false; + /** A percentage (0-1) that controls the mix between the constrained and unconstrained rotations. */ + mix = 1; + /** For two bone IK, the distance from the maximum reach of the bones that rotation will slow. */ + softness = 0; + active = false; + constructor(data, skeleton) { + if (!data) + throw new Error("data cannot be null."); + if (!skeleton) + throw new Error("skeleton cannot be null."); + this.data = data; + this.mix = data.mix; + this.softness = data.softness; + this.bendDirection = data.bendDirection; + this.compress = data.compress; + this.stretch = data.stretch; + this.bones = new Array(); + for (let i = 0; i < data.bones.length; i++) { + let bone = skeleton.findBone(data.bones[i].name); + if (!bone) + throw new Error(`Couldn't find bone ${data.bones[i].name}`); + this.bones.push(bone); + } + let target = skeleton.findBone(data.target.name); + if (!target) + throw new Error(`Couldn't find bone ${data.target.name}`); + this.target = target; + } + isActive() { + return this.active; + } + update() { + if (this.mix == 0) + return; + let target = this.target; + let bones = this.bones; + switch (bones.length) { + case 1: + this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix); + break; + case 2: + this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.data.uniform, this.softness, this.mix); + break; + } + } + /** Applies 1 bone IK. The target is specified in the world coordinate system. */ + apply1(bone, targetX, targetY, compress, stretch, uniform, alpha) { + let p = bone.parent; + if (!p) + throw new Error("IK bone must have parent."); + let pa = p.a, pb = p.b, pc = p.c, pd = p.d; + let rotationIK = -bone.ashearX - bone.arotation, tx = 0, ty = 0; + switch (bone.data.transformMode) { + case 1 /* OnlyTranslation */: + tx = (targetX - bone.worldX) * MathUtils.signum(bone.skeleton.scaleX); + ty = (targetY - bone.worldY) * MathUtils.signum(bone.skeleton.scaleY); + break; + case 2 /* NoRotationOrReflection */: + let s = Math.abs(pa * pd - pb * pc) / Math.max(1e-4, pa * pa + pc * pc); + let sa = pa / bone.skeleton.scaleX; + let sc = pc / bone.skeleton.scaleY; + pb = -sc * s * bone.skeleton.scaleX; + pd = sa * s * bone.skeleton.scaleY; + rotationIK += Math.atan2(sc, sa) * MathUtils.radDeg; + default: + let x = targetX - p.worldX, y = targetY - p.worldY; + let d = pa * pd - pb * pc; + if (Math.abs(d) <= 1e-4) { + tx = 0; + ty = 0; + } else { + tx = (x * pd - y * pb) / d - bone.ax; + ty = (y * pa - x * pc) / d - bone.ay; + } + } + rotationIK += Math.atan2(ty, tx) * MathUtils.radDeg; + if (bone.ascaleX < 0) + rotationIK += 180; + if (rotationIK > 180) + rotationIK -= 360; + else if (rotationIK < -180) + rotationIK += 360; + let sx = bone.ascaleX, sy = bone.ascaleY; + if (compress || stretch) { + switch (bone.data.transformMode) { + case 3 /* NoScale */: + case 4 /* NoScaleOrReflection */: + tx = targetX - bone.worldX; + ty = targetY - bone.worldY; + } + let b = bone.data.length * sx, dd = Math.sqrt(tx * tx + ty * ty); + if (compress && dd < b || stretch && dd > b && b > 1e-4) { + let s = (dd / b - 1) * alpha + 1; + sx *= s; + if (uniform) + sy *= s; + } + } + bone.updateWorldTransformWith( + bone.ax, + bone.ay, + bone.arotation + rotationIK * alpha, + sx, + sy, + bone.ashearX, + bone.ashearY + ); + } + /** Applies 2 bone IK. The target is specified in the world coordinate system. + * @param child A direct descendant of the parent bone. */ + apply2(parent, child, targetX, targetY, bendDir, stretch, uniform, softness, alpha) { + let px = parent.ax, py = parent.ay, psx = parent.ascaleX, psy = parent.ascaleY, sx = psx, sy = psy, csx = child.ascaleX; + let os1 = 0, os2 = 0, s2 = 0; + if (psx < 0) { + psx = -psx; + os1 = 180; + s2 = -1; + } else { + os1 = 0; + s2 = 1; + } + if (psy < 0) { + psy = -psy; + s2 = -s2; + } + if (csx < 0) { + csx = -csx; + os2 = 180; + } else + os2 = 0; + let cx = child.ax, cy = 0, cwx = 0, cwy = 0, a = parent.a, b = parent.b, c = parent.c, d = parent.d; + let u = Math.abs(psx - psy) <= 1e-4; + if (!u || stretch) { + cy = 0; + cwx = a * cx + parent.worldX; + cwy = c * cx + parent.worldY; + } else { + cy = child.ay; + cwx = a * cx + b * cy + parent.worldX; + cwy = c * cx + d * cy + parent.worldY; + } + let pp = parent.parent; + if (!pp) + throw new Error("IK parent must itself have a parent."); + a = pp.a; + b = pp.b; + c = pp.c; + d = pp.d; + let id = a * d - b * c, x = cwx - pp.worldX, y = cwy - pp.worldY; + id = Math.abs(id) <= 1e-4 ? 0 : 1 / id; + let dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; + let l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2; + if (l1 < 1e-4) { + this.apply1(parent, targetX, targetY, false, stretch, false, alpha); + child.updateWorldTransformWith(cx, cy, 0, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY); + return; + } + x = targetX - pp.worldX; + y = targetY - pp.worldY; + let tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py; + let dd = tx * tx + ty * ty; + if (softness != 0) { + softness *= psx * (csx + 1) * 0.5; + let td = Math.sqrt(dd), sd = td - l1 - l2 * psx + softness; + if (sd > 0) { + let p = Math.min(1, sd / (softness * 2)) - 1; + p = (sd - softness * (1 - p * p)) / td; + tx -= p * tx; + ty -= p * ty; + dd = tx * tx + ty * ty; + } + } + outer: + if (u) { + l2 *= psx; + let cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2); + if (cos < -1) { + cos = -1; + a2 = Math.PI * bendDir; + } else if (cos > 1) { + cos = 1; + a2 = 0; + if (stretch) { + a = (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1; + sx *= a; + if (uniform) + sy *= a; + } + } else + a2 = Math.acos(cos) * bendDir; + a = l1 + l2 * cos; + b = l2 * Math.sin(a2); + a1 = Math.atan2(ty * a - tx * b, tx * a + ty * b); + } else { + a = psx * l2; + b = psy * l2; + let aa = a * a, bb = b * b, ta = Math.atan2(ty, tx); + c = bb * l1 * l1 + aa * dd - aa * bb; + let c1 = -2 * bb * l1, c2 = bb - aa; + d = c1 * c1 - 4 * c2 * c; + if (d >= 0) { + let q = Math.sqrt(d); + if (c1 < 0) + q = -q; + q = -(c1 + q) * 0.5; + let r0 = q / c2, r1 = c / q; + let r = Math.abs(r0) < Math.abs(r1) ? r0 : r1; + if (r * r <= dd) { + y = Math.sqrt(dd - r * r) * bendDir; + a1 = ta - Math.atan2(y, r); + a2 = Math.atan2(y / psy, (r - l1) / psx); + break outer; + } + } + let minAngle = MathUtils.PI, minX = l1 - a, minDist = minX * minX, minY = 0; + let maxAngle = 0, maxX = l1 + a, maxDist = maxX * maxX, maxY = 0; + c = -a * l1 / (aa - bb); + if (c >= -1 && c <= 1) { + c = Math.acos(c); + x = a * Math.cos(c) + l1; + y = b * Math.sin(c); + d = x * x + y * y; + if (d < minDist) { + minAngle = c; + minDist = d; + minX = x; + minY = y; + } + if (d > maxDist) { + maxAngle = c; + maxDist = d; + maxX = x; + maxY = y; + } + } + if (dd <= (minDist + maxDist) * 0.5) { + a1 = ta - Math.atan2(minY * bendDir, minX); + a2 = minAngle * bendDir; + } else { + a1 = ta - Math.atan2(maxY * bendDir, maxX); + a2 = maxAngle * bendDir; + } + } + let os = Math.atan2(cy, cx) * s2; + let rotation = parent.arotation; + a1 = (a1 - os) * MathUtils.radDeg + os1 - rotation; + if (a1 > 180) + a1 -= 360; + else if (a1 < -180) + a1 += 360; + parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, sx, sy, 0, 0); + rotation = child.arotation; + a2 = ((a2 + os) * MathUtils.radDeg - child.ashearX) * s2 + os2 - rotation; + if (a2 > 180) + a2 -= 360; + else if (a2 < -180) + a2 += 360; + child.updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY); + } + }; + + // spine-core/src/IkConstraintData.ts + var IkConstraintData = class extends ConstraintData { + /** The bones that are constrained by this IK constraint. */ + bones = new Array(); + /** The bone that is the IK target. */ + _target = null; + set target(boneData) { + this._target = boneData; + } + get target() { + if (!this._target) + throw new Error("BoneData not set."); + else + return this._target; + } + /** Controls the bend direction of the IK bones, either 1 or -1. */ + bendDirection = 1; + /** When true and only a single bone is being constrained, if the target is too close, the bone is scaled to reach it. */ + compress = false; + /** When true, if the target is out of range, the parent bone is scaled to reach it. If more than one bone is being constrained + * and the parent bone has local nonuniform scale, stretch is not applied. */ + stretch = false; + /** When true, only a single bone is being constrained, and {@link #getCompress()} or {@link #getStretch()} is used, the bone + * is scaled on both the X and Y axes. */ + uniform = false; + /** A percentage (0-1) that controls the mix between the constrained and unconstrained rotations. */ + mix = 1; + /** For two bone IK, the distance from the maximum reach of the bones that rotation will slow. */ + softness = 0; + constructor(name) { + super(name, 0, false); + } + }; + + // spine-core/src/PathConstraintData.ts + var PathConstraintData = class extends ConstraintData { + /** The bones that will be modified by this path constraint. */ + bones = new Array(); + /** The slot whose path attachment will be used to constrained the bones. */ + _target = null; + set target(slotData) { + this._target = slotData; + } + get target() { + if (!this._target) + throw new Error("SlotData not set."); + else + return this._target; + } + /** The mode for positioning the first bone on the path. */ + positionMode = PositionMode.Fixed; + /** The mode for positioning the bones after the first bone on the path. */ + spacingMode = SpacingMode.Fixed; + /** The mode for adjusting the rotation of the bones. */ + rotateMode = RotateMode.Chain; + /** An offset added to the constrained bone rotation. */ + offsetRotation = 0; + /** The position along the path. */ + position = 0; + /** The spacing between bones. */ + spacing = 0; + mixRotate = 0; + mixX = 0; + mixY = 0; + constructor(name) { + super(name, 0, false); + } + }; + var PositionMode = /* @__PURE__ */ ((PositionMode2) => { + PositionMode2[PositionMode2["Fixed"] = 0] = "Fixed"; + PositionMode2[PositionMode2["Percent"] = 1] = "Percent"; + return PositionMode2; + })(PositionMode || {}); + var SpacingMode = /* @__PURE__ */ ((SpacingMode2) => { + SpacingMode2[SpacingMode2["Length"] = 0] = "Length"; + SpacingMode2[SpacingMode2["Fixed"] = 1] = "Fixed"; + SpacingMode2[SpacingMode2["Percent"] = 2] = "Percent"; + SpacingMode2[SpacingMode2["Proportional"] = 3] = "Proportional"; + return SpacingMode2; + })(SpacingMode || {}); + var RotateMode = /* @__PURE__ */ ((RotateMode2) => { + RotateMode2[RotateMode2["Tangent"] = 0] = "Tangent"; + RotateMode2[RotateMode2["Chain"] = 1] = "Chain"; + RotateMode2[RotateMode2["ChainScale"] = 2] = "ChainScale"; + return RotateMode2; + })(RotateMode || {}); + + // spine-core/src/PathConstraint.ts + var _PathConstraint = class { + /** The path constraint's setup pose data. */ + data; + /** The bones that will be modified by this path constraint. */ + bones; + /** The slot whose path attachment will be used to constrained the bones. */ + target; + /** The position along the path. */ + position = 0; + /** The spacing between bones. */ + spacing = 0; + mixRotate = 0; + mixX = 0; + mixY = 0; + spaces = new Array(); + positions = new Array(); + world = new Array(); + curves = new Array(); + lengths = new Array(); + segments = new Array(); + active = false; + constructor(data, skeleton) { + if (!data) + throw new Error("data cannot be null."); + if (!skeleton) + throw new Error("skeleton cannot be null."); + this.data = data; + this.bones = new Array(); + for (let i = 0, n = data.bones.length; i < n; i++) { + let bone = skeleton.findBone(data.bones[i].name); + if (!bone) + throw new Error(`Couldn't find bone ${data.bones[i].name}.`); + this.bones.push(bone); + } + let target = skeleton.findSlot(data.target.name); + if (!target) + throw new Error(`Couldn't find target bone ${data.target.name}`); + this.target = target; + this.position = data.position; + this.spacing = data.spacing; + this.mixRotate = data.mixRotate; + this.mixX = data.mixX; + this.mixY = data.mixY; + } + isActive() { + return this.active; + } + update() { + let attachment = this.target.getAttachment(); + if (!(attachment instanceof PathAttachment)) + return; + let mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY; + if (mixRotate == 0 && mixX == 0 && mixY == 0) + return; + let data = this.data; + let tangents = data.rotateMode == 0 /* Tangent */, scale = data.rotateMode == 2 /* ChainScale */; + let bones = this.bones; + let boneCount = bones.length, spacesCount = tangents ? boneCount : boneCount + 1; + let spaces = Utils.setArraySize(this.spaces, spacesCount), lengths = scale ? this.lengths = Utils.setArraySize(this.lengths, boneCount) : []; + let spacing = this.spacing; + switch (data.spacingMode) { + case 2 /* Percent */: + if (scale) { + for (let i = 0, n = spacesCount - 1; i < n; i++) { + let bone = bones[i]; + let setupLength = bone.data.length; + if (setupLength < _PathConstraint.epsilon) + lengths[i] = 0; + else { + let x = setupLength * bone.a, y = setupLength * bone.c; + lengths[i] = Math.sqrt(x * x + y * y); + } + } + } + Utils.arrayFill(spaces, 1, spacesCount, spacing); + break; + case 3 /* Proportional */: + let sum = 0; + for (let i = 0, n = spacesCount - 1; i < n; ) { + let bone = bones[i]; + let setupLength = bone.data.length; + if (setupLength < _PathConstraint.epsilon) { + if (scale) + lengths[i] = 0; + spaces[++i] = spacing; + } else { + let x = setupLength * bone.a, y = setupLength * bone.c; + let length = Math.sqrt(x * x + y * y); + if (scale) + lengths[i] = length; + spaces[++i] = length; + sum += length; + } + } + if (sum > 0) { + sum = spacesCount / sum * spacing; + for (let i = 1; i < spacesCount; i++) + spaces[i] *= sum; + } + break; + default: + let lengthSpacing = data.spacingMode == 0 /* Length */; + for (let i = 0, n = spacesCount - 1; i < n; ) { + let bone = bones[i]; + let setupLength = bone.data.length; + if (setupLength < _PathConstraint.epsilon) { + if (scale) + lengths[i] = 0; + spaces[++i] = spacing; + } else { + let x = setupLength * bone.a, y = setupLength * bone.c; + let length = Math.sqrt(x * x + y * y); + if (scale) + lengths[i] = length; + spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength; + } + } + } + let positions = this.computeWorldPositions(attachment, spacesCount, tangents); + let boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation; + let tip = false; + if (offsetRotation == 0) + tip = data.rotateMode == 1 /* Chain */; + else { + tip = false; + let p = this.target.bone; + offsetRotation *= p.a * p.d - p.b * p.c > 0 ? MathUtils.degRad : -MathUtils.degRad; + } + for (let i = 0, p = 3; i < boneCount; i++, p += 3) { + let bone = bones[i]; + bone.worldX += (boneX - bone.worldX) * mixX; + bone.worldY += (boneY - bone.worldY) * mixY; + let x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY; + if (scale) { + let length = lengths[i]; + if (length != 0) { + let s = (Math.sqrt(dx * dx + dy * dy) / length - 1) * mixRotate + 1; + bone.a *= s; + bone.c *= s; + } + } + boneX = x; + boneY = y; + if (mixRotate > 0) { + let a = bone.a, b = bone.b, c = bone.c, d = bone.d, r = 0, cos = 0, sin = 0; + if (tangents) + r = positions[p - 1]; + else if (spaces[i + 1] == 0) + r = positions[p + 2]; + else + r = Math.atan2(dy, dx); + r -= Math.atan2(c, a); + if (tip) { + cos = Math.cos(r); + sin = Math.sin(r); + let length = bone.data.length; + boneX += (length * (cos * a - sin * c) - dx) * mixRotate; + boneY += (length * (sin * a + cos * c) - dy) * mixRotate; + } else { + r += offsetRotation; + } + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + r *= mixRotate; + cos = Math.cos(r); + sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + bone.updateAppliedTransform(); + } + } + computeWorldPositions(path, spacesCount, tangents) { + let target = this.target; + let position = this.position; + let spaces = this.spaces, out = Utils.setArraySize(this.positions, spacesCount * 3 + 2), world = this.world; + let closed2 = path.closed; + let verticesLength = path.worldVerticesLength, curveCount = verticesLength / 6, prevCurve = _PathConstraint.NONE; + if (!path.constantSpeed) { + let lengths = path.lengths; + curveCount -= closed2 ? 1 : 2; + let pathLength2 = lengths[curveCount]; + if (this.data.positionMode == 1 /* Percent */) + position *= pathLength2; + let multiplier2; + switch (this.data.spacingMode) { + case 2 /* Percent */: + multiplier2 = pathLength2; + break; + case 3 /* Proportional */: + multiplier2 = pathLength2 / spacesCount; + break; + default: + multiplier2 = 1; + } + world = Utils.setArraySize(this.world, 8); + for (let i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { + let space = spaces[i] * multiplier2; + position += space; + let p = position; + if (closed2) { + p %= pathLength2; + if (p < 0) + p += pathLength2; + curve = 0; + } else if (p < 0) { + if (prevCurve != _PathConstraint.BEFORE) { + prevCurve = _PathConstraint.BEFORE; + path.computeWorldVertices(target, 2, 4, world, 0, 2); + } + this.addBeforePosition(p, world, 0, out, o); + continue; + } else if (p > pathLength2) { + if (prevCurve != _PathConstraint.AFTER) { + prevCurve = _PathConstraint.AFTER; + path.computeWorldVertices(target, verticesLength - 6, 4, world, 0, 2); + } + this.addAfterPosition(p - pathLength2, world, 0, out, o); + continue; + } + for (; ; curve++) { + let length = lengths[curve]; + if (p > length) + continue; + if (curve == 0) + p /= length; + else { + let prev = lengths[curve - 1]; + p = (p - prev) / (length - prev); + } + break; + } + if (curve != prevCurve) { + prevCurve = curve; + if (closed2 && curve == curveCount) { + path.computeWorldVertices(target, verticesLength - 4, 4, world, 0, 2); + path.computeWorldVertices(target, 0, 4, world, 4, 2); + } else + path.computeWorldVertices(target, curve * 6 + 2, 8, world, 0, 2); + } + this.addCurvePosition( + p, + world[0], + world[1], + world[2], + world[3], + world[4], + world[5], + world[6], + world[7], + out, + o, + tangents || i > 0 && space == 0 + ); + } + return out; + } + if (closed2) { + verticesLength += 2; + world = Utils.setArraySize(this.world, verticesLength); + path.computeWorldVertices(target, 2, verticesLength - 4, world, 0, 2); + path.computeWorldVertices(target, 0, 2, world, verticesLength - 4, 2); + world[verticesLength - 2] = world[0]; + world[verticesLength - 1] = world[1]; + } else { + curveCount--; + verticesLength -= 4; + world = Utils.setArraySize(this.world, verticesLength); + path.computeWorldVertices(target, 2, verticesLength, world, 0, 2); + } + let curves = Utils.setArraySize(this.curves, curveCount); + let pathLength = 0; + let x1 = world[0], y1 = world[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0; + let tmpx = 0, tmpy = 0, dddfx = 0, dddfy = 0, ddfx = 0, ddfy = 0, dfx = 0, dfy = 0; + for (let i = 0, w = 2; i < curveCount; i++, w += 6) { + cx1 = world[w]; + cy1 = world[w + 1]; + cx2 = world[w + 2]; + cy2 = world[w + 3]; + x2 = world[w + 4]; + y2 = world[w + 5]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.1875; + tmpy = (y1 - cy1 * 2 + cy2) * 0.1875; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + curves[i] = pathLength; + x1 = x2; + y1 = y2; + } + if (this.data.positionMode == 1 /* Percent */) + position *= pathLength; + let multiplier; + switch (this.data.spacingMode) { + case 2 /* Percent */: + multiplier = pathLength; + break; + case 3 /* Proportional */: + multiplier = pathLength / spacesCount; + break; + default: + multiplier = 1; + } + let segments = this.segments; + let curveLength = 0; + for (let i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { + let space = spaces[i] * multiplier; + position += space; + let p = position; + if (closed2) { + p %= pathLength; + if (p < 0) + p += pathLength; + curve = 0; + } else if (p < 0) { + this.addBeforePosition(p, world, 0, out, o); + continue; + } else if (p > pathLength) { + this.addAfterPosition(p - pathLength, world, verticesLength - 4, out, o); + continue; + } + for (; ; curve++) { + let length = curves[curve]; + if (p > length) + continue; + if (curve == 0) + p /= length; + else { + let prev = curves[curve - 1]; + p = (p - prev) / (length - prev); + } + break; + } + if (curve != prevCurve) { + prevCurve = curve; + let ii = curve * 6; + x1 = world[ii]; + y1 = world[ii + 1]; + cx1 = world[ii + 2]; + cy1 = world[ii + 3]; + cx2 = world[ii + 4]; + cy2 = world[ii + 5]; + x2 = world[ii + 6]; + y2 = world[ii + 7]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.03; + tmpy = (y1 - cy1 * 2 + cy2) * 0.03; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 6e-3; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 6e-3; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667; + curveLength = Math.sqrt(dfx * dfx + dfy * dfy); + segments[0] = curveLength; + for (ii = 1; ii < 8; ii++) { + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[ii] = curveLength; + } + dfx += ddfx; + dfy += ddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[8] = curveLength; + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[9] = curveLength; + segment = 0; + } + p *= curveLength; + for (; ; segment++) { + let length = segments[segment]; + if (p > length) + continue; + if (segment == 0) + p /= length; + else { + let prev = segments[segment - 1]; + p = segment + (p - prev) / (length - prev); + } + break; + } + this.addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || i > 0 && space == 0); + } + return out; + } + addBeforePosition(p, temp, i, out, o) { + let x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + } + addAfterPosition(p, temp, i, out, o) { + let x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + } + addCurvePosition(p, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents) { + if (p == 0 || isNaN(p)) { + out[o] = x1; + out[o + 1] = y1; + out[o + 2] = Math.atan2(cy1 - y1, cx1 - x1); + return; + } + let tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u; + let ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p; + let x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; + out[o] = x; + out[o + 1] = y; + if (tangents) { + if (p < 1e-3) + out[o + 2] = Math.atan2(cy1 - y1, cx1 - x1); + else + out[o + 2] = Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); + } + } + }; + var PathConstraint = _PathConstraint; + __publicField(PathConstraint, "NONE", -1); + __publicField(PathConstraint, "BEFORE", -2); + __publicField(PathConstraint, "AFTER", -3); + __publicField(PathConstraint, "epsilon", 1e-5); + + // spine-core/src/Slot.ts + var Slot = class { + /** The slot's setup pose data. */ + data; + /** The bone this slot belongs to. */ + bone; + /** The color used to tint the slot's attachment. If {@link #getDarkColor()} is set, this is used as the light color for two + * color tinting. */ + color; + /** The dark color used to tint the slot's attachment for two color tinting, or null if two color tinting is not used. The dark + * color's alpha is not used. */ + darkColor = null; + attachment = null; + attachmentState = 0; + /** The index of the texture region to display when the slot's attachment has a {@link Sequence}. -1 represents the + * {@link Sequence#getSetupIndex()}. */ + sequenceIndex = -1; + /** Values to deform the slot's attachment. For an unweighted mesh, the entries are local positions for each vertex. For a + * weighted mesh, the entries are an offset for each vertex which will be added to the mesh's local vertex positions. + * + * See {@link VertexAttachment#computeWorldVertices()} and {@link DeformTimeline}. */ + deform = new Array(); + constructor(data, bone) { + if (!data) + throw new Error("data cannot be null."); + if (!bone) + throw new Error("bone cannot be null."); + this.data = data; + this.bone = bone; + this.color = new Color(); + this.darkColor = !data.darkColor ? null : new Color(); + this.setToSetupPose(); + } + /** The skeleton this slot belongs to. */ + getSkeleton() { + return this.bone.skeleton; + } + /** The current attachment for the slot, or null if the slot has no attachment. */ + getAttachment() { + return this.attachment; + } + /** Sets the slot's attachment and, if the attachment changed, resets {@link #sequenceIndex} and clears the {@link #deform}. + * The deform is not cleared if the old attachment has the same {@link VertexAttachment#getTimelineAttachment()} as the + * specified attachment. */ + setAttachment(attachment) { + if (this.attachment == attachment) + return; + if (!(attachment instanceof VertexAttachment) || !(this.attachment instanceof VertexAttachment) || attachment.timelineAttachment != this.attachment.timelineAttachment) { + this.deform.length = 0; + } + this.attachment = attachment; + this.sequenceIndex = -1; + } + /** Sets this slot to the setup pose. */ + setToSetupPose() { + this.color.setFromColor(this.data.color); + if (this.darkColor) + this.darkColor.setFromColor(this.data.darkColor); + if (!this.data.attachmentName) + this.attachment = null; + else { + this.attachment = null; + this.setAttachment(this.bone.skeleton.getAttachment(this.data.index, this.data.attachmentName)); + } + } + }; + + // spine-core/src/TransformConstraint.ts + var TransformConstraint = class { + /** The transform constraint's setup pose data. */ + data; + /** The bones that will be modified by this transform constraint. */ + bones; + /** The target bone whose world transform will be copied to the constrained bones. */ + target; + mixRotate = 0; + mixX = 0; + mixY = 0; + mixScaleX = 0; + mixScaleY = 0; + mixShearY = 0; + temp = new Vector2(); + active = false; + constructor(data, skeleton) { + if (!data) + throw new Error("data cannot be null."); + if (!skeleton) + throw new Error("skeleton cannot be null."); + this.data = data; + this.mixRotate = data.mixRotate; + this.mixX = data.mixX; + this.mixY = data.mixY; + this.mixScaleX = data.mixScaleX; + this.mixScaleY = data.mixScaleY; + this.mixShearY = data.mixShearY; + this.bones = new Array(); + for (let i = 0; i < data.bones.length; i++) { + let bone = skeleton.findBone(data.bones[i].name); + if (!bone) + throw new Error(`Couldn't find bone ${data.bones[i].name}.`); + this.bones.push(bone); + } + let target = skeleton.findBone(data.target.name); + if (!target) + throw new Error(`Couldn't find target bone ${data.target.name}.`); + this.target = target; + } + isActive() { + return this.active; + } + update() { + if (this.mixRotate == 0 && this.mixX == 0 && this.mixY == 0 && this.mixScaleX == 0 && this.mixScaleY == 0 && this.mixShearY == 0) + return; + if (this.data.local) { + if (this.data.relative) + this.applyRelativeLocal(); + else + this.applyAbsoluteLocal(); + } else { + if (this.data.relative) + this.applyRelativeWorld(); + else + this.applyAbsoluteWorld(); + } + } + applyAbsoluteWorld() { + let mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX, mixScaleY = this.mixScaleY, mixShearY = this.mixShearY; + let translate = mixX != 0 || mixY != 0; + let target = this.target; + let ta = target.a, tb = target.b, tc = target.c, td = target.d; + let degRadReflect = ta * td - tb * tc > 0 ? MathUtils.degRad : -MathUtils.degRad; + let offsetRotation = this.data.offsetRotation * degRadReflect; + let offsetShearY = this.data.offsetShearY * degRadReflect; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (mixRotate != 0) { + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + let r = Math.atan2(tc, ta) - Math.atan2(c, a) + offsetRotation; + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + r *= mixRotate; + let cos = Math.cos(r), sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + if (translate) { + let temp = this.temp; + target.localToWorld(temp.set(this.data.offsetX, this.data.offsetY)); + bone.worldX += (temp.x - bone.worldX) * mixX; + bone.worldY += (temp.y - bone.worldY) * mixY; + } + if (mixScaleX != 0) { + let s = Math.sqrt(bone.a * bone.a + bone.c * bone.c); + if (s != 0) + s = (s + (Math.sqrt(ta * ta + tc * tc) - s + this.data.offsetScaleX) * mixScaleX) / s; + bone.a *= s; + bone.c *= s; + } + if (mixScaleY != 0) { + let s = Math.sqrt(bone.b * bone.b + bone.d * bone.d); + if (s != 0) + s = (s + (Math.sqrt(tb * tb + td * td) - s + this.data.offsetScaleY) * mixScaleY) / s; + bone.b *= s; + bone.d *= s; + } + if (mixShearY > 0) { + let b = bone.b, d = bone.d; + let by = Math.atan2(d, b); + let r = Math.atan2(td, tb) - Math.atan2(tc, ta) - (by - Math.atan2(bone.c, bone.a)); + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + r = by + (r + offsetShearY) * mixShearY; + let s = Math.sqrt(b * b + d * d); + bone.b = Math.cos(r) * s; + bone.d = Math.sin(r) * s; + } + bone.updateAppliedTransform(); + } + } + applyRelativeWorld() { + let mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX, mixScaleY = this.mixScaleY, mixShearY = this.mixShearY; + let translate = mixX != 0 || mixY != 0; + let target = this.target; + let ta = target.a, tb = target.b, tc = target.c, td = target.d; + let degRadReflect = ta * td - tb * tc > 0 ? MathUtils.degRad : -MathUtils.degRad; + let offsetRotation = this.data.offsetRotation * degRadReflect, offsetShearY = this.data.offsetShearY * degRadReflect; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (mixRotate != 0) { + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + let r = Math.atan2(tc, ta) + offsetRotation; + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + r *= mixRotate; + let cos = Math.cos(r), sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + if (translate) { + let temp = this.temp; + target.localToWorld(temp.set(this.data.offsetX, this.data.offsetY)); + bone.worldX += temp.x * mixX; + bone.worldY += temp.y * mixY; + } + if (mixScaleX != 0) { + let s = (Math.sqrt(ta * ta + tc * tc) - 1 + this.data.offsetScaleX) * mixScaleX + 1; + bone.a *= s; + bone.c *= s; + } + if (mixScaleY != 0) { + let s = (Math.sqrt(tb * tb + td * td) - 1 + this.data.offsetScaleY) * mixScaleY + 1; + bone.b *= s; + bone.d *= s; + } + if (mixShearY > 0) { + let r = Math.atan2(td, tb) - Math.atan2(tc, ta); + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + let b = bone.b, d = bone.d; + r = Math.atan2(d, b) + (r - MathUtils.PI / 2 + offsetShearY) * mixShearY; + let s = Math.sqrt(b * b + d * d); + bone.b = Math.cos(r) * s; + bone.d = Math.sin(r) * s; + } + bone.updateAppliedTransform(); + } + } + applyAbsoluteLocal() { + let mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX, mixScaleY = this.mixScaleY, mixShearY = this.mixShearY; + let target = this.target; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + let rotation = bone.arotation; + if (mixRotate != 0) { + let r = target.arotation - rotation + this.data.offsetRotation; + r -= (16384 - (16384.499999999996 - r / 360 | 0)) * 360; + rotation += r * mixRotate; + } + let x = bone.ax, y = bone.ay; + x += (target.ax - x + this.data.offsetX) * mixX; + y += (target.ay - y + this.data.offsetY) * mixY; + let scaleX = bone.ascaleX, scaleY = bone.ascaleY; + if (mixScaleX != 0 && scaleX != 0) + scaleX = (scaleX + (target.ascaleX - scaleX + this.data.offsetScaleX) * mixScaleX) / scaleX; + if (mixScaleY != 0 && scaleY != 0) + scaleY = (scaleY + (target.ascaleY - scaleY + this.data.offsetScaleY) * mixScaleY) / scaleY; + let shearY = bone.ashearY; + if (mixShearY != 0) { + let r = target.ashearY - shearY + this.data.offsetShearY; + r -= (16384 - (16384.499999999996 - r / 360 | 0)) * 360; + shearY += r * mixShearY; + } + bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY); + } + } + applyRelativeLocal() { + let mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX, mixScaleY = this.mixScaleY, mixShearY = this.mixShearY; + let target = this.target; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + let rotation = bone.arotation + (target.arotation + this.data.offsetRotation) * mixRotate; + let x = bone.ax + (target.ax + this.data.offsetX) * mixX; + let y = bone.ay + (target.ay + this.data.offsetY) * mixY; + let scaleX = bone.ascaleX * ((target.ascaleX - 1 + this.data.offsetScaleX) * mixScaleX + 1); + let scaleY = bone.ascaleY * ((target.ascaleY - 1 + this.data.offsetScaleY) * mixScaleY + 1); + let shearY = bone.ashearY + (target.ashearY + this.data.offsetShearY) * mixShearY; + bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY); + } + } + }; + + // spine-core/src/Skeleton.ts + var _Skeleton = class { + /** The skeleton's setup pose data. */ + data; + /** The skeleton's bones, sorted parent first. The root bone is always the first bone. */ + bones; + /** The skeleton's slots. */ + slots; + /** The skeleton's slots in the order they should be drawn. The returned array may be modified to change the draw order. */ + drawOrder; + /** The skeleton's IK constraints. */ + ikConstraints; + /** The skeleton's transform constraints. */ + transformConstraints; + /** The skeleton's path constraints. */ + pathConstraints; + /** The list of bones and constraints, sorted in the order they should be updated, as computed by {@link #updateCache()}. */ + _updateCache = new Array(); + /** The skeleton's current skin. May be null. */ + skin = null; + /** The color to tint all the skeleton's attachments. */ + color; + /** Scales the entire skeleton on the X axis. This affects all bones, even if the bone's transform mode disallows scale + * inheritance. */ + scaleX = 1; + /** Scales the entire skeleton on the Y axis. This affects all bones, even if the bone's transform mode disallows scale + * inheritance. */ + _scaleY = 1; + get scaleY() { + return _Skeleton.yDown ? -this._scaleY : this._scaleY; + } + set scaleY(scaleY) { + this._scaleY = scaleY; + } + /** Sets the skeleton X position, which is added to the root bone worldX position. */ + x = 0; + /** Sets the skeleton Y position, which is added to the root bone worldY position. */ + y = 0; + constructor(data) { + if (!data) + throw new Error("data cannot be null."); + this.data = data; + this.bones = new Array(); + for (let i = 0; i < data.bones.length; i++) { + let boneData = data.bones[i]; + let bone; + if (!boneData.parent) + bone = new Bone(boneData, this, null); + else { + let parent = this.bones[boneData.parent.index]; + bone = new Bone(boneData, this, parent); + parent.children.push(bone); + } + this.bones.push(bone); + } + this.slots = new Array(); + this.drawOrder = new Array(); + for (let i = 0; i < data.slots.length; i++) { + let slotData = data.slots[i]; + let bone = this.bones[slotData.boneData.index]; + let slot = new Slot(slotData, bone); + this.slots.push(slot); + this.drawOrder.push(slot); + } + this.ikConstraints = new Array(); + for (let i = 0; i < data.ikConstraints.length; i++) { + let ikConstraintData = data.ikConstraints[i]; + this.ikConstraints.push(new IkConstraint(ikConstraintData, this)); + } + this.transformConstraints = new Array(); + for (let i = 0; i < data.transformConstraints.length; i++) { + let transformConstraintData = data.transformConstraints[i]; + this.transformConstraints.push(new TransformConstraint(transformConstraintData, this)); + } + this.pathConstraints = new Array(); + for (let i = 0; i < data.pathConstraints.length; i++) { + let pathConstraintData = data.pathConstraints[i]; + this.pathConstraints.push(new PathConstraint(pathConstraintData, this)); + } + this.color = new Color(1, 1, 1, 1); + this.updateCache(); + } + /** Caches information about bones and constraints. Must be called if the {@link #getSkin()} is modified or if bones, + * constraints, or weighted path attachments are added or removed. */ + updateCache() { + let updateCache = this._updateCache; + updateCache.length = 0; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + bone.sorted = bone.data.skinRequired; + bone.active = !bone.sorted; + } + if (this.skin) { + let skinBones = this.skin.bones; + for (let i = 0, n = this.skin.bones.length; i < n; i++) { + let bone = this.bones[skinBones[i].index]; + do { + bone.sorted = false; + bone.active = true; + bone = bone.parent; + } while (bone); + } + } + let ikConstraints = this.ikConstraints; + let transformConstraints = this.transformConstraints; + let pathConstraints = this.pathConstraints; + let ikCount = ikConstraints.length, transformCount = transformConstraints.length, pathCount = pathConstraints.length; + let constraintCount = ikCount + transformCount + pathCount; + outer: + for (let i = 0; i < constraintCount; i++) { + for (let ii = 0; ii < ikCount; ii++) { + let constraint = ikConstraints[ii]; + if (constraint.data.order == i) { + this.sortIkConstraint(constraint); + continue outer; + } + } + for (let ii = 0; ii < transformCount; ii++) { + let constraint = transformConstraints[ii]; + if (constraint.data.order == i) { + this.sortTransformConstraint(constraint); + continue outer; + } + } + for (let ii = 0; ii < pathCount; ii++) { + let constraint = pathConstraints[ii]; + if (constraint.data.order == i) { + this.sortPathConstraint(constraint); + continue outer; + } + } + } + for (let i = 0, n = bones.length; i < n; i++) + this.sortBone(bones[i]); + } + sortIkConstraint(constraint) { + constraint.active = constraint.target.isActive() && (!constraint.data.skinRequired || this.skin && Utils.contains(this.skin.constraints, constraint.data, true)); + if (!constraint.active) + return; + let target = constraint.target; + this.sortBone(target); + let constrained = constraint.bones; + let parent = constrained[0]; + this.sortBone(parent); + if (constrained.length == 1) { + this._updateCache.push(constraint); + this.sortReset(parent.children); + } else { + let child = constrained[constrained.length - 1]; + this.sortBone(child); + this._updateCache.push(constraint); + this.sortReset(parent.children); + child.sorted = true; + } + } + sortPathConstraint(constraint) { + constraint.active = constraint.target.bone.isActive() && (!constraint.data.skinRequired || this.skin && Utils.contains(this.skin.constraints, constraint.data, true)); + if (!constraint.active) + return; + let slot = constraint.target; + let slotIndex = slot.data.index; + let slotBone = slot.bone; + if (this.skin) + this.sortPathConstraintAttachment(this.skin, slotIndex, slotBone); + if (this.data.defaultSkin && this.data.defaultSkin != this.skin) + this.sortPathConstraintAttachment(this.data.defaultSkin, slotIndex, slotBone); + for (let i = 0, n = this.data.skins.length; i < n; i++) + this.sortPathConstraintAttachment(this.data.skins[i], slotIndex, slotBone); + let attachment = slot.getAttachment(); + if (attachment instanceof PathAttachment) + this.sortPathConstraintAttachmentWith(attachment, slotBone); + let constrained = constraint.bones; + let boneCount = constrained.length; + for (let i = 0; i < boneCount; i++) + this.sortBone(constrained[i]); + this._updateCache.push(constraint); + for (let i = 0; i < boneCount; i++) + this.sortReset(constrained[i].children); + for (let i = 0; i < boneCount; i++) + constrained[i].sorted = true; + } + sortTransformConstraint(constraint) { + constraint.active = constraint.target.isActive() && (!constraint.data.skinRequired || this.skin && Utils.contains(this.skin.constraints, constraint.data, true)); + if (!constraint.active) + return; + this.sortBone(constraint.target); + let constrained = constraint.bones; + let boneCount = constrained.length; + if (constraint.data.local) { + for (let i = 0; i < boneCount; i++) { + let child = constrained[i]; + this.sortBone(child.parent); + this.sortBone(child); + } + } else { + for (let i = 0; i < boneCount; i++) { + this.sortBone(constrained[i]); + } + } + this._updateCache.push(constraint); + for (let i = 0; i < boneCount; i++) + this.sortReset(constrained[i].children); + for (let i = 0; i < boneCount; i++) + constrained[i].sorted = true; + } + sortPathConstraintAttachment(skin, slotIndex, slotBone) { + let attachments = skin.attachments[slotIndex]; + if (!attachments) + return; + for (let key in attachments) { + this.sortPathConstraintAttachmentWith(attachments[key], slotBone); + } + } + sortPathConstraintAttachmentWith(attachment, slotBone) { + if (!(attachment instanceof PathAttachment)) + return; + let pathBones = attachment.bones; + if (!pathBones) + this.sortBone(slotBone); + else { + let bones = this.bones; + for (let i = 0, n = pathBones.length; i < n; ) { + let nn = pathBones[i++]; + nn += i; + while (i < nn) + this.sortBone(bones[pathBones[i++]]); + } + } + } + sortBone(bone) { + if (!bone) + return; + if (bone.sorted) + return; + let parent = bone.parent; + if (parent) + this.sortBone(parent); + bone.sorted = true; + this._updateCache.push(bone); + } + sortReset(bones) { + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (!bone.active) + continue; + if (bone.sorted) + this.sortReset(bone.children); + bone.sorted = false; + } + } + /** Updates the world transform for each bone and applies all constraints. + * + * See [World transforms](http://esotericsoftware.com/spine-runtime-skeletons#World-transforms) in the Spine + * Runtimes Guide. */ + updateWorldTransform() { + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + bone.ax = bone.x; + bone.ay = bone.y; + bone.arotation = bone.rotation; + bone.ascaleX = bone.scaleX; + bone.ascaleY = bone.scaleY; + bone.ashearX = bone.shearX; + bone.ashearY = bone.shearY; + } + let updateCache = this._updateCache; + for (let i = 0, n = updateCache.length; i < n; i++) + updateCache[i].update(); + } + updateWorldTransformWith(parent) { + let rootBone = this.getRootBone(); + if (!rootBone) + throw new Error("Root bone must not be null."); + let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + rootBone.worldX = pa * this.x + pb * this.y + parent.worldX; + rootBone.worldY = pc * this.x + pd * this.y + parent.worldY; + let rotationY = rootBone.rotation + 90 + rootBone.shearY; + let la = MathUtils.cosDeg(rootBone.rotation + rootBone.shearX) * rootBone.scaleX; + let lb = MathUtils.cosDeg(rotationY) * rootBone.scaleY; + let lc = MathUtils.sinDeg(rootBone.rotation + rootBone.shearX) * rootBone.scaleX; + let ld = MathUtils.sinDeg(rotationY) * rootBone.scaleY; + rootBone.a = (pa * la + pb * lc) * this.scaleX; + rootBone.b = (pa * lb + pb * ld) * this.scaleX; + rootBone.c = (pc * la + pd * lc) * this.scaleY; + rootBone.d = (pc * lb + pd * ld) * this.scaleY; + let updateCache = this._updateCache; + for (let i = 0, n = updateCache.length; i < n; i++) { + let updatable = updateCache[i]; + if (updatable != rootBone) + updatable.update(); + } + } + /** Sets the bones, constraints, and slots to their setup pose values. */ + setToSetupPose() { + this.setBonesToSetupPose(); + this.setSlotsToSetupPose(); + } + /** Sets the bones and constraints to their setup pose values. */ + setBonesToSetupPose() { + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) + bones[i].setToSetupPose(); + let ikConstraints = this.ikConstraints; + for (let i = 0, n = ikConstraints.length; i < n; i++) { + let constraint = ikConstraints[i]; + constraint.mix = constraint.data.mix; + constraint.softness = constraint.data.softness; + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } + let transformConstraints = this.transformConstraints; + for (let i = 0, n = transformConstraints.length; i < n; i++) { + let constraint = transformConstraints[i]; + let data = constraint.data; + constraint.mixRotate = data.mixRotate; + constraint.mixX = data.mixX; + constraint.mixY = data.mixY; + constraint.mixScaleX = data.mixScaleX; + constraint.mixScaleY = data.mixScaleY; + constraint.mixShearY = data.mixShearY; + } + let pathConstraints = this.pathConstraints; + for (let i = 0, n = pathConstraints.length; i < n; i++) { + let constraint = pathConstraints[i]; + let data = constraint.data; + constraint.position = data.position; + constraint.spacing = data.spacing; + constraint.mixRotate = data.mixRotate; + constraint.mixX = data.mixX; + constraint.mixY = data.mixY; + } + } + /** Sets the slots and draw order to their setup pose values. */ + setSlotsToSetupPose() { + let slots = this.slots; + Utils.arrayCopy(slots, 0, this.drawOrder, 0, slots.length); + for (let i = 0, n = slots.length; i < n; i++) + slots[i].setToSetupPose(); + } + /** @returns May return null. */ + getRootBone() { + if (this.bones.length == 0) + return null; + return this.bones[0]; + } + /** @returns May be null. */ + findBone(boneName) { + if (!boneName) + throw new Error("boneName cannot be null."); + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (bone.data.name == boneName) + return bone; + } + return null; + } + /** Finds a slot by comparing each slot's name. It is more efficient to cache the results of this method than to call it + * repeatedly. + * @returns May be null. */ + findSlot(slotName) { + if (!slotName) + throw new Error("slotName cannot be null."); + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + if (slot.data.name == slotName) + return slot; + } + return null; + } + /** Sets a skin by name. + * + * See {@link #setSkin()}. */ + setSkinByName(skinName) { + let skin = this.data.findSkin(skinName); + if (!skin) + throw new Error("Skin not found: " + skinName); + this.setSkin(skin); + } + /** Sets the skin used to look up attachments before looking in the {@link SkeletonData#defaultSkin default skin}. If the + * skin is changed, {@link #updateCache()} is called. + * + * Attachments from the new skin are attached if the corresponding attachment from the old skin was attached. If there was no + * old skin, each slot's setup mode attachment is attached from the new skin. + * + * After changing the skin, the visible attachments can be reset to those attached in the setup pose by calling + * {@link #setSlotsToSetupPose()}. Also, often {@link AnimationState#apply()} is called before the next time the + * skeleton is rendered to allow any attachment keys in the current animation(s) to hide or show attachments from the new skin. + * @param newSkin May be null. */ + setSkin(newSkin) { + if (newSkin == this.skin) + return; + if (newSkin) { + if (this.skin) + newSkin.attachAll(this, this.skin); + else { + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + let name = slot.data.attachmentName; + if (name) { + let attachment = newSkin.getAttachment(i, name); + if (attachment) + slot.setAttachment(attachment); + } + } + } + } + this.skin = newSkin; + this.updateCache(); + } + /** Finds an attachment by looking in the {@link #skin} and {@link SkeletonData#defaultSkin} using the slot name and attachment + * name. + * + * See {@link #getAttachment()}. + * @returns May be null. */ + getAttachmentByName(slotName, attachmentName) { + let slot = this.data.findSlot(slotName); + if (!slot) + throw new Error(`Can't find slot with name ${slotName}`); + return this.getAttachment(slot.index, attachmentName); + } + /** Finds an attachment by looking in the {@link #skin} and {@link SkeletonData#defaultSkin} using the slot index and + * attachment name. First the skin is checked and if the attachment was not found, the default skin is checked. + * + * See [Runtime skins](http://esotericsoftware.com/spine-runtime-skins) in the Spine Runtimes Guide. + * @returns May be null. */ + getAttachment(slotIndex, attachmentName) { + if (!attachmentName) + throw new Error("attachmentName cannot be null."); + if (this.skin) { + let attachment = this.skin.getAttachment(slotIndex, attachmentName); + if (attachment) + return attachment; + } + if (this.data.defaultSkin) + return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); + return null; + } + /** A convenience method to set an attachment by finding the slot with {@link #findSlot()}, finding the attachment with + * {@link #getAttachment()}, then setting the slot's {@link Slot#attachment}. + * @param attachmentName May be null to clear the slot's attachment. */ + setAttachment(slotName, attachmentName) { + if (!slotName) + throw new Error("slotName cannot be null."); + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + if (slot.data.name == slotName) { + let attachment = null; + if (attachmentName) { + attachment = this.getAttachment(i, attachmentName); + if (!attachment) + throw new Error("Attachment not found: " + attachmentName + ", for slot: " + slotName); + } + slot.setAttachment(attachment); + return; + } + } + throw new Error("Slot not found: " + slotName); + } + /** Finds an IK constraint by comparing each IK constraint's name. It is more efficient to cache the results of this method + * than to call it repeatedly. + * @return May be null. */ + findIkConstraint(constraintName) { + if (!constraintName) + throw new Error("constraintName cannot be null."); + let ikConstraints = this.ikConstraints; + for (let i = 0, n = ikConstraints.length; i < n; i++) { + let ikConstraint = ikConstraints[i]; + if (ikConstraint.data.name == constraintName) + return ikConstraint; + } + return null; + } + /** Finds a transform constraint by comparing each transform constraint's name. It is more efficient to cache the results of + * this method than to call it repeatedly. + * @return May be null. */ + findTransformConstraint(constraintName) { + if (!constraintName) + throw new Error("constraintName cannot be null."); + let transformConstraints = this.transformConstraints; + for (let i = 0, n = transformConstraints.length; i < n; i++) { + let constraint = transformConstraints[i]; + if (constraint.data.name == constraintName) + return constraint; + } + return null; + } + /** Finds a path constraint by comparing each path constraint's name. It is more efficient to cache the results of this method + * than to call it repeatedly. + * @return May be null. */ + findPathConstraint(constraintName) { + if (!constraintName) + throw new Error("constraintName cannot be null."); + let pathConstraints = this.pathConstraints; + for (let i = 0, n = pathConstraints.length; i < n; i++) { + let constraint = pathConstraints[i]; + if (constraint.data.name == constraintName) + return constraint; + } + return null; + } + /** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose as `{ x: number, y: number, width: number, height: number }`. + * Note that this method will create temporary objects which can add to garbage collection pressure. Use `getBounds()` if garbage collection is a concern. */ + getBoundsRect() { + let offset = new Vector2(); + let size = new Vector2(); + this.getBounds(offset, size); + return { x: offset.x, y: offset.y, width: size.x, height: size.y }; + } + /** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose. + * @param offset An output value, the distance from the skeleton origin to the bottom left corner of the AABB. + * @param size An output value, the width and height of the AABB. + * @param temp Working memory to temporarily store attachments' computed world vertices. */ + getBounds(offset, size, temp = new Array(2)) { + if (!offset) + throw new Error("offset cannot be null."); + if (!size) + throw new Error("size cannot be null."); + let drawOrder = this.drawOrder; + let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + for (let i = 0, n = drawOrder.length; i < n; i++) { + let slot = drawOrder[i]; + if (!slot.bone.active) + continue; + let verticesLength = 0; + let vertices = null; + let attachment = slot.getAttachment(); + if (attachment instanceof RegionAttachment) { + verticesLength = 8; + vertices = Utils.setArraySize(temp, verticesLength, 0); + attachment.computeWorldVertices(slot, vertices, 0, 2); + } else if (attachment instanceof MeshAttachment) { + let mesh = attachment; + verticesLength = mesh.worldVerticesLength; + vertices = Utils.setArraySize(temp, verticesLength, 0); + mesh.computeWorldVertices(slot, 0, verticesLength, vertices, 0, 2); + } + if (vertices) { + for (let ii = 0, nn = vertices.length; ii < nn; ii += 2) { + let x = vertices[ii], y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + } + offset.set(minX, minY); + size.set(maxX - minX, maxY - minY); + } + }; + var Skeleton = _Skeleton; + __publicField(Skeleton, "yDown", false); + + // spine-core/src/SkeletonData.ts + var SkeletonData = class { + /** The skeleton's name, which by default is the name of the skeleton data file, if possible. May be null. */ + name = null; + /** The skeleton's bones, sorted parent first. The root bone is always the first bone. */ + bones = new Array(); + // Ordered parents first. + /** The skeleton's slots. */ + slots = new Array(); + // Setup pose draw order. + skins = new Array(); + /** The skeleton's default skin. By default this skin contains all attachments that were not in a skin in Spine. + * + * See {@link Skeleton#getAttachmentByName()}. + * May be null. */ + defaultSkin = null; + /** The skeleton's events. */ + events = new Array(); + /** The skeleton's animations. */ + animations = new Array(); + /** The skeleton's IK constraints. */ + ikConstraints = new Array(); + /** The skeleton's transform constraints. */ + transformConstraints = new Array(); + /** The skeleton's path constraints. */ + pathConstraints = new Array(); + /** The X coordinate of the skeleton's axis aligned bounding box in the setup pose. */ + x = 0; + /** The Y coordinate of the skeleton's axis aligned bounding box in the setup pose. */ + y = 0; + /** The width of the skeleton's axis aligned bounding box in the setup pose. */ + width = 0; + /** The height of the skeleton's axis aligned bounding box in the setup pose. */ + height = 0; + /** The Spine version used to export the skeleton data, or null. */ + version = null; + /** The skeleton data hash. This value will change if any of the skeleton data has changed. May be null. */ + hash = null; + // Nonessential + /** The dopesheet FPS in Spine. Available only when nonessential data was exported. */ + fps = 0; + /** The path to the images directory as defined in Spine. Available only when nonessential data was exported. May be null. */ + imagesPath = null; + /** The path to the audio directory as defined in Spine. Available only when nonessential data was exported. May be null. */ + audioPath = null; + /** Finds a bone by comparing each bone's name. It is more efficient to cache the results of this method than to call it + * multiple times. + * @returns May be null. */ + findBone(boneName) { + if (!boneName) + throw new Error("boneName cannot be null."); + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (bone.name == boneName) + return bone; + } + return null; + } + /** Finds a slot by comparing each slot's name. It is more efficient to cache the results of this method than to call it + * multiple times. + * @returns May be null. */ + findSlot(slotName) { + if (!slotName) + throw new Error("slotName cannot be null."); + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + if (slot.name == slotName) + return slot; + } + return null; + } + /** Finds a skin by comparing each skin's name. It is more efficient to cache the results of this method than to call it + * multiple times. + * @returns May be null. */ + findSkin(skinName) { + if (!skinName) + throw new Error("skinName cannot be null."); + let skins = this.skins; + for (let i = 0, n = skins.length; i < n; i++) { + let skin = skins[i]; + if (skin.name == skinName) + return skin; + } + return null; + } + /** Finds an event by comparing each events's name. It is more efficient to cache the results of this method than to call it + * multiple times. + * @returns May be null. */ + findEvent(eventDataName) { + if (!eventDataName) + throw new Error("eventDataName cannot be null."); + let events = this.events; + for (let i = 0, n = events.length; i < n; i++) { + let event = events[i]; + if (event.name == eventDataName) + return event; + } + return null; + } + /** Finds an animation by comparing each animation's name. It is more efficient to cache the results of this method than to + * call it multiple times. + * @returns May be null. */ + findAnimation(animationName) { + if (!animationName) + throw new Error("animationName cannot be null."); + let animations = this.animations; + for (let i = 0, n = animations.length; i < n; i++) { + let animation = animations[i]; + if (animation.name == animationName) + return animation; + } + return null; + } + /** Finds an IK constraint by comparing each IK constraint's name. It is more efficient to cache the results of this method + * than to call it multiple times. + * @return May be null. */ + findIkConstraint(constraintName) { + if (!constraintName) + throw new Error("constraintName cannot be null."); + let ikConstraints = this.ikConstraints; + for (let i = 0, n = ikConstraints.length; i < n; i++) { + let constraint = ikConstraints[i]; + if (constraint.name == constraintName) + return constraint; + } + return null; + } + /** Finds a transform constraint by comparing each transform constraint's name. It is more efficient to cache the results of + * this method than to call it multiple times. + * @return May be null. */ + findTransformConstraint(constraintName) { + if (!constraintName) + throw new Error("constraintName cannot be null."); + let transformConstraints = this.transformConstraints; + for (let i = 0, n = transformConstraints.length; i < n; i++) { + let constraint = transformConstraints[i]; + if (constraint.name == constraintName) + return constraint; + } + return null; + } + /** Finds a path constraint by comparing each path constraint's name. It is more efficient to cache the results of this method + * than to call it multiple times. + * @return May be null. */ + findPathConstraint(constraintName) { + if (!constraintName) + throw new Error("constraintName cannot be null."); + let pathConstraints = this.pathConstraints; + for (let i = 0, n = pathConstraints.length; i < n; i++) { + let constraint = pathConstraints[i]; + if (constraint.name == constraintName) + return constraint; + } + return null; + } + }; + + // spine-core/src/Skin.ts + var SkinEntry = class { + constructor(slotIndex = 0, name, attachment) { + this.slotIndex = slotIndex; + this.name = name; + this.attachment = attachment; + } + }; + var Skin = class { + /** The skin's name, which is unique across all skins in the skeleton. */ + name; + attachments = new Array(); + bones = Array(); + constraints = new Array(); + constructor(name) { + if (!name) + throw new Error("name cannot be null."); + this.name = name; + } + /** Adds an attachment to the skin for the specified slot index and name. */ + setAttachment(slotIndex, name, attachment) { + if (!attachment) + throw new Error("attachment cannot be null."); + let attachments = this.attachments; + if (slotIndex >= attachments.length) + attachments.length = slotIndex + 1; + if (!attachments[slotIndex]) + attachments[slotIndex] = {}; + attachments[slotIndex][name] = attachment; + } + /** Adds all attachments, bones, and constraints from the specified skin to this skin. */ + addSkin(skin) { + for (let i = 0; i < skin.bones.length; i++) { + let bone = skin.bones[i]; + let contained = false; + for (let ii = 0; ii < this.bones.length; ii++) { + if (this.bones[ii] == bone) { + contained = true; + break; + } + } + if (!contained) + this.bones.push(bone); + } + for (let i = 0; i < skin.constraints.length; i++) { + let constraint = skin.constraints[i]; + let contained = false; + for (let ii = 0; ii < this.constraints.length; ii++) { + if (this.constraints[ii] == constraint) { + contained = true; + break; + } + } + if (!contained) + this.constraints.push(constraint); + } + let attachments = skin.getAttachments(); + for (let i = 0; i < attachments.length; i++) { + var attachment = attachments[i]; + this.setAttachment(attachment.slotIndex, attachment.name, attachment.attachment); + } + } + /** Adds all bones and constraints and copies of all attachments from the specified skin to this skin. Mesh attachments are not + * copied, instead a new linked mesh is created. The attachment copies can be modified without affecting the originals. */ + copySkin(skin) { + for (let i = 0; i < skin.bones.length; i++) { + let bone = skin.bones[i]; + let contained = false; + for (let ii = 0; ii < this.bones.length; ii++) { + if (this.bones[ii] == bone) { + contained = true; + break; + } + } + if (!contained) + this.bones.push(bone); + } + for (let i = 0; i < skin.constraints.length; i++) { + let constraint = skin.constraints[i]; + let contained = false; + for (let ii = 0; ii < this.constraints.length; ii++) { + if (this.constraints[ii] == constraint) { + contained = true; + break; + } + } + if (!contained) + this.constraints.push(constraint); + } + let attachments = skin.getAttachments(); + for (let i = 0; i < attachments.length; i++) { + var attachment = attachments[i]; + if (!attachment.attachment) + continue; + if (attachment.attachment instanceof MeshAttachment) { + attachment.attachment = attachment.attachment.newLinkedMesh(); + this.setAttachment(attachment.slotIndex, attachment.name, attachment.attachment); + } else { + attachment.attachment = attachment.attachment.copy(); + this.setAttachment(attachment.slotIndex, attachment.name, attachment.attachment); + } + } + } + /** Returns the attachment for the specified slot index and name, or null. */ + getAttachment(slotIndex, name) { + let dictionary = this.attachments[slotIndex]; + return dictionary ? dictionary[name] : null; + } + /** Removes the attachment in the skin for the specified slot index and name, if any. */ + removeAttachment(slotIndex, name) { + let dictionary = this.attachments[slotIndex]; + if (dictionary) + delete dictionary[name]; + } + /** Returns all attachments in this skin. */ + getAttachments() { + let entries = new Array(); + for (var i = 0; i < this.attachments.length; i++) { + let slotAttachments = this.attachments[i]; + if (slotAttachments) { + for (let name in slotAttachments) { + let attachment = slotAttachments[name]; + if (attachment) + entries.push(new SkinEntry(i, name, attachment)); + } + } + } + return entries; + } + /** Returns all attachments in this skin for the specified slot index. */ + getAttachmentsForSlot(slotIndex, attachments) { + let slotAttachments = this.attachments[slotIndex]; + if (slotAttachments) { + for (let name in slotAttachments) { + let attachment = slotAttachments[name]; + if (attachment) + attachments.push(new SkinEntry(slotIndex, name, attachment)); + } + } + } + /** Clears all attachments, bones, and constraints. */ + clear() { + this.attachments.length = 0; + this.bones.length = 0; + this.constraints.length = 0; + } + /** Attach each attachment in this skin if the corresponding attachment in the old skin is currently attached. */ + attachAll(skeleton, oldSkin) { + let slotIndex = 0; + for (let i = 0; i < skeleton.slots.length; i++) { + let slot = skeleton.slots[i]; + let slotAttachment = slot.getAttachment(); + if (slotAttachment && slotIndex < oldSkin.attachments.length) { + let dictionary = oldSkin.attachments[slotIndex]; + for (let key in dictionary) { + let skinAttachment = dictionary[key]; + if (slotAttachment == skinAttachment) { + let attachment = this.getAttachment(slotIndex, key); + if (attachment) + slot.setAttachment(attachment); + break; + } + } + } + slotIndex++; + } + } + }; + + // spine-core/src/SlotData.ts + var SlotData = class { + /** The index of the slot in {@link Skeleton#getSlots()}. */ + index = 0; + /** The name of the slot, which is unique across all slots in the skeleton. */ + name; + /** The bone this slot belongs to. */ + boneData; + /** The color used to tint the slot's attachment. If {@link #getDarkColor()} is set, this is used as the light color for two + * color tinting. */ + color = new Color(1, 1, 1, 1); + /** The dark color used to tint the slot's attachment for two color tinting, or null if two color tinting is not used. The dark + * color's alpha is not used. */ + darkColor = null; + /** The name of the attachment that is visible for this slot in the setup pose, or null if no attachment is visible. */ + attachmentName = null; + /** The blend mode for drawing the slot's attachment. */ + blendMode = BlendMode.Normal; + constructor(index, name, boneData) { + if (index < 0) + throw new Error("index must be >= 0."); + if (!name) + throw new Error("name cannot be null."); + if (!boneData) + throw new Error("boneData cannot be null."); + this.index = index; + this.name = name; + this.boneData = boneData; + } + }; + var BlendMode = /* @__PURE__ */ ((BlendMode3) => { + BlendMode3[BlendMode3["Normal"] = 0] = "Normal"; + BlendMode3[BlendMode3["Additive"] = 1] = "Additive"; + BlendMode3[BlendMode3["Multiply"] = 2] = "Multiply"; + BlendMode3[BlendMode3["Screen"] = 3] = "Screen"; + return BlendMode3; + })(BlendMode || {}); + + // spine-core/src/TransformConstraintData.ts + var TransformConstraintData = class extends ConstraintData { + /** The bones that will be modified by this transform constraint. */ + bones = new Array(); + /** The target bone whose world transform will be copied to the constrained bones. */ + _target = null; + set target(boneData) { + this._target = boneData; + } + get target() { + if (!this._target) + throw new Error("BoneData not set."); + else + return this._target; + } + mixRotate = 0; + mixX = 0; + mixY = 0; + mixScaleX = 0; + mixScaleY = 0; + mixShearY = 0; + /** An offset added to the constrained bone rotation. */ + offsetRotation = 0; + /** An offset added to the constrained bone X translation. */ + offsetX = 0; + /** An offset added to the constrained bone Y translation. */ + offsetY = 0; + /** An offset added to the constrained bone scaleX. */ + offsetScaleX = 0; + /** An offset added to the constrained bone scaleY. */ + offsetScaleY = 0; + /** An offset added to the constrained bone shearY. */ + offsetShearY = 0; + relative = false; + local = false; + constructor(name) { + super(name, 0, false); + } + }; + + // spine-core/src/SkeletonBinary.ts + var SkeletonBinary = class { + /** Scales bone positions, image sizes, and translations as they are loaded. This allows different size images to be used at + * runtime than were used in Spine. + * + * See [Scaling](http://esotericsoftware.com/spine-loading-skeleton-data#Scaling) in the Spine Runtimes Guide. */ + scale = 1; + attachmentLoader; + linkedMeshes = new Array(); + constructor(attachmentLoader) { + this.attachmentLoader = attachmentLoader; + } + readSkeletonData(binary) { + let scale = this.scale; + let skeletonData = new SkeletonData(); + skeletonData.name = ""; + let input = new BinaryInput(binary); + let lowHash = input.readInt32(); + let highHash = input.readInt32(); + skeletonData.hash = highHash == 0 && lowHash == 0 ? null : highHash.toString(16) + lowHash.toString(16); + skeletonData.version = input.readString(); + skeletonData.x = input.readFloat(); + skeletonData.y = input.readFloat(); + skeletonData.width = input.readFloat(); + skeletonData.height = input.readFloat(); + let nonessential = input.readBoolean(); + if (nonessential) { + skeletonData.fps = input.readFloat(); + skeletonData.imagesPath = input.readString(); + skeletonData.audioPath = input.readString(); + } + let n = 0; + n = input.readInt(true); + for (let i = 0; i < n; i++) { + let str = input.readString(); + if (!str) + throw new Error("String in string table must not be null."); + input.strings.push(str); + } + n = input.readInt(true); + for (let i = 0; i < n; i++) { + let name = input.readString(); + if (!name) + throw new Error("Bone name must not be null."); + let parent = i == 0 ? null : skeletonData.bones[input.readInt(true)]; + let data = new BoneData(i, name, parent); + data.rotation = input.readFloat(); + data.x = input.readFloat() * scale; + data.y = input.readFloat() * scale; + data.scaleX = input.readFloat(); + data.scaleY = input.readFloat(); + data.shearX = input.readFloat(); + data.shearY = input.readFloat(); + data.length = input.readFloat() * scale; + data.transformMode = input.readInt(true); + data.skinRequired = input.readBoolean(); + if (nonessential) + Color.rgba8888ToColor(data.color, input.readInt32()); + skeletonData.bones.push(data); + } + n = input.readInt(true); + for (let i = 0; i < n; i++) { + let slotName = input.readString(); + if (!slotName) + throw new Error("Slot name must not be null."); + let boneData = skeletonData.bones[input.readInt(true)]; + let data = new SlotData(i, slotName, boneData); + Color.rgba8888ToColor(data.color, input.readInt32()); + let darkColor = input.readInt32(); + if (darkColor != -1) + Color.rgb888ToColor(data.darkColor = new Color(), darkColor); + data.attachmentName = input.readStringRef(); + data.blendMode = input.readInt(true); + skeletonData.slots.push(data); + } + n = input.readInt(true); + for (let i = 0, nn; i < n; i++) { + let name = input.readString(); + if (!name) + throw new Error("IK constraint data name must not be null."); + let data = new IkConstraintData(name); + data.order = input.readInt(true); + data.skinRequired = input.readBoolean(); + nn = input.readInt(true); + for (let ii = 0; ii < nn; ii++) + data.bones.push(skeletonData.bones[input.readInt(true)]); + data.target = skeletonData.bones[input.readInt(true)]; + data.mix = input.readFloat(); + data.softness = input.readFloat() * scale; + data.bendDirection = input.readByte(); + data.compress = input.readBoolean(); + data.stretch = input.readBoolean(); + data.uniform = input.readBoolean(); + skeletonData.ikConstraints.push(data); + } + n = input.readInt(true); + for (let i = 0, nn; i < n; i++) { + let name = input.readString(); + if (!name) + throw new Error("Transform constraint data name must not be null."); + let data = new TransformConstraintData(name); + data.order = input.readInt(true); + data.skinRequired = input.readBoolean(); + nn = input.readInt(true); + for (let ii = 0; ii < nn; ii++) + data.bones.push(skeletonData.bones[input.readInt(true)]); + data.target = skeletonData.bones[input.readInt(true)]; + data.local = input.readBoolean(); + data.relative = input.readBoolean(); + data.offsetRotation = input.readFloat(); + data.offsetX = input.readFloat() * scale; + data.offsetY = input.readFloat() * scale; + data.offsetScaleX = input.readFloat(); + data.offsetScaleY = input.readFloat(); + data.offsetShearY = input.readFloat(); + data.mixRotate = input.readFloat(); + data.mixX = input.readFloat(); + data.mixY = input.readFloat(); + data.mixScaleX = input.readFloat(); + data.mixScaleY = input.readFloat(); + data.mixShearY = input.readFloat(); + skeletonData.transformConstraints.push(data); + } + n = input.readInt(true); + for (let i = 0, nn; i < n; i++) { + let name = input.readString(); + if (!name) + throw new Error("Path constraint data name must not be null."); + let data = new PathConstraintData(name); + data.order = input.readInt(true); + data.skinRequired = input.readBoolean(); + nn = input.readInt(true); + for (let ii = 0; ii < nn; ii++) + data.bones.push(skeletonData.bones[input.readInt(true)]); + data.target = skeletonData.slots[input.readInt(true)]; + data.positionMode = input.readInt(true); + data.spacingMode = input.readInt(true); + data.rotateMode = input.readInt(true); + data.offsetRotation = input.readFloat(); + data.position = input.readFloat(); + if (data.positionMode == 0 /* Fixed */) + data.position *= scale; + data.spacing = input.readFloat(); + if (data.spacingMode == 0 /* Length */ || data.spacingMode == 1 /* Fixed */) + data.spacing *= scale; + data.mixRotate = input.readFloat(); + data.mixX = input.readFloat(); + data.mixY = input.readFloat(); + skeletonData.pathConstraints.push(data); + } + let defaultSkin = this.readSkin(input, skeletonData, true, nonessential); + if (defaultSkin) { + skeletonData.defaultSkin = defaultSkin; + skeletonData.skins.push(defaultSkin); + } + { + let i = skeletonData.skins.length; + Utils.setArraySize(skeletonData.skins, n = i + input.readInt(true)); + for (; i < n; i++) { + let skin = this.readSkin(input, skeletonData, false, nonessential); + if (!skin) + throw new Error("readSkin() should not have returned null."); + skeletonData.skins[i] = skin; + } + } + n = this.linkedMeshes.length; + for (let i = 0; i < n; i++) { + let linkedMesh = this.linkedMeshes[i]; + let skin = !linkedMesh.skin ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin); + if (!skin) + throw new Error("Not skin found for linked mesh."); + if (!linkedMesh.parent) + throw new Error("Linked mesh parent must not be null"); + let parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); + if (!parent) + throw new Error(`Parent mesh not found: ${linkedMesh.parent}`); + linkedMesh.mesh.timelineAttachment = linkedMesh.inheritTimeline ? parent : linkedMesh.mesh; + linkedMesh.mesh.setParentMesh(parent); + if (linkedMesh.mesh.region != null) + linkedMesh.mesh.updateRegion(); + } + this.linkedMeshes.length = 0; + n = input.readInt(true); + for (let i = 0; i < n; i++) { + let eventName = input.readStringRef(); + if (!eventName) + throw new Error(); + let data = new EventData(eventName); + data.intValue = input.readInt(false); + data.floatValue = input.readFloat(); + data.stringValue = input.readString(); + data.audioPath = input.readString(); + if (data.audioPath) { + data.volume = input.readFloat(); + data.balance = input.readFloat(); + } + skeletonData.events.push(data); + } + n = input.readInt(true); + for (let i = 0; i < n; i++) { + let animationName = input.readString(); + if (!animationName) + throw new Error("Animatio name must not be null."); + skeletonData.animations.push(this.readAnimation(input, animationName, skeletonData)); + } + return skeletonData; + } + readSkin(input, skeletonData, defaultSkin, nonessential) { + let skin = null; + let slotCount = 0; + if (defaultSkin) { + slotCount = input.readInt(true); + if (slotCount == 0) + return null; + skin = new Skin("default"); + } else { + let skinName = input.readStringRef(); + if (!skinName) + throw new Error("Skin name must not be null."); + skin = new Skin(skinName); + skin.bones.length = input.readInt(true); + for (let i = 0, n = skin.bones.length; i < n; i++) + skin.bones[i] = skeletonData.bones[input.readInt(true)]; + for (let i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.push(skeletonData.ikConstraints[input.readInt(true)]); + for (let i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.push(skeletonData.transformConstraints[input.readInt(true)]); + for (let i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.push(skeletonData.pathConstraints[input.readInt(true)]); + slotCount = input.readInt(true); + } + for (let i = 0; i < slotCount; i++) { + let slotIndex = input.readInt(true); + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + let name = input.readStringRef(); + if (!name) + throw new Error("Attachment name must not be null"); + let attachment = this.readAttachment(input, skeletonData, skin, slotIndex, name, nonessential); + if (attachment) + skin.setAttachment(slotIndex, name, attachment); + } + } + return skin; + } + readAttachment(input, skeletonData, skin, slotIndex, attachmentName, nonessential) { + let scale = this.scale; + let name = input.readStringRef(); + if (!name) + name = attachmentName; + switch (input.readByte()) { + case AttachmentType.Region: { + let path = input.readStringRef(); + let rotation = input.readFloat(); + let x = input.readFloat(); + let y = input.readFloat(); + let scaleX = input.readFloat(); + let scaleY = input.readFloat(); + let width = input.readFloat(); + let height = input.readFloat(); + let color = input.readInt32(); + let sequence = this.readSequence(input); + if (!path) + path = name; + let region = this.attachmentLoader.newRegionAttachment(skin, name, path, sequence); + if (!region) + return null; + region.path = path; + region.x = x * scale; + region.y = y * scale; + region.scaleX = scaleX; + region.scaleY = scaleY; + region.rotation = rotation; + region.width = width * scale; + region.height = height * scale; + Color.rgba8888ToColor(region.color, color); + region.sequence = sequence; + if (sequence == null) + region.updateRegion(); + return region; + } + case AttachmentType.BoundingBox: { + let vertexCount = input.readInt(true); + let vertices = this.readVertices(input, vertexCount); + let color = nonessential ? input.readInt32() : 0; + let box = this.attachmentLoader.newBoundingBoxAttachment(skin, name); + if (!box) + return null; + box.worldVerticesLength = vertexCount << 1; + box.vertices = vertices.vertices; + box.bones = vertices.bones; + if (nonessential) + Color.rgba8888ToColor(box.color, color); + return box; + } + case AttachmentType.Mesh: { + let path = input.readStringRef(); + let color = input.readInt32(); + let vertexCount = input.readInt(true); + let uvs = this.readFloatArray(input, vertexCount << 1, 1); + let triangles = this.readShortArray(input); + let vertices = this.readVertices(input, vertexCount); + let hullLength = input.readInt(true); + let sequence = this.readSequence(input); + let edges = []; + let width = 0, height = 0; + if (nonessential) { + edges = this.readShortArray(input); + width = input.readFloat(); + height = input.readFloat(); + } + if (!path) + path = name; + let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path, sequence); + if (!mesh) + return null; + mesh.path = path; + Color.rgba8888ToColor(mesh.color, color); + mesh.bones = vertices.bones; + mesh.vertices = vertices.vertices; + mesh.worldVerticesLength = vertexCount << 1; + mesh.triangles = triangles; + mesh.regionUVs = uvs; + if (sequence == null) + mesh.updateRegion(); + mesh.hullLength = hullLength << 1; + mesh.sequence = sequence; + if (nonessential) { + mesh.edges = edges; + mesh.width = width * scale; + mesh.height = height * scale; + } + return mesh; + } + case AttachmentType.LinkedMesh: { + let path = input.readStringRef(); + let color = input.readInt32(); + let skinName = input.readStringRef(); + let parent = input.readStringRef(); + let inheritTimelines = input.readBoolean(); + let sequence = this.readSequence(input); + let width = 0, height = 0; + if (nonessential) { + width = input.readFloat(); + height = input.readFloat(); + } + if (!path) + path = name; + let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path, sequence); + if (!mesh) + return null; + mesh.path = path; + Color.rgba8888ToColor(mesh.color, color); + mesh.sequence = sequence; + if (nonessential) { + mesh.width = width * scale; + mesh.height = height * scale; + } + this.linkedMeshes.push(new LinkedMesh(mesh, skinName, slotIndex, parent, inheritTimelines)); + return mesh; + } + case AttachmentType.Path: { + let closed2 = input.readBoolean(); + let constantSpeed = input.readBoolean(); + let vertexCount = input.readInt(true); + let vertices = this.readVertices(input, vertexCount); + let lengths = Utils.newArray(vertexCount / 3, 0); + for (let i = 0, n = lengths.length; i < n; i++) + lengths[i] = input.readFloat() * scale; + let color = nonessential ? input.readInt32() : 0; + let path = this.attachmentLoader.newPathAttachment(skin, name); + if (!path) + return null; + path.closed = closed2; + path.constantSpeed = constantSpeed; + path.worldVerticesLength = vertexCount << 1; + path.vertices = vertices.vertices; + path.bones = vertices.bones; + path.lengths = lengths; + if (nonessential) + Color.rgba8888ToColor(path.color, color); + return path; + } + case AttachmentType.Point: { + let rotation = input.readFloat(); + let x = input.readFloat(); + let y = input.readFloat(); + let color = nonessential ? input.readInt32() : 0; + let point = this.attachmentLoader.newPointAttachment(skin, name); + if (!point) + return null; + point.x = x * scale; + point.y = y * scale; + point.rotation = rotation; + if (nonessential) + Color.rgba8888ToColor(point.color, color); + return point; + } + case AttachmentType.Clipping: { + let endSlotIndex = input.readInt(true); + let vertexCount = input.readInt(true); + let vertices = this.readVertices(input, vertexCount); + let color = nonessential ? input.readInt32() : 0; + let clip = this.attachmentLoader.newClippingAttachment(skin, name); + if (!clip) + return null; + clip.endSlot = skeletonData.slots[endSlotIndex]; + clip.worldVerticesLength = vertexCount << 1; + clip.vertices = vertices.vertices; + clip.bones = vertices.bones; + if (nonessential) + Color.rgba8888ToColor(clip.color, color); + return clip; + } + } + return null; + } + readSequence(input) { + if (!input.readBoolean()) + return null; + let sequence = new Sequence(input.readInt(true)); + sequence.start = input.readInt(true); + sequence.digits = input.readInt(true); + sequence.setupIndex = input.readInt(true); + return sequence; + } + readVertices(input, vertexCount) { + let scale = this.scale; + let verticesLength = vertexCount << 1; + let vertices = new Vertices(); + if (!input.readBoolean()) { + vertices.vertices = this.readFloatArray(input, verticesLength, scale); + return vertices; + } + let weights = new Array(); + let bonesArray = new Array(); + for (let i = 0; i < vertexCount; i++) { + let boneCount = input.readInt(true); + bonesArray.push(boneCount); + for (let ii = 0; ii < boneCount; ii++) { + bonesArray.push(input.readInt(true)); + weights.push(input.readFloat() * scale); + weights.push(input.readFloat() * scale); + weights.push(input.readFloat()); + } + } + vertices.vertices = Utils.toFloatArray(weights); + vertices.bones = bonesArray; + return vertices; + } + readFloatArray(input, n, scale) { + let array = new Array(n); + if (scale == 1) { + for (let i = 0; i < n; i++) + array[i] = input.readFloat(); + } else { + for (let i = 0; i < n; i++) + array[i] = input.readFloat() * scale; + } + return array; + } + readShortArray(input) { + let n = input.readInt(true); + let array = new Array(n); + for (let i = 0; i < n; i++) + array[i] = input.readShort(); + return array; + } + readAnimation(input, name, skeletonData) { + input.readInt(true); + let timelines = new Array(); + let scale = this.scale; + let tempColor1 = new Color(); + let tempColor2 = new Color(); + for (let i = 0, n = input.readInt(true); i < n; i++) { + let slotIndex = input.readInt(true); + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + let timelineType = input.readByte(); + let frameCount = input.readInt(true); + let frameLast = frameCount - 1; + switch (timelineType) { + case SLOT_ATTACHMENT: { + let timeline = new AttachmentTimeline(frameCount, slotIndex); + for (let frame = 0; frame < frameCount; frame++) + timeline.setFrame(frame, input.readFloat(), input.readStringRef()); + timelines.push(timeline); + break; + } + case SLOT_RGBA: { + let bezierCount = input.readInt(true); + let timeline = new RGBATimeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + let a = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b, a); + if (frame == frameLast) + break; + let time2 = input.readFloat(); + let r2 = input.readUnsignedByte() / 255; + let g2 = input.readUnsignedByte() / 255; + let b2 = input.readUnsignedByte() / 255; + let a2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, r2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, g2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, b2, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, a, a2, 1); + } + time = time2; + r = r2; + g = g2; + b = b2; + a = a2; + } + timelines.push(timeline); + break; + } + case SLOT_RGB: { + let bezierCount = input.readInt(true); + let timeline = new RGBTimeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b); + if (frame == frameLast) + break; + let time2 = input.readFloat(); + let r2 = input.readUnsignedByte() / 255; + let g2 = input.readUnsignedByte() / 255; + let b2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, r2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, g2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, b2, 1); + } + time = time2; + r = r2; + g = g2; + b = b2; + } + timelines.push(timeline); + break; + } + case SLOT_RGBA2: { + let bezierCount = input.readInt(true); + let timeline = new RGBA2Timeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + let a = input.readUnsignedByte() / 255; + let r2 = input.readUnsignedByte() / 255; + let g2 = input.readUnsignedByte() / 255; + let b2 = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b, a, r2, g2, b2); + if (frame == frameLast) + break; + let time2 = input.readFloat(); + let nr = input.readUnsignedByte() / 255; + let ng = input.readUnsignedByte() / 255; + let nb = input.readUnsignedByte() / 255; + let na = input.readUnsignedByte() / 255; + let nr2 = input.readUnsignedByte() / 255; + let ng2 = input.readUnsignedByte() / 255; + let nb2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, nr, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, ng, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, nb, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, a, na, 1); + setBezier(input, timeline, bezier++, frame, 4, time, time2, r2, nr2, 1); + setBezier(input, timeline, bezier++, frame, 5, time, time2, g2, ng2, 1); + setBezier(input, timeline, bezier++, frame, 6, time, time2, b2, nb2, 1); + } + time = time2; + r = nr; + g = ng; + b = nb; + a = na; + r2 = nr2; + g2 = ng2; + b2 = nb2; + } + timelines.push(timeline); + break; + } + case SLOT_RGB2: { + let bezierCount = input.readInt(true); + let timeline = new RGB2Timeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + let r2 = input.readUnsignedByte() / 255; + let g2 = input.readUnsignedByte() / 255; + let b2 = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b, r2, g2, b2); + if (frame == frameLast) + break; + let time2 = input.readFloat(); + let nr = input.readUnsignedByte() / 255; + let ng = input.readUnsignedByte() / 255; + let nb = input.readUnsignedByte() / 255; + let nr2 = input.readUnsignedByte() / 255; + let ng2 = input.readUnsignedByte() / 255; + let nb2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, nr, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, ng, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, nb, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, r2, nr2, 1); + setBezier(input, timeline, bezier++, frame, 4, time, time2, g2, ng2, 1); + setBezier(input, timeline, bezier++, frame, 5, time, time2, b2, nb2, 1); + } + time = time2; + r = nr; + g = ng; + b = nb; + r2 = nr2; + g2 = ng2; + b2 = nb2; + } + timelines.push(timeline); + break; + } + case SLOT_ALPHA: { + let timeline = new AlphaTimeline(frameCount, input.readInt(true), slotIndex); + let time = input.readFloat(), a = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, a); + if (frame == frameLast) + break; + let time2 = input.readFloat(); + let a2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, a, a2, 1); + } + time = time2; + a = a2; + } + timelines.push(timeline); + } + } + } + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + let boneIndex = input.readInt(true); + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + let type = input.readByte(), frameCount = input.readInt(true), bezierCount = input.readInt(true); + switch (type) { + case BONE_ROTATE: + timelines.push(readTimeline1(input, new RotateTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_TRANSLATE: + timelines.push(readTimeline2(input, new TranslateTimeline(frameCount, bezierCount, boneIndex), scale)); + break; + case BONE_TRANSLATEX: + timelines.push(readTimeline1(input, new TranslateXTimeline(frameCount, bezierCount, boneIndex), scale)); + break; + case BONE_TRANSLATEY: + timelines.push(readTimeline1(input, new TranslateYTimeline(frameCount, bezierCount, boneIndex), scale)); + break; + case BONE_SCALE: + timelines.push(readTimeline2(input, new ScaleTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_SCALEX: + timelines.push(readTimeline1(input, new ScaleXTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_SCALEY: + timelines.push(readTimeline1(input, new ScaleYTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_SHEAR: + timelines.push(readTimeline2(input, new ShearTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_SHEARX: + timelines.push(readTimeline1(input, new ShearXTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_SHEARY: + timelines.push(readTimeline1(input, new ShearYTimeline(frameCount, bezierCount, boneIndex), 1)); + } + } + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + let index = input.readInt(true), frameCount = input.readInt(true), frameLast = frameCount - 1; + let timeline = new IkConstraintTimeline(frameCount, input.readInt(true), index); + let time = input.readFloat(), mix = input.readFloat(), softness = input.readFloat() * scale; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mix, softness, input.readByte(), input.readBoolean(), input.readBoolean()); + if (frame == frameLast) + break; + let time2 = input.readFloat(), mix2 = input.readFloat(), softness2 = input.readFloat() * scale; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, mix, mix2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, softness, softness2, scale); + } + time = time2; + mix = mix2; + softness = softness2; + } + timelines.push(timeline); + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + let index = input.readInt(true), frameCount = input.readInt(true), frameLast = frameCount - 1; + let timeline = new TransformConstraintTimeline(frameCount, input.readInt(true), index); + let time = input.readFloat(), mixRotate = input.readFloat(), mixX = input.readFloat(), mixY = input.readFloat(), mixScaleX = input.readFloat(), mixScaleY = input.readFloat(), mixShearY = input.readFloat(); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY); + if (frame == frameLast) + break; + let time2 = input.readFloat(), mixRotate2 = input.readFloat(), mixX2 = input.readFloat(), mixY2 = input.readFloat(), mixScaleX2 = input.readFloat(), mixScaleY2 = input.readFloat(), mixShearY2 = input.readFloat(); + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, mixY, mixY2, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, mixScaleX, mixScaleX2, 1); + setBezier(input, timeline, bezier++, frame, 4, time, time2, mixScaleY, mixScaleY2, 1); + setBezier(input, timeline, bezier++, frame, 5, time, time2, mixShearY, mixShearY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + mixScaleX = mixScaleX2; + mixScaleY = mixScaleY2; + mixShearY = mixShearY2; + } + timelines.push(timeline); + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + let index = input.readInt(true); + let data = skeletonData.pathConstraints[index]; + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + switch (input.readByte()) { + case PATH_POSITION: + timelines.push(readTimeline1( + input, + new PathConstraintPositionTimeline(input.readInt(true), input.readInt(true), index), + data.positionMode == 0 /* Fixed */ ? scale : 1 + )); + break; + case PATH_SPACING: + timelines.push(readTimeline1( + input, + new PathConstraintSpacingTimeline(input.readInt(true), input.readInt(true), index), + data.spacingMode == 0 /* Length */ || data.spacingMode == 1 /* Fixed */ ? scale : 1 + )); + break; + case PATH_MIX: + let timeline = new PathConstraintMixTimeline(input.readInt(true), input.readInt(true), index); + let time = input.readFloat(), mixRotate = input.readFloat(), mixX = input.readFloat(), mixY = input.readFloat(); + for (let frame = 0, bezier = 0, frameLast = timeline.getFrameCount() - 1; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY); + if (frame == frameLast) + break; + let time2 = input.readFloat(), mixRotate2 = input.readFloat(), mixX2 = input.readFloat(), mixY2 = input.readFloat(); + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, mixY, mixY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + } + timelines.push(timeline); + } + } + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + let skin = skeletonData.skins[input.readInt(true)]; + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + let slotIndex = input.readInt(true); + for (let iii = 0, nnn = input.readInt(true); iii < nnn; iii++) { + let attachmentName = input.readStringRef(); + if (!attachmentName) + throw new Error("attachmentName must not be null."); + let attachment = skin.getAttachment(slotIndex, attachmentName); + let timelineType = input.readByte(); + let frameCount = input.readInt(true); + let frameLast = frameCount - 1; + switch (timelineType) { + case ATTACHMENT_DEFORM: { + let vertexAttachment = attachment; + let weighted = vertexAttachment.bones; + let vertices = vertexAttachment.vertices; + let deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + let bezierCount = input.readInt(true); + let timeline = new DeformTimeline(frameCount, bezierCount, slotIndex, vertexAttachment); + let time = input.readFloat(); + for (let frame = 0, bezier = 0; ; frame++) { + let deform; + let end = input.readInt(true); + if (end == 0) + deform = weighted ? Utils.newFloatArray(deformLength) : vertices; + else { + deform = Utils.newFloatArray(deformLength); + let start = input.readInt(true); + end += start; + if (scale == 1) { + for (let v = start; v < end; v++) + deform[v] = input.readFloat(); + } else { + for (let v = start; v < end; v++) + deform[v] = input.readFloat() * scale; + } + if (!weighted) { + for (let v = 0, vn = deform.length; v < vn; v++) + deform[v] += vertices[v]; + } + } + timeline.setFrame(frame, time, deform); + if (frame == frameLast) + break; + let time2 = input.readFloat(); + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, 0, 1, 1); + } + time = time2; + } + timelines.push(timeline); + break; + } + case ATTACHMENT_SEQUENCE: { + let timeline = new SequenceTimeline(frameCount, slotIndex, attachment); + for (let frame = 0; frame < frameCount; frame++) { + let time = input.readFloat(); + let modeAndIndex = input.readInt32(); + timeline.setFrame( + frame, + time, + SequenceModeValues[modeAndIndex & 15], + modeAndIndex >> 4, + input.readFloat() + ); + } + timelines.push(timeline); + break; + } + } + } + } + } + let drawOrderCount = input.readInt(true); + if (drawOrderCount > 0) { + let timeline = new DrawOrderTimeline(drawOrderCount); + let slotCount = skeletonData.slots.length; + for (let i = 0; i < drawOrderCount; i++) { + let time = input.readFloat(); + let offsetCount = input.readInt(true); + let drawOrder = Utils.newArray(slotCount, 0); + for (let ii = slotCount - 1; ii >= 0; ii--) + drawOrder[ii] = -1; + let unchanged = Utils.newArray(slotCount - offsetCount, 0); + let originalIndex = 0, unchangedIndex = 0; + for (let ii = 0; ii < offsetCount; ii++) { + let slotIndex = input.readInt(true); + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + drawOrder[originalIndex + input.readInt(true)] = originalIndex++; + } + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + for (let ii = slotCount - 1; ii >= 0; ii--) + if (drawOrder[ii] == -1) + drawOrder[ii] = unchanged[--unchangedIndex]; + timeline.setFrame(i, time, drawOrder); + } + timelines.push(timeline); + } + let eventCount = input.readInt(true); + if (eventCount > 0) { + let timeline = new EventTimeline(eventCount); + for (let i = 0; i < eventCount; i++) { + let time = input.readFloat(); + let eventData = skeletonData.events[input.readInt(true)]; + let event = new Event(time, eventData); + event.intValue = input.readInt(false); + event.floatValue = input.readFloat(); + event.stringValue = input.readBoolean() ? input.readString() : eventData.stringValue; + if (event.data.audioPath) { + event.volume = input.readFloat(); + event.balance = input.readFloat(); + } + timeline.setFrame(i, event); + } + timelines.push(timeline); + } + let duration = 0; + for (let i = 0, n = timelines.length; i < n; i++) + duration = Math.max(duration, timelines[i].getDuration()); + return new Animation(name, timelines, duration); + } + }; + var BinaryInput = class { + constructor(data, strings = new Array(), index = 0, buffer = new DataView(data.buffer)) { + this.strings = strings; + this.index = index; + this.buffer = buffer; + } + readByte() { + return this.buffer.getInt8(this.index++); + } + readUnsignedByte() { + return this.buffer.getUint8(this.index++); + } + readShort() { + let value = this.buffer.getInt16(this.index); + this.index += 2; + return value; + } + readInt32() { + let value = this.buffer.getInt32(this.index); + this.index += 4; + return value; + } + readInt(optimizePositive) { + let b = this.readByte(); + let result = b & 127; + if ((b & 128) != 0) { + b = this.readByte(); + result |= (b & 127) << 7; + if ((b & 128) != 0) { + b = this.readByte(); + result |= (b & 127) << 14; + if ((b & 128) != 0) { + b = this.readByte(); + result |= (b & 127) << 21; + if ((b & 128) != 0) { + b = this.readByte(); + result |= (b & 127) << 28; + } + } + } + } + return optimizePositive ? result : result >>> 1 ^ -(result & 1); + } + readStringRef() { + let index = this.readInt(true); + return index == 0 ? null : this.strings[index - 1]; + } + readString() { + let byteCount = this.readInt(true); + switch (byteCount) { + case 0: + return null; + case 1: + return ""; + } + byteCount--; + let chars = ""; + let charCount = 0; + for (let i = 0; i < byteCount; ) { + let b = this.readUnsignedByte(); + switch (b >> 4) { + case 12: + case 13: + chars += String.fromCharCode((b & 31) << 6 | this.readByte() & 63); + i += 2; + break; + case 14: + chars += String.fromCharCode((b & 15) << 12 | (this.readByte() & 63) << 6 | this.readByte() & 63); + i += 3; + break; + default: + chars += String.fromCharCode(b); + i++; + } + } + return chars; + } + readFloat() { + let value = this.buffer.getFloat32(this.index); + this.index += 4; + return value; + } + readBoolean() { + return this.readByte() != 0; + } + }; + var LinkedMesh = class { + parent; + skin; + slotIndex; + mesh; + inheritTimeline; + constructor(mesh, skin, slotIndex, parent, inheritDeform) { + this.mesh = mesh; + this.skin = skin; + this.slotIndex = slotIndex; + this.parent = parent; + this.inheritTimeline = inheritDeform; + } + }; + var Vertices = class { + constructor(bones = null, vertices = null) { + this.bones = bones; + this.vertices = vertices; + } + }; + var AttachmentType = /* @__PURE__ */ ((AttachmentType2) => { + AttachmentType2[AttachmentType2["Region"] = 0] = "Region"; + AttachmentType2[AttachmentType2["BoundingBox"] = 1] = "BoundingBox"; + AttachmentType2[AttachmentType2["Mesh"] = 2] = "Mesh"; + AttachmentType2[AttachmentType2["LinkedMesh"] = 3] = "LinkedMesh"; + AttachmentType2[AttachmentType2["Path"] = 4] = "Path"; + AttachmentType2[AttachmentType2["Point"] = 5] = "Point"; + AttachmentType2[AttachmentType2["Clipping"] = 6] = "Clipping"; + return AttachmentType2; + })(AttachmentType || {}); + function readTimeline1(input, timeline, scale) { + let time = input.readFloat(), value = input.readFloat() * scale; + for (let frame = 0, bezier = 0, frameLast = timeline.getFrameCount() - 1; ; frame++) { + timeline.setFrame(frame, time, value); + if (frame == frameLast) + break; + let time2 = input.readFloat(), value2 = input.readFloat() * scale; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, value, value2, scale); + } + time = time2; + value = value2; + } + return timeline; + } + function readTimeline2(input, timeline, scale) { + let time = input.readFloat(), value1 = input.readFloat() * scale, value2 = input.readFloat() * scale; + for (let frame = 0, bezier = 0, frameLast = timeline.getFrameCount() - 1; ; frame++) { + timeline.setFrame(frame, time, value1, value2); + if (frame == frameLast) + break; + let time2 = input.readFloat(), nvalue1 = input.readFloat() * scale, nvalue2 = input.readFloat() * scale; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, value1, nvalue1, scale); + setBezier(input, timeline, bezier++, frame, 1, time, time2, value2, nvalue2, scale); + } + time = time2; + value1 = nvalue1; + value2 = nvalue2; + } + return timeline; + } + function setBezier(input, timeline, bezier, frame, value, time1, time2, value1, value2, scale) { + timeline.setBezier(bezier, frame, value, time1, value1, input.readFloat(), input.readFloat() * scale, input.readFloat(), input.readFloat() * scale, time2, value2); + } + var BONE_ROTATE = 0; + var BONE_TRANSLATE = 1; + var BONE_TRANSLATEX = 2; + var BONE_TRANSLATEY = 3; + var BONE_SCALE = 4; + var BONE_SCALEX = 5; + var BONE_SCALEY = 6; + var BONE_SHEAR = 7; + var BONE_SHEARX = 8; + var BONE_SHEARY = 9; + var SLOT_ATTACHMENT = 0; + var SLOT_RGBA = 1; + var SLOT_RGB = 2; + var SLOT_RGBA2 = 3; + var SLOT_RGB2 = 4; + var SLOT_ALPHA = 5; + var ATTACHMENT_DEFORM = 0; + var ATTACHMENT_SEQUENCE = 1; + var PATH_POSITION = 0; + var PATH_SPACING = 1; + var PATH_MIX = 2; + var CURVE_STEPPED = 1; + var CURVE_BEZIER = 2; + + // spine-core/src/SkeletonBounds.ts + var SkeletonBounds = class { + /** The left edge of the axis aligned bounding box. */ + minX = 0; + /** The bottom edge of the axis aligned bounding box. */ + minY = 0; + /** The right edge of the axis aligned bounding box. */ + maxX = 0; + /** The top edge of the axis aligned bounding box. */ + maxY = 0; + /** The visible bounding boxes. */ + boundingBoxes = new Array(); + /** The world vertices for the bounding box polygons. */ + polygons = new Array(); + polygonPool = new Pool(() => { + return Utils.newFloatArray(16); + }); + /** Clears any previous polygons, finds all visible bounding box attachments, and computes the world vertices for each bounding + * box's polygon. + * @param updateAabb If true, the axis aligned bounding box containing all the polygons is computed. If false, the + * SkeletonBounds AABB methods will always return true. */ + update(skeleton, updateAabb) { + if (!skeleton) + throw new Error("skeleton cannot be null."); + let boundingBoxes = this.boundingBoxes; + let polygons = this.polygons; + let polygonPool = this.polygonPool; + let slots = skeleton.slots; + let slotCount = slots.length; + boundingBoxes.length = 0; + polygonPool.freeAll(polygons); + polygons.length = 0; + for (let i = 0; i < slotCount; i++) { + let slot = slots[i]; + if (!slot.bone.active) + continue; + let attachment = slot.getAttachment(); + if (attachment instanceof BoundingBoxAttachment) { + let boundingBox = attachment; + boundingBoxes.push(boundingBox); + let polygon = polygonPool.obtain(); + if (polygon.length != boundingBox.worldVerticesLength) { + polygon = Utils.newFloatArray(boundingBox.worldVerticesLength); + } + polygons.push(polygon); + boundingBox.computeWorldVertices(slot, 0, boundingBox.worldVerticesLength, polygon, 0, 2); + } + } + if (updateAabb) { + this.aabbCompute(); + } else { + this.minX = Number.POSITIVE_INFINITY; + this.minY = Number.POSITIVE_INFINITY; + this.maxX = Number.NEGATIVE_INFINITY; + this.maxY = Number.NEGATIVE_INFINITY; + } + } + aabbCompute() { + let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + let polygons = this.polygons; + for (let i = 0, n = polygons.length; i < n; i++) { + let polygon = polygons[i]; + let vertices = polygon; + for (let ii = 0, nn = polygon.length; ii < nn; ii += 2) { + let x = vertices[ii]; + let y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + /** Returns true if the axis aligned bounding box contains the point. */ + aabbContainsPoint(x, y) { + return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY; + } + /** Returns true if the axis aligned bounding box intersects the line segment. */ + aabbIntersectsSegment(x1, y1, x2, y2) { + let minX = this.minX; + let minY = this.minY; + let maxX = this.maxX; + let maxY = this.maxY; + if (x1 <= minX && x2 <= minX || y1 <= minY && y2 <= minY || x1 >= maxX && x2 >= maxX || y1 >= maxY && y2 >= maxY) + return false; + let m = (y2 - y1) / (x2 - x1); + let y = m * (minX - x1) + y1; + if (y > minY && y < maxY) + return true; + y = m * (maxX - x1) + y1; + if (y > minY && y < maxY) + return true; + let x = (minY - y1) / m + x1; + if (x > minX && x < maxX) + return true; + x = (maxY - y1) / m + x1; + if (x > minX && x < maxX) + return true; + return false; + } + /** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ + aabbIntersectsSkeleton(bounds) { + return this.minX < bounds.maxX && this.maxX > bounds.minX && this.minY < bounds.maxY && this.maxY > bounds.minY; + } + /** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more + * efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */ + containsPoint(x, y) { + let polygons = this.polygons; + for (let i = 0, n = polygons.length; i < n; i++) + if (this.containsPointPolygon(polygons[i], x, y)) + return this.boundingBoxes[i]; + return null; + } + /** Returns true if the polygon contains the point. */ + containsPointPolygon(polygon, x, y) { + let vertices = polygon; + let nn = polygon.length; + let prevIndex = nn - 2; + let inside = false; + for (let ii = 0; ii < nn; ii += 2) { + let vertexY = vertices[ii + 1]; + let prevY = vertices[prevIndex + 1]; + if (vertexY < y && prevY >= y || prevY < y && vertexY >= y) { + let vertexX = vertices[ii]; + if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) + inside = !inside; + } + prevIndex = ii; + } + return inside; + } + /** Returns the first bounding box attachment that contains any part of the line segment, or null. When doing many checks, it + * is usually more efficient to only call this method if {@link #aabbIntersectsSegment()} returns + * true. */ + intersectsSegment(x1, y1, x2, y2) { + let polygons = this.polygons; + for (let i = 0, n = polygons.length; i < n; i++) + if (this.intersectsSegmentPolygon(polygons[i], x1, y1, x2, y2)) + return this.boundingBoxes[i]; + return null; + } + /** Returns true if the polygon contains any part of the line segment. */ + intersectsSegmentPolygon(polygon, x1, y1, x2, y2) { + let vertices = polygon; + let nn = polygon.length; + let width12 = x1 - x2, height12 = y1 - y2; + let det1 = x1 * y2 - y1 * x2; + let x3 = vertices[nn - 2], y3 = vertices[nn - 1]; + for (let ii = 0; ii < nn; ii += 2) { + let x4 = vertices[ii], y4 = vertices[ii + 1]; + let det2 = x3 * y4 - y3 * x4; + let width34 = x3 - x4, height34 = y3 - y4; + let det3 = width12 * height34 - height12 * width34; + let x = (det1 * width34 - width12 * det2) / det3; + if ((x >= x3 && x <= x4 || x >= x4 && x <= x3) && (x >= x1 && x <= x2 || x >= x2 && x <= x1)) { + let y = (det1 * height34 - height12 * det2) / det3; + if ((y >= y3 && y <= y4 || y >= y4 && y <= y3) && (y >= y1 && y <= y2 || y >= y2 && y <= y1)) + return true; + } + x3 = x4; + y3 = y4; + } + return false; + } + /** Returns the polygon for the specified bounding box, or null. */ + getPolygon(boundingBox) { + if (!boundingBox) + throw new Error("boundingBox cannot be null."); + let index = this.boundingBoxes.indexOf(boundingBox); + return index == -1 ? null : this.polygons[index]; + } + /** The width of the axis aligned bounding box. */ + getWidth() { + return this.maxX - this.minX; + } + /** The height of the axis aligned bounding box. */ + getHeight() { + return this.maxY - this.minY; + } + }; + + // spine-core/src/Triangulator.ts + var Triangulator = class { + convexPolygons = new Array(); + convexPolygonsIndices = new Array(); + indicesArray = new Array(); + isConcaveArray = new Array(); + triangles = new Array(); + polygonPool = new Pool(() => { + return new Array(); + }); + polygonIndicesPool = new Pool(() => { + return new Array(); + }); + triangulate(verticesArray) { + let vertices = verticesArray; + let vertexCount = verticesArray.length >> 1; + let indices = this.indicesArray; + indices.length = 0; + for (let i = 0; i < vertexCount; i++) + indices[i] = i; + let isConcave = this.isConcaveArray; + isConcave.length = 0; + for (let i = 0, n = vertexCount; i < n; ++i) + isConcave[i] = Triangulator.isConcave(i, vertexCount, vertices, indices); + let triangles = this.triangles; + triangles.length = 0; + while (vertexCount > 3) { + let previous = vertexCount - 1, i = 0, next = 1; + while (true) { + outer: + if (!isConcave[i]) { + let p1 = indices[previous] << 1, p2 = indices[i] << 1, p3 = indices[next] << 1; + let p1x = vertices[p1], p1y = vertices[p1 + 1]; + let p2x = vertices[p2], p2y = vertices[p2 + 1]; + let p3x = vertices[p3], p3y = vertices[p3 + 1]; + for (let ii = (next + 1) % vertexCount; ii != previous; ii = (ii + 1) % vertexCount) { + if (!isConcave[ii]) + continue; + let v = indices[ii] << 1; + let vx = vertices[v], vy = vertices[v + 1]; + if (Triangulator.positiveArea(p3x, p3y, p1x, p1y, vx, vy)) { + if (Triangulator.positiveArea(p1x, p1y, p2x, p2y, vx, vy)) { + if (Triangulator.positiveArea(p2x, p2y, p3x, p3y, vx, vy)) + break outer; + } + } + } + break; + } + if (next == 0) { + do { + if (!isConcave[i]) + break; + i--; + } while (i > 0); + break; + } + previous = i; + i = next; + next = (next + 1) % vertexCount; + } + triangles.push(indices[(vertexCount + i - 1) % vertexCount]); + triangles.push(indices[i]); + triangles.push(indices[(i + 1) % vertexCount]); + indices.splice(i, 1); + isConcave.splice(i, 1); + vertexCount--; + let previousIndex = (vertexCount + i - 1) % vertexCount; + let nextIndex = i == vertexCount ? 0 : i; + isConcave[previousIndex] = Triangulator.isConcave(previousIndex, vertexCount, vertices, indices); + isConcave[nextIndex] = Triangulator.isConcave(nextIndex, vertexCount, vertices, indices); + } + if (vertexCount == 3) { + triangles.push(indices[2]); + triangles.push(indices[0]); + triangles.push(indices[1]); + } + return triangles; + } + decompose(verticesArray, triangles) { + let vertices = verticesArray; + let convexPolygons = this.convexPolygons; + this.polygonPool.freeAll(convexPolygons); + convexPolygons.length = 0; + let convexPolygonsIndices = this.convexPolygonsIndices; + this.polygonIndicesPool.freeAll(convexPolygonsIndices); + convexPolygonsIndices.length = 0; + let polygonIndices = this.polygonIndicesPool.obtain(); + polygonIndices.length = 0; + let polygon = this.polygonPool.obtain(); + polygon.length = 0; + let fanBaseIndex = -1, lastWinding = 0; + for (let i = 0, n = triangles.length; i < n; i += 3) { + let t1 = triangles[i] << 1, t2 = triangles[i + 1] << 1, t3 = triangles[i + 2] << 1; + let x1 = vertices[t1], y1 = vertices[t1 + 1]; + let x2 = vertices[t2], y2 = vertices[t2 + 1]; + let x3 = vertices[t3], y3 = vertices[t3 + 1]; + let merged = false; + if (fanBaseIndex == t1) { + let o = polygon.length - 4; + let winding1 = Triangulator.winding(polygon[o], polygon[o + 1], polygon[o + 2], polygon[o + 3], x3, y3); + let winding2 = Triangulator.winding(x3, y3, polygon[0], polygon[1], polygon[2], polygon[3]); + if (winding1 == lastWinding && winding2 == lastWinding) { + polygon.push(x3); + polygon.push(y3); + polygonIndices.push(t3); + merged = true; + } + } + if (!merged) { + if (polygon.length > 0) { + convexPolygons.push(polygon); + convexPolygonsIndices.push(polygonIndices); + } else { + this.polygonPool.free(polygon); + this.polygonIndicesPool.free(polygonIndices); + } + polygon = this.polygonPool.obtain(); + polygon.length = 0; + polygon.push(x1); + polygon.push(y1); + polygon.push(x2); + polygon.push(y2); + polygon.push(x3); + polygon.push(y3); + polygonIndices = this.polygonIndicesPool.obtain(); + polygonIndices.length = 0; + polygonIndices.push(t1); + polygonIndices.push(t2); + polygonIndices.push(t3); + lastWinding = Triangulator.winding(x1, y1, x2, y2, x3, y3); + fanBaseIndex = t1; + } + } + if (polygon.length > 0) { + convexPolygons.push(polygon); + convexPolygonsIndices.push(polygonIndices); + } + for (let i = 0, n = convexPolygons.length; i < n; i++) { + polygonIndices = convexPolygonsIndices[i]; + if (polygonIndices.length == 0) + continue; + let firstIndex = polygonIndices[0]; + let lastIndex = polygonIndices[polygonIndices.length - 1]; + polygon = convexPolygons[i]; + let o = polygon.length - 4; + let prevPrevX = polygon[o], prevPrevY = polygon[o + 1]; + let prevX = polygon[o + 2], prevY = polygon[o + 3]; + let firstX = polygon[0], firstY = polygon[1]; + let secondX = polygon[2], secondY = polygon[3]; + let winding = Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, firstX, firstY); + for (let ii = 0; ii < n; ii++) { + if (ii == i) + continue; + let otherIndices = convexPolygonsIndices[ii]; + if (otherIndices.length != 3) + continue; + let otherFirstIndex = otherIndices[0]; + let otherSecondIndex = otherIndices[1]; + let otherLastIndex = otherIndices[2]; + let otherPoly = convexPolygons[ii]; + let x3 = otherPoly[otherPoly.length - 2], y3 = otherPoly[otherPoly.length - 1]; + if (otherFirstIndex != firstIndex || otherSecondIndex != lastIndex) + continue; + let winding1 = Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, x3, y3); + let winding2 = Triangulator.winding(x3, y3, firstX, firstY, secondX, secondY); + if (winding1 == winding && winding2 == winding) { + otherPoly.length = 0; + otherIndices.length = 0; + polygon.push(x3); + polygon.push(y3); + polygonIndices.push(otherLastIndex); + prevPrevX = prevX; + prevPrevY = prevY; + prevX = x3; + prevY = y3; + ii = 0; + } + } + } + for (let i = convexPolygons.length - 1; i >= 0; i--) { + polygon = convexPolygons[i]; + if (polygon.length == 0) { + convexPolygons.splice(i, 1); + this.polygonPool.free(polygon); + polygonIndices = convexPolygonsIndices[i]; + convexPolygonsIndices.splice(i, 1); + this.polygonIndicesPool.free(polygonIndices); + } + } + return convexPolygons; + } + static isConcave(index, vertexCount, vertices, indices) { + let previous = indices[(vertexCount + index - 1) % vertexCount] << 1; + let current = indices[index] << 1; + let next = indices[(index + 1) % vertexCount] << 1; + return !this.positiveArea( + vertices[previous], + vertices[previous + 1], + vertices[current], + vertices[current + 1], + vertices[next], + vertices[next + 1] + ); + } + static positiveArea(p1x, p1y, p2x, p2y, p3x, p3y) { + return p1x * (p3y - p2y) + p2x * (p1y - p3y) + p3x * (p2y - p1y) >= 0; + } + static winding(p1x, p1y, p2x, p2y, p3x, p3y) { + let px = p2x - p1x, py = p2y - p1y; + return p3x * py - p3y * px + px * p1y - p1x * py >= 0 ? 1 : -1; + } + }; + + // spine-core/src/SkeletonClipping.ts + var SkeletonClipping = class { + triangulator = new Triangulator(); + clippingPolygon = new Array(); + clipOutput = new Array(); + clippedVertices = new Array(); + clippedTriangles = new Array(); + scratch = new Array(); + clipAttachment = null; + clippingPolygons = null; + clipStart(slot, clip) { + if (this.clipAttachment) + return 0; + this.clipAttachment = clip; + let n = clip.worldVerticesLength; + let vertices = Utils.setArraySize(this.clippingPolygon, n); + clip.computeWorldVertices(slot, 0, n, vertices, 0, 2); + let clippingPolygon = this.clippingPolygon; + SkeletonClipping.makeClockwise(clippingPolygon); + let clippingPolygons = this.clippingPolygons = this.triangulator.decompose(clippingPolygon, this.triangulator.triangulate(clippingPolygon)); + for (let i = 0, n2 = clippingPolygons.length; i < n2; i++) { + let polygon = clippingPolygons[i]; + SkeletonClipping.makeClockwise(polygon); + polygon.push(polygon[0]); + polygon.push(polygon[1]); + } + return clippingPolygons.length; + } + clipEndWithSlot(slot) { + if (this.clipAttachment && this.clipAttachment.endSlot == slot.data) + this.clipEnd(); + } + clipEnd() { + if (!this.clipAttachment) + return; + this.clipAttachment = null; + this.clippingPolygons = null; + this.clippedVertices.length = 0; + this.clippedTriangles.length = 0; + this.clippingPolygon.length = 0; + } + isClipping() { + return this.clipAttachment != null; + } + clipTriangles(vertices, verticesLength, triangles, trianglesLength, uvs, light, dark, twoColor) { + let clipOutput = this.clipOutput, clippedVertices = this.clippedVertices; + let clippedTriangles = this.clippedTriangles; + let polygons = this.clippingPolygons; + let polygonsCount = polygons.length; + let vertexSize = twoColor ? 12 : 8; + let index = 0; + clippedVertices.length = 0; + clippedTriangles.length = 0; + outer: + for (let i = 0; i < trianglesLength; i += 3) { + let vertexOffset = triangles[i] << 1; + let x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1]; + let u1 = uvs[vertexOffset], v1 = uvs[vertexOffset + 1]; + vertexOffset = triangles[i + 1] << 1; + let x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1]; + let u2 = uvs[vertexOffset], v2 = uvs[vertexOffset + 1]; + vertexOffset = triangles[i + 2] << 1; + let x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1]; + let u3 = uvs[vertexOffset], v3 = uvs[vertexOffset + 1]; + for (let p = 0; p < polygonsCount; p++) { + let s = clippedVertices.length; + if (this.clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) { + let clipOutputLength = clipOutput.length; + if (clipOutputLength == 0) + continue; + let d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1; + let d = 1 / (d0 * d2 + d1 * (y1 - y3)); + let clipOutputCount = clipOutputLength >> 1; + let clipOutputItems = this.clipOutput; + let clippedVerticesItems = Utils.setArraySize(clippedVertices, s + clipOutputCount * vertexSize); + for (let ii = 0; ii < clipOutputLength; ii += 2) { + let x = clipOutputItems[ii], y = clipOutputItems[ii + 1]; + clippedVerticesItems[s] = x; + clippedVerticesItems[s + 1] = y; + clippedVerticesItems[s + 2] = light.r; + clippedVerticesItems[s + 3] = light.g; + clippedVerticesItems[s + 4] = light.b; + clippedVerticesItems[s + 5] = light.a; + let c0 = x - x3, c1 = y - y3; + let a = (d0 * c0 + d1 * c1) * d; + let b = (d4 * c0 + d2 * c1) * d; + let c = 1 - a - b; + clippedVerticesItems[s + 6] = u1 * a + u2 * b + u3 * c; + clippedVerticesItems[s + 7] = v1 * a + v2 * b + v3 * c; + if (twoColor) { + clippedVerticesItems[s + 8] = dark.r; + clippedVerticesItems[s + 9] = dark.g; + clippedVerticesItems[s + 10] = dark.b; + clippedVerticesItems[s + 11] = dark.a; + } + s += vertexSize; + } + s = clippedTriangles.length; + let clippedTrianglesItems = Utils.setArraySize(clippedTriangles, s + 3 * (clipOutputCount - 2)); + clipOutputCount--; + for (let ii = 1; ii < clipOutputCount; ii++) { + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = index + ii; + clippedTrianglesItems[s + 2] = index + ii + 1; + s += 3; + } + index += clipOutputCount + 1; + } else { + let clippedVerticesItems = Utils.setArraySize(clippedVertices, s + 3 * vertexSize); + clippedVerticesItems[s] = x1; + clippedVerticesItems[s + 1] = y1; + clippedVerticesItems[s + 2] = light.r; + clippedVerticesItems[s + 3] = light.g; + clippedVerticesItems[s + 4] = light.b; + clippedVerticesItems[s + 5] = light.a; + if (!twoColor) { + clippedVerticesItems[s + 6] = u1; + clippedVerticesItems[s + 7] = v1; + clippedVerticesItems[s + 8] = x2; + clippedVerticesItems[s + 9] = y2; + clippedVerticesItems[s + 10] = light.r; + clippedVerticesItems[s + 11] = light.g; + clippedVerticesItems[s + 12] = light.b; + clippedVerticesItems[s + 13] = light.a; + clippedVerticesItems[s + 14] = u2; + clippedVerticesItems[s + 15] = v2; + clippedVerticesItems[s + 16] = x3; + clippedVerticesItems[s + 17] = y3; + clippedVerticesItems[s + 18] = light.r; + clippedVerticesItems[s + 19] = light.g; + clippedVerticesItems[s + 20] = light.b; + clippedVerticesItems[s + 21] = light.a; + clippedVerticesItems[s + 22] = u3; + clippedVerticesItems[s + 23] = v3; + } else { + clippedVerticesItems[s + 6] = u1; + clippedVerticesItems[s + 7] = v1; + clippedVerticesItems[s + 8] = dark.r; + clippedVerticesItems[s + 9] = dark.g; + clippedVerticesItems[s + 10] = dark.b; + clippedVerticesItems[s + 11] = dark.a; + clippedVerticesItems[s + 12] = x2; + clippedVerticesItems[s + 13] = y2; + clippedVerticesItems[s + 14] = light.r; + clippedVerticesItems[s + 15] = light.g; + clippedVerticesItems[s + 16] = light.b; + clippedVerticesItems[s + 17] = light.a; + clippedVerticesItems[s + 18] = u2; + clippedVerticesItems[s + 19] = v2; + clippedVerticesItems[s + 20] = dark.r; + clippedVerticesItems[s + 21] = dark.g; + clippedVerticesItems[s + 22] = dark.b; + clippedVerticesItems[s + 23] = dark.a; + clippedVerticesItems[s + 24] = x3; + clippedVerticesItems[s + 25] = y3; + clippedVerticesItems[s + 26] = light.r; + clippedVerticesItems[s + 27] = light.g; + clippedVerticesItems[s + 28] = light.b; + clippedVerticesItems[s + 29] = light.a; + clippedVerticesItems[s + 30] = u3; + clippedVerticesItems[s + 31] = v3; + clippedVerticesItems[s + 32] = dark.r; + clippedVerticesItems[s + 33] = dark.g; + clippedVerticesItems[s + 34] = dark.b; + clippedVerticesItems[s + 35] = dark.a; + } + s = clippedTriangles.length; + let clippedTrianglesItems = Utils.setArraySize(clippedTriangles, s + 3); + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = index + 1; + clippedTrianglesItems[s + 2] = index + 2; + index += 3; + continue outer; + } + } + } + } + /** Clips the input triangle against the convex, clockwise clipping area. If the triangle lies entirely within the clipping + * area, false is returned. The clipping area must duplicate the first vertex at the end of the vertices list. */ + clip(x1, y1, x2, y2, x3, y3, clippingArea, output) { + let originalOutput = output; + let clipped = false; + let input; + if (clippingArea.length % 4 >= 2) { + input = output; + output = this.scratch; + } else + input = this.scratch; + input.length = 0; + input.push(x1); + input.push(y1); + input.push(x2); + input.push(y2); + input.push(x3); + input.push(y3); + input.push(x1); + input.push(y1); + output.length = 0; + let clippingVertices = clippingArea; + let clippingVerticesLast = clippingArea.length - 4; + for (let i = 0; ; i += 2) { + let edgeX = clippingVertices[i], edgeY = clippingVertices[i + 1]; + let edgeX2 = clippingVertices[i + 2], edgeY2 = clippingVertices[i + 3]; + let deltaX = edgeX - edgeX2, deltaY = edgeY - edgeY2; + let inputVertices = input; + let inputVerticesLength = input.length - 2, outputStart = output.length; + for (let ii = 0; ii < inputVerticesLength; ii += 2) { + let inputX = inputVertices[ii], inputY = inputVertices[ii + 1]; + let inputX2 = inputVertices[ii + 2], inputY2 = inputVertices[ii + 3]; + let side2 = deltaX * (inputY2 - edgeY2) - deltaY * (inputX2 - edgeX2) > 0; + if (deltaX * (inputY - edgeY2) - deltaY * (inputX - edgeX2) > 0) { + if (side2) { + output.push(inputX2); + output.push(inputY2); + continue; + } + let c0 = inputY2 - inputY, c2 = inputX2 - inputX; + let s = c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY); + if (Math.abs(s) > 1e-6) { + let ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / s; + output.push(edgeX + (edgeX2 - edgeX) * ua); + output.push(edgeY + (edgeY2 - edgeY) * ua); + } else { + output.push(edgeX); + output.push(edgeY); + } + } else if (side2) { + let c0 = inputY2 - inputY, c2 = inputX2 - inputX; + let s = c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY); + if (Math.abs(s) > 1e-6) { + let ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / s; + output.push(edgeX + (edgeX2 - edgeX) * ua); + output.push(edgeY + (edgeY2 - edgeY) * ua); + } else { + output.push(edgeX); + output.push(edgeY); + } + output.push(inputX2); + output.push(inputY2); + } + clipped = true; + } + if (outputStart == output.length) { + originalOutput.length = 0; + return true; + } + output.push(output[0]); + output.push(output[1]); + if (i == clippingVerticesLast) + break; + let temp = output; + output = input; + output.length = 0; + input = temp; + } + if (originalOutput != output) { + originalOutput.length = 0; + for (let i = 0, n = output.length - 2; i < n; i++) + originalOutput[i] = output[i]; + } else + originalOutput.length = originalOutput.length - 2; + return clipped; + } + static makeClockwise(polygon) { + let vertices = polygon; + let verticeslength = polygon.length; + let area = vertices[verticeslength - 2] * vertices[1] - vertices[0] * vertices[verticeslength - 1], p1x = 0, p1y = 0, p2x = 0, p2y = 0; + for (let i = 0, n = verticeslength - 3; i < n; i += 2) { + p1x = vertices[i]; + p1y = vertices[i + 1]; + p2x = vertices[i + 2]; + p2y = vertices[i + 3]; + area += p1x * p2y - p2x * p1y; + } + if (area < 0) + return; + for (let i = 0, lastX = verticeslength - 2, n = verticeslength >> 1; i < n; i += 2) { + let x = vertices[i], y = vertices[i + 1]; + let other = lastX - i; + vertices[i] = vertices[other]; + vertices[i + 1] = vertices[other + 1]; + vertices[other] = x; + vertices[other + 1] = y; + } + } + }; + + // spine-core/src/SkeletonJson.ts + var SkeletonJson = class { + attachmentLoader; + /** Scales bone positions, image sizes, and translations as they are loaded. This allows different size images to be used at + * runtime than were used in Spine. + * + * See [Scaling](http://esotericsoftware.com/spine-loading-skeleton-data#Scaling) in the Spine Runtimes Guide. */ + scale = 1; + linkedMeshes = new Array(); + constructor(attachmentLoader) { + this.attachmentLoader = attachmentLoader; + } + readSkeletonData(json) { + let scale = this.scale; + let skeletonData = new SkeletonData(); + let root = typeof json === "string" ? JSON.parse(json) : json; + let skeletonMap = root.skeleton; + if (skeletonMap) { + skeletonData.hash = skeletonMap.hash; + skeletonData.version = skeletonMap.spine; + skeletonData.x = skeletonMap.x; + skeletonData.y = skeletonMap.y; + skeletonData.width = skeletonMap.width; + skeletonData.height = skeletonMap.height; + skeletonData.fps = skeletonMap.fps; + skeletonData.imagesPath = skeletonMap.images; + } + if (root.bones) { + for (let i = 0; i < root.bones.length; i++) { + let boneMap = root.bones[i]; + let parent = null; + let parentName = getValue(boneMap, "parent", null); + if (parentName) + parent = skeletonData.findBone(parentName); + let data = new BoneData(skeletonData.bones.length, boneMap.name, parent); + data.length = getValue(boneMap, "length", 0) * scale; + data.x = getValue(boneMap, "x", 0) * scale; + data.y = getValue(boneMap, "y", 0) * scale; + data.rotation = getValue(boneMap, "rotation", 0); + data.scaleX = getValue(boneMap, "scaleX", 1); + data.scaleY = getValue(boneMap, "scaleY", 1); + data.shearX = getValue(boneMap, "shearX", 0); + data.shearY = getValue(boneMap, "shearY", 0); + data.transformMode = Utils.enumValue(TransformMode, getValue(boneMap, "transform", "Normal")); + data.skinRequired = getValue(boneMap, "skin", false); + let color = getValue(boneMap, "color", null); + if (color) + data.color.setFromString(color); + skeletonData.bones.push(data); + } + } + if (root.slots) { + for (let i = 0; i < root.slots.length; i++) { + let slotMap = root.slots[i]; + let boneData = skeletonData.findBone(slotMap.bone); + if (!boneData) + throw new Error(`Couldn't find bone ${slotMap.bone} for slot ${slotMap.name}`); + let data = new SlotData(skeletonData.slots.length, slotMap.name, boneData); + let color = getValue(slotMap, "color", null); + if (color) + data.color.setFromString(color); + let dark = getValue(slotMap, "dark", null); + if (dark) + data.darkColor = Color.fromString(dark); + data.attachmentName = getValue(slotMap, "attachment", null); + data.blendMode = Utils.enumValue(BlendMode, getValue(slotMap, "blend", "normal")); + skeletonData.slots.push(data); + } + } + if (root.ik) { + for (let i = 0; i < root.ik.length; i++) { + let constraintMap = root.ik[i]; + let data = new IkConstraintData(constraintMap.name); + data.order = getValue(constraintMap, "order", 0); + data.skinRequired = getValue(constraintMap, "skin", false); + for (let ii = 0; ii < constraintMap.bones.length; ii++) { + let bone = skeletonData.findBone(constraintMap.bones[ii]); + if (!bone) + throw new Error(`Couldn't find bone ${constraintMap.bones[ii]} for IK constraint ${constraintMap.name}.`); + data.bones.push(bone); + } + let target = skeletonData.findBone(constraintMap.target); + ; + if (!target) + throw new Error(`Couldn't find target bone ${constraintMap.target} for IK constraint ${constraintMap.name}.`); + data.target = target; + data.mix = getValue(constraintMap, "mix", 1); + data.softness = getValue(constraintMap, "softness", 0) * scale; + data.bendDirection = getValue(constraintMap, "bendPositive", true) ? 1 : -1; + data.compress = getValue(constraintMap, "compress", false); + data.stretch = getValue(constraintMap, "stretch", false); + data.uniform = getValue(constraintMap, "uniform", false); + skeletonData.ikConstraints.push(data); + } + } + if (root.transform) { + for (let i = 0; i < root.transform.length; i++) { + let constraintMap = root.transform[i]; + let data = new TransformConstraintData(constraintMap.name); + data.order = getValue(constraintMap, "order", 0); + data.skinRequired = getValue(constraintMap, "skin", false); + for (let ii = 0; ii < constraintMap.bones.length; ii++) { + let boneName = constraintMap.bones[ii]; + let bone = skeletonData.findBone(boneName); + if (!bone) + throw new Error(`Couldn't find bone ${boneName} for transform constraint ${constraintMap.name}.`); + data.bones.push(bone); + } + let targetName = constraintMap.target; + let target = skeletonData.findBone(targetName); + if (!target) + throw new Error(`Couldn't find target bone ${targetName} for transform constraint ${constraintMap.name}.`); + data.target = target; + data.local = getValue(constraintMap, "local", false); + data.relative = getValue(constraintMap, "relative", false); + data.offsetRotation = getValue(constraintMap, "rotation", 0); + data.offsetX = getValue(constraintMap, "x", 0) * scale; + data.offsetY = getValue(constraintMap, "y", 0) * scale; + data.offsetScaleX = getValue(constraintMap, "scaleX", 0); + data.offsetScaleY = getValue(constraintMap, "scaleY", 0); + data.offsetShearY = getValue(constraintMap, "shearY", 0); + data.mixRotate = getValue(constraintMap, "mixRotate", 1); + data.mixX = getValue(constraintMap, "mixX", 1); + data.mixY = getValue(constraintMap, "mixY", data.mixX); + data.mixScaleX = getValue(constraintMap, "mixScaleX", 1); + data.mixScaleY = getValue(constraintMap, "mixScaleY", data.mixScaleX); + data.mixShearY = getValue(constraintMap, "mixShearY", 1); + skeletonData.transformConstraints.push(data); + } + } + if (root.path) { + for (let i = 0; i < root.path.length; i++) { + let constraintMap = root.path[i]; + let data = new PathConstraintData(constraintMap.name); + data.order = getValue(constraintMap, "order", 0); + data.skinRequired = getValue(constraintMap, "skin", false); + for (let ii = 0; ii < constraintMap.bones.length; ii++) { + let boneName = constraintMap.bones[ii]; + let bone = skeletonData.findBone(boneName); + if (!bone) + throw new Error(`Couldn't find bone ${boneName} for path constraint ${constraintMap.name}.`); + data.bones.push(bone); + } + let targetName = constraintMap.target; + let target = skeletonData.findSlot(targetName); + if (!target) + throw new Error(`Couldn't find target slot ${targetName} for path constraint ${constraintMap.name}.`); + data.target = target; + data.positionMode = Utils.enumValue(PositionMode, getValue(constraintMap, "positionMode", "Percent")); + data.spacingMode = Utils.enumValue(SpacingMode, getValue(constraintMap, "spacingMode", "Length")); + data.rotateMode = Utils.enumValue(RotateMode, getValue(constraintMap, "rotateMode", "Tangent")); + data.offsetRotation = getValue(constraintMap, "rotation", 0); + data.position = getValue(constraintMap, "position", 0); + if (data.positionMode == 0 /* Fixed */) + data.position *= scale; + data.spacing = getValue(constraintMap, "spacing", 0); + if (data.spacingMode == 0 /* Length */ || data.spacingMode == 1 /* Fixed */) + data.spacing *= scale; + data.mixRotate = getValue(constraintMap, "mixRotate", 1); + data.mixX = getValue(constraintMap, "mixX", 1); + data.mixY = getValue(constraintMap, "mixY", data.mixX); + skeletonData.pathConstraints.push(data); + } + } + if (root.skins) { + for (let i = 0; i < root.skins.length; i++) { + let skinMap = root.skins[i]; + let skin = new Skin(skinMap.name); + if (skinMap.bones) { + for (let ii = 0; ii < skinMap.bones.length; ii++) { + let boneName = skinMap.bones[ii]; + let bone = skeletonData.findBone(boneName); + if (!bone) + throw new Error(`Couldn't find bone ${boneName} for skin ${skinMap.name}.`); + skin.bones.push(bone); + } + } + if (skinMap.ik) { + for (let ii = 0; ii < skinMap.ik.length; ii++) { + let constraintName = skinMap.ik[ii]; + let constraint = skeletonData.findIkConstraint(constraintName); + if (!constraint) + throw new Error(`Couldn't find IK constraint ${constraintName} for skin ${skinMap.name}.`); + skin.constraints.push(constraint); + } + } + if (skinMap.transform) { + for (let ii = 0; ii < skinMap.transform.length; ii++) { + let constraintName = skinMap.transform[ii]; + let constraint = skeletonData.findTransformConstraint(constraintName); + if (!constraint) + throw new Error(`Couldn't find transform constraint ${constraintName} for skin ${skinMap.name}.`); + skin.constraints.push(constraint); + } + } + if (skinMap.path) { + for (let ii = 0; ii < skinMap.path.length; ii++) { + let constraintName = skinMap.path[ii]; + let constraint = skeletonData.findPathConstraint(constraintName); + if (!constraint) + throw new Error(`Couldn't find path constraint ${constraintName} for skin ${skinMap.name}.`); + skin.constraints.push(constraint); + } + } + for (let slotName in skinMap.attachments) { + let slot = skeletonData.findSlot(slotName); + if (!slot) + throw new Error(`Couldn't find slot ${slotName} for skin ${skinMap.name}.`); + let slotMap = skinMap.attachments[slotName]; + for (let entryName in slotMap) { + let attachment = this.readAttachment(slotMap[entryName], skin, slot.index, entryName, skeletonData); + if (attachment) + skin.setAttachment(slot.index, entryName, attachment); + } + } + skeletonData.skins.push(skin); + if (skin.name == "default") + skeletonData.defaultSkin = skin; + } + } + for (let i = 0, n = this.linkedMeshes.length; i < n; i++) { + let linkedMesh = this.linkedMeshes[i]; + let skin = !linkedMesh.skin ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin); + if (!skin) + throw new Error(`Skin not found: ${linkedMesh.skin}`); + let parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); + if (!parent) + throw new Error(`Parent mesh not found: ${linkedMesh.parent}`); + linkedMesh.mesh.timelineAttachment = linkedMesh.inheritTimeline ? parent : linkedMesh.mesh; + linkedMesh.mesh.setParentMesh(parent); + if (linkedMesh.mesh.region != null) + linkedMesh.mesh.updateRegion(); + } + this.linkedMeshes.length = 0; + if (root.events) { + for (let eventName in root.events) { + let eventMap = root.events[eventName]; + let data = new EventData(eventName); + data.intValue = getValue(eventMap, "int", 0); + data.floatValue = getValue(eventMap, "float", 0); + data.stringValue = getValue(eventMap, "string", ""); + data.audioPath = getValue(eventMap, "audio", null); + if (data.audioPath) { + data.volume = getValue(eventMap, "volume", 1); + data.balance = getValue(eventMap, "balance", 0); + } + skeletonData.events.push(data); + } + } + if (root.animations) { + for (let animationName in root.animations) { + let animationMap = root.animations[animationName]; + this.readAnimation(animationMap, animationName, skeletonData); + } + } + return skeletonData; + } + readAttachment(map, skin, slotIndex, name, skeletonData) { + let scale = this.scale; + name = getValue(map, "name", name); + switch (getValue(map, "type", "region")) { + case "region": { + let path = getValue(map, "path", name); + let sequence = this.readSequence(getValue(map, "sequence", null)); + let region = this.attachmentLoader.newRegionAttachment(skin, name, path, sequence); + if (!region) + return null; + region.path = path; + region.x = getValue(map, "x", 0) * scale; + region.y = getValue(map, "y", 0) * scale; + region.scaleX = getValue(map, "scaleX", 1); + region.scaleY = getValue(map, "scaleY", 1); + region.rotation = getValue(map, "rotation", 0); + region.width = map.width * scale; + region.height = map.height * scale; + region.sequence = sequence; + let color = getValue(map, "color", null); + if (color) + region.color.setFromString(color); + if (region.region != null) + region.updateRegion(); + return region; + } + case "boundingbox": { + let box = this.attachmentLoader.newBoundingBoxAttachment(skin, name); + if (!box) + return null; + this.readVertices(map, box, map.vertexCount << 1); + let color = getValue(map, "color", null); + if (color) + box.color.setFromString(color); + return box; + } + case "mesh": + case "linkedmesh": { + let path = getValue(map, "path", name); + let sequence = this.readSequence(getValue(map, "sequence", null)); + let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path, sequence); + if (!mesh) + return null; + mesh.path = path; + let color = getValue(map, "color", null); + if (color) + mesh.color.setFromString(color); + mesh.width = getValue(map, "width", 0) * scale; + mesh.height = getValue(map, "height", 0) * scale; + mesh.sequence = sequence; + let parent = getValue(map, "parent", null); + if (parent) { + this.linkedMeshes.push(new LinkedMesh2(mesh, getValue(map, "skin", null), slotIndex, parent, getValue(map, "timelines", true))); + return mesh; + } + let uvs = map.uvs; + this.readVertices(map, mesh, uvs.length); + mesh.triangles = map.triangles; + mesh.regionUVs = uvs; + if (mesh.region != null) + mesh.updateRegion(); + mesh.edges = getValue(map, "edges", null); + mesh.hullLength = getValue(map, "hull", 0) * 2; + return mesh; + } + case "path": { + let path = this.attachmentLoader.newPathAttachment(skin, name); + if (!path) + return null; + path.closed = getValue(map, "closed", false); + path.constantSpeed = getValue(map, "constantSpeed", true); + let vertexCount = map.vertexCount; + this.readVertices(map, path, vertexCount << 1); + let lengths = Utils.newArray(vertexCount / 3, 0); + for (let i = 0; i < map.lengths.length; i++) + lengths[i] = map.lengths[i] * scale; + path.lengths = lengths; + let color = getValue(map, "color", null); + if (color) + path.color.setFromString(color); + return path; + } + case "point": { + let point = this.attachmentLoader.newPointAttachment(skin, name); + if (!point) + return null; + point.x = getValue(map, "x", 0) * scale; + point.y = getValue(map, "y", 0) * scale; + point.rotation = getValue(map, "rotation", 0); + let color = getValue(map, "color", null); + if (color) + point.color.setFromString(color); + return point; + } + case "clipping": { + let clip = this.attachmentLoader.newClippingAttachment(skin, name); + if (!clip) + return null; + let end = getValue(map, "end", null); + if (end) + clip.endSlot = skeletonData.findSlot(end); + let vertexCount = map.vertexCount; + this.readVertices(map, clip, vertexCount << 1); + let color = getValue(map, "color", null); + if (color) + clip.color.setFromString(color); + return clip; + } + } + return null; + } + readSequence(map) { + if (map == null) + return null; + let sequence = new Sequence(getValue(map, "count", 0)); + sequence.start = getValue(map, "start", 1); + sequence.digits = getValue(map, "digits", 0); + sequence.setupIndex = getValue(map, "setup", 0); + return sequence; + } + readVertices(map, attachment, verticesLength) { + let scale = this.scale; + attachment.worldVerticesLength = verticesLength; + let vertices = map.vertices; + if (verticesLength == vertices.length) { + let scaledVertices = Utils.toFloatArray(vertices); + if (scale != 1) { + for (let i = 0, n = vertices.length; i < n; i++) + scaledVertices[i] *= scale; + } + attachment.vertices = scaledVertices; + return; + } + let weights = new Array(); + let bones = new Array(); + for (let i = 0, n = vertices.length; i < n; ) { + let boneCount = vertices[i++]; + bones.push(boneCount); + for (let nn = i + boneCount * 4; i < nn; i += 4) { + bones.push(vertices[i]); + weights.push(vertices[i + 1] * scale); + weights.push(vertices[i + 2] * scale); + weights.push(vertices[i + 3]); + } + } + attachment.bones = bones; + attachment.vertices = Utils.toFloatArray(weights); + } + readAnimation(map, name, skeletonData) { + let scale = this.scale; + let timelines = new Array(); + if (map.slots) { + for (let slotName in map.slots) { + let slotMap = map.slots[slotName]; + let slot = skeletonData.findSlot(slotName); + if (!slot) + throw new Error("Slot not found: " + slotName); + let slotIndex = slot.index; + for (let timelineName in slotMap) { + let timelineMap = slotMap[timelineName]; + if (!timelineMap) + continue; + let frames = timelineMap.length; + if (timelineName == "attachment") { + let timeline = new AttachmentTimeline(frames, slotIndex); + for (let frame = 0; frame < frames; frame++) { + let keyMap = timelineMap[frame]; + timeline.setFrame(frame, getValue(keyMap, "time", 0), getValue(keyMap, "name", null)); + } + timelines.push(timeline); + } else if (timelineName == "rgba") { + let timeline = new RGBATimeline(frames, frames << 2, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color = Color.fromString(keyMap.color); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color.r, color.g, color.b, color.a); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let newColor = Color.fromString(nextMap.color); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, color.a, newColor.a, 1); + } + time = time2; + color = newColor; + keyMap = nextMap; + } + timelines.push(timeline); + } else if (timelineName == "rgb") { + let timeline = new RGBTimeline(frames, frames * 3, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color = Color.fromString(keyMap.color); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color.r, color.g, color.b); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let newColor = Color.fromString(nextMap.color); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1); + } + time = time2; + color = newColor; + keyMap = nextMap; + } + timelines.push(timeline); + } else if (timelineName == "alpha") { + timelines.push(readTimeline12(timelineMap, new AlphaTimeline(frames, frames, slotIndex), 0, 1)); + } else if (timelineName == "rgba2") { + let timeline = new RGBA2Timeline(frames, frames * 7, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color = Color.fromString(keyMap.light); + let color2 = Color.fromString(keyMap.dark); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color.r, color.g, color.b, color.a, color2.r, color2.g, color2.b); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let newColor = Color.fromString(nextMap.light); + let newColor2 = Color.fromString(nextMap.dark); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, color.a, newColor.a, 1); + bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, color2.r, newColor2.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, color2.g, newColor2.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 6, time, time2, color2.b, newColor2.b, 1); + } + time = time2; + color = newColor; + color2 = newColor2; + keyMap = nextMap; + } + timelines.push(timeline); + } else if (timelineName == "rgb2") { + let timeline = new RGB2Timeline(frames, frames * 6, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color = Color.fromString(keyMap.light); + let color2 = Color.fromString(keyMap.dark); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color.r, color.g, color.b, color2.r, color2.g, color2.b); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let newColor = Color.fromString(nextMap.light); + let newColor2 = Color.fromString(nextMap.dark); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, color2.r, newColor2.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, color2.g, newColor2.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, color2.b, newColor2.b, 1); + } + time = time2; + color = newColor; + color2 = newColor2; + keyMap = nextMap; + } + timelines.push(timeline); + } + } + } + } + if (map.bones) { + for (let boneName in map.bones) { + let boneMap = map.bones[boneName]; + let bone = skeletonData.findBone(boneName); + if (!bone) + throw new Error("Bone not found: " + boneName); + let boneIndex = bone.index; + for (let timelineName in boneMap) { + let timelineMap = boneMap[timelineName]; + let frames = timelineMap.length; + if (frames == 0) + continue; + if (timelineName === "rotate") { + timelines.push(readTimeline12(timelineMap, new RotateTimeline(frames, frames, boneIndex), 0, 1)); + } else if (timelineName === "translate") { + let timeline = new TranslateTimeline(frames, frames << 1, boneIndex); + timelines.push(readTimeline22(timelineMap, timeline, "x", "y", 0, scale)); + } else if (timelineName === "translatex") { + let timeline = new TranslateXTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, scale)); + } else if (timelineName === "translatey") { + let timeline = new TranslateYTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, scale)); + } else if (timelineName === "scale") { + let timeline = new ScaleTimeline(frames, frames << 1, boneIndex); + timelines.push(readTimeline22(timelineMap, timeline, "x", "y", 1, 1)); + } else if (timelineName === "scalex") { + let timeline = new ScaleXTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 1, 1)); + } else if (timelineName === "scaley") { + let timeline = new ScaleYTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 1, 1)); + } else if (timelineName === "shear") { + let timeline = new ShearTimeline(frames, frames << 1, boneIndex); + timelines.push(readTimeline22(timelineMap, timeline, "x", "y", 0, 1)); + } else if (timelineName === "shearx") { + let timeline = new ShearXTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, 1)); + } else if (timelineName === "sheary") { + let timeline = new ShearYTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, 1)); + } + } + } + } + if (map.ik) { + for (let constraintName in map.ik) { + let constraintMap = map.ik[constraintName]; + let keyMap = constraintMap[0]; + if (!keyMap) + continue; + let constraint = skeletonData.findIkConstraint(constraintName); + if (!constraint) + throw new Error("IK Constraint not found: " + constraintName); + let constraintIndex = skeletonData.ikConstraints.indexOf(constraint); + let timeline = new IkConstraintTimeline(constraintMap.length, constraintMap.length << 1, constraintIndex); + let time = getValue(keyMap, "time", 0); + let mix = getValue(keyMap, "mix", 1); + let softness = getValue(keyMap, "softness", 0) * scale; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mix, softness, getValue(keyMap, "bendPositive", true) ? 1 : -1, getValue(keyMap, "compress", false), getValue(keyMap, "stretch", false)); + let nextMap = constraintMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let mix2 = getValue(nextMap, "mix", 1); + let softness2 = getValue(nextMap, "softness", 0) * scale; + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mix, mix2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, softness, softness2, scale); + } + time = time2; + mix = mix2; + softness = softness2; + keyMap = nextMap; + } + timelines.push(timeline); + } + } + if (map.transform) { + for (let constraintName in map.transform) { + let timelineMap = map.transform[constraintName]; + let keyMap = timelineMap[0]; + if (!keyMap) + continue; + let constraint = skeletonData.findTransformConstraint(constraintName); + if (!constraint) + throw new Error("Transform constraint not found: " + constraintName); + let constraintIndex = skeletonData.transformConstraints.indexOf(constraint); + let timeline = new TransformConstraintTimeline(timelineMap.length, timelineMap.length * 6, constraintIndex); + let time = getValue(keyMap, "time", 0); + let mixRotate = getValue(keyMap, "mixRotate", 1); + let mixX = getValue(keyMap, "mixX", 1); + let mixY = getValue(keyMap, "mixY", mixX); + let mixScaleX = getValue(keyMap, "mixScaleX", 1); + let mixScaleY = getValue(keyMap, "mixScaleY", mixScaleX); + let mixShearY = getValue(keyMap, "mixShearY", 1); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let mixRotate2 = getValue(nextMap, "mixRotate", 1); + let mixX2 = getValue(nextMap, "mixX", 1); + let mixY2 = getValue(nextMap, "mixY", mixX2); + let mixScaleX2 = getValue(nextMap, "mixScaleX", 1); + let mixScaleY2 = getValue(nextMap, "mixScaleY", mixScaleX2); + let mixShearY2 = getValue(nextMap, "mixShearY", 1); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mixRotate, mixRotate2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, mixX, mixX2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, mixY, mixY2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, mixScaleX, mixScaleX2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, mixScaleY, mixScaleY2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, mixShearY, mixShearY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + mixScaleX = mixScaleX2; + mixScaleY = mixScaleY2; + mixScaleX = mixScaleX2; + keyMap = nextMap; + } + timelines.push(timeline); + } + } + if (map.path) { + for (let constraintName in map.path) { + let constraintMap = map.path[constraintName]; + let constraint = skeletonData.findPathConstraint(constraintName); + if (!constraint) + throw new Error("Path constraint not found: " + constraintName); + let constraintIndex = skeletonData.pathConstraints.indexOf(constraint); + for (let timelineName in constraintMap) { + let timelineMap = constraintMap[timelineName]; + let keyMap = timelineMap[0]; + if (!keyMap) + continue; + let frames = timelineMap.length; + if (timelineName === "position") { + let timeline = new PathConstraintPositionTimeline(frames, frames, constraintIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, constraint.positionMode == 0 /* Fixed */ ? scale : 1)); + } else if (timelineName === "spacing") { + let timeline = new PathConstraintSpacingTimeline(frames, frames, constraintIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, constraint.spacingMode == 0 /* Length */ || constraint.spacingMode == 1 /* Fixed */ ? scale : 1)); + } else if (timelineName === "mix") { + let timeline = new PathConstraintMixTimeline(frames, frames * 3, constraintIndex); + let time = getValue(keyMap, "time", 0); + let mixRotate = getValue(keyMap, "mixRotate", 1); + let mixX = getValue(keyMap, "mixX", 1); + let mixY = getValue(keyMap, "mixY", mixX); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let mixRotate2 = getValue(nextMap, "mixRotate", 1); + let mixX2 = getValue(nextMap, "mixX", 1); + let mixY2 = getValue(nextMap, "mixY", mixX2); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mixRotate, mixRotate2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, mixX, mixX2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, mixY, mixY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + keyMap = nextMap; + } + timelines.push(timeline); + } + } + } + } + if (map.attachments) { + for (let attachmentsName in map.attachments) { + let attachmentsMap = map.attachments[attachmentsName]; + let skin = skeletonData.findSkin(attachmentsName); + if (!skin) + throw new Error("Skin not found: " + attachmentsName); + for (let slotMapName in attachmentsMap) { + let slotMap = attachmentsMap[slotMapName]; + let slot = skeletonData.findSlot(slotMapName); + if (!slot) + throw new Error("Slot not found: " + slotMapName); + let slotIndex = slot.index; + for (let attachmentMapName in slotMap) { + let attachmentMap = slotMap[attachmentMapName]; + let attachment = skin.getAttachment(slotIndex, attachmentMapName); + for (let timelineMapName in attachmentMap) { + let timelineMap = attachmentMap[timelineMapName]; + let keyMap = timelineMap[0]; + if (!keyMap) + continue; + if (timelineMapName == "deform") { + let weighted = attachment.bones; + let vertices = attachment.vertices; + let deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + let timeline = new DeformTimeline(timelineMap.length, timelineMap.length, slotIndex, attachment); + let time = getValue(keyMap, "time", 0); + for (let frame = 0, bezier = 0; ; frame++) { + let deform; + let verticesValue = getValue(keyMap, "vertices", null); + if (!verticesValue) + deform = weighted ? Utils.newFloatArray(deformLength) : vertices; + else { + deform = Utils.newFloatArray(deformLength); + let start = getValue(keyMap, "offset", 0); + Utils.arrayCopy(verticesValue, 0, deform, start, verticesValue.length); + if (scale != 1) { + for (let i = start, n = i + verticesValue.length; i < n; i++) + deform[i] *= scale; + } + if (!weighted) { + for (let i = 0; i < deformLength; i++) + deform[i] += vertices[i]; + } + } + timeline.setFrame(frame, time, deform); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let curve = keyMap.curve; + if (curve) + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, 0, 1, 1); + time = time2; + keyMap = nextMap; + } + timelines.push(timeline); + } else if (timelineMapName == "sequence") { + let timeline = new SequenceTimeline(timelineMap.length, slotIndex, attachment); + let lastDelay = 0; + for (let frame = 0; frame < timelineMap.length; frame++) { + let delay = getValue(keyMap, "delay", lastDelay); + let time = getValue(keyMap, "time", 0); + let mode = SequenceMode[getValue(keyMap, "mode", "hold")]; + let index = getValue(keyMap, "index", 0); + timeline.setFrame(frame, time, mode, index, delay); + lastDelay = delay; + keyMap = timelineMap[frame + 1]; + } + timelines.push(timeline); + } + } + } + } + } + } + if (map.drawOrder) { + let timeline = new DrawOrderTimeline(map.drawOrder.length); + let slotCount = skeletonData.slots.length; + let frame = 0; + for (let i = 0; i < map.drawOrder.length; i++, frame++) { + let drawOrderMap = map.drawOrder[i]; + let drawOrder = null; + let offsets = getValue(drawOrderMap, "offsets", null); + if (offsets) { + drawOrder = Utils.newArray(slotCount, -1); + let unchanged = Utils.newArray(slotCount - offsets.length, 0); + let originalIndex = 0, unchangedIndex = 0; + for (let ii = 0; ii < offsets.length; ii++) { + let offsetMap = offsets[ii]; + let slot = skeletonData.findSlot(offsetMap.slot); + if (!slot) + throw new Error("Slot not found: " + slot); + let slotIndex = slot.index; + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + drawOrder[originalIndex + offsetMap.offset] = originalIndex++; + } + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + for (let ii = slotCount - 1; ii >= 0; ii--) + if (drawOrder[ii] == -1) + drawOrder[ii] = unchanged[--unchangedIndex]; + } + timeline.setFrame(frame, getValue(drawOrderMap, "time", 0), drawOrder); + } + timelines.push(timeline); + } + if (map.events) { + let timeline = new EventTimeline(map.events.length); + let frame = 0; + for (let i = 0; i < map.events.length; i++, frame++) { + let eventMap = map.events[i]; + let eventData = skeletonData.findEvent(eventMap.name); + if (!eventData) + throw new Error("Event not found: " + eventMap.name); + let event = new Event(Utils.toSinglePrecision(getValue(eventMap, "time", 0)), eventData); + event.intValue = getValue(eventMap, "int", eventData.intValue); + event.floatValue = getValue(eventMap, "float", eventData.floatValue); + event.stringValue = getValue(eventMap, "string", eventData.stringValue); + if (event.data.audioPath) { + event.volume = getValue(eventMap, "volume", 1); + event.balance = getValue(eventMap, "balance", 0); + } + timeline.setFrame(frame, event); + } + timelines.push(timeline); + } + let duration = 0; + for (let i = 0, n = timelines.length; i < n; i++) + duration = Math.max(duration, timelines[i].getDuration()); + skeletonData.animations.push(new Animation(name, timelines, duration)); + } + }; + var LinkedMesh2 = class { + parent; + skin; + slotIndex; + mesh; + inheritTimeline; + constructor(mesh, skin, slotIndex, parent, inheritDeform) { + this.mesh = mesh; + this.skin = skin; + this.slotIndex = slotIndex; + this.parent = parent; + this.inheritTimeline = inheritDeform; + } + }; + function readTimeline12(keys, timeline, defaultValue, scale) { + let keyMap = keys[0]; + let time = getValue(keyMap, "time", 0); + let value = getValue(keyMap, "value", defaultValue) * scale; + let bezier = 0; + for (let frame = 0; ; frame++) { + timeline.setFrame(frame, time, value); + let nextMap = keys[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + return timeline; + } + let time2 = getValue(nextMap, "time", 0); + let value2 = getValue(nextMap, "value", defaultValue) * scale; + if (keyMap.curve) + bezier = readCurve(keyMap.curve, timeline, bezier, frame, 0, time, time2, value, value2, scale); + time = time2; + value = value2; + keyMap = nextMap; + } + } + function readTimeline22(keys, timeline, name1, name2, defaultValue, scale) { + let keyMap = keys[0]; + let time = getValue(keyMap, "time", 0); + let value1 = getValue(keyMap, name1, defaultValue) * scale; + let value2 = getValue(keyMap, name2, defaultValue) * scale; + let bezier = 0; + for (let frame = 0; ; frame++) { + timeline.setFrame(frame, time, value1, value2); + let nextMap = keys[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + return timeline; + } + let time2 = getValue(nextMap, "time", 0); + let nvalue1 = getValue(nextMap, name1, defaultValue) * scale; + let nvalue2 = getValue(nextMap, name2, defaultValue) * scale; + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, value1, nvalue1, scale); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, value2, nvalue2, scale); + } + time = time2; + value1 = nvalue1; + value2 = nvalue2; + keyMap = nextMap; + } + } + function readCurve(curve, timeline, bezier, frame, value, time1, time2, value1, value2, scale) { + if (curve == "stepped") { + timeline.setStepped(frame); + return bezier; + } + let i = value << 2; + let cx1 = curve[i]; + let cy1 = curve[i + 1] * scale; + let cx2 = curve[i + 2]; + let cy2 = curve[i + 3] * scale; + timeline.setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2); + return bezier + 1; + } + function getValue(map, property, defaultValue) { + return map[property] !== void 0 ? map[property] : defaultValue; + } + + // spine-core/src/polyfills.ts + (() => { + if (typeof Math.fround === "undefined") { + Math.fround = function(array) { + return function(x) { + return array[0] = x, array[0]; + }; + }(new Float32Array(1)); + } + })(); + + // spine-canvas/src/CanvasTexture.ts + var CanvasTexture = class extends Texture { + constructor(image) { + super(image); + } + setFilters(minFilter, magFilter) { + } + setWraps(uWrap, vWrap) { + } + dispose() { + } + }; + + // spine-canvas/src/AssetManager.ts + var AssetManager = class extends AssetManagerBase { + constructor(pathPrefix = "", downloader = new Downloader()) { + super((image) => { + return new CanvasTexture(image); + }, pathPrefix, downloader); + } + }; + + // spine-canvas/src/SkeletonRenderer.ts + var worldVertices = Utils.newFloatArray(8); + var _SkeletonRenderer = class { + ctx; + triangleRendering = false; + debugRendering = false; + vertices = Utils.newFloatArray(8 * 1024); + tempColor = new Color(); + constructor(context) { + this.ctx = context; + } + draw(skeleton) { + if (this.triangleRendering) + this.drawTriangles(skeleton); + else + this.drawImages(skeleton); + } + drawImages(skeleton) { + let ctx = this.ctx; + let color = this.tempColor; + let skeletonColor = skeleton.color; + let drawOrder = skeleton.drawOrder; + if (this.debugRendering) + ctx.strokeStyle = "green"; + for (let i = 0, n = drawOrder.length; i < n; i++) { + let slot = drawOrder[i]; + let bone = slot.bone; + if (!bone.active) + continue; + let attachment = slot.getAttachment(); + if (!(attachment instanceof RegionAttachment)) + continue; + attachment.computeWorldVertices(slot, worldVertices, 0, 2); + let region = attachment.region; + let image = region.texture.getImage(); + let slotColor = slot.color; + let regionColor = attachment.color; + color.set( + skeletonColor.r * slotColor.r * regionColor.r, + skeletonColor.g * slotColor.g * regionColor.g, + skeletonColor.b * slotColor.b * regionColor.b, + skeletonColor.a * slotColor.a * regionColor.a + ); + ctx.save(); + ctx.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY); + ctx.translate(attachment.offset[0], attachment.offset[1]); + ctx.rotate(attachment.rotation * Math.PI / 180); + let atlasScale = attachment.width / region.originalWidth; + ctx.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY); + let w = region.width, h = region.height; + ctx.translate(w / 2, h / 2); + if (attachment.region.degrees == 90) { + let t = w; + w = h; + h = t; + ctx.rotate(-Math.PI / 2); + } + ctx.scale(1, -1); + ctx.translate(-w / 2, -h / 2); + ctx.globalAlpha = color.a; + ctx.drawImage(image, image.width * region.u, image.height * region.v, w, h, 0, 0, w, h); + if (this.debugRendering) + ctx.strokeRect(0, 0, w, h); + ctx.restore(); + } + } + drawTriangles(skeleton) { + let ctx = this.ctx; + let color = this.tempColor; + let skeletonColor = skeleton.color; + let drawOrder = skeleton.drawOrder; + let blendMode = null; + let vertices = this.vertices; + let triangles = null; + for (let i = 0, n = drawOrder.length; i < n; i++) { + let slot = drawOrder[i]; + let attachment = slot.getAttachment(); + let texture; + let region; + if (attachment instanceof RegionAttachment) { + let regionAttachment = attachment; + vertices = this.computeRegionVertices(slot, regionAttachment, false); + triangles = _SkeletonRenderer.QUAD_TRIANGLES; + texture = regionAttachment.region.texture.getImage(); + } else if (attachment instanceof MeshAttachment) { + let mesh = attachment; + vertices = this.computeMeshVertices(slot, mesh, false); + triangles = mesh.triangles; + texture = mesh.region.texture.getImage(); + } else + continue; + if (texture) { + if (slot.data.blendMode != blendMode) + blendMode = slot.data.blendMode; + let slotColor = slot.color; + let attachmentColor = attachment.color; + color.set( + skeletonColor.r * slotColor.r * attachmentColor.r, + skeletonColor.g * slotColor.g * attachmentColor.g, + skeletonColor.b * slotColor.b * attachmentColor.b, + skeletonColor.a * slotColor.a * attachmentColor.a + ); + ctx.globalAlpha = color.a; + for (var j = 0; j < triangles.length; j += 3) { + let t1 = triangles[j] * 8, t2 = triangles[j + 1] * 8, t3 = triangles[j + 2] * 8; + let x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7]; + let x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7]; + let x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7]; + this.drawTriangle(texture, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2); + if (this.debugRendering) { + ctx.strokeStyle = "green"; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.lineTo(x0, y0); + ctx.stroke(); + } + } + } + } + this.ctx.globalAlpha = 1; + } + // Adapted from http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 + // Apache 2 licensed + drawTriangle(img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2) { + let ctx = this.ctx; + u0 *= img.width; + v0 *= img.height; + u1 *= img.width; + v1 *= img.height; + u2 *= img.width; + v2 *= img.height; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.closePath(); + x1 -= x0; + y1 -= y0; + x2 -= x0; + y2 -= y0; + u1 -= u0; + v1 -= v0; + u2 -= u0; + v2 -= v0; + var det = 1 / (u1 * v2 - u2 * v1), a = (v2 * x1 - v1 * x2) * det, b = (v2 * y1 - v1 * y2) * det, c = (u1 * x2 - u2 * x1) * det, d = (u1 * y2 - u2 * y1) * det, e = x0 - a * u0 - c * v0, f = y0 - b * u0 - d * v0; + ctx.save(); + ctx.transform(a, b, c, d, e, f); + ctx.clip(); + ctx.drawImage(img, 0, 0); + ctx.restore(); + } + computeRegionVertices(slot, region, pma) { + let skeletonColor = slot.bone.skeleton.color; + let slotColor = slot.color; + let regionColor = region.color; + let alpha = skeletonColor.a * slotColor.a * regionColor.a; + let multiplier = pma ? alpha : 1; + let color = this.tempColor; + color.set( + skeletonColor.r * slotColor.r * regionColor.r * multiplier, + skeletonColor.g * slotColor.g * regionColor.g * multiplier, + skeletonColor.b * slotColor.b * regionColor.b * multiplier, + alpha + ); + region.computeWorldVertices(slot, this.vertices, 0, _SkeletonRenderer.VERTEX_SIZE); + let vertices = this.vertices; + let uvs = region.uvs; + vertices[RegionAttachment.C1R] = color.r; + vertices[RegionAttachment.C1G] = color.g; + vertices[RegionAttachment.C1B] = color.b; + vertices[RegionAttachment.C1A] = color.a; + vertices[RegionAttachment.U1] = uvs[0]; + vertices[RegionAttachment.V1] = uvs[1]; + vertices[RegionAttachment.C2R] = color.r; + vertices[RegionAttachment.C2G] = color.g; + vertices[RegionAttachment.C2B] = color.b; + vertices[RegionAttachment.C2A] = color.a; + vertices[RegionAttachment.U2] = uvs[2]; + vertices[RegionAttachment.V2] = uvs[3]; + vertices[RegionAttachment.C3R] = color.r; + vertices[RegionAttachment.C3G] = color.g; + vertices[RegionAttachment.C3B] = color.b; + vertices[RegionAttachment.C3A] = color.a; + vertices[RegionAttachment.U3] = uvs[4]; + vertices[RegionAttachment.V3] = uvs[5]; + vertices[RegionAttachment.C4R] = color.r; + vertices[RegionAttachment.C4G] = color.g; + vertices[RegionAttachment.C4B] = color.b; + vertices[RegionAttachment.C4A] = color.a; + vertices[RegionAttachment.U4] = uvs[6]; + vertices[RegionAttachment.V4] = uvs[7]; + return vertices; + } + computeMeshVertices(slot, mesh, pma) { + let skeletonColor = slot.bone.skeleton.color; + let slotColor = slot.color; + let regionColor = mesh.color; + let alpha = skeletonColor.a * slotColor.a * regionColor.a; + let multiplier = pma ? alpha : 1; + let color = this.tempColor; + color.set( + skeletonColor.r * slotColor.r * regionColor.r * multiplier, + skeletonColor.g * slotColor.g * regionColor.g * multiplier, + skeletonColor.b * slotColor.b * regionColor.b * multiplier, + alpha + ); + let vertexCount = mesh.worldVerticesLength / 2; + let vertices = this.vertices; + if (vertices.length < mesh.worldVerticesLength) + this.vertices = vertices = Utils.newFloatArray(mesh.worldVerticesLength); + mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, _SkeletonRenderer.VERTEX_SIZE); + let uvs = mesh.uvs; + for (let i = 0, u = 0, v = 2; i < vertexCount; i++) { + vertices[v++] = color.r; + vertices[v++] = color.g; + vertices[v++] = color.b; + vertices[v++] = color.a; + vertices[v++] = uvs[u++]; + vertices[v++] = uvs[u++]; + v += 2; + } + return vertices; + } + }; + var SkeletonRenderer = _SkeletonRenderer; + __publicField(SkeletonRenderer, "QUAD_TRIANGLES", [0, 1, 2, 2, 3, 0]); + __publicField(SkeletonRenderer, "VERTEX_SIZE", 2 + 2 + 4); + return __toCommonJS(src_exports); +})(); +//# sourceMappingURL=spine-canvas.js.map diff --git a/lib/4.2/spine-canvas.js b/lib/4.2/spine-canvas.js new file mode 100644 index 0000000..2dbc1f7 --- /dev/null +++ b/lib/4.2/spine-canvas.js @@ -0,0 +1,11714 @@ +"use strict"; +var spine = (() => { + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + + // spine-canvas/src/index.ts + var index_exports = {}; + __export(index_exports, { + AlphaTimeline: () => AlphaTimeline, + Animation: () => Animation, + AnimationState: () => AnimationState, + AnimationStateAdapter: () => AnimationStateAdapter, + AnimationStateData: () => AnimationStateData, + AssetCache: () => AssetCache, + AssetManager: () => AssetManager, + AssetManagerBase: () => AssetManagerBase, + AtlasAttachmentLoader: () => AtlasAttachmentLoader, + Attachment: () => Attachment, + AttachmentTimeline: () => AttachmentTimeline, + BinaryInput: () => BinaryInput, + BlendMode: () => BlendMode, + Bone: () => Bone, + BoneData: () => BoneData, + BoundingBoxAttachment: () => BoundingBoxAttachment, + CURRENT: () => CURRENT, + CanvasTexture: () => CanvasTexture, + ClippingAttachment: () => ClippingAttachment, + Color: () => Color, + ConstraintData: () => ConstraintData, + CurveTimeline: () => CurveTimeline, + CurveTimeline1: () => CurveTimeline1, + CurveTimeline2: () => CurveTimeline2, + DebugUtils: () => DebugUtils, + DeformTimeline: () => DeformTimeline, + Downloader: () => Downloader, + DrawOrderTimeline: () => DrawOrderTimeline, + Event: () => Event, + EventData: () => EventData, + EventQueue: () => EventQueue, + EventTimeline: () => EventTimeline, + EventType: () => EventType, + FIRST: () => FIRST, + FakeTexture: () => FakeTexture, + HOLD_FIRST: () => HOLD_FIRST, + HOLD_MIX: () => HOLD_MIX, + HOLD_SUBSEQUENT: () => HOLD_SUBSEQUENT, + IkConstraint: () => IkConstraint, + IkConstraintData: () => IkConstraintData, + IkConstraintTimeline: () => IkConstraintTimeline, + Inherit: () => Inherit, + InheritTimeline: () => InheritTimeline, + IntSet: () => IntSet, + Interpolation: () => Interpolation, + MathUtils: () => MathUtils, + MeshAttachment: () => MeshAttachment, + MixBlend: () => MixBlend, + MixDirection: () => MixDirection, + PathAttachment: () => PathAttachment, + PathConstraint: () => PathConstraint, + PathConstraintData: () => PathConstraintData, + PathConstraintMixTimeline: () => PathConstraintMixTimeline, + PathConstraintPositionTimeline: () => PathConstraintPositionTimeline, + PathConstraintSpacingTimeline: () => PathConstraintSpacingTimeline, + Physics: () => Physics, + PhysicsConstraintDampingTimeline: () => PhysicsConstraintDampingTimeline, + PhysicsConstraintGravityTimeline: () => PhysicsConstraintGravityTimeline, + PhysicsConstraintInertiaTimeline: () => PhysicsConstraintInertiaTimeline, + PhysicsConstraintMassTimeline: () => PhysicsConstraintMassTimeline, + PhysicsConstraintMixTimeline: () => PhysicsConstraintMixTimeline, + PhysicsConstraintResetTimeline: () => PhysicsConstraintResetTimeline, + PhysicsConstraintStrengthTimeline: () => PhysicsConstraintStrengthTimeline, + PhysicsConstraintTimeline: () => PhysicsConstraintTimeline, + PhysicsConstraintWindTimeline: () => PhysicsConstraintWindTimeline, + PointAttachment: () => PointAttachment, + Pool: () => Pool, + PositionMode: () => PositionMode, + Pow: () => Pow, + PowOut: () => PowOut, + RGB2Timeline: () => RGB2Timeline, + RGBA2Timeline: () => RGBA2Timeline, + RGBATimeline: () => RGBATimeline, + RGBTimeline: () => RGBTimeline, + RegionAttachment: () => RegionAttachment, + RotateMode: () => RotateMode, + RotateTimeline: () => RotateTimeline, + SETUP: () => SETUP, + SUBSEQUENT: () => SUBSEQUENT, + ScaleTimeline: () => ScaleTimeline, + ScaleXTimeline: () => ScaleXTimeline, + ScaleYTimeline: () => ScaleYTimeline, + SequenceTimeline: () => SequenceTimeline, + ShearTimeline: () => ShearTimeline, + ShearXTimeline: () => ShearXTimeline, + ShearYTimeline: () => ShearYTimeline, + Skeleton: () => Skeleton, + SkeletonBinary: () => SkeletonBinary, + SkeletonBounds: () => SkeletonBounds, + SkeletonClipping: () => SkeletonClipping, + SkeletonData: () => SkeletonData, + SkeletonJson: () => SkeletonJson, + SkeletonRenderer: () => SkeletonRenderer, + Skin: () => Skin, + SkinEntry: () => SkinEntry, + Slot: () => Slot, + SlotData: () => SlotData, + SpacingMode: () => SpacingMode, + StringSet: () => StringSet, + Texture: () => Texture, + TextureAtlas: () => TextureAtlas, + TextureAtlasPage: () => TextureAtlasPage, + TextureAtlasRegion: () => TextureAtlasRegion, + TextureFilter: () => TextureFilter, + TextureRegion: () => TextureRegion, + TextureWrap: () => TextureWrap, + TimeKeeper: () => TimeKeeper, + Timeline: () => Timeline, + TrackEntry: () => TrackEntry, + TransformConstraint: () => TransformConstraint, + TransformConstraintData: () => TransformConstraintData, + TransformConstraintTimeline: () => TransformConstraintTimeline, + TranslateTimeline: () => TranslateTimeline, + TranslateXTimeline: () => TranslateXTimeline, + TranslateYTimeline: () => TranslateYTimeline, + Triangulator: () => Triangulator, + Utils: () => Utils, + Vector2: () => Vector2, + VertexAttachment: () => VertexAttachment, + WindowedMean: () => WindowedMean + }); + + // spine-core/src/Utils.ts + var IntSet = class { + array = new Array(); + add(value) { + let contains = this.contains(value); + this.array[value | 0] = value | 0; + return !contains; + } + contains(value) { + return this.array[value | 0] != void 0; + } + remove(value) { + this.array[value | 0] = void 0; + } + clear() { + this.array.length = 0; + } + }; + var StringSet = class { + entries = {}; + size = 0; + add(value) { + let contains = this.entries[value]; + this.entries[value] = true; + if (!contains) { + this.size++; + return true; + } + return false; + } + addAll(values) { + let oldSize = this.size; + for (var i = 0, n = values.length; i < n; i++) + this.add(values[i]); + return oldSize != this.size; + } + contains(value) { + return this.entries[value]; + } + clear() { + this.entries = {}; + this.size = 0; + } + }; + var Color = class _Color { + constructor(r = 0, g = 0, b = 0, a = 0) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + static WHITE = new _Color(1, 1, 1, 1); + static RED = new _Color(1, 0, 0, 1); + static GREEN = new _Color(0, 1, 0, 1); + static BLUE = new _Color(0, 0, 1, 1); + static MAGENTA = new _Color(1, 0, 1, 1); + set(r, g, b, a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + return this.clamp(); + } + setFromColor(c) { + this.r = c.r; + this.g = c.g; + this.b = c.b; + this.a = c.a; + return this; + } + setFromString(hex) { + hex = hex.charAt(0) == "#" ? hex.substr(1) : hex; + this.r = parseInt(hex.substr(0, 2), 16) / 255; + this.g = parseInt(hex.substr(2, 2), 16) / 255; + this.b = parseInt(hex.substr(4, 2), 16) / 255; + this.a = hex.length != 8 ? 1 : parseInt(hex.substr(6, 2), 16) / 255; + return this; + } + add(r, g, b, a) { + this.r += r; + this.g += g; + this.b += b; + this.a += a; + return this.clamp(); + } + clamp() { + if (this.r < 0) this.r = 0; + else if (this.r > 1) this.r = 1; + if (this.g < 0) this.g = 0; + else if (this.g > 1) this.g = 1; + if (this.b < 0) this.b = 0; + else if (this.b > 1) this.b = 1; + if (this.a < 0) this.a = 0; + else if (this.a > 1) this.a = 1; + return this; + } + static rgba8888ToColor(color, value) { + color.r = ((value & 4278190080) >>> 24) / 255; + color.g = ((value & 16711680) >>> 16) / 255; + color.b = ((value & 65280) >>> 8) / 255; + color.a = (value & 255) / 255; + } + static rgb888ToColor(color, value) { + color.r = ((value & 16711680) >>> 16) / 255; + color.g = ((value & 65280) >>> 8) / 255; + color.b = (value & 255) / 255; + } + toRgb888() { + const hex = (x) => ("0" + (x * 255).toString(16)).slice(-2); + return Number("0x" + hex(this.r) + hex(this.g) + hex(this.b)); + } + static fromString(hex, color = new _Color()) { + return color.setFromString(hex); + } + }; + var MathUtils = class _MathUtils { + static PI = 3.1415927; + static PI2 = _MathUtils.PI * 2; + static invPI2 = 1 / _MathUtils.PI2; + static radiansToDegrees = 180 / _MathUtils.PI; + static radDeg = _MathUtils.radiansToDegrees; + static degreesToRadians = _MathUtils.PI / 180; + static degRad = _MathUtils.degreesToRadians; + static clamp(value, min, max) { + if (value < min) return min; + if (value > max) return max; + return value; + } + static cosDeg(degrees) { + return Math.cos(degrees * _MathUtils.degRad); + } + static sinDeg(degrees) { + return Math.sin(degrees * _MathUtils.degRad); + } + static atan2Deg(y, x) { + return Math.atan2(y, x) * _MathUtils.degRad; + } + static signum(value) { + return value > 0 ? 1 : value < 0 ? -1 : 0; + } + static toInt(x) { + return x > 0 ? Math.floor(x) : Math.ceil(x); + } + static cbrt(x) { + let y = Math.pow(Math.abs(x), 1 / 3); + return x < 0 ? -y : y; + } + static randomTriangular(min, max) { + return _MathUtils.randomTriangularWith(min, max, (min + max) * 0.5); + } + static randomTriangularWith(min, max, mode) { + let u = Math.random(); + let d = max - min; + if (u <= (mode - min) / d) return min + Math.sqrt(u * d * (mode - min)); + return max - Math.sqrt((1 - u) * d * (max - mode)); + } + static isPowerOfTwo(value) { + return value && (value & value - 1) === 0; + } + }; + var Interpolation = class { + apply(start, end, a) { + return start + (end - start) * this.applyInternal(a); + } + }; + var Pow = class extends Interpolation { + power = 2; + constructor(power) { + super(); + this.power = power; + } + applyInternal(a) { + if (a <= 0.5) return Math.pow(a * 2, this.power) / 2; + return Math.pow((a - 1) * 2, this.power) / (this.power % 2 == 0 ? -2 : 2) + 1; + } + }; + var PowOut = class extends Pow { + constructor(power) { + super(power); + } + applyInternal(a) { + return Math.pow(a - 1, this.power) * (this.power % 2 == 0 ? -1 : 1) + 1; + } + }; + var Utils = class _Utils { + static SUPPORTS_TYPED_ARRAYS = typeof Float32Array !== "undefined"; + static arrayCopy(source, sourceStart, dest, destStart, numElements) { + for (let i = sourceStart, j = destStart; i < sourceStart + numElements; i++, j++) { + dest[j] = source[i]; + } + } + static arrayFill(array, fromIndex, toIndex, value) { + for (let i = fromIndex; i < toIndex; i++) + array[i] = value; + } + static setArraySize(array, size, value = 0) { + let oldSize = array.length; + if (oldSize == size) return array; + array.length = size; + if (oldSize < size) { + for (let i = oldSize; i < size; i++) array[i] = value; + } + return array; + } + static ensureArrayCapacity(array, size, value = 0) { + if (array.length >= size) return array; + return _Utils.setArraySize(array, size, value); + } + static newArray(size, defaultValue) { + let array = new Array(size); + for (let i = 0; i < size; i++) array[i] = defaultValue; + return array; + } + static newFloatArray(size) { + if (_Utils.SUPPORTS_TYPED_ARRAYS) + return new Float32Array(size); + else { + let array = new Array(size); + for (let i = 0; i < array.length; i++) array[i] = 0; + return array; + } + } + static newShortArray(size) { + if (_Utils.SUPPORTS_TYPED_ARRAYS) + return new Int16Array(size); + else { + let array = new Array(size); + for (let i = 0; i < array.length; i++) array[i] = 0; + return array; + } + } + static toFloatArray(array) { + return _Utils.SUPPORTS_TYPED_ARRAYS ? new Float32Array(array) : array; + } + static toSinglePrecision(value) { + return _Utils.SUPPORTS_TYPED_ARRAYS ? Math.fround(value) : value; + } + // This function is used to fix WebKit 602 specific issue described at http://esotericsoftware.com/forum/iOS-10-disappearing-graphics-10109 + static webkit602BugfixHelper(alpha, blend) { + } + static contains(array, element, identity = true) { + for (var i = 0; i < array.length; i++) + if (array[i] == element) return true; + return false; + } + static enumValue(type, name) { + return type[name[0].toUpperCase() + name.slice(1)]; + } + }; + var DebugUtils = class { + static logBones(skeleton) { + for (let i = 0; i < skeleton.bones.length; i++) { + let bone = skeleton.bones[i]; + console.log(bone.data.name + ", " + bone.a + ", " + bone.b + ", " + bone.c + ", " + bone.d + ", " + bone.worldX + ", " + bone.worldY); + } + } + }; + var Pool = class { + items = new Array(); + instantiator; + constructor(instantiator) { + this.instantiator = instantiator; + } + obtain() { + return this.items.length > 0 ? this.items.pop() : this.instantiator(); + } + free(item) { + if (item.reset) item.reset(); + this.items.push(item); + } + freeAll(items) { + for (let i = 0; i < items.length; i++) + this.free(items[i]); + } + clear() { + this.items.length = 0; + } + }; + var Vector2 = class { + constructor(x = 0, y = 0) { + this.x = x; + this.y = y; + } + set(x, y) { + this.x = x; + this.y = y; + return this; + } + length() { + let x = this.x; + let y = this.y; + return Math.sqrt(x * x + y * y); + } + normalize() { + let len = this.length(); + if (len != 0) { + this.x /= len; + this.y /= len; + } + return this; + } + }; + var TimeKeeper = class { + maxDelta = 0.064; + framesPerSecond = 0; + delta = 0; + totalTime = 0; + lastTime = Date.now() / 1e3; + frameCount = 0; + frameTime = 0; + update() { + let now = Date.now() / 1e3; + this.delta = now - this.lastTime; + this.frameTime += this.delta; + this.totalTime += this.delta; + if (this.delta > this.maxDelta) this.delta = this.maxDelta; + this.lastTime = now; + this.frameCount++; + if (this.frameTime > 1) { + this.framesPerSecond = this.frameCount / this.frameTime; + this.frameTime = 0; + this.frameCount = 0; + } + } + }; + var WindowedMean = class { + values; + addedValues = 0; + lastValue = 0; + mean = 0; + dirty = true; + constructor(windowSize = 32) { + this.values = new Array(windowSize); + } + hasEnoughData() { + return this.addedValues >= this.values.length; + } + addValue(value) { + if (this.addedValues < this.values.length) this.addedValues++; + this.values[this.lastValue++] = value; + if (this.lastValue > this.values.length - 1) this.lastValue = 0; + this.dirty = true; + } + getMean() { + if (this.hasEnoughData()) { + if (this.dirty) { + let mean = 0; + for (let i = 0; i < this.values.length; i++) + mean += this.values[i]; + this.mean = mean / this.values.length; + this.dirty = false; + } + return this.mean; + } + return 0; + } + }; + + // spine-core/src/attachments/Attachment.ts + var Attachment = class { + name; + constructor(name) { + if (!name) throw new Error("name cannot be null."); + this.name = name; + } + }; + var VertexAttachment = class _VertexAttachment extends Attachment { + static nextID = 0; + /** The unique ID for this attachment. */ + id = _VertexAttachment.nextID++; + /** The bones which affect the {@link #getVertices()}. The array entries are, for each vertex, the number of bones affecting + * the vertex followed by that many bone indices, which is the index of the bone in {@link Skeleton#bones}. Will be null + * if this attachment has no weights. */ + bones = null; + /** The vertex positions in the bone's coordinate system. For a non-weighted attachment, the values are `x,y` + * entries for each vertex. For a weighted attachment, the values are `x,y,weight` entries for each bone affecting + * each vertex. */ + vertices = []; + /** The maximum number of world vertex values that can be output by + * {@link #computeWorldVertices()} using the `count` parameter. */ + worldVerticesLength = 0; + /** Timelines for the timeline attachment are also applied to this attachment. + * May be null if no attachment-specific timelines should be applied. */ + timelineAttachment = this; + constructor(name) { + super(name); + } + /** Transforms the attachment's local {@link #vertices} to world coordinates. If the slot's {@link Slot#deform} is + * not empty, it is used to deform the vertices. + * + * See [World transforms](http://esotericsoftware.com/spine-runtime-skeletons#World-transforms) in the Spine + * Runtimes Guide. + * @param start The index of the first {@link #vertices} value to transform. Each vertex has 2 values, x and y. + * @param count The number of world vertex values to output. Must be <= {@link #worldVerticesLength} - `start`. + * @param worldVertices The output world vertices. Must have a length >= `offset` + `count` * + * `stride` / 2. + * @param offset The `worldVertices` index to begin writing values. + * @param stride The number of `worldVertices` entries between the value pairs written. */ + computeWorldVertices(slot, start, count, worldVertices2, offset, stride) { + count = offset + (count >> 1) * stride; + let skeleton = slot.bone.skeleton; + let deformArray = slot.deform; + let vertices = this.vertices; + let bones = this.bones; + if (!bones) { + if (deformArray.length > 0) vertices = deformArray; + let bone = slot.bone; + let x = bone.worldX; + let y = bone.worldY; + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + for (let v2 = start, w = offset; w < count; v2 += 2, w += stride) { + let vx = vertices[v2], vy = vertices[v2 + 1]; + worldVertices2[w] = vx * a + vy * b + x; + worldVertices2[w + 1] = vx * c + vy * d + y; + } + return; + } + let v = 0, skip = 0; + for (let i = 0; i < start; i += 2) { + let n = bones[v]; + v += n + 1; + skip += n; + } + let skeletonBones = skeleton.bones; + if (deformArray.length == 0) { + for (let w = offset, b = skip * 3; w < count; w += stride) { + let wx = 0, wy = 0; + let n = bones[v++]; + n += v; + for (; v < n; v++, b += 3) { + let bone = skeletonBones[bones[v]]; + let vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices2[w] = wx; + worldVertices2[w + 1] = wy; + } + } else { + let deform = deformArray; + for (let w = offset, b = skip * 3, f = skip << 1; w < count; w += stride) { + let wx = 0, wy = 0; + let n = bones[v++]; + n += v; + for (; v < n; v++, b += 3, f += 2) { + let bone = skeletonBones[bones[v]]; + let vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices2[w] = wx; + worldVertices2[w + 1] = wy; + } + } + } + /** Does not copy id (generated) or name (set on construction). **/ + copyTo(attachment) { + if (this.bones) { + attachment.bones = new Array(this.bones.length); + Utils.arrayCopy(this.bones, 0, attachment.bones, 0, this.bones.length); + } else + attachment.bones = null; + if (this.vertices) { + attachment.vertices = Utils.newFloatArray(this.vertices.length); + Utils.arrayCopy(this.vertices, 0, attachment.vertices, 0, this.vertices.length); + } + attachment.worldVerticesLength = this.worldVerticesLength; + attachment.timelineAttachment = this.timelineAttachment; + } + }; + + // spine-core/src/attachments/Sequence.ts + var Sequence = class _Sequence { + static _nextID = 0; + id = _Sequence.nextID(); + regions; + start = 0; + digits = 0; + /** The index of the region to show for the setup pose. */ + setupIndex = 0; + constructor(count) { + this.regions = new Array(count); + } + copy() { + let copy = new _Sequence(this.regions.length); + Utils.arrayCopy(this.regions, 0, copy.regions, 0, this.regions.length); + copy.start = this.start; + copy.digits = this.digits; + copy.setupIndex = this.setupIndex; + return copy; + } + apply(slot, attachment) { + let index = slot.sequenceIndex; + if (index == -1) index = this.setupIndex; + if (index >= this.regions.length) index = this.regions.length - 1; + let region = this.regions[index]; + if (attachment.region != region) { + attachment.region = region; + attachment.updateRegion(); + } + } + getPath(basePath, index) { + let result = basePath; + let frame = (this.start + index).toString(); + for (let i = this.digits - frame.length; i > 0; i--) + result += "0"; + result += frame; + return result; + } + static nextID() { + return _Sequence._nextID++; + } + }; + var SequenceMode = /* @__PURE__ */ ((SequenceMode2) => { + SequenceMode2[SequenceMode2["hold"] = 0] = "hold"; + SequenceMode2[SequenceMode2["once"] = 1] = "once"; + SequenceMode2[SequenceMode2["loop"] = 2] = "loop"; + SequenceMode2[SequenceMode2["pingpong"] = 3] = "pingpong"; + SequenceMode2[SequenceMode2["onceReverse"] = 4] = "onceReverse"; + SequenceMode2[SequenceMode2["loopReverse"] = 5] = "loopReverse"; + SequenceMode2[SequenceMode2["pingpongReverse"] = 6] = "pingpongReverse"; + return SequenceMode2; + })(SequenceMode || {}); + var SequenceModeValues = [ + 0 /* hold */, + 1 /* once */, + 2 /* loop */, + 3 /* pingpong */, + 4 /* onceReverse */, + 5 /* loopReverse */, + 6 /* pingpongReverse */ + ]; + + // spine-core/src/Animation.ts + var Animation = class { + /** The animation's name, which is unique across all animations in the skeleton. */ + name; + timelines = []; + timelineIds = new StringSet(); + /** The duration of the animation in seconds, which is the highest time of all keys in the timeline. */ + duration; + constructor(name, timelines, duration) { + if (!name) throw new Error("name cannot be null."); + this.name = name; + this.setTimelines(timelines); + this.duration = duration; + } + setTimelines(timelines) { + if (!timelines) throw new Error("timelines cannot be null."); + this.timelines = timelines; + this.timelineIds.clear(); + for (var i = 0; i < timelines.length; i++) + this.timelineIds.addAll(timelines[i].getPropertyIds()); + } + hasTimeline(ids) { + for (let i = 0; i < ids.length; i++) + if (this.timelineIds.contains(ids[i])) return true; + return false; + } + /** Applies all the animation's timelines to the specified skeleton. + * + * See Timeline {@link Timeline#apply(Skeleton, float, float, Array, float, MixBlend, MixDirection)}. + * @param loop If true, the animation repeats after {@link #getDuration()}. + * @param events May be null to ignore fired events. */ + apply(skeleton, lastTime, time, loop, events, alpha, blend, direction) { + if (!skeleton) throw new Error("skeleton cannot be null."); + if (loop && this.duration != 0) { + time %= this.duration; + if (lastTime > 0) lastTime %= this.duration; + } + let timelines = this.timelines; + for (let i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, lastTime, time, events, alpha, blend, direction); + } + }; + var MixBlend = /* @__PURE__ */ ((MixBlend2) => { + MixBlend2[MixBlend2["setup"] = 0] = "setup"; + MixBlend2[MixBlend2["first"] = 1] = "first"; + MixBlend2[MixBlend2["replace"] = 2] = "replace"; + MixBlend2[MixBlend2["add"] = 3] = "add"; + return MixBlend2; + })(MixBlend || {}); + var MixDirection = /* @__PURE__ */ ((MixDirection2) => { + MixDirection2[MixDirection2["mixIn"] = 0] = "mixIn"; + MixDirection2[MixDirection2["mixOut"] = 1] = "mixOut"; + return MixDirection2; + })(MixDirection || {}); + var Property = { + rotate: 0, + x: 1, + y: 2, + scaleX: 3, + scaleY: 4, + shearX: 5, + shearY: 6, + inherit: 7, + rgb: 8, + alpha: 9, + rgb2: 10, + attachment: 11, + deform: 12, + event: 13, + drawOrder: 14, + ikConstraint: 15, + transformConstraint: 16, + pathConstraintPosition: 17, + pathConstraintSpacing: 18, + pathConstraintMix: 19, + physicsConstraintInertia: 20, + physicsConstraintStrength: 21, + physicsConstraintDamping: 22, + physicsConstraintMass: 23, + physicsConstraintWind: 24, + physicsConstraintGravity: 25, + physicsConstraintMix: 26, + physicsConstraintReset: 27, + sequence: 28 + }; + var Timeline = class { + propertyIds; + frames; + constructor(frameCount, propertyIds) { + this.propertyIds = propertyIds; + this.frames = Utils.newFloatArray(frameCount * this.getFrameEntries()); + } + getPropertyIds() { + return this.propertyIds; + } + getFrameEntries() { + return 1; + } + getFrameCount() { + return this.frames.length / this.getFrameEntries(); + } + getDuration() { + return this.frames[this.frames.length - this.getFrameEntries()]; + } + static search1(frames, time) { + let n = frames.length; + for (let i = 1; i < n; i++) + if (frames[i] > time) return i - 1; + return n - 1; + } + static search(frames, time, step) { + let n = frames.length; + for (let i = step; i < n; i += step) + if (frames[i] > time) return i - step; + return n - step; + } + }; + var CurveTimeline = class extends Timeline { + curves; + // type, x, y, ... + constructor(frameCount, bezierCount, propertyIds) { + super(frameCount, propertyIds); + this.curves = Utils.newFloatArray( + frameCount + bezierCount * 18 + /*BEZIER_SIZE*/ + ); + this.curves[frameCount - 1] = 1; + } + /** Sets the specified key frame to linear interpolation. */ + setLinear(frame) { + this.curves[frame] = 0; + } + /** Sets the specified key frame to stepped interpolation. */ + setStepped(frame) { + this.curves[frame] = 1; + } + /** Shrinks the storage for Bezier curves, for use when bezierCount (specified in the constructor) was larger + * than the actual number of Bezier curves. */ + shrink(bezierCount) { + let size = this.getFrameCount() + bezierCount * 18; + if (this.curves.length > size) { + let newCurves = Utils.newFloatArray(size); + Utils.arrayCopy(this.curves, 0, newCurves, 0, size); + this.curves = newCurves; + } + } + /** Stores the segments for the specified Bezier curve. For timelines that modify multiple values, there may be more than + * one curve per frame. + * @param bezier The ordinal of this Bezier curve for this timeline, between 0 and bezierCount - 1 (specified + * in the constructor), inclusive. + * @param frame Between 0 and frameCount - 1, inclusive. + * @param value The index of the value for this frame that this curve is used for. + * @param time1 The time for the first key. + * @param value1 The value for the first key. + * @param cx1 The time for the first Bezier handle. + * @param cy1 The value for the first Bezier handle. + * @param cx2 The time of the second Bezier handle. + * @param cy2 The value for the second Bezier handle. + * @param time2 The time for the second key. + * @param value2 The value for the second key. */ + setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2) { + let curves = this.curves; + let i = this.getFrameCount() + bezier * 18; + if (value == 0) curves[frame] = 2 + i; + let tmpx = (time1 - cx1 * 2 + cx2) * 0.03, tmpy = (value1 - cy1 * 2 + cy2) * 0.03; + let dddx = ((cx1 - cx2) * 3 - time1 + time2) * 6e-3, dddy = ((cy1 - cy2) * 3 - value1 + value2) * 6e-3; + let ddx = tmpx * 2 + dddx, ddy = tmpy * 2 + dddy; + let dx = (cx1 - time1) * 0.3 + tmpx + dddx * 0.16666667, dy = (cy1 - value1) * 0.3 + tmpy + dddy * 0.16666667; + let x = time1 + dx, y = value1 + dy; + for (let n = i + 18; i < n; i += 2) { + curves[i] = x; + curves[i + 1] = y; + dx += ddx; + dy += ddy; + ddx += dddx; + ddy += dddy; + x += dx; + y += dy; + } + } + /** Returns the Bezier interpolated value for the specified time. + * @param frameIndex The index into {@link #getFrames()} for the values of the frame before time. + * @param valueOffset The offset from frameIndex to the value this curve is used for. + * @param i The index of the Bezier segments. See {@link #getCurveType(int)}. */ + getBezierValue(time, frameIndex, valueOffset, i) { + let curves = this.curves; + if (curves[i] > time) { + let x2 = this.frames[frameIndex], y2 = this.frames[frameIndex + valueOffset]; + return y2 + (time - x2) / (curves[i] - x2) * (curves[i + 1] - y2); + } + let n = i + 18; + for (i += 2; i < n; i += 2) { + if (curves[i] >= time) { + let x2 = curves[i - 2], y2 = curves[i - 1]; + return y2 + (time - x2) / (curves[i] - x2) * (curves[i + 1] - y2); + } + } + frameIndex += this.getFrameEntries(); + let x = curves[n - 2], y = curves[n - 1]; + return y + (time - x) / (this.frames[frameIndex] - x) * (this.frames[frameIndex + valueOffset] - y); + } + }; + var CurveTimeline1 = class extends CurveTimeline { + constructor(frameCount, bezierCount, propertyId) { + super(frameCount, bezierCount, [propertyId]); + } + getFrameEntries() { + return 2; + } + /** Sets the time and value for the specified frame. + * @param frame Between 0 and frameCount, inclusive. + * @param time The frame time in seconds. */ + setFrame(frame, time, value) { + frame <<= 1; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*VALUE*/ + ] = value; + } + /** Returns the interpolated value for the specified time. */ + getCurveValue(time) { + let frames = this.frames; + let i = frames.length - 2; + for (let ii = 2; ii <= i; ii += 2) { + if (frames[ii] > time) { + i = ii - 2; + break; + } + } + let curveType = this.curves[i >> 1]; + switch (curveType) { + case 0: + let before = frames[i], value = frames[ + i + 1 + /*VALUE*/ + ]; + return value + (time - before) / (frames[ + i + 2 + /*ENTRIES*/ + ] - before) * (frames[ + i + 2 + 1 + /*VALUE*/ + ] - value); + case 1: + return frames[ + i + 1 + /*VALUE*/ + ]; + } + return this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + } + getRelativeValue(time, alpha, blend, current, setup) { + if (time < this.frames[0]) { + switch (blend) { + case 0 /* setup */: + return setup; + case 1 /* first */: + return current + (setup - current) * alpha; + } + return current; + } + let value = this.getCurveValue(time); + switch (blend) { + case 0 /* setup */: + return setup + value * alpha; + case 1 /* first */: + case 2 /* replace */: + value += setup - current; + } + return current + value * alpha; + } + getAbsoluteValue(time, alpha, blend, current, setup) { + if (time < this.frames[0]) { + switch (blend) { + case 0 /* setup */: + return setup; + case 1 /* first */: + return current + (setup - current) * alpha; + } + return current; + } + let value = this.getCurveValue(time); + if (blend == 0 /* setup */) return setup + (value - setup) * alpha; + return current + (value - current) * alpha; + } + getAbsoluteValue2(time, alpha, blend, current, setup, value) { + if (time < this.frames[0]) { + switch (blend) { + case 0 /* setup */: + return setup; + case 1 /* first */: + return current + (setup - current) * alpha; + } + return current; + } + if (blend == 0 /* setup */) return setup + (value - setup) * alpha; + return current + (value - current) * alpha; + } + getScaleValue(time, alpha, blend, direction, current, setup) { + const frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + return setup; + case 1 /* first */: + return current + (setup - current) * alpha; + } + return current; + } + let value = this.getCurveValue(time) * setup; + if (alpha == 1) { + if (blend == 3 /* add */) return current + value - setup; + return value; + } + if (direction == 1 /* mixOut */) { + switch (blend) { + case 0 /* setup */: + return setup + (Math.abs(value) * MathUtils.signum(setup) - setup) * alpha; + case 1 /* first */: + case 2 /* replace */: + return current + (Math.abs(value) * MathUtils.signum(current) - current) * alpha; + } + } else { + let s = 0; + switch (blend) { + case 0 /* setup */: + s = Math.abs(setup) * MathUtils.signum(value); + return s + (value - s) * alpha; + case 1 /* first */: + case 2 /* replace */: + s = Math.abs(current) * MathUtils.signum(value); + return s + (value - s) * alpha; + } + } + return current + (value - setup) * alpha; + } + }; + var CurveTimeline2 = class extends CurveTimeline { + /** @param bezierCount The maximum number of Bezier curves. See {@link #shrink(int)}. + * @param propertyIds Unique identifiers for the properties the timeline modifies. */ + constructor(frameCount, bezierCount, propertyId1, propertyId2) { + super(frameCount, bezierCount, [propertyId1, propertyId2]); + } + getFrameEntries() { + return 3; + } + /** Sets the time and values for the specified frame. + * @param frame Between 0 and frameCount, inclusive. + * @param time The frame time in seconds. */ + setFrame(frame, time, value1, value2) { + frame *= 3; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*VALUE1*/ + ] = value1; + this.frames[ + frame + 2 + /*VALUE2*/ + ] = value2; + } + }; + var RotateTimeline = class extends CurveTimeline1 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.rotate + "|" + boneIndex); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (bone.active) bone.rotation = this.getRelativeValue(time, alpha, blend, bone.rotation, bone.data.rotation); + } + }; + var TranslateTimeline = class extends CurveTimeline2 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super( + frameCount, + bezierCount, + Property.x + "|" + boneIndex, + Property.y + "|" + boneIndex + ); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + bone.x = bone.data.x; + bone.y = bone.data.y; + return; + case 1 /* first */: + bone.x += (bone.data.x - bone.x) * alpha; + bone.y += (bone.data.y - bone.y) * alpha; + } + return; + } + let x = 0, y = 0; + let i = Timeline.search( + frames, + time, + 3 + /*ENTRIES*/ + ); + let curveType = this.curves[ + i / 3 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: + let before = frames[i]; + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + let t = (time - before) / (frames[ + i + 3 + /*ENTRIES*/ + ] - before); + x += (frames[ + i + 3 + 1 + /*VALUE1*/ + ] - x) * t; + y += (frames[ + i + 3 + 2 + /*VALUE2*/ + ] - y) * t; + break; + case 1: + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + break; + default: + x = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + y = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + } + switch (blend) { + case 0 /* setup */: + bone.x = bone.data.x + x * alpha; + bone.y = bone.data.y + y * alpha; + break; + case 1 /* first */: + case 2 /* replace */: + bone.x += (bone.data.x + x - bone.x) * alpha; + bone.y += (bone.data.y + y - bone.y) * alpha; + break; + case 3 /* add */: + bone.x += x * alpha; + bone.y += y * alpha; + } + } + }; + var TranslateXTimeline = class extends CurveTimeline1 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.x + "|" + boneIndex); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (bone.active) bone.x = this.getRelativeValue(time, alpha, blend, bone.x, bone.data.x); + } + }; + var TranslateYTimeline = class extends CurveTimeline1 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.y + "|" + boneIndex); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (bone.active) bone.y = this.getRelativeValue(time, alpha, blend, bone.y, bone.data.y); + } + }; + var ScaleTimeline = class extends CurveTimeline2 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super( + frameCount, + bezierCount, + Property.scaleX + "|" + boneIndex, + Property.scaleY + "|" + boneIndex + ); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + bone.scaleX = bone.data.scaleX; + bone.scaleY = bone.data.scaleY; + return; + case 1 /* first */: + bone.scaleX += (bone.data.scaleX - bone.scaleX) * alpha; + bone.scaleY += (bone.data.scaleY - bone.scaleY) * alpha; + } + return; + } + let x, y; + let i = Timeline.search( + frames, + time, + 3 + /*ENTRIES*/ + ); + let curveType = this.curves[ + i / 3 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: + let before = frames[i]; + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + let t = (time - before) / (frames[ + i + 3 + /*ENTRIES*/ + ] - before); + x += (frames[ + i + 3 + 1 + /*VALUE1*/ + ] - x) * t; + y += (frames[ + i + 3 + 2 + /*VALUE2*/ + ] - y) * t; + break; + case 1: + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + break; + default: + x = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + y = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + } + x *= bone.data.scaleX; + y *= bone.data.scaleY; + if (alpha == 1) { + if (blend == 3 /* add */) { + bone.scaleX += x - bone.data.scaleX; + bone.scaleY += y - bone.data.scaleY; + } else { + bone.scaleX = x; + bone.scaleY = y; + } + } else { + let bx = 0, by = 0; + if (direction == 1 /* mixOut */) { + switch (blend) { + case 0 /* 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 1 /* first */: + case 2 /* 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 3 /* add */: + bone.scaleX += (x - bone.data.scaleX) * alpha; + bone.scaleY += (y - bone.data.scaleY) * alpha; + } + } else { + switch (blend) { + case 0 /* 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 1 /* first */: + case 2 /* 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 3 /* add */: + bone.scaleX += (x - bone.data.scaleX) * alpha; + bone.scaleY += (y - bone.data.scaleY) * alpha; + } + } + } + } + }; + var ScaleXTimeline = class extends CurveTimeline1 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.scaleX + "|" + boneIndex); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (bone.active) bone.scaleX = this.getScaleValue(time, alpha, blend, direction, bone.scaleX, bone.data.scaleX); + } + }; + var ScaleYTimeline = class extends CurveTimeline1 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.scaleY + "|" + boneIndex); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (bone.active) bone.scaleY = this.getScaleValue(time, alpha, blend, direction, bone.scaleY, bone.data.scaleY); + } + }; + var ShearTimeline = class extends CurveTimeline2 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super( + frameCount, + bezierCount, + Property.shearX + "|" + boneIndex, + Property.shearY + "|" + boneIndex + ); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + bone.shearX = bone.data.shearX; + bone.shearY = bone.data.shearY; + return; + case 1 /* first */: + bone.shearX += (bone.data.shearX - bone.shearX) * alpha; + bone.shearY += (bone.data.shearY - bone.shearY) * alpha; + } + return; + } + let x = 0, y = 0; + let i = Timeline.search( + frames, + time, + 3 + /*ENTRIES*/ + ); + let curveType = this.curves[ + i / 3 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: + let before = frames[i]; + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + let t = (time - before) / (frames[ + i + 3 + /*ENTRIES*/ + ] - before); + x += (frames[ + i + 3 + 1 + /*VALUE1*/ + ] - x) * t; + y += (frames[ + i + 3 + 2 + /*VALUE2*/ + ] - y) * t; + break; + case 1: + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + break; + default: + x = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + y = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + } + switch (blend) { + case 0 /* setup */: + bone.shearX = bone.data.shearX + x * alpha; + bone.shearY = bone.data.shearY + y * alpha; + break; + case 1 /* first */: + case 2 /* replace */: + bone.shearX += (bone.data.shearX + x - bone.shearX) * alpha; + bone.shearY += (bone.data.shearY + y - bone.shearY) * alpha; + break; + case 3 /* add */: + bone.shearX += x * alpha; + bone.shearY += y * alpha; + } + } + }; + var ShearXTimeline = class extends CurveTimeline1 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.shearX + "|" + boneIndex); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (bone.active) bone.shearX = this.getRelativeValue(time, alpha, blend, bone.shearX, bone.data.shearX); + } + }; + var ShearYTimeline = class extends CurveTimeline1 { + boneIndex = 0; + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, Property.shearY + "|" + boneIndex); + this.boneIndex = boneIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (bone.active) bone.shearY = this.getRelativeValue(time, alpha, blend, bone.shearY, bone.data.shearY); + } + }; + var InheritTimeline = class extends Timeline { + boneIndex = 0; + constructor(frameCount, boneIndex) { + super(frameCount, [Property.inherit + "|" + boneIndex]); + this.boneIndex = boneIndex; + } + getFrameEntries() { + return 2; + } + /** Sets the transform mode for the specified frame. + * @param frame Between 0 and frameCount, inclusive. + * @param time The frame time in seconds. */ + setFrame(frame, time, inherit) { + frame *= 2; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*INHERIT*/ + ] = inherit; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let bone = skeleton.bones[this.boneIndex]; + if (!bone.active) return; + if (direction == 1 /* mixOut */) { + if (blend == 0 /* setup */) bone.inherit = bone.data.inherit; + return; + } + let frames = this.frames; + if (time < frames[0]) { + if (blend == 0 /* setup */ || blend == 1 /* first */) bone.inherit = bone.data.inherit; + return; + } + bone.inherit = this.frames[ + Timeline.search( + frames, + time, + 2 + /*ENTRIES*/ + ) + 1 + /*INHERIT*/ + ]; + } + }; + var RGBATimeline = class extends CurveTimeline { + slotIndex = 0; + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, [ + Property.rgb + "|" + slotIndex, + Property.alpha + "|" + slotIndex + ]); + this.slotIndex = slotIndex; + } + getFrameEntries() { + return 5; + } + /** Sets the time in seconds, red, green, blue, and alpha for the specified key frame. */ + setFrame(frame, time, r, g, b, a) { + frame *= 5; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*R*/ + ] = r; + this.frames[ + frame + 2 + /*G*/ + ] = g; + this.frames[ + frame + 3 + /*B*/ + ] = b; + this.frames[ + frame + 4 + /*A*/ + ] = a; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) return; + let frames = this.frames; + let color = slot.color; + if (time < frames[0]) { + let setup = slot.data.color; + switch (blend) { + case 0 /* setup */: + color.setFromColor(setup); + return; + case 1 /* first */: + color.add( + (setup.r - color.r) * alpha, + (setup.g - color.g) * alpha, + (setup.b - color.b) * alpha, + (setup.a - color.a) * alpha + ); + } + return; + } + let r = 0, g = 0, b = 0, a = 0; + let i = Timeline.search( + frames, + time, + 5 + /*ENTRIES*/ + ); + let curveType = this.curves[ + i / 5 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: + let before = frames[i]; + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + a = frames[ + i + 4 + /*A*/ + ]; + let t = (time - before) / (frames[ + i + 5 + /*ENTRIES*/ + ] - before); + r += (frames[ + i + 5 + 1 + /*R*/ + ] - r) * t; + g += (frames[ + i + 5 + 2 + /*G*/ + ] - g) * t; + b += (frames[ + i + 5 + 3 + /*B*/ + ] - b) * t; + a += (frames[ + i + 5 + 4 + /*A*/ + ] - a) * t; + break; + case 1: + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + a = frames[ + i + 4 + /*A*/ + ]; + break; + default: + r = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + g = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + b = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + a = this.getBezierValue( + time, + i, + 4, + curveType + 18 * 3 - 2 + /*BEZIER*/ + ); + } + if (alpha == 1) + color.set(r, g, b, a); + else { + if (blend == 0 /* setup */) color.setFromColor(slot.data.color); + color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha); + } + } + }; + var RGBTimeline = class extends CurveTimeline { + slotIndex = 0; + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, [ + Property.rgb + "|" + slotIndex + ]); + this.slotIndex = slotIndex; + } + getFrameEntries() { + return 4; + } + /** Sets the time in seconds, red, green, blue, and alpha for the specified key frame. */ + setFrame(frame, time, r, g, b) { + frame <<= 2; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*R*/ + ] = r; + this.frames[ + frame + 2 + /*G*/ + ] = g; + this.frames[ + frame + 3 + /*B*/ + ] = b; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) return; + let frames = this.frames; + let color = slot.color; + if (time < frames[0]) { + let setup = slot.data.color; + switch (blend) { + case 0 /* setup */: + color.r = setup.r; + color.g = setup.g; + color.b = setup.b; + return; + case 1 /* first */: + color.r += (setup.r - color.r) * alpha; + color.g += (setup.g - color.g) * alpha; + color.b += (setup.b - color.b) * alpha; + } + return; + } + let r = 0, g = 0, b = 0; + let i = Timeline.search( + frames, + time, + 4 + /*ENTRIES*/ + ); + let curveType = this.curves[i >> 2]; + switch (curveType) { + case 0: + let before = frames[i]; + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + let t = (time - before) / (frames[ + i + 4 + /*ENTRIES*/ + ] - before); + r += (frames[ + i + 4 + 1 + /*R*/ + ] - r) * t; + g += (frames[ + i + 4 + 2 + /*G*/ + ] - g) * t; + b += (frames[ + i + 4 + 3 + /*B*/ + ] - b) * t; + break; + case 1: + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + break; + default: + r = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + g = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + b = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + } + if (alpha == 1) { + color.r = r; + color.g = g; + color.b = b; + } else { + if (blend == 0 /* setup */) { + let setup = slot.data.color; + color.r = setup.r; + color.g = setup.g; + color.b = setup.b; + } + color.r += (r - color.r) * alpha; + color.g += (g - color.g) * alpha; + color.b += (b - color.b) * alpha; + } + } + }; + var AlphaTimeline = class extends CurveTimeline1 { + slotIndex = 0; + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, Property.alpha + "|" + slotIndex); + this.slotIndex = slotIndex; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) return; + let color = slot.color; + if (time < this.frames[0]) { + let setup = slot.data.color; + switch (blend) { + case 0 /* setup */: + color.a = setup.a; + return; + case 1 /* first */: + color.a += (setup.a - color.a) * alpha; + } + return; + } + let a = this.getCurveValue(time); + if (alpha == 1) + color.a = a; + else { + if (blend == 0 /* setup */) color.a = slot.data.color.a; + color.a += (a - color.a) * alpha; + } + } + }; + var RGBA2Timeline = class extends CurveTimeline { + slotIndex = 0; + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, [ + Property.rgb + "|" + slotIndex, + Property.alpha + "|" + slotIndex, + Property.rgb2 + "|" + slotIndex + ]); + this.slotIndex = slotIndex; + } + getFrameEntries() { + return 8; + } + /** Sets the time in seconds, light, and dark colors for the specified key frame. */ + setFrame(frame, time, r, g, b, a, r2, g2, b2) { + frame <<= 3; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*R*/ + ] = r; + this.frames[ + frame + 2 + /*G*/ + ] = g; + this.frames[ + frame + 3 + /*B*/ + ] = b; + this.frames[ + frame + 4 + /*A*/ + ] = a; + this.frames[ + frame + 5 + /*R2*/ + ] = r2; + this.frames[ + frame + 6 + /*G2*/ + ] = g2; + this.frames[ + frame + 7 + /*B2*/ + ] = b2; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) return; + let frames = this.frames; + let light = slot.color, dark = slot.darkColor; + if (time < frames[0]) { + let setupLight = slot.data.color, setupDark = slot.data.darkColor; + switch (blend) { + case 0 /* setup */: + light.setFromColor(setupLight); + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; + return; + case 1 /* first */: + light.add( + (setupLight.r - light.r) * alpha, + (setupLight.g - light.g) * alpha, + (setupLight.b - light.b) * alpha, + (setupLight.a - light.a) * alpha + ); + dark.r += (setupDark.r - dark.r) * alpha; + dark.g += (setupDark.g - dark.g) * alpha; + dark.b += (setupDark.b - dark.b) * alpha; + } + return; + } + let r = 0, g = 0, b = 0, a = 0, r2 = 0, g2 = 0, b2 = 0; + let i = Timeline.search( + frames, + time, + 8 + /*ENTRIES*/ + ); + let curveType = this.curves[i >> 3]; + switch (curveType) { + case 0: + let before = frames[i]; + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + a = frames[ + i + 4 + /*A*/ + ]; + r2 = frames[ + i + 5 + /*R2*/ + ]; + g2 = frames[ + i + 6 + /*G2*/ + ]; + b2 = frames[ + i + 7 + /*B2*/ + ]; + let t = (time - before) / (frames[ + i + 8 + /*ENTRIES*/ + ] - before); + r += (frames[ + i + 8 + 1 + /*R*/ + ] - r) * t; + g += (frames[ + i + 8 + 2 + /*G*/ + ] - g) * t; + b += (frames[ + i + 8 + 3 + /*B*/ + ] - b) * t; + a += (frames[ + i + 8 + 4 + /*A*/ + ] - a) * t; + r2 += (frames[ + i + 8 + 5 + /*R2*/ + ] - r2) * t; + g2 += (frames[ + i + 8 + 6 + /*G2*/ + ] - g2) * t; + b2 += (frames[ + i + 8 + 7 + /*B2*/ + ] - b2) * t; + break; + case 1: + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + a = frames[ + i + 4 + /*A*/ + ]; + r2 = frames[ + i + 5 + /*R2*/ + ]; + g2 = frames[ + i + 6 + /*G2*/ + ]; + b2 = frames[ + i + 7 + /*B2*/ + ]; + break; + default: + r = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + g = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + b = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + a = this.getBezierValue( + time, + i, + 4, + curveType + 18 * 3 - 2 + /*BEZIER*/ + ); + r2 = this.getBezierValue( + time, + i, + 5, + curveType + 18 * 4 - 2 + /*BEZIER*/ + ); + g2 = this.getBezierValue( + time, + i, + 6, + curveType + 18 * 5 - 2 + /*BEZIER*/ + ); + b2 = this.getBezierValue( + time, + i, + 7, + curveType + 18 * 6 - 2 + /*BEZIER*/ + ); + } + if (alpha == 1) { + light.set(r, g, b, a); + dark.r = r2; + dark.g = g2; + dark.b = b2; + } else { + if (blend == 0 /* setup */) { + light.setFromColor(slot.data.color); + let setupDark = slot.data.darkColor; + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; + } + light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha); + dark.r += (r2 - dark.r) * alpha; + dark.g += (g2 - dark.g) * alpha; + dark.b += (b2 - dark.b) * alpha; + } + } + }; + var RGB2Timeline = class extends CurveTimeline { + slotIndex = 0; + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, [ + Property.rgb + "|" + slotIndex, + Property.rgb2 + "|" + slotIndex + ]); + this.slotIndex = slotIndex; + } + getFrameEntries() { + return 7; + } + /** Sets the time in seconds, light, and dark colors for the specified key frame. */ + setFrame(frame, time, r, g, b, r2, g2, b2) { + frame *= 7; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*R*/ + ] = r; + this.frames[ + frame + 2 + /*G*/ + ] = g; + this.frames[ + frame + 3 + /*B*/ + ] = b; + this.frames[ + frame + 4 + /*R2*/ + ] = r2; + this.frames[ + frame + 5 + /*G2*/ + ] = g2; + this.frames[ + frame + 6 + /*B2*/ + ] = b2; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) return; + let frames = this.frames; + let light = slot.color, dark = slot.darkColor; + if (time < frames[0]) { + let setupLight = slot.data.color, setupDark = slot.data.darkColor; + switch (blend) { + case 0 /* setup */: + light.r = setupLight.r; + light.g = setupLight.g; + light.b = setupLight.b; + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; + return; + case 1 /* first */: + light.r += (setupLight.r - light.r) * alpha; + light.g += (setupLight.g - light.g) * alpha; + light.b += (setupLight.b - light.b) * alpha; + dark.r += (setupDark.r - dark.r) * alpha; + dark.g += (setupDark.g - dark.g) * alpha; + dark.b += (setupDark.b - dark.b) * alpha; + } + return; + } + let r = 0, g = 0, b = 0, a = 0, r2 = 0, g2 = 0, b2 = 0; + let i = Timeline.search( + frames, + time, + 7 + /*ENTRIES*/ + ); + let curveType = this.curves[ + i / 7 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: + let before = frames[i]; + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + r2 = frames[ + i + 4 + /*R2*/ + ]; + g2 = frames[ + i + 5 + /*G2*/ + ]; + b2 = frames[ + i + 6 + /*B2*/ + ]; + let t = (time - before) / (frames[ + i + 7 + /*ENTRIES*/ + ] - before); + r += (frames[ + i + 7 + 1 + /*R*/ + ] - r) * t; + g += (frames[ + i + 7 + 2 + /*G*/ + ] - g) * t; + b += (frames[ + i + 7 + 3 + /*B*/ + ] - b) * t; + r2 += (frames[ + i + 7 + 4 + /*R2*/ + ] - r2) * t; + g2 += (frames[ + i + 7 + 5 + /*G2*/ + ] - g2) * t; + b2 += (frames[ + i + 7 + 6 + /*B2*/ + ] - b2) * t; + break; + case 1: + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + r2 = frames[ + i + 4 + /*R2*/ + ]; + g2 = frames[ + i + 5 + /*G2*/ + ]; + b2 = frames[ + i + 6 + /*B2*/ + ]; + break; + default: + r = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + g = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + b = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + r2 = this.getBezierValue( + time, + i, + 4, + curveType + 18 * 3 - 2 + /*BEZIER*/ + ); + g2 = this.getBezierValue( + time, + i, + 5, + curveType + 18 * 4 - 2 + /*BEZIER*/ + ); + b2 = this.getBezierValue( + time, + i, + 6, + curveType + 18 * 5 - 2 + /*BEZIER*/ + ); + } + if (alpha == 1) { + light.r = r; + light.g = g; + light.b = b; + dark.r = r2; + dark.g = g2; + dark.b = b2; + } else { + if (blend == 0 /* setup */) { + let setupLight = slot.data.color, setupDark = slot.data.darkColor; + light.r = setupLight.r; + light.g = setupLight.g; + light.b = setupLight.b; + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; + } + light.r += (r - light.r) * alpha; + light.g += (g - light.g) * alpha; + light.b += (b - light.b) * alpha; + dark.r += (r2 - dark.r) * alpha; + dark.g += (g2 - dark.g) * alpha; + dark.b += (b2 - dark.b) * alpha; + } + } + }; + var AttachmentTimeline = class extends Timeline { + slotIndex = 0; + /** The attachment name for each key frame. May contain null values to clear the attachment. */ + attachmentNames; + constructor(frameCount, slotIndex) { + super(frameCount, [ + Property.attachment + "|" + slotIndex + ]); + this.slotIndex = slotIndex; + this.attachmentNames = new Array(frameCount); + } + getFrameCount() { + return this.frames.length; + } + /** Sets the time in seconds and the attachment name for the specified key frame. */ + setFrame(frame, time, attachmentName) { + this.frames[frame] = time; + this.attachmentNames[frame] = attachmentName; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) return; + if (direction == 1 /* mixOut */) { + if (blend == 0 /* setup */) this.setAttachment(skeleton, slot, slot.data.attachmentName); + return; + } + if (time < this.frames[0]) { + if (blend == 0 /* setup */ || blend == 1 /* first */) this.setAttachment(skeleton, slot, slot.data.attachmentName); + return; + } + this.setAttachment(skeleton, slot, this.attachmentNames[Timeline.search1(this.frames, time)]); + } + setAttachment(skeleton, slot, attachmentName) { + slot.setAttachment(!attachmentName ? null : skeleton.getAttachment(this.slotIndex, attachmentName)); + } + }; + var DeformTimeline = class extends CurveTimeline { + slotIndex = 0; + /** The attachment that will be deformed. */ + attachment; + /** The vertices for each key frame. */ + vertices; + constructor(frameCount, bezierCount, slotIndex, attachment) { + super(frameCount, bezierCount, [ + Property.deform + "|" + slotIndex + "|" + attachment.id + ]); + this.slotIndex = slotIndex; + this.attachment = attachment; + this.vertices = new Array(frameCount); + } + getFrameCount() { + return this.frames.length; + } + /** Sets the time in seconds and the vertices for the specified key frame. + * @param vertices Vertex positions for an unweighted VertexAttachment, or deform offsets if it has weights. */ + setFrame(frame, time, vertices) { + this.frames[frame] = time; + this.vertices[frame] = vertices; + } + /** @param value1 Ignored (0 is used for a deform timeline). + * @param value2 Ignored (1 is used for a deform timeline). */ + setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2) { + let curves = this.curves; + let i = this.getFrameCount() + bezier * 18; + if (value == 0) curves[frame] = 2 + i; + let tmpx = (time1 - cx1 * 2 + cx2) * 0.03, tmpy = cy2 * 0.03 - cy1 * 0.06; + let dddx = ((cx1 - cx2) * 3 - time1 + time2) * 6e-3, dddy = (cy1 - cy2 + 0.33333333) * 0.018; + let ddx = tmpx * 2 + dddx, ddy = tmpy * 2 + dddy; + let dx = (cx1 - time1) * 0.3 + tmpx + dddx * 0.16666667, dy = cy1 * 0.3 + tmpy + dddy * 0.16666667; + let x = time1 + dx, y = dy; + for (let n = i + 18; i < n; i += 2) { + curves[i] = x; + curves[i + 1] = y; + dx += ddx; + dy += ddy; + ddx += dddx; + ddy += dddy; + x += dx; + y += dy; + } + } + getCurvePercent(time, frame) { + let curves = this.curves; + let i = curves[frame]; + switch (i) { + case 0: + let x2 = this.frames[frame]; + return (time - x2) / (this.frames[frame + this.getFrameEntries()] - x2); + case 1: + return 0; + } + i -= 2; + if (curves[i] > time) { + let x2 = this.frames[frame]; + return curves[i + 1] * (time - x2) / (curves[i] - x2); + } + let n = i + 18; + for (i += 2; i < n; i += 2) { + if (curves[i] >= time) { + let x2 = curves[i - 2], y2 = curves[i - 1]; + return y2 + (time - x2) / (curves[i] - x2) * (curves[i + 1] - y2); + } + } + let x = curves[n - 2], y = curves[n - 1]; + return y + (1 - y) * (time - x) / (this.frames[frame + this.getFrameEntries()] - x); + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) return; + let slotAttachment = slot.getAttachment(); + if (!slotAttachment) return; + if (!(slotAttachment instanceof VertexAttachment) || slotAttachment.timelineAttachment != this.attachment) return; + let deform = slot.deform; + if (deform.length == 0) blend = 0 /* setup */; + let vertices = this.vertices; + let vertexCount = vertices[0].length; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + deform.length = 0; + return; + case 1 /* first */: + if (alpha == 1) { + deform.length = 0; + return; + } + deform.length = vertexCount; + let vertexAttachment = slotAttachment; + if (!vertexAttachment.bones) { + let setupVertices = vertexAttachment.vertices; + for (var i = 0; i < vertexCount; i++) + deform[i] += (setupVertices[i] - deform[i]) * alpha; + } else { + alpha = 1 - alpha; + for (var i = 0; i < vertexCount; i++) + deform[i] *= alpha; + } + } + return; + } + deform.length = vertexCount; + if (time >= frames[frames.length - 1]) { + let lastVertices = vertices[frames.length - 1]; + if (alpha == 1) { + if (blend == 3 /* add */) { + let vertexAttachment = slotAttachment; + if (!vertexAttachment.bones) { + let setupVertices = vertexAttachment.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] += lastVertices[i2] - setupVertices[i2]; + } else { + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] += lastVertices[i2]; + } + } else + Utils.arrayCopy(lastVertices, 0, deform, 0, vertexCount); + } else { + switch (blend) { + case 0 /* setup */: { + let vertexAttachment2 = slotAttachment; + if (!vertexAttachment2.bones) { + let setupVertices = vertexAttachment2.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) { + let setup = setupVertices[i2]; + deform[i2] = setup + (lastVertices[i2] - setup) * alpha; + } + } else { + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] = lastVertices[i2] * alpha; + } + break; + } + case 1 /* first */: + case 2 /* replace */: + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] += (lastVertices[i2] - deform[i2]) * alpha; + break; + case 3 /* add */: + let vertexAttachment = slotAttachment; + if (!vertexAttachment.bones) { + let setupVertices = vertexAttachment.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] += (lastVertices[i2] - setupVertices[i2]) * alpha; + } else { + for (let i2 = 0; i2 < vertexCount; i2++) + deform[i2] += lastVertices[i2] * alpha; + } + } + } + return; + } + let frame = Timeline.search1(frames, time); + let percent = this.getCurvePercent(time, frame); + let prevVertices = vertices[frame]; + let nextVertices = vertices[frame + 1]; + if (alpha == 1) { + if (blend == 3 /* add */) { + let vertexAttachment = slotAttachment; + if (!vertexAttachment.bones) { + let setupVertices = vertexAttachment.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] += prev + (nextVertices[i2] - prev) * percent - setupVertices[i2]; + } + } else { + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] += prev + (nextVertices[i2] - prev) * percent; + } + } + } else { + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] = prev + (nextVertices[i2] - prev) * percent; + } + } + } else { + switch (blend) { + case 0 /* setup */: { + let vertexAttachment2 = slotAttachment; + if (!vertexAttachment2.bones) { + let setupVertices = vertexAttachment2.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2], setup = setupVertices[i2]; + deform[i2] = setup + (prev + (nextVertices[i2] - prev) * percent - setup) * alpha; + } + } else { + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] = (prev + (nextVertices[i2] - prev) * percent) * alpha; + } + } + break; + } + case 1 /* first */: + case 2 /* replace */: + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] += (prev + (nextVertices[i2] - prev) * percent - deform[i2]) * alpha; + } + break; + case 3 /* add */: + let vertexAttachment = slotAttachment; + if (!vertexAttachment.bones) { + let setupVertices = vertexAttachment.vertices; + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] += (prev + (nextVertices[i2] - prev) * percent - setupVertices[i2]) * alpha; + } + } else { + for (let i2 = 0; i2 < vertexCount; i2++) { + let prev = prevVertices[i2]; + deform[i2] += (prev + (nextVertices[i2] - prev) * percent) * alpha; + } + } + } + } + } + }; + var EventTimeline = class _EventTimeline extends Timeline { + static propertyIds = ["" + Property.event]; + /** The event for each key frame. */ + events; + constructor(frameCount) { + super(frameCount, _EventTimeline.propertyIds); + this.events = new Array(frameCount); + } + getFrameCount() { + return this.frames.length; + } + /** Sets the time in seconds and the event for the specified key frame. */ + setFrame(frame, event) { + this.frames[frame] = event.time; + this.events[frame] = event; + } + /** Fires events for frames > `lastTime` and <= `time`. */ + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + if (!firedEvents) return; + let frames = this.frames; + let frameCount = this.frames.length; + if (lastTime > time) { + this.apply(skeleton, lastTime, Number.MAX_VALUE, firedEvents, alpha, blend, direction); + lastTime = -1; + } else if (lastTime >= frames[frameCount - 1]) + return; + if (time < frames[0]) return; + let i = 0; + if (lastTime < frames[0]) + i = 0; + else { + i = Timeline.search1(frames, lastTime) + 1; + let frameTime = frames[i]; + while (i > 0) { + if (frames[i - 1] != frameTime) break; + i--; + } + } + for (; i < frameCount && time >= frames[i]; i++) + firedEvents.push(this.events[i]); + } + }; + var DrawOrderTimeline = class _DrawOrderTimeline extends Timeline { + static propertyIds = ["" + Property.drawOrder]; + /** The draw order for each key frame. See {@link #setFrame(int, float, int[])}. */ + drawOrders; + constructor(frameCount) { + super(frameCount, _DrawOrderTimeline.propertyIds); + this.drawOrders = new Array(frameCount); + } + getFrameCount() { + return this.frames.length; + } + /** Sets the time in seconds and the draw order for the specified key frame. + * @param drawOrder For each slot in {@link Skeleton#slots}, the index of the new draw order. May be null to use setup pose + * draw order. */ + setFrame(frame, time, drawOrder) { + this.frames[frame] = time; + this.drawOrders[frame] = drawOrder; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + if (direction == 1 /* mixOut */) { + if (blend == 0 /* setup */) Utils.arrayCopy(skeleton.slots, 0, skeleton.drawOrder, 0, skeleton.slots.length); + return; + } + if (time < this.frames[0]) { + if (blend == 0 /* setup */ || blend == 1 /* first */) Utils.arrayCopy(skeleton.slots, 0, skeleton.drawOrder, 0, skeleton.slots.length); + return; + } + let idx = Timeline.search1(this.frames, time); + let drawOrderToSetupIndex = this.drawOrders[idx]; + if (!drawOrderToSetupIndex) + Utils.arrayCopy(skeleton.slots, 0, skeleton.drawOrder, 0, skeleton.slots.length); + else { + let drawOrder = skeleton.drawOrder; + let slots = skeleton.slots; + for (let i = 0, n = drawOrderToSetupIndex.length; i < n; i++) + drawOrder[i] = slots[drawOrderToSetupIndex[i]]; + } + } + }; + var IkConstraintTimeline = class extends CurveTimeline { + /** The index of the IK constraint in {@link Skeleton#getIkConstraints()} that will be changed when this timeline is applied */ + constraintIndex = 0; + constructor(frameCount, bezierCount, ikConstraintIndex) { + super(frameCount, bezierCount, [ + Property.ikConstraint + "|" + ikConstraintIndex + ]); + this.constraintIndex = ikConstraintIndex; + } + getFrameEntries() { + return 6; + } + /** Sets the time in seconds, mix, softness, bend direction, compress, and stretch for the specified key frame. */ + setFrame(frame, time, mix, softness, bendDirection, compress, stretch) { + frame *= 6; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*MIX*/ + ] = mix; + this.frames[ + frame + 2 + /*SOFTNESS*/ + ] = softness; + this.frames[ + frame + 3 + /*BEND_DIRECTION*/ + ] = bendDirection; + this.frames[ + frame + 4 + /*COMPRESS*/ + ] = compress ? 1 : 0; + this.frames[ + frame + 5 + /*STRETCH*/ + ] = stretch ? 1 : 0; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint = skeleton.ikConstraints[this.constraintIndex]; + if (!constraint.active) return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + constraint.mix = constraint.data.mix; + constraint.softness = constraint.data.softness; + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + return; + case 1 /* first */: + constraint.mix += (constraint.data.mix - constraint.mix) * alpha; + constraint.softness += (constraint.data.softness - constraint.softness) * alpha; + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } + return; + } + let mix = 0, softness = 0; + let i = Timeline.search( + frames, + time, + 6 + /*ENTRIES*/ + ); + let curveType = this.curves[ + i / 6 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: + let before = frames[i]; + mix = frames[ + i + 1 + /*MIX*/ + ]; + softness = frames[ + i + 2 + /*SOFTNESS*/ + ]; + let t = (time - before) / (frames[ + i + 6 + /*ENTRIES*/ + ] - before); + mix += (frames[ + i + 6 + 1 + /*MIX*/ + ] - mix) * t; + softness += (frames[ + i + 6 + 2 + /*SOFTNESS*/ + ] - softness) * t; + break; + case 1: + mix = frames[ + i + 1 + /*MIX*/ + ]; + softness = frames[ + i + 2 + /*SOFTNESS*/ + ]; + break; + default: + mix = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + softness = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + } + if (blend == 0 /* setup */) { + constraint.mix = constraint.data.mix + (mix - constraint.data.mix) * alpha; + constraint.softness = constraint.data.softness + (softness - constraint.data.softness) * alpha; + if (direction == 1 /* mixOut */) { + constraint.bendDirection = constraint.data.bendDirection; + constraint.compress = constraint.data.compress; + constraint.stretch = constraint.data.stretch; + } else { + constraint.bendDirection = frames[ + i + 3 + /*BEND_DIRECTION*/ + ]; + constraint.compress = frames[ + i + 4 + /*COMPRESS*/ + ] != 0; + constraint.stretch = frames[ + i + 5 + /*STRETCH*/ + ] != 0; + } + } else { + constraint.mix += (mix - constraint.mix) * alpha; + constraint.softness += (softness - constraint.softness) * alpha; + if (direction == 0 /* mixIn */) { + constraint.bendDirection = frames[ + i + 3 + /*BEND_DIRECTION*/ + ]; + constraint.compress = frames[ + i + 4 + /*COMPRESS*/ + ] != 0; + constraint.stretch = frames[ + i + 5 + /*STRETCH*/ + ] != 0; + } + } + } + }; + var TransformConstraintTimeline = class extends CurveTimeline { + /** The index of the transform constraint slot in {@link Skeleton#transformConstraints} that will be changed. */ + constraintIndex = 0; + constructor(frameCount, bezierCount, transformConstraintIndex) { + super(frameCount, bezierCount, [ + Property.transformConstraint + "|" + transformConstraintIndex + ]); + this.constraintIndex = transformConstraintIndex; + } + getFrameEntries() { + return 7; + } + /** The time in seconds, rotate mix, translate mix, scale mix, and shear mix for the specified key frame. */ + setFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY) { + let frames = this.frames; + frame *= 7; + frames[frame] = time; + frames[ + frame + 1 + /*ROTATE*/ + ] = mixRotate; + frames[ + frame + 2 + /*X*/ + ] = mixX; + frames[ + frame + 3 + /*Y*/ + ] = mixY; + frames[ + frame + 4 + /*SCALEX*/ + ] = mixScaleX; + frames[ + frame + 5 + /*SCALEY*/ + ] = mixScaleY; + frames[ + frame + 6 + /*SHEARY*/ + ] = mixShearY; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint = skeleton.transformConstraints[this.constraintIndex]; + if (!constraint.active) return; + let frames = this.frames; + if (time < frames[0]) { + let data = constraint.data; + switch (blend) { + case 0 /* setup */: + constraint.mixRotate = data.mixRotate; + constraint.mixX = data.mixX; + constraint.mixY = data.mixY; + constraint.mixScaleX = data.mixScaleX; + constraint.mixScaleY = data.mixScaleY; + constraint.mixShearY = data.mixShearY; + return; + case 1 /* first */: + constraint.mixRotate += (data.mixRotate - constraint.mixRotate) * alpha; + constraint.mixX += (data.mixX - constraint.mixX) * alpha; + constraint.mixY += (data.mixY - constraint.mixY) * alpha; + constraint.mixScaleX += (data.mixScaleX - constraint.mixScaleX) * alpha; + constraint.mixScaleY += (data.mixScaleY - constraint.mixScaleY) * alpha; + constraint.mixShearY += (data.mixShearY - constraint.mixShearY) * alpha; + } + return; + } + let rotate, x, y, scaleX, scaleY, shearY; + let i = Timeline.search( + frames, + time, + 7 + /*ENTRIES*/ + ); + let curveType = this.curves[ + i / 7 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: + let before = frames[i]; + rotate = frames[ + i + 1 + /*ROTATE*/ + ]; + x = frames[ + i + 2 + /*X*/ + ]; + y = frames[ + i + 3 + /*Y*/ + ]; + scaleX = frames[ + i + 4 + /*SCALEX*/ + ]; + scaleY = frames[ + i + 5 + /*SCALEY*/ + ]; + shearY = frames[ + i + 6 + /*SHEARY*/ + ]; + let t = (time - before) / (frames[ + i + 7 + /*ENTRIES*/ + ] - before); + rotate += (frames[ + i + 7 + 1 + /*ROTATE*/ + ] - rotate) * t; + x += (frames[ + i + 7 + 2 + /*X*/ + ] - x) * t; + y += (frames[ + i + 7 + 3 + /*Y*/ + ] - y) * t; + scaleX += (frames[ + i + 7 + 4 + /*SCALEX*/ + ] - scaleX) * t; + scaleY += (frames[ + i + 7 + 5 + /*SCALEY*/ + ] - scaleY) * t; + shearY += (frames[ + i + 7 + 6 + /*SHEARY*/ + ] - shearY) * t; + break; + case 1: + rotate = frames[ + i + 1 + /*ROTATE*/ + ]; + x = frames[ + i + 2 + /*X*/ + ]; + y = frames[ + i + 3 + /*Y*/ + ]; + scaleX = frames[ + i + 4 + /*SCALEX*/ + ]; + scaleY = frames[ + i + 5 + /*SCALEY*/ + ]; + shearY = frames[ + i + 6 + /*SHEARY*/ + ]; + break; + default: + rotate = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + x = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + y = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + scaleX = this.getBezierValue( + time, + i, + 4, + curveType + 18 * 3 - 2 + /*BEZIER*/ + ); + scaleY = this.getBezierValue( + time, + i, + 5, + curveType + 18 * 4 - 2 + /*BEZIER*/ + ); + shearY = this.getBezierValue( + time, + i, + 6, + curveType + 18 * 5 - 2 + /*BEZIER*/ + ); + } + if (blend == 0 /* setup */) { + let data = constraint.data; + constraint.mixRotate = data.mixRotate + (rotate - data.mixRotate) * alpha; + constraint.mixX = data.mixX + (x - data.mixX) * alpha; + constraint.mixY = data.mixY + (y - data.mixY) * alpha; + constraint.mixScaleX = data.mixScaleX + (scaleX - data.mixScaleX) * alpha; + constraint.mixScaleY = data.mixScaleY + (scaleY - data.mixScaleY) * alpha; + constraint.mixShearY = data.mixShearY + (shearY - data.mixShearY) * alpha; + } else { + constraint.mixRotate += (rotate - constraint.mixRotate) * alpha; + constraint.mixX += (x - constraint.mixX) * alpha; + constraint.mixY += (y - constraint.mixY) * alpha; + constraint.mixScaleX += (scaleX - constraint.mixScaleX) * alpha; + constraint.mixScaleY += (scaleY - constraint.mixScaleY) * alpha; + constraint.mixShearY += (shearY - constraint.mixShearY) * alpha; + } + } + }; + var PathConstraintPositionTimeline = class extends CurveTimeline1 { + /** The index of the path constraint in {@link Skeleton#getPathConstraints()} that will be changed when this timeline is + * applied. */ + constraintIndex = 0; + constructor(frameCount, bezierCount, pathConstraintIndex) { + super(frameCount, bezierCount, Property.pathConstraintPosition + "|" + pathConstraintIndex); + this.constraintIndex = pathConstraintIndex; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint = skeleton.pathConstraints[this.constraintIndex]; + if (constraint.active) + constraint.position = this.getAbsoluteValue(time, alpha, blend, constraint.position, constraint.data.position); + } + }; + var PathConstraintSpacingTimeline = class extends CurveTimeline1 { + /** The index of the path constraint in {@link Skeleton#getPathConstraints()} that will be changed when this timeline is + * applied. */ + constraintIndex = 0; + constructor(frameCount, bezierCount, pathConstraintIndex) { + super(frameCount, bezierCount, Property.pathConstraintSpacing + "|" + pathConstraintIndex); + this.constraintIndex = pathConstraintIndex; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint = skeleton.pathConstraints[this.constraintIndex]; + if (constraint.active) + constraint.spacing = this.getAbsoluteValue(time, alpha, blend, constraint.spacing, constraint.data.spacing); + } + }; + var PathConstraintMixTimeline = class extends CurveTimeline { + /** The index of the path constraint in {@link Skeleton#getPathConstraints()} that will be changed when this timeline is + * applied. */ + constraintIndex = 0; + constructor(frameCount, bezierCount, pathConstraintIndex) { + super(frameCount, bezierCount, [ + Property.pathConstraintMix + "|" + pathConstraintIndex + ]); + this.constraintIndex = pathConstraintIndex; + } + getFrameEntries() { + return 4; + } + setFrame(frame, time, mixRotate, mixX, mixY) { + let frames = this.frames; + frame <<= 2; + frames[frame] = time; + frames[ + frame + 1 + /*ROTATE*/ + ] = mixRotate; + frames[ + frame + 2 + /*X*/ + ] = mixX; + frames[ + frame + 3 + /*Y*/ + ] = mixY; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint = skeleton.pathConstraints[this.constraintIndex]; + if (!constraint.active) return; + let frames = this.frames; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + constraint.mixRotate = constraint.data.mixRotate; + constraint.mixX = constraint.data.mixX; + constraint.mixY = constraint.data.mixY; + return; + case 1 /* first */: + constraint.mixRotate += (constraint.data.mixRotate - constraint.mixRotate) * alpha; + constraint.mixX += (constraint.data.mixX - constraint.mixX) * alpha; + constraint.mixY += (constraint.data.mixY - constraint.mixY) * alpha; + } + return; + } + let rotate, x, y; + let i = Timeline.search( + frames, + time, + 4 + /*ENTRIES*/ + ); + let curveType = this.curves[i >> 2]; + switch (curveType) { + case 0: + let before = frames[i]; + rotate = frames[ + i + 1 + /*ROTATE*/ + ]; + x = frames[ + i + 2 + /*X*/ + ]; + y = frames[ + i + 3 + /*Y*/ + ]; + let t = (time - before) / (frames[ + i + 4 + /*ENTRIES*/ + ] - before); + rotate += (frames[ + i + 4 + 1 + /*ROTATE*/ + ] - rotate) * t; + x += (frames[ + i + 4 + 2 + /*X*/ + ] - x) * t; + y += (frames[ + i + 4 + 3 + /*Y*/ + ] - y) * t; + break; + case 1: + rotate = frames[ + i + 1 + /*ROTATE*/ + ]; + x = frames[ + i + 2 + /*X*/ + ]; + y = frames[ + i + 3 + /*Y*/ + ]; + break; + default: + rotate = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + x = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + y = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + } + if (blend == 0 /* setup */) { + let data = constraint.data; + constraint.mixRotate = data.mixRotate + (rotate - data.mixRotate) * alpha; + constraint.mixX = data.mixX + (x - data.mixX) * alpha; + constraint.mixY = data.mixY + (y - data.mixY) * alpha; + } else { + constraint.mixRotate += (rotate - constraint.mixRotate) * alpha; + constraint.mixX += (x - constraint.mixX) * alpha; + constraint.mixY += (y - constraint.mixY) * alpha; + } + } + }; + var PhysicsConstraintTimeline = class extends CurveTimeline1 { + /** The index of the physics constraint in {@link Skeleton#getPhysicsConstraints()} that will be changed when this timeline + * is applied, or -1 if all physics constraints in the skeleton will be changed. */ + constraintIndex = 0; + /** @param physicsConstraintIndex -1 for all physics constraints in the skeleton. */ + constructor(frameCount, bezierCount, physicsConstraintIndex, property) { + super(frameCount, bezierCount, property + "|" + physicsConstraintIndex); + this.constraintIndex = physicsConstraintIndex; + } + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint; + if (this.constraintIndex == -1) { + const value = time >= this.frames[0] ? this.getCurveValue(time) : 0; + for (const constraint2 of skeleton.physicsConstraints) { + if (constraint2.active && this.global(constraint2.data)) + this.set(constraint2, this.getAbsoluteValue2(time, alpha, blend, this.get(constraint2), this.setup(constraint2), value)); + } + } else { + constraint = skeleton.physicsConstraints[this.constraintIndex]; + if (constraint.active) this.set(constraint, this.getAbsoluteValue(time, alpha, blend, this.get(constraint), this.setup(constraint))); + } + } + }; + var PhysicsConstraintInertiaTimeline = class extends PhysicsConstraintTimeline { + constructor(frameCount, bezierCount, physicsConstraintIndex) { + super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintInertia); + } + setup(constraint) { + return constraint.data.inertia; + } + get(constraint) { + return constraint.inertia; + } + set(constraint, value) { + constraint.inertia = value; + } + global(constraint) { + return constraint.inertiaGlobal; + } + }; + var PhysicsConstraintStrengthTimeline = class extends PhysicsConstraintTimeline { + constructor(frameCount, bezierCount, physicsConstraintIndex) { + super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintStrength); + } + setup(constraint) { + return constraint.data.strength; + } + get(constraint) { + return constraint.strength; + } + set(constraint, value) { + constraint.strength = value; + } + global(constraint) { + return constraint.strengthGlobal; + } + }; + var PhysicsConstraintDampingTimeline = class extends PhysicsConstraintTimeline { + constructor(frameCount, bezierCount, physicsConstraintIndex) { + super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintDamping); + } + setup(constraint) { + return constraint.data.damping; + } + get(constraint) { + return constraint.damping; + } + set(constraint, value) { + constraint.damping = value; + } + global(constraint) { + return constraint.dampingGlobal; + } + }; + var PhysicsConstraintMassTimeline = class extends PhysicsConstraintTimeline { + constructor(frameCount, bezierCount, physicsConstraintIndex) { + super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintMass); + } + setup(constraint) { + return 1 / constraint.data.massInverse; + } + get(constraint) { + return 1 / constraint.massInverse; + } + set(constraint, value) { + constraint.massInverse = 1 / value; + } + global(constraint) { + return constraint.massGlobal; + } + }; + var PhysicsConstraintWindTimeline = class extends PhysicsConstraintTimeline { + constructor(frameCount, bezierCount, physicsConstraintIndex) { + super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintWind); + } + setup(constraint) { + return constraint.data.wind; + } + get(constraint) { + return constraint.wind; + } + set(constraint, value) { + constraint.wind = value; + } + global(constraint) { + return constraint.windGlobal; + } + }; + var PhysicsConstraintGravityTimeline = class extends PhysicsConstraintTimeline { + constructor(frameCount, bezierCount, physicsConstraintIndex) { + super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintGravity); + } + setup(constraint) { + return constraint.data.gravity; + } + get(constraint) { + return constraint.gravity; + } + set(constraint, value) { + constraint.gravity = value; + } + global(constraint) { + return constraint.gravityGlobal; + } + }; + var PhysicsConstraintMixTimeline = class extends PhysicsConstraintTimeline { + constructor(frameCount, bezierCount, physicsConstraintIndex) { + super(frameCount, bezierCount, physicsConstraintIndex, Property.physicsConstraintMix); + } + setup(constraint) { + return constraint.data.mix; + } + get(constraint) { + return constraint.mix; + } + set(constraint, value) { + constraint.mix = value; + } + global(constraint) { + return constraint.mixGlobal; + } + }; + var PhysicsConstraintResetTimeline = class _PhysicsConstraintResetTimeline extends Timeline { + static propertyIds = [Property.physicsConstraintReset.toString()]; + /** The index of the physics constraint in {@link Skeleton#getPhysicsConstraints()} that will be reset when this timeline is + * applied, or -1 if all physics constraints in the skeleton will be reset. */ + constraintIndex; + /** @param physicsConstraintIndex -1 for all physics constraints in the skeleton. */ + constructor(frameCount, physicsConstraintIndex) { + super(frameCount, _PhysicsConstraintResetTimeline.propertyIds); + this.constraintIndex = physicsConstraintIndex; + } + getFrameCount() { + return this.frames.length; + } + /** Sets the time for the specified frame. + * @param frame Between 0 and frameCount, inclusive. */ + setFrame(frame, time) { + this.frames[frame] = time; + } + /** Resets the physics constraint when frames > lastTime and <= time. */ + apply(skeleton, lastTime, time, firedEvents, alpha, blend, direction) { + let constraint; + if (this.constraintIndex != -1) { + constraint = skeleton.physicsConstraints[this.constraintIndex]; + if (!constraint.active) return; + } + const frames = this.frames; + if (lastTime > time) { + this.apply(skeleton, lastTime, Number.MAX_VALUE, [], alpha, blend, direction); + lastTime = -1; + } else if (lastTime >= frames[frames.length - 1]) + return; + if (time < frames[0]) return; + if (lastTime < frames[0] || time >= frames[Timeline.search1(frames, lastTime) + 1]) { + if (constraint != null) + constraint.reset(); + else { + for (const constraint2 of skeleton.physicsConstraints) { + if (constraint2.active) constraint2.reset(); + } + } + } + } + }; + var SequenceTimeline = class _SequenceTimeline extends Timeline { + static ENTRIES = 3; + static MODE = 1; + static DELAY = 2; + slotIndex; + attachment; + constructor(frameCount, slotIndex, attachment) { + super(frameCount, [ + Property.sequence + "|" + slotIndex + "|" + attachment.sequence.id + ]); + this.slotIndex = slotIndex; + this.attachment = attachment; + } + getFrameEntries() { + return _SequenceTimeline.ENTRIES; + } + getSlotIndex() { + return this.slotIndex; + } + getAttachment() { + return this.attachment; + } + /** Sets the time, mode, index, and frame time for the specified frame. + * @param frame Between 0 and frameCount, inclusive. + * @param time Seconds between frames. */ + setFrame(frame, time, mode, index, delay) { + let frames = this.frames; + frame *= _SequenceTimeline.ENTRIES; + frames[frame] = time; + frames[frame + _SequenceTimeline.MODE] = mode | index << 4; + frames[frame + _SequenceTimeline.DELAY] = delay; + } + apply(skeleton, lastTime, time, events, alpha, blend, direction) { + let slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) return; + let slotAttachment = slot.attachment; + let attachment = this.attachment; + if (slotAttachment != attachment) { + if (!(slotAttachment instanceof VertexAttachment) || slotAttachment.timelineAttachment != attachment) return; + } + if (direction == 1 /* mixOut */) { + if (blend == 0 /* setup */) slot.sequenceIndex = -1; + return; + } + let frames = this.frames; + if (time < frames[0]) { + if (blend == 0 /* setup */ || blend == 1 /* first */) slot.sequenceIndex = -1; + return; + } + let i = Timeline.search(frames, time, _SequenceTimeline.ENTRIES); + let before = frames[i]; + let modeAndIndex = frames[i + _SequenceTimeline.MODE]; + let delay = frames[i + _SequenceTimeline.DELAY]; + if (!this.attachment.sequence) return; + let index = modeAndIndex >> 4, count = this.attachment.sequence.regions.length; + let mode = SequenceModeValues[modeAndIndex & 15]; + if (mode != 0 /* hold */) { + index += (time - before) / delay + 1e-5 | 0; + switch (mode) { + case 1 /* once */: + index = Math.min(count - 1, index); + break; + case 2 /* loop */: + index %= count; + break; + case 3 /* pingpong */: { + let n = (count << 1) - 2; + index = n == 0 ? 0 : index % n; + if (index >= count) index = n - index; + break; + } + case 4 /* onceReverse */: + index = Math.max(count - 1 - index, 0); + break; + case 5 /* loopReverse */: + index = count - 1 - index % count; + break; + case 6 /* pingpongReverse */: { + let n = (count << 1) - 2; + index = n == 0 ? 0 : (index + count - 1) % n; + if (index >= count) index = n - index; + } + } + } + slot.sequenceIndex = index; + } + }; + + // spine-core/src/AnimationState.ts + var AnimationState = class _AnimationState { + static _emptyAnimation = new Animation("", [], 0); + static emptyAnimation() { + return _AnimationState._emptyAnimation; + } + /** The AnimationStateData to look up mix durations. */ + data; + /** The list of tracks that currently have animations, which may contain null entries. */ + tracks = new Array(); + /** Multiplier for the delta time when the animation state is updated, causing time for all animations and mixes to play slower + * or faster. Defaults to 1. + * + * See TrackEntry {@link TrackEntry#timeScale} for affecting a single animation. */ + timeScale = 1; + unkeyedState = 0; + events = new Array(); + listeners = new Array(); + queue = new EventQueue(this); + propertyIDs = new StringSet(); + animationsChanged = false; + trackEntryPool = new Pool(() => new TrackEntry()); + constructor(data) { + this.data = data; + } + /** Increments each track entry {@link TrackEntry#trackTime()}, setting queued animations as current if needed. */ + update(delta) { + delta *= this.timeScale; + let tracks = this.tracks; + for (let i = 0, n = tracks.length; i < n; i++) { + let current = tracks[i]; + if (!current) continue; + current.animationLast = current.nextAnimationLast; + current.trackLast = current.nextTrackLast; + let currentDelta = delta * current.timeScale; + if (current.delay > 0) { + current.delay -= currentDelta; + if (current.delay > 0) continue; + currentDelta = -current.delay; + current.delay = 0; + } + let next = current.next; + if (next) { + let 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) { + next.mixTime += delta; + next = next.mixingFrom; + } + continue; + } + } else if (current.trackLast >= current.trackEnd && !current.mixingFrom) { + tracks[i] = null; + this.queue.end(current); + this.clearNext(current); + continue; + } + if (current.mixingFrom && this.updateMixingFrom(current, delta)) { + let from = current.mixingFrom; + current.mixingFrom = null; + if (from) from.mixingTo = null; + while (from) { + this.queue.end(from); + from = from.mixingFrom; + } + } + current.trackTime += currentDelta; + } + this.queue.drain(); + } + /** Returns true when all mixing from entries are complete. */ + updateMixingFrom(to, delta) { + let from = to.mixingFrom; + if (!from) return true; + let finished = this.updateMixingFrom(from, delta); + from.animationLast = from.nextAnimationLast; + from.trackLast = from.nextTrackLast; + if (to.nextTrackLast != -1 && to.mixTime >= to.mixDuration) { + 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; + } + /** Poses the skeleton using the track entry animations. There are no side effects other than invoking listeners, so the + * animation state can be applied to multiple skeletons to pose them identically. + * @returns True if any animations were applied. */ + apply(skeleton) { + if (!skeleton) throw new Error("skeleton cannot be null."); + if (this.animationsChanged) this._animationsChanged(); + let events = this.events; + let tracks = this.tracks; + let applied = false; + for (let i2 = 0, n2 = tracks.length; i2 < n2; i2++) { + let current = tracks[i2]; + if (!current || current.delay > 0) continue; + applied = true; + let blend = i2 == 0 ? 1 /* first */ : current.mixBlend; + let alpha = current.alpha; + if (current.mixingFrom) + alpha *= this.applyMixingFrom(current, skeleton, blend); + else if (current.trackTime >= current.trackEnd && !current.next) + alpha = 0; + let attachments = alpha >= current.alphaAttachmentThreshold; + let animationLast = current.animationLast, animationTime = current.getAnimationTime(), applyTime = animationTime; + let applyEvents = events; + if (current.reverse) { + applyTime = current.animation.duration - applyTime; + applyEvents = null; + } + let timelines = current.animation.timelines; + let timelineCount = timelines.length; + if (i2 == 0 && alpha == 1 || blend == 3 /* add */) { + if (i2 == 0) attachments = true; + for (let ii = 0; ii < timelineCount; ii++) { + Utils.webkit602BugfixHelper(alpha, blend); + var timeline = timelines[ii]; + if (timeline instanceof AttachmentTimeline) + this.applyAttachmentTimeline(timeline, skeleton, applyTime, blend, attachments); + else + timeline.apply(skeleton, animationLast, applyTime, applyEvents, alpha, blend, 0 /* mixIn */); + } + } else { + let timelineMode = current.timelineMode; + let shortestRotation = current.shortestRotation; + let firstFrame = !shortestRotation && current.timelinesRotation.length != timelineCount << 1; + if (firstFrame) current.timelinesRotation.length = timelineCount << 1; + for (let ii = 0; ii < timelineCount; ii++) { + let timeline2 = timelines[ii]; + let timelineBlend = timelineMode[ii] == SUBSEQUENT ? blend : 0 /* setup */; + if (!shortestRotation && timeline2 instanceof RotateTimeline) { + this.applyRotateTimeline(timeline2, skeleton, applyTime, alpha, timelineBlend, current.timelinesRotation, ii << 1, firstFrame); + } else if (timeline2 instanceof AttachmentTimeline) { + this.applyAttachmentTimeline(timeline2, skeleton, applyTime, blend, attachments); + } else { + Utils.webkit602BugfixHelper(alpha, blend); + timeline2.apply(skeleton, animationLast, applyTime, applyEvents, alpha, timelineBlend, 0 /* mixIn */); + } + } + } + this.queueEvents(current, animationTime); + events.length = 0; + current.nextAnimationLast = animationTime; + current.nextTrackLast = current.trackTime; + } + var setupState = this.unkeyedState + SETUP; + var slots = skeleton.slots; + for (var i = 0, n = skeleton.slots.length; i < n; i++) { + var slot = slots[i]; + if (slot.attachmentState == setupState) { + var attachmentName = slot.data.attachmentName; + slot.setAttachment(!attachmentName ? null : skeleton.getAttachment(slot.data.index, attachmentName)); + } + } + this.unkeyedState += 2; + this.queue.drain(); + return applied; + } + applyMixingFrom(to, skeleton, blend) { + let from = to.mixingFrom; + if (from.mixingFrom) this.applyMixingFrom(from, skeleton, blend); + let mix = 0; + if (to.mixDuration == 0) { + mix = 1; + if (blend == 1 /* first */) blend = 0 /* setup */; + } else { + mix = to.mixTime / to.mixDuration; + if (mix > 1) mix = 1; + if (blend != 1 /* first */) blend = from.mixBlend; + } + let attachments = mix < from.mixAttachmentThreshold, drawOrder = mix < from.mixDrawOrderThreshold; + let timelines = from.animation.timelines; + let timelineCount = timelines.length; + let alphaHold = from.alpha * to.interruptAlpha, alphaMix = alphaHold * (1 - mix); + let animationLast = from.animationLast, animationTime = from.getAnimationTime(), applyTime = animationTime; + let events = null; + if (from.reverse) + applyTime = from.animation.duration - applyTime; + else if (mix < from.eventThreshold) + events = this.events; + if (blend == 3 /* add */) { + for (let i = 0; i < timelineCount; i++) + timelines[i].apply(skeleton, animationLast, applyTime, events, alphaMix, blend, 1 /* mixOut */); + } else { + let timelineMode = from.timelineMode; + let timelineHoldMix = from.timelineHoldMix; + let shortestRotation = from.shortestRotation; + let firstFrame = !shortestRotation && from.timelinesRotation.length != timelineCount << 1; + if (firstFrame) from.timelinesRotation.length = timelineCount << 1; + from.totalAlpha = 0; + for (let i = 0; i < timelineCount; i++) { + let timeline = timelines[i]; + let direction = 1 /* mixOut */; + let timelineBlend; + let alpha = 0; + switch (timelineMode[i]) { + case SUBSEQUENT: + if (!drawOrder && timeline instanceof DrawOrderTimeline) continue; + timelineBlend = blend; + alpha = alphaMix; + break; + case FIRST: + timelineBlend = 0 /* setup */; + alpha = alphaMix; + break; + case HOLD_SUBSEQUENT: + timelineBlend = blend; + alpha = alphaHold; + break; + case HOLD_FIRST: + timelineBlend = 0 /* setup */; + alpha = alphaHold; + break; + default: + timelineBlend = 0 /* setup */; + let holdMix = timelineHoldMix[i]; + alpha = alphaHold * Math.max(0, 1 - holdMix.mixTime / holdMix.mixDuration); + break; + } + from.totalAlpha += alpha; + if (!shortestRotation && timeline instanceof RotateTimeline) + this.applyRotateTimeline(timeline, skeleton, applyTime, alpha, timelineBlend, from.timelinesRotation, i << 1, firstFrame); + else if (timeline instanceof AttachmentTimeline) + this.applyAttachmentTimeline(timeline, skeleton, applyTime, timelineBlend, attachments && alpha >= from.alphaAttachmentThreshold); + else { + Utils.webkit602BugfixHelper(alpha, blend); + if (drawOrder && timeline instanceof DrawOrderTimeline && timelineBlend == 0 /* setup */) + direction = 0 /* mixIn */; + timeline.apply(skeleton, animationLast, applyTime, 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; + } + applyAttachmentTimeline(timeline, skeleton, time, blend, attachments) { + var slot = skeleton.slots[timeline.slotIndex]; + if (!slot.bone.active) return; + if (time < timeline.frames[0]) { + if (blend == 0 /* setup */ || blend == 1 /* first */) + this.setAttachment(skeleton, slot, slot.data.attachmentName, attachments); + } else + this.setAttachment(skeleton, slot, timeline.attachmentNames[Timeline.search1(timeline.frames, time)], attachments); + if (slot.attachmentState <= this.unkeyedState) slot.attachmentState = this.unkeyedState + SETUP; + } + setAttachment(skeleton, slot, attachmentName, attachments) { + slot.setAttachment(!attachmentName ? null : skeleton.getAttachment(slot.data.index, attachmentName)); + if (attachments) slot.attachmentState = this.unkeyedState + CURRENT; + } + applyRotateTimeline(timeline, skeleton, time, alpha, blend, timelinesRotation, i, firstFrame) { + if (firstFrame) timelinesRotation[i] = 0; + if (alpha == 1) { + timeline.apply(skeleton, 0, time, null, 1, blend, 0 /* mixIn */); + return; + } + let bone = skeleton.bones[timeline.boneIndex]; + if (!bone.active) return; + let frames = timeline.frames; + let r1 = 0, r2 = 0; + if (time < frames[0]) { + switch (blend) { + case 0 /* setup */: + bone.rotation = bone.data.rotation; + default: + return; + case 1 /* first */: + r1 = bone.rotation; + r2 = bone.data.rotation; + } + } else { + r1 = blend == 0 /* setup */ ? bone.data.rotation : bone.rotation; + r2 = bone.data.rotation + timeline.getCurveValue(time); + } + let total = 0, diff = r2 - r1; + diff -= Math.ceil(diff / 360 - 0.5) * 360; + if (diff == 0) { + total = timelinesRotation[i]; + } else { + let lastTotal = 0, lastDiff = 0; + if (firstFrame) { + lastTotal = 0; + lastDiff = diff; + } else { + lastTotal = timelinesRotation[i]; + lastDiff = timelinesRotation[i + 1]; + } + let loops = lastTotal - lastTotal % 360; + total = diff + loops; + let current = diff >= 0, dir = lastTotal >= 0; + if (Math.abs(lastDiff) <= 90 && MathUtils.signum(lastDiff) != MathUtils.signum(diff)) { + if (Math.abs(lastTotal - loops) > 180) { + total += 360 * MathUtils.signum(lastTotal); + dir = current; + } else if (loops != 0) + total -= 360 * MathUtils.signum(lastTotal); + else + dir = current; + } + if (dir != current) total += 360 * MathUtils.signum(lastTotal); + timelinesRotation[i] = total; + } + timelinesRotation[i + 1] = diff; + bone.rotation = r1 + total * alpha; + } + queueEvents(entry, animationTime) { + let animationStart = entry.animationStart, animationEnd = entry.animationEnd; + let duration = animationEnd - animationStart; + let trackLastWrapped = entry.trackLast % duration; + let events = this.events; + let i = 0, n = events.length; + for (; i < n; i++) { + let event = events[i]; + if (event.time < trackLastWrapped) break; + if (event.time > animationEnd) continue; + this.queue.event(entry, event); + } + let complete = false; + if (entry.loop) { + if (duration == 0) + complete = true; + else { + const cycles = Math.floor(entry.trackTime / duration); + complete = cycles > 0 && cycles > Math.floor(entry.trackLast / duration); + } + } else + complete = animationTime >= animationEnd && entry.animationLast < animationEnd; + if (complete) this.queue.complete(entry); + for (; i < n; i++) { + let event = events[i]; + if (event.time < animationStart) continue; + this.queue.event(entry, event); + } + } + /** Removes all animations from all tracks, leaving skeletons in their current pose. + * + * It may be desired to use {@link AnimationState#setEmptyAnimation()} to mix the skeletons back to the setup pose, + * rather than leaving them in their current pose. */ + clearTracks() { + let oldDrainDisabled = this.queue.drainDisabled; + this.queue.drainDisabled = true; + for (let i = 0, n = this.tracks.length; i < n; i++) + this.clearTrack(i); + this.tracks.length = 0; + this.queue.drainDisabled = oldDrainDisabled; + this.queue.drain(); + } + /** Removes all animations from the track, leaving skeletons in their current pose. + * + * It may be desired to use {@link AnimationState#setEmptyAnimation()} to mix the skeletons back to the setup pose, + * rather than leaving them in their current pose. */ + clearTrack(trackIndex) { + if (trackIndex >= this.tracks.length) return; + let current = this.tracks[trackIndex]; + if (!current) return; + this.queue.end(current); + this.clearNext(current); + let entry = current; + while (true) { + let from = entry.mixingFrom; + if (!from) break; + this.queue.end(from); + entry.mixingFrom = null; + entry.mixingTo = null; + entry = from; + } + this.tracks[current.trackIndex] = null; + this.queue.drain(); + } + setCurrent(index, current, interrupt) { + let from = this.expandToIndex(index); + this.tracks[index] = current; + current.previous = null; + if (from) { + if (interrupt) this.queue.interrupt(from); + current.mixingFrom = from; + from.mixingTo = current; + current.mixTime = 0; + if (from.mixingFrom && from.mixDuration > 0) + current.interruptAlpha *= Math.min(1, from.mixTime / from.mixDuration); + from.timelinesRotation.length = 0; + } + this.queue.start(current); + } + /** Sets an animation by name. + * + * See {@link #setAnimationWith()}. */ + setAnimation(trackIndex, animationName, loop = false) { + let animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) throw new Error("Animation not found: " + animationName); + return this.setAnimationWith(trackIndex, animation, loop); + } + /** Sets the current animation for a track, discarding any queued animations. If the formerly current track entry was never + * applied to a skeleton, it is replaced (not mixed from). + * @param loop If true, the animation will repeat. If false it will not, instead its last frame is applied if played beyond its + * duration. In either case {@link TrackEntry#trackEnd} determines when the track is cleared. + * @returns A track entry to allow further customization of animation playback. References to the track entry must not be kept + * after the {@link AnimationStateListener#dispose()} event occurs. */ + setAnimationWith(trackIndex, animation, loop = false) { + if (!animation) throw new Error("animation cannot be null."); + let interrupt = true; + let current = this.expandToIndex(trackIndex); + if (current) { + if (current.nextTrackLast == -1) { + this.tracks[trackIndex] = current.mixingFrom; + this.queue.interrupt(current); + this.queue.end(current); + this.clearNext(current); + current = current.mixingFrom; + interrupt = false; + } else + this.clearNext(current); + } + let entry = this.trackEntry(trackIndex, animation, loop, current); + this.setCurrent(trackIndex, entry, interrupt); + this.queue.drain(); + return entry; + } + /** Queues an animation by name. + * + * See {@link #addAnimationWith()}. */ + addAnimation(trackIndex, animationName, loop = false, delay = 0) { + let animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) throw new Error("Animation not found: " + animationName); + return this.addAnimationWith(trackIndex, animation, loop, delay); + } + /** Adds an animation to be played after the current or last queued animation for a track. If the track is empty, it is + * equivalent to calling {@link #setAnimationWith()}. + * @param delay If > 0, sets {@link TrackEntry#delay}. If <= 0, the delay set is the duration of the previous track entry + * minus any mix duration (from the {@link AnimationStateData}) plus the specified `delay` (ie the mix + * ends at (`delay` = 0) or before (`delay` < 0) the previous track entry duration). If the + * previous entry is looping, its next loop completion is used instead of its duration. + * @returns A track entry to allow further customization of animation playback. References to the track entry must not be kept + * after the {@link AnimationStateListener#dispose()} event occurs. */ + addAnimationWith(trackIndex, animation, loop = false, delay = 0) { + if (!animation) throw new Error("animation cannot be null."); + let last = this.expandToIndex(trackIndex); + if (last) { + while (last.next) + last = last.next; + } + let entry = this.trackEntry(trackIndex, animation, loop, last); + if (!last) { + this.setCurrent(trackIndex, entry, true); + this.queue.drain(); + if (delay < 0) delay = 0; + } else { + last.next = entry; + entry.previous = last; + if (delay <= 0) delay = Math.max(delay + last.getTrackComplete() - entry.mixDuration, 0); + } + entry.delay = delay; + return entry; + } + /** Sets an empty animation for a track, discarding any queued animations, and sets the track entry's + * {@link TrackEntry#mixduration}. An empty animation has no timelines and serves as a placeholder for mixing in or out. + * + * Mixing out is done by setting an empty animation with a mix duration using either {@link #setEmptyAnimation()}, + * {@link #setEmptyAnimations()}, or {@link #addEmptyAnimation()}. Mixing to an empty animation causes + * the previous animation to be applied less and less over the mix duration. Properties keyed in the previous animation + * transition to the value from lower tracks or to the setup pose value if no lower tracks key the property. A mix duration of + * 0 still mixes out over one frame. + * + * Mixing in is done by first setting an empty animation, then adding an animation using + * {@link #addAnimation()} and on the returned track entry, set the + * {@link TrackEntry#setMixDuration()}. Mixing from an empty animation causes the new animation to be applied more and + * more over the mix duration. Properties keyed in the new animation transition from the value from lower tracks or from the + * setup pose value if no lower tracks key the property to the value keyed in the new animation. */ + setEmptyAnimation(trackIndex, mixDuration = 0) { + let entry = this.setAnimationWith(trackIndex, _AnimationState.emptyAnimation(), false); + entry.mixDuration = mixDuration; + entry.trackEnd = mixDuration; + return entry; + } + /** Adds an empty animation to be played after the current or last queued animation for a track, and sets the track entry's + * {@link TrackEntry#mixDuration}. If the track is empty, it is equivalent to calling + * {@link #setEmptyAnimation()}. + * + * See {@link #setEmptyAnimation()}. + * @param delay If > 0, sets {@link TrackEntry#delay}. If <= 0, the delay set is the duration of the previous track entry + * minus any mix duration plus the specified `delay` (ie the mix ends at (`delay` = 0) or + * before (`delay` < 0) the previous track entry duration). If the previous entry is looping, its next + * loop completion is used instead of its duration. + * @return A track entry to allow further customization of animation playback. References to the track entry must not be kept + * after the {@link AnimationStateListener#dispose()} event occurs. */ + addEmptyAnimation(trackIndex, mixDuration = 0, delay = 0) { + let entry = this.addAnimationWith(trackIndex, _AnimationState.emptyAnimation(), false, delay); + if (delay <= 0) entry.delay = Math.max(entry.delay + entry.mixDuration - mixDuration, 0); + entry.mixDuration = mixDuration; + entry.trackEnd = mixDuration; + return entry; + } + /** Sets an empty animation for every track, discarding any queued animations, and mixes to it over the specified mix + * duration. */ + setEmptyAnimations(mixDuration = 0) { + let oldDrainDisabled = this.queue.drainDisabled; + this.queue.drainDisabled = true; + for (let i = 0, n = this.tracks.length; i < n; i++) { + let current = this.tracks[i]; + if (current) this.setEmptyAnimation(current.trackIndex, mixDuration); + } + this.queue.drainDisabled = oldDrainDisabled; + this.queue.drain(); + } + expandToIndex(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 last May be null. */ + trackEntry(trackIndex, animation, loop, last) { + let entry = this.trackEntryPool.obtain(); + entry.reset(); + entry.trackIndex = trackIndex; + entry.animation = animation; + entry.loop = loop; + entry.holdPrevious = false; + entry.reverse = false; + entry.shortestRotation = false; + entry.eventThreshold = 0; + entry.alphaAttachmentThreshold = 0; + entry.mixAttachmentThreshold = 0; + entry.mixDrawOrderThreshold = 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.mixTime = 0; + entry.mixDuration = !last ? 0 : this.data.getMix(last.animation, animation); + entry.interruptAlpha = 1; + entry.totalAlpha = 0; + entry.mixBlend = 2 /* replace */; + return entry; + } + /** Removes the {@link TrackEntry#getNext() next entry} and all entries after it for the specified entry. */ + clearNext(entry) { + let next = entry.next; + while (next) { + this.queue.dispose(next); + next = next.next; + } + entry.next = null; + } + _animationsChanged() { + this.animationsChanged = false; + this.propertyIDs.clear(); + let tracks = this.tracks; + for (let i = 0, n = tracks.length; i < n; i++) { + let entry = tracks[i]; + if (!entry) continue; + while (entry.mixingFrom) + entry = entry.mixingFrom; + do { + if (!entry.mixingTo || entry.mixBlend != 3 /* add */) this.computeHold(entry); + entry = entry.mixingTo; + } while (entry); + } + } + computeHold(entry) { + let to = entry.mixingTo; + let timelines = entry.animation.timelines; + let timelinesCount = entry.animation.timelines.length; + let timelineMode = entry.timelineMode; + timelineMode.length = timelinesCount; + let timelineHoldMix = entry.timelineHoldMix; + timelineHoldMix.length = 0; + let propertyIDs = this.propertyIDs; + if (to && to.holdPrevious) { + for (let i = 0; i < timelinesCount; i++) + timelineMode[i] = propertyIDs.addAll(timelines[i].getPropertyIds()) ? HOLD_FIRST : HOLD_SUBSEQUENT; + return; + } + outer: + for (let i = 0; i < timelinesCount; i++) { + let timeline = timelines[i]; + let ids = timeline.getPropertyIds(); + if (!propertyIDs.addAll(ids)) + timelineMode[i] = SUBSEQUENT; + else if (!to || timeline instanceof AttachmentTimeline || timeline instanceof DrawOrderTimeline || timeline instanceof EventTimeline || !to.animation.hasTimeline(ids)) { + timelineMode[i] = FIRST; + } else { + for (let next = to.mixingTo; next; next = next.mixingTo) { + if (next.animation.hasTimeline(ids)) continue; + if (entry.mixDuration > 0) { + timelineMode[i] = HOLD_MIX; + timelineHoldMix[i] = next; + continue outer; + } + break; + } + timelineMode[i] = HOLD_FIRST; + } + } + } + /** Returns the track entry for the animation currently playing on the track, or null if no animation is currently playing. */ + getCurrent(trackIndex) { + if (trackIndex >= this.tracks.length) return null; + return this.tracks[trackIndex]; + } + /** Adds a listener to receive events for all track entries. */ + addListener(listener) { + if (!listener) throw new Error("listener cannot be null."); + this.listeners.push(listener); + } + /** Removes the listener added with {@link #addListener()}. */ + removeListener(listener) { + let index = this.listeners.indexOf(listener); + if (index >= 0) this.listeners.splice(index, 1); + } + /** Removes all listeners added with {@link #addListener()}. */ + clearListeners() { + this.listeners.length = 0; + } + /** Discards all listener notifications that have not yet been delivered. This can be useful to call from an + * {@link AnimationStateListener} when it is known that further notifications that may have been already queued for delivery + * are not wanted because new animations are being set. */ + clearListenerNotifications() { + this.queue.clear(); + } + }; + var TrackEntry = class { + /** The animation to apply for this track entry. */ + animation = null; + previous = null; + /** The animation queued to start after this animation, or null. `next` makes up a linked list. */ + next = null; + /** The track entry for the previous animation when mixing from the previous animation to this animation, or null if no + * mixing is currently occuring. When mixing from multiple animations, `mixingFrom` makes up a linked list. */ + mixingFrom = null; + /** The track entry for the next animation when mixing from this animation to the next animation, or null if no mixing is + * currently occuring. When mixing to multiple animations, `mixingTo` makes up a linked list. */ + mixingTo = null; + /** The listener for events generated by this track entry, or null. + * + * A track entry returned from {@link AnimationState#setAnimation()} is already the current animation + * for the track, so the track entry listener {@link AnimationStateListener#start()} will not be called. */ + listener = null; + /** The index of the track where this track entry is either current or queued. + * + * See {@link AnimationState#getCurrent()}. */ + trackIndex = 0; + /** If true, the animation will repeat. If false it will not, instead its last frame is applied if played beyond its + * duration. */ + loop = false; + /** If true, when mixing from the previous animation to this animation, the previous animation is applied as normal instead + * of being mixed out. + * + * When mixing between animations that key the same property, if a lower track also keys that property then the value will + * briefly dip toward the lower track value during the mix. This happens because the first animation mixes from 100% to 0% + * while the second animation mixes from 0% to 100%. Setting `holdPrevious` to true applies the first animation + * at 100% during the mix so the lower track value is overwritten. Such dipping does not occur on the lowest track which + * keys the property, only when a higher track also keys the property. + * + * Snapping will occur if `holdPrevious` is true and this animation does not key all the same properties as the + * previous animation. */ + holdPrevious = false; + reverse = false; + shortestRotation = false; + /** When the mix percentage ({@link #mixTime} / {@link #mixDuration}) is less than the + * `eventThreshold`, event timelines are applied while this animation is being mixed out. Defaults to 0, so event + * timelines are not applied while this animation is being mixed out. */ + eventThreshold = 0; + /** When the mix percentage ({@link #mixtime} / {@link #mixDuration}) is less than the + * `attachmentThreshold`, attachment timelines are applied while this animation is being mixed out. Defaults to + * 0, so attachment timelines are not applied while this animation is being mixed out. */ + mixAttachmentThreshold = 0; + /** When {@link #getAlpha()} is greater than alphaAttachmentThreshold, attachment timelines are applied. + * Defaults to 0, so attachment timelines are always applied. */ + alphaAttachmentThreshold = 0; + /** When the mix percentage ({@link #getMixTime()} / {@link #getMixDuration()}) is less than the + * mixDrawOrderThreshold, draw order timelines are applied while this animation is being mixed out. Defaults to + * 0, so draw order timelines are not applied while this animation is being mixed out. */ + mixDrawOrderThreshold = 0; + /** Seconds when this animation starts, both initially and after looping. Defaults to 0. + * + * When changing the `animationStart` time, it often makes sense to set {@link #animationLast} to the same + * value to prevent timeline keys before the start time from triggering. */ + animationStart = 0; + /** Seconds for the last frame of this animation. Non-looping animations won't play past this time. Looping animations will + * loop back to {@link #animationStart} at this time. Defaults to the animation {@link Animation#duration}. */ + animationEnd = 0; + /** The time in seconds this animation was last applied. Some timelines use this for one-time triggers. Eg, when this + * animation is applied, event timelines will fire all events between the `animationLast` time (exclusive) and + * `animationTime` (inclusive). Defaults to -1 to ensure triggers on frame 0 happen the first time this animation + * is applied. */ + animationLast = 0; + nextAnimationLast = 0; + /** Seconds to postpone playing the animation. When this track entry is the current track entry, `delay` + * postpones incrementing the {@link #trackTime}. When this track entry is queued, `delay` is the time from + * the start of the previous animation to when this track entry will become the current track entry (ie when the previous + * track entry {@link TrackEntry#trackTime} >= this track entry's `delay`). + * + * {@link #timeScale} affects the delay. */ + delay = 0; + /** Current time in seconds this track entry has been the current track entry. The track time determines + * {@link #animationTime}. The track time can be set to start the animation at a time other than 0, without affecting + * looping. */ + trackTime = 0; + trackLast = 0; + nextTrackLast = 0; + /** The track time in seconds when this animation will be removed from the track. Defaults to the highest possible float + * value, meaning the animation will be applied until a new animation is set or the track is cleared. If the track end time + * is reached, no other animations are queued for playback, and mixing from any previous animations is complete, then the + * properties keyed by the animation are set to the setup pose and the track is cleared. + * + * It may be desired to use {@link AnimationState#addEmptyAnimation()} rather than have the animation + * abruptly cease being applied. */ + trackEnd = 0; + /** Multiplier for the delta time when this track entry is updated, causing time for this animation to pass slower or + * faster. Defaults to 1. + * + * {@link #mixTime} is not affected by track entry time scale, so {@link #mixDuration} may need to be adjusted to + * match the animation speed. + * + * When using {@link AnimationState#addAnimation()} with a `delay` <= 0, note the + * {@link #delay} is set using the mix duration from the {@link AnimationStateData}, assuming time scale to be 1. If + * the time scale is not 1, the delay may need to be adjusted. + * + * See AnimationState {@link AnimationState#timeScale} for affecting all animations. */ + timeScale = 0; + /** Values < 1 mix this animation with the skeleton's current pose (usually the pose resulting from lower tracks). Defaults + * to 1, which overwrites the skeleton's current pose with this animation. + * + * Typically track 0 is used to completely pose the skeleton, then alpha is used on higher tracks. It doesn't make sense to + * use alpha on track 0 if the skeleton pose is from the last frame render. */ + alpha = 0; + /** Seconds from 0 to the {@link #getMixDuration()} when mixing from the previous animation to this animation. May be + * slightly more than `mixDuration` when the mix is complete. */ + mixTime = 0; + /** Seconds for mixing from the previous animation to this animation. Defaults to the value provided by AnimationStateData + * {@link AnimationStateData#getMix()} based on the animation before this animation (if any). + * + * A mix duration of 0 still mixes out over one frame to provide the track entry being mixed out a chance to revert the + * properties it was animating. + * + * The `mixDuration` can be set manually rather than use the value from + * {@link AnimationStateData#getMix()}. In that case, the `mixDuration` can be set for a new + * track entry only before {@link AnimationState#update(float)} is first called. + * + * When using {@link AnimationState#addAnimation()} with a `delay` <= 0, note the + * {@link #delay} is set using the mix duration from the {@link AnimationStateData}, not a mix duration set + * afterward. */ + _mixDuration = 0; + interruptAlpha = 0; + totalAlpha = 0; + get mixDuration() { + return this._mixDuration; + } + set mixDuration(mixDuration) { + this._mixDuration = mixDuration; + } + setMixDurationWithDelay(mixDuration, delay) { + this._mixDuration = mixDuration; + if (delay <= 0) { + if (this.previous != null) + delay = Math.max(delay + this.previous.getTrackComplete() - mixDuration, 0); + else + delay = 0; + } + this.delay = delay; + } + /** Controls how properties keyed in the animation are mixed with lower tracks. Defaults to {@link MixBlend#replace}, which + * replaces the values from the lower tracks with the animation values. {@link MixBlend#add} adds the animation values to + * the values from the lower tracks. + * + * The `mixBlend` can be set for a new track entry only before {@link AnimationState#apply()} is first + * called. */ + mixBlend = 2 /* replace */; + timelineMode = new Array(); + timelineHoldMix = new Array(); + timelinesRotation = new Array(); + reset() { + this.next = null; + this.previous = 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; + } + /** Uses {@link #trackTime} to compute the `animationTime`, which is between {@link #animationStart} + * and {@link #animationEnd}. When the `trackTime` is 0, the `animationTime` is equal to the + * `animationStart` time. */ + getAnimationTime() { + if (this.loop) { + let 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); + } + setAnimationLast(animationLast) { + this.animationLast = animationLast; + this.nextAnimationLast = animationLast; + } + /** Returns true if at least one loop has been completed. + * + * See {@link AnimationStateListener#complete()}. */ + isComplete() { + return this.trackTime >= this.animationEnd - this.animationStart; + } + /** Resets the rotation directions for mixing this entry's rotate timelines. This can be useful to avoid bones rotating the + * long way around when using {@link #alpha} and starting animations on other tracks. + * + * Mixing with {@link MixBlend#replace} involves finding a rotation between two others, which has two possible solutions: + * the short way or the long way around. The two rotations likely change over time, so which direction is the short or long + * way also changes. If the short way was always chosen, bones would flip to the other side when that direction became the + * long way. TrackEntry chooses the short way the first time it is applied and remembers that direction. */ + resetRotationDirections() { + this.timelinesRotation.length = 0; + } + getTrackComplete() { + let duration = this.animationEnd - this.animationStart; + if (duration != 0) { + if (this.loop) return duration * (1 + (this.trackTime / duration | 0)); + if (this.trackTime < duration) return duration; + } + return this.trackTime; + } + /** Returns true if this track entry has been applied at least once. + *

+ * See {@link AnimationState#apply(Skeleton)}. */ + wasApplied() { + return this.nextTrackLast != -1; + } + /** Returns true if there is a {@link #getNext()} track entry and it will become the current track entry during the next + * {@link AnimationState#update(float)}. */ + isNextReady() { + return this.next != null && this.nextTrackLast - this.next.delay >= 0; + } + }; + var EventQueue = class { + objects = []; + drainDisabled = false; + animState; + constructor(animState) { + this.animState = animState; + } + start(entry) { + this.objects.push(0 /* start */); + this.objects.push(entry); + this.animState.animationsChanged = true; + } + interrupt(entry) { + this.objects.push(1 /* interrupt */); + this.objects.push(entry); + } + end(entry) { + this.objects.push(2 /* end */); + this.objects.push(entry); + this.animState.animationsChanged = true; + } + dispose(entry) { + this.objects.push(3 /* dispose */); + this.objects.push(entry); + } + complete(entry) { + this.objects.push(4 /* complete */); + this.objects.push(entry); + } + event(entry, event) { + this.objects.push(5 /* event */); + this.objects.push(entry); + this.objects.push(event); + } + drain() { + if (this.drainDisabled) return; + this.drainDisabled = true; + let objects = this.objects; + for (let i = 0; i < objects.length; i += 2) { + let type = objects[i]; + let entry = objects[i + 1]; + let listeners = this.animState.listeners.slice(); + switch (type) { + case 0 /* start */: + if (entry.listener && entry.listener.start) entry.listener.start(entry); + for (let ii = 0; ii < listeners.length; ii++) { + let listener = listeners[ii]; + if (listener.start) listener.start(entry); + } + break; + case 1 /* interrupt */: + if (entry.listener && entry.listener.interrupt) entry.listener.interrupt(entry); + for (let ii = 0; ii < listeners.length; ii++) { + let listener = listeners[ii]; + if (listener.interrupt) listener.interrupt(entry); + } + break; + case 2 /* end */: + if (entry.listener && entry.listener.end) entry.listener.end(entry); + for (let ii = 0; ii < listeners.length; ii++) { + let listener = listeners[ii]; + if (listener.end) listener.end(entry); + } + // Fall through. + case 3 /* dispose */: + if (entry.listener && entry.listener.dispose) entry.listener.dispose(entry); + for (let ii = 0; ii < listeners.length; ii++) { + let listener = listeners[ii]; + if (listener.dispose) listener.dispose(entry); + } + this.animState.trackEntryPool.free(entry); + break; + case 4 /* complete */: + if (entry.listener && entry.listener.complete) entry.listener.complete(entry); + for (let ii = 0; ii < listeners.length; ii++) { + let listener = listeners[ii]; + if (listener.complete) listener.complete(entry); + } + break; + case 5 /* event */: + let event = objects[i++ + 2]; + if (entry.listener && entry.listener.event) entry.listener.event(entry, event); + for (let ii = 0; ii < listeners.length; ii++) { + let listener = listeners[ii]; + if (listener.event) listener.event(entry, event); + } + break; + } + } + this.clear(); + this.drainDisabled = false; + } + clear() { + this.objects.length = 0; + } + }; + var EventType = /* @__PURE__ */ ((EventType2) => { + EventType2[EventType2["start"] = 0] = "start"; + EventType2[EventType2["interrupt"] = 1] = "interrupt"; + EventType2[EventType2["end"] = 2] = "end"; + EventType2[EventType2["dispose"] = 3] = "dispose"; + EventType2[EventType2["complete"] = 4] = "complete"; + EventType2[EventType2["event"] = 5] = "event"; + return EventType2; + })(EventType || {}); + var AnimationStateAdapter = class { + start(entry) { + } + interrupt(entry) { + } + end(entry) { + } + dispose(entry) { + } + complete(entry) { + } + event(entry, event) { + } + }; + var SUBSEQUENT = 0; + var FIRST = 1; + var HOLD_SUBSEQUENT = 2; + var HOLD_FIRST = 3; + var HOLD_MIX = 4; + var SETUP = 1; + var CURRENT = 2; + + // spine-core/src/AnimationStateData.ts + var AnimationStateData = class { + /** The SkeletonData to look up animations when they are specified by name. */ + skeletonData; + animationToMixTime = {}; + /** The mix duration to use when no mix duration has been defined between two animations. */ + defaultMix = 0; + constructor(skeletonData) { + if (!skeletonData) throw new Error("skeletonData cannot be null."); + this.skeletonData = skeletonData; + } + /** Sets a mix duration by animation name. + * + * See {@link #setMixWith()}. */ + setMix(fromName, toName, duration) { + let from = this.skeletonData.findAnimation(fromName); + if (!from) throw new Error("Animation not found: " + fromName); + let to = this.skeletonData.findAnimation(toName); + if (!to) throw new Error("Animation not found: " + toName); + this.setMixWith(from, to, duration); + } + /** Sets the mix duration when changing from the specified animation to the other. + * + * See {@link TrackEntry#mixDuration}. */ + setMixWith(from, to, duration) { + if (!from) throw new Error("from cannot be null."); + if (!to) throw new Error("to cannot be null."); + let key = from.name + "." + to.name; + this.animationToMixTime[key] = duration; + } + /** Returns the mix duration to use when changing from the specified animation to the other, or the {@link #defaultMix} if + * no mix duration has been set. */ + getMix(from, to) { + let key = from.name + "." + to.name; + let value = this.animationToMixTime[key]; + return value === void 0 ? this.defaultMix : value; + } + }; + + // spine-core/src/attachments/BoundingBoxAttachment.ts + var BoundingBoxAttachment = class _BoundingBoxAttachment extends VertexAttachment { + color = new Color(1, 1, 1, 1); + constructor(name) { + super(name); + } + copy() { + let copy = new _BoundingBoxAttachment(this.name); + this.copyTo(copy); + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/attachments/ClippingAttachment.ts + var ClippingAttachment = class _ClippingAttachment extends VertexAttachment { + /** Clipping is performed between the clipping polygon's slot and the end slot. Returns null if clipping is done until the end of + * the skeleton's rendering. */ + endSlot = null; + // Nonessential. + /** The color of the clipping polygon as it was in Spine. Available only when nonessential data was exported. Clipping polygons + * are not usually rendered at runtime. */ + color = new Color(0.2275, 0.2275, 0.8078, 1); + // ce3a3aff + constructor(name) { + super(name); + } + copy() { + let copy = new _ClippingAttachment(this.name); + this.copyTo(copy); + copy.endSlot = this.endSlot; + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/Texture.ts + var Texture = class { + _image; + constructor(image) { + this._image = image; + } + getImage() { + return this._image; + } + }; + var TextureFilter = /* @__PURE__ */ ((TextureFilter3) => { + TextureFilter3[TextureFilter3["Nearest"] = 9728] = "Nearest"; + TextureFilter3[TextureFilter3["Linear"] = 9729] = "Linear"; + TextureFilter3[TextureFilter3["MipMap"] = 9987] = "MipMap"; + TextureFilter3[TextureFilter3["MipMapNearestNearest"] = 9984] = "MipMapNearestNearest"; + TextureFilter3[TextureFilter3["MipMapLinearNearest"] = 9985] = "MipMapLinearNearest"; + TextureFilter3[TextureFilter3["MipMapNearestLinear"] = 9986] = "MipMapNearestLinear"; + TextureFilter3[TextureFilter3["MipMapLinearLinear"] = 9987] = "MipMapLinearLinear"; + return TextureFilter3; + })(TextureFilter || {}); + var TextureWrap = /* @__PURE__ */ ((TextureWrap3) => { + TextureWrap3[TextureWrap3["MirroredRepeat"] = 33648] = "MirroredRepeat"; + TextureWrap3[TextureWrap3["ClampToEdge"] = 33071] = "ClampToEdge"; + TextureWrap3[TextureWrap3["Repeat"] = 10497] = "Repeat"; + return TextureWrap3; + })(TextureWrap || {}); + var TextureRegion = class { + texture; + u = 0; + v = 0; + u2 = 0; + v2 = 0; + width = 0; + height = 0; + degrees = 0; + offsetX = 0; + offsetY = 0; + originalWidth = 0; + originalHeight = 0; + }; + var FakeTexture = class extends Texture { + setFilters(minFilter, magFilter) { + } + setWraps(uWrap, vWrap) { + } + dispose() { + } + }; + + // spine-core/src/TextureAtlas.ts + var TextureAtlas = class { + pages = new Array(); + regions = new Array(); + constructor(atlasText) { + let reader = new TextureAtlasReader(atlasText); + let entry = new Array(4); + let pageFields = {}; + pageFields["size"] = (page2) => { + page2.width = parseInt(entry[1]); + page2.height = parseInt(entry[2]); + }; + pageFields["format"] = () => { + }; + pageFields["filter"] = (page2) => { + page2.minFilter = Utils.enumValue(TextureFilter, entry[1]); + page2.magFilter = Utils.enumValue(TextureFilter, entry[2]); + }; + pageFields["repeat"] = (page2) => { + if (entry[1].indexOf("x") != -1) page2.uWrap = 10497 /* Repeat */; + if (entry[1].indexOf("y") != -1) page2.vWrap = 10497 /* Repeat */; + }; + pageFields["pma"] = (page2) => { + page2.pma = entry[1] == "true"; + }; + var regionFields = {}; + regionFields["xy"] = (region) => { + region.x = parseInt(entry[1]); + region.y = parseInt(entry[2]); + }; + regionFields["size"] = (region) => { + region.width = parseInt(entry[1]); + region.height = parseInt(entry[2]); + }; + regionFields["bounds"] = (region) => { + region.x = parseInt(entry[1]); + region.y = parseInt(entry[2]); + region.width = parseInt(entry[3]); + region.height = parseInt(entry[4]); + }; + regionFields["offset"] = (region) => { + region.offsetX = parseInt(entry[1]); + region.offsetY = parseInt(entry[2]); + }; + regionFields["orig"] = (region) => { + region.originalWidth = parseInt(entry[1]); + region.originalHeight = parseInt(entry[2]); + }; + regionFields["offsets"] = (region) => { + region.offsetX = parseInt(entry[1]); + region.offsetY = parseInt(entry[2]); + region.originalWidth = parseInt(entry[3]); + region.originalHeight = parseInt(entry[4]); + }; + regionFields["rotate"] = (region) => { + let value = entry[1]; + if (value == "true") + region.degrees = 90; + else if (value != "false") + region.degrees = parseInt(value); + }; + regionFields["index"] = (region) => { + region.index = parseInt(entry[1]); + }; + let line = reader.readLine(); + while (line && line.trim().length == 0) + line = reader.readLine(); + while (true) { + if (!line || line.trim().length == 0) break; + if (reader.readEntry(entry, line) == 0) break; + line = reader.readLine(); + } + let page = null; + let names = null; + let values = null; + while (true) { + if (line === null) break; + if (line.trim().length == 0) { + page = null; + line = reader.readLine(); + } else if (!page) { + page = new TextureAtlasPage(line.trim()); + while (true) { + if (reader.readEntry(entry, line = reader.readLine()) == 0) break; + let field = pageFields[entry[0]]; + if (field) field(page); + } + this.pages.push(page); + } else { + let region = new TextureAtlasRegion(page, line); + while (true) { + let count = reader.readEntry(entry, line = reader.readLine()); + if (count == 0) break; + let field = regionFields[entry[0]]; + if (field) + field(region); + else { + if (!names) names = []; + if (!values) values = []; + names.push(entry[0]); + let entryValues = []; + for (let i = 0; i < count; i++) + entryValues.push(parseInt(entry[i + 1])); + values.push(entryValues); + } + } + if (region.originalWidth == 0 && region.originalHeight == 0) { + region.originalWidth = region.width; + region.originalHeight = region.height; + } + if (names && names.length > 0 && values && values.length > 0) { + region.names = names; + region.values = values; + names = null; + values = null; + } + region.u = region.x / page.width; + region.v = region.y / page.height; + if (region.degrees == 90) { + region.u2 = (region.x + region.height) / page.width; + region.v2 = (region.y + region.width) / page.height; + } else { + region.u2 = (region.x + region.width) / page.width; + region.v2 = (region.y + region.height) / page.height; + } + this.regions.push(region); + } + } + } + findRegion(name) { + for (let i = 0; i < this.regions.length; i++) { + if (this.regions[i].name == name) { + return this.regions[i]; + } + } + return null; + } + setTextures(assetManager, pathPrefix = "") { + for (let page of this.pages) + page.setTexture(assetManager.get(pathPrefix + page.name)); + } + dispose() { + for (let i = 0; i < this.pages.length; i++) { + this.pages[i].texture?.dispose(); + } + } + }; + var TextureAtlasReader = class { + lines; + index = 0; + constructor(text) { + this.lines = text.split(/\r\n|\r|\n/); + } + readLine() { + if (this.index >= this.lines.length) + return null; + return this.lines[this.index++]; + } + readEntry(entry, line) { + if (!line) return 0; + line = line.trim(); + if (line.length == 0) return 0; + let colon = line.indexOf(":"); + if (colon == -1) return 0; + entry[0] = line.substr(0, colon).trim(); + for (let i = 1, lastMatch = colon + 1; ; i++) { + let comma = line.indexOf(",", lastMatch); + if (comma == -1) { + entry[i] = line.substr(lastMatch).trim(); + return i; + } + entry[i] = line.substr(lastMatch, comma - lastMatch).trim(); + lastMatch = comma + 1; + if (i == 4) return 4; + } + } + }; + var TextureAtlasPage = class { + name; + minFilter = 9728 /* Nearest */; + magFilter = 9728 /* Nearest */; + uWrap = 33071 /* ClampToEdge */; + vWrap = 33071 /* ClampToEdge */; + texture = null; + width = 0; + height = 0; + pma = false; + regions = new Array(); + constructor(name) { + this.name = name; + } + setTexture(texture) { + this.texture = texture; + texture.setFilters(this.minFilter, this.magFilter); + texture.setWraps(this.uWrap, this.vWrap); + for (let region of this.regions) + region.texture = texture; + } + }; + var TextureAtlasRegion = class extends TextureRegion { + page; + name; + x = 0; + y = 0; + offsetX = 0; + offsetY = 0; + originalWidth = 0; + originalHeight = 0; + index = 0; + degrees = 0; + names = null; + values = null; + constructor(page, name) { + super(); + this.page = page; + this.name = name; + page.regions.push(this); + } + }; + + // spine-core/src/attachments/MeshAttachment.ts + var MeshAttachment = class _MeshAttachment extends VertexAttachment { + region = null; + /** The name of the texture region for this attachment. */ + path; + /** The UV pair for each vertex, normalized within the texture region. */ + regionUVs = []; + /** The UV pair for each vertex, normalized within the entire texture. + * + * See {@link #updateUVs}. */ + uvs = []; + /** Triplets of vertex indices which describe the mesh's triangulation. */ + triangles = []; + /** The color to tint the mesh. */ + color = new Color(1, 1, 1, 1); + /** The width of the mesh's image. Available only when nonessential data was exported. */ + width = 0; + /** The height of the mesh's image. Available only when nonessential data was exported. */ + height = 0; + /** The number of entries at the beginning of {@link #vertices} that make up the mesh hull. */ + hullLength = 0; + /** Vertex index pairs describing edges for controling triangulation. Mesh triangles will never cross edges. Only available if + * nonessential data was exported. Triangulation is not performed at runtime. */ + edges = []; + parentMesh = null; + sequence = null; + tempColor = new Color(0, 0, 0, 0); + constructor(name, path) { + super(name); + this.path = path; + } + /** Calculates {@link #uvs} using the {@link #regionUVs} and region. Must be called if the region, the region's properties, or + * the {@link #regionUVs} are changed. */ + updateRegion() { + if (!this.region) throw new Error("Region not set."); + let regionUVs = this.regionUVs; + if (!this.uvs || this.uvs.length != regionUVs.length) this.uvs = Utils.newFloatArray(regionUVs.length); + let uvs = this.uvs; + let n = this.uvs.length; + let u = this.region.u, v = this.region.v, width = 0, height = 0; + if (this.region instanceof TextureAtlasRegion) { + let region = this.region, page = region.page; + let textureWidth = page.width, textureHeight = page.height; + switch (region.degrees) { + case 90: + u -= (region.originalHeight - region.offsetY - region.height) / textureWidth; + v -= (region.originalWidth - region.offsetX - region.width) / textureHeight; + width = region.originalHeight / textureWidth; + height = region.originalWidth / textureHeight; + for (let i = 0; i < n; i += 2) { + uvs[i] = u + regionUVs[i + 1] * width; + uvs[i + 1] = v + (1 - regionUVs[i]) * height; + } + return; + case 180: + u -= (region.originalWidth - region.offsetX - region.width) / textureWidth; + v -= region.offsetY / textureHeight; + width = region.originalWidth / textureWidth; + height = region.originalHeight / textureHeight; + for (let i = 0; i < n; i += 2) { + uvs[i] = u + (1 - regionUVs[i]) * width; + uvs[i + 1] = v + (1 - regionUVs[i + 1]) * height; + } + return; + case 270: + u -= region.offsetY / textureWidth; + v -= region.offsetX / textureHeight; + width = region.originalHeight / textureWidth; + height = region.originalWidth / textureHeight; + for (let i = 0; i < n; i += 2) { + uvs[i] = u + (1 - regionUVs[i + 1]) * width; + uvs[i + 1] = v + regionUVs[i] * height; + } + return; + } + u -= region.offsetX / textureWidth; + v -= (region.originalHeight - region.offsetY - region.height) / textureHeight; + width = region.originalWidth / textureWidth; + height = region.originalHeight / textureHeight; + } else if (!this.region) { + u = v = 0; + width = height = 1; + } else { + width = this.region.u2 - u; + height = this.region.v2 - v; + } + for (let i = 0; i < n; i += 2) { + uvs[i] = u + regionUVs[i] * width; + uvs[i + 1] = v + regionUVs[i + 1] * height; + } + } + /** The parent mesh if this is a linked mesh, else null. A linked mesh shares the {@link #bones}, {@link #vertices}, + * {@link #regionUVs}, {@link #triangles}, {@link #hullLength}, {@link #edges}, {@link #width}, and {@link #height} with the + * parent mesh, but may have a different {@link #name} or {@link #path} (and therefore a different texture). */ + getParentMesh() { + return this.parentMesh; + } + /** @param parentMesh May be null. */ + setParentMesh(parentMesh) { + this.parentMesh = parentMesh; + if (parentMesh) { + this.bones = parentMesh.bones; + this.vertices = parentMesh.vertices; + this.worldVerticesLength = parentMesh.worldVerticesLength; + this.regionUVs = parentMesh.regionUVs; + this.triangles = parentMesh.triangles; + this.hullLength = parentMesh.hullLength; + this.worldVerticesLength = parentMesh.worldVerticesLength; + } + } + copy() { + if (this.parentMesh) return this.newLinkedMesh(); + let copy = new _MeshAttachment(this.name, this.path); + copy.region = this.region; + copy.color.setFromColor(this.color); + this.copyTo(copy); + copy.regionUVs = new Array(this.regionUVs.length); + Utils.arrayCopy(this.regionUVs, 0, copy.regionUVs, 0, this.regionUVs.length); + copy.uvs = this.uvs instanceof Float32Array ? Utils.newFloatArray(this.uvs.length) : new Array(this.uvs.length); + Utils.arrayCopy(this.uvs, 0, copy.uvs, 0, this.uvs.length); + copy.triangles = new Array(this.triangles.length); + Utils.arrayCopy(this.triangles, 0, copy.triangles, 0, this.triangles.length); + copy.hullLength = this.hullLength; + copy.sequence = this.sequence != null ? this.sequence.copy() : null; + if (this.edges) { + copy.edges = new Array(this.edges.length); + Utils.arrayCopy(this.edges, 0, copy.edges, 0, this.edges.length); + } + copy.width = this.width; + copy.height = this.height; + return copy; + } + computeWorldVertices(slot, start, count, worldVertices2, offset, stride) { + if (this.sequence != null) this.sequence.apply(slot, this); + super.computeWorldVertices(slot, start, count, worldVertices2, offset, stride); + } + /** Returns a new mesh with the {@link #parentMesh} set to this mesh's parent mesh, if any, else to this mesh. **/ + newLinkedMesh() { + let copy = new _MeshAttachment(this.name, this.path); + copy.region = this.region; + copy.color.setFromColor(this.color); + copy.timelineAttachment = this.timelineAttachment; + copy.setParentMesh(this.parentMesh ? this.parentMesh : this); + if (copy.region != null) copy.updateRegion(); + return copy; + } + }; + + // spine-core/src/attachments/PathAttachment.ts + var PathAttachment = class _PathAttachment extends VertexAttachment { + /** The lengths along the path in the setup pose from the start of the path to the end of each Bezier curve. */ + lengths = []; + /** If true, the start and end knots are connected. */ + closed = false; + /** If true, additional calculations are performed to make calculating positions along the path more accurate. If false, fewer + * calculations are performed but calculating positions along the path is less accurate. */ + constantSpeed = false; + /** The color of the path as it was in Spine. Available only when nonessential data was exported. Paths are not usually + * rendered at runtime. */ + color = new Color(1, 1, 1, 1); + constructor(name) { + super(name); + } + copy() { + let copy = new _PathAttachment(this.name); + this.copyTo(copy); + copy.lengths = new Array(this.lengths.length); + Utils.arrayCopy(this.lengths, 0, copy.lengths, 0, this.lengths.length); + copy.closed = closed; + copy.constantSpeed = this.constantSpeed; + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/attachments/PointAttachment.ts + var PointAttachment = class _PointAttachment extends VertexAttachment { + x = 0; + y = 0; + rotation = 0; + /** The color of the point attachment as it was in Spine. Available only when nonessential data was exported. Point attachments + * are not usually rendered at runtime. */ + color = new Color(0.38, 0.94, 0, 1); + constructor(name) { + super(name); + } + computeWorldPosition(bone, point) { + point.x = this.x * bone.a + this.y * bone.b + bone.worldX; + point.y = this.x * bone.c + this.y * bone.d + bone.worldY; + return point; + } + computeWorldRotation(bone) { + const r = this.rotation * MathUtils.degRad, cos = Math.cos(r), sin = Math.sin(r); + const x = cos * bone.a + sin * bone.b; + const y = cos * bone.c + sin * bone.d; + return MathUtils.atan2Deg(y, x); + } + copy() { + let copy = new _PointAttachment(this.name); + copy.x = this.x; + copy.y = this.y; + copy.rotation = this.rotation; + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/attachments/RegionAttachment.ts + var RegionAttachment = class _RegionAttachment extends Attachment { + /** The local x translation. */ + x = 0; + /** The local y translation. */ + y = 0; + /** The local scaleX. */ + scaleX = 1; + /** The local scaleY. */ + scaleY = 1; + /** The local rotation. */ + rotation = 0; + /** The width of the region attachment in Spine. */ + width = 0; + /** The height of the region attachment in Spine. */ + height = 0; + /** The color to tint the region attachment. */ + color = new Color(1, 1, 1, 1); + /** The name of the texture region for this attachment. */ + path; + region = null; + sequence = null; + /** For each of the 4 vertices, a pair of x,y values that is the local position of the vertex. + * + * See {@link #updateOffset()}. */ + offset = Utils.newFloatArray(8); + uvs = Utils.newFloatArray(8); + tempColor = new Color(1, 1, 1, 1); + constructor(name, path) { + super(name); + this.path = path; + } + /** Calculates the {@link #offset} using the region settings. Must be called after changing region settings. */ + updateRegion() { + if (!this.region) throw new Error("Region not set."); + let region = this.region; + let uvs = this.uvs; + if (region == null) { + uvs[0] = 0; + uvs[1] = 0; + uvs[2] = 0; + uvs[3] = 1; + uvs[4] = 1; + uvs[5] = 1; + uvs[6] = 1; + uvs[7] = 0; + return; + } + let regionScaleX = this.width / this.region.originalWidth * this.scaleX; + let regionScaleY = this.height / this.region.originalHeight * this.scaleY; + let localX = -this.width / 2 * this.scaleX + this.region.offsetX * regionScaleX; + let localY = -this.height / 2 * this.scaleY + this.region.offsetY * regionScaleY; + let localX2 = localX + this.region.width * regionScaleX; + let localY2 = localY + this.region.height * regionScaleY; + let radians = this.rotation * MathUtils.degRad; + let cos = Math.cos(radians); + let sin = Math.sin(radians); + let x = this.x, y = this.y; + let localXCos = localX * cos + x; + let localXSin = localX * sin; + let localYCos = localY * cos + y; + let localYSin = localY * sin; + let localX2Cos = localX2 * cos + x; + let localX2Sin = localX2 * sin; + let localY2Cos = localY2 * cos + y; + let localY2Sin = localY2 * sin; + let offset = this.offset; + offset[0] = localXCos - localYSin; + offset[1] = localYCos + localXSin; + offset[2] = localXCos - localY2Sin; + offset[3] = localY2Cos + localXSin; + offset[4] = localX2Cos - localY2Sin; + offset[5] = localY2Cos + localX2Sin; + offset[6] = localX2Cos - localYSin; + offset[7] = localYCos + localX2Sin; + if (region.degrees == 90) { + uvs[0] = region.u2; + uvs[1] = region.v2; + uvs[2] = region.u; + uvs[3] = region.v2; + uvs[4] = region.u; + uvs[5] = region.v; + uvs[6] = region.u2; + uvs[7] = region.v; + } else { + uvs[0] = region.u; + uvs[1] = region.v2; + uvs[2] = region.u; + uvs[3] = region.v; + uvs[4] = region.u2; + uvs[5] = region.v; + uvs[6] = region.u2; + uvs[7] = region.v2; + } + } + /** Transforms the attachment's four vertices to world coordinates. If the attachment has a {@link #sequence}, the region may + * be changed. + *

+ * See World transforms in the Spine + * Runtimes Guide. + * @param worldVertices The output world vertices. Must have a length >= offset + 8. + * @param offset The worldVertices index to begin writing values. + * @param stride The number of worldVertices entries between the value pairs written. */ + computeWorldVertices(slot, worldVertices2, offset, stride) { + if (this.sequence != null) + this.sequence.apply(slot, this); + let bone = slot.bone; + let vertexOffset = this.offset; + let x = bone.worldX, y = bone.worldY; + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + let offsetX = 0, offsetY = 0; + offsetX = vertexOffset[0]; + offsetY = vertexOffset[1]; + worldVertices2[offset] = offsetX * a + offsetY * b + x; + worldVertices2[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[2]; + offsetY = vertexOffset[3]; + worldVertices2[offset] = offsetX * a + offsetY * b + x; + worldVertices2[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[4]; + offsetY = vertexOffset[5]; + worldVertices2[offset] = offsetX * a + offsetY * b + x; + worldVertices2[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffset[6]; + offsetY = vertexOffset[7]; + worldVertices2[offset] = offsetX * a + offsetY * b + x; + worldVertices2[offset + 1] = offsetX * c + offsetY * d + y; + } + copy() { + let copy = new _RegionAttachment(this.name, this.path); + copy.region = this.region; + copy.x = this.x; + copy.y = this.y; + copy.scaleX = this.scaleX; + copy.scaleY = this.scaleY; + copy.rotation = this.rotation; + copy.width = this.width; + copy.height = this.height; + Utils.arrayCopy(this.uvs, 0, copy.uvs, 0, 8); + Utils.arrayCopy(this.offset, 0, copy.offset, 0, 8); + copy.color.setFromColor(this.color); + copy.sequence = this.sequence != null ? this.sequence.copy() : null; + return copy; + } + static X1 = 0; + static Y1 = 1; + static C1R = 2; + static C1G = 3; + static C1B = 4; + static C1A = 5; + static U1 = 6; + static V1 = 7; + static X2 = 8; + static Y2 = 9; + static C2R = 10; + static C2G = 11; + static C2B = 12; + static C2A = 13; + static U2 = 14; + static V2 = 15; + static X3 = 16; + static Y3 = 17; + static C3R = 18; + static C3G = 19; + static C3B = 20; + static C3A = 21; + static U3 = 22; + static V3 = 23; + static X4 = 24; + static Y4 = 25; + static C4R = 26; + static C4G = 27; + static C4B = 28; + static C4A = 29; + static U4 = 30; + static V4 = 31; + }; + + // spine-core/src/AtlasAttachmentLoader.ts + var AtlasAttachmentLoader = class { + atlas; + constructor(atlas) { + this.atlas = atlas; + } + loadSequence(name, basePath, sequence) { + let regions = sequence.regions; + for (let i = 0, n = regions.length; i < n; i++) { + let path = sequence.getPath(basePath, i); + let region = this.atlas.findRegion(path); + if (region == null) throw new Error("Region not found in atlas: " + path + " (sequence: " + name + ")"); + regions[i] = region; + } + } + newRegionAttachment(skin, name, path, sequence) { + let attachment = new RegionAttachment(name, path); + if (sequence != null) { + this.loadSequence(name, path, sequence); + } else { + let region = this.atlas.findRegion(path); + if (!region) throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")"); + attachment.region = region; + } + return attachment; + } + newMeshAttachment(skin, name, path, sequence) { + let attachment = new MeshAttachment(name, path); + if (sequence != null) { + this.loadSequence(name, path, sequence); + } else { + let region = this.atlas.findRegion(path); + if (!region) throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")"); + attachment.region = region; + } + return attachment; + } + newBoundingBoxAttachment(skin, name) { + return new BoundingBoxAttachment(name); + } + newPathAttachment(skin, name) { + return new PathAttachment(name); + } + newPointAttachment(skin, name) { + return new PointAttachment(name); + } + newClippingAttachment(skin, name) { + return new ClippingAttachment(name); + } + }; + + // spine-core/src/BoneData.ts + var BoneData = class { + /** The index of the bone in {@link Skeleton#getBones()}. */ + index = 0; + /** The name of the bone, which is unique across all bones in the skeleton. */ + name; + /** @returns May be null. */ + parent = null; + /** The bone's length. */ + length = 0; + /** The local x translation. */ + x = 0; + /** The local y translation. */ + y = 0; + /** The local rotation in degrees, counter clockwise. */ + rotation = 0; + /** The local scaleX. */ + scaleX = 1; + /** The local scaleY. */ + scaleY = 1; + /** The local shearX. */ + shearX = 0; + /** The local shearX. */ + shearY = 0; + /** The transform mode for how parent world transforms affect this bone. */ + inherit = 0 /* Normal */; + /** When true, {@link Skeleton#updateWorldTransform()} only updates this bone if the {@link Skeleton#skin} contains this + * bone. + * @see Skin#bones */ + skinRequired = false; + /** The color of the bone as it was in Spine. Available only when nonessential data was exported. Bones are not usually + * rendered at runtime. */ + color = new Color(); + /** The bone icon as it was in Spine, or null if nonessential data was not exported. */ + icon; + /** False if the bone was hidden in Spine and nonessential data was exported. Does not affect runtime rendering. */ + visible = false; + constructor(index, name, parent) { + if (index < 0) throw new Error("index must be >= 0."); + if (!name) throw new Error("name cannot be null."); + this.index = index; + this.name = name; + this.parent = parent; + } + }; + var Inherit = /* @__PURE__ */ ((Inherit2) => { + Inherit2[Inherit2["Normal"] = 0] = "Normal"; + Inherit2[Inherit2["OnlyTranslation"] = 1] = "OnlyTranslation"; + Inherit2[Inherit2["NoRotationOrReflection"] = 2] = "NoRotationOrReflection"; + Inherit2[Inherit2["NoScale"] = 3] = "NoScale"; + Inherit2[Inherit2["NoScaleOrReflection"] = 4] = "NoScaleOrReflection"; + return Inherit2; + })(Inherit || {}); + + // spine-core/src/Bone.ts + var Bone = class { + /** The bone's setup pose data. */ + data; + /** The skeleton this bone belongs to. */ + skeleton; + /** The parent bone, or null if this is the root bone. */ + parent = null; + /** The immediate children of this bone. */ + children = new Array(); + /** The local x translation. */ + x = 0; + /** The local y translation. */ + y = 0; + /** The local rotation in degrees, counter clockwise. */ + rotation = 0; + /** The local scaleX. */ + scaleX = 0; + /** The local scaleY. */ + scaleY = 0; + /** The local shearX. */ + shearX = 0; + /** The local shearY. */ + shearY = 0; + /** The applied local x translation. */ + ax = 0; + /** The applied local y translation. */ + ay = 0; + /** The applied local rotation in degrees, counter clockwise. */ + arotation = 0; + /** The applied local scaleX. */ + ascaleX = 0; + /** The applied local scaleY. */ + ascaleY = 0; + /** The applied local shearX. */ + ashearX = 0; + /** The applied local shearY. */ + ashearY = 0; + /** Part of the world transform matrix for the X axis. If changed, {@link #updateAppliedTransform()} should be called. */ + a = 0; + /** Part of the world transform matrix for the Y axis. If changed, {@link #updateAppliedTransform()} should be called. */ + b = 0; + /** Part of the world transform matrix for the X axis. If changed, {@link #updateAppliedTransform()} should be called. */ + c = 0; + /** Part of the world transform matrix for the Y axis. If changed, {@link #updateAppliedTransform()} should be called. */ + d = 0; + /** The world X position. If changed, {@link #updateAppliedTransform()} should be called. */ + worldY = 0; + /** The world Y position. If changed, {@link #updateAppliedTransform()} should be called. */ + worldX = 0; + inherit = 0 /* Normal */; + sorted = false; + active = false; + /** @param parent May be null. */ + constructor(data, skeleton, parent) { + if (!data) throw new Error("data cannot be null."); + if (!skeleton) throw new Error("skeleton cannot be null."); + this.data = data; + this.skeleton = skeleton; + this.parent = parent; + this.setToSetupPose(); + } + /** Returns false when the bone has not been computed because {@link BoneData#skinRequired} is true and the + * {@link Skeleton#skin active skin} does not {@link Skin#bones contain} this bone. */ + isActive() { + return this.active; + } + /** Computes the world transform using the parent bone and this bone's local applied transform. */ + update(physics) { + this.updateWorldTransformWith(this.ax, this.ay, this.arotation, this.ascaleX, this.ascaleY, this.ashearX, this.ashearY); + } + /** Computes the world transform using the parent bone and this bone's local transform. + * + * See {@link #updateWorldTransformWith()}. */ + updateWorldTransform() { + this.updateWorldTransformWith(this.x, this.y, this.rotation, this.scaleX, this.scaleY, this.shearX, this.shearY); + } + /** Computes the world transform using the parent bone and the specified local transform. The applied transform is set to the + * specified local transform. Child bones are not updated. + * + * See [World transforms](http://esotericsoftware.com/spine-runtime-skeletons#World-transforms) in the Spine + * Runtimes Guide. */ + updateWorldTransformWith(x, y, rotation, scaleX, scaleY, shearX, shearY) { + this.ax = x; + this.ay = y; + this.arotation = rotation; + this.ascaleX = scaleX; + this.ascaleY = scaleY; + this.ashearX = shearX; + this.ashearY = shearY; + let parent = this.parent; + if (!parent) { + let skeleton = this.skeleton; + const sx = skeleton.scaleX, sy = skeleton.scaleY; + const rx = (rotation + shearX) * MathUtils.degRad; + const ry = (rotation + 90 + shearY) * MathUtils.degRad; + this.a = Math.cos(rx) * scaleX * sx; + this.b = Math.cos(ry) * scaleY * sx; + this.c = Math.sin(rx) * scaleX * sy; + this.d = Math.sin(ry) * scaleY * sy; + this.worldX = x * sx + skeleton.x; + this.worldY = y * sy + skeleton.y; + return; + } + let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + this.worldX = pa * x + pb * y + parent.worldX; + this.worldY = pc * x + pd * y + parent.worldY; + switch (this.inherit) { + case 0 /* Normal */: { + const rx = (rotation + shearX) * MathUtils.degRad; + const ry = (rotation + 90 + shearY) * MathUtils.degRad; + const la = Math.cos(rx) * scaleX; + const lb = Math.cos(ry) * scaleY; + const lc = Math.sin(rx) * scaleX; + const ld = Math.sin(ry) * scaleY; + this.a = pa * la + pb * lc; + this.b = pa * lb + pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + return; + } + case 1 /* OnlyTranslation */: { + const rx = (rotation + shearX) * MathUtils.degRad; + const ry = (rotation + 90 + shearY) * MathUtils.degRad; + this.a = Math.cos(rx) * scaleX; + this.b = Math.cos(ry) * scaleY; + this.c = Math.sin(rx) * scaleX; + this.d = Math.sin(ry) * scaleY; + break; + } + case 2 /* NoRotationOrReflection */: { + let sx = 1 / this.skeleton.scaleX, sy = 1 / this.skeleton.scaleY; + pa *= sx; + pc *= sy; + let s = pa * pa + pc * pc; + let prx = 0; + if (s > 1e-4) { + s = Math.abs(pa * pd * sy - pb * sx * pc) / s; + pb = pc * s; + pd = pa * s; + prx = Math.atan2(pc, pa) * MathUtils.radDeg; + } else { + pa = 0; + pc = 0; + prx = 90 - Math.atan2(pd, pb) * MathUtils.radDeg; + } + const rx = (rotation + shearX - prx) * MathUtils.degRad; + const ry = (rotation + shearY - prx + 90) * MathUtils.degRad; + const la = Math.cos(rx) * scaleX; + const lb = Math.cos(ry) * scaleY; + const lc = Math.sin(rx) * scaleX; + const ld = Math.sin(ry) * scaleY; + this.a = pa * la - pb * lc; + this.b = pa * lb - pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + break; + } + case 3 /* NoScale */: + case 4 /* NoScaleOrReflection */: { + rotation *= MathUtils.degRad; + const cos = Math.cos(rotation), sin = Math.sin(rotation); + let za = (pa * cos + pb * sin) / this.skeleton.scaleX; + let zc = (pc * cos + pd * sin) / this.skeleton.scaleY; + let s = Math.sqrt(za * za + zc * zc); + if (s > 1e-5) s = 1 / s; + za *= s; + zc *= s; + s = Math.sqrt(za * za + zc * zc); + if (this.inherit == 3 /* NoScale */ && pa * pd - pb * pc < 0 != (this.skeleton.scaleX < 0 != this.skeleton.scaleY < 0)) s = -s; + rotation = Math.PI / 2 + Math.atan2(zc, za); + const zb = Math.cos(rotation) * s; + const zd = Math.sin(rotation) * s; + shearX *= MathUtils.degRad; + shearY = (90 + shearY) * MathUtils.degRad; + const la = Math.cos(shearX) * scaleX; + const lb = Math.cos(shearY) * scaleY; + const lc = Math.sin(shearX) * scaleX; + const ld = Math.sin(shearY) * scaleY; + this.a = za * la + zb * lc; + this.b = za * lb + zb * ld; + this.c = zc * la + zd * lc; + this.d = zc * lb + zd * ld; + break; + } + } + this.a *= this.skeleton.scaleX; + this.b *= this.skeleton.scaleX; + this.c *= this.skeleton.scaleY; + this.d *= this.skeleton.scaleY; + } + /** Sets this bone's local transform to the setup pose. */ + setToSetupPose() { + let data = this.data; + this.x = data.x; + this.y = data.y; + this.rotation = data.rotation; + this.scaleX = data.scaleX; + this.scaleY = data.scaleY; + this.shearX = data.shearX; + this.shearY = data.shearY; + this.inherit = data.inherit; + } + /** Computes the applied transform values from the world transform. + * + * If the world transform is modified (by a constraint, {@link #rotateWorld(float)}, etc) then this method should be called so + * the applied transform matches the world transform. The applied transform may be needed by other code (eg to apply other + * constraints). + * + * Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. The applied transform after + * calling this method is equivalent to the local transform used to compute the world transform, but may not be identical. */ + updateAppliedTransform() { + let parent = this.parent; + if (!parent) { + this.ax = this.worldX - this.skeleton.x; + this.ay = this.worldY - this.skeleton.y; + this.arotation = Math.atan2(this.c, this.a) * MathUtils.radDeg; + this.ascaleX = Math.sqrt(this.a * this.a + this.c * this.c); + this.ascaleY = Math.sqrt(this.b * this.b + this.d * this.d); + this.ashearX = 0; + this.ashearY = Math.atan2(this.a * this.b + this.c * this.d, this.a * this.d - this.b * this.c) * MathUtils.radDeg; + return; + } + let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + let pid = 1 / (pa * pd - pb * pc); + let ia = pd * pid, ib = pb * pid, ic = pc * pid, id = pa * pid; + let dx = this.worldX - parent.worldX, dy = this.worldY - parent.worldY; + this.ax = dx * ia - dy * ib; + this.ay = dy * id - dx * ic; + let ra, rb, rc, rd; + if (this.inherit == 1 /* OnlyTranslation */) { + ra = this.a; + rb = this.b; + rc = this.c; + rd = this.d; + } else { + switch (this.inherit) { + case 2 /* NoRotationOrReflection */: { + let s2 = Math.abs(pa * pd - pb * pc) / (pa * pa + pc * pc); + pb = -pc * this.skeleton.scaleX * s2 / this.skeleton.scaleY; + pd = pa * this.skeleton.scaleY * s2 / this.skeleton.scaleX; + pid = 1 / (pa * pd - pb * pc); + ia = pd * pid; + ib = pb * pid; + break; + } + case 3 /* NoScale */: + case 4 /* NoScaleOrReflection */: + let cos = MathUtils.cosDeg(this.rotation), sin = MathUtils.sinDeg(this.rotation); + pa = (pa * cos + pb * sin) / this.skeleton.scaleX; + pc = (pc * cos + pd * sin) / this.skeleton.scaleY; + let s = Math.sqrt(pa * pa + pc * pc); + if (s > 1e-5) s = 1 / s; + pa *= s; + pc *= s; + s = Math.sqrt(pa * pa + pc * pc); + if (this.inherit == 3 /* NoScale */ && pid < 0 != (this.skeleton.scaleX < 0 != this.skeleton.scaleY < 0)) s = -s; + let r = MathUtils.PI / 2 + Math.atan2(pc, pa); + pb = Math.cos(r) * s; + pd = Math.sin(r) * s; + pid = 1 / (pa * pd - pb * pc); + ia = pd * pid; + ib = pb * pid; + ic = pc * pid; + id = pa * pid; + } + ra = ia * this.a - ib * this.c; + rb = ia * this.b - ib * this.d; + rc = id * this.c - ic * this.a; + rd = id * this.d - ic * this.b; + } + this.ashearX = 0; + this.ascaleX = Math.sqrt(ra * ra + rc * rc); + if (this.ascaleX > 1e-4) { + let det = ra * rd - rb * rc; + this.ascaleY = det / this.ascaleX; + this.ashearY = -Math.atan2(ra * rb + rc * rd, det) * MathUtils.radDeg; + this.arotation = Math.atan2(rc, ra) * MathUtils.radDeg; + } else { + this.ascaleX = 0; + this.ascaleY = Math.sqrt(rb * rb + rd * rd); + this.ashearY = 0; + this.arotation = 90 - Math.atan2(rd, rb) * MathUtils.radDeg; + } + } + /** The world rotation for the X axis, calculated using {@link #a} and {@link #c}. */ + getWorldRotationX() { + return Math.atan2(this.c, this.a) * MathUtils.radDeg; + } + /** The world rotation for the Y axis, calculated using {@link #b} and {@link #d}. */ + getWorldRotationY() { + return Math.atan2(this.d, this.b) * MathUtils.radDeg; + } + /** The magnitude (always positive) of the world scale X, calculated using {@link #a} and {@link #c}. */ + getWorldScaleX() { + return Math.sqrt(this.a * this.a + this.c * this.c); + } + /** The magnitude (always positive) of the world scale Y, calculated using {@link #b} and {@link #d}. */ + getWorldScaleY() { + return Math.sqrt(this.b * this.b + this.d * this.d); + } + /** Transforms a point from world coordinates to the bone's local coordinates. */ + worldToLocal(world) { + let invDet = 1 / (this.a * this.d - this.b * this.c); + let x = world.x - this.worldX, y = world.y - this.worldY; + world.x = x * this.d * invDet - y * this.b * invDet; + world.y = y * this.a * invDet - x * this.c * invDet; + return world; + } + /** Transforms a point from the bone's local coordinates to world coordinates. */ + localToWorld(local) { + let x = local.x, y = local.y; + local.x = x * this.a + y * this.b + this.worldX; + local.y = x * this.c + y * this.d + this.worldY; + return local; + } + /** Transforms a point from world coordinates to the parent bone's local coordinates. */ + worldToParent(world) { + if (world == null) throw new Error("world cannot be null."); + return this.parent == null ? world : this.parent.worldToLocal(world); + } + /** Transforms a point from the parent bone's coordinates to world coordinates. */ + parentToWorld(world) { + if (world == null) throw new Error("world cannot be null."); + return this.parent == null ? world : this.parent.localToWorld(world); + } + /** Transforms a world rotation to a local rotation. */ + worldToLocalRotation(worldRotation) { + let sin = MathUtils.sinDeg(worldRotation), cos = MathUtils.cosDeg(worldRotation); + return Math.atan2(this.a * sin - this.c * cos, this.d * cos - this.b * sin) * MathUtils.radDeg + this.rotation - this.shearX; + } + /** Transforms a local rotation to a world rotation. */ + localToWorldRotation(localRotation) { + localRotation -= this.rotation - this.shearX; + let sin = MathUtils.sinDeg(localRotation), cos = MathUtils.cosDeg(localRotation); + return Math.atan2(cos * this.c + sin * this.d, cos * this.a + sin * this.b) * MathUtils.radDeg; + } + /** Rotates the world transform the specified amount. + *

+ * After changes are made to the world transform, {@link #updateAppliedTransform()} should be called and + * {@link #update(Physics)} will need to be called on any child bones, recursively. */ + rotateWorld(degrees) { + degrees *= MathUtils.degRad; + const sin = Math.sin(degrees), cos = Math.cos(degrees); + const ra = this.a, rb = this.b; + this.a = cos * ra - sin * this.c; + this.b = cos * rb - sin * this.d; + this.c = sin * ra + cos * this.c; + this.d = sin * rb + cos * this.d; + } + }; + + // spine-core/src/ConstraintData.ts + var ConstraintData = class { + constructor(name, order, skinRequired) { + this.name = name; + this.order = order; + this.skinRequired = skinRequired; + } + }; + + // spine-core/src/AssetManagerBase.ts + var AssetManagerBase = class { + pathPrefix = ""; + textureLoader; + downloader; + cache; + errors = {}; + toLoad = 0; + loaded = 0; + constructor(textureLoader, pathPrefix = "", downloader = new Downloader(), cache = new AssetCache()) { + this.textureLoader = textureLoader; + this.pathPrefix = pathPrefix; + this.downloader = downloader; + this.cache = cache; + } + start(path) { + this.toLoad++; + return this.pathPrefix + path; + } + success(callback, path, asset) { + this.toLoad--; + this.loaded++; + this.cache.assets[path] = asset; + this.cache.assetsRefCount[path] = (this.cache.assetsRefCount[path] || 0) + 1; + if (callback) callback(path, asset); + } + error(callback, path, message) { + this.toLoad--; + this.loaded++; + this.errors[path] = message; + if (callback) callback(path, message); + } + loadAll() { + let promise = new Promise((resolve, reject) => { + let check = () => { + if (this.isLoadingComplete()) { + if (this.hasErrors()) reject(this.errors); + else resolve(this); + return; + } + requestAnimationFrame(check); + }; + requestAnimationFrame(check); + }); + return promise; + } + setRawDataURI(path, data) { + this.downloader.rawDataUris[this.pathPrefix + path] = data; + } + loadBinary(path, success = () => { + }, error = () => { + }) { + path = this.start(path); + if (this.reuseAssets(path, success, error)) return; + this.cache.assetsLoaded[path] = new Promise((resolve, reject) => { + this.downloader.downloadBinary(path, (data) => { + this.success(success, path, data); + resolve(data); + }, (status, responseText) => { + const errorMsg = `Couldn't load binary ${path}: status ${status}, ${responseText}`; + this.error(error, path, errorMsg); + reject(errorMsg); + }); + }); + } + loadText(path, success = () => { + }, error = () => { + }) { + path = this.start(path); + this.downloader.downloadText(path, (data) => { + this.success(success, path, data); + }, (status, responseText) => { + this.error(error, path, `Couldn't load text ${path}: status ${status}, ${responseText}`); + }); + } + loadJson(path, success = () => { + }, error = () => { + }) { + path = this.start(path); + if (this.reuseAssets(path, success, error)) return; + this.cache.assetsLoaded[path] = new Promise((resolve, reject) => { + this.downloader.downloadJson(path, (data) => { + this.success(success, path, data); + resolve(data); + }, (status, responseText) => { + const errorMsg = `Couldn't load JSON ${path}: status ${status}, ${responseText}`; + this.error(error, path, errorMsg); + reject(errorMsg); + }); + }); + } + reuseAssets(path, success = () => { + }, error = () => { + }) { + const loadedStatus = this.cache.assetsLoaded[path]; + const alreadyExistsOrLoading = loadedStatus !== void 0; + if (alreadyExistsOrLoading) { + this.cache.assetsLoaded[path] = loadedStatus.then((data) => { + data = data instanceof Image || data instanceof ImageBitmap ? this.textureLoader(data) : data; + this.success(success, path, data); + return data; + }).catch((errorMsg) => this.error(error, path, errorMsg)); + } + return alreadyExistsOrLoading; + } + loadTexture(path, success = () => { + }, error = () => { + }) { + path = this.start(path); + if (this.reuseAssets(path, success, error)) return; + this.cache.assetsLoaded[path] = new Promise((resolve, reject) => { + let isBrowser = !!(typeof window !== "undefined" && typeof navigator !== "undefined" && window.document); + let isWebWorker = !isBrowser; + if (isWebWorker) { + fetch(path, { mode: "cors" }).then((response) => { + if (response.ok) return response.blob(); + const errorMsg = `Couldn't load image: ${path}`; + this.error(error, path, `Couldn't load image: ${path}`); + reject(errorMsg); + }).then((blob) => { + return blob ? createImageBitmap(blob, { premultiplyAlpha: "none", colorSpaceConversion: "none" }) : null; + }).then((bitmap) => { + if (bitmap) { + const texture = this.createTexture(path, bitmap); + this.success(success, path, texture); + resolve(texture); + } + ; + }); + } else { + let image = new Image(); + image.crossOrigin = "anonymous"; + image.onload = () => { + const texture = this.createTexture(path, image); + this.success(success, path, texture); + resolve(texture); + }; + image.onerror = () => { + const errorMsg = `Couldn't load image: ${path}`; + this.error(error, path, errorMsg); + reject(errorMsg); + }; + if (this.downloader.rawDataUris[path]) path = this.downloader.rawDataUris[path]; + image.src = path; + } + }); + } + loadTextureAtlas(path, success = () => { + }, error = () => { + }, fileAlias) { + let index = path.lastIndexOf("/"); + let parent = index >= 0 ? path.substring(0, index + 1) : ""; + path = this.start(path); + if (this.reuseAssets(path, success, error)) return; + this.cache.assetsLoaded[path] = new Promise((resolve, reject) => { + this.downloader.downloadText(path, (atlasText) => { + try { + const atlas = this.createTextureAtlas(path, atlasText); + let toLoad = atlas.pages.length, abort = false; + if (toLoad === 0) { + this.success(success, path, atlas); + resolve(atlas); + return; + } + for (let page of atlas.pages) { + this.loadTexture( + !fileAlias ? parent + page.name : fileAlias[page.name], + (imagePath, texture) => { + if (!abort) { + page.setTexture(texture); + if (--toLoad == 0) { + this.success(success, path, atlas); + resolve(atlas); + } + } + }, + (imagePath, message) => { + if (!abort) { + const errorMsg = `Couldn't load texture ${path} page image: ${imagePath}`; + this.error(error, path, errorMsg); + reject(errorMsg); + } + abort = true; + } + ); + } + } catch (e) { + const errorMsg = `Couldn't parse texture atlas ${path}: ${e.message}`; + this.error(error, path, errorMsg); + reject(errorMsg); + } + }, (status, responseText) => { + const errorMsg = `Couldn't load texture atlas ${path}: status ${status}, ${responseText}`; + this.error(error, path, errorMsg); + reject(errorMsg); + }); + }); + } + loadTextureAtlasButNoTextures(path, success = () => { + }, error = () => { + }, fileAlias) { + path = this.start(path); + if (this.reuseAssets(path, success, error)) return; + this.cache.assetsLoaded[path] = new Promise((resolve, reject) => { + this.downloader.downloadText(path, (atlasText) => { + try { + const atlas = this.createTextureAtlas(path, atlasText); + this.success(success, path, atlas); + resolve(atlas); + } catch (e) { + const errorMsg = `Couldn't parse texture atlas ${path}: ${e.message}`; + this.error(error, path, errorMsg); + reject(errorMsg); + } + }, (status, responseText) => { + const errorMsg = `Couldn't load texture atlas ${path}: status ${status}, ${responseText}`; + this.error(error, path, errorMsg); + reject(errorMsg); + }); + }); + } + // Promisified versions of load function + async loadBinaryAsync(path) { + return new Promise((resolve, reject) => { + this.loadBinary( + path, + (_, binary) => resolve(binary), + (_, message) => reject(message) + ); + }); + } + async loadJsonAsync(path) { + return new Promise((resolve, reject) => { + this.loadJson( + path, + (_, object) => resolve(object), + (_, message) => reject(message) + ); + }); + } + async loadTextureAsync(path) { + return new Promise((resolve, reject) => { + this.loadTexture( + path, + (_, texture) => resolve(texture), + (_, message) => reject(message) + ); + }); + } + async loadTextureAtlasAsync(path) { + return new Promise((resolve, reject) => { + this.loadTextureAtlas( + path, + (_, atlas) => resolve(atlas), + (_, message) => reject(message) + ); + }); + } + async loadTextureAtlasButNoTexturesAsync(path) { + return new Promise((resolve, reject) => { + this.loadTextureAtlasButNoTextures( + path, + (_, atlas) => resolve(atlas), + (_, message) => reject(message) + ); + }); + } + setCache(cache) { + this.cache = cache; + } + get(path) { + return this.cache.assets[this.pathPrefix + path]; + } + require(path) { + path = this.pathPrefix + path; + let asset = this.cache.assets[path]; + if (asset) return asset; + let error = this.errors[path]; + throw Error("Asset not found: " + path + (error ? "\n" + error : "")); + } + remove(path) { + path = this.pathPrefix + path; + let asset = this.cache.assets[path]; + if (asset.dispose) asset.dispose(); + delete this.cache.assets[path]; + delete this.cache.assetsRefCount[path]; + delete this.cache.assetsLoaded[path]; + return asset; + } + removeAll() { + for (let path in this.cache.assets) { + let asset = this.cache.assets[path]; + if (asset.dispose) asset.dispose(); + } + this.cache.assets = {}; + this.cache.assetsLoaded = {}; + this.cache.assetsRefCount = {}; + } + isLoadingComplete() { + return this.toLoad == 0; + } + getToLoad() { + return this.toLoad; + } + getLoaded() { + return this.loaded; + } + dispose() { + this.removeAll(); + } + // dispose asset only if it's not used by others + disposeAsset(path) { + const asset = this.cache.assets[path]; + if (asset instanceof TextureAtlas) { + asset.dispose(); + return; + } + this.disposeAssetInternal(path); + } + hasErrors() { + return Object.keys(this.errors).length > 0; + } + getErrors() { + return this.errors; + } + disposeAssetInternal(path) { + if (this.cache.assetsRefCount[path] > 0 && --this.cache.assetsRefCount[path] === 0) { + return this.remove(path); + } + } + createTextureAtlas(path, atlasText) { + const atlas = new TextureAtlas(atlasText); + atlas.dispose = () => { + if (this.cache.assetsRefCount[path] <= 0) return; + this.disposeAssetInternal(path); + for (const page of atlas.pages) { + page.texture?.dispose(); + } + }; + return atlas; + } + createTexture(path, image) { + const texture = this.textureLoader(image); + const textureDispose = texture.dispose.bind(texture); + texture.dispose = () => { + if (this.disposeAssetInternal(path)) textureDispose(); + }; + return texture; + } + }; + var AssetCache = class _AssetCache { + assets = {}; + assetsRefCount = {}; + assetsLoaded = {}; + static AVAILABLE_CACHES = /* @__PURE__ */ new Map(); + static getCache(id) { + const cache = _AssetCache.AVAILABLE_CACHES.get(id); + if (cache) return cache; + const newCache = new _AssetCache(); + _AssetCache.AVAILABLE_CACHES.set(id, newCache); + return newCache; + } + async addAsset(path, asset) { + this.assetsLoaded[path] = Promise.resolve(asset); + this.assets[path] = await asset; + } + }; + var Downloader = class { + callbacks = {}; + rawDataUris = {}; + dataUriToString(dataUri) { + if (!dataUri.startsWith("data:")) { + throw new Error("Not a data URI."); + } + let base64Idx = dataUri.indexOf("base64,"); + if (base64Idx != -1) { + base64Idx += "base64,".length; + return atob(dataUri.substr(base64Idx)); + } else { + return dataUri.substr(dataUri.indexOf(",") + 1); + } + } + base64ToUint8Array(base64) { + var binary_string = window.atob(base64); + var len = binary_string.length; + var bytes = new Uint8Array(len); + for (var i = 0; i < len; i++) { + bytes[i] = binary_string.charCodeAt(i); + } + return bytes; + } + dataUriToUint8Array(dataUri) { + if (!dataUri.startsWith("data:")) { + throw new Error("Not a data URI."); + } + let base64Idx = dataUri.indexOf("base64,"); + if (base64Idx == -1) throw new Error("Not a binary data URI."); + base64Idx += "base64,".length; + return this.base64ToUint8Array(dataUri.substr(base64Idx)); + } + downloadText(url, success, error) { + if (this.start(url, success, error)) return; + const rawDataUri = this.rawDataUris[url]; + if (rawDataUri && !rawDataUri.includes(".")) { + try { + this.finish(url, 200, this.dataUriToString(rawDataUri)); + } catch (e) { + this.finish(url, 400, JSON.stringify(e)); + } + return; + } + let request = new XMLHttpRequest(); + request.overrideMimeType("text/html"); + request.open("GET", rawDataUri ? rawDataUri : url, true); + let done = () => { + this.finish(url, request.status, request.responseText); + }; + request.onload = done; + request.onerror = done; + request.send(); + } + downloadJson(url, success, error) { + this.downloadText(url, (data) => { + success(JSON.parse(data)); + }, error); + } + downloadBinary(url, success, error) { + if (this.start(url, success, error)) return; + const rawDataUri = this.rawDataUris[url]; + if (rawDataUri && !rawDataUri.includes(".")) { + try { + this.finish(url, 200, this.dataUriToUint8Array(rawDataUri)); + } catch (e) { + this.finish(url, 400, JSON.stringify(e)); + } + return; + } + let request = new XMLHttpRequest(); + request.open("GET", rawDataUri ? rawDataUri : url, true); + request.responseType = "arraybuffer"; + let onerror = () => { + this.finish(url, request.status, request.response); + }; + request.onload = () => { + if (request.status == 200 || request.status == 0) + this.finish(url, 200, new Uint8Array(request.response)); + else + onerror(); + }; + request.onerror = onerror; + request.send(); + } + start(url, success, error) { + let callbacks = this.callbacks[url]; + try { + if (callbacks) return true; + this.callbacks[url] = callbacks = []; + } finally { + callbacks.push(success, error); + } + } + finish(url, status, data) { + let callbacks = this.callbacks[url]; + delete this.callbacks[url]; + let args = status == 200 || status == 0 ? [data] : [status, data]; + for (let i = args.length - 1, n = callbacks.length; i < n; i += 2) + callbacks[i].apply(null, args); + } + }; + + // spine-core/src/Event.ts + var Event = class { + data; + intValue = 0; + floatValue = 0; + stringValue = null; + time = 0; + volume = 0; + balance = 0; + constructor(time, data) { + if (!data) throw new Error("data cannot be null."); + this.time = time; + this.data = data; + } + }; + + // spine-core/src/EventData.ts + var EventData = class { + name; + intValue = 0; + floatValue = 0; + stringValue = null; + audioPath = null; + volume = 0; + balance = 0; + constructor(name) { + this.name = name; + } + }; + + // spine-core/src/IkConstraint.ts + var IkConstraint = class { + /** The IK constraint's setup pose data. */ + data; + /** The bones that will be modified by this IK constraint. */ + bones; + /** The bone that is the IK target. */ + target; + /** Controls the bend direction of the IK bones, either 1 or -1. */ + bendDirection = 0; + /** When true and only a single bone is being constrained, if the target is too close, the bone is scaled to reach it. */ + compress = false; + /** When true, if the target is out of range, the parent bone is scaled to reach it. If more than one bone is being constrained + * and the parent bone has local nonuniform scale, stretch is not applied. */ + stretch = false; + /** A percentage (0-1) that controls the mix between the constrained and unconstrained rotations. */ + mix = 1; + /** For two bone IK, the distance from the maximum reach of the bones that rotation will slow. */ + softness = 0; + active = false; + constructor(data, skeleton) { + if (!data) throw new Error("data cannot be null."); + if (!skeleton) throw new Error("skeleton cannot be null."); + this.data = data; + this.bones = new Array(); + for (let i = 0; i < data.bones.length; i++) { + let bone = skeleton.findBone(data.bones[i].name); + if (!bone) throw new Error(`Couldn't find bone ${data.bones[i].name}`); + this.bones.push(bone); + } + let target = skeleton.findBone(data.target.name); + if (!target) throw new Error(`Couldn't find bone ${data.target.name}`); + this.target = target; + this.mix = data.mix; + this.softness = data.softness; + this.bendDirection = data.bendDirection; + this.compress = data.compress; + this.stretch = data.stretch; + } + isActive() { + return this.active; + } + setToSetupPose() { + const data = this.data; + this.mix = data.mix; + this.softness = data.softness; + this.bendDirection = data.bendDirection; + this.compress = data.compress; + this.stretch = data.stretch; + } + update(physics) { + if (this.mix == 0) return; + let target = this.target; + let bones = this.bones; + switch (bones.length) { + case 1: + this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix); + break; + case 2: + this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.data.uniform, this.softness, this.mix); + break; + } + } + /** Applies 1 bone IK. The target is specified in the world coordinate system. */ + apply1(bone, targetX, targetY, compress, stretch, uniform, alpha) { + let p = bone.parent; + if (!p) throw new Error("IK bone must have parent."); + let pa = p.a, pb = p.b, pc = p.c, pd = p.d; + let rotationIK = -bone.ashearX - bone.arotation, tx = 0, ty = 0; + switch (bone.inherit) { + case 1 /* OnlyTranslation */: + tx = (targetX - bone.worldX) * MathUtils.signum(bone.skeleton.scaleX); + ty = (targetY - bone.worldY) * MathUtils.signum(bone.skeleton.scaleY); + break; + case 2 /* NoRotationOrReflection */: + let s = Math.abs(pa * pd - pb * pc) / Math.max(1e-4, pa * pa + pc * pc); + let sa = pa / bone.skeleton.scaleX; + let sc = pc / bone.skeleton.scaleY; + pb = -sc * s * bone.skeleton.scaleX; + pd = sa * s * bone.skeleton.scaleY; + rotationIK += Math.atan2(sc, sa) * MathUtils.radDeg; + // Fall through + default: + let x = targetX - p.worldX, y = targetY - p.worldY; + let d = pa * pd - pb * pc; + if (Math.abs(d) <= 1e-4) { + tx = 0; + ty = 0; + } else { + tx = (x * pd - y * pb) / d - bone.ax; + ty = (y * pa - x * pc) / d - bone.ay; + } + } + rotationIK += Math.atan2(ty, tx) * MathUtils.radDeg; + if (bone.ascaleX < 0) rotationIK += 180; + if (rotationIK > 180) + rotationIK -= 360; + else if (rotationIK < -180) + rotationIK += 360; + let sx = bone.ascaleX, sy = bone.ascaleY; + if (compress || stretch) { + switch (bone.inherit) { + case 3 /* NoScale */: + case 4 /* NoScaleOrReflection */: + tx = targetX - bone.worldX; + ty = targetY - bone.worldY; + } + const b = bone.data.length * sx; + if (b > 1e-4) { + const dd = tx * tx + ty * ty; + if (compress && dd < b * b || stretch && dd > b * b) { + const s = (Math.sqrt(dd) / b - 1) * alpha + 1; + sx *= s; + if (uniform) sy *= s; + } + } + } + bone.updateWorldTransformWith( + bone.ax, + bone.ay, + bone.arotation + rotationIK * alpha, + sx, + sy, + bone.ashearX, + bone.ashearY + ); + } + /** Applies 2 bone IK. The target is specified in the world coordinate system. + * @param child A direct descendant of the parent bone. */ + apply2(parent, child, targetX, targetY, bendDir, stretch, uniform, softness, alpha) { + if (parent.inherit != 0 /* Normal */ || child.inherit != 0 /* Normal */) return; + let px = parent.ax, py = parent.ay, psx = parent.ascaleX, psy = parent.ascaleY, sx = psx, sy = psy, csx = child.ascaleX; + let os1 = 0, os2 = 0, s2 = 0; + if (psx < 0) { + psx = -psx; + os1 = 180; + s2 = -1; + } else { + os1 = 0; + s2 = 1; + } + if (psy < 0) { + psy = -psy; + s2 = -s2; + } + if (csx < 0) { + csx = -csx; + os2 = 180; + } else + os2 = 0; + let cx = child.ax, cy = 0, cwx = 0, cwy = 0, a = parent.a, b = parent.b, c = parent.c, d = parent.d; + let u = Math.abs(psx - psy) <= 1e-4; + if (!u || stretch) { + cy = 0; + cwx = a * cx + parent.worldX; + cwy = c * cx + parent.worldY; + } else { + cy = child.ay; + cwx = a * cx + b * cy + parent.worldX; + cwy = c * cx + d * cy + parent.worldY; + } + let pp = parent.parent; + if (!pp) throw new Error("IK parent must itself have a parent."); + a = pp.a; + b = pp.b; + c = pp.c; + d = pp.d; + let id = a * d - b * c, x = cwx - pp.worldX, y = cwy - pp.worldY; + id = Math.abs(id) <= 1e-4 ? 0 : 1 / id; + let dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; + let l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.data.length * csx, a1, a2; + if (l1 < 1e-4) { + this.apply1(parent, targetX, targetY, false, stretch, false, alpha); + child.updateWorldTransformWith(cx, cy, 0, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY); + return; + } + x = targetX - pp.worldX; + y = targetY - pp.worldY; + let tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py; + let dd = tx * tx + ty * ty; + if (softness != 0) { + softness *= psx * (csx + 1) * 0.5; + let td = Math.sqrt(dd), sd = td - l1 - l2 * psx + softness; + if (sd > 0) { + let p = Math.min(1, sd / (softness * 2)) - 1; + p = (sd - softness * (1 - p * p)) / td; + tx -= p * tx; + ty -= p * ty; + dd = tx * tx + ty * ty; + } + } + outer: + if (u) { + l2 *= psx; + let cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2); + if (cos < -1) { + cos = -1; + a2 = Math.PI * bendDir; + } else if (cos > 1) { + cos = 1; + a2 = 0; + if (stretch) { + a = (Math.sqrt(dd) / (l1 + l2) - 1) * alpha + 1; + sx *= a; + if (uniform) sy *= a; + } + } else + a2 = Math.acos(cos) * bendDir; + a = l1 + l2 * cos; + b = l2 * Math.sin(a2); + a1 = Math.atan2(ty * a - tx * b, tx * a + ty * b); + } else { + a = psx * l2; + b = psy * l2; + let aa = a * a, bb = b * b, ta = Math.atan2(ty, tx); + c = bb * l1 * l1 + aa * dd - aa * bb; + let c1 = -2 * bb * l1, c2 = bb - aa; + d = c1 * c1 - 4 * c2 * c; + if (d >= 0) { + let q = Math.sqrt(d); + if (c1 < 0) q = -q; + q = -(c1 + q) * 0.5; + let r0 = q / c2, r1 = c / q; + let r = Math.abs(r0) < Math.abs(r1) ? r0 : r1; + r0 = dd - r * r; + if (r0 >= 0) { + y = Math.sqrt(r0) * bendDir; + a1 = ta - Math.atan2(y, r); + a2 = Math.atan2(y / psy, (r - l1) / psx); + break outer; + } + } + let minAngle = MathUtils.PI, minX = l1 - a, minDist = minX * minX, minY = 0; + let maxAngle = 0, maxX = l1 + a, maxDist = maxX * maxX, maxY = 0; + c = -a * l1 / (aa - bb); + if (c >= -1 && c <= 1) { + c = Math.acos(c); + x = a * Math.cos(c) + l1; + y = b * Math.sin(c); + d = x * x + y * y; + if (d < minDist) { + minAngle = c; + minDist = d; + minX = x; + minY = y; + } + if (d > maxDist) { + maxAngle = c; + maxDist = d; + maxX = x; + maxY = y; + } + } + if (dd <= (minDist + maxDist) * 0.5) { + a1 = ta - Math.atan2(minY * bendDir, minX); + a2 = minAngle * bendDir; + } else { + a1 = ta - Math.atan2(maxY * bendDir, maxX); + a2 = maxAngle * bendDir; + } + } + let os = Math.atan2(cy, cx) * s2; + let rotation = parent.arotation; + a1 = (a1 - os) * MathUtils.radDeg + os1 - rotation; + if (a1 > 180) + a1 -= 360; + else if (a1 < -180) + a1 += 360; + parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, sx, sy, 0, 0); + rotation = child.arotation; + a2 = ((a2 + os) * MathUtils.radDeg - child.ashearX) * s2 + os2 - rotation; + if (a2 > 180) + a2 -= 360; + else if (a2 < -180) + a2 += 360; + child.updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY); + } + }; + + // spine-core/src/IkConstraintData.ts + var IkConstraintData = class extends ConstraintData { + /** The bones that are constrained by this IK constraint. */ + bones = new Array(); + /** The bone that is the IK target. */ + _target = null; + set target(boneData) { + this._target = boneData; + } + get target() { + if (!this._target) throw new Error("BoneData not set."); + else return this._target; + } + /** Controls the bend direction of the IK bones, either 1 or -1. */ + bendDirection = 0; + /** When true and only a single bone is being constrained, if the target is too close, the bone is scaled to reach it. */ + compress = false; + /** When true, if the target is out of range, the parent bone is scaled to reach it. If more than one bone is being constrained + * and the parent bone has local nonuniform scale, stretch is not applied. */ + stretch = false; + /** When true, only a single bone is being constrained, and {@link #getCompress()} or {@link #getStretch()} is used, the bone + * is scaled on both the X and Y axes. */ + uniform = false; + /** A percentage (0-1) that controls the mix between the constrained and unconstrained rotations. */ + mix = 0; + /** For two bone IK, the distance from the maximum reach of the bones that rotation will slow. */ + softness = 0; + constructor(name) { + super(name, 0, false); + } + }; + + // spine-core/src/PathConstraintData.ts + var PathConstraintData = class extends ConstraintData { + /** The bones that will be modified by this path constraint. */ + bones = new Array(); + /** The slot whose path attachment will be used to constrained the bones. */ + _target = null; + set target(slotData) { + this._target = slotData; + } + get target() { + if (!this._target) throw new Error("SlotData not set."); + else return this._target; + } + /** The mode for positioning the first bone on the path. */ + positionMode = 0 /* Fixed */; + /** The mode for positioning the bones after the first bone on the path. */ + spacingMode = 1 /* Fixed */; + /** The mode for adjusting the rotation of the bones. */ + rotateMode = 1 /* Chain */; + /** An offset added to the constrained bone rotation. */ + offsetRotation = 0; + /** The position along the path. */ + position = 0; + /** The spacing between bones. */ + spacing = 0; + mixRotate = 0; + mixX = 0; + mixY = 0; + constructor(name) { + super(name, 0, false); + } + }; + var PositionMode = /* @__PURE__ */ ((PositionMode2) => { + PositionMode2[PositionMode2["Fixed"] = 0] = "Fixed"; + PositionMode2[PositionMode2["Percent"] = 1] = "Percent"; + return PositionMode2; + })(PositionMode || {}); + var SpacingMode = /* @__PURE__ */ ((SpacingMode2) => { + SpacingMode2[SpacingMode2["Length"] = 0] = "Length"; + SpacingMode2[SpacingMode2["Fixed"] = 1] = "Fixed"; + SpacingMode2[SpacingMode2["Percent"] = 2] = "Percent"; + SpacingMode2[SpacingMode2["Proportional"] = 3] = "Proportional"; + return SpacingMode2; + })(SpacingMode || {}); + var RotateMode = /* @__PURE__ */ ((RotateMode2) => { + RotateMode2[RotateMode2["Tangent"] = 0] = "Tangent"; + RotateMode2[RotateMode2["Chain"] = 1] = "Chain"; + RotateMode2[RotateMode2["ChainScale"] = 2] = "ChainScale"; + return RotateMode2; + })(RotateMode || {}); + + // spine-core/src/PathConstraint.ts + var PathConstraint = class _PathConstraint { + static NONE = -1; + static BEFORE = -2; + static AFTER = -3; + static epsilon = 1e-5; + /** The path constraint's setup pose data. */ + data; + /** The bones that will be modified by this path constraint. */ + bones; + /** The slot whose path attachment will be used to constrained the bones. */ + target; + /** The position along the path. */ + position = 0; + /** The spacing between bones. */ + spacing = 0; + mixRotate = 0; + mixX = 0; + mixY = 0; + spaces = new Array(); + positions = new Array(); + world = new Array(); + curves = new Array(); + lengths = new Array(); + segments = new Array(); + active = false; + constructor(data, skeleton) { + if (!data) throw new Error("data cannot be null."); + if (!skeleton) throw new Error("skeleton cannot be null."); + this.data = data; + this.bones = new Array(); + for (let i = 0, n = data.bones.length; i < n; i++) { + let bone = skeleton.findBone(data.bones[i].name); + if (!bone) throw new Error(`Couldn't find bone ${data.bones[i].name}.`); + this.bones.push(bone); + } + let target = skeleton.findSlot(data.target.name); + if (!target) throw new Error(`Couldn't find target bone ${data.target.name}`); + this.target = target; + this.position = data.position; + this.spacing = data.spacing; + this.mixRotate = data.mixRotate; + this.mixX = data.mixX; + this.mixY = data.mixY; + } + isActive() { + return this.active; + } + setToSetupPose() { + const data = this.data; + this.position = data.position; + this.spacing = data.spacing; + this.mixRotate = data.mixRotate; + this.mixX = data.mixX; + this.mixY = data.mixY; + } + update(physics) { + let attachment = this.target.getAttachment(); + if (!(attachment instanceof PathAttachment)) return; + let mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY; + if (mixRotate == 0 && mixX == 0 && mixY == 0) return; + let data = this.data; + let tangents = data.rotateMode == 0 /* Tangent */, scale = data.rotateMode == 2 /* ChainScale */; + let bones = this.bones; + let boneCount = bones.length, spacesCount = tangents ? boneCount : boneCount + 1; + let spaces = Utils.setArraySize(this.spaces, spacesCount), lengths = scale ? this.lengths = Utils.setArraySize(this.lengths, boneCount) : []; + let spacing = this.spacing; + switch (data.spacingMode) { + case 2 /* Percent */: + if (scale) { + for (let i = 0, n = spacesCount - 1; i < n; i++) { + let bone = bones[i]; + let setupLength = bone.data.length; + let x = setupLength * bone.a, y = setupLength * bone.c; + lengths[i] = Math.sqrt(x * x + y * y); + } + } + Utils.arrayFill(spaces, 1, spacesCount, spacing); + break; + case 3 /* Proportional */: + let sum = 0; + for (let i = 0, n = spacesCount - 1; i < n; ) { + let bone = bones[i]; + let setupLength = bone.data.length; + if (setupLength < _PathConstraint.epsilon) { + if (scale) lengths[i] = 0; + spaces[++i] = spacing; + } else { + let x = setupLength * bone.a, y = setupLength * bone.c; + let length = Math.sqrt(x * x + y * y); + if (scale) lengths[i] = length; + spaces[++i] = length; + sum += length; + } + } + if (sum > 0) { + sum = spacesCount / sum * spacing; + for (let i = 1; i < spacesCount; i++) + spaces[i] *= sum; + } + break; + default: + let lengthSpacing = data.spacingMode == 0 /* Length */; + for (let i = 0, n = spacesCount - 1; i < n; ) { + let bone = bones[i]; + let setupLength = bone.data.length; + if (setupLength < _PathConstraint.epsilon) { + if (scale) lengths[i] = 0; + spaces[++i] = spacing; + } else { + let x = setupLength * bone.a, y = setupLength * bone.c; + let length = Math.sqrt(x * x + y * y); + if (scale) lengths[i] = length; + spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength; + } + } + } + let positions = this.computeWorldPositions(attachment, spacesCount, tangents); + let boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation; + let tip = false; + if (offsetRotation == 0) + tip = data.rotateMode == 1 /* Chain */; + else { + tip = false; + let p = this.target.bone; + offsetRotation *= p.a * p.d - p.b * p.c > 0 ? MathUtils.degRad : -MathUtils.degRad; + } + for (let i = 0, p = 3; i < boneCount; i++, p += 3) { + let bone = bones[i]; + bone.worldX += (boneX - bone.worldX) * mixX; + bone.worldY += (boneY - bone.worldY) * mixY; + let x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY; + if (scale) { + let length = lengths[i]; + if (length != 0) { + let s = (Math.sqrt(dx * dx + dy * dy) / length - 1) * mixRotate + 1; + bone.a *= s; + bone.c *= s; + } + } + boneX = x; + boneY = y; + if (mixRotate > 0) { + let a = bone.a, b = bone.b, c = bone.c, d = bone.d, r = 0, cos = 0, sin = 0; + if (tangents) + r = positions[p - 1]; + else if (spaces[i + 1] == 0) + r = positions[p + 2]; + else + r = Math.atan2(dy, dx); + r -= Math.atan2(c, a); + if (tip) { + cos = Math.cos(r); + sin = Math.sin(r); + let length = bone.data.length; + boneX += (length * (cos * a - sin * c) - dx) * mixRotate; + boneY += (length * (sin * a + cos * c) - dy) * mixRotate; + } else { + r += offsetRotation; + } + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + r *= mixRotate; + cos = Math.cos(r); + sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + bone.updateAppliedTransform(); + } + } + computeWorldPositions(path, spacesCount, tangents) { + let target = this.target; + let position = this.position; + let spaces = this.spaces, out = Utils.setArraySize(this.positions, spacesCount * 3 + 2), world = this.world; + let closed2 = path.closed; + let verticesLength = path.worldVerticesLength, curveCount = verticesLength / 6, prevCurve = _PathConstraint.NONE; + if (!path.constantSpeed) { + let lengths = path.lengths; + curveCount -= closed2 ? 1 : 2; + let pathLength2 = lengths[curveCount]; + if (this.data.positionMode == 1 /* Percent */) position *= pathLength2; + let multiplier2; + switch (this.data.spacingMode) { + case 2 /* Percent */: + multiplier2 = pathLength2; + break; + case 3 /* Proportional */: + multiplier2 = pathLength2 / spacesCount; + break; + default: + multiplier2 = 1; + } + world = Utils.setArraySize(this.world, 8); + for (let i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { + let space = spaces[i] * multiplier2; + position += space; + let p = position; + if (closed2) { + p %= pathLength2; + if (p < 0) p += pathLength2; + curve = 0; + } else if (p < 0) { + if (prevCurve != _PathConstraint.BEFORE) { + prevCurve = _PathConstraint.BEFORE; + path.computeWorldVertices(target, 2, 4, world, 0, 2); + } + this.addBeforePosition(p, world, 0, out, o); + continue; + } else if (p > pathLength2) { + if (prevCurve != _PathConstraint.AFTER) { + prevCurve = _PathConstraint.AFTER; + path.computeWorldVertices(target, verticesLength - 6, 4, world, 0, 2); + } + this.addAfterPosition(p - pathLength2, world, 0, out, o); + continue; + } + for (; ; curve++) { + let length = lengths[curve]; + if (p > length) continue; + if (curve == 0) + p /= length; + else { + let prev = lengths[curve - 1]; + p = (p - prev) / (length - prev); + } + break; + } + if (curve != prevCurve) { + prevCurve = curve; + if (closed2 && curve == curveCount) { + path.computeWorldVertices(target, verticesLength - 4, 4, world, 0, 2); + path.computeWorldVertices(target, 0, 4, world, 4, 2); + } else + path.computeWorldVertices(target, curve * 6 + 2, 8, world, 0, 2); + } + this.addCurvePosition( + p, + world[0], + world[1], + world[2], + world[3], + world[4], + world[5], + world[6], + world[7], + out, + o, + tangents || i > 0 && space == 0 + ); + } + return out; + } + if (closed2) { + verticesLength += 2; + world = Utils.setArraySize(this.world, verticesLength); + path.computeWorldVertices(target, 2, verticesLength - 4, world, 0, 2); + path.computeWorldVertices(target, 0, 2, world, verticesLength - 4, 2); + world[verticesLength - 2] = world[0]; + world[verticesLength - 1] = world[1]; + } else { + curveCount--; + verticesLength -= 4; + world = Utils.setArraySize(this.world, verticesLength); + path.computeWorldVertices(target, 2, verticesLength, world, 0, 2); + } + let curves = Utils.setArraySize(this.curves, curveCount); + let pathLength = 0; + let x1 = world[0], y1 = world[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0; + let tmpx = 0, tmpy = 0, dddfx = 0, dddfy = 0, ddfx = 0, ddfy = 0, dfx = 0, dfy = 0; + for (let i = 0, w = 2; i < curveCount; i++, w += 6) { + cx1 = world[w]; + cy1 = world[w + 1]; + cx2 = world[w + 2]; + cy2 = world[w + 3]; + x2 = world[w + 4]; + y2 = world[w + 5]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.1875; + tmpy = (y1 - cy1 * 2 + cy2) * 0.1875; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + curves[i] = pathLength; + x1 = x2; + y1 = y2; + } + if (this.data.positionMode == 1 /* Percent */) position *= pathLength; + let multiplier; + switch (this.data.spacingMode) { + case 2 /* Percent */: + multiplier = pathLength; + break; + case 3 /* Proportional */: + multiplier = pathLength / spacesCount; + break; + default: + multiplier = 1; + } + let segments = this.segments; + let curveLength = 0; + for (let i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { + let space = spaces[i] * multiplier; + position += space; + let p = position; + if (closed2) { + p %= pathLength; + if (p < 0) p += pathLength; + curve = 0; + } else if (p < 0) { + this.addBeforePosition(p, world, 0, out, o); + continue; + } else if (p > pathLength) { + this.addAfterPosition(p - pathLength, world, verticesLength - 4, out, o); + continue; + } + for (; ; curve++) { + let length = curves[curve]; + if (p > length) continue; + if (curve == 0) + p /= length; + else { + let prev = curves[curve - 1]; + p = (p - prev) / (length - prev); + } + break; + } + if (curve != prevCurve) { + prevCurve = curve; + let ii = curve * 6; + x1 = world[ii]; + y1 = world[ii + 1]; + cx1 = world[ii + 2]; + cy1 = world[ii + 3]; + cx2 = world[ii + 4]; + cy2 = world[ii + 5]; + x2 = world[ii + 6]; + y2 = world[ii + 7]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.03; + tmpy = (y1 - cy1 * 2 + cy2) * 0.03; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 6e-3; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 6e-3; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667; + curveLength = Math.sqrt(dfx * dfx + dfy * dfy); + segments[0] = curveLength; + for (ii = 1; ii < 8; ii++) { + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[ii] = curveLength; + } + dfx += ddfx; + dfy += ddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[8] = curveLength; + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[9] = curveLength; + segment = 0; + } + p *= curveLength; + for (; ; segment++) { + let length = segments[segment]; + if (p > length) continue; + if (segment == 0) + p /= length; + else { + let prev = segments[segment - 1]; + p = segment + (p - prev) / (length - prev); + } + break; + } + this.addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || i > 0 && space == 0); + } + return out; + } + addBeforePosition(p, temp, i, out, o) { + let x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + } + addAfterPosition(p, temp, i, out, o) { + let x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + } + addCurvePosition(p, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents) { + if (p == 0 || isNaN(p)) { + out[o] = x1; + out[o + 1] = y1; + out[o + 2] = Math.atan2(cy1 - y1, cx1 - x1); + return; + } + let tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u; + let ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p; + let x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; + out[o] = x; + out[o + 1] = y; + if (tangents) { + if (p < 1e-3) + out[o + 2] = Math.atan2(cy1 - y1, cx1 - x1); + else + out[o + 2] = Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); + } + } + }; + + // spine-core/src/PhysicsConstraint.ts + var PhysicsConstraint = class { + data; + _bone = null; + /** The bone constrained by this physics constraint. */ + set bone(bone) { + this._bone = bone; + } + get bone() { + if (!this._bone) throw new Error("Bone not set."); + else return this._bone; + } + inertia = 0; + strength = 0; + damping = 0; + massInverse = 0; + wind = 0; + gravity = 0; + mix = 0; + _reset = true; + ux = 0; + uy = 0; + cx = 0; + cy = 0; + tx = 0; + ty = 0; + xOffset = 0; + xVelocity = 0; + yOffset = 0; + yVelocity = 0; + rotateOffset = 0; + rotateVelocity = 0; + scaleOffset = 0; + scaleVelocity = 0; + active = false; + skeleton; + remaining = 0; + lastTime = 0; + constructor(data, skeleton) { + this.data = data; + this.skeleton = skeleton; + this.bone = skeleton.bones[data.bone.index]; + this.inertia = data.inertia; + this.strength = data.strength; + this.damping = data.damping; + this.massInverse = data.massInverse; + this.wind = data.wind; + this.gravity = data.gravity; + this.mix = data.mix; + } + reset() { + this.remaining = 0; + this.lastTime = this.skeleton.time; + this._reset = true; + this.xOffset = 0; + this.xVelocity = 0; + this.yOffset = 0; + this.yVelocity = 0; + this.rotateOffset = 0; + this.rotateVelocity = 0; + this.scaleOffset = 0; + this.scaleVelocity = 0; + } + setToSetupPose() { + const data = this.data; + this.inertia = data.inertia; + this.strength = data.strength; + this.damping = data.damping; + this.massInverse = data.massInverse; + this.wind = data.wind; + this.gravity = data.gravity; + this.mix = data.mix; + } + isActive() { + return this.active; + } + /** Applies the constraint to the constrained bones. */ + update(physics) { + const mix = this.mix; + if (mix == 0) return; + const x = this.data.x > 0, y = this.data.y > 0, rotateOrShearX = this.data.rotate > 0 || this.data.shearX > 0, scaleX = this.data.scaleX > 0; + const bone = this.bone; + const l = bone.data.length; + switch (physics) { + case 0 /* none */: + return; + case 1 /* reset */: + this.reset(); + // Fall through. + case 2 /* update */: + const skeleton = this.skeleton; + const delta = Math.max(this.skeleton.time - this.lastTime, 0); + this.remaining += delta; + this.lastTime = skeleton.time; + const bx = bone.worldX, by = bone.worldY; + if (this._reset) { + this._reset = false; + this.ux = bx; + this.uy = by; + } else { + let a = this.remaining, i = this.inertia, t = this.data.step, f = this.skeleton.data.referenceScale, d = -1; + let qx = this.data.limit * delta, qy = qx * Math.abs(skeleton.scaleY); + qx *= Math.abs(skeleton.scaleX); + if (x || y) { + if (x) { + const u = (this.ux - bx) * i; + this.xOffset += u > qx ? qx : u < -qx ? -qx : u; + this.ux = bx; + } + if (y) { + const u = (this.uy - by) * i; + this.yOffset += u > qy ? qy : u < -qy ? -qy : u; + this.uy = by; + } + if (a >= t) { + d = Math.pow(this.damping, 60 * t); + const m = this.massInverse * t, e = this.strength, w = this.wind * f * skeleton.scaleX, g = this.gravity * f * skeleton.scaleY; + do { + if (x) { + this.xVelocity += (w - this.xOffset * e) * m; + this.xOffset += this.xVelocity * t; + this.xVelocity *= d; + } + if (y) { + this.yVelocity -= (g + this.yOffset * e) * m; + this.yOffset += this.yVelocity * t; + this.yVelocity *= d; + } + a -= t; + } while (a >= t); + } + if (x) bone.worldX += this.xOffset * mix * this.data.x; + if (y) bone.worldY += this.yOffset * mix * this.data.y; + } + if (rotateOrShearX || scaleX) { + let ca = Math.atan2(bone.c, bone.a), c = 0, s = 0, mr = 0; + let dx = this.cx - bone.worldX, dy = this.cy - bone.worldY; + if (dx > qx) + dx = qx; + else if (dx < -qx) + dx = -qx; + if (dy > qy) + dy = qy; + else if (dy < -qy) + dy = -qy; + if (rotateOrShearX) { + mr = (this.data.rotate + this.data.shearX) * mix; + let r = Math.atan2(dy + this.ty, dx + this.tx) - ca - this.rotateOffset * mr; + this.rotateOffset += (r - Math.ceil(r * MathUtils.invPI2 - 0.5) * MathUtils.PI2) * i; + r = this.rotateOffset * mr + ca; + c = Math.cos(r); + s = Math.sin(r); + if (scaleX) { + r = l * bone.getWorldScaleX(); + if (r > 0) this.scaleOffset += (dx * c + dy * s) * i / r; + } + } else { + c = Math.cos(ca); + s = Math.sin(ca); + const r = l * bone.getWorldScaleX(); + if (r > 0) this.scaleOffset += (dx * c + dy * s) * i / r; + } + a = this.remaining; + if (a >= t) { + if (d == -1) d = Math.pow(this.damping, 60 * t); + const m = this.massInverse * t, e = this.strength, w = this.wind, g = Skeleton.yDown ? -this.gravity : this.gravity, h = l / f; + while (true) { + a -= t; + if (scaleX) { + this.scaleVelocity += (w * c - g * s - this.scaleOffset * e) * m; + this.scaleOffset += this.scaleVelocity * t; + this.scaleVelocity *= d; + } + if (rotateOrShearX) { + this.rotateVelocity -= ((w * s + g * c) * h + this.rotateOffset * e) * m; + this.rotateOffset += this.rotateVelocity * t; + this.rotateVelocity *= d; + if (a < t) break; + const r = this.rotateOffset * mr + ca; + c = Math.cos(r); + s = Math.sin(r); + } else if (a < t) + break; + } + } + } + this.remaining = a; + } + this.cx = bone.worldX; + this.cy = bone.worldY; + break; + case 3 /* pose */: + if (x) bone.worldX += this.xOffset * mix * this.data.x; + if (y) bone.worldY += this.yOffset * mix * this.data.y; + } + if (rotateOrShearX) { + let o = this.rotateOffset * mix, s = 0, c = 0, a = 0; + if (this.data.shearX > 0) { + let r = 0; + if (this.data.rotate > 0) { + r = o * this.data.rotate; + s = Math.sin(r); + c = Math.cos(r); + a = bone.b; + bone.b = c * a - s * bone.d; + bone.d = s * a + c * bone.d; + } + r += o * this.data.shearX; + s = Math.sin(r); + c = Math.cos(r); + a = bone.a; + bone.a = c * a - s * bone.c; + bone.c = s * a + c * bone.c; + } else { + o *= this.data.rotate; + s = Math.sin(o); + c = Math.cos(o); + a = bone.a; + bone.a = c * a - s * bone.c; + bone.c = s * a + c * bone.c; + a = bone.b; + bone.b = c * a - s * bone.d; + bone.d = s * a + c * bone.d; + } + } + if (scaleX) { + const s = 1 + this.scaleOffset * mix * this.data.scaleX; + bone.a *= s; + bone.c *= s; + } + if (physics != 3 /* pose */) { + this.tx = l * bone.a; + this.ty = l * bone.c; + } + bone.updateAppliedTransform(); + } + /** Translates the physics constraint so next {@link #update(Physics)} forces are applied as if the bone moved an additional + * amount in world space. */ + translate(x, y) { + this.ux -= x; + this.uy -= y; + this.cx -= x; + this.cy -= y; + } + /** Rotates the physics constraint so next {@link #update(Physics)} forces are applied as if the bone rotated around the + * specified point in world space. */ + rotate(x, y, degrees) { + const r = degrees * MathUtils.degRad, cos = Math.cos(r), sin = Math.sin(r); + const dx = this.cx - x, dy = this.cy - y; + this.translate(dx * cos - dy * sin - dx, dx * sin + dy * cos - dy); + } + }; + + // spine-core/src/Slot.ts + var Slot = class { + /** The slot's setup pose data. */ + data; + /** The bone this slot belongs to. */ + bone; + /** The color used to tint the slot's attachment. If {@link #getDarkColor()} is set, this is used as the light color for two + * color tinting. */ + color; + /** The dark color used to tint the slot's attachment for two color tinting, or null if two color tinting is not used. The dark + * color's alpha is not used. */ + darkColor = null; + attachment = null; + attachmentState = 0; + /** The index of the texture region to display when the slot's attachment has a {@link Sequence}. -1 represents the + * {@link Sequence#getSetupIndex()}. */ + sequenceIndex = -1; + /** Values to deform the slot's attachment. For an unweighted mesh, the entries are local positions for each vertex. For a + * weighted mesh, the entries are an offset for each vertex which will be added to the mesh's local vertex positions. + * + * See {@link VertexAttachment#computeWorldVertices()} and {@link DeformTimeline}. */ + deform = new Array(); + constructor(data, bone) { + if (!data) throw new Error("data cannot be null."); + if (!bone) throw new Error("bone cannot be null."); + this.data = data; + this.bone = bone; + this.color = new Color(); + this.darkColor = !data.darkColor ? null : new Color(); + this.setToSetupPose(); + } + /** The skeleton this slot belongs to. */ + getSkeleton() { + return this.bone.skeleton; + } + /** The current attachment for the slot, or null if the slot has no attachment. */ + getAttachment() { + return this.attachment; + } + /** Sets the slot's attachment and, if the attachment changed, resets {@link #sequenceIndex} and clears the {@link #deform}. + * The deform is not cleared if the old attachment has the same {@link VertexAttachment#getTimelineAttachment()} as the + * specified attachment. */ + setAttachment(attachment) { + if (this.attachment == attachment) return; + if (!(attachment instanceof VertexAttachment) || !(this.attachment instanceof VertexAttachment) || attachment.timelineAttachment != this.attachment.timelineAttachment) { + this.deform.length = 0; + } + this.attachment = attachment; + this.sequenceIndex = -1; + } + /** Sets this slot to the setup pose. */ + setToSetupPose() { + this.color.setFromColor(this.data.color); + if (this.darkColor) this.darkColor.setFromColor(this.data.darkColor); + if (!this.data.attachmentName) + this.attachment = null; + else { + this.attachment = null; + this.setAttachment(this.bone.skeleton.getAttachment(this.data.index, this.data.attachmentName)); + } + } + }; + + // spine-core/src/TransformConstraint.ts + var TransformConstraint = class { + /** The transform constraint's setup pose data. */ + data; + /** The bones that will be modified by this transform constraint. */ + bones; + /** The target bone whose world transform will be copied to the constrained bones. */ + target; + mixRotate = 0; + mixX = 0; + mixY = 0; + mixScaleX = 0; + mixScaleY = 0; + mixShearY = 0; + temp = new Vector2(); + active = false; + constructor(data, skeleton) { + if (!data) throw new Error("data cannot be null."); + if (!skeleton) throw new Error("skeleton cannot be null."); + this.data = data; + this.bones = new Array(); + for (let i = 0; i < data.bones.length; i++) { + let bone = skeleton.findBone(data.bones[i].name); + if (!bone) throw new Error(`Couldn't find bone ${data.bones[i].name}.`); + this.bones.push(bone); + } + let target = skeleton.findBone(data.target.name); + if (!target) throw new Error(`Couldn't find target bone ${data.target.name}.`); + this.target = target; + this.mixRotate = data.mixRotate; + this.mixX = data.mixX; + this.mixY = data.mixY; + this.mixScaleX = data.mixScaleX; + this.mixScaleY = data.mixScaleY; + this.mixShearY = data.mixShearY; + } + isActive() { + return this.active; + } + setToSetupPose() { + const data = this.data; + this.mixRotate = data.mixRotate; + this.mixX = data.mixX; + this.mixY = data.mixY; + this.mixScaleX = data.mixScaleX; + this.mixScaleY = data.mixScaleY; + this.mixShearY = data.mixShearY; + } + update(physics) { + if (this.mixRotate == 0 && this.mixX == 0 && this.mixY == 0 && this.mixScaleX == 0 && this.mixScaleY == 0 && this.mixShearY == 0) return; + if (this.data.local) { + if (this.data.relative) + this.applyRelativeLocal(); + else + this.applyAbsoluteLocal(); + } else { + if (this.data.relative) + this.applyRelativeWorld(); + else + this.applyAbsoluteWorld(); + } + } + applyAbsoluteWorld() { + let mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX, mixScaleY = this.mixScaleY, mixShearY = this.mixShearY; + let translate = mixX != 0 || mixY != 0; + let target = this.target; + let ta = target.a, tb = target.b, tc = target.c, td = target.d; + let degRadReflect = ta * td - tb * tc > 0 ? MathUtils.degRad : -MathUtils.degRad; + let offsetRotation = this.data.offsetRotation * degRadReflect; + let offsetShearY = this.data.offsetShearY * degRadReflect; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (mixRotate != 0) { + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + let r = Math.atan2(tc, ta) - Math.atan2(c, a) + offsetRotation; + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + r *= mixRotate; + let cos = Math.cos(r), sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + if (translate) { + let temp = this.temp; + target.localToWorld(temp.set(this.data.offsetX, this.data.offsetY)); + bone.worldX += (temp.x - bone.worldX) * mixX; + bone.worldY += (temp.y - bone.worldY) * mixY; + } + if (mixScaleX != 0) { + let s = Math.sqrt(bone.a * bone.a + bone.c * bone.c); + if (s != 0) s = (s + (Math.sqrt(ta * ta + tc * tc) - s + this.data.offsetScaleX) * mixScaleX) / s; + bone.a *= s; + bone.c *= s; + } + if (mixScaleY != 0) { + let s = Math.sqrt(bone.b * bone.b + bone.d * bone.d); + if (s != 0) s = (s + (Math.sqrt(tb * tb + td * td) - s + this.data.offsetScaleY) * mixScaleY) / s; + bone.b *= s; + bone.d *= s; + } + if (mixShearY > 0) { + let b = bone.b, d = bone.d; + let by = Math.atan2(d, b); + let r = Math.atan2(td, tb) - Math.atan2(tc, ta) - (by - Math.atan2(bone.c, bone.a)); + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + r = by + (r + offsetShearY) * mixShearY; + let s = Math.sqrt(b * b + d * d); + bone.b = Math.cos(r) * s; + bone.d = Math.sin(r) * s; + } + bone.updateAppliedTransform(); + } + } + applyRelativeWorld() { + let mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX, mixScaleY = this.mixScaleY, mixShearY = this.mixShearY; + let translate = mixX != 0 || mixY != 0; + let target = this.target; + let ta = target.a, tb = target.b, tc = target.c, td = target.d; + let degRadReflect = ta * td - tb * tc > 0 ? MathUtils.degRad : -MathUtils.degRad; + let offsetRotation = this.data.offsetRotation * degRadReflect, offsetShearY = this.data.offsetShearY * degRadReflect; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (mixRotate != 0) { + let a = bone.a, b = bone.b, c = bone.c, d = bone.d; + let r = Math.atan2(tc, ta) + offsetRotation; + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + r *= mixRotate; + let cos = Math.cos(r), sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + if (translate) { + let temp = this.temp; + target.localToWorld(temp.set(this.data.offsetX, this.data.offsetY)); + bone.worldX += temp.x * mixX; + bone.worldY += temp.y * mixY; + } + if (mixScaleX != 0) { + let s = (Math.sqrt(ta * ta + tc * tc) - 1 + this.data.offsetScaleX) * mixScaleX + 1; + bone.a *= s; + bone.c *= s; + } + if (mixScaleY != 0) { + let s = (Math.sqrt(tb * tb + td * td) - 1 + this.data.offsetScaleY) * mixScaleY + 1; + bone.b *= s; + bone.d *= s; + } + if (mixShearY > 0) { + let r = Math.atan2(td, tb) - Math.atan2(tc, ta); + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + let b = bone.b, d = bone.d; + r = Math.atan2(d, b) + (r - MathUtils.PI / 2 + offsetShearY) * mixShearY; + let s = Math.sqrt(b * b + d * d); + bone.b = Math.cos(r) * s; + bone.d = Math.sin(r) * s; + } + bone.updateAppliedTransform(); + } + } + applyAbsoluteLocal() { + let mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX, mixScaleY = this.mixScaleY, mixShearY = this.mixShearY; + let target = this.target; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + let rotation = bone.arotation; + if (mixRotate != 0) rotation += (target.arotation - rotation + this.data.offsetRotation) * mixRotate; + let x = bone.ax, y = bone.ay; + x += (target.ax - x + this.data.offsetX) * mixX; + y += (target.ay - y + this.data.offsetY) * mixY; + let scaleX = bone.ascaleX, scaleY = bone.ascaleY; + if (mixScaleX != 0 && scaleX != 0) + scaleX = (scaleX + (target.ascaleX - scaleX + this.data.offsetScaleX) * mixScaleX) / scaleX; + if (mixScaleY != 0 && scaleY != 0) + scaleY = (scaleY + (target.ascaleY - scaleY + this.data.offsetScaleY) * mixScaleY) / scaleY; + let shearY = bone.ashearY; + if (mixShearY != 0) shearY += (target.ashearY - shearY + this.data.offsetShearY) * mixShearY; + bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY); + } + } + applyRelativeLocal() { + let mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX, mixScaleY = this.mixScaleY, mixShearY = this.mixShearY; + let target = this.target; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + let rotation = bone.arotation + (target.arotation + this.data.offsetRotation) * mixRotate; + let x = bone.ax + (target.ax + this.data.offsetX) * mixX; + let y = bone.ay + (target.ay + this.data.offsetY) * mixY; + let scaleX = bone.ascaleX * ((target.ascaleX - 1 + this.data.offsetScaleX) * mixScaleX + 1); + let scaleY = bone.ascaleY * ((target.ascaleY - 1 + this.data.offsetScaleY) * mixScaleY + 1); + let shearY = bone.ashearY + (target.ashearY + this.data.offsetShearY) * mixShearY; + bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY); + } + } + }; + + // spine-core/src/Skeleton.ts + var Skeleton = class _Skeleton { + static quadTriangles = [0, 1, 2, 2, 3, 0]; + static yDown = false; + /** The skeleton's setup pose data. */ + data; + /** The skeleton's bones, sorted parent first. The root bone is always the first bone. */ + bones; + /** The skeleton's slots in the setup pose draw order. */ + slots; + /** The skeleton's slots in the order they should be drawn. The returned array may be modified to change the draw order. */ + drawOrder; + /** The skeleton's IK constraints. */ + ikConstraints; + /** The skeleton's transform constraints. */ + transformConstraints; + /** The skeleton's path constraints. */ + pathConstraints; + /** The skeleton's physics constraints. */ + physicsConstraints; + /** The list of bones and constraints, sorted in the order they should be updated, as computed by {@link #updateCache()}. */ + _updateCache = new Array(); + /** The skeleton's current skin. May be null. */ + skin = null; + /** The color to tint all the skeleton's attachments. */ + color; + /** Scales the entire skeleton on the X axis. This affects all bones, even if the bone's transform mode disallows scale + * inheritance. */ + scaleX = 1; + /** Scales the entire skeleton on the Y axis. This affects all bones, even if the bone's transform mode disallows scale + * inheritance. */ + _scaleY = 1; + get scaleY() { + return _Skeleton.yDown ? -this._scaleY : this._scaleY; + } + set scaleY(scaleY) { + this._scaleY = scaleY; + } + /** Sets the skeleton X position, which is added to the root bone worldX position. */ + x = 0; + /** Sets the skeleton Y position, which is added to the root bone worldY position. */ + y = 0; + /** Returns the skeleton's time. This is used for time-based manipulations, such as {@link PhysicsConstraint}. + *

+ * See {@link #update(float)}. */ + time = 0; + constructor(data) { + if (!data) throw new Error("data cannot be null."); + this.data = data; + this.bones = new Array(); + for (let i = 0; i < data.bones.length; i++) { + let boneData = data.bones[i]; + let bone; + if (!boneData.parent) + bone = new Bone(boneData, this, null); + else { + let parent = this.bones[boneData.parent.index]; + bone = new Bone(boneData, this, parent); + parent.children.push(bone); + } + this.bones.push(bone); + } + this.slots = new Array(); + this.drawOrder = new Array(); + for (let i = 0; i < data.slots.length; i++) { + let slotData = data.slots[i]; + let bone = this.bones[slotData.boneData.index]; + let slot = new Slot(slotData, bone); + this.slots.push(slot); + this.drawOrder.push(slot); + } + this.ikConstraints = new Array(); + for (let i = 0; i < data.ikConstraints.length; i++) { + let ikConstraintData = data.ikConstraints[i]; + this.ikConstraints.push(new IkConstraint(ikConstraintData, this)); + } + this.transformConstraints = new Array(); + for (let i = 0; i < data.transformConstraints.length; i++) { + let transformConstraintData = data.transformConstraints[i]; + this.transformConstraints.push(new TransformConstraint(transformConstraintData, this)); + } + this.pathConstraints = new Array(); + for (let i = 0; i < data.pathConstraints.length; i++) { + let pathConstraintData = data.pathConstraints[i]; + this.pathConstraints.push(new PathConstraint(pathConstraintData, this)); + } + this.physicsConstraints = new Array(); + for (let i = 0; i < data.physicsConstraints.length; i++) { + let physicsConstraintData = data.physicsConstraints[i]; + this.physicsConstraints.push(new PhysicsConstraint(physicsConstraintData, this)); + } + this.color = new Color(1, 1, 1, 1); + this.updateCache(); + } + /** Caches information about bones and constraints. Must be called if the {@link #getSkin()} is modified or if bones, + * constraints, or weighted path attachments are added or removed. */ + updateCache() { + let updateCache = this._updateCache; + updateCache.length = 0; + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + bone.sorted = bone.data.skinRequired; + bone.active = !bone.sorted; + } + if (this.skin) { + let skinBones = this.skin.bones; + for (let i = 0, n = this.skin.bones.length; i < n; i++) { + let bone = this.bones[skinBones[i].index]; + do { + bone.sorted = false; + bone.active = true; + bone = bone.parent; + } while (bone); + } + } + let ikConstraints = this.ikConstraints; + let transformConstraints = this.transformConstraints; + let pathConstraints = this.pathConstraints; + let physicsConstraints = this.physicsConstraints; + let ikCount = ikConstraints.length, transformCount = transformConstraints.length, pathCount = pathConstraints.length, physicsCount = this.physicsConstraints.length; + let constraintCount = ikCount + transformCount + pathCount + physicsCount; + outer: + for (let i = 0; i < constraintCount; i++) { + for (let ii = 0; ii < ikCount; ii++) { + let constraint = ikConstraints[ii]; + if (constraint.data.order == i) { + this.sortIkConstraint(constraint); + continue outer; + } + } + for (let ii = 0; ii < transformCount; ii++) { + let constraint = transformConstraints[ii]; + if (constraint.data.order == i) { + this.sortTransformConstraint(constraint); + continue outer; + } + } + for (let ii = 0; ii < pathCount; ii++) { + let constraint = pathConstraints[ii]; + if (constraint.data.order == i) { + this.sortPathConstraint(constraint); + continue outer; + } + } + for (let ii = 0; ii < physicsCount; ii++) { + const constraint = physicsConstraints[ii]; + if (constraint.data.order == i) { + this.sortPhysicsConstraint(constraint); + continue outer; + } + } + } + for (let i = 0, n = bones.length; i < n; i++) + this.sortBone(bones[i]); + } + sortIkConstraint(constraint) { + constraint.active = constraint.target.isActive() && (!constraint.data.skinRequired || this.skin && Utils.contains(this.skin.constraints, constraint.data, true)); + if (!constraint.active) return; + let target = constraint.target; + this.sortBone(target); + let constrained = constraint.bones; + let parent = constrained[0]; + this.sortBone(parent); + if (constrained.length == 1) { + this._updateCache.push(constraint); + this.sortReset(parent.children); + } else { + let child = constrained[constrained.length - 1]; + this.sortBone(child); + this._updateCache.push(constraint); + this.sortReset(parent.children); + child.sorted = true; + } + } + sortPathConstraint(constraint) { + constraint.active = constraint.target.bone.isActive() && (!constraint.data.skinRequired || this.skin && Utils.contains(this.skin.constraints, constraint.data, true)); + if (!constraint.active) return; + let slot = constraint.target; + let slotIndex = slot.data.index; + let slotBone = slot.bone; + if (this.skin) this.sortPathConstraintAttachment(this.skin, slotIndex, slotBone); + if (this.data.defaultSkin && this.data.defaultSkin != this.skin) + this.sortPathConstraintAttachment(this.data.defaultSkin, slotIndex, slotBone); + for (let i = 0, n = this.data.skins.length; i < n; i++) + this.sortPathConstraintAttachment(this.data.skins[i], slotIndex, slotBone); + let attachment = slot.getAttachment(); + if (attachment instanceof PathAttachment) this.sortPathConstraintAttachmentWith(attachment, slotBone); + let constrained = constraint.bones; + let boneCount = constrained.length; + for (let i = 0; i < boneCount; i++) + this.sortBone(constrained[i]); + this._updateCache.push(constraint); + for (let i = 0; i < boneCount; i++) + this.sortReset(constrained[i].children); + for (let i = 0; i < boneCount; i++) + constrained[i].sorted = true; + } + sortTransformConstraint(constraint) { + constraint.active = constraint.target.isActive() && (!constraint.data.skinRequired || this.skin && Utils.contains(this.skin.constraints, constraint.data, true)); + if (!constraint.active) return; + this.sortBone(constraint.target); + let constrained = constraint.bones; + let boneCount = constrained.length; + if (constraint.data.local) { + for (let i = 0; i < boneCount; i++) { + let child = constrained[i]; + this.sortBone(child.parent); + this.sortBone(child); + } + } else { + for (let i = 0; i < boneCount; i++) { + this.sortBone(constrained[i]); + } + } + this._updateCache.push(constraint); + for (let i = 0; i < boneCount; i++) + this.sortReset(constrained[i].children); + for (let i = 0; i < boneCount; i++) + constrained[i].sorted = true; + } + sortPathConstraintAttachment(skin, slotIndex, slotBone) { + let attachments = skin.attachments[slotIndex]; + if (!attachments) return; + for (let key in attachments) { + this.sortPathConstraintAttachmentWith(attachments[key], slotBone); + } + } + sortPathConstraintAttachmentWith(attachment, slotBone) { + if (!(attachment instanceof PathAttachment)) return; + let pathBones = attachment.bones; + if (!pathBones) + this.sortBone(slotBone); + else { + let bones = this.bones; + for (let i = 0, n = pathBones.length; i < n; ) { + let nn = pathBones[i++]; + nn += i; + while (i < nn) + this.sortBone(bones[pathBones[i++]]); + } + } + } + sortPhysicsConstraint(constraint) { + const bone = constraint.bone; + constraint.active = bone.active && (!constraint.data.skinRequired || this.skin != null && Utils.contains(this.skin.constraints, constraint.data, true)); + if (!constraint.active) return; + this.sortBone(bone); + this._updateCache.push(constraint); + this.sortReset(bone.children); + bone.sorted = true; + } + sortBone(bone) { + if (!bone) return; + if (bone.sorted) return; + let parent = bone.parent; + if (parent) this.sortBone(parent); + bone.sorted = true; + this._updateCache.push(bone); + } + sortReset(bones) { + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (!bone.active) continue; + if (bone.sorted) this.sortReset(bone.children); + bone.sorted = false; + } + } + /** Updates the world transform for each bone and applies all constraints. + * + * See [World transforms](http://esotericsoftware.com/spine-runtime-skeletons#World-transforms) in the Spine + * Runtimes Guide. */ + updateWorldTransform(physics) { + if (physics === void 0 || physics === null) throw new Error("physics is undefined"); + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + bone.ax = bone.x; + bone.ay = bone.y; + bone.arotation = bone.rotation; + bone.ascaleX = bone.scaleX; + bone.ascaleY = bone.scaleY; + bone.ashearX = bone.shearX; + bone.ashearY = bone.shearY; + } + let updateCache = this._updateCache; + for (let i = 0, n = updateCache.length; i < n; i++) + updateCache[i].update(physics); + } + updateWorldTransformWith(physics, parent) { + if (!parent) throw new Error("parent cannot be null."); + let bones = this.bones; + for (let i = 1, n = bones.length; i < n; i++) { + let bone = bones[i]; + bone.ax = bone.x; + bone.ay = bone.y; + bone.arotation = bone.rotation; + bone.ascaleX = bone.scaleX; + bone.ascaleY = bone.scaleY; + bone.ashearX = bone.shearX; + bone.ashearY = bone.shearY; + } + let rootBone = this.getRootBone(); + if (!rootBone) throw new Error("Root bone must not be null."); + let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + rootBone.worldX = pa * this.x + pb * this.y + parent.worldX; + rootBone.worldY = pc * this.x + pd * this.y + parent.worldY; + const rx = (rootBone.rotation + rootBone.shearX) * MathUtils.degRad; + const ry = (rootBone.rotation + 90 + rootBone.shearY) * MathUtils.degRad; + const la = Math.cos(rx) * rootBone.scaleX; + const lb = Math.cos(ry) * rootBone.scaleY; + const lc = Math.sin(rx) * rootBone.scaleX; + const ld = Math.sin(ry) * rootBone.scaleY; + rootBone.a = (pa * la + pb * lc) * this.scaleX; + rootBone.b = (pa * lb + pb * ld) * this.scaleX; + rootBone.c = (pc * la + pd * lc) * this.scaleY; + rootBone.d = (pc * lb + pd * ld) * this.scaleY; + let updateCache = this._updateCache; + for (let i = 0, n = updateCache.length; i < n; i++) { + let updatable = updateCache[i]; + if (updatable != rootBone) updatable.update(physics); + } + } + /** Sets the bones, constraints, and slots to their setup pose values. */ + setToSetupPose() { + this.setBonesToSetupPose(); + this.setSlotsToSetupPose(); + } + /** Sets the bones and constraints to their setup pose values. */ + setBonesToSetupPose() { + for (const bone of this.bones) bone.setToSetupPose(); + for (const constraint of this.ikConstraints) constraint.setToSetupPose(); + for (const constraint of this.transformConstraints) constraint.setToSetupPose(); + for (const constraint of this.pathConstraints) constraint.setToSetupPose(); + for (const constraint of this.physicsConstraints) constraint.setToSetupPose(); + } + /** Sets the slots and draw order to their setup pose values. */ + setSlotsToSetupPose() { + let slots = this.slots; + Utils.arrayCopy(slots, 0, this.drawOrder, 0, slots.length); + for (let i = 0, n = slots.length; i < n; i++) + slots[i].setToSetupPose(); + } + /** @returns May return null. */ + getRootBone() { + if (this.bones.length == 0) return null; + return this.bones[0]; + } + /** @returns May be null. */ + findBone(boneName) { + if (!boneName) throw new Error("boneName cannot be null."); + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (bone.data.name == boneName) return bone; + } + return null; + } + /** Finds a slot by comparing each slot's name. It is more efficient to cache the results of this method than to call it + * repeatedly. + * @returns May be null. */ + findSlot(slotName) { + if (!slotName) throw new Error("slotName cannot be null."); + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + if (slot.data.name == slotName) return slot; + } + return null; + } + /** Sets a skin by name. + * + * See {@link #setSkin()}. */ + setSkinByName(skinName) { + let skin = this.data.findSkin(skinName); + if (!skin) throw new Error("Skin not found: " + skinName); + this.setSkin(skin); + } + /** Sets the skin used to look up attachments before looking in the {@link SkeletonData#defaultSkin default skin}. If the + * skin is changed, {@link #updateCache()} is called. + * + * Attachments from the new skin are attached if the corresponding attachment from the old skin was attached. If there was no + * old skin, each slot's setup mode attachment is attached from the new skin. + * + * After changing the skin, the visible attachments can be reset to those attached in the setup pose by calling + * {@link #setSlotsToSetupPose()}. Also, often {@link AnimationState#apply()} is called before the next time the + * skeleton is rendered to allow any attachment keys in the current animation(s) to hide or show attachments from the new skin. + * @param newSkin May be null. */ + setSkin(newSkin) { + if (newSkin == this.skin) return; + if (newSkin) { + if (this.skin) + newSkin.attachAll(this, this.skin); + else { + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + let name = slot.data.attachmentName; + if (name) { + let attachment = newSkin.getAttachment(i, name); + if (attachment) slot.setAttachment(attachment); + } + } + } + } + this.skin = newSkin; + this.updateCache(); + } + /** Finds an attachment by looking in the {@link #skin} and {@link SkeletonData#defaultSkin} using the slot name and attachment + * name. + * + * See {@link #getAttachment()}. + * @returns May be null. */ + getAttachmentByName(slotName, attachmentName) { + let slot = this.data.findSlot(slotName); + if (!slot) throw new Error(`Can't find slot with name ${slotName}`); + return this.getAttachment(slot.index, attachmentName); + } + /** Finds an attachment by looking in the {@link #skin} and {@link SkeletonData#defaultSkin} using the slot index and + * attachment name. First the skin is checked and if the attachment was not found, the default skin is checked. + * + * See [Runtime skins](http://esotericsoftware.com/spine-runtime-skins) in the Spine Runtimes Guide. + * @returns May be null. */ + getAttachment(slotIndex, attachmentName) { + if (!attachmentName) throw new Error("attachmentName cannot be null."); + if (this.skin) { + let attachment = this.skin.getAttachment(slotIndex, attachmentName); + if (attachment) return attachment; + } + if (this.data.defaultSkin) return this.data.defaultSkin.getAttachment(slotIndex, attachmentName); + return null; + } + /** A convenience method to set an attachment by finding the slot with {@link #findSlot()}, finding the attachment with + * {@link #getAttachment()}, then setting the slot's {@link Slot#attachment}. + * @param attachmentName May be null to clear the slot's attachment. */ + setAttachment(slotName, attachmentName) { + if (!slotName) throw new Error("slotName cannot be null."); + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + if (slot.data.name == slotName) { + let attachment = null; + if (attachmentName) { + attachment = this.getAttachment(i, attachmentName); + if (!attachment) throw new Error("Attachment not found: " + attachmentName + ", for slot: " + slotName); + } + slot.setAttachment(attachment); + return; + } + } + throw new Error("Slot not found: " + slotName); + } + /** Finds an IK constraint by comparing each IK constraint's name. It is more efficient to cache the results of this method + * than to call it repeatedly. + * @return May be null. */ + findIkConstraint(constraintName) { + if (!constraintName) throw new Error("constraintName cannot be null."); + return this.ikConstraints.find((constraint) => constraint.data.name == constraintName) ?? null; + } + /** Finds a transform constraint by comparing each transform constraint's name. It is more efficient to cache the results of + * this method than to call it repeatedly. + * @return May be null. */ + findTransformConstraint(constraintName) { + if (!constraintName) throw new Error("constraintName cannot be null."); + return this.transformConstraints.find((constraint) => constraint.data.name == constraintName) ?? null; + } + /** Finds a path constraint by comparing each path constraint's name. It is more efficient to cache the results of this method + * than to call it repeatedly. + * @return May be null. */ + findPathConstraint(constraintName) { + if (!constraintName) throw new Error("constraintName cannot be null."); + return this.pathConstraints.find((constraint) => constraint.data.name == constraintName) ?? null; + } + /** Finds a physics constraint by comparing each physics constraint's name. It is more efficient to cache the results of this + * method than to call it repeatedly. */ + findPhysicsConstraint(constraintName) { + if (constraintName == null) throw new Error("constraintName cannot be null."); + return this.physicsConstraints.find((constraint) => constraint.data.name == constraintName) ?? null; + } + /** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose as `{ x: number, y: number, width: number, height: number }`. + * Note that this method will create temporary objects which can add to garbage collection pressure. Use `getBounds()` if garbage collection is a concern. */ + getBoundsRect(clipper) { + let offset = new Vector2(); + let size = new Vector2(); + this.getBounds(offset, size, void 0, clipper); + return { x: offset.x, y: offset.y, width: size.x, height: size.y }; + } + /** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the current pose. + * @param offset An output value, the distance from the skeleton origin to the bottom left corner of the AABB. + * @param size An output value, the width and height of the AABB. + * @param temp Working memory to temporarily store attachments' computed world vertices. + * @param clipper {@link SkeletonClipping} to use. If null, no clipping is applied. */ + getBounds(offset, size, temp = new Array(2), clipper = null) { + if (!offset) throw new Error("offset cannot be null."); + if (!size) throw new Error("size cannot be null."); + let drawOrder = this.drawOrder; + let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + for (let i = 0, n = drawOrder.length; i < n; i++) { + let slot = drawOrder[i]; + if (!slot.bone.active) continue; + let verticesLength = 0; + let vertices = null; + let triangles = null; + let attachment = slot.getAttachment(); + if (attachment instanceof RegionAttachment) { + verticesLength = 8; + vertices = Utils.setArraySize(temp, verticesLength, 0); + attachment.computeWorldVertices(slot, vertices, 0, 2); + triangles = _Skeleton.quadTriangles; + } else if (attachment instanceof MeshAttachment) { + let mesh = attachment; + verticesLength = mesh.worldVerticesLength; + vertices = Utils.setArraySize(temp, verticesLength, 0); + mesh.computeWorldVertices(slot, 0, verticesLength, vertices, 0, 2); + triangles = mesh.triangles; + } else if (attachment instanceof ClippingAttachment && clipper != null) { + clipper.clipStart(slot, attachment); + continue; + } + if (vertices && triangles) { + if (clipper != null && clipper.isClipping()) { + clipper.clipTriangles(vertices, triangles, triangles.length); + vertices = clipper.clippedVertices; + verticesLength = clipper.clippedVertices.length; + } + for (let ii = 0, nn = vertices.length; ii < nn; ii += 2) { + let x = vertices[ii], y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + if (clipper != null) clipper.clipEndWithSlot(slot); + } + if (clipper != null) clipper.clipEnd(); + offset.set(minX, minY); + size.set(maxX - minX, maxY - minY); + } + /** Increments the skeleton's {@link #time}. */ + update(delta) { + this.time += delta; + } + physicsTranslate(x, y) { + const physicsConstraints = this.physicsConstraints; + for (let i = 0, n = physicsConstraints.length; i < n; i++) + physicsConstraints[i].translate(x, y); + } + /** Calls {@link PhysicsConstraint#rotate(float, float, float)} for each physics constraint. */ + physicsRotate(x, y, degrees) { + const physicsConstraints = this.physicsConstraints; + for (let i = 0, n = physicsConstraints.length; i < n; i++) + physicsConstraints[i].rotate(x, y, degrees); + } + }; + var Physics = /* @__PURE__ */ ((Physics2) => { + Physics2[Physics2["none"] = 0] = "none"; + Physics2[Physics2["reset"] = 1] = "reset"; + Physics2[Physics2["update"] = 2] = "update"; + Physics2[Physics2["pose"] = 3] = "pose"; + return Physics2; + })(Physics || {}); + + // spine-core/src/PhysicsConstraintData.ts + var PhysicsConstraintData = class extends ConstraintData { + _bone = null; + /** The bone constrained by this physics constraint. */ + set bone(boneData) { + this._bone = boneData; + } + get bone() { + if (!this._bone) throw new Error("BoneData not set."); + else return this._bone; + } + x = 0; + y = 0; + rotate = 0; + scaleX = 0; + shearX = 0; + limit = 0; + step = 0; + inertia = 0; + strength = 0; + damping = 0; + massInverse = 0; + wind = 0; + gravity = 0; + /** A percentage (0-1) that controls the mix between the constrained and unconstrained poses. */ + mix = 0; + inertiaGlobal = false; + strengthGlobal = false; + dampingGlobal = false; + massGlobal = false; + windGlobal = false; + gravityGlobal = false; + mixGlobal = false; + constructor(name) { + super(name, 0, false); + } + }; + + // spine-core/src/SkeletonData.ts + var SkeletonData = class { + /** The skeleton's name, which by default is the name of the skeleton data file, if possible. May be null. */ + name = null; + /** The skeleton's bones, sorted parent first. The root bone is always the first bone. */ + bones = new Array(); + // Ordered parents first. + /** The skeleton's slots in the setup pose draw order. */ + slots = new Array(); + // Setup pose draw order. + skins = new Array(); + /** The skeleton's default skin. By default this skin contains all attachments that were not in a skin in Spine. + * + * See {@link Skeleton#getAttachmentByName()}. + * May be null. */ + defaultSkin = null; + /** The skeleton's events. */ + events = new Array(); + /** The skeleton's animations. */ + animations = new Array(); + /** The skeleton's IK constraints. */ + ikConstraints = new Array(); + /** The skeleton's transform constraints. */ + transformConstraints = new Array(); + /** The skeleton's path constraints. */ + pathConstraints = new Array(); + /** The skeleton's physics constraints. */ + physicsConstraints = new Array(); + /** The X coordinate of the skeleton's axis aligned bounding box in the setup pose. */ + x = 0; + /** The Y coordinate of the skeleton's axis aligned bounding box in the setup pose. */ + y = 0; + /** The width of the skeleton's axis aligned bounding box in the setup pose. */ + width = 0; + /** The height of the skeleton's axis aligned bounding box in the setup pose. */ + height = 0; + /** Baseline scale factor for applying distance-dependent effects on non-scalable properties, such as angle or scale. Default + * is 100. */ + referenceScale = 100; + /** The Spine version used to export the skeleton data, or null. */ + version = null; + /** The skeleton data hash. This value will change if any of the skeleton data has changed. May be null. */ + hash = null; + // Nonessential + /** The dopesheet FPS in Spine. Available only when nonessential data was exported. */ + fps = 0; + /** The path to the images directory as defined in Spine. Available only when nonessential data was exported. May be null. */ + imagesPath = null; + /** The path to the audio directory as defined in Spine. Available only when nonessential data was exported. May be null. */ + audioPath = null; + /** Finds a bone by comparing each bone's name. It is more efficient to cache the results of this method than to call it + * multiple times. + * @returns May be null. */ + findBone(boneName) { + if (!boneName) throw new Error("boneName cannot be null."); + let bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) { + let bone = bones[i]; + if (bone.name == boneName) return bone; + } + return null; + } + /** Finds a slot by comparing each slot's name. It is more efficient to cache the results of this method than to call it + * multiple times. + * @returns May be null. */ + findSlot(slotName) { + if (!slotName) throw new Error("slotName cannot be null."); + let slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + let slot = slots[i]; + if (slot.name == slotName) return slot; + } + return null; + } + /** Finds a skin by comparing each skin's name. It is more efficient to cache the results of this method than to call it + * multiple times. + * @returns May be null. */ + findSkin(skinName) { + if (!skinName) throw new Error("skinName cannot be null."); + let skins = this.skins; + for (let i = 0, n = skins.length; i < n; i++) { + let skin = skins[i]; + if (skin.name == skinName) return skin; + } + return null; + } + /** Finds an event by comparing each events's name. It is more efficient to cache the results of this method than to call it + * multiple times. + * @returns May be null. */ + findEvent(eventDataName) { + if (!eventDataName) throw new Error("eventDataName cannot be null."); + let events = this.events; + for (let i = 0, n = events.length; i < n; i++) { + let event = events[i]; + if (event.name == eventDataName) return event; + } + return null; + } + /** Finds an animation by comparing each animation's name. It is more efficient to cache the results of this method than to + * call it multiple times. + * @returns May be null. */ + findAnimation(animationName) { + if (!animationName) throw new Error("animationName cannot be null."); + let animations = this.animations; + for (let i = 0, n = animations.length; i < n; i++) { + let animation = animations[i]; + if (animation.name == animationName) return animation; + } + return null; + } + /** Finds an IK constraint by comparing each IK constraint's name. It is more efficient to cache the results of this method + * than to call it multiple times. + * @return May be null. */ + findIkConstraint(constraintName) { + if (!constraintName) throw new Error("constraintName cannot be null."); + const ikConstraints = this.ikConstraints; + for (let i = 0, n = ikConstraints.length; i < n; i++) { + const constraint = ikConstraints[i]; + if (constraint.name == constraintName) return constraint; + } + return null; + } + /** Finds a transform constraint by comparing each transform constraint's name. It is more efficient to cache the results of + * this method than to call it multiple times. + * @return May be null. */ + findTransformConstraint(constraintName) { + if (!constraintName) throw new Error("constraintName cannot be null."); + const transformConstraints = this.transformConstraints; + for (let i = 0, n = transformConstraints.length; i < n; i++) { + const constraint = transformConstraints[i]; + if (constraint.name == constraintName) return constraint; + } + return null; + } + /** Finds a path constraint by comparing each path constraint's name. It is more efficient to cache the results of this method + * than to call it multiple times. + * @return May be null. */ + findPathConstraint(constraintName) { + if (!constraintName) throw new Error("constraintName cannot be null."); + const pathConstraints = this.pathConstraints; + for (let i = 0, n = pathConstraints.length; i < n; i++) { + const constraint = pathConstraints[i]; + if (constraint.name == constraintName) return constraint; + } + return null; + } + /** Finds a physics constraint by comparing each physics constraint's name. It is more efficient to cache the results of this method + * than to call it multiple times. + * @return May be null. */ + findPhysicsConstraint(constraintName) { + if (!constraintName) throw new Error("constraintName cannot be null."); + const physicsConstraints = this.physicsConstraints; + for (let i = 0, n = physicsConstraints.length; i < n; i++) { + const constraint = physicsConstraints[i]; + if (constraint.name == constraintName) return constraint; + } + return null; + } + }; + + // spine-core/src/Skin.ts + var SkinEntry = class { + constructor(slotIndex = 0, name, attachment) { + this.slotIndex = slotIndex; + this.name = name; + this.attachment = attachment; + } + }; + var Skin = class { + /** The skin's name, which is unique across all skins in the skeleton. */ + name; + attachments = new Array(); + bones = Array(); + constraints = new Array(); + /** The color of the skin as it was in Spine, or a default color if nonessential data was not exported. */ + color = new Color(0.99607843, 0.61960787, 0.30980393, 1); + // fe9e4fff + constructor(name) { + if (!name) throw new Error("name cannot be null."); + this.name = name; + } + /** Adds an attachment to the skin for the specified slot index and name. */ + setAttachment(slotIndex, name, attachment) { + if (!attachment) throw new Error("attachment cannot be null."); + let attachments = this.attachments; + if (slotIndex >= attachments.length) attachments.length = slotIndex + 1; + if (!attachments[slotIndex]) attachments[slotIndex] = {}; + attachments[slotIndex][name] = attachment; + } + /** Adds all attachments, bones, and constraints from the specified skin to this skin. */ + addSkin(skin) { + for (let i = 0; i < skin.bones.length; i++) { + let bone = skin.bones[i]; + let contained = false; + for (let ii = 0; ii < this.bones.length; ii++) { + if (this.bones[ii] == bone) { + contained = true; + break; + } + } + if (!contained) this.bones.push(bone); + } + for (let i = 0; i < skin.constraints.length; i++) { + let constraint = skin.constraints[i]; + let contained = false; + for (let ii = 0; ii < this.constraints.length; ii++) { + if (this.constraints[ii] == constraint) { + contained = true; + break; + } + } + if (!contained) this.constraints.push(constraint); + } + let attachments = skin.getAttachments(); + for (let i = 0; i < attachments.length; i++) { + var attachment = attachments[i]; + this.setAttachment(attachment.slotIndex, attachment.name, attachment.attachment); + } + } + /** Adds all bones and constraints and copies of all attachments from the specified skin to this skin. Mesh attachments are not + * copied, instead a new linked mesh is created. The attachment copies can be modified without affecting the originals. */ + copySkin(skin) { + for (let i = 0; i < skin.bones.length; i++) { + let bone = skin.bones[i]; + let contained = false; + for (let ii = 0; ii < this.bones.length; ii++) { + if (this.bones[ii] == bone) { + contained = true; + break; + } + } + if (!contained) this.bones.push(bone); + } + for (let i = 0; i < skin.constraints.length; i++) { + let constraint = skin.constraints[i]; + let contained = false; + for (let ii = 0; ii < this.constraints.length; ii++) { + if (this.constraints[ii] == constraint) { + contained = true; + break; + } + } + if (!contained) this.constraints.push(constraint); + } + let attachments = skin.getAttachments(); + for (let i = 0; i < attachments.length; i++) { + var attachment = attachments[i]; + if (!attachment.attachment) continue; + if (attachment.attachment instanceof MeshAttachment) { + attachment.attachment = attachment.attachment.newLinkedMesh(); + this.setAttachment(attachment.slotIndex, attachment.name, attachment.attachment); + } else { + attachment.attachment = attachment.attachment.copy(); + this.setAttachment(attachment.slotIndex, attachment.name, attachment.attachment); + } + } + } + /** Returns the attachment for the specified slot index and name, or null. */ + getAttachment(slotIndex, name) { + let dictionary = this.attachments[slotIndex]; + return dictionary ? dictionary[name] : null; + } + /** Removes the attachment in the skin for the specified slot index and name, if any. */ + removeAttachment(slotIndex, name) { + let dictionary = this.attachments[slotIndex]; + if (dictionary) delete dictionary[name]; + } + /** Returns all attachments in this skin. */ + getAttachments() { + let entries = new Array(); + for (var i = 0; i < this.attachments.length; i++) { + let slotAttachments = this.attachments[i]; + if (slotAttachments) { + for (let name in slotAttachments) { + let attachment = slotAttachments[name]; + if (attachment) entries.push(new SkinEntry(i, name, attachment)); + } + } + } + return entries; + } + /** Returns all attachments in this skin for the specified slot index. */ + getAttachmentsForSlot(slotIndex, attachments) { + let slotAttachments = this.attachments[slotIndex]; + if (slotAttachments) { + for (let name in slotAttachments) { + let attachment = slotAttachments[name]; + if (attachment) attachments.push(new SkinEntry(slotIndex, name, attachment)); + } + } + } + /** Clears all attachments, bones, and constraints. */ + clear() { + this.attachments.length = 0; + this.bones.length = 0; + this.constraints.length = 0; + } + /** Attach each attachment in this skin if the corresponding attachment in the old skin is currently attached. */ + attachAll(skeleton, oldSkin) { + let slotIndex = 0; + for (let i = 0; i < skeleton.slots.length; i++) { + let slot = skeleton.slots[i]; + let slotAttachment = slot.getAttachment(); + if (slotAttachment && slotIndex < oldSkin.attachments.length) { + let dictionary = oldSkin.attachments[slotIndex]; + for (let key in dictionary) { + let skinAttachment = dictionary[key]; + if (slotAttachment == skinAttachment) { + let attachment = this.getAttachment(slotIndex, key); + if (attachment) slot.setAttachment(attachment); + break; + } + } + } + slotIndex++; + } + } + }; + + // spine-core/src/SlotData.ts + var SlotData = class { + /** The index of the slot in {@link Skeleton#getSlots()}. */ + index = 0; + /** The name of the slot, which is unique across all slots in the skeleton. */ + name; + /** The bone this slot belongs to. */ + boneData; + /** The color used to tint the slot's attachment. If {@link #getDarkColor()} is set, this is used as the light color for two + * color tinting. */ + color = new Color(1, 1, 1, 1); + /** The dark color used to tint the slot's attachment for two color tinting, or null if two color tinting is not used. The dark + * color's alpha is not used. */ + darkColor = null; + /** The name of the attachment that is visible for this slot in the setup pose, or null if no attachment is visible. */ + attachmentName = null; + /** The blend mode for drawing the slot's attachment. */ + blendMode = 0 /* Normal */; + /** False if the slot was hidden in Spine and nonessential data was exported. Does not affect runtime rendering. */ + visible = true; + constructor(index, name, boneData) { + if (index < 0) throw new Error("index must be >= 0."); + if (!name) throw new Error("name cannot be null."); + if (!boneData) throw new Error("boneData cannot be null."); + this.index = index; + this.name = name; + this.boneData = boneData; + } + }; + var BlendMode = /* @__PURE__ */ ((BlendMode3) => { + BlendMode3[BlendMode3["Normal"] = 0] = "Normal"; + BlendMode3[BlendMode3["Additive"] = 1] = "Additive"; + BlendMode3[BlendMode3["Multiply"] = 2] = "Multiply"; + BlendMode3[BlendMode3["Screen"] = 3] = "Screen"; + return BlendMode3; + })(BlendMode || {}); + + // spine-core/src/TransformConstraintData.ts + var TransformConstraintData = class extends ConstraintData { + /** The bones that will be modified by this transform constraint. */ + bones = new Array(); + /** The target bone whose world transform will be copied to the constrained bones. */ + _target = null; + set target(boneData) { + this._target = boneData; + } + get target() { + if (!this._target) throw new Error("BoneData not set."); + else return this._target; + } + mixRotate = 0; + mixX = 0; + mixY = 0; + mixScaleX = 0; + mixScaleY = 0; + mixShearY = 0; + /** An offset added to the constrained bone rotation. */ + offsetRotation = 0; + /** An offset added to the constrained bone X translation. */ + offsetX = 0; + /** An offset added to the constrained bone Y translation. */ + offsetY = 0; + /** An offset added to the constrained bone scaleX. */ + offsetScaleX = 0; + /** An offset added to the constrained bone scaleY. */ + offsetScaleY = 0; + /** An offset added to the constrained bone shearY. */ + offsetShearY = 0; + relative = false; + local = false; + constructor(name) { + super(name, 0, false); + } + }; + + // spine-core/src/SkeletonBinary.ts + var SkeletonBinary = class { + /** Scales bone positions, image sizes, and translations as they are loaded. This allows different size images to be used at + * runtime than were used in Spine. + * + * See [Scaling](http://esotericsoftware.com/spine-loading-skeleton-data#Scaling) in the Spine Runtimes Guide. */ + scale = 1; + attachmentLoader; + linkedMeshes = new Array(); + constructor(attachmentLoader) { + this.attachmentLoader = attachmentLoader; + } + readSkeletonData(binary) { + let scale = this.scale; + let skeletonData = new SkeletonData(); + skeletonData.name = ""; + let input = new BinaryInput(binary); + let lowHash = input.readInt32(); + let highHash = input.readInt32(); + skeletonData.hash = highHash == 0 && lowHash == 0 ? null : highHash.toString(16) + lowHash.toString(16); + skeletonData.version = input.readString(); + skeletonData.x = input.readFloat(); + skeletonData.y = input.readFloat(); + skeletonData.width = input.readFloat(); + skeletonData.height = input.readFloat(); + skeletonData.referenceScale = input.readFloat() * scale; + let nonessential = input.readBoolean(); + if (nonessential) { + skeletonData.fps = input.readFloat(); + skeletonData.imagesPath = input.readString(); + skeletonData.audioPath = input.readString(); + } + let n = 0; + n = input.readInt(true); + for (let i = 0; i < n; i++) { + let str = input.readString(); + if (!str) throw new Error("String in string table must not be null."); + input.strings.push(str); + } + n = input.readInt(true); + for (let i = 0; i < n; i++) { + let name = input.readString(); + if (!name) throw new Error("Bone name must not be null."); + let parent = i == 0 ? null : skeletonData.bones[input.readInt(true)]; + let data = new BoneData(i, name, parent); + data.rotation = input.readFloat(); + data.x = input.readFloat() * scale; + data.y = input.readFloat() * scale; + data.scaleX = input.readFloat(); + data.scaleY = input.readFloat(); + data.shearX = input.readFloat(); + data.shearY = input.readFloat(); + data.length = input.readFloat() * scale; + data.inherit = input.readByte(); + data.skinRequired = input.readBoolean(); + if (nonessential) { + Color.rgba8888ToColor(data.color, input.readInt32()); + data.icon = input.readString() ?? void 0; + data.visible = input.readBoolean(); + } + skeletonData.bones.push(data); + } + n = input.readInt(true); + for (let i = 0; i < n; i++) { + let slotName = input.readString(); + if (!slotName) throw new Error("Slot name must not be null."); + let boneData = skeletonData.bones[input.readInt(true)]; + let data = new SlotData(i, slotName, boneData); + Color.rgba8888ToColor(data.color, input.readInt32()); + let darkColor = input.readInt32(); + if (darkColor != -1) Color.rgb888ToColor(data.darkColor = new Color(), darkColor); + data.attachmentName = input.readStringRef(); + data.blendMode = input.readInt(true); + if (nonessential) data.visible = input.readBoolean(); + skeletonData.slots.push(data); + } + n = input.readInt(true); + for (let i = 0, nn; i < n; i++) { + let name = input.readString(); + if (!name) throw new Error("IK constraint data name must not be null."); + let data = new IkConstraintData(name); + data.order = input.readInt(true); + nn = input.readInt(true); + for (let ii = 0; ii < nn; ii++) + data.bones.push(skeletonData.bones[input.readInt(true)]); + data.target = skeletonData.bones[input.readInt(true)]; + let flags = input.readByte(); + data.skinRequired = (flags & 1) != 0; + data.bendDirection = (flags & 2) != 0 ? 1 : -1; + data.compress = (flags & 4) != 0; + data.stretch = (flags & 8) != 0; + data.uniform = (flags & 16) != 0; + if ((flags & 32) != 0) data.mix = (flags & 64) != 0 ? input.readFloat() : 1; + if ((flags & 128) != 0) data.softness = input.readFloat() * scale; + skeletonData.ikConstraints.push(data); + } + n = input.readInt(true); + for (let i = 0, nn; i < n; i++) { + let name = input.readString(); + if (!name) throw new Error("Transform constraint data name must not be null."); + let data = new TransformConstraintData(name); + data.order = input.readInt(true); + nn = input.readInt(true); + for (let ii = 0; ii < nn; ii++) + data.bones.push(skeletonData.bones[input.readInt(true)]); + data.target = skeletonData.bones[input.readInt(true)]; + let flags = input.readByte(); + data.skinRequired = (flags & 1) != 0; + data.local = (flags & 2) != 0; + data.relative = (flags & 4) != 0; + if ((flags & 8) != 0) data.offsetRotation = input.readFloat(); + if ((flags & 16) != 0) data.offsetX = input.readFloat() * scale; + if ((flags & 32) != 0) data.offsetY = input.readFloat() * scale; + if ((flags & 64) != 0) data.offsetScaleX = input.readFloat(); + if ((flags & 128) != 0) data.offsetScaleY = input.readFloat(); + flags = input.readByte(); + if ((flags & 1) != 0) data.offsetShearY = input.readFloat(); + if ((flags & 2) != 0) data.mixRotate = input.readFloat(); + if ((flags & 4) != 0) data.mixX = input.readFloat(); + if ((flags & 8) != 0) data.mixY = input.readFloat(); + if ((flags & 16) != 0) data.mixScaleX = input.readFloat(); + if ((flags & 32) != 0) data.mixScaleY = input.readFloat(); + if ((flags & 64) != 0) data.mixShearY = input.readFloat(); + skeletonData.transformConstraints.push(data); + } + n = input.readInt(true); + for (let i = 0, nn; i < n; i++) { + let name = input.readString(); + if (!name) throw new Error("Path constraint data name must not be null."); + let data = new PathConstraintData(name); + data.order = input.readInt(true); + data.skinRequired = input.readBoolean(); + nn = input.readInt(true); + for (let ii = 0; ii < nn; ii++) + data.bones.push(skeletonData.bones[input.readInt(true)]); + data.target = skeletonData.slots[input.readInt(true)]; + const flags = input.readByte(); + data.positionMode = flags & 1; + data.spacingMode = flags >> 1 & 3; + data.rotateMode = flags >> 3 & 3; + if ((flags & 128) != 0) data.offsetRotation = input.readFloat(); + data.position = input.readFloat(); + if (data.positionMode == 0 /* Fixed */) data.position *= scale; + data.spacing = input.readFloat(); + if (data.spacingMode == 0 /* Length */ || data.spacingMode == 1 /* Fixed */) data.spacing *= scale; + data.mixRotate = input.readFloat(); + data.mixX = input.readFloat(); + data.mixY = input.readFloat(); + skeletonData.pathConstraints.push(data); + } + n = input.readInt(true); + for (let i = 0, nn; i < n; i++) { + const name = input.readString(); + if (!name) throw new Error("Physics constraint data name must not be null."); + const data = new PhysicsConstraintData(name); + data.order = input.readInt(true); + data.bone = skeletonData.bones[input.readInt(true)]; + let flags = input.readByte(); + data.skinRequired = (flags & 1) != 0; + if ((flags & 2) != 0) data.x = input.readFloat(); + if ((flags & 4) != 0) data.y = input.readFloat(); + if ((flags & 8) != 0) data.rotate = input.readFloat(); + if ((flags & 16) != 0) data.scaleX = input.readFloat(); + if ((flags & 32) != 0) data.shearX = input.readFloat(); + data.limit = ((flags & 64) != 0 ? input.readFloat() : 5e3) * scale; + data.step = 1 / input.readUnsignedByte(); + data.inertia = input.readFloat(); + data.strength = input.readFloat(); + data.damping = input.readFloat(); + data.massInverse = (flags & 128) != 0 ? input.readFloat() : 1; + data.wind = input.readFloat(); + data.gravity = input.readFloat(); + flags = input.readByte(); + if ((flags & 1) != 0) data.inertiaGlobal = true; + if ((flags & 2) != 0) data.strengthGlobal = true; + if ((flags & 4) != 0) data.dampingGlobal = true; + if ((flags & 8) != 0) data.massGlobal = true; + if ((flags & 16) != 0) data.windGlobal = true; + if ((flags & 32) != 0) data.gravityGlobal = true; + if ((flags & 64) != 0) data.mixGlobal = true; + data.mix = (flags & 128) != 0 ? input.readFloat() : 1; + skeletonData.physicsConstraints.push(data); + } + let defaultSkin = this.readSkin(input, skeletonData, true, nonessential); + if (defaultSkin) { + skeletonData.defaultSkin = defaultSkin; + skeletonData.skins.push(defaultSkin); + } + { + let i = skeletonData.skins.length; + Utils.setArraySize(skeletonData.skins, n = i + input.readInt(true)); + for (; i < n; i++) { + let skin = this.readSkin(input, skeletonData, false, nonessential); + if (!skin) throw new Error("readSkin() should not have returned null."); + skeletonData.skins[i] = skin; + } + } + n = this.linkedMeshes.length; + for (let i = 0; i < n; i++) { + let linkedMesh = this.linkedMeshes[i]; + const skin = skeletonData.skins[linkedMesh.skinIndex]; + if (!linkedMesh.parent) throw new Error("Linked mesh parent must not be null"); + let parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); + if (!parent) throw new Error(`Parent mesh not found: ${linkedMesh.parent}`); + linkedMesh.mesh.timelineAttachment = linkedMesh.inheritTimeline ? parent : linkedMesh.mesh; + linkedMesh.mesh.setParentMesh(parent); + if (linkedMesh.mesh.region != null) linkedMesh.mesh.updateRegion(); + } + this.linkedMeshes.length = 0; + n = input.readInt(true); + for (let i = 0; i < n; i++) { + let eventName = input.readString(); + if (!eventName) throw new Error("Event data name must not be null"); + let data = new EventData(eventName); + data.intValue = input.readInt(false); + data.floatValue = input.readFloat(); + data.stringValue = input.readString(); + data.audioPath = input.readString(); + if (data.audioPath) { + data.volume = input.readFloat(); + data.balance = input.readFloat(); + } + skeletonData.events.push(data); + } + n = input.readInt(true); + for (let i = 0; i < n; i++) { + let animationName = input.readString(); + if (!animationName) throw new Error("Animatio name must not be null."); + skeletonData.animations.push(this.readAnimation(input, animationName, skeletonData)); + } + return skeletonData; + } + readSkin(input, skeletonData, defaultSkin, nonessential) { + let skin = null; + let slotCount = 0; + if (defaultSkin) { + slotCount = input.readInt(true); + if (slotCount == 0) return null; + skin = new Skin("default"); + } else { + let skinName = input.readString(); + if (!skinName) throw new Error("Skin name must not be null."); + skin = new Skin(skinName); + if (nonessential) Color.rgba8888ToColor(skin.color, input.readInt32()); + skin.bones.length = input.readInt(true); + for (let i = 0, n = skin.bones.length; i < n; i++) + skin.bones[i] = skeletonData.bones[input.readInt(true)]; + for (let i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.push(skeletonData.ikConstraints[input.readInt(true)]); + for (let i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.push(skeletonData.transformConstraints[input.readInt(true)]); + for (let i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.push(skeletonData.pathConstraints[input.readInt(true)]); + for (let i = 0, n = input.readInt(true); i < n; i++) + skin.constraints.push(skeletonData.physicsConstraints[input.readInt(true)]); + slotCount = input.readInt(true); + } + for (let i = 0; i < slotCount; i++) { + let slotIndex = input.readInt(true); + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + let name = input.readStringRef(); + if (!name) + throw new Error("Attachment name must not be null"); + let attachment = this.readAttachment(input, skeletonData, skin, slotIndex, name, nonessential); + if (attachment) skin.setAttachment(slotIndex, name, attachment); + } + } + return skin; + } + readAttachment(input, skeletonData, skin, slotIndex, attachmentName, nonessential) { + let scale = this.scale; + let flags = input.readByte(); + const name = (flags & 8) != 0 ? input.readStringRef() : attachmentName; + if (!name) throw new Error("Attachment name must not be null"); + switch (flags & 7) { + // BUG? + case 0 /* Region */: { + let path = (flags & 16) != 0 ? input.readStringRef() : null; + const color = (flags & 32) != 0 ? input.readInt32() : 4294967295; + const sequence = (flags & 64) != 0 ? this.readSequence(input) : null; + let rotation = (flags & 128) != 0 ? input.readFloat() : 0; + let x = input.readFloat(); + let y = input.readFloat(); + let scaleX = input.readFloat(); + let scaleY = input.readFloat(); + let width = input.readFloat(); + let height = input.readFloat(); + if (!path) path = name; + let region = this.attachmentLoader.newRegionAttachment(skin, name, path, sequence); + if (!region) return null; + region.path = path; + region.x = x * scale; + region.y = y * scale; + region.scaleX = scaleX; + region.scaleY = scaleY; + region.rotation = rotation; + region.width = width * scale; + region.height = height * scale; + Color.rgba8888ToColor(region.color, color); + region.sequence = sequence; + if (sequence == null) region.updateRegion(); + return region; + } + case 1 /* BoundingBox */: { + let vertices = this.readVertices(input, (flags & 16) != 0); + let color = nonessential ? input.readInt32() : 0; + let box = this.attachmentLoader.newBoundingBoxAttachment(skin, name); + if (!box) return null; + box.worldVerticesLength = vertices.length; + box.vertices = vertices.vertices; + box.bones = vertices.bones; + if (nonessential) Color.rgba8888ToColor(box.color, color); + return box; + } + case 2 /* Mesh */: { + let path = (flags & 16) != 0 ? input.readStringRef() : name; + const color = (flags & 32) != 0 ? input.readInt32() : 4294967295; + const sequence = (flags & 64) != 0 ? this.readSequence(input) : null; + const hullLength = input.readInt(true); + const vertices = this.readVertices(input, (flags & 128) != 0); + const uvs = this.readFloatArray(input, vertices.length, 1); + const triangles = this.readShortArray(input, (vertices.length - hullLength - 2) * 3); + let edges = []; + let width = 0, height = 0; + if (nonessential) { + edges = this.readShortArray(input, input.readInt(true)); + width = input.readFloat(); + height = input.readFloat(); + } + if (!path) path = name; + let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path, sequence); + if (!mesh) return null; + mesh.path = path; + Color.rgba8888ToColor(mesh.color, color); + mesh.bones = vertices.bones; + mesh.vertices = vertices.vertices; + mesh.worldVerticesLength = vertices.length; + mesh.triangles = triangles; + mesh.regionUVs = uvs; + if (sequence == null) mesh.updateRegion(); + mesh.hullLength = hullLength << 1; + mesh.sequence = sequence; + if (nonessential) { + mesh.edges = edges; + mesh.width = width * scale; + mesh.height = height * scale; + } + return mesh; + } + case 3 /* LinkedMesh */: { + const path = (flags & 16) != 0 ? input.readStringRef() : name; + if (path == null) throw new Error("Path of linked mesh must not be null"); + const color = (flags & 32) != 0 ? input.readInt32() : 4294967295; + const sequence = (flags & 64) != 0 ? this.readSequence(input) : null; + const inheritTimelines = (flags & 128) != 0; + const skinIndex = input.readInt(true); + const parent = input.readStringRef(); + let width = 0, height = 0; + if (nonessential) { + width = input.readFloat(); + height = input.readFloat(); + } + let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path, sequence); + if (!mesh) return null; + mesh.path = path; + Color.rgba8888ToColor(mesh.color, color); + mesh.sequence = sequence; + if (nonessential) { + mesh.width = width * scale; + mesh.height = height * scale; + } + this.linkedMeshes.push(new LinkedMesh(mesh, skinIndex, slotIndex, parent, inheritTimelines)); + return mesh; + } + case 4 /* Path */: { + const closed2 = (flags & 16) != 0; + const constantSpeed = (flags & 32) != 0; + const vertices = this.readVertices(input, (flags & 64) != 0); + const lengths = Utils.newArray(vertices.length / 6, 0); + for (let i = 0, n = lengths.length; i < n; i++) + lengths[i] = input.readFloat() * scale; + const color = nonessential ? input.readInt32() : 0; + const path = this.attachmentLoader.newPathAttachment(skin, name); + if (!path) return null; + path.closed = closed2; + path.constantSpeed = constantSpeed; + path.worldVerticesLength = vertices.length; + path.vertices = vertices.vertices; + path.bones = vertices.bones; + path.lengths = lengths; + if (nonessential) Color.rgba8888ToColor(path.color, color); + return path; + } + case 5 /* Point */: { + const rotation = input.readFloat(); + const x = input.readFloat(); + const y = input.readFloat(); + const color = nonessential ? input.readInt32() : 0; + const point = this.attachmentLoader.newPointAttachment(skin, name); + if (!point) return null; + point.x = x * scale; + point.y = y * scale; + point.rotation = rotation; + if (nonessential) Color.rgba8888ToColor(point.color, color); + return point; + } + case 6 /* Clipping */: { + const endSlotIndex = input.readInt(true); + const vertices = this.readVertices(input, (flags & 16) != 0); + let color = nonessential ? input.readInt32() : 0; + let clip = this.attachmentLoader.newClippingAttachment(skin, name); + if (!clip) return null; + clip.endSlot = skeletonData.slots[endSlotIndex]; + clip.worldVerticesLength = vertices.length; + clip.vertices = vertices.vertices; + clip.bones = vertices.bones; + if (nonessential) Color.rgba8888ToColor(clip.color, color); + return clip; + } + } + return null; + } + readSequence(input) { + let sequence = new Sequence(input.readInt(true)); + sequence.start = input.readInt(true); + sequence.digits = input.readInt(true); + sequence.setupIndex = input.readInt(true); + return sequence; + } + readVertices(input, weighted) { + const scale = this.scale; + const vertexCount = input.readInt(true); + const vertices = new Vertices(); + vertices.length = vertexCount << 1; + if (!weighted) { + vertices.vertices = this.readFloatArray(input, vertices.length, scale); + return vertices; + } + let weights = new Array(); + let bonesArray = new Array(); + for (let i = 0; i < vertexCount; i++) { + let boneCount = input.readInt(true); + bonesArray.push(boneCount); + for (let ii = 0; ii < boneCount; ii++) { + bonesArray.push(input.readInt(true)); + weights.push(input.readFloat() * scale); + weights.push(input.readFloat() * scale); + weights.push(input.readFloat()); + } + } + vertices.vertices = Utils.toFloatArray(weights); + vertices.bones = bonesArray; + return vertices; + } + readFloatArray(input, n, scale) { + let array = new Array(n); + if (scale == 1) { + for (let i = 0; i < n; i++) + array[i] = input.readFloat(); + } else { + for (let i = 0; i < n; i++) + array[i] = input.readFloat() * scale; + } + return array; + } + readShortArray(input, n) { + let array = new Array(n); + for (let i = 0; i < n; i++) + array[i] = input.readInt(true); + return array; + } + readAnimation(input, name, skeletonData) { + input.readInt(true); + let timelines = new Array(); + let scale = this.scale; + for (let i = 0, n = input.readInt(true); i < n; i++) { + let slotIndex = input.readInt(true); + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + let timelineType = input.readByte(); + let frameCount = input.readInt(true); + let frameLast = frameCount - 1; + switch (timelineType) { + case SLOT_ATTACHMENT: { + let timeline = new AttachmentTimeline(frameCount, slotIndex); + for (let frame = 0; frame < frameCount; frame++) + timeline.setFrame(frame, input.readFloat(), input.readStringRef()); + timelines.push(timeline); + break; + } + case SLOT_RGBA: { + let bezierCount = input.readInt(true); + let timeline = new RGBATimeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + let a = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b, a); + if (frame == frameLast) break; + let time2 = input.readFloat(); + let r2 = input.readUnsignedByte() / 255; + let g2 = input.readUnsignedByte() / 255; + let b2 = input.readUnsignedByte() / 255; + let a2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, r2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, g2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, b2, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, a, a2, 1); + } + time = time2; + r = r2; + g = g2; + b = b2; + a = a2; + } + timelines.push(timeline); + break; + } + case SLOT_RGB: { + let bezierCount = input.readInt(true); + let timeline = new RGBTimeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b); + if (frame == frameLast) break; + let time2 = input.readFloat(); + let r2 = input.readUnsignedByte() / 255; + let g2 = input.readUnsignedByte() / 255; + let b2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, r2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, g2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, b2, 1); + } + time = time2; + r = r2; + g = g2; + b = b2; + } + timelines.push(timeline); + break; + } + case SLOT_RGBA2: { + let bezierCount = input.readInt(true); + let timeline = new RGBA2Timeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + let a = input.readUnsignedByte() / 255; + let r2 = input.readUnsignedByte() / 255; + let g2 = input.readUnsignedByte() / 255; + let b2 = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b, a, r2, g2, b2); + if (frame == frameLast) break; + let time2 = input.readFloat(); + let nr = input.readUnsignedByte() / 255; + let ng = input.readUnsignedByte() / 255; + let nb = input.readUnsignedByte() / 255; + let na = input.readUnsignedByte() / 255; + let nr2 = input.readUnsignedByte() / 255; + let ng2 = input.readUnsignedByte() / 255; + let nb2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, nr, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, ng, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, nb, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, a, na, 1); + setBezier(input, timeline, bezier++, frame, 4, time, time2, r2, nr2, 1); + setBezier(input, timeline, bezier++, frame, 5, time, time2, g2, ng2, 1); + setBezier(input, timeline, bezier++, frame, 6, time, time2, b2, nb2, 1); + } + time = time2; + r = nr; + g = ng; + b = nb; + a = na; + r2 = nr2; + g2 = ng2; + b2 = nb2; + } + timelines.push(timeline); + break; + } + case SLOT_RGB2: { + let bezierCount = input.readInt(true); + let timeline = new RGB2Timeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + let r2 = input.readUnsignedByte() / 255; + let g2 = input.readUnsignedByte() / 255; + let b2 = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b, r2, g2, b2); + if (frame == frameLast) break; + let time2 = input.readFloat(); + let nr = input.readUnsignedByte() / 255; + let ng = input.readUnsignedByte() / 255; + let nb = input.readUnsignedByte() / 255; + let nr2 = input.readUnsignedByte() / 255; + let ng2 = input.readUnsignedByte() / 255; + let nb2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, nr, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, ng, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, nb, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, r2, nr2, 1); + setBezier(input, timeline, bezier++, frame, 4, time, time2, g2, ng2, 1); + setBezier(input, timeline, bezier++, frame, 5, time, time2, b2, nb2, 1); + } + time = time2; + r = nr; + g = ng; + b = nb; + r2 = nr2; + g2 = ng2; + b2 = nb2; + } + timelines.push(timeline); + break; + } + case SLOT_ALPHA: { + let timeline = new AlphaTimeline(frameCount, input.readInt(true), slotIndex); + let time = input.readFloat(), a = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, a); + if (frame == frameLast) break; + let time2 = input.readFloat(); + let a2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, a, a2, 1); + } + time = time2; + a = a2; + } + timelines.push(timeline); + } + } + } + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + let boneIndex = input.readInt(true); + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + let type = input.readByte(), frameCount = input.readInt(true); + if (type == BONE_INHERIT) { + let timeline = new InheritTimeline(frameCount, boneIndex); + for (let frame = 0; frame < frameCount; frame++) { + timeline.setFrame(frame, input.readFloat(), input.readByte()); + } + timelines.push(timeline); + continue; + } + let bezierCount = input.readInt(true); + switch (type) { + case BONE_ROTATE: + timelines.push(readTimeline1(input, new RotateTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_TRANSLATE: + timelines.push(readTimeline2(input, new TranslateTimeline(frameCount, bezierCount, boneIndex), scale)); + break; + case BONE_TRANSLATEX: + timelines.push(readTimeline1(input, new TranslateXTimeline(frameCount, bezierCount, boneIndex), scale)); + break; + case BONE_TRANSLATEY: + timelines.push(readTimeline1(input, new TranslateYTimeline(frameCount, bezierCount, boneIndex), scale)); + break; + case BONE_SCALE: + timelines.push(readTimeline2(input, new ScaleTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_SCALEX: + timelines.push(readTimeline1(input, new ScaleXTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_SCALEY: + timelines.push(readTimeline1(input, new ScaleYTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_SHEAR: + timelines.push(readTimeline2(input, new ShearTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_SHEARX: + timelines.push(readTimeline1(input, new ShearXTimeline(frameCount, bezierCount, boneIndex), 1)); + break; + case BONE_SHEARY: + timelines.push(readTimeline1(input, new ShearYTimeline(frameCount, bezierCount, boneIndex), 1)); + } + } + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + let index = input.readInt(true), frameCount = input.readInt(true), frameLast = frameCount - 1; + let timeline = new IkConstraintTimeline(frameCount, input.readInt(true), index); + let flags = input.readByte(); + let time = input.readFloat(), mix = (flags & 1) != 0 ? (flags & 2) != 0 ? input.readFloat() : 1 : 0; + let softness = (flags & 4) != 0 ? input.readFloat() * scale : 0; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mix, softness, (flags & 8) != 0 ? 1 : -1, (flags & 16) != 0, (flags & 32) != 0); + if (frame == frameLast) break; + flags = input.readByte(); + const time2 = input.readFloat(), mix2 = (flags & 1) != 0 ? (flags & 2) != 0 ? input.readFloat() : 1 : 0; + const softness2 = (flags & 4) != 0 ? input.readFloat() * scale : 0; + if ((flags & 64) != 0) { + timeline.setStepped(frame); + } else if ((flags & 128) != 0) { + setBezier(input, timeline, bezier++, frame, 0, time, time2, mix, mix2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, softness, softness2, scale); + } + time = time2; + mix = mix2; + softness = softness2; + } + timelines.push(timeline); + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + let index = input.readInt(true), frameCount = input.readInt(true), frameLast = frameCount - 1; + let timeline = new TransformConstraintTimeline(frameCount, input.readInt(true), index); + let time = input.readFloat(), mixRotate = input.readFloat(), mixX = input.readFloat(), mixY = input.readFloat(), mixScaleX = input.readFloat(), mixScaleY = input.readFloat(), mixShearY = input.readFloat(); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY); + if (frame == frameLast) break; + let time2 = input.readFloat(), mixRotate2 = input.readFloat(), mixX2 = input.readFloat(), mixY2 = input.readFloat(), mixScaleX2 = input.readFloat(), mixScaleY2 = input.readFloat(), mixShearY2 = input.readFloat(); + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, mixY, mixY2, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, mixScaleX, mixScaleX2, 1); + setBezier(input, timeline, bezier++, frame, 4, time, time2, mixScaleY, mixScaleY2, 1); + setBezier(input, timeline, bezier++, frame, 5, time, time2, mixShearY, mixShearY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + mixScaleX = mixScaleX2; + mixScaleY = mixScaleY2; + mixShearY = mixShearY2; + } + timelines.push(timeline); + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + let index = input.readInt(true); + let data = skeletonData.pathConstraints[index]; + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + const type = input.readByte(), frameCount = input.readInt(true), bezierCount = input.readInt(true); + switch (type) { + case PATH_POSITION: + timelines.push(readTimeline1( + input, + new PathConstraintPositionTimeline(frameCount, bezierCount, index), + data.positionMode == 0 /* Fixed */ ? scale : 1 + )); + break; + case PATH_SPACING: + timelines.push(readTimeline1( + input, + new PathConstraintSpacingTimeline(frameCount, bezierCount, index), + data.spacingMode == 0 /* Length */ || data.spacingMode == 1 /* Fixed */ ? scale : 1 + )); + break; + case PATH_MIX: + let timeline = new PathConstraintMixTimeline(frameCount, bezierCount, index); + let time = input.readFloat(), mixRotate = input.readFloat(), mixX = input.readFloat(), mixY = input.readFloat(); + for (let frame = 0, bezier = 0, frameLast = timeline.getFrameCount() - 1; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY); + if (frame == frameLast) break; + let time2 = input.readFloat(), mixRotate2 = input.readFloat(), mixX2 = input.readFloat(), mixY2 = input.readFloat(); + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, mixY, mixY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + } + timelines.push(timeline); + } + } + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + const index = input.readInt(true) - 1; + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + const type = input.readByte(), frameCount = input.readInt(true); + if (type == PHYSICS_RESET) { + const timeline = new PhysicsConstraintResetTimeline(frameCount, index); + for (let frame = 0; frame < frameCount; frame++) + timeline.setFrame(frame, input.readFloat()); + timelines.push(timeline); + continue; + } + const bezierCount = input.readInt(true); + switch (type) { + case PHYSICS_INERTIA: + timelines.push(readTimeline1(input, new PhysicsConstraintInertiaTimeline(frameCount, bezierCount, index), 1)); + break; + case PHYSICS_STRENGTH: + timelines.push(readTimeline1(input, new PhysicsConstraintStrengthTimeline(frameCount, bezierCount, index), 1)); + break; + case PHYSICS_DAMPING: + timelines.push(readTimeline1(input, new PhysicsConstraintDampingTimeline(frameCount, bezierCount, index), 1)); + break; + case PHYSICS_MASS: + timelines.push(readTimeline1(input, new PhysicsConstraintMassTimeline(frameCount, bezierCount, index), 1)); + break; + case PHYSICS_WIND: + timelines.push(readTimeline1(input, new PhysicsConstraintWindTimeline(frameCount, bezierCount, index), 1)); + break; + case PHYSICS_GRAVITY: + timelines.push(readTimeline1(input, new PhysicsConstraintGravityTimeline(frameCount, bezierCount, index), 1)); + break; + case PHYSICS_MIX: + timelines.push(readTimeline1(input, new PhysicsConstraintMixTimeline(frameCount, bezierCount, index), 1)); + } + } + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + let skin = skeletonData.skins[input.readInt(true)]; + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + let slotIndex = input.readInt(true); + for (let iii = 0, nnn = input.readInt(true); iii < nnn; iii++) { + let attachmentName = input.readStringRef(); + if (!attachmentName) throw new Error("attachmentName must not be null."); + let attachment = skin.getAttachment(slotIndex, attachmentName); + let timelineType = input.readByte(); + let frameCount = input.readInt(true); + let frameLast = frameCount - 1; + switch (timelineType) { + case ATTACHMENT_DEFORM: { + let vertexAttachment = attachment; + let weighted = vertexAttachment.bones; + let vertices = vertexAttachment.vertices; + let deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + let bezierCount = input.readInt(true); + let timeline = new DeformTimeline(frameCount, bezierCount, slotIndex, vertexAttachment); + let time = input.readFloat(); + for (let frame = 0, bezier = 0; ; frame++) { + let deform; + let end = input.readInt(true); + if (end == 0) + deform = weighted ? Utils.newFloatArray(deformLength) : vertices; + else { + deform = Utils.newFloatArray(deformLength); + let start = input.readInt(true); + end += start; + if (scale == 1) { + for (let v = start; v < end; v++) + deform[v] = input.readFloat(); + } else { + for (let v = start; v < end; v++) + deform[v] = input.readFloat() * scale; + } + if (!weighted) { + for (let v = 0, vn = deform.length; v < vn; v++) + deform[v] += vertices[v]; + } + } + timeline.setFrame(frame, time, deform); + if (frame == frameLast) break; + let time2 = input.readFloat(); + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, 0, 1, 1); + } + time = time2; + } + timelines.push(timeline); + break; + } + case ATTACHMENT_SEQUENCE: { + let timeline = new SequenceTimeline(frameCount, slotIndex, attachment); + for (let frame = 0; frame < frameCount; frame++) { + let time = input.readFloat(); + let modeAndIndex = input.readInt32(); + timeline.setFrame( + frame, + time, + SequenceModeValues[modeAndIndex & 15], + modeAndIndex >> 4, + input.readFloat() + ); + } + timelines.push(timeline); + break; + } + } + } + } + } + let drawOrderCount = input.readInt(true); + if (drawOrderCount > 0) { + let timeline = new DrawOrderTimeline(drawOrderCount); + let slotCount = skeletonData.slots.length; + for (let i = 0; i < drawOrderCount; i++) { + let time = input.readFloat(); + let offsetCount = input.readInt(true); + let drawOrder = Utils.newArray(slotCount, 0); + for (let ii = slotCount - 1; ii >= 0; ii--) + drawOrder[ii] = -1; + let unchanged = Utils.newArray(slotCount - offsetCount, 0); + let originalIndex = 0, unchangedIndex = 0; + for (let ii = 0; ii < offsetCount; ii++) { + let slotIndex = input.readInt(true); + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + drawOrder[originalIndex + input.readInt(true)] = originalIndex++; + } + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + for (let ii = slotCount - 1; ii >= 0; ii--) + if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex]; + timeline.setFrame(i, time, drawOrder); + } + timelines.push(timeline); + } + let eventCount = input.readInt(true); + if (eventCount > 0) { + let timeline = new EventTimeline(eventCount); + for (let i = 0; i < eventCount; i++) { + let time = input.readFloat(); + let eventData = skeletonData.events[input.readInt(true)]; + let event = new Event(time, eventData); + event.intValue = input.readInt(false); + event.floatValue = input.readFloat(); + event.stringValue = input.readString(); + if (event.stringValue == null) event.stringValue = eventData.stringValue; + if (event.data.audioPath) { + event.volume = input.readFloat(); + event.balance = input.readFloat(); + } + timeline.setFrame(i, event); + } + timelines.push(timeline); + } + let duration = 0; + for (let i = 0, n = timelines.length; i < n; i++) + duration = Math.max(duration, timelines[i].getDuration()); + return new Animation(name, timelines, duration); + } + }; + var BinaryInput = class { + constructor(data, strings = new Array(), index = 0, buffer = new DataView(data instanceof ArrayBuffer ? data : data.buffer)) { + this.strings = strings; + this.index = index; + this.buffer = buffer; + } + readByte() { + return this.buffer.getInt8(this.index++); + } + readUnsignedByte() { + return this.buffer.getUint8(this.index++); + } + readShort() { + let value = this.buffer.getInt16(this.index); + this.index += 2; + return value; + } + readInt32() { + let value = this.buffer.getInt32(this.index); + this.index += 4; + return value; + } + readInt(optimizePositive) { + let b = this.readByte(); + let result = b & 127; + if ((b & 128) != 0) { + b = this.readByte(); + result |= (b & 127) << 7; + if ((b & 128) != 0) { + b = this.readByte(); + result |= (b & 127) << 14; + if ((b & 128) != 0) { + b = this.readByte(); + result |= (b & 127) << 21; + if ((b & 128) != 0) { + b = this.readByte(); + result |= (b & 127) << 28; + } + } + } + } + return optimizePositive ? result : result >>> 1 ^ -(result & 1); + } + readStringRef() { + let index = this.readInt(true); + return index == 0 ? null : this.strings[index - 1]; + } + readString() { + let byteCount = this.readInt(true); + switch (byteCount) { + case 0: + return null; + case 1: + return ""; + } + byteCount--; + let chars = ""; + let charCount = 0; + for (let i = 0; i < byteCount; ) { + let b = this.readUnsignedByte(); + switch (b >> 4) { + case 12: + case 13: + chars += String.fromCharCode((b & 31) << 6 | this.readByte() & 63); + i += 2; + break; + case 14: + chars += String.fromCharCode((b & 15) << 12 | (this.readByte() & 63) << 6 | this.readByte() & 63); + i += 3; + break; + default: + chars += String.fromCharCode(b); + i++; + } + } + return chars; + } + readFloat() { + let value = this.buffer.getFloat32(this.index); + this.index += 4; + return value; + } + readBoolean() { + return this.readByte() != 0; + } + }; + var LinkedMesh = class { + parent; + skinIndex; + slotIndex; + mesh; + inheritTimeline; + constructor(mesh, skinIndex, slotIndex, parent, inheritDeform) { + this.mesh = mesh; + this.skinIndex = skinIndex; + this.slotIndex = slotIndex; + this.parent = parent; + this.inheritTimeline = inheritDeform; + } + }; + var Vertices = class { + constructor(bones = null, vertices = null, length = 0) { + this.bones = bones; + this.vertices = vertices; + this.length = length; + } + }; + function readTimeline1(input, timeline, scale) { + let time = input.readFloat(), value = input.readFloat() * scale; + for (let frame = 0, bezier = 0, frameLast = timeline.getFrameCount() - 1; ; frame++) { + timeline.setFrame(frame, time, value); + if (frame == frameLast) break; + let time2 = input.readFloat(), value2 = input.readFloat() * scale; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, value, value2, scale); + } + time = time2; + value = value2; + } + return timeline; + } + function readTimeline2(input, timeline, scale) { + let time = input.readFloat(), value1 = input.readFloat() * scale, value2 = input.readFloat() * scale; + for (let frame = 0, bezier = 0, frameLast = timeline.getFrameCount() - 1; ; frame++) { + timeline.setFrame(frame, time, value1, value2); + if (frame == frameLast) break; + let time2 = input.readFloat(), nvalue1 = input.readFloat() * scale, nvalue2 = input.readFloat() * scale; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, value1, nvalue1, scale); + setBezier(input, timeline, bezier++, frame, 1, time, time2, value2, nvalue2, scale); + } + time = time2; + value1 = nvalue1; + value2 = nvalue2; + } + return timeline; + } + function setBezier(input, timeline, bezier, frame, value, time1, time2, value1, value2, scale) { + timeline.setBezier(bezier, frame, value, time1, value1, input.readFloat(), input.readFloat() * scale, input.readFloat(), input.readFloat() * scale, time2, value2); + } + var BONE_ROTATE = 0; + var BONE_TRANSLATE = 1; + var BONE_TRANSLATEX = 2; + var BONE_TRANSLATEY = 3; + var BONE_SCALE = 4; + var BONE_SCALEX = 5; + var BONE_SCALEY = 6; + var BONE_SHEAR = 7; + var BONE_SHEARX = 8; + var BONE_SHEARY = 9; + var BONE_INHERIT = 10; + var SLOT_ATTACHMENT = 0; + var SLOT_RGBA = 1; + var SLOT_RGB = 2; + var SLOT_RGBA2 = 3; + var SLOT_RGB2 = 4; + var SLOT_ALPHA = 5; + var ATTACHMENT_DEFORM = 0; + var ATTACHMENT_SEQUENCE = 1; + var PATH_POSITION = 0; + var PATH_SPACING = 1; + var PATH_MIX = 2; + var PHYSICS_INERTIA = 0; + var PHYSICS_STRENGTH = 1; + var PHYSICS_DAMPING = 2; + var PHYSICS_MASS = 4; + var PHYSICS_WIND = 5; + var PHYSICS_GRAVITY = 6; + var PHYSICS_MIX = 7; + var PHYSICS_RESET = 8; + var CURVE_STEPPED = 1; + var CURVE_BEZIER = 2; + + // spine-core/src/SkeletonBounds.ts + var SkeletonBounds = class { + /** The left edge of the axis aligned bounding box. */ + minX = 0; + /** The bottom edge of the axis aligned bounding box. */ + minY = 0; + /** The right edge of the axis aligned bounding box. */ + maxX = 0; + /** The top edge of the axis aligned bounding box. */ + maxY = 0; + /** The visible bounding boxes. */ + boundingBoxes = new Array(); + /** The world vertices for the bounding box polygons. */ + polygons = new Array(); + polygonPool = new Pool(() => { + return Utils.newFloatArray(16); + }); + /** Clears any previous polygons, finds all visible bounding box attachments, and computes the world vertices for each bounding + * box's polygon. + * @param updateAabb If true, the axis aligned bounding box containing all the polygons is computed. If false, the + * SkeletonBounds AABB methods will always return true. */ + update(skeleton, updateAabb) { + if (!skeleton) throw new Error("skeleton cannot be null."); + let boundingBoxes = this.boundingBoxes; + let polygons = this.polygons; + let polygonPool = this.polygonPool; + let slots = skeleton.slots; + let slotCount = slots.length; + boundingBoxes.length = 0; + polygonPool.freeAll(polygons); + polygons.length = 0; + for (let i = 0; i < slotCount; i++) { + let slot = slots[i]; + if (!slot.bone.active) continue; + let attachment = slot.getAttachment(); + if (attachment instanceof BoundingBoxAttachment) { + let boundingBox = attachment; + boundingBoxes.push(boundingBox); + let polygon = polygonPool.obtain(); + if (polygon.length != boundingBox.worldVerticesLength) { + polygon = Utils.newFloatArray(boundingBox.worldVerticesLength); + } + polygons.push(polygon); + boundingBox.computeWorldVertices(slot, 0, boundingBox.worldVerticesLength, polygon, 0, 2); + } + } + if (updateAabb) { + this.aabbCompute(); + } else { + this.minX = Number.POSITIVE_INFINITY; + this.minY = Number.POSITIVE_INFINITY; + this.maxX = Number.NEGATIVE_INFINITY; + this.maxY = Number.NEGATIVE_INFINITY; + } + } + aabbCompute() { + let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + let polygons = this.polygons; + for (let i = 0, n = polygons.length; i < n; i++) { + let polygon = polygons[i]; + let vertices = polygon; + for (let ii = 0, nn = polygon.length; ii < nn; ii += 2) { + let x = vertices[ii]; + let y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + /** Returns true if the axis aligned bounding box contains the point. */ + aabbContainsPoint(x, y) { + return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY; + } + /** Returns true if the axis aligned bounding box intersects the line segment. */ + aabbIntersectsSegment(x1, y1, x2, y2) { + let minX = this.minX; + let minY = this.minY; + let maxX = this.maxX; + let maxY = this.maxY; + if (x1 <= minX && x2 <= minX || y1 <= minY && y2 <= minY || x1 >= maxX && x2 >= maxX || y1 >= maxY && y2 >= maxY) + return false; + let m = (y2 - y1) / (x2 - x1); + let y = m * (minX - x1) + y1; + if (y > minY && y < maxY) return true; + y = m * (maxX - x1) + y1; + if (y > minY && y < maxY) return true; + let x = (minY - y1) / m + x1; + if (x > minX && x < maxX) return true; + x = (maxY - y1) / m + x1; + if (x > minX && x < maxX) return true; + return false; + } + /** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ + aabbIntersectsSkeleton(bounds) { + return this.minX < bounds.maxX && this.maxX > bounds.minX && this.minY < bounds.maxY && this.maxY > bounds.minY; + } + /** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more + * efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */ + containsPoint(x, y) { + let polygons = this.polygons; + for (let i = 0, n = polygons.length; i < n; i++) + if (this.containsPointPolygon(polygons[i], x, y)) return this.boundingBoxes[i]; + return null; + } + /** Returns true if the polygon contains the point. */ + containsPointPolygon(polygon, x, y) { + let vertices = polygon; + let nn = polygon.length; + let prevIndex = nn - 2; + let inside = false; + for (let ii = 0; ii < nn; ii += 2) { + let vertexY = vertices[ii + 1]; + let prevY = vertices[prevIndex + 1]; + if (vertexY < y && prevY >= y || prevY < y && vertexY >= y) { + let vertexX = vertices[ii]; + if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; + } + prevIndex = ii; + } + return inside; + } + /** Returns the first bounding box attachment that contains any part of the line segment, or null. When doing many checks, it + * is usually more efficient to only call this method if {@link #aabbIntersectsSegment()} returns + * true. */ + intersectsSegment(x1, y1, x2, y2) { + let polygons = this.polygons; + for (let i = 0, n = polygons.length; i < n; i++) + if (this.intersectsSegmentPolygon(polygons[i], x1, y1, x2, y2)) return this.boundingBoxes[i]; + return null; + } + /** Returns true if the polygon contains any part of the line segment. */ + intersectsSegmentPolygon(polygon, x1, y1, x2, y2) { + let vertices = polygon; + let nn = polygon.length; + let width12 = x1 - x2, height12 = y1 - y2; + let det1 = x1 * y2 - y1 * x2; + let x3 = vertices[nn - 2], y3 = vertices[nn - 1]; + for (let ii = 0; ii < nn; ii += 2) { + let x4 = vertices[ii], y4 = vertices[ii + 1]; + let det2 = x3 * y4 - y3 * x4; + let width34 = x3 - x4, height34 = y3 - y4; + let det3 = width12 * height34 - height12 * width34; + let x = (det1 * width34 - width12 * det2) / det3; + if ((x >= x3 && x <= x4 || x >= x4 && x <= x3) && (x >= x1 && x <= x2 || x >= x2 && x <= x1)) { + let y = (det1 * height34 - height12 * det2) / det3; + if ((y >= y3 && y <= y4 || y >= y4 && y <= y3) && (y >= y1 && y <= y2 || y >= y2 && y <= y1)) return true; + } + x3 = x4; + y3 = y4; + } + return false; + } + /** Returns the polygon for the specified bounding box, or null. */ + getPolygon(boundingBox) { + if (!boundingBox) throw new Error("boundingBox cannot be null."); + let index = this.boundingBoxes.indexOf(boundingBox); + return index == -1 ? null : this.polygons[index]; + } + /** The width of the axis aligned bounding box. */ + getWidth() { + return this.maxX - this.minX; + } + /** The height of the axis aligned bounding box. */ + getHeight() { + return this.maxY - this.minY; + } + }; + + // spine-core/src/Triangulator.ts + var Triangulator = class _Triangulator { + convexPolygons = new Array(); + convexPolygonsIndices = new Array(); + indicesArray = new Array(); + isConcaveArray = new Array(); + triangles = new Array(); + polygonPool = new Pool(() => { + return new Array(); + }); + polygonIndicesPool = new Pool(() => { + return new Array(); + }); + triangulate(verticesArray) { + let vertices = verticesArray; + let vertexCount = verticesArray.length >> 1; + let indices = this.indicesArray; + indices.length = 0; + for (let i = 0; i < vertexCount; i++) + indices[i] = i; + let isConcave = this.isConcaveArray; + isConcave.length = 0; + for (let i = 0, n = vertexCount; i < n; ++i) + isConcave[i] = _Triangulator.isConcave(i, vertexCount, vertices, indices); + let triangles = this.triangles; + triangles.length = 0; + while (vertexCount > 3) { + let previous = vertexCount - 1, i = 0, next = 1; + while (true) { + outer: + if (!isConcave[i]) { + let p1 = indices[previous] << 1, p2 = indices[i] << 1, p3 = indices[next] << 1; + let p1x = vertices[p1], p1y = vertices[p1 + 1]; + let p2x = vertices[p2], p2y = vertices[p2 + 1]; + let p3x = vertices[p3], p3y = vertices[p3 + 1]; + for (let ii = (next + 1) % vertexCount; ii != previous; ii = (ii + 1) % vertexCount) { + if (!isConcave[ii]) continue; + let v = indices[ii] << 1; + let vx = vertices[v], vy = vertices[v + 1]; + if (_Triangulator.positiveArea(p3x, p3y, p1x, p1y, vx, vy)) { + if (_Triangulator.positiveArea(p1x, p1y, p2x, p2y, vx, vy)) { + if (_Triangulator.positiveArea(p2x, p2y, p3x, p3y, vx, vy)) break outer; + } + } + } + break; + } + if (next == 0) { + do { + if (!isConcave[i]) break; + i--; + } while (i > 0); + break; + } + previous = i; + i = next; + next = (next + 1) % vertexCount; + } + triangles.push(indices[(vertexCount + i - 1) % vertexCount]); + triangles.push(indices[i]); + triangles.push(indices[(i + 1) % vertexCount]); + indices.splice(i, 1); + isConcave.splice(i, 1); + vertexCount--; + let previousIndex = (vertexCount + i - 1) % vertexCount; + let nextIndex = i == vertexCount ? 0 : i; + isConcave[previousIndex] = _Triangulator.isConcave(previousIndex, vertexCount, vertices, indices); + isConcave[nextIndex] = _Triangulator.isConcave(nextIndex, vertexCount, vertices, indices); + } + if (vertexCount == 3) { + triangles.push(indices[2]); + triangles.push(indices[0]); + triangles.push(indices[1]); + } + return triangles; + } + decompose(verticesArray, triangles) { + let vertices = verticesArray; + let convexPolygons = this.convexPolygons; + this.polygonPool.freeAll(convexPolygons); + convexPolygons.length = 0; + let convexPolygonsIndices = this.convexPolygonsIndices; + this.polygonIndicesPool.freeAll(convexPolygonsIndices); + convexPolygonsIndices.length = 0; + let polygonIndices = this.polygonIndicesPool.obtain(); + polygonIndices.length = 0; + let polygon = this.polygonPool.obtain(); + polygon.length = 0; + let fanBaseIndex = -1, lastWinding = 0; + for (let i = 0, n = triangles.length; i < n; i += 3) { + let t1 = triangles[i] << 1, t2 = triangles[i + 1] << 1, t3 = triangles[i + 2] << 1; + let x1 = vertices[t1], y1 = vertices[t1 + 1]; + let x2 = vertices[t2], y2 = vertices[t2 + 1]; + let x3 = vertices[t3], y3 = vertices[t3 + 1]; + let merged = false; + if (fanBaseIndex == t1) { + let o = polygon.length - 4; + let winding1 = _Triangulator.winding(polygon[o], polygon[o + 1], polygon[o + 2], polygon[o + 3], x3, y3); + let winding2 = _Triangulator.winding(x3, y3, polygon[0], polygon[1], polygon[2], polygon[3]); + if (winding1 == lastWinding && winding2 == lastWinding) { + polygon.push(x3); + polygon.push(y3); + polygonIndices.push(t3); + merged = true; + } + } + if (!merged) { + if (polygon.length > 0) { + convexPolygons.push(polygon); + convexPolygonsIndices.push(polygonIndices); + } else { + this.polygonPool.free(polygon); + this.polygonIndicesPool.free(polygonIndices); + } + polygon = this.polygonPool.obtain(); + polygon.length = 0; + polygon.push(x1); + polygon.push(y1); + polygon.push(x2); + polygon.push(y2); + polygon.push(x3); + polygon.push(y3); + polygonIndices = this.polygonIndicesPool.obtain(); + polygonIndices.length = 0; + polygonIndices.push(t1); + polygonIndices.push(t2); + polygonIndices.push(t3); + lastWinding = _Triangulator.winding(x1, y1, x2, y2, x3, y3); + fanBaseIndex = t1; + } + } + if (polygon.length > 0) { + convexPolygons.push(polygon); + convexPolygonsIndices.push(polygonIndices); + } + for (let i = 0, n = convexPolygons.length; i < n; i++) { + polygonIndices = convexPolygonsIndices[i]; + if (polygonIndices.length == 0) continue; + let firstIndex = polygonIndices[0]; + let lastIndex = polygonIndices[polygonIndices.length - 1]; + polygon = convexPolygons[i]; + let o = polygon.length - 4; + let prevPrevX = polygon[o], prevPrevY = polygon[o + 1]; + let prevX = polygon[o + 2], prevY = polygon[o + 3]; + let firstX = polygon[0], firstY = polygon[1]; + let secondX = polygon[2], secondY = polygon[3]; + let winding = _Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, firstX, firstY); + for (let ii = 0; ii < n; ii++) { + if (ii == i) continue; + let otherIndices = convexPolygonsIndices[ii]; + if (otherIndices.length != 3) continue; + let otherFirstIndex = otherIndices[0]; + let otherSecondIndex = otherIndices[1]; + let otherLastIndex = otherIndices[2]; + let otherPoly = convexPolygons[ii]; + let x3 = otherPoly[otherPoly.length - 2], y3 = otherPoly[otherPoly.length - 1]; + if (otherFirstIndex != firstIndex || otherSecondIndex != lastIndex) continue; + let winding1 = _Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, x3, y3); + let winding2 = _Triangulator.winding(x3, y3, firstX, firstY, secondX, secondY); + if (winding1 == winding && winding2 == winding) { + otherPoly.length = 0; + otherIndices.length = 0; + polygon.push(x3); + polygon.push(y3); + polygonIndices.push(otherLastIndex); + prevPrevX = prevX; + prevPrevY = prevY; + prevX = x3; + prevY = y3; + ii = 0; + } + } + } + for (let i = convexPolygons.length - 1; i >= 0; i--) { + polygon = convexPolygons[i]; + if (polygon.length == 0) { + convexPolygons.splice(i, 1); + this.polygonPool.free(polygon); + polygonIndices = convexPolygonsIndices[i]; + convexPolygonsIndices.splice(i, 1); + this.polygonIndicesPool.free(polygonIndices); + } + } + return convexPolygons; + } + static isConcave(index, vertexCount, vertices, indices) { + let previous = indices[(vertexCount + index - 1) % vertexCount] << 1; + let current = indices[index] << 1; + let next = indices[(index + 1) % vertexCount] << 1; + return !this.positiveArea( + vertices[previous], + vertices[previous + 1], + vertices[current], + vertices[current + 1], + vertices[next], + vertices[next + 1] + ); + } + static positiveArea(p1x, p1y, p2x, p2y, p3x, p3y) { + return p1x * (p3y - p2y) + p2x * (p1y - p3y) + p3x * (p2y - p1y) >= 0; + } + static winding(p1x, p1y, p2x, p2y, p3x, p3y) { + let px = p2x - p1x, py = p2y - p1y; + return p3x * py - p3y * px + px * p1y - p1x * py >= 0 ? 1 : -1; + } + }; + + // spine-core/src/SkeletonClipping.ts + var SkeletonClipping = class _SkeletonClipping { + triangulator = new Triangulator(); + clippingPolygon = new Array(); + clipOutput = new Array(); + clippedVertices = new Array(); + clippedUVs = new Array(); + clippedTriangles = new Array(); + scratch = new Array(); + clipAttachment = null; + clippingPolygons = null; + clipStart(slot, clip) { + if (this.clipAttachment) return 0; + this.clipAttachment = clip; + let n = clip.worldVerticesLength; + let vertices = Utils.setArraySize(this.clippingPolygon, n); + clip.computeWorldVertices(slot, 0, n, vertices, 0, 2); + let clippingPolygon = this.clippingPolygon; + _SkeletonClipping.makeClockwise(clippingPolygon); + let clippingPolygons = this.clippingPolygons = this.triangulator.decompose(clippingPolygon, this.triangulator.triangulate(clippingPolygon)); + for (let i = 0, n2 = clippingPolygons.length; i < n2; i++) { + let polygon = clippingPolygons[i]; + _SkeletonClipping.makeClockwise(polygon); + polygon.push(polygon[0]); + polygon.push(polygon[1]); + } + return clippingPolygons.length; + } + clipEndWithSlot(slot) { + if (this.clipAttachment && this.clipAttachment.endSlot == slot.data) this.clipEnd(); + } + clipEnd() { + if (!this.clipAttachment) return; + this.clipAttachment = null; + this.clippingPolygons = null; + this.clippedVertices.length = 0; + this.clippedTriangles.length = 0; + this.clippingPolygon.length = 0; + } + isClipping() { + return this.clipAttachment != null; + } + clipTriangles(vertices, verticesLengthOrTriangles, trianglesOrTrianglesLength, trianglesLengthOrUvs, uvsOrLight, lightOrDark, darkOrTwoColor, twoColorParam) { + let triangles; + let trianglesLength; + let uvs; + let light; + let dark; + let twoColor; + if (typeof verticesLengthOrTriangles === "number") { + triangles = trianglesOrTrianglesLength; + trianglesLength = trianglesLengthOrUvs; + uvs = uvsOrLight; + light = lightOrDark; + dark = darkOrTwoColor; + twoColor = twoColorParam; + } else { + triangles = verticesLengthOrTriangles; + trianglesLength = trianglesOrTrianglesLength; + uvs = trianglesLengthOrUvs; + light = uvsOrLight; + dark = lightOrDark; + twoColor = darkOrTwoColor; + } + if (uvs && light && dark && typeof twoColor === "boolean") + this.clipTrianglesRender(vertices, triangles, trianglesLength, uvs, light, dark, twoColor); + else + this.clipTrianglesNoRender(vertices, triangles, trianglesLength); + } + clipTrianglesNoRender(vertices, triangles, trianglesLength) { + let clipOutput = this.clipOutput, clippedVertices = this.clippedVertices; + let clippedTriangles = this.clippedTriangles; + let polygons = this.clippingPolygons; + let polygonsCount = polygons.length; + let index = 0; + clippedVertices.length = 0; + clippedTriangles.length = 0; + for (let i = 0; i < trianglesLength; i += 3) { + let vertexOffset = triangles[i] << 1; + let x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1]; + vertexOffset = triangles[i + 1] << 1; + let x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1]; + vertexOffset = triangles[i + 2] << 1; + let x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1]; + for (let p = 0; p < polygonsCount; p++) { + let s = clippedVertices.length; + if (this.clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) { + let clipOutputLength = clipOutput.length; + if (clipOutputLength == 0) continue; + let clipOutputCount = clipOutputLength >> 1; + let clipOutputItems = this.clipOutput; + let clippedVerticesItems = Utils.setArraySize(clippedVertices, s + clipOutputCount * 2); + for (let ii = 0; ii < clipOutputLength; ii += 2, s += 2) { + let x = clipOutputItems[ii], y = clipOutputItems[ii + 1]; + clippedVerticesItems[s] = x; + clippedVerticesItems[s + 1] = y; + } + s = clippedTriangles.length; + let clippedTrianglesItems = Utils.setArraySize(clippedTriangles, s + 3 * (clipOutputCount - 2)); + clipOutputCount--; + for (let ii = 1; ii < clipOutputCount; ii++, s += 3) { + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = index + ii; + clippedTrianglesItems[s + 2] = index + ii + 1; + } + index += clipOutputCount + 1; + } else { + let clippedVerticesItems = Utils.setArraySize(clippedVertices, s + 3 * 2); + clippedVerticesItems[s] = x1; + clippedVerticesItems[s + 1] = y1; + clippedVerticesItems[s + 2] = x2; + clippedVerticesItems[s + 3] = y2; + clippedVerticesItems[s + 4] = x3; + clippedVerticesItems[s + 5] = y3; + s = clippedTriangles.length; + let clippedTrianglesItems = Utils.setArraySize(clippedTriangles, s + 3); + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = index + 1; + clippedTrianglesItems[s + 2] = index + 2; + index += 3; + break; + } + } + } + } + clipTrianglesRender(vertices, triangles, trianglesLength, uvs, light, dark, twoColor) { + let clipOutput = this.clipOutput, clippedVertices = this.clippedVertices; + let clippedTriangles = this.clippedTriangles; + let polygons = this.clippingPolygons; + let polygonsCount = polygons.length; + let vertexSize = twoColor ? 12 : 8; + let index = 0; + clippedVertices.length = 0; + clippedTriangles.length = 0; + for (let i = 0; i < trianglesLength; i += 3) { + let vertexOffset = triangles[i] << 1; + let x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1]; + let u1 = uvs[vertexOffset], v1 = uvs[vertexOffset + 1]; + vertexOffset = triangles[i + 1] << 1; + let x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1]; + let u2 = uvs[vertexOffset], v2 = uvs[vertexOffset + 1]; + vertexOffset = triangles[i + 2] << 1; + let x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1]; + let u3 = uvs[vertexOffset], v3 = uvs[vertexOffset + 1]; + for (let p = 0; p < polygonsCount; p++) { + let s = clippedVertices.length; + if (this.clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) { + let clipOutputLength = clipOutput.length; + if (clipOutputLength == 0) continue; + let d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1; + let d = 1 / (d0 * d2 + d1 * (y1 - y3)); + let clipOutputCount = clipOutputLength >> 1; + let clipOutputItems = this.clipOutput; + let clippedVerticesItems = Utils.setArraySize(clippedVertices, s + clipOutputCount * vertexSize); + for (let ii = 0; ii < clipOutputLength; ii += 2, s += vertexSize) { + let x = clipOutputItems[ii], y = clipOutputItems[ii + 1]; + clippedVerticesItems[s] = x; + clippedVerticesItems[s + 1] = y; + clippedVerticesItems[s + 2] = light.r; + clippedVerticesItems[s + 3] = light.g; + clippedVerticesItems[s + 4] = light.b; + clippedVerticesItems[s + 5] = light.a; + let c0 = x - x3, c1 = y - y3; + let a = (d0 * c0 + d1 * c1) * d; + let b = (d4 * c0 + d2 * c1) * d; + let c = 1 - a - b; + clippedVerticesItems[s + 6] = u1 * a + u2 * b + u3 * c; + clippedVerticesItems[s + 7] = v1 * a + v2 * b + v3 * c; + if (twoColor) { + clippedVerticesItems[s + 8] = dark.r; + clippedVerticesItems[s + 9] = dark.g; + clippedVerticesItems[s + 10] = dark.b; + clippedVerticesItems[s + 11] = dark.a; + } + } + s = clippedTriangles.length; + let clippedTrianglesItems = Utils.setArraySize(clippedTriangles, s + 3 * (clipOutputCount - 2)); + clipOutputCount--; + for (let ii = 1; ii < clipOutputCount; ii++, s += 3) { + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = index + ii; + clippedTrianglesItems[s + 2] = index + ii + 1; + } + index += clipOutputCount + 1; + } else { + let clippedVerticesItems = Utils.setArraySize(clippedVertices, s + 3 * vertexSize); + clippedVerticesItems[s] = x1; + clippedVerticesItems[s + 1] = y1; + clippedVerticesItems[s + 2] = light.r; + clippedVerticesItems[s + 3] = light.g; + clippedVerticesItems[s + 4] = light.b; + clippedVerticesItems[s + 5] = light.a; + if (!twoColor) { + clippedVerticesItems[s + 6] = u1; + clippedVerticesItems[s + 7] = v1; + clippedVerticesItems[s + 8] = x2; + clippedVerticesItems[s + 9] = y2; + clippedVerticesItems[s + 10] = light.r; + clippedVerticesItems[s + 11] = light.g; + clippedVerticesItems[s + 12] = light.b; + clippedVerticesItems[s + 13] = light.a; + clippedVerticesItems[s + 14] = u2; + clippedVerticesItems[s + 15] = v2; + clippedVerticesItems[s + 16] = x3; + clippedVerticesItems[s + 17] = y3; + clippedVerticesItems[s + 18] = light.r; + clippedVerticesItems[s + 19] = light.g; + clippedVerticesItems[s + 20] = light.b; + clippedVerticesItems[s + 21] = light.a; + clippedVerticesItems[s + 22] = u3; + clippedVerticesItems[s + 23] = v3; + } else { + clippedVerticesItems[s + 6] = u1; + clippedVerticesItems[s + 7] = v1; + clippedVerticesItems[s + 8] = dark.r; + clippedVerticesItems[s + 9] = dark.g; + clippedVerticesItems[s + 10] = dark.b; + clippedVerticesItems[s + 11] = dark.a; + clippedVerticesItems[s + 12] = x2; + clippedVerticesItems[s + 13] = y2; + clippedVerticesItems[s + 14] = light.r; + clippedVerticesItems[s + 15] = light.g; + clippedVerticesItems[s + 16] = light.b; + clippedVerticesItems[s + 17] = light.a; + clippedVerticesItems[s + 18] = u2; + clippedVerticesItems[s + 19] = v2; + clippedVerticesItems[s + 20] = dark.r; + clippedVerticesItems[s + 21] = dark.g; + clippedVerticesItems[s + 22] = dark.b; + clippedVerticesItems[s + 23] = dark.a; + clippedVerticesItems[s + 24] = x3; + clippedVerticesItems[s + 25] = y3; + clippedVerticesItems[s + 26] = light.r; + clippedVerticesItems[s + 27] = light.g; + clippedVerticesItems[s + 28] = light.b; + clippedVerticesItems[s + 29] = light.a; + clippedVerticesItems[s + 30] = u3; + clippedVerticesItems[s + 31] = v3; + clippedVerticesItems[s + 32] = dark.r; + clippedVerticesItems[s + 33] = dark.g; + clippedVerticesItems[s + 34] = dark.b; + clippedVerticesItems[s + 35] = dark.a; + } + s = clippedTriangles.length; + let clippedTrianglesItems = Utils.setArraySize(clippedTriangles, s + 3); + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = index + 1; + clippedTrianglesItems[s + 2] = index + 2; + index += 3; + break; + } + } + } + } + clipTrianglesUnpacked(vertices, triangles, trianglesLength, uvs) { + let clipOutput = this.clipOutput, clippedVertices = this.clippedVertices, clippedUVs = this.clippedUVs; + let clippedTriangles = this.clippedTriangles; + let polygons = this.clippingPolygons; + let polygonsCount = polygons.length; + let index = 0; + clippedVertices.length = 0; + clippedUVs.length = 0; + clippedTriangles.length = 0; + for (let i = 0; i < trianglesLength; i += 3) { + let vertexOffset = triangles[i] << 1; + let x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1]; + let u1 = uvs[vertexOffset], v1 = uvs[vertexOffset + 1]; + vertexOffset = triangles[i + 1] << 1; + let x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1]; + let u2 = uvs[vertexOffset], v2 = uvs[vertexOffset + 1]; + vertexOffset = triangles[i + 2] << 1; + let x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1]; + let u3 = uvs[vertexOffset], v3 = uvs[vertexOffset + 1]; + for (let p = 0; p < polygonsCount; p++) { + let s = clippedVertices.length; + if (this.clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) { + let clipOutputLength = clipOutput.length; + if (clipOutputLength == 0) continue; + let d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1; + let d = 1 / (d0 * d2 + d1 * (y1 - y3)); + let clipOutputCount = clipOutputLength >> 1; + let clipOutputItems = this.clipOutput; + let clippedVerticesItems = Utils.setArraySize(clippedVertices, s + clipOutputCount * 2); + let clippedUVsItems = Utils.setArraySize(clippedUVs, s + clipOutputCount * 2); + for (let ii = 0; ii < clipOutputLength; ii += 2, s += 2) { + let x = clipOutputItems[ii], y = clipOutputItems[ii + 1]; + clippedVerticesItems[s] = x; + clippedVerticesItems[s + 1] = y; + let c0 = x - x3, c1 = y - y3; + let a = (d0 * c0 + d1 * c1) * d; + let b = (d4 * c0 + d2 * c1) * d; + let c = 1 - a - b; + clippedUVsItems[s] = u1 * a + u2 * b + u3 * c; + clippedUVsItems[s + 1] = v1 * a + v2 * b + v3 * c; + } + s = clippedTriangles.length; + let clippedTrianglesItems = Utils.setArraySize(clippedTriangles, s + 3 * (clipOutputCount - 2)); + clipOutputCount--; + for (let ii = 1; ii < clipOutputCount; ii++, s += 3) { + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = index + ii; + clippedTrianglesItems[s + 2] = index + ii + 1; + } + index += clipOutputCount + 1; + } else { + let clippedVerticesItems = Utils.setArraySize(clippedVertices, s + 3 * 2); + clippedVerticesItems[s] = x1; + clippedVerticesItems[s + 1] = y1; + clippedVerticesItems[s + 2] = x2; + clippedVerticesItems[s + 3] = y2; + clippedVerticesItems[s + 4] = x3; + clippedVerticesItems[s + 5] = y3; + let clippedUVSItems = Utils.setArraySize(clippedUVs, s + 3 * 2); + clippedUVSItems[s] = u1; + clippedUVSItems[s + 1] = v1; + clippedUVSItems[s + 2] = u2; + clippedUVSItems[s + 3] = v2; + clippedUVSItems[s + 4] = u3; + clippedUVSItems[s + 5] = v3; + s = clippedTriangles.length; + let clippedTrianglesItems = Utils.setArraySize(clippedTriangles, s + 3); + clippedTrianglesItems[s] = index; + clippedTrianglesItems[s + 1] = index + 1; + clippedTrianglesItems[s + 2] = index + 2; + index += 3; + break; + } + } + } + } + /** Clips the input triangle against the convex, clockwise clipping area. If the triangle lies entirely within the clipping + * area, false is returned. The clipping area must duplicate the first vertex at the end of the vertices list. */ + clip(x1, y1, x2, y2, x3, y3, clippingArea, output) { + let originalOutput = output; + let clipped = false; + let input; + if (clippingArea.length % 4 >= 2) { + input = output; + output = this.scratch; + } else + input = this.scratch; + input.length = 0; + input.push(x1); + input.push(y1); + input.push(x2); + input.push(y2); + input.push(x3); + input.push(y3); + input.push(x1); + input.push(y1); + output.length = 0; + let clippingVerticesLast = clippingArea.length - 4; + let clippingVertices = clippingArea; + for (let i = 0; ; i += 2) { + let edgeX = clippingVertices[i], edgeY = clippingVertices[i + 1]; + let ex = edgeX - clippingVertices[i + 2], ey = edgeY - clippingVertices[i + 3]; + let outputStart = output.length; + let inputVertices = input; + for (let ii = 0, nn = input.length - 2; ii < nn; ) { + let inputX = inputVertices[ii], inputY = inputVertices[ii + 1]; + ii += 2; + let inputX2 = inputVertices[ii], inputY2 = inputVertices[ii + 1]; + let s2 = ey * (edgeX - inputX2) > ex * (edgeY - inputY2); + let s1 = ey * (edgeX - inputX) - ex * (edgeY - inputY); + if (s1 > 0) { + if (s2) { + output.push(inputX2); + output.push(inputY2); + continue; + } + let ix = inputX2 - inputX, iy = inputY2 - inputY, t = s1 / (ix * ey - iy * ex); + if (t >= 0 && t <= 1) { + output.push(inputX + ix * t); + output.push(inputY + iy * t); + } else { + output.push(inputX2); + output.push(inputY2); + continue; + } + } else if (s2) { + let ix = inputX2 - inputX, iy = inputY2 - inputY, t = s1 / (ix * ey - iy * ex); + if (t >= 0 && t <= 1) { + output.push(inputX + ix * t); + output.push(inputY + iy * t); + output.push(inputX2); + output.push(inputY2); + } else { + output.push(inputX2); + output.push(inputY2); + continue; + } + } + clipped = true; + } + if (outputStart == output.length) { + originalOutput.length = 0; + return true; + } + output.push(output[0]); + output.push(output[1]); + if (i == clippingVerticesLast) break; + let temp = output; + output = input; + output.length = 0; + input = temp; + } + if (originalOutput != output) { + originalOutput.length = 0; + for (let i = 0, n = output.length - 2; i < n; i++) + originalOutput[i] = output[i]; + } else + originalOutput.length = originalOutput.length - 2; + return clipped; + } + static makeClockwise(polygon) { + let vertices = polygon; + let verticeslength = polygon.length; + let area = vertices[verticeslength - 2] * vertices[1] - vertices[0] * vertices[verticeslength - 1], p1x = 0, p1y = 0, p2x = 0, p2y = 0; + for (let i = 0, n = verticeslength - 3; i < n; i += 2) { + p1x = vertices[i]; + p1y = vertices[i + 1]; + p2x = vertices[i + 2]; + p2y = vertices[i + 3]; + area += p1x * p2y - p2x * p1y; + } + if (area < 0) return; + for (let i = 0, lastX = verticeslength - 2, n = verticeslength >> 1; i < n; i += 2) { + let x = vertices[i], y = vertices[i + 1]; + let other = lastX - i; + vertices[i] = vertices[other]; + vertices[i + 1] = vertices[other + 1]; + vertices[other] = x; + vertices[other + 1] = y; + } + } + }; + + // spine-core/src/SkeletonJson.ts + var SkeletonJson = class { + attachmentLoader; + /** Scales bone positions, image sizes, and translations as they are loaded. This allows different size images to be used at + * runtime than were used in Spine. + * + * See [Scaling](http://esotericsoftware.com/spine-loading-skeleton-data#Scaling) in the Spine Runtimes Guide. */ + scale = 1; + linkedMeshes = new Array(); + constructor(attachmentLoader) { + this.attachmentLoader = attachmentLoader; + } + readSkeletonData(json) { + let scale = this.scale; + let skeletonData = new SkeletonData(); + let root = typeof json === "string" ? JSON.parse(json) : json; + let skeletonMap = root.skeleton; + if (skeletonMap) { + skeletonData.hash = skeletonMap.hash; + skeletonData.version = skeletonMap.spine; + skeletonData.x = skeletonMap.x; + skeletonData.y = skeletonMap.y; + skeletonData.width = skeletonMap.width; + skeletonData.height = skeletonMap.height; + skeletonData.referenceScale = getValue(skeletonMap, "referenceScale", 100) * scale; + skeletonData.fps = skeletonMap.fps; + skeletonData.imagesPath = skeletonMap.images ?? null; + skeletonData.audioPath = skeletonMap.audio ?? null; + } + if (root.bones) { + for (let i = 0; i < root.bones.length; i++) { + let boneMap = root.bones[i]; + let parent = null; + let parentName = getValue(boneMap, "parent", null); + if (parentName) parent = skeletonData.findBone(parentName); + let data = new BoneData(skeletonData.bones.length, boneMap.name, parent); + data.length = getValue(boneMap, "length", 0) * scale; + data.x = getValue(boneMap, "x", 0) * scale; + data.y = getValue(boneMap, "y", 0) * scale; + data.rotation = getValue(boneMap, "rotation", 0); + data.scaleX = getValue(boneMap, "scaleX", 1); + data.scaleY = getValue(boneMap, "scaleY", 1); + data.shearX = getValue(boneMap, "shearX", 0); + data.shearY = getValue(boneMap, "shearY", 0); + data.inherit = Utils.enumValue(Inherit, getValue(boneMap, "inherit", "Normal")); + data.skinRequired = getValue(boneMap, "skin", false); + let color = getValue(boneMap, "color", null); + if (color) data.color.setFromString(color); + skeletonData.bones.push(data); + } + } + if (root.slots) { + for (let i = 0; i < root.slots.length; i++) { + let slotMap = root.slots[i]; + let slotName = slotMap.name; + let boneData = skeletonData.findBone(slotMap.bone); + if (!boneData) throw new Error(`Couldn't find bone ${slotMap.bone} for slot ${slotName}`); + let data = new SlotData(skeletonData.slots.length, slotName, boneData); + let color = getValue(slotMap, "color", null); + if (color) data.color.setFromString(color); + let dark = getValue(slotMap, "dark", null); + if (dark) data.darkColor = Color.fromString(dark); + data.attachmentName = getValue(slotMap, "attachment", null); + data.blendMode = Utils.enumValue(BlendMode, getValue(slotMap, "blend", "normal")); + data.visible = getValue(slotMap, "visible", true); + skeletonData.slots.push(data); + } + } + if (root.ik) { + for (let i = 0; i < root.ik.length; i++) { + let constraintMap = root.ik[i]; + let data = new IkConstraintData(constraintMap.name); + data.order = getValue(constraintMap, "order", 0); + data.skinRequired = getValue(constraintMap, "skin", false); + for (let ii = 0; ii < constraintMap.bones.length; ii++) { + let bone = skeletonData.findBone(constraintMap.bones[ii]); + if (!bone) throw new Error(`Couldn't find bone ${constraintMap.bones[ii]} for IK constraint ${constraintMap.name}.`); + data.bones.push(bone); + } + let target = skeletonData.findBone(constraintMap.target); + ; + if (!target) throw new Error(`Couldn't find target bone ${constraintMap.target} for IK constraint ${constraintMap.name}.`); + data.target = target; + data.mix = getValue(constraintMap, "mix", 1); + data.softness = getValue(constraintMap, "softness", 0) * scale; + data.bendDirection = getValue(constraintMap, "bendPositive", true) ? 1 : -1; + data.compress = getValue(constraintMap, "compress", false); + data.stretch = getValue(constraintMap, "stretch", false); + data.uniform = getValue(constraintMap, "uniform", false); + skeletonData.ikConstraints.push(data); + } + } + if (root.transform) { + for (let i = 0; i < root.transform.length; i++) { + let constraintMap = root.transform[i]; + let data = new TransformConstraintData(constraintMap.name); + data.order = getValue(constraintMap, "order", 0); + data.skinRequired = getValue(constraintMap, "skin", false); + for (let ii = 0; ii < constraintMap.bones.length; ii++) { + let boneName = constraintMap.bones[ii]; + let bone = skeletonData.findBone(boneName); + if (!bone) throw new Error(`Couldn't find bone ${boneName} for transform constraint ${constraintMap.name}.`); + data.bones.push(bone); + } + let targetName = constraintMap.target; + let target = skeletonData.findBone(targetName); + if (!target) throw new Error(`Couldn't find target bone ${targetName} for transform constraint ${constraintMap.name}.`); + data.target = target; + data.local = getValue(constraintMap, "local", false); + data.relative = getValue(constraintMap, "relative", false); + data.offsetRotation = getValue(constraintMap, "rotation", 0); + data.offsetX = getValue(constraintMap, "x", 0) * scale; + data.offsetY = getValue(constraintMap, "y", 0) * scale; + data.offsetScaleX = getValue(constraintMap, "scaleX", 0); + data.offsetScaleY = getValue(constraintMap, "scaleY", 0); + data.offsetShearY = getValue(constraintMap, "shearY", 0); + data.mixRotate = getValue(constraintMap, "mixRotate", 1); + data.mixX = getValue(constraintMap, "mixX", 1); + data.mixY = getValue(constraintMap, "mixY", data.mixX); + data.mixScaleX = getValue(constraintMap, "mixScaleX", 1); + data.mixScaleY = getValue(constraintMap, "mixScaleY", data.mixScaleX); + data.mixShearY = getValue(constraintMap, "mixShearY", 1); + skeletonData.transformConstraints.push(data); + } + } + if (root.path) { + for (let i = 0; i < root.path.length; i++) { + let constraintMap = root.path[i]; + let data = new PathConstraintData(constraintMap.name); + data.order = getValue(constraintMap, "order", 0); + data.skinRequired = getValue(constraintMap, "skin", false); + for (let ii = 0; ii < constraintMap.bones.length; ii++) { + let boneName = constraintMap.bones[ii]; + let bone = skeletonData.findBone(boneName); + if (!bone) throw new Error(`Couldn't find bone ${boneName} for path constraint ${constraintMap.name}.`); + data.bones.push(bone); + } + let targetName = constraintMap.target; + let target = skeletonData.findSlot(targetName); + if (!target) throw new Error(`Couldn't find target slot ${targetName} for path constraint ${constraintMap.name}.`); + data.target = target; + data.positionMode = Utils.enumValue(PositionMode, getValue(constraintMap, "positionMode", "Percent")); + data.spacingMode = Utils.enumValue(SpacingMode, getValue(constraintMap, "spacingMode", "Length")); + data.rotateMode = Utils.enumValue(RotateMode, getValue(constraintMap, "rotateMode", "Tangent")); + data.offsetRotation = getValue(constraintMap, "rotation", 0); + data.position = getValue(constraintMap, "position", 0); + if (data.positionMode == 0 /* Fixed */) data.position *= scale; + data.spacing = getValue(constraintMap, "spacing", 0); + if (data.spacingMode == 0 /* Length */ || data.spacingMode == 1 /* Fixed */) data.spacing *= scale; + data.mixRotate = getValue(constraintMap, "mixRotate", 1); + data.mixX = getValue(constraintMap, "mixX", 1); + data.mixY = getValue(constraintMap, "mixY", data.mixX); + skeletonData.pathConstraints.push(data); + } + } + if (root.physics) { + for (let i = 0; i < root.physics.length; i++) { + const constraintMap = root.physics[i]; + const data = new PhysicsConstraintData(constraintMap.name); + data.order = getValue(constraintMap, "order", 0); + data.skinRequired = getValue(constraintMap, "skin", false); + const boneName = constraintMap.bone; + const bone = skeletonData.findBone(boneName); + if (bone == null) throw new Error("Physics bone not found: " + boneName); + data.bone = bone; + data.x = getValue(constraintMap, "x", 0); + data.y = getValue(constraintMap, "y", 0); + data.rotate = getValue(constraintMap, "rotate", 0); + data.scaleX = getValue(constraintMap, "scaleX", 0); + data.shearX = getValue(constraintMap, "shearX", 0); + data.limit = getValue(constraintMap, "limit", 5e3) * scale; + data.step = 1 / getValue(constraintMap, "fps", 60); + data.inertia = getValue(constraintMap, "inertia", 1); + data.strength = getValue(constraintMap, "strength", 100); + data.damping = getValue(constraintMap, "damping", 1); + data.massInverse = 1 / getValue(constraintMap, "mass", 1); + data.wind = getValue(constraintMap, "wind", 0); + data.gravity = getValue(constraintMap, "gravity", 0); + data.mix = getValue(constraintMap, "mix", 1); + data.inertiaGlobal = getValue(constraintMap, "inertiaGlobal", false); + data.strengthGlobal = getValue(constraintMap, "strengthGlobal", false); + data.dampingGlobal = getValue(constraintMap, "dampingGlobal", false); + data.massGlobal = getValue(constraintMap, "massGlobal", false); + data.windGlobal = getValue(constraintMap, "windGlobal", false); + data.gravityGlobal = getValue(constraintMap, "gravityGlobal", false); + data.mixGlobal = getValue(constraintMap, "mixGlobal", false); + skeletonData.physicsConstraints.push(data); + } + } + if (root.skins) { + for (let i = 0; i < root.skins.length; i++) { + let skinMap = root.skins[i]; + let skin = new Skin(skinMap.name); + if (skinMap.bones) { + for (let ii = 0; ii < skinMap.bones.length; ii++) { + let boneName = skinMap.bones[ii]; + let bone = skeletonData.findBone(boneName); + if (!bone) throw new Error(`Couldn't find bone ${boneName} for skin ${skinMap.name}.`); + skin.bones.push(bone); + } + } + if (skinMap.ik) { + for (let ii = 0; ii < skinMap.ik.length; ii++) { + let constraintName = skinMap.ik[ii]; + let constraint = skeletonData.findIkConstraint(constraintName); + if (!constraint) throw new Error(`Couldn't find IK constraint ${constraintName} for skin ${skinMap.name}.`); + skin.constraints.push(constraint); + } + } + if (skinMap.transform) { + for (let ii = 0; ii < skinMap.transform.length; ii++) { + let constraintName = skinMap.transform[ii]; + let constraint = skeletonData.findTransformConstraint(constraintName); + if (!constraint) throw new Error(`Couldn't find transform constraint ${constraintName} for skin ${skinMap.name}.`); + skin.constraints.push(constraint); + } + } + if (skinMap.path) { + for (let ii = 0; ii < skinMap.path.length; ii++) { + let constraintName = skinMap.path[ii]; + let constraint = skeletonData.findPathConstraint(constraintName); + if (!constraint) throw new Error(`Couldn't find path constraint ${constraintName} for skin ${skinMap.name}.`); + skin.constraints.push(constraint); + } + } + if (skinMap.physics) { + for (let ii = 0; ii < skinMap.physics.length; ii++) { + let constraintName = skinMap.physics[ii]; + let constraint = skeletonData.findPhysicsConstraint(constraintName); + if (!constraint) throw new Error(`Couldn't find physics constraint ${constraintName} for skin ${skinMap.name}.`); + skin.constraints.push(constraint); + } + } + for (let slotName in skinMap.attachments) { + let slot = skeletonData.findSlot(slotName); + if (!slot) throw new Error(`Couldn't find slot ${slotName} for skin ${skinMap.name}.`); + let slotMap = skinMap.attachments[slotName]; + for (let entryName in slotMap) { + let attachment = this.readAttachment(slotMap[entryName], skin, slot.index, entryName, skeletonData); + if (attachment) skin.setAttachment(slot.index, entryName, attachment); + } + } + skeletonData.skins.push(skin); + if (skin.name == "default") skeletonData.defaultSkin = skin; + } + } + for (let i = 0, n = this.linkedMeshes.length; i < n; i++) { + let linkedMesh = this.linkedMeshes[i]; + let skin = !linkedMesh.skin ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin); + if (!skin) throw new Error(`Skin not found: ${linkedMesh.skin}`); + let parent = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent); + if (!parent) throw new Error(`Parent mesh not found: ${linkedMesh.parent}`); + linkedMesh.mesh.timelineAttachment = linkedMesh.inheritTimeline ? parent : linkedMesh.mesh; + linkedMesh.mesh.setParentMesh(parent); + if (linkedMesh.mesh.region != null) linkedMesh.mesh.updateRegion(); + } + this.linkedMeshes.length = 0; + if (root.events) { + for (let eventName in root.events) { + let eventMap = root.events[eventName]; + let data = new EventData(eventName); + data.intValue = getValue(eventMap, "int", 0); + data.floatValue = getValue(eventMap, "float", 0); + data.stringValue = getValue(eventMap, "string", ""); + data.audioPath = getValue(eventMap, "audio", null); + if (data.audioPath) { + data.volume = getValue(eventMap, "volume", 1); + data.balance = getValue(eventMap, "balance", 0); + } + skeletonData.events.push(data); + } + } + if (root.animations) { + for (let animationName in root.animations) { + let animationMap = root.animations[animationName]; + this.readAnimation(animationMap, animationName, skeletonData); + } + } + return skeletonData; + } + readAttachment(map, skin, slotIndex, name, skeletonData) { + let scale = this.scale; + name = getValue(map, "name", name); + switch (getValue(map, "type", "region")) { + case "region": { + let path = getValue(map, "path", name); + let sequence = this.readSequence(getValue(map, "sequence", null)); + let region = this.attachmentLoader.newRegionAttachment(skin, name, path, sequence); + if (!region) return null; + region.path = path; + region.x = getValue(map, "x", 0) * scale; + region.y = getValue(map, "y", 0) * scale; + region.scaleX = getValue(map, "scaleX", 1); + region.scaleY = getValue(map, "scaleY", 1); + region.rotation = getValue(map, "rotation", 0); + region.width = map.width * scale; + region.height = map.height * scale; + region.sequence = sequence; + let color = getValue(map, "color", null); + if (color) region.color.setFromString(color); + if (region.region != null) region.updateRegion(); + return region; + } + case "boundingbox": { + let box = this.attachmentLoader.newBoundingBoxAttachment(skin, name); + if (!box) return null; + this.readVertices(map, box, map.vertexCount << 1); + let color = getValue(map, "color", null); + if (color) box.color.setFromString(color); + return box; + } + case "mesh": + case "linkedmesh": { + let path = getValue(map, "path", name); + let sequence = this.readSequence(getValue(map, "sequence", null)); + let mesh = this.attachmentLoader.newMeshAttachment(skin, name, path, sequence); + if (!mesh) return null; + mesh.path = path; + let color = getValue(map, "color", null); + if (color) mesh.color.setFromString(color); + mesh.width = getValue(map, "width", 0) * scale; + mesh.height = getValue(map, "height", 0) * scale; + mesh.sequence = sequence; + let parent = getValue(map, "parent", null); + if (parent) { + this.linkedMeshes.push(new LinkedMesh2(mesh, getValue(map, "skin", null), slotIndex, parent, getValue(map, "timelines", true))); + return mesh; + } + let uvs = map.uvs; + this.readVertices(map, mesh, uvs.length); + mesh.triangles = map.triangles; + mesh.regionUVs = uvs; + if (mesh.region != null) mesh.updateRegion(); + mesh.edges = getValue(map, "edges", null); + mesh.hullLength = getValue(map, "hull", 0) * 2; + return mesh; + } + case "path": { + let path = this.attachmentLoader.newPathAttachment(skin, name); + if (!path) return null; + path.closed = getValue(map, "closed", false); + path.constantSpeed = getValue(map, "constantSpeed", true); + let vertexCount = map.vertexCount; + this.readVertices(map, path, vertexCount << 1); + let lengths = Utils.newArray(vertexCount / 3, 0); + for (let i = 0; i < map.lengths.length; i++) + lengths[i] = map.lengths[i] * scale; + path.lengths = lengths; + let color = getValue(map, "color", null); + if (color) path.color.setFromString(color); + return path; + } + case "point": { + let point = this.attachmentLoader.newPointAttachment(skin, name); + if (!point) return null; + point.x = getValue(map, "x", 0) * scale; + point.y = getValue(map, "y", 0) * scale; + point.rotation = getValue(map, "rotation", 0); + let color = getValue(map, "color", null); + if (color) point.color.setFromString(color); + return point; + } + case "clipping": { + let clip = this.attachmentLoader.newClippingAttachment(skin, name); + if (!clip) return null; + let end = getValue(map, "end", null); + if (end) clip.endSlot = skeletonData.findSlot(end); + let vertexCount = map.vertexCount; + this.readVertices(map, clip, vertexCount << 1); + let color = getValue(map, "color", null); + if (color) clip.color.setFromString(color); + return clip; + } + } + return null; + } + readSequence(map) { + if (map == null) return null; + let sequence = new Sequence(getValue(map, "count", 0)); + sequence.start = getValue(map, "start", 1); + sequence.digits = getValue(map, "digits", 0); + sequence.setupIndex = getValue(map, "setup", 0); + return sequence; + } + readVertices(map, attachment, verticesLength) { + let scale = this.scale; + attachment.worldVerticesLength = verticesLength; + let vertices = map.vertices; + if (verticesLength == vertices.length) { + let scaledVertices = Utils.toFloatArray(vertices); + if (scale != 1) { + for (let i = 0, n = vertices.length; i < n; i++) + scaledVertices[i] *= scale; + } + attachment.vertices = scaledVertices; + return; + } + let weights = new Array(); + let bones = new Array(); + for (let i = 0, n = vertices.length; i < n; ) { + let boneCount = vertices[i++]; + bones.push(boneCount); + for (let nn = i + boneCount * 4; i < nn; i += 4) { + bones.push(vertices[i]); + weights.push(vertices[i + 1] * scale); + weights.push(vertices[i + 2] * scale); + weights.push(vertices[i + 3]); + } + } + attachment.bones = bones; + attachment.vertices = Utils.toFloatArray(weights); + } + readAnimation(map, name, skeletonData) { + let scale = this.scale; + let timelines = new Array(); + if (map.slots) { + for (let slotName in map.slots) { + let slotMap = map.slots[slotName]; + let slot = skeletonData.findSlot(slotName); + if (!slot) throw new Error("Slot not found: " + slotName); + let slotIndex = slot.index; + for (let timelineName in slotMap) { + let timelineMap = slotMap[timelineName]; + if (!timelineMap) continue; + let frames = timelineMap.length; + if (timelineName == "attachment") { + let timeline = new AttachmentTimeline(frames, slotIndex); + for (let frame = 0; frame < frames; frame++) { + let keyMap = timelineMap[frame]; + timeline.setFrame(frame, getValue(keyMap, "time", 0), getValue(keyMap, "name", null)); + } + timelines.push(timeline); + } else if (timelineName == "rgba") { + let timeline = new RGBATimeline(frames, frames << 2, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color = Color.fromString(keyMap.color); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color.r, color.g, color.b, color.a); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let newColor = Color.fromString(nextMap.color); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, color.a, newColor.a, 1); + } + time = time2; + color = newColor; + keyMap = nextMap; + } + timelines.push(timeline); + } else if (timelineName == "rgb") { + let timeline = new RGBTimeline(frames, frames * 3, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color = Color.fromString(keyMap.color); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color.r, color.g, color.b); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let newColor = Color.fromString(nextMap.color); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1); + } + time = time2; + color = newColor; + keyMap = nextMap; + } + timelines.push(timeline); + } else if (timelineName == "alpha") { + timelines.push(readTimeline12(timelineMap, new AlphaTimeline(frames, frames, slotIndex), 0, 1)); + } else if (timelineName == "rgba2") { + let timeline = new RGBA2Timeline(frames, frames * 7, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color = Color.fromString(keyMap.light); + let color2 = Color.fromString(keyMap.dark); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color.r, color.g, color.b, color.a, color2.r, color2.g, color2.b); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let newColor = Color.fromString(nextMap.light); + let newColor2 = Color.fromString(nextMap.dark); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, color.a, newColor.a, 1); + bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, color2.r, newColor2.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, color2.g, newColor2.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 6, time, time2, color2.b, newColor2.b, 1); + } + time = time2; + color = newColor; + color2 = newColor2; + keyMap = nextMap; + } + timelines.push(timeline); + } else if (timelineName == "rgb2") { + let timeline = new RGB2Timeline(frames, frames * 6, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color = Color.fromString(keyMap.light); + let color2 = Color.fromString(keyMap.dark); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color.r, color.g, color.b, color2.r, color2.g, color2.b); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let newColor = Color.fromString(nextMap.light); + let newColor2 = Color.fromString(nextMap.dark); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color.b, newColor.b, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, color2.r, newColor2.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, color2.g, newColor2.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, color2.b, newColor2.b, 1); + } + time = time2; + color = newColor; + color2 = newColor2; + keyMap = nextMap; + } + timelines.push(timeline); + } + } + } + } + if (map.bones) { + for (let boneName in map.bones) { + let boneMap = map.bones[boneName]; + let bone = skeletonData.findBone(boneName); + if (!bone) throw new Error("Bone not found: " + boneName); + let boneIndex = bone.index; + for (let timelineName in boneMap) { + let timelineMap = boneMap[timelineName]; + let frames = timelineMap.length; + if (frames == 0) continue; + if (timelineName === "rotate") { + timelines.push(readTimeline12(timelineMap, new RotateTimeline(frames, frames, boneIndex), 0, 1)); + } else if (timelineName === "translate") { + let timeline = new TranslateTimeline(frames, frames << 1, boneIndex); + timelines.push(readTimeline22(timelineMap, timeline, "x", "y", 0, scale)); + } else if (timelineName === "translatex") { + let timeline = new TranslateXTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, scale)); + } else if (timelineName === "translatey") { + let timeline = new TranslateYTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, scale)); + } else if (timelineName === "scale") { + let timeline = new ScaleTimeline(frames, frames << 1, boneIndex); + timelines.push(readTimeline22(timelineMap, timeline, "x", "y", 1, 1)); + } else if (timelineName === "scalex") { + let timeline = new ScaleXTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 1, 1)); + } else if (timelineName === "scaley") { + let timeline = new ScaleYTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 1, 1)); + } else if (timelineName === "shear") { + let timeline = new ShearTimeline(frames, frames << 1, boneIndex); + timelines.push(readTimeline22(timelineMap, timeline, "x", "y", 0, 1)); + } else if (timelineName === "shearx") { + let timeline = new ShearXTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, 1)); + } else if (timelineName === "sheary") { + let timeline = new ShearYTimeline(frames, frames, boneIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, 1)); + } else if (timelineName === "inherit") { + let timeline = new InheritTimeline(frames, bone.index); + for (let frame = 0; frame < timelineMap.length; frame++) { + let aFrame = timelineMap[frame]; + timeline.setFrame(frame, getValue(aFrame, "time", 0), Utils.enumValue(Inherit, getValue(aFrame, "inherit", "Normal"))); + } + timelines.push(timeline); + } + } + } + } + if (map.ik) { + for (let constraintName in map.ik) { + let constraintMap = map.ik[constraintName]; + let keyMap = constraintMap[0]; + if (!keyMap) continue; + let constraint = skeletonData.findIkConstraint(constraintName); + if (!constraint) throw new Error("IK Constraint not found: " + constraintName); + let constraintIndex = skeletonData.ikConstraints.indexOf(constraint); + let timeline = new IkConstraintTimeline(constraintMap.length, constraintMap.length << 1, constraintIndex); + let time = getValue(keyMap, "time", 0); + let mix = getValue(keyMap, "mix", 1); + let softness = getValue(keyMap, "softness", 0) * scale; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mix, softness, getValue(keyMap, "bendPositive", true) ? 1 : -1, getValue(keyMap, "compress", false), getValue(keyMap, "stretch", false)); + let nextMap = constraintMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let mix2 = getValue(nextMap, "mix", 1); + let softness2 = getValue(nextMap, "softness", 0) * scale; + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mix, mix2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, softness, softness2, scale); + } + time = time2; + mix = mix2; + softness = softness2; + keyMap = nextMap; + } + timelines.push(timeline); + } + } + if (map.transform) { + for (let constraintName in map.transform) { + let timelineMap = map.transform[constraintName]; + let keyMap = timelineMap[0]; + if (!keyMap) continue; + let constraint = skeletonData.findTransformConstraint(constraintName); + if (!constraint) throw new Error("Transform constraint not found: " + constraintName); + let constraintIndex = skeletonData.transformConstraints.indexOf(constraint); + let timeline = new TransformConstraintTimeline(timelineMap.length, timelineMap.length * 6, constraintIndex); + let time = getValue(keyMap, "time", 0); + let mixRotate = getValue(keyMap, "mixRotate", 1); + let mixX = getValue(keyMap, "mixX", 1); + let mixY = getValue(keyMap, "mixY", mixX); + let mixScaleX = getValue(keyMap, "mixScaleX", 1); + let mixScaleY = getValue(keyMap, "mixScaleY", mixScaleX); + let mixShearY = getValue(keyMap, "mixShearY", 1); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let mixRotate2 = getValue(nextMap, "mixRotate", 1); + let mixX2 = getValue(nextMap, "mixX", 1); + let mixY2 = getValue(nextMap, "mixY", mixX2); + let mixScaleX2 = getValue(nextMap, "mixScaleX", 1); + let mixScaleY2 = getValue(nextMap, "mixScaleY", mixScaleX2); + let mixShearY2 = getValue(nextMap, "mixShearY", 1); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mixRotate, mixRotate2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, mixX, mixX2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, mixY, mixY2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, mixScaleX, mixScaleX2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, mixScaleY, mixScaleY2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, mixShearY, mixShearY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + mixScaleX = mixScaleX2; + mixScaleY = mixScaleY2; + mixShearY = mixShearY2; + keyMap = nextMap; + } + timelines.push(timeline); + } + } + if (map.path) { + for (let constraintName in map.path) { + let constraintMap = map.path[constraintName]; + let constraint = skeletonData.findPathConstraint(constraintName); + if (!constraint) throw new Error("Path constraint not found: " + constraintName); + let constraintIndex = skeletonData.pathConstraints.indexOf(constraint); + for (let timelineName in constraintMap) { + let timelineMap = constraintMap[timelineName]; + let keyMap = timelineMap[0]; + if (!keyMap) continue; + let frames = timelineMap.length; + if (timelineName === "position") { + let timeline = new PathConstraintPositionTimeline(frames, frames, constraintIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, constraint.positionMode == 0 /* Fixed */ ? scale : 1)); + } else if (timelineName === "spacing") { + let timeline = new PathConstraintSpacingTimeline(frames, frames, constraintIndex); + timelines.push(readTimeline12(timelineMap, timeline, 0, constraint.spacingMode == 0 /* Length */ || constraint.spacingMode == 1 /* Fixed */ ? scale : 1)); + } else if (timelineName === "mix") { + let timeline = new PathConstraintMixTimeline(frames, frames * 3, constraintIndex); + let time = getValue(keyMap, "time", 0); + let mixRotate = getValue(keyMap, "mixRotate", 1); + let mixX = getValue(keyMap, "mixX", 1); + let mixY = getValue(keyMap, "mixY", mixX); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let mixRotate2 = getValue(nextMap, "mixRotate", 1); + let mixX2 = getValue(nextMap, "mixX", 1); + let mixY2 = getValue(nextMap, "mixY", mixX2); + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mixRotate, mixRotate2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, mixX, mixX2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, mixY, mixY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + keyMap = nextMap; + } + timelines.push(timeline); + } + } + } + } + if (map.physics) { + for (let constraintName in map.physics) { + let constraintMap = map.physics[constraintName]; + let constraintIndex = -1; + if (constraintName.length > 0) { + let constraint = skeletonData.findPhysicsConstraint(constraintName); + if (!constraint) throw new Error("Physics constraint not found: " + constraintName); + constraintIndex = skeletonData.physicsConstraints.indexOf(constraint); + } + for (let timelineName in constraintMap) { + let timelineMap = constraintMap[timelineName]; + let keyMap = timelineMap[0]; + if (!keyMap) continue; + let frames = timelineMap.length; + if (timelineName == "reset") { + const timeline2 = new PhysicsConstraintResetTimeline(frames, constraintIndex); + for (let frame = 0; keyMap != null; keyMap = timelineMap[frame + 1], frame++) + timeline2.setFrame(frame, getValue(keyMap, "time", 0)); + timelines.push(timeline2); + continue; + } + let timeline; + if (timelineName == "inertia") + timeline = new PhysicsConstraintInertiaTimeline(frames, frames, constraintIndex); + else if (timelineName == "strength") + timeline = new PhysicsConstraintStrengthTimeline(frames, frames, constraintIndex); + else if (timelineName == "damping") + timeline = new PhysicsConstraintDampingTimeline(frames, frames, constraintIndex); + else if (timelineName == "mass") + timeline = new PhysicsConstraintMassTimeline(frames, frames, constraintIndex); + else if (timelineName == "wind") + timeline = new PhysicsConstraintWindTimeline(frames, frames, constraintIndex); + else if (timelineName == "gravity") + timeline = new PhysicsConstraintGravityTimeline(frames, frames, constraintIndex); + else if (timelineName == "mix") + timeline = new PhysicsConstraintMixTimeline(frames, frames, constraintIndex); + else + continue; + timelines.push(readTimeline12(timelineMap, timeline, 0, 1)); + } + } + } + if (map.attachments) { + for (let attachmentsName in map.attachments) { + let attachmentsMap = map.attachments[attachmentsName]; + let skin = skeletonData.findSkin(attachmentsName); + if (!skin) throw new Error("Skin not found: " + attachmentsName); + for (let slotMapName in attachmentsMap) { + let slotMap = attachmentsMap[slotMapName]; + let slot = skeletonData.findSlot(slotMapName); + if (!slot) throw new Error("Slot not found: " + slotMapName); + let slotIndex = slot.index; + for (let attachmentMapName in slotMap) { + let attachmentMap = slotMap[attachmentMapName]; + let attachment = skin.getAttachment(slotIndex, attachmentMapName); + for (let timelineMapName in attachmentMap) { + let timelineMap = attachmentMap[timelineMapName]; + let keyMap = timelineMap[0]; + if (!keyMap) continue; + if (timelineMapName == "deform") { + let weighted = attachment.bones; + let vertices = attachment.vertices; + let deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + let timeline = new DeformTimeline(timelineMap.length, timelineMap.length, slotIndex, attachment); + let time = getValue(keyMap, "time", 0); + for (let frame = 0, bezier = 0; ; frame++) { + let deform; + let verticesValue = getValue(keyMap, "vertices", null); + if (!verticesValue) + deform = weighted ? Utils.newFloatArray(deformLength) : vertices; + else { + deform = Utils.newFloatArray(deformLength); + let start = getValue(keyMap, "offset", 0); + Utils.arrayCopy(verticesValue, 0, deform, start, verticesValue.length); + if (scale != 1) { + for (let i = start, n = i + verticesValue.length; i < n; i++) + deform[i] *= scale; + } + if (!weighted) { + for (let i = 0; i < deformLength; i++) + deform[i] += vertices[i]; + } + } + timeline.setFrame(frame, time, deform); + let nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + let time2 = getValue(nextMap, "time", 0); + let curve = keyMap.curve; + if (curve) bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, 0, 1, 1); + time = time2; + keyMap = nextMap; + } + timelines.push(timeline); + } else if (timelineMapName == "sequence") { + let timeline = new SequenceTimeline(timelineMap.length, slotIndex, attachment); + let lastDelay = 0; + for (let frame = 0; frame < timelineMap.length; frame++) { + let delay = getValue(keyMap, "delay", lastDelay); + let time = getValue(keyMap, "time", 0); + let mode = SequenceMode[getValue(keyMap, "mode", "hold")]; + let index = getValue(keyMap, "index", 0); + timeline.setFrame(frame, time, mode, index, delay); + lastDelay = delay; + keyMap = timelineMap[frame + 1]; + } + timelines.push(timeline); + } + } + } + } + } + } + if (map.drawOrder) { + let timeline = new DrawOrderTimeline(map.drawOrder.length); + let slotCount = skeletonData.slots.length; + let frame = 0; + for (let i = 0; i < map.drawOrder.length; i++, frame++) { + let drawOrderMap = map.drawOrder[i]; + let drawOrder = null; + let offsets = getValue(drawOrderMap, "offsets", null); + if (offsets) { + drawOrder = Utils.newArray(slotCount, -1); + let unchanged = Utils.newArray(slotCount - offsets.length, 0); + let originalIndex = 0, unchangedIndex = 0; + for (let ii = 0; ii < offsets.length; ii++) { + let offsetMap = offsets[ii]; + let slot = skeletonData.findSlot(offsetMap.slot); + if (!slot) throw new Error("Slot not found: " + slot); + let slotIndex = slot.index; + while (originalIndex != slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + drawOrder[originalIndex + offsetMap.offset] = originalIndex++; + } + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + for (let ii = slotCount - 1; ii >= 0; ii--) + if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex]; + } + timeline.setFrame(frame, getValue(drawOrderMap, "time", 0), drawOrder); + } + timelines.push(timeline); + } + if (map.events) { + let timeline = new EventTimeline(map.events.length); + let frame = 0; + for (let i = 0; i < map.events.length; i++, frame++) { + let eventMap = map.events[i]; + let eventData = skeletonData.findEvent(eventMap.name); + if (!eventData) throw new Error("Event not found: " + eventMap.name); + let event = new Event(Utils.toSinglePrecision(getValue(eventMap, "time", 0)), eventData); + event.intValue = getValue(eventMap, "int", eventData.intValue); + event.floatValue = getValue(eventMap, "float", eventData.floatValue); + event.stringValue = getValue(eventMap, "string", eventData.stringValue); + if (event.data.audioPath) { + event.volume = getValue(eventMap, "volume", 1); + event.balance = getValue(eventMap, "balance", 0); + } + timeline.setFrame(frame, event); + } + timelines.push(timeline); + } + let duration = 0; + for (let i = 0, n = timelines.length; i < n; i++) + duration = Math.max(duration, timelines[i].getDuration()); + skeletonData.animations.push(new Animation(name, timelines, duration)); + } + }; + var LinkedMesh2 = class { + parent; + skin; + slotIndex; + mesh; + inheritTimeline; + constructor(mesh, skin, slotIndex, parent, inheritDeform) { + this.mesh = mesh; + this.skin = skin; + this.slotIndex = slotIndex; + this.parent = parent; + this.inheritTimeline = inheritDeform; + } + }; + function readTimeline12(keys, timeline, defaultValue, scale) { + let keyMap = keys[0]; + let time = getValue(keyMap, "time", 0); + let value = getValue(keyMap, "value", defaultValue) * scale; + let bezier = 0; + for (let frame = 0; ; frame++) { + timeline.setFrame(frame, time, value); + let nextMap = keys[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + return timeline; + } + let time2 = getValue(nextMap, "time", 0); + let value2 = getValue(nextMap, "value", defaultValue) * scale; + if (keyMap.curve) bezier = readCurve(keyMap.curve, timeline, bezier, frame, 0, time, time2, value, value2, scale); + time = time2; + value = value2; + keyMap = nextMap; + } + } + function readTimeline22(keys, timeline, name1, name2, defaultValue, scale) { + let keyMap = keys[0]; + let time = getValue(keyMap, "time", 0); + let value1 = getValue(keyMap, name1, defaultValue) * scale; + let value2 = getValue(keyMap, name2, defaultValue) * scale; + let bezier = 0; + for (let frame = 0; ; frame++) { + timeline.setFrame(frame, time, value1, value2); + let nextMap = keys[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + return timeline; + } + let time2 = getValue(nextMap, "time", 0); + let nvalue1 = getValue(nextMap, name1, defaultValue) * scale; + let nvalue2 = getValue(nextMap, name2, defaultValue) * scale; + let curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, value1, nvalue1, scale); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, value2, nvalue2, scale); + } + time = time2; + value1 = nvalue1; + value2 = nvalue2; + keyMap = nextMap; + } + } + function readCurve(curve, timeline, bezier, frame, value, time1, time2, value1, value2, scale) { + if (curve == "stepped") { + timeline.setStepped(frame); + return bezier; + } + let i = value << 2; + let cx1 = curve[i]; + let cy1 = curve[i + 1] * scale; + let cx2 = curve[i + 2]; + let cy2 = curve[i + 3] * scale; + timeline.setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2); + return bezier + 1; + } + function getValue(map, property, defaultValue) { + return map[property] !== void 0 ? map[property] : defaultValue; + } + + // spine-core/src/polyfills.ts + (() => { + if (typeof Math.fround === "undefined") { + Math.fround = /* @__PURE__ */ function(array) { + return function(x) { + return array[0] = x, array[0]; + }; + }(new Float32Array(1)); + } + })(); + + // spine-canvas/src/CanvasTexture.ts + var CanvasTexture = class extends Texture { + constructor(image) { + super(image); + } + setFilters(minFilter, magFilter) { + } + setWraps(uWrap, vWrap) { + } + dispose() { + } + }; + + // spine-canvas/src/AssetManager.ts + var AssetManager = class extends AssetManagerBase { + constructor(pathPrefix = "", downloader = new Downloader()) { + super((image) => { + return new CanvasTexture(image); + }, pathPrefix, downloader); + } + }; + + // spine-canvas/src/SkeletonRenderer.ts + var worldVertices = Utils.newFloatArray(8); + var SkeletonRenderer = class _SkeletonRenderer { + static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; + static VERTEX_SIZE = 2 + 2 + 4; + ctx; + triangleRendering = false; + debugRendering = false; + vertices = Utils.newFloatArray(8 * 1024); + tempColor = new Color(); + constructor(context) { + this.ctx = context; + } + draw(skeleton) { + if (this.triangleRendering) this.drawTriangles(skeleton); + else this.drawImages(skeleton); + } + drawImages(skeleton) { + let ctx = this.ctx; + let color = this.tempColor; + let skeletonColor = skeleton.color; + let drawOrder = skeleton.drawOrder; + if (this.debugRendering) ctx.strokeStyle = "green"; + for (let i = 0, n = drawOrder.length; i < n; i++) { + let slot = drawOrder[i]; + let bone = slot.bone; + if (!bone.active) continue; + let attachment = slot.getAttachment(); + if (!(attachment instanceof RegionAttachment)) continue; + attachment.computeWorldVertices(slot, worldVertices, 0, 2); + let region = attachment.region; + let image = region.texture.getImage(); + let slotColor = slot.color; + let regionColor = attachment.color; + color.set( + skeletonColor.r * slotColor.r * regionColor.r, + skeletonColor.g * slotColor.g * regionColor.g, + skeletonColor.b * slotColor.b * regionColor.b, + skeletonColor.a * slotColor.a * regionColor.a + ); + ctx.save(); + ctx.transform(bone.a, bone.c, bone.b, bone.d, bone.worldX, bone.worldY); + ctx.translate(attachment.offset[0], attachment.offset[1]); + ctx.rotate(attachment.rotation * Math.PI / 180); + let atlasScale = attachment.width / region.originalWidth; + ctx.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY); + let w = region.width, h = region.height; + ctx.translate(w / 2, h / 2); + if (attachment.region.degrees == 90) { + let t = w; + w = h; + h = t; + ctx.rotate(-Math.PI / 2); + } + ctx.scale(1, -1); + ctx.translate(-w / 2, -h / 2); + ctx.globalAlpha = color.a; + ctx.drawImage(image, image.width * region.u, image.height * region.v, w, h, 0, 0, w, h); + if (this.debugRendering) ctx.strokeRect(0, 0, w, h); + ctx.restore(); + } + } + drawTriangles(skeleton) { + let ctx = this.ctx; + let color = this.tempColor; + let skeletonColor = skeleton.color; + let drawOrder = skeleton.drawOrder; + let blendMode = null; + let vertices = this.vertices; + let triangles = null; + for (let i = 0, n = drawOrder.length; i < n; i++) { + let slot = drawOrder[i]; + let attachment = slot.getAttachment(); + let texture; + let region; + if (attachment instanceof RegionAttachment) { + let regionAttachment = attachment; + vertices = this.computeRegionVertices(slot, regionAttachment, false); + triangles = _SkeletonRenderer.QUAD_TRIANGLES; + texture = regionAttachment.region.texture.getImage(); + } else if (attachment instanceof MeshAttachment) { + let mesh = attachment; + vertices = this.computeMeshVertices(slot, mesh, false); + triangles = mesh.triangles; + texture = mesh.region.texture.getImage(); + } else + continue; + if (texture) { + if (slot.data.blendMode != blendMode) blendMode = slot.data.blendMode; + let slotColor = slot.color; + let attachmentColor = attachment.color; + color.set( + skeletonColor.r * slotColor.r * attachmentColor.r, + skeletonColor.g * slotColor.g * attachmentColor.g, + skeletonColor.b * slotColor.b * attachmentColor.b, + skeletonColor.a * slotColor.a * attachmentColor.a + ); + ctx.globalAlpha = color.a; + for (var j = 0; j < triangles.length; j += 3) { + let t1 = triangles[j] * 8, t2 = triangles[j + 1] * 8, t3 = triangles[j + 2] * 8; + let x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7]; + let x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7]; + let x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7]; + this.drawTriangle(texture, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2); + if (this.debugRendering) { + ctx.strokeStyle = "green"; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.lineTo(x0, y0); + ctx.stroke(); + } + } + } + } + this.ctx.globalAlpha = 1; + } + // Adapted from http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 + // Apache 2 licensed + drawTriangle(img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2) { + let ctx = this.ctx; + const width = img.width - 1; + const height = img.height - 1; + u0 *= width; + v0 *= height; + u1 *= width; + v1 *= height; + u2 *= width; + v2 *= height; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.closePath(); + x1 -= x0; + y1 -= y0; + x2 -= x0; + y2 -= y0; + u1 -= u0; + v1 -= v0; + u2 -= u0; + v2 -= v0; + let det = u1 * v2 - u2 * v1; + if (det == 0) return; + det = 1 / det; + const a = (v2 * x1 - v1 * x2) * det; + const b = (v2 * y1 - v1 * y2) * det; + const c = (u1 * x2 - u2 * x1) * det; + const d = (u1 * y2 - u2 * y1) * det; + const e = x0 - a * u0 - c * v0; + const f = y0 - b * u0 - d * v0; + ctx.save(); + ctx.transform(a, b, c, d, e, f); + ctx.clip(); + ctx.drawImage(img, 0, 0); + ctx.restore(); + } + computeRegionVertices(slot, region, pma) { + let skeletonColor = slot.bone.skeleton.color; + let slotColor = slot.color; + let regionColor = region.color; + let alpha = skeletonColor.a * slotColor.a * regionColor.a; + let multiplier = pma ? alpha : 1; + let color = this.tempColor; + color.set( + skeletonColor.r * slotColor.r * regionColor.r * multiplier, + skeletonColor.g * slotColor.g * regionColor.g * multiplier, + skeletonColor.b * slotColor.b * regionColor.b * multiplier, + alpha + ); + region.computeWorldVertices(slot, this.vertices, 0, _SkeletonRenderer.VERTEX_SIZE); + let vertices = this.vertices; + let uvs = region.uvs; + vertices[RegionAttachment.C1R] = color.r; + vertices[RegionAttachment.C1G] = color.g; + vertices[RegionAttachment.C1B] = color.b; + vertices[RegionAttachment.C1A] = color.a; + vertices[RegionAttachment.U1] = uvs[0]; + vertices[RegionAttachment.V1] = uvs[1]; + vertices[RegionAttachment.C2R] = color.r; + vertices[RegionAttachment.C2G] = color.g; + vertices[RegionAttachment.C2B] = color.b; + vertices[RegionAttachment.C2A] = color.a; + vertices[RegionAttachment.U2] = uvs[2]; + vertices[RegionAttachment.V2] = uvs[3]; + vertices[RegionAttachment.C3R] = color.r; + vertices[RegionAttachment.C3G] = color.g; + vertices[RegionAttachment.C3B] = color.b; + vertices[RegionAttachment.C3A] = color.a; + vertices[RegionAttachment.U3] = uvs[4]; + vertices[RegionAttachment.V3] = uvs[5]; + vertices[RegionAttachment.C4R] = color.r; + vertices[RegionAttachment.C4G] = color.g; + vertices[RegionAttachment.C4B] = color.b; + vertices[RegionAttachment.C4A] = color.a; + vertices[RegionAttachment.U4] = uvs[6]; + vertices[RegionAttachment.V4] = uvs[7]; + return vertices; + } + computeMeshVertices(slot, mesh, pma) { + let skeletonColor = slot.bone.skeleton.color; + let slotColor = slot.color; + let regionColor = mesh.color; + let alpha = skeletonColor.a * slotColor.a * regionColor.a; + let multiplier = pma ? alpha : 1; + let color = this.tempColor; + color.set( + skeletonColor.r * slotColor.r * regionColor.r * multiplier, + skeletonColor.g * slotColor.g * regionColor.g * multiplier, + skeletonColor.b * slotColor.b * regionColor.b * multiplier, + alpha + ); + let vertexCount = mesh.worldVerticesLength / 2; + let vertices = this.vertices; + if (vertices.length < mesh.worldVerticesLength) this.vertices = vertices = Utils.newFloatArray(mesh.worldVerticesLength); + mesh.computeWorldVertices(slot, 0, mesh.worldVerticesLength, vertices, 0, _SkeletonRenderer.VERTEX_SIZE); + let uvs = mesh.uvs; + for (let i = 0, u = 0, v = 2; i < vertexCount; i++) { + vertices[v++] = color.r; + vertices[v++] = color.g; + vertices[v++] = color.b; + vertices[v++] = color.a; + vertices[v++] = uvs[u++]; + vertices[v++] = uvs[u++]; + v += 2; + } + return vertices; + } + }; + return __toCommonJS(index_exports); +})(); +//# sourceMappingURL=spine-canvas.js.map diff --git a/lib/4.3/spine-canvas.js b/lib/4.3/spine-canvas.js new file mode 100644 index 0000000..e7405c6 --- /dev/null +++ b/lib/4.3/spine-canvas.js @@ -0,0 +1,13723 @@ +"use strict"; +var spine = (() => { + var __defProp = Object.defineProperty; + var __getOwnPropDesc = Object.getOwnPropertyDescriptor; + var __getOwnPropNames = Object.getOwnPropertyNames; + var __hasOwnProp = Object.prototype.hasOwnProperty; + var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); + }; + var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; + }; + var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + + // spine-canvas/src/index.ts + var index_exports = {}; + __export(index_exports, { + ATTACH_RETAIN: () => ATTACH_RETAIN, + ATTACH_SETUP: () => ATTACH_SETUP, + AlphaTimeline: () => AlphaTimeline, + Animation: () => Animation, + AnimationState: () => AnimationState, + AnimationStateAdapter: () => AnimationStateAdapter, + AnimationStateData: () => AnimationStateData, + AssetCache: () => AssetCache, + AssetManager: () => AssetManager, + AssetManagerBase: () => AssetManagerBase, + AtlasAttachmentLoader: () => AtlasAttachmentLoader, + Attachment: () => Attachment, + AttachmentTimeline: () => AttachmentTimeline, + BinaryInput: () => BinaryInput, + BlendMode: () => BlendMode, + Bone: () => Bone, + BoneData: () => BoneData, + BonePose: () => BonePose, + BoneTimeline1: () => BoneTimeline1, + BoneTimeline2: () => BoneTimeline2, + BoundingBoxAttachment: () => BoundingBoxAttachment, + CURRENT: () => CURRENT, + CanvasTexture: () => CanvasTexture, + ClippingAttachment: () => ClippingAttachment, + Color: () => Color, + Constraint: () => Constraint, + ConstraintData: () => ConstraintData, + ConstraintTimeline1: () => ConstraintTimeline1, + CurveTimeline: () => CurveTimeline, + CurveTimeline1: () => CurveTimeline1, + DebugUtils: () => DebugUtils, + DeformTimeline: () => DeformTimeline, + Downloader: () => Downloader, + DrawOrder: () => DrawOrder, + DrawOrderFolderTimeline: () => DrawOrderFolderTimeline, + DrawOrderTimeline: () => DrawOrderTimeline, + Event: () => Event, + EventData: () => EventData, + EventQueue: () => EventQueue, + EventTimeline: () => EventTimeline, + EventType: () => EventType, + FIRST: () => FIRST, + FakeTexture: () => FakeTexture, + FromProperty: () => FromProperty, + FromRotate: () => FromRotate, + FromScaleX: () => FromScaleX, + FromScaleY: () => FromScaleY, + FromShearY: () => FromShearY, + FromX: () => FromX, + FromY: () => FromY, + HOLD: () => HOLD, + IkConstraint: () => IkConstraint, + IkConstraintData: () => IkConstraintData, + IkConstraintPose: () => IkConstraintPose, + IkConstraintTimeline: () => IkConstraintTimeline, + Inherit: () => Inherit, + InheritTimeline: () => InheritTimeline, + IntSet: () => IntSet, + Interpolation: () => Interpolation, + MODE: () => MODE, + MathUtils: () => MathUtils, + MeshAttachment: () => MeshAttachment, + MixFrom: () => MixFrom, + PathAttachment: () => PathAttachment, + PathConstraint: () => PathConstraint, + PathConstraintData: () => PathConstraintData, + PathConstraintMixTimeline: () => PathConstraintMixTimeline, + PathConstraintPose: () => PathConstraintPose, + PathConstraintPositionTimeline: () => PathConstraintPositionTimeline, + PathConstraintSpacingTimeline: () => PathConstraintSpacingTimeline, + Physics: () => Physics, + PhysicsConstraint: () => PhysicsConstraint, + PhysicsConstraintDampingTimeline: () => PhysicsConstraintDampingTimeline, + PhysicsConstraintData: () => PhysicsConstraintData, + PhysicsConstraintGravityTimeline: () => PhysicsConstraintGravityTimeline, + PhysicsConstraintInertiaTimeline: () => PhysicsConstraintInertiaTimeline, + PhysicsConstraintMassTimeline: () => PhysicsConstraintMassTimeline, + PhysicsConstraintMixTimeline: () => PhysicsConstraintMixTimeline, + PhysicsConstraintPose: () => PhysicsConstraintPose, + PhysicsConstraintResetTimeline: () => PhysicsConstraintResetTimeline, + PhysicsConstraintStrengthTimeline: () => PhysicsConstraintStrengthTimeline, + PhysicsConstraintTimeline: () => PhysicsConstraintTimeline, + PhysicsConstraintWindTimeline: () => PhysicsConstraintWindTimeline, + PointAttachment: () => PointAttachment, + Pool: () => Pool, + Posed: () => Posed, + PosedActive: () => PosedActive, + PosedData: () => PosedData, + PositionMode: () => PositionMode, + Pow: () => Pow, + PowOut: () => PowOut, + Property: () => Property, + RGB2Timeline: () => RGB2Timeline, + RGBA2Timeline: () => RGBA2Timeline, + RGBATimeline: () => RGBATimeline, + RGBTimeline: () => RGBTimeline, + RegionAttachment: () => RegionAttachment, + RotateMode: () => RotateMode, + RotateTimeline: () => RotateTimeline, + SETUP: () => SETUP, + ScaleTimeline: () => ScaleTimeline, + ScaleXTimeline: () => ScaleXTimeline, + ScaleYMode: () => ScaleYMode, + ScaleYTimeline: () => ScaleYTimeline, + Sequence: () => Sequence, + SequenceMode: () => SequenceMode, + SequenceModeValues: () => SequenceModeValues, + SequenceTimeline: () => SequenceTimeline, + ShearTimeline: () => ShearTimeline, + ShearXTimeline: () => ShearXTimeline, + ShearYTimeline: () => ShearYTimeline, + Skeleton: () => Skeleton, + SkeletonBinary: () => SkeletonBinary, + SkeletonBounds: () => SkeletonBounds, + SkeletonClipping: () => SkeletonClipping, + SkeletonData: () => SkeletonData, + SkeletonJson: () => SkeletonJson, + SkeletonPhysicsMovement: () => SkeletonPhysicsMovement, + SkeletonRenderer: () => SkeletonRenderer, + SkeletonRendererCore: () => SkeletonRendererCore, + Skin: () => Skin, + SkinEntry: () => SkinEntry, + Slider: () => Slider, + SliderData: () => SliderData, + SliderMixTimeline: () => SliderMixTimeline, + SliderPose: () => SliderPose, + SliderTimeline: () => SliderTimeline, + Slot: () => Slot, + SlotCurveTimeline: () => SlotCurveTimeline, + SlotData: () => SlotData, + SlotPose: () => SlotPose, + SpacingMode: () => SpacingMode, + StringSet: () => StringSet, + Texture: () => Texture, + TextureAtlas: () => TextureAtlas, + TextureAtlasPage: () => TextureAtlasPage, + TextureAtlasRegion: () => TextureAtlasRegion, + TextureFilter: () => TextureFilter, + TextureRegion: () => TextureRegion, + TextureWrap: () => TextureWrap, + TimeKeeper: () => TimeKeeper, + Timeline: () => Timeline, + ToProperty: () => ToProperty, + ToRotate: () => ToRotate, + ToScaleX: () => ToScaleX, + ToScaleY: () => ToScaleY, + ToShearY: () => ToShearY, + ToX: () => ToX, + ToY: () => ToY, + TrackEntry: () => TrackEntry, + TransformConstraint: () => TransformConstraint, + TransformConstraintData: () => TransformConstraintData, + TransformConstraintPose: () => TransformConstraintPose, + TransformConstraintTimeline: () => TransformConstraintTimeline, + TranslateTimeline: () => TranslateTimeline, + TranslateXTimeline: () => TranslateXTimeline, + TranslateYTimeline: () => TranslateYTimeline, + Triangulator: () => Triangulator, + Utils: () => Utils, + Vector2: () => Vector2, + VertexAttachment: () => VertexAttachment, + WindowedMean: () => WindowedMean, + isBoneTimeline: () => isBoneTimeline, + isConstraintTimeline: () => isConstraintTimeline, + isSlotTimeline: () => isSlotTimeline + }); + + // spine-core/src/Utils.ts + var IntSet = class { + array = []; + add(value) { + const contains = this.contains(value); + this.array[value | 0] = value | 0; + return !contains; + } + contains(value) { + return this.array[value | 0] !== void 0; + } + remove(value) { + this.array[value | 0] = void 0; + } + clear() { + this.array.length = 0; + } + }; + var StringSet = class { + entries = {}; + size = 0; + add(value) { + const contains = this.entries[value]; + this.entries[value] = true; + if (!contains) { + this.size++; + return true; + } + return false; + } + addAll(values) { + const oldSize = this.size; + for (let i = 0, n = values.length; i < n; i++) + this.add(values[i]); + return oldSize !== this.size; + } + contains(value) { + return this.entries[value]; + } + clear() { + this.entries = {}; + this.size = 0; + } + }; + var Color = class _Color { + constructor(r = 0, g = 0, b = 0, a = 0) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + static WHITE = new _Color(1, 1, 1, 1); + static RED = new _Color(1, 0, 0, 1); + static GREEN = new _Color(0, 1, 0, 1); + static BLUE = new _Color(0, 0, 1, 1); + static MAGENTA = new _Color(1, 0, 1, 1); + set(r, g, b, a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + return this.clamp(); + } + setFromColor(c) { + this.r = c.r; + this.g = c.g; + this.b = c.b; + this.a = c.a; + return this; + } + setFromString(hex) { + hex = hex.charAt(0) === "#" ? hex.substr(1) : hex; + this.r = parseInt(hex.substr(0, 2), 16) / 255; + this.g = parseInt(hex.substr(2, 2), 16) / 255; + this.b = parseInt(hex.substr(4, 2), 16) / 255; + this.a = hex.length !== 8 ? 1 : parseInt(hex.substr(6, 2), 16) / 255; + return this; + } + add(r, g, b, a) { + this.r += r; + this.g += g; + this.b += b; + this.a += a; + return this.clamp(); + } + clamp() { + if (this.r < 0) this.r = 0; + else if (this.r > 1) this.r = 1; + if (this.g < 0) this.g = 0; + else if (this.g > 1) this.g = 1; + if (this.b < 0) this.b = 0; + else if (this.b > 1) this.b = 1; + if (this.a < 0) this.a = 0; + else if (this.a > 1) this.a = 1; + return this; + } + static rgba8888ToColor(color, value) { + color.r = ((value & 4278190080) >>> 24) / 255; + color.g = ((value & 16711680) >>> 16) / 255; + color.b = ((value & 65280) >>> 8) / 255; + color.a = (value & 255) / 255; + } + static rgb888ToColor(color, value) { + color.r = ((value & 16711680) >>> 16) / 255; + color.g = ((value & 65280) >>> 8) / 255; + color.b = (value & 255) / 255; + } + toRgb888() { + const hex = (x) => `0${(x * 255).toString(16)}`.slice(-2); + return Number(`0x${hex(this.r)}${hex(this.g)}${hex(this.b)}`); + } + static fromString(hex, color = new _Color()) { + return color.setFromString(hex); + } + }; + var MathUtils = class _MathUtils { + static epsilon = 1e-5; + static epsilon2 = _MathUtils.epsilon * _MathUtils.epsilon; + // biome-ignore lint/suspicious/noApproximativeNumericConstant: reference runtime + static PI = 3.1415927; + static PI2 = _MathUtils.PI * 2; + static invPI2 = 1 / _MathUtils.PI2; + static radiansToDegrees = 180 / _MathUtils.PI; + static radDeg = _MathUtils.radiansToDegrees; + static degreesToRadians = _MathUtils.PI / 180; + static degRad = _MathUtils.degreesToRadians; + static clamp(value, min, max) { + if (value < min) return min; + if (value > max) return max; + return value; + } + static cosDeg(degrees) { + return Math.cos(degrees * _MathUtils.degRad); + } + static sinDeg(degrees) { + return Math.sin(degrees * _MathUtils.degRad); + } + static atan2Deg(y, x) { + return Math.atan2(y, x) * _MathUtils.radDeg; + } + static signum(value) { + return value > 0 ? 1 : value < 0 ? -1 : 0; + } + static toInt(x) { + return x > 0 ? Math.floor(x) : Math.ceil(x); + } + static cbrt(x) { + const y = Math.pow(Math.abs(x), 1 / 3); + return x < 0 ? -y : y; + } + static randomTriangular(min, max) { + return _MathUtils.randomTriangularWith(min, max, (min + max) * 0.5); + } + static randomTriangularWith(min, max, mode) { + const u = Math.random(); + const d = max - min; + if (u <= (mode - min) / d) return min + Math.sqrt(u * d * (mode - min)); + return max - Math.sqrt((1 - u) * d * (max - mode)); + } + static isPowerOfTwo(value) { + return value && (value & value - 1) === 0; + } + }; + var Interpolation = class _Interpolation { + static linear = new class extends _Interpolation { + applyInternal(a) { + return a; + } + }(); + /** Aka "smoothstep". */ + static smooth = new class extends _Interpolation { + applyInternal(a) { + return a * a * (3 - 2 * a); + } + }(); + /** Slow, then fast. */ + static slowFast = new class extends _Interpolation { + applyInternal(a) { + return a * a; + } + }(); + /** Fast, then slow. */ + static fastSlow = new class extends _Interpolation { + applyInternal(a) { + return (a - 1) * (a - 1) * -1 + 1; + } + }(); + static circle = new class extends _Interpolation { + applyInternal(a) { + if (a <= 0.5) { + a *= 2; + return (1 - Math.sqrt(1 - a * a)) / 2; + } + a--; + a *= 2; + return (Math.sqrt(1 - a * a) + 1) / 2; + } + }(); + apply(start, end, a) { + if (end === void 0 || a === void 0) return this.applyInternal(start); + return start + (end - start) * this.applyInternal(a); + } + }; + var Pow = class extends Interpolation { + power = 2; + constructor(power) { + super(); + this.power = power; + } + applyInternal(a) { + if (a <= 0.5) return Math.pow(a * 2, this.power) / 2; + return Math.pow((a - 1) * 2, this.power) / (this.power % 2 === 0 ? -2 : 2) + 1; + } + }; + var PowOut = class extends Pow { + constructor(power) { + super(power); + } + applyInternal(a) { + return Math.pow(a - 1, this.power) * (this.power % 2 === 0 ? -1 : 1) + 1; + } + }; + var Utils = class _Utils { + static SUPPORTS_TYPED_ARRAYS = typeof Float32Array !== "undefined"; + static arrayCopy(source, sourceStart, dest, destStart, numElements) { + for (let i = sourceStart, j = destStart; i < sourceStart + numElements; i++, j++) { + dest[j] = source[i]; + } + } + static arrayFill(array, fromIndex, toIndex, value) { + for (let i = fromIndex; i < toIndex; i++) + array[i] = value; + } + // biome-ignore lint/suspicious/noExplicitAny: ok any in this case + static setArraySize(array, size, value = 0) { + const oldSize = array.length; + if (oldSize === size) return array; + array.length = size; + if (oldSize < size) { + for (let i = oldSize; i < size; i++) array[i] = value; + } + return array; + } + // biome-ignore lint/suspicious/noExplicitAny: ok any in this case + static ensureArrayCapacity(array, size, value = 0) { + if (array.length >= size) return array; + return _Utils.setArraySize(array, size, value); + } + static newArray(size, defaultValue) { + const array = []; + for (let i = 0; i < size; i++) array[i] = defaultValue; + return array; + } + static newFloatArray(size) { + if (_Utils.SUPPORTS_TYPED_ARRAYS) + return new Float32Array(size); + else { + const array = []; + for (let i = 0; i < array.length; i++) array[i] = 0; + return array; + } + } + static newShortArray(size) { + if (_Utils.SUPPORTS_TYPED_ARRAYS) + return new Int16Array(size); + else { + const array = []; + for (let i = 0; i < array.length; i++) array[i] = 0; + return array; + } + } + static toFloatArray(array) { + return _Utils.SUPPORTS_TYPED_ARRAYS ? new Float32Array(array) : array; + } + static toSinglePrecision(value) { + return _Utils.SUPPORTS_TYPED_ARRAYS ? Math.fround(value) : value; + } + // This function is used to fix WebKit 602 specific issue described at https://esotericsoftware.com/forum/d/10109-ios-10-disappearing-graphics + static webkit602BugfixHelper(alpha) { + } + static contains(array, element, identity = true) { + for (let i = 0; i < array.length; i++) + if (array[i] === element) return true; + return false; + } + // biome-ignore lint/suspicious/noExplicitAny: ok any in this case + static enumValue(type, name) { + return type[name[0].toUpperCase() + name.slice(1)]; + } + }; + var DebugUtils = class { + static logBones(skeleton) { + for (let i = 0; i < skeleton.bones.length; i++) { + const bone = skeleton.bones[i].appliedPose; + console.log(`${bone.bone.data.name}, ${bone.a}, ${bone.b}, ${bone.c}, ${bone.d}, ${bone.worldX}, ${bone.worldY}`); + } + } + }; + var Pool = class { + items = []; + instantiator; + constructor(instantiator) { + this.instantiator = instantiator; + } + obtain() { + return this.items.length > 0 ? this.items.pop() : this.instantiator(); + } + free(item) { + item.reset?.(); + this.items.push(item); + } + freeAll(items) { + for (let i = 0; i < items.length; i++) + this.free(items[i]); + } + clear() { + this.items.length = 0; + } + }; + var Vector2 = class { + constructor(x = 0, y = 0) { + this.x = x; + this.y = y; + } + set(x, y) { + this.x = x; + this.y = y; + return this; + } + length() { + const x = this.x; + const y = this.y; + return Math.sqrt(x * x + y * y); + } + normalize() { + const len = this.length(); + if (len !== 0) { + this.x /= len; + this.y /= len; + } + return this; + } + }; + var TimeKeeper = class { + maxDelta = 0.064; + framesPerSecond = 0; + delta = 0; + totalTime = 0; + lastTime = Date.now() / 1e3; + frameCount = 0; + frameTime = 0; + update() { + const now = Date.now() / 1e3; + this.delta = now - this.lastTime; + this.frameTime += this.delta; + this.totalTime += this.delta; + if (this.delta > this.maxDelta) this.delta = this.maxDelta; + this.lastTime = now; + this.frameCount++; + if (this.frameTime > 1) { + this.framesPerSecond = this.frameCount / this.frameTime; + this.frameTime = 0; + this.frameCount = 0; + } + } + }; + var WindowedMean = class { + values; + addedValues = 0; + lastValue = 0; + mean = 0; + dirty = true; + constructor(windowSize = 32) { + this.values = new Array(windowSize); + } + hasEnoughData() { + return this.addedValues >= this.values.length; + } + addValue(value) { + if (this.addedValues < this.values.length) this.addedValues++; + this.values[this.lastValue++] = value; + if (this.lastValue > this.values.length - 1) this.lastValue = 0; + this.dirty = true; + } + getMean() { + if (this.hasEnoughData()) { + if (this.dirty) { + let mean = 0; + for (let i = 0; i < this.values.length; i++) + mean += this.values[i]; + this.mean = mean / this.values.length; + this.dirty = false; + } + return this.mean; + } + return 0; + } + }; + + // spine-core/src/Texture.ts + var Texture = class { + _image; + constructor(image) { + this._image = image; + } + getImage() { + return this._image; + } + }; + var TextureFilter = /* @__PURE__ */ ((TextureFilter2) => { + TextureFilter2[TextureFilter2["Nearest"] = 9728] = "Nearest"; + TextureFilter2[TextureFilter2["Linear"] = 9729] = "Linear"; + TextureFilter2[TextureFilter2["MipMap"] = 9987] = "MipMap"; + TextureFilter2[TextureFilter2["MipMapNearestNearest"] = 9984] = "MipMapNearestNearest"; + TextureFilter2[TextureFilter2["MipMapLinearNearest"] = 9985] = "MipMapLinearNearest"; + TextureFilter2[TextureFilter2["MipMapNearestLinear"] = 9986] = "MipMapNearestLinear"; + TextureFilter2[TextureFilter2["MipMapLinearLinear"] = 9987] = "MipMapLinearLinear"; + return TextureFilter2; + })(TextureFilter || {}); + var TextureWrap = /* @__PURE__ */ ((TextureWrap2) => { + TextureWrap2[TextureWrap2["MirroredRepeat"] = 33648] = "MirroredRepeat"; + TextureWrap2[TextureWrap2["ClampToEdge"] = 33071] = "ClampToEdge"; + TextureWrap2[TextureWrap2["Repeat"] = 10497] = "Repeat"; + return TextureWrap2; + })(TextureWrap || {}); + var TextureRegion = class { + texture; + u = 0; + v = 0; + u2 = 0; + v2 = 0; + width = 0; + height = 0; + degrees = 0; + offsetX = 0; + offsetY = 0; + originalWidth = 0; + originalHeight = 0; + }; + var FakeTexture = class extends Texture { + setFilters(minFilter, magFilter) { + } + setWraps(uWrap, vWrap) { + } + dispose() { + } + }; + + // spine-core/src/TextureAtlas.ts + var TextureAtlas = class { + pages = []; + regions = []; + constructor(atlasText) { + const reader = new TextureAtlasReader(atlasText); + const entry = new Array(4); + const pageFields = {}; + pageFields.size = (page2) => { + page2.width = parseInt(entry[1]); + page2.height = parseInt(entry[2]); + }; + pageFields.format = () => { + }; + pageFields.filter = (page2) => { + page2.minFilter = Utils.enumValue(TextureFilter, entry[1]); + page2.magFilter = Utils.enumValue(TextureFilter, entry[2]); + }; + pageFields.repeat = (page2) => { + if (entry[1].indexOf("x") !== -1) page2.uWrap = 10497 /* Repeat */; + if (entry[1].indexOf("y") !== -1) page2.vWrap = 10497 /* Repeat */; + }; + pageFields.pma = (page2) => { + page2.pma = entry[1] === "true"; + }; + var regionFields = {}; + regionFields.xy = (region) => { + region.x = parseInt(entry[1]); + region.y = parseInt(entry[2]); + }; + regionFields.size = (region) => { + region.width = parseInt(entry[1]); + region.height = parseInt(entry[2]); + }; + regionFields.bounds = (region) => { + region.x = parseInt(entry[1]); + region.y = parseInt(entry[2]); + region.width = parseInt(entry[3]); + region.height = parseInt(entry[4]); + }; + regionFields.offset = (region) => { + region.offsetX = parseInt(entry[1]); + region.offsetY = parseInt(entry[2]); + }; + regionFields.orig = (region) => { + region.originalWidth = parseInt(entry[1]); + region.originalHeight = parseInt(entry[2]); + }; + regionFields.offsets = (region) => { + region.offsetX = parseInt(entry[1]); + region.offsetY = parseInt(entry[2]); + region.originalWidth = parseInt(entry[3]); + region.originalHeight = parseInt(entry[4]); + }; + regionFields.rotate = (region) => { + const value = entry[1]; + if (value === "true") + region.degrees = 90; + else if (value !== "false") + region.degrees = parseInt(value); + }; + regionFields.index = (region) => { + region.index = parseInt(entry[1]); + }; + let line = reader.readLine(); + while (line && line.trim().length === 0) + line = reader.readLine(); + while (true) { + if (!line || line.trim().length === 0) break; + if (reader.readEntry(entry, line) === 0) break; + line = reader.readLine(); + } + let page = null; + let names = null; + let values = null; + while (true) { + if (line === null) break; + if (line.trim().length === 0) { + page = null; + line = reader.readLine(); + } else if (!page) { + page = new TextureAtlasPage(line.trim()); + while (true) { + if (reader.readEntry(entry, line = reader.readLine()) === 0) break; + const field = pageFields[entry[0]]; + if (field) field(page); + } + this.pages.push(page); + } else { + const region = new TextureAtlasRegion(page, line); + while (true) { + const count = reader.readEntry(entry, line = reader.readLine()); + if (count === 0) break; + const field = regionFields[entry[0]]; + if (field) + field(region); + else { + if (!names) names = []; + if (!values) values = []; + names.push(entry[0]); + const entryValues = []; + for (let i = 0; i < count; i++) + entryValues.push(parseInt(entry[i + 1])); + values.push(entryValues); + } + } + if (region.originalWidth === 0 && region.originalHeight === 0) { + region.originalWidth = region.width; + region.originalHeight = region.height; + } + if (names && names.length > 0 && values && values.length > 0) { + region.names = names; + region.values = values; + names = null; + values = null; + } + region.u = region.x / page.width; + region.v = region.y / page.height; + if (region.degrees === 90) { + region.u2 = (region.x + region.height) / page.width; + region.v2 = (region.y + region.width) / page.height; + } else { + region.u2 = (region.x + region.width) / page.width; + region.v2 = (region.y + region.height) / page.height; + } + this.regions.push(region); + } + } + } + findRegion(name) { + for (let i = 0; i < this.regions.length; i++) { + if (this.regions[i].name === name) { + return this.regions[i]; + } + } + return null; + } + setTextures(assetManager, pathPrefix = "") { + for (const page of this.pages) + page.setTexture(assetManager.get(pathPrefix + page.name)); + } + dispose() { + for (let i = 0; i < this.pages.length; i++) { + this.pages[i].texture?.dispose(); + } + } + }; + var TextureAtlasReader = class { + lines; + index = 0; + constructor(text) { + this.lines = text.split(/\r\n|\r|\n/); + } + readLine() { + if (this.index >= this.lines.length) + return null; + return this.lines[this.index++]; + } + readEntry(entry, line) { + if (!line) return 0; + line = line.trim(); + if (line.length === 0) return 0; + const colon = line.indexOf(":"); + if (colon === -1) return 0; + entry[0] = line.substr(0, colon).trim(); + for (let i = 1, lastMatch = colon + 1; ; i++) { + const comma = line.indexOf(",", lastMatch); + if (comma === -1) { + entry[i] = line.substr(lastMatch).trim(); + return i; + } + entry[i] = line.substr(lastMatch, comma - lastMatch).trim(); + lastMatch = comma + 1; + if (i === 4) return 4; + } + } + }; + var TextureAtlasPage = class { + name; + minFilter = 9728 /* Nearest */; + magFilter = 9728 /* Nearest */; + uWrap = 33071 /* ClampToEdge */; + vWrap = 33071 /* ClampToEdge */; + texture = null; + width = 0; + height = 0; + pma = false; + regions = []; + constructor(name) { + this.name = name; + } + setTexture(texture) { + this.texture = texture; + texture.setFilters(this.minFilter, this.magFilter); + texture.setWraps(this.uWrap, this.vWrap); + for (const region of this.regions) + region.texture = texture; + } + }; + var TextureAtlasRegion = class extends TextureRegion { + page; + name; + x = 0; + y = 0; + offsetX = 0; + offsetY = 0; + originalWidth = 0; + originalHeight = 0; + index = 0; + degrees = 0; + names = null; + values = null; + constructor(page, name) { + super(); + this.page = page; + this.name = name; + page.regions.push(this); + } + }; + + // spine-core/src/attachments/Attachment.ts + var Attachment = class _Attachment { + static empty = []; + name; + /** Timelines for the timeline attachment are also applied to this attachment. + * @return May be null if no attachment-specific timelines should be applied. */ + timelineAttachment; + /** Slots that can have attachments whose {@link timelineAttachment} is this attachment. */ + timelineSlots = _Attachment.empty; + constructor(name) { + if (!name) throw new Error("name cannot be null."); + this.name = name; + this.timelineAttachment = this; + } + /** Returns true if the {@code slotIndex} or any {@link timelineSlots} have an attachment whose {@link timelineAttachment} is + * this attachment. + * @param slots The {@link Skeleton.slots}. + * @param slotIndex The timeline's primary slot index. */ + isTimelineActive(slots, slotIndex, appliedPose) { + let slot = slots[slotIndex]; + if (slot.bone.isActive()) { + const other = (appliedPose ? slot.getAppliedPose() : slot.getPose()).getAttachment(); + if (other != null && other.timelineAttachment === this) return true; + } + for (let i = 0, n = this.timelineSlots.length; i < n; i++) { + slot = slots[this.timelineSlots[i]]; + if (!slot.bone.isActive()) continue; + const other = (appliedPose ? slot.getAppliedPose() : slot.getPose()).getAttachment(); + if (other != null && other.timelineAttachment === this) return true; + } + return false; + } + }; + var VertexAttachment = class _VertexAttachment extends Attachment { + static nextID = 0; + /** The unique ID for this attachment. */ + id = _VertexAttachment.nextID++; + /** The bones that affect the {@link vertices}. The entries are, for each vertex, the number of bones affecting the vertex + * followed by that many bone indices, which is {@link Skeleton.getBones} index. Null if this attachment has no weights. */ + bones = null; + /** The vertex positions in the bone's coordinate system. For a non-weighted attachment, the values are `x,y` + * entries for each vertex. For a weighted attachment, the values are `x,y,weight` triplets for each bone affecting + * each vertex. */ + vertices = []; + /** The maximum number of world vertex values that can be output by + * {@link computeWorldVertices} using the `count` parameter. */ + worldVerticesLength = 0; + constructor(name) { + super(name); + } + /** Transforms the attachment's local {@link vertices} to world coordinates. If {@link SlotPose.getDeform} is not empty, it + * is used to deform the vertices. + * + * See World transforms in the Spine + * Runtimes Guide. + * @param start The index of the first {@link vertices} value to transform. Each vertex has 2 values, x and y. + * @param count The number of world vertex values to output. Must be <= {@link worldVerticesLength} - `start`. + * @param worldVertices The output world vertices. Must have a length >= `offset` + `count` * + * `stride` / 2. + * @param offset The `worldVertices` index to begin writing values. + * @param stride The number of `worldVertices` entries between the value pairs written. */ + computeWorldVertices(skeleton, slot, start, count, worldVertices2, offset, stride) { + count = offset + (count >> 1) * stride; + const deformArray = slot.appliedPose.deform; + let vertices = this.vertices; + const bones = this.bones; + if (!bones) { + if (deformArray.length > 0) vertices = deformArray; + const bone = slot.bone.appliedPose; + const x = bone.worldX; + const y = bone.worldY; + const a = bone.a, b = bone.b, c = bone.c, d = bone.d; + for (let v2 = start, w = offset; w < count; v2 += 2, w += stride) { + const vx = vertices[v2], vy = vertices[v2 + 1]; + worldVertices2[w] = vx * a + vy * b + x; + worldVertices2[w + 1] = vx * c + vy * d + y; + } + return; + } + let v = 0, skip = 0; + for (let i = 0; i < start; i += 2) { + const n = bones[v]; + v += n + 1; + skip += n; + } + const skeletonBones = skeleton.bones; + if (deformArray.length === 0) { + for (let w = offset, b = skip * 3; w < count; w += stride) { + let wx = 0, wy = 0; + let n = bones[v++]; + n += v; + for (; v < n; v++, b += 3) { + const bone = skeletonBones[bones[v]].appliedPose; + const vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices2[w] = wx; + worldVertices2[w + 1] = wy; + } + } else { + const deform = deformArray; + for (let w = offset, b = skip * 3, f = skip << 1; w < count; w += stride) { + let wx = 0, wy = 0; + let n = bones[v++]; + n += v; + for (; v < n; v++, b += 3, f += 2) { + const bone = skeletonBones[bones[v]].appliedPose; + const vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2]; + wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight; + wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight; + } + worldVertices2[w] = wx; + worldVertices2[w + 1] = wy; + } + } + } + /** Does not copy id (generated) or name (set on construction). **/ + copyTo(attachment) { + if (this.bones) { + attachment.bones = []; + Utils.arrayCopy(this.bones, 0, attachment.bones, 0, this.bones.length); + } else + attachment.bones = null; + if (this.vertices) { + attachment.vertices = Utils.newFloatArray(this.vertices.length); + Utils.arrayCopy(this.vertices, 0, attachment.vertices, 0, this.vertices.length); + } + attachment.worldVerticesLength = this.worldVerticesLength; + attachment.timelineAttachment = this.timelineAttachment; + attachment.timelineSlots = this.timelineSlots; + } + }; + + // spine-core/src/attachments/MeshAttachment.ts + var MeshAttachment = class _MeshAttachment extends VertexAttachment { + sequence; + /** The UV pair for each vertex, normalized within the texture region. */ + regionUVs = []; + /** Triplets of vertex indices which describe the mesh's triangulation. */ + triangles = []; + /** The number of entries at the beginning of {@link vertices} that make up the mesh hull. */ + hullLength = 0; + /** The name of the texture region for this attachment. */ + path; + /** The color to tint the mesh. */ + color = new Color(1, 1, 1, 1); + sourceMesh = null; + /** Vertex index pairs describing edges for controlling triangulation, or null if nonessential data was not exported. Mesh + * triangles do not never cross edges. Triangulation is not performed at runtime. */ + edges = []; + /** The width of the mesh's image. Available only when nonessential data was exported. */ + width = 0; + /** The height of the mesh's image. Available only when nonessential data was exported. */ + height = 0; + tempColor = new Color(0, 0, 0, 0); + constructor(name, sequence) { + super(name); + this.sequence = sequence; + } + copy() { + if (this.sourceMesh) return this.newLinkedMesh(); + const copy = new _MeshAttachment(this.name, this.sequence.copy()); + copy.path = this.path; + copy.color.setFromColor(this.color); + this.copyTo(copy); + copy.regionUVs = []; + Utils.arrayCopy(this.regionUVs, 0, copy.regionUVs, 0, this.regionUVs.length); + copy.triangles = []; + Utils.arrayCopy(this.triangles, 0, copy.triangles, 0, this.triangles.length); + copy.hullLength = this.hullLength; + if (this.edges) { + copy.edges = []; + Utils.arrayCopy(this.edges, 0, copy.edges, 0, this.edges.length); + } + copy.width = this.width; + copy.height = this.height; + return copy; + } + updateSequence() { + this.sequence.update(this); + } + /** The source mesh if this is a linked mesh, else null. A linked mesh shares the {@link bones}, {@link vertices}, + * {@link regionUVs}, {@link triangles}, {@link hullLength}, {@link edges}, {@link width}, and {@link height} with the + * source mesh, but may have a different {@link name} or {@link path}, and therefore a different texture region. */ + getSourceMesh() { + return this.sourceMesh; + } + setSourceMesh(sourceMesh) { + this.sourceMesh = sourceMesh; + if (sourceMesh) { + this.bones = sourceMesh.bones; + this.vertices = sourceMesh.vertices; + this.worldVerticesLength = sourceMesh.worldVerticesLength; + this.regionUVs = sourceMesh.regionUVs; + this.triangles = sourceMesh.triangles; + this.hullLength = sourceMesh.hullLength; + this.worldVerticesLength = sourceMesh.worldVerticesLength; + this.edges = sourceMesh.edges; + this.width = sourceMesh.width; + this.height = sourceMesh.height; + } + } + /** Returns a new mesh with the {@link sourceMesh} set to this mesh's source mesh, if any, else to this mesh. **/ + newLinkedMesh() { + const copy = new _MeshAttachment(this.name, this.sequence.copy()); + copy.timelineAttachment = this.timelineAttachment; + copy.path = this.path; + copy.color.setFromColor(this.color); + copy.setSourceMesh(this.sourceMesh ? this.sourceMesh : this); + copy.updateSequence(); + return copy; + } + /** Computes {@link Sequence.getUVs | UVs} for a mesh attachment. + * @param uvs Output array for the computed UVs, same length as regionUVs. */ + static computeUVs(region, regionUVs, uvs) { + if (!region) throw new Error("Region not set."); + const n = uvs.length; + let u = region.u, v = region.v, width = 0, height = 0; + if (region instanceof TextureAtlasRegion) { + const page = region.page; + const textureWidth = page.width, textureHeight = page.height; + switch (region.degrees) { + case 90: + u -= (region.originalHeight - region.offsetY - region.height) / textureWidth; + v -= (region.originalWidth - region.offsetX - region.width) / textureHeight; + width = region.originalHeight / textureWidth; + height = region.originalWidth / textureHeight; + for (let i = 0; i < n; i += 2) { + uvs[i] = u + regionUVs[i + 1] * width; + uvs[i + 1] = v + (1 - regionUVs[i]) * height; + } + return; + case 180: + u -= (region.originalWidth - region.offsetX - region.width) / textureWidth; + v -= region.offsetY / textureHeight; + width = region.originalWidth / textureWidth; + height = region.originalHeight / textureHeight; + for (let i = 0; i < n; i += 2) { + uvs[i] = u + (1 - regionUVs[i]) * width; + uvs[i + 1] = v + (1 - regionUVs[i + 1]) * height; + } + return; + case 270: + u -= region.offsetY / textureWidth; + v -= region.offsetX / textureHeight; + width = region.originalHeight / textureWidth; + height = region.originalWidth / textureHeight; + for (let i = 0; i < n; i += 2) { + uvs[i] = u + (1 - regionUVs[i + 1]) * width; + uvs[i + 1] = v + regionUVs[i] * height; + } + return; + default: + u -= region.offsetX / textureWidth; + v -= (region.originalHeight - region.offsetY - region.height) / textureHeight; + width = region.originalWidth / textureWidth; + height = region.originalHeight / textureHeight; + } + } else if (!region) { + u = v = 0; + width = height = 1; + } else { + width = region.u2 - u; + height = region.v2 - v; + } + for (let i = 0; i < n; i += 2) { + uvs[i] = u + regionUVs[i] * width; + uvs[i + 1] = v + regionUVs[i + 1] * height; + } + } + }; + + // spine-core/src/attachments/RegionAttachment.ts + var RegionAttachment = class _RegionAttachment extends Attachment { + sequence; + /** The local x translation. */ + x = 0; + /** The local y translation. */ + y = 0; + /** The local scaleX. */ + scaleX = 1; + /** The local scaleY. */ + scaleY = 1; + /** The local rotation in degrees, counter clockwise. */ + rotation = 0; + /** The width of the region attachment in Spine. */ + width = 0; + /** The height of the region attachment in Spine. */ + height = 0; + /** The name of the texture region for this attachment. */ + path; + /** The color to tint the region attachment. */ + color = new Color(1, 1, 1, 1); + tempColor = new Color(1, 1, 1, 1); + constructor(name, sequence) { + super(name); + this.sequence = sequence; + } + copy() { + const copy = new _RegionAttachment(this.name, this.sequence.copy()); + copy.path = this.path; + copy.x = this.x; + copy.y = this.y; + copy.scaleX = this.scaleX; + copy.scaleY = this.scaleY; + copy.rotation = this.rotation; + copy.width = this.width; + copy.height = this.height; + copy.color.setFromColor(this.color); + return copy; + } + /** Transforms the attachment's four vertices to world coordinates. + * + * See World transforms in the Spine + * Runtimes Guide. + * @param worldVertices The output world vertices. Must have a length >= `offset` + 8. + * @param offset The `worldVertices` index to begin writing values. + * @param stride The number of `worldVertices` entries between the value pairs written. */ + computeWorldVertices(slot, vertexOffsets, worldVertices2, offset, stride) { + const bone = slot.bone.appliedPose; + const x = bone.worldX, y = bone.worldY; + const a = bone.a, b = bone.b, c = bone.c, d = bone.d; + let offsetX = vertexOffsets[0]; + let offsetY = vertexOffsets[1]; + worldVertices2[offset] = offsetX * a + offsetY * b + x; + worldVertices2[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffsets[2]; + offsetY = vertexOffsets[3]; + worldVertices2[offset] = offsetX * a + offsetY * b + x; + worldVertices2[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffsets[4]; + offsetY = vertexOffsets[5]; + worldVertices2[offset] = offsetX * a + offsetY * b + x; + worldVertices2[offset + 1] = offsetX * c + offsetY * d + y; + offset += stride; + offsetX = vertexOffsets[6]; + offsetY = vertexOffsets[7]; + worldVertices2[offset] = offsetX * a + offsetY * b + x; + worldVertices2[offset + 1] = offsetX * c + offsetY * d + y; + } + getOffsets(pose) { + return this.sequence.offsets[this.sequence.resolveIndex(pose)]; + } + updateSequence() { + this.sequence.update(this); + } + /** Computes {@link Sequence.getUVs | UVs} and {@link Sequence.getOffsets | offsets} for a region attachment. + * @param uvs Output array for the computed UVs, length of 8. + * @param offset Output array for the computed vertex offsets, length of 8. */ + static computeUVs(region, x, y, scaleX, scaleY, rotation, width, height, offset, uvs) { + if (!region) throw new Error("Region not set."); + const regionScaleX = width / region.originalWidth * scaleX; + const regionScaleY = height / region.originalHeight * scaleY; + const localX = -width / 2 * scaleX + region.offsetX * regionScaleX; + const localY = -height / 2 * scaleY + region.offsetY * regionScaleY; + const localX2 = localX + region.width * regionScaleX; + const localY2 = localY + region.height * regionScaleY; + const radians = rotation * MathUtils.degRad; + const cos = Math.cos(radians); + const sin = Math.sin(radians); + const localXCos = localX * cos + x; + const localXSin = localX * sin; + const localYCos = localY * cos + y; + const localYSin = localY * sin; + const localX2Cos = localX2 * cos + x; + const localX2Sin = localX2 * sin; + const localY2Cos = localY2 * cos + y; + const localY2Sin = localY2 * sin; + offset[0] = localXCos - localYSin; + offset[1] = localYCos + localXSin; + offset[2] = localXCos - localY2Sin; + offset[3] = localY2Cos + localXSin; + offset[4] = localX2Cos - localY2Sin; + offset[5] = localY2Cos + localX2Sin; + offset[6] = localX2Cos - localYSin; + offset[7] = localYCos + localX2Sin; + if (region == null) { + uvs[0] = 0; + uvs[1] = 0; + uvs[2] = 0; + uvs[3] = 1; + uvs[4] = 1; + uvs[5] = 1; + uvs[6] = 1; + uvs[7] = 0; + } else { + uvs[1] = region.v2; + uvs[2] = region.u; + uvs[5] = region.v; + uvs[6] = region.u2; + if (region.degrees === 90) { + uvs[0] = region.u2; + uvs[3] = region.v2; + uvs[4] = region.u; + uvs[7] = region.v; + } else { + uvs[0] = region.u; + uvs[3] = region.v; + uvs[4] = region.u2; + uvs[7] = region.v2; + } + } + } + static X1 = 0; + static Y1 = 1; + static C1R = 2; + static C1G = 3; + static C1B = 4; + static C1A = 5; + static U1 = 6; + static V1 = 7; + static X2 = 8; + static Y2 = 9; + static C2R = 10; + static C2G = 11; + static C2B = 12; + static C2A = 13; + static U2 = 14; + static V2 = 15; + static X3 = 16; + static Y3 = 17; + static C3R = 18; + static C3G = 19; + static C3B = 20; + static C3A = 21; + static U3 = 22; + static V3 = 23; + static X4 = 24; + static Y4 = 25; + static C4R = 26; + static C4G = 27; + static C4B = 28; + static C4A = 29; + static U4 = 30; + static V4 = 31; + }; + + // spine-core/src/attachments/Sequence.ts + var Sequence = class _Sequence { + static _nextID = 0; + id = _Sequence.nextID(); + /** The list of texture regions this sequence will display. */ + regions; + pathSuffix; + uvs; + /** Returns vertex offsets from the center of a {@link RegionAttachment}. Invalid to call for a {@link MeshAttachment}. */ + offsets; + /** The starting number for the numeric {@link getPath | path} suffix. */ + start = 0; + /** The minimum number of digits in the numeric {@link getPath | path} suffix, for zero padding. 0 for no zero + * padding. */ + digits = 0; + /** The index of the region to show for the setup pose. */ + setupIndex = 0; + /** @param count The number of texture regions this sequence will display. + * @param pathSuffix If true, the {@link getPath | path} has a numeric suffix. If false, all regions will use the + * same path, so `count` should be 1. */ + constructor(count, pathSuffix) { + this.regions = new Array(count); + this.pathSuffix = pathSuffix; + } + copy() { + const regionCount = this.regions.length; + const copy = new _Sequence(regionCount, this.pathSuffix); + Utils.arrayCopy(this.regions, 0, copy.regions, 0, regionCount); + copy.start = this.start; + copy.digits = this.digits; + copy.setupIndex = this.setupIndex; + if (this.uvs != null) { + const length = this.uvs[0].length; + copy.uvs = []; + for (let i = 0; i < regionCount; i++) { + copy.uvs[i] = Utils.newFloatArray(length); + Utils.arrayCopy(this.uvs[i], 0, copy.uvs[i], 0, length); + } + } + if (this.offsets != null) { + copy.offsets = []; + for (let i = 0; i < regionCount; i++) { + copy.offsets[i] = []; + Utils.arrayCopy(this.offsets[i], 0, copy.offsets[i], 0, 8); + } + } + return copy; + } + /** Computes UVs and offsets for the specified attachment. Must be called if the regions or attachment properties are + * changed. */ + update(attachment) { + const regionCount = this.regions.length; + if (attachment instanceof RegionAttachment) { + this.uvs = []; + this.offsets = []; + for (let i = 0; i < regionCount; i++) { + this.uvs[i] = Utils.newFloatArray(8); + this.offsets[i] = []; + RegionAttachment.computeUVs( + this.regions[i], + attachment.x, + attachment.y, + attachment.scaleX, + attachment.scaleY, + attachment.rotation, + attachment.width, + attachment.height, + this.offsets[i], + this.uvs[i] + ); + } + } else if (attachment instanceof MeshAttachment) { + const regionUVs = attachment.regionUVs; + this.uvs = []; + this.offsets = void 0; + for (let i = 0; i < regionCount; i++) { + this.uvs[i] = Utils.newFloatArray(regionUVs.length); + MeshAttachment.computeUVs(this.regions[i], regionUVs, this.uvs[i]); + } + } + } + /** Returns the {@link regions} index for the {@link SlotPose.getSequenceIndex}. */ + resolveIndex(pose) { + let index = pose.sequenceIndex; + if (index === -1) index = this.setupIndex; + if (index >= this.regions.length) index = this.regions.length - 1; + return index; + } + /** Returns the UVs for the specified index. {@link regions Regions} must be populated and {@link update} called + * before calling this method. */ + getUVs(index) { + return this.uvs[index]; + } + /** Returns true if the {@link getPath | path} has a numeric suffix. */ + hasPathSuffix() { + return this.pathSuffix; + } + /** Returns the specified base path with an optional numeric suffix for the specified index. */ + getPath(basePath, index) { + if (!this.pathSuffix) return basePath; + let result = basePath; + const frame = (this.start + index).toString(); + for (let i = this.digits - frame.length; i > 0; i--) + result += "0"; + result += frame; + return result; + } + static nextID() { + return _Sequence._nextID++; + } + }; + var SequenceMode = /* @__PURE__ */ ((SequenceMode2) => { + SequenceMode2[SequenceMode2["hold"] = 0] = "hold"; + SequenceMode2[SequenceMode2["once"] = 1] = "once"; + SequenceMode2[SequenceMode2["loop"] = 2] = "loop"; + SequenceMode2[SequenceMode2["pingpong"] = 3] = "pingpong"; + SequenceMode2[SequenceMode2["onceReverse"] = 4] = "onceReverse"; + SequenceMode2[SequenceMode2["loopReverse"] = 5] = "loopReverse"; + SequenceMode2[SequenceMode2["pingpongReverse"] = 6] = "pingpongReverse"; + return SequenceMode2; + })(SequenceMode || {}); + var SequenceModeValues = [ + 0 /* hold */, + 1 /* once */, + 2 /* loop */, + 3 /* pingpong */, + 4 /* onceReverse */, + 5 /* loopReverse */, + 6 /* pingpongReverse */ + ]; + + // spine-core/src/Animation.ts + var Animation = class { + /** The animation's name, unique across all animations in the skeleton. + * + * See {@link SkeletonData.findAnimation}. */ + name; + /** The duration of the animation in seconds, which is usually the highest time of all frames in the timelines. The duration is + * used to know when the animation has completed and, for animations that repeat, when it should loop back to the start. */ + timelines = []; + timelineIds; + /** {@link Skeleton.getBones} indices that this animation's timelines modify. + * + * See {@link BoneTimeline.bones}. */ + bones; + // Nonessential. + /** The color of the animation as it was in Spine, or a default color if nonessential data was not exported. */ + color = new Color(1, 1, 1, 1); + /** The duration of the animation in seconds, which is usually the highest time of all frames in the timeline. The duration is + * used to know when it has completed and when it should loop back to the start. */ + duration; + constructor(name, timelines, duration) { + if (!name) throw new Error("name cannot be null."); + this.name = name; + this.duration = duration; + this.timelineIds = new StringSet(); + this.bones = []; + this.setTimelines(timelines); + } + setTimelines(timelines) { + if (!timelines) throw new Error("timelines cannot be null."); + this.timelines = timelines; + const n = timelines.length; + this.timelineIds.clear(); + this.bones.length = 0; + const boneSet = /* @__PURE__ */ new Set(); + const items = timelines; + for (let i = 0; i < n; i++) { + const timeline = items[i]; + this.timelineIds.addAll(timeline.propertyIds); + if (isBoneTimeline(timeline) && boneSet.add(timeline.boneIndex)) + this.bones.push(timeline.boneIndex); + } + } + /** Returns true if this animation contains a timeline with any of the specified property IDs. + * + * See {@link Timeline.propertyIds}. */ + hasTimeline(ids) { + for (let i = 0; i < ids.length; i++) + if (this.timelineIds.contains(ids[i])) return true; + return false; + } + /** Applies the animation's timelines to the specified skeleton. + * + * See {@link Timeline.apply} and + * Applying Animations in the Spine Runtimes + * Guide. + * @param skeleton The skeleton the animation is applied to. This provides access to the bones, slots, and other skeleton + * components the timelines may change. + * @param lastTime The last time in seconds this animation was applied. Some timelines trigger only at discrete times, in which + * case all keys are triggered between `lastTime` (exclusive) and `time` (inclusive). Pass -1 + * the first time an animation is applied to ensure frame 0 is triggered. + * @param time The time in seconds the skeleton is being posed for. Timelines find the frame before and after this time and + * interpolate between the frame values. + * @param loop True if `time` beyond the {@link duration} repeats the animation, else the last frame is used. + * @param events If any events are fired, they are added to this list. Pass null to ignore fired events or if no timelines fire + * events. + * @param alpha 0 applies setup or current values (depending on `from`), 1 uses timeline values, and intermediate + * values interpolate between them. Adjusting `alpha` over time can mix an animation in or out. + * @param from Controls how `alpha` and `add` mix from current or setup pose values to timeline values. + * @param add If true, for timelines that support it, their values are added to the setup or current values (depending on + * `from`). + * @param out True when the animation is mixing out, else it is mixing in. Used by timelines that perform instant transitions. + * @param appliedPose True to modify {@link Posed.appliedPose}, else {@link Posed.pose} is modified. */ + apply(skeleton, lastTime, time, loop, events, alpha, from, add, out, appliedPose) { + if (!skeleton) throw new Error("skeleton cannot be null."); + if (loop && this.duration !== 0) { + time %= this.duration; + if (lastTime > 0) lastTime %= this.duration; + } + const timelines = this.timelines; + for (let i = 0, n = timelines.length; i < n; i++) + timelines[i].apply(skeleton, lastTime, time, events, alpha, from, add, out, appliedPose); + } + }; + var MixFrom = /* @__PURE__ */ ((MixFrom2) => { + MixFrom2[MixFrom2["current"] = 0] = "current"; + MixFrom2[MixFrom2["setup"] = 1] = "setup"; + MixFrom2[MixFrom2["first"] = 2] = "first"; + return MixFrom2; + })(MixFrom || {}); + var Property = /* @__PURE__ */ ((Property2) => { + Property2[Property2["rotate"] = 0] = "rotate"; + Property2[Property2["x"] = 1] = "x"; + Property2[Property2["y"] = 2] = "y"; + Property2[Property2["scaleX"] = 3] = "scaleX"; + Property2[Property2["scaleY"] = 4] = "scaleY"; + Property2[Property2["shearX"] = 5] = "shearX"; + Property2[Property2["shearY"] = 6] = "shearY"; + Property2[Property2["inherit"] = 7] = "inherit"; + Property2[Property2["rgb"] = 8] = "rgb"; + Property2[Property2["alpha"] = 9] = "alpha"; + Property2[Property2["rgb2"] = 10] = "rgb2"; + Property2[Property2["attachment"] = 11] = "attachment"; + Property2[Property2["deform"] = 12] = "deform"; + Property2[Property2["event"] = 13] = "event"; + Property2[Property2["drawOrder"] = 14] = "drawOrder"; + Property2[Property2["drawOrderFolder"] = 15] = "drawOrderFolder"; + Property2[Property2["ikConstraint"] = 16] = "ikConstraint"; + Property2[Property2["transformConstraint"] = 17] = "transformConstraint"; + Property2[Property2["pathConstraintPosition"] = 18] = "pathConstraintPosition"; + Property2[Property2["pathConstraintSpacing"] = 19] = "pathConstraintSpacing"; + Property2[Property2["pathConstraintMix"] = 20] = "pathConstraintMix"; + Property2[Property2["physicsConstraintInertia"] = 21] = "physicsConstraintInertia"; + Property2[Property2["physicsConstraintStrength"] = 22] = "physicsConstraintStrength"; + Property2[Property2["physicsConstraintDamping"] = 23] = "physicsConstraintDamping"; + Property2[Property2["physicsConstraintMass"] = 24] = "physicsConstraintMass"; + Property2[Property2["physicsConstraintWind"] = 25] = "physicsConstraintWind"; + Property2[Property2["physicsConstraintGravity"] = 26] = "physicsConstraintGravity"; + Property2[Property2["physicsConstraintMix"] = 27] = "physicsConstraintMix"; + Property2[Property2["physicsConstraintReset"] = 28] = "physicsConstraintReset"; + Property2[Property2["sequence"] = 29] = "sequence"; + Property2[Property2["sliderTime"] = 30] = "sliderTime"; + Property2[Property2["sliderMix"] = 31] = "sliderMix"; + return Property2; + })(Property || {}); + var Timeline = class { + propertyIds; + frames; + /** True if this timeline supports being applied additively. + * + * See the `add` parameter in {@link Timeline.apply}. */ + additive = false; + /** True if this timeline sets values instantaneously and does not support interpolation between frames. */ + instant = false; + constructor(frameCount, ...propertyIds) { + this.propertyIds = propertyIds; + this.frames = Utils.newFloatArray(frameCount * this.getFrameEntries()); + } + getPropertyIds() { + return this.propertyIds; + } + /** The number of values stored per frame. */ + getFrameEntries() { + return 1; + } + /** The number of frames in this timeline. */ + getFrameCount() { + return this.frames.length / this.getFrameEntries(); + } + /** The duration of the timeline in seconds, which is usually the highest time of all frames in the timeline. */ + getDuration() { + return this.frames[this.frames.length - this.getFrameEntries()]; + } + /** Linear search using the specified stride (default 1). + * @param time Must be >= the first value in `frames`. + * @return The index of the first value <= `time`. */ + static search(frames, time, step = 1) { + const n = frames.length; + for (let i = step; i < n; i += step) + if (frames[i] > time) return i - step; + return n - step; + } + }; + function isSlotTimeline(obj) { + return typeof obj === "object" && obj !== null && typeof obj.slotIndex === "number"; + } + var CurveTimeline = class extends Timeline { + curves; + // type, x, y, ... + constructor(frameCount, bezierCount, ...propertyIds) { + super(frameCount, ...propertyIds); + this.curves = Utils.newFloatArray( + frameCount + bezierCount * 18 + /*BEZIER_SIZE*/ + ); + this.curves[frameCount - 1] = 1; + } + /** Sets the specified key frame to linear interpolation. */ + setLinear(frame) { + this.curves[frame] = 0; + } + /** Sets the specified key frame to stepped interpolation. */ + setStepped(frame) { + this.curves[frame] = 1; + } + /** Shrinks the storage for Bezier curves, for use when `bezierCount` (specified in the constructor) was larger + * than the actual number of Bezier curves. */ + shrink(bezierCount) { + const size = this.getFrameCount() + bezierCount * 18; + if (this.curves.length > size) { + const newCurves = Utils.newFloatArray(size); + Utils.arrayCopy(this.curves, 0, newCurves, 0, size); + this.curves = newCurves; + } + } + /** Stores the segments for the specified Bezier curve. For timelines that modify multiple values, there may be more than + * one curve per frame. + * @param bezier The ordinal of this Bezier curve for this timeline, between 0 and `bezierCount - 1` (specified + * in the constructor), inclusive. + * @param frame Between 0 and `frameCount - 1`, inclusive. + * @param value The index of the value for this frame that this curve is used for. + * @param time1 The time for the first key. + * @param value1 The value for the first key. + * @param cx1 The time for the first Bezier handle. + * @param cy1 The value for the first Bezier handle. + * @param cx2 The time of the second Bezier handle. + * @param cy2 The value for the second Bezier handle. + * @param time2 The time for the second key. + * @param value2 The value for the second key. */ + setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2) { + const curves = this.curves; + let i = this.getFrameCount() + bezier * 18; + if (value === 0) curves[frame] = 2 + i; + const tmpx = (time1 - cx1 * 2 + cx2) * 0.03, tmpy = (value1 - cy1 * 2 + cy2) * 0.03; + const dddx = ((cx1 - cx2) * 3 - time1 + time2) * 6e-3, dddy = ((cy1 - cy2) * 3 - value1 + value2) * 6e-3; + let ddx = tmpx * 2 + dddx, ddy = tmpy * 2 + dddy; + let dx = (cx1 - time1) * 0.3 + tmpx + dddx * 0.16666667, dy = (cy1 - value1) * 0.3 + tmpy + dddy * 0.16666667; + let x = time1 + dx, y = value1 + dy; + for (let n = i + 18; i < n; i += 2) { + curves[i] = x; + curves[i + 1] = y; + dx += ddx; + dy += ddy; + ddx += dddx; + ddy += dddy; + x += dx; + y += dy; + } + } + /** Returns the Bezier interpolated value for the specified time. + * @param frameIndex The index into {@link frames} for the values of the frame before `time`. + * @param valueOffset The offset from `frameIndex` to the value this curve is used for. + * @param i The index of the Bezier segments. See {@link getCurveType}. */ + getBezierValue(time, frameIndex, valueOffset, i) { + const curves = this.curves; + if (curves[i] > time) { + const x2 = this.frames[frameIndex], y2 = this.frames[frameIndex + valueOffset]; + return y2 + (time - x2) / (curves[i] - x2) * (curves[i + 1] - y2); + } + const n = i + 18; + for (i += 2; i < n; i += 2) { + if (curves[i] >= time) { + const x2 = curves[i - 2], y2 = curves[i - 1]; + return y2 + (time - x2) / (curves[i] - x2) * (curves[i + 1] - y2); + } + } + frameIndex += this.getFrameEntries(); + const x = curves[n - 2], y = curves[n - 1]; + return y + (time - x) / (this.frames[frameIndex] - x) * (this.frames[frameIndex + valueOffset] - y); + } + }; + var CurveTimeline1 = class _CurveTimeline1 extends CurveTimeline { + constructor(frameCount, bezierCount, propertyId) { + super(frameCount, bezierCount, propertyId); + } + getFrameEntries() { + return 2; + } + /** Sets the time and value for the specified frame. + * @param frame Between 0 and `frameCount`, inclusive. + * @param time The frame time in seconds. */ + setFrame(frame, time, value) { + frame <<= 1; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*VALUE*/ + ] = value; + } + /** Returns the interpolated value for the specified time. */ + getCurveValue(time) { + const frames = this.frames; + let i = frames.length - 2; + for (let ii = 2; ii <= i; ii += 2) { + if (frames[ii] > time) { + i = ii - 2; + break; + } + } + const curveType = this.curves[i >> 1]; + switch (curveType) { + case 0: { + const before = frames[i], value = frames[ + i + 1 + /*VALUE*/ + ]; + return value + (time - before) / (frames[ + i + 2 + /*ENTRIES*/ + ] - before) * (frames[ + i + 2 + 1 + /*VALUE*/ + ] - value); + } + case 1: + return frames[ + i + 1 + /*VALUE*/ + ]; + } + return this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + } + /** Returns the interpolated value for properties relative to the setup value. The timeline value is added to the setup + * value, rather than replacing it. + * + * See {@link Timeline.apply}. + * @param current The current value for the property. + * @param setup The setup value for the property. */ + getRelativeValue(time, alpha, from, add, current, setup) { + if (time < this.frames[0]) return _CurveTimeline1.beforeFirstKey(from, alpha, current, setup); + const value = this.getCurveValue(time); + return from === 1 /* setup */ ? setup + value * alpha : current + (add ? value : value + setup - current) * alpha; + } + getAbsoluteValue(time, alpha, from, add, current, setup, value) { + if (value === void 0) + return this.getAbsoluteValue1(time, alpha, from, add, current, setup); + else + return this.getAbsoluteValue2(time, alpha, from, add, current, setup, value); + } + getAbsoluteValue1(time, alpha, from, add, current, setup) { + if (time < this.frames[0]) return _CurveTimeline1.beforeFirstKey(from, alpha, current, setup); + const value = this.getCurveValue(time); + return from === 1 /* setup */ ? setup + (add ? value : value - setup) * alpha : current + (add ? value : value - current) * alpha; + } + getAbsoluteValue2(time, alpha, from, add, current, setup, value) { + if (time < this.frames[0]) return _CurveTimeline1.beforeFirstKey(from, alpha, current, setup); + return from === 1 /* setup */ ? setup + (add ? value : value - setup) * alpha : current + (add ? value : value - current) * alpha; + } + /** Returns the interpolated value for scale properties. The timeline and setup values are multiplied and sign adjusted. + * + * See {@link Timeline.apply}. + * @param current The current value for the property. + * @param setup The setup value for the property. */ + getScaleValue(time, alpha, from, add, out, current, setup) { + if (time < this.frames[0]) return _CurveTimeline1.beforeFirstKey(from, alpha, current, setup); + const value = this.getCurveValue(time) * setup; + if (alpha === 1 && !add) return value; + let base = from === 1 /* setup */ ? setup : current; + if (add) return base + (value - setup) * alpha; + if (out) return base + (Math.abs(value) * Math.sign(base) - base) * alpha; + base = Math.abs(base) * Math.sign(value); + return base + (value - base) * alpha; + } + static beforeFirstKey(from, alpha, current, setup) { + switch (from) { + case 1 /* setup */: + return setup; + case 2 /* first */: + return current + (setup - current) * alpha; + case 0 /* current */: + return current; + } + } + }; + function isBoneTimeline(obj) { + return typeof obj === "object" && obj !== null && typeof obj.boneIndex === "number"; + } + var BoneTimeline1 = class extends CurveTimeline1 { + boneIndex; + constructor(frameCount, bezierCount, boneIndex, property) { + super(frameCount, bezierCount, `${property}|${boneIndex}`); + this.boneIndex = boneIndex; + this.additive = true; + } + apply(skeleton, lastTime, time, events, alpha, from, add, out, appliedPose) { + const bone = skeleton.bones[this.boneIndex]; + if (bone.active) + this.apply1(appliedPose ? bone.appliedPose : bone.pose, bone.data.setupPose, time, alpha, from, add, out); + } + }; + var BoneTimeline2 = class extends CurveTimeline { + boneIndex; + /** @param bezierCount The maximum number of Bezier curves. See {@link shrink}. + * @param propertyIds Unique identifiers for the properties the timeline modifies. */ + constructor(frameCount, bezierCount, boneIndex, property1, property2) { + super(frameCount, bezierCount, `${property1}|${boneIndex}`, `${property2}|${boneIndex}`); + this.boneIndex = boneIndex; + this.additive = true; + } + getFrameEntries() { + return 3; + } + /** Sets the time and values for the specified frame. + * @param frame Between 0 and `frameCount`, inclusive. + * @param time The frame time in seconds. */ + setFrame(frame, time, value1, value2) { + frame *= 3; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*VALUE1*/ + ] = value1; + this.frames[ + frame + 2 + /*VALUE2*/ + ] = value2; + } + apply(skeleton, lastTime, time, events, alpha, from, add, out, appliedPose) { + const bone = skeleton.bones[this.boneIndex]; + if (bone.active) + this.apply1(appliedPose ? bone.appliedPose : bone.pose, bone.data.setupPose, time, alpha, from, add, out); + } + }; + var RotateTimeline = class extends BoneTimeline1 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, boneIndex, 0 /* rotate */); + } + apply1(pose, setup, time, alpha, from, add, out) { + pose.rotation = this.getRelativeValue(time, alpha, from, add, pose.rotation, setup.rotation); + } + }; + var TranslateTimeline = class extends BoneTimeline2 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, boneIndex, 1 /* x */, 2 /* y */); + } + apply1(pose, setup, time, alpha, from, add, out) { + const frames = this.frames; + if (time < frames[0]) { + switch (from) { + case 1 /* setup */: + pose.x = setup.x; + pose.y = setup.y; + break; + case 2 /* first */: + pose.x += (setup.x - pose.x) * alpha; + pose.y += (setup.y - pose.y) * alpha; + break; + } + return; + } + let x = 0, y = 0; + const i = Timeline.search( + frames, + time, + 3 + /*ENTRIES*/ + ); + const curveType = this.curves[ + i / 3 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: { + const before = frames[i]; + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + const t = (time - before) / (frames[ + i + 3 + /*ENTRIES*/ + ] - before); + x += (frames[ + i + 3 + 1 + /*VALUE1*/ + ] - x) * t; + y += (frames[ + i + 3 + 2 + /*VALUE2*/ + ] - y) * t; + break; + } + case 1: + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + break; + default: + x = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + y = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + } + if (from === 1 /* setup */) { + pose.x = setup.x + x * alpha; + pose.y = setup.y + y * alpha; + } else if (add) { + pose.x += x * alpha; + pose.y += y * alpha; + } else { + pose.x += (setup.x + x - pose.x) * alpha; + pose.y += (setup.y + y - pose.y) * alpha; + } + } + }; + var TranslateXTimeline = class extends BoneTimeline1 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, boneIndex, 1 /* x */); + } + apply1(pose, setup, time, alpha, from, add, out) { + pose.x = this.getRelativeValue(time, alpha, from, add, pose.x, setup.x); + } + }; + var TranslateYTimeline = class extends BoneTimeline1 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, boneIndex, 2 /* y */); + } + apply1(pose, setup, time, alpha, from, add, out) { + pose.y = this.getRelativeValue(time, alpha, from, add, pose.y, setup.y); + } + }; + var ScaleTimeline = class extends BoneTimeline2 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, boneIndex, 3 /* scaleX */, 4 /* scaleY */); + } + apply1(pose, setup, time, alpha, from, add, out) { + const frames = this.frames; + if (time < frames[0]) { + switch (from) { + case 1 /* setup */: + pose.scaleX = setup.scaleX; + pose.scaleY = setup.scaleY; + break; + case 2 /* first */: + pose.scaleX += (setup.scaleX - pose.scaleX) * alpha; + pose.scaleY += (setup.scaleY - pose.scaleY) * alpha; + break; + } + return; + } + let x, y; + const i = Timeline.search( + frames, + time, + 3 + /*ENTRIES*/ + ); + const curveType = this.curves[ + i / 3 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: { + const before = frames[i]; + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + const t = (time - before) / (frames[ + i + 3 + /*ENTRIES*/ + ] - before); + x += (frames[ + i + 3 + 1 + /*VALUE1*/ + ] - x) * t; + y += (frames[ + i + 3 + 2 + /*VALUE2*/ + ] - y) * t; + break; + } + case 1: + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + break; + default: + x = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + y = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + } + x *= setup.scaleX; + y *= setup.scaleY; + if (alpha === 1 && !add) { + pose.scaleX = x; + pose.scaleY = y; + } else { + let bx = 0, by = 0; + if (from === 1 /* setup */) { + bx = setup.scaleX; + by = setup.scaleY; + } else { + bx = pose.scaleX; + by = pose.scaleY; + } + if (add) { + pose.scaleX = bx + (x - setup.scaleX) * alpha; + pose.scaleY = by + (y - setup.scaleY) * alpha; + } else if (out) { + pose.scaleX = bx + (Math.abs(x) * Math.sign(bx) - bx) * alpha; + pose.scaleY = by + (Math.abs(y) * Math.sign(by) - by) * alpha; + } else { + bx = Math.abs(bx) * Math.sign(x); + by = Math.abs(by) * Math.sign(y); + pose.scaleX = bx + (x - bx) * alpha; + pose.scaleY = by + (y - by) * alpha; + } + } + } + }; + var ScaleXTimeline = class extends BoneTimeline1 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, boneIndex, 3 /* scaleX */); + } + apply1(pose, setup, time, alpha, from, add, out) { + pose.scaleX = this.getScaleValue(time, alpha, from, add, out, pose.scaleX, setup.scaleX); + } + }; + var ScaleYTimeline = class extends BoneTimeline1 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, boneIndex, 4 /* scaleY */); + } + apply1(pose, setup, time, alpha, from, add, out) { + pose.scaleY = this.getScaleValue(time, alpha, from, add, out, pose.scaleY, setup.scaleY); + } + }; + var ShearTimeline = class extends BoneTimeline2 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, boneIndex, 5 /* shearX */, 6 /* shearY */); + } + apply1(pose, setup, time, alpha, from, add, out) { + const frames = this.frames; + if (time < frames[0]) { + switch (from) { + case 1 /* setup */: + pose.shearX = setup.shearX; + pose.shearY = setup.shearY; + break; + case 2 /* first */: + pose.shearX += (setup.shearX - pose.shearX) * alpha; + pose.shearY += (setup.shearY - pose.shearY) * alpha; + break; + } + return; + } + let x = 0, y = 0; + const i = Timeline.search( + frames, + time, + 3 + /*ENTRIES*/ + ); + const curveType = this.curves[ + i / 3 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: { + const before = frames[i]; + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + const t = (time - before) / (frames[ + i + 3 + /*ENTRIES*/ + ] - before); + x += (frames[ + i + 3 + 1 + /*VALUE1*/ + ] - x) * t; + y += (frames[ + i + 3 + 2 + /*VALUE2*/ + ] - y) * t; + break; + } + case 1: + x = frames[ + i + 1 + /*VALUE1*/ + ]; + y = frames[ + i + 2 + /*VALUE2*/ + ]; + break; + default: + x = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + y = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + } + if (from === 1 /* setup */) { + pose.shearX = setup.shearX + x * alpha; + pose.shearY = setup.shearY + y * alpha; + } else if (add) { + pose.shearX += x * alpha; + pose.shearY += y * alpha; + } else { + pose.shearX += (setup.shearX + x - pose.shearX) * alpha; + pose.shearY += (setup.shearY + y - pose.shearY) * alpha; + } + } + }; + var ShearXTimeline = class extends BoneTimeline1 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, boneIndex, 5 /* shearX */); + } + apply1(pose, setup, time, alpha, from, add, out) { + pose.shearX = this.getRelativeValue(time, alpha, from, add, pose.shearX, setup.shearX); + } + }; + var ShearYTimeline = class extends BoneTimeline1 { + constructor(frameCount, bezierCount, boneIndex) { + super(frameCount, bezierCount, boneIndex, 6 /* shearY */); + } + apply1(pose, setup, time, alpha, from, add, out) { + pose.shearY = this.getRelativeValue(time, alpha, from, add, pose.shearY, setup.shearY); + } + }; + var InheritTimeline = class extends Timeline { + boneIndex; + constructor(frameCount, boneIndex) { + super(frameCount, `${7 /* inherit */}|${boneIndex}`); + this.boneIndex = boneIndex; + this.instant = true; + } + getFrameEntries() { + return 2; + } + /** Sets the inherit transform mode for the specified frame. + * @param frame Between 0 and `frameCount`, inclusive. + * @param time The frame time in seconds. */ + setFrame(frame, time, inherit) { + frame *= 2; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*INHERIT*/ + ] = inherit; + } + apply(skeleton, lastTime, time, events, alpha, from, add, out, appliedPose) { + const bone = skeleton.bones[this.boneIndex]; + if (!bone.active) return; + const pose = appliedPose ? bone.appliedPose : bone.pose; + if (out) { + if (from !== 0 /* current */) pose.inherit = bone.data.setupPose.inherit; + } else { + const frames = this.frames; + if (time < frames[0]) { + if (from !== 0 /* current */) pose.inherit = bone.data.setupPose.inherit; + } else + pose.inherit = this.frames[ + Timeline.search( + frames, + time, + 2 + /*ENTRIES*/ + ) + 1 + /*INHERIT*/ + ]; + } + } + }; + var SlotCurveTimeline = class extends CurveTimeline { + slotIndex; + constructor(frameCount, bezierCount, slotIndex, ...propertyIds) { + super(frameCount, bezierCount, ...propertyIds); + this.slotIndex = slotIndex; + } + apply(skeleton, lastTime, time, events, alpha, from, add, out, appliedPose) { + const slot = skeleton.slots[this.slotIndex]; + if (slot.bone.active) this.apply1(slot, appliedPose ? slot.appliedPose : slot.pose, time, alpha, from, add); + } + }; + var RGBATimeline = class extends SlotCurveTimeline { + constructor(frameCount, bezierCount, slotIndex) { + super( + frameCount, + bezierCount, + slotIndex, + // + `${8 /* rgb */}|${slotIndex}`, + // + `${9 /* alpha */}|${slotIndex}` + ); + } + getFrameEntries() { + return 5; + } + /** Sets the time in seconds, red, green, blue, and alpha for the specified key frame. */ + setFrame(frame, time, r, g, b, a) { + frame *= 5; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*R*/ + ] = r; + this.frames[ + frame + 2 + /*G*/ + ] = g; + this.frames[ + frame + 3 + /*B*/ + ] = b; + this.frames[ + frame + 4 + /*A*/ + ] = a; + } + apply1(slot, pose, time, alpha, from, add) { + const color = pose.color; + const frames = this.frames; + if (time < frames[0]) { + const setup = slot.data.setupPose.color; + switch (from) { + case 1 /* setup */: + color.setFromColor(setup); + break; + case 2 /* first */: + color.add( + (setup.r - color.r) * alpha, + (setup.g - color.g) * alpha, + (setup.b - color.b) * alpha, + (setup.a - color.a) * alpha + ); + break; + } + return; + } + let r = 0, g = 0, b = 0, a = 0; + const i = Timeline.search( + frames, + time, + 5 + /*ENTRIES*/ + ); + const curveType = this.curves[ + i / 5 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: { + const before = frames[i]; + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + a = frames[ + i + 4 + /*A*/ + ]; + const t = (time - before) / (frames[ + i + 5 + /*ENTRIES*/ + ] - before); + r += (frames[ + i + 5 + 1 + /*R*/ + ] - r) * t; + g += (frames[ + i + 5 + 2 + /*G*/ + ] - g) * t; + b += (frames[ + i + 5 + 3 + /*B*/ + ] - b) * t; + a += (frames[ + i + 5 + 4 + /*A*/ + ] - a) * t; + break; + } + case 1: + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + a = frames[ + i + 4 + /*A*/ + ]; + break; + default: + r = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + g = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + b = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + a = this.getBezierValue( + time, + i, + 4, + curveType + 18 * 3 - 2 + /*BEZIER*/ + ); + } + if (alpha === 1) + color.set(r, g, b, a); + else { + if (from === 1 /* setup */) { + const setup = slot.data.setupPose.color; + color.set( + setup.r + (r - setup.r) * alpha, + setup.g + (g - setup.g) * alpha, + setup.b + (b - setup.b) * alpha, + setup.a + (a - setup.a) * alpha + ); + } else + color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha); + } + } + }; + var RGBTimeline = class extends SlotCurveTimeline { + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, slotIndex, `${8 /* rgb */}|${slotIndex}`); + } + getFrameEntries() { + return 4; + } + /** Sets the time in seconds, red, green, blue, and alpha for the specified key frame. */ + setFrame(frame, time, r, g, b) { + frame <<= 2; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*R*/ + ] = r; + this.frames[ + frame + 2 + /*G*/ + ] = g; + this.frames[ + frame + 3 + /*B*/ + ] = b; + } + apply1(slot, pose, time, alpha, from, add) { + const color = pose.color; + let r = 0, g = 0, b = 0; + const frames = this.frames; + if (time < frames[0]) { + const setup = slot.data.setupPose.color; + switch (from) { + case 1 /* setup */: { + color.r = setup.r; + color.g = setup.g; + color.b = setup.b; + break; + } + case 2 /* first */: { + color.r += (setup.r - color.r) * alpha; + color.g += (setup.g - color.g) * alpha; + color.b += (setup.b - color.b) * alpha; + break; + } + } + return; + } + const i = Timeline.search( + frames, + time, + 4 + /*ENTRIES*/ + ); + const curveType = this.curves[i >> 2]; + switch (curveType) { + case 0: { + const before = frames[i]; + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + const t = (time - before) / (frames[ + i + 4 + /*ENTRIES*/ + ] - before); + r += (frames[ + i + 4 + 1 + /*R*/ + ] - r) * t; + g += (frames[ + i + 4 + 2 + /*G*/ + ] - g) * t; + b += (frames[ + i + 4 + 3 + /*B*/ + ] - b) * t; + break; + } + case 1: + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + break; + default: + r = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + g = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + b = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + } + if (alpha !== 1) { + if (from === 1 /* setup */) { + const setup = slot.data.setupPose.color; + r = setup.r + (r - setup.r) * alpha; + g = setup.g + (g - setup.g) * alpha; + b = setup.b + (b - setup.b) * alpha; + } else { + r = color.r + (r - color.r) * alpha; + g = color.g + (g - color.g) * alpha; + b = color.b + (b - color.b) * alpha; + } + } + color.r = r < 0 ? 0 : r > 1 ? 1 : r; + color.g = g < 0 ? 0 : g > 1 ? 1 : g; + color.b = b < 0 ? 0 : b > 1 ? 1 : b; + } + }; + var AlphaTimeline = class extends CurveTimeline1 { + slotIndex = 0; + constructor(frameCount, bezierCount, slotIndex) { + super(frameCount, bezierCount, `${9 /* alpha */}|${slotIndex}`); + this.slotIndex = slotIndex; + } + apply(skeleton, lastTime, time, events, alpha, from, add, out, appliedPose) { + const slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) return; + const color = (appliedPose ? slot.appliedPose : slot.pose).color; + let a = 0; + const frames = this.frames; + if (time < frames[0]) { + const setup = slot.data.setupPose.color.a; + switch (from) { + case 1 /* setup */: + color.a = setup; + break; + case 2 /* first */: + color.a += (setup - color.a) * alpha; + break; + } + return; + } + a = this.getCurveValue(time); + if (alpha !== 1) { + if (from === 1 /* setup */) { + const setup = slot.data.setupPose.color; + a = setup.a + (a - setup.a) * alpha; + } else + a = color.a + (a - color.a) * alpha; + } + color.a = a < 0 ? 0 : a > 1 ? 1 : a; + } + }; + var RGBA2Timeline = class extends SlotCurveTimeline { + constructor(frameCount, bezierCount, slotIndex) { + super( + frameCount, + bezierCount, + slotIndex, + // + `${8 /* rgb */}|${slotIndex}`, + // + `${9 /* alpha */}|${slotIndex}`, + // + `${10 /* rgb2 */}|${slotIndex}` + ); + } + getFrameEntries() { + return 8; + } + /** Sets the time in seconds, light, and dark colors for the specified key frame. */ + setFrame(frame, time, r, g, b, a, r2, g2, b2) { + frame <<= 3; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*R*/ + ] = r; + this.frames[ + frame + 2 + /*G*/ + ] = g; + this.frames[ + frame + 3 + /*B*/ + ] = b; + this.frames[ + frame + 4 + /*A*/ + ] = a; + this.frames[ + frame + 5 + /*R2*/ + ] = r2; + this.frames[ + frame + 6 + /*G2*/ + ] = g2; + this.frames[ + frame + 7 + /*B2*/ + ] = b2; + } + apply1(slot, pose, time, alpha, from, add) { + const light = pose.color, dark = pose.darkColor; + let r2 = 0, g2 = 0, b2 = 0; + const frames = this.frames; + if (time < frames[0]) { + const setup = slot.data.setupPose; + const setupLight = setup.color, setupDark = setup.darkColor; + switch (from) { + case 1 /* setup */: { + light.setFromColor(setupLight); + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; + break; + } + case 2 /* first */: { + light.add( + (setupLight.r - light.r) * alpha, + (setupLight.g - light.g) * alpha, + (setupLight.b - light.b) * alpha, + (setupLight.a - light.a) * alpha + ); + dark.r += (setupDark.r - dark.r) * alpha; + dark.g += (setupDark.g - dark.g) * alpha; + dark.b += (setupDark.b - dark.b) * alpha; + break; + } + } + return; + } + let r = 0, g = 0, b = 0, a = 0; + const i = Timeline.search( + frames, + time, + 8 + /*ENTRIES*/ + ); + const curveType = this.curves[i >> 3]; + switch (curveType) { + case 0: { + const before = frames[i]; + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + a = frames[ + i + 4 + /*A*/ + ]; + r2 = frames[ + i + 5 + /*R2*/ + ]; + g2 = frames[ + i + 6 + /*G2*/ + ]; + b2 = frames[ + i + 7 + /*B2*/ + ]; + const t = (time - before) / (frames[ + i + 8 + /*ENTRIES*/ + ] - before); + r += (frames[ + i + 8 + 1 + /*R*/ + ] - r) * t; + g += (frames[ + i + 8 + 2 + /*G*/ + ] - g) * t; + b += (frames[ + i + 8 + 3 + /*B*/ + ] - b) * t; + a += (frames[ + i + 8 + 4 + /*A*/ + ] - a) * t; + r2 += (frames[ + i + 8 + 5 + /*R2*/ + ] - r2) * t; + g2 += (frames[ + i + 8 + 6 + /*G2*/ + ] - g2) * t; + b2 += (frames[ + i + 8 + 7 + /*B2*/ + ] - b2) * t; + break; + } + case 1: + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + a = frames[ + i + 4 + /*A*/ + ]; + r2 = frames[ + i + 5 + /*R2*/ + ]; + g2 = frames[ + i + 6 + /*G2*/ + ]; + b2 = frames[ + i + 7 + /*B2*/ + ]; + break; + default: + r = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + g = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + b = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + a = this.getBezierValue( + time, + i, + 4, + curveType + 18 * 3 - 2 + /*BEZIER*/ + ); + r2 = this.getBezierValue( + time, + i, + 5, + curveType + 18 * 4 - 2 + /*BEZIER*/ + ); + g2 = this.getBezierValue( + time, + i, + 6, + curveType + 18 * 5 - 2 + /*BEZIER*/ + ); + b2 = this.getBezierValue( + time, + i, + 7, + curveType + 18 * 6 - 2 + /*BEZIER*/ + ); + } + if (alpha === 1) + light.set(r, g, b, a); + else if (from === 1 /* setup */) { + const setupPose = slot.data.setupPose; + let setup = setupPose.color; + light.set( + setup.r + (r - setup.r) * alpha, + setup.g + (g - setup.g) * alpha, + setup.b + (b - setup.b) * alpha, + setup.a + (a - setup.a) * alpha + ); + setup = setupPose.darkColor; + r2 = setup.r + (r2 - setup.r) * alpha; + g2 = setup.g + (g2 - setup.g) * alpha; + b2 = setup.b + (b2 - setup.b) * alpha; + } else { + light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha); + r2 = dark.r + (r2 - dark.r) * alpha; + g2 = dark.g + (g2 - dark.g) * alpha; + b2 = dark.b + (b2 - dark.b) * alpha; + } + dark.r = r2 < 0 ? 0 : r2 > 1 ? 1 : r2; + dark.g = g2 < 0 ? 0 : g2 > 1 ? 1 : g2; + dark.b = b2 < 0 ? 0 : b2 > 1 ? 1 : b2; + } + }; + var RGB2Timeline = class extends SlotCurveTimeline { + constructor(frameCount, bezierCount, slotIndex) { + super( + frameCount, + bezierCount, + slotIndex, + // + `${8 /* rgb */}|${slotIndex}`, + // + `${10 /* rgb2 */}|${slotIndex}` + ); + } + getFrameEntries() { + return 7; + } + /** Sets the time in seconds, light, and dark colors for the specified key frame. */ + setFrame(frame, time, r, g, b, r2, g2, b2) { + frame *= 7; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*R*/ + ] = r; + this.frames[ + frame + 2 + /*G*/ + ] = g; + this.frames[ + frame + 3 + /*B*/ + ] = b; + this.frames[ + frame + 4 + /*R2*/ + ] = r2; + this.frames[ + frame + 5 + /*G2*/ + ] = g2; + this.frames[ + frame + 6 + /*B2*/ + ] = b2; + } + apply1(slot, pose, time, alpha, from, add) { + const light = pose.color, dark = pose.darkColor; + let r = 0, g = 0, b = 0, r2 = 0, g2 = 0, b2 = 0; + const frames = this.frames; + if (time < frames[0]) { + const setup = slot.data.setupPose; + const setupLight = setup.color, setupDark = setup.darkColor; + switch (from) { + case 1 /* setup */: + light.r = setupLight.r; + light.g = setupLight.g; + light.b = setupLight.b; + dark.r = setupDark.r; + dark.g = setupDark.g; + dark.b = setupDark.b; + break; + case 2 /* first */: + light.r += (setupLight.r - light.r) * alpha; + light.g += (setupLight.g - light.g) * alpha; + light.b += (setupLight.b - light.b) * alpha; + dark.r += (setupDark.r - dark.r) * alpha; + dark.g += (setupDark.g - dark.g) * alpha; + dark.b += (setupDark.b - dark.b) * alpha; + break; + } + return; + } + const i = Timeline.search( + frames, + time, + 7 + /*ENTRIES*/ + ); + const curveType = this.curves[ + i / 7 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: { + const before = frames[i]; + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + r2 = frames[ + i + 4 + /*R2*/ + ]; + g2 = frames[ + i + 5 + /*G2*/ + ]; + b2 = frames[ + i + 6 + /*B2*/ + ]; + const t = (time - before) / (frames[ + i + 7 + /*ENTRIES*/ + ] - before); + r += (frames[ + i + 7 + 1 + /*R*/ + ] - r) * t; + g += (frames[ + i + 7 + 2 + /*G*/ + ] - g) * t; + b += (frames[ + i + 7 + 3 + /*B*/ + ] - b) * t; + r2 += (frames[ + i + 7 + 4 + /*R2*/ + ] - r2) * t; + g2 += (frames[ + i + 7 + 5 + /*G2*/ + ] - g2) * t; + b2 += (frames[ + i + 7 + 6 + /*B2*/ + ] - b2) * t; + break; + } + case 1: + r = frames[ + i + 1 + /*R*/ + ]; + g = frames[ + i + 2 + /*G*/ + ]; + b = frames[ + i + 3 + /*B*/ + ]; + r2 = frames[ + i + 4 + /*R2*/ + ]; + g2 = frames[ + i + 5 + /*G2*/ + ]; + b2 = frames[ + i + 6 + /*B2*/ + ]; + break; + default: + r = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + g = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + b = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + r2 = this.getBezierValue( + time, + i, + 4, + curveType + 18 * 3 - 2 + /*BEZIER*/ + ); + g2 = this.getBezierValue( + time, + i, + 5, + curveType + 18 * 4 - 2 + /*BEZIER*/ + ); + b2 = this.getBezierValue( + time, + i, + 6, + curveType + 18 * 5 - 2 + /*BEZIER*/ + ); + } + if (alpha !== 1) { + if (from === 1 /* setup */) { + const setupPose = slot.data.setupPose; + let setup = setupPose.color; + r = setup.r + (r - setup.r) * alpha; + g = setup.g + (g - setup.g) * alpha; + b = setup.b + (b - setup.b) * alpha; + setup = setupPose.darkColor; + r2 = setup.r + (r2 - setup.r) * alpha; + g2 = setup.g + (g2 - setup.g) * alpha; + b2 = setup.b + (b2 - setup.b) * alpha; + } else { + r = light.r + (r - light.r) * alpha; + g = light.g + (g - light.g) * alpha; + b = light.b + (b - light.b) * alpha; + r2 = dark.r + (r2 - dark.r) * alpha; + g2 = dark.g + (g2 - dark.g) * alpha; + b2 = dark.b + (b2 - dark.b) * alpha; + } + } + light.r = r < 0 ? 0 : r > 1 ? 1 : r; + light.g = g < 0 ? 0 : g > 1 ? 1 : g; + light.b = b < 0 ? 0 : b > 1 ? 1 : b; + dark.r = r2 < 0 ? 0 : r2 > 1 ? 1 : r2; + dark.g = g2 < 0 ? 0 : g2 > 1 ? 1 : g2; + dark.b = b2 < 0 ? 0 : b2 > 1 ? 1 : b2; + } + }; + var AttachmentTimeline = class extends Timeline { + slotIndex = 0; + /** The attachment name for each key frame. May contain null values to clear the attachment. */ + attachmentNames; + constructor(frameCount, slotIndex) { + super(frameCount, `${11 /* attachment */}|${slotIndex}`); + this.slotIndex = slotIndex; + this.attachmentNames = new Array(frameCount); + this.instant = true; + } + getFrameCount() { + return this.frames.length; + } + /** Sets the time in seconds and the attachment name for the specified key frame. */ + setFrame(frame, time, attachmentName) { + this.frames[frame] = time; + this.attachmentNames[frame] = attachmentName; + } + apply(skeleton, lastTime, time, events, alpha, from, add, out, appliedPose) { + const slot = skeleton.slots[this.slotIndex]; + if (!slot.bone.active) return; + const pose = appliedPose ? slot.appliedPose : slot.pose; + if (out || time < this.frames[0]) { + if (from !== 0 /* current */) this.setAttachment(skeleton, pose, slot.data.attachmentName); + } else + this.setAttachment(skeleton, pose, this.attachmentNames[Timeline.search(this.frames, time)]); + } + setAttachment(skeleton, pose, attachmentName) { + pose.setAttachment(!attachmentName ? null : skeleton.getAttachment(this.slotIndex, attachmentName)); + } + }; + var DeformTimeline = class extends CurveTimeline { + slotIndex; + /** The attachment that will be deformed. + * + * See {@link VertexAttachment.getTimelineAttachment}. */ + attachment; + /** The vertices for each key frame. */ + vertices; + constructor(frameCount, bezierCount, slotIndex, attachment) { + super(frameCount, bezierCount, `${12 /* deform */}|${slotIndex}|${attachment.id}`); + this.slotIndex = slotIndex; + this.attachment = attachment; + this.vertices = new Array(frameCount); + this.additive = true; + } + getFrameCount() { + return this.frames.length; + } + /** Sets the time and vertices for the specified frame. + * @param frame Between 0 and `frameCount`, inclusive. + * @param time The frame time in seconds. + * @param vertices Vertex positions for an unweighted VertexAttachment, or deform offsets if it has weights. */ + setFrame(frame, time, vertices) { + this.frames[frame] = time; + this.vertices[frame] = vertices; + } + /** @param value1 Ignored (0 is used for a deform timeline). + * @param value2 Ignored (1 is used for a deform timeline). */ + setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2) { + const curves = this.curves; + let i = this.getFrameCount() + bezier * 18; + if (value === 0) curves[frame] = 2 + i; + const tmpx = (time1 - cx1 * 2 + cx2) * 0.03, tmpy = cy2 * 0.03 - cy1 * 0.06; + const dddx = ((cx1 - cx2) * 3 - time1 + time2) * 6e-3, dddy = (cy1 - cy2 + 0.33333333) * 0.018; + let ddx = tmpx * 2 + dddx, ddy = tmpy * 2 + dddy; + let dx = (cx1 - time1) * 0.3 + tmpx + dddx * 0.16666667, dy = cy1 * 0.3 + tmpy + dddy * 0.16666667; + let x = time1 + dx, y = dy; + for (let n = i + 18; i < n; i += 2) { + curves[i] = x; + curves[i + 1] = y; + dx += ddx; + dy += ddy; + ddx += dddx; + ddy += dddy; + x += dx; + y += dy; + } + } + getCurvePercent(time, frame) { + const curves = this.curves; + let i = curves[frame]; + switch (i) { + case 0: { + const x2 = this.frames[frame]; + return (time - x2) / (this.frames[frame + this.getFrameEntries()] - x2); + } + case 1: + return 0; + } + i -= 2; + if (curves[i] > time) { + const x2 = this.frames[frame]; + return curves[i + 1] * (time - x2) / (curves[i] - x2); + } + const n = i + 18; + for (i += 2; i < n; i += 2) { + if (curves[i] >= time) { + const x2 = curves[i - 2], y2 = curves[i - 1]; + return y2 + (time - x2) / (curves[i] - x2) * (curves[i + 1] - y2); + } + } + const x = curves[n - 2], y = curves[n - 1]; + return y + (1 - y) * (time - x) / (this.frames[frame + this.getFrameEntries()] - x); + } + apply(skeleton, lastTime, time, events, alpha, from, add, out, appliedPose) { + const slots = skeleton.slots; + if (!this.attachment.isTimelineActive(slots, this.slotIndex, appliedPose)) return; + const timelineSlots = this.attachment.timelineSlots; + const frames = this.frames; + if (time < frames[0]) { + this.applyBeforeFirst(slots[this.slotIndex], appliedPose, alpha, from); + for (const slotIndex of timelineSlots) + this.applyBeforeFirst(slots[slotIndex], appliedPose, alpha, from); + return; + } + let v1, v2; + let percent; + if (time >= frames[frames.length - 1]) { + percent = 0; + v1 = this.vertices[frames.length - 1]; + v2 = null; + } else { + const frame = Timeline.search(frames, time); + percent = this.getCurvePercent(time, frame); + v1 = this.vertices[frame]; + v2 = this.vertices[frame + 1]; + } + const vertexCount = this.vertices[0].length; + this.applyToSlot(slots[this.slotIndex], appliedPose, v1, v2, percent, vertexCount, alpha, from, add); + for (const slotIndex of timelineSlots) + this.applyToSlot(slots[slotIndex], appliedPose, v1, v2, percent, vertexCount, alpha, from, add); + } + applyBeforeFirst(slot, appliedPose, alpha, from) { + if (!slot.bone.active) return; + const pose = appliedPose ? slot.appliedPose : slot.pose; + if (pose.attachment == null || pose.attachment.timelineAttachment !== this.attachment) return; + const deformArray = pose.deform; + if (deformArray.length === 0) from = 1 /* setup */; + switch (from) { + case 1 /* setup */: + deformArray.length = 0; + break; + case 2 /* first */: { + if (alpha === 1) { + deformArray.length = 0; + return; + } + const vertexCount = this.vertices[0].length; + deformArray.length = vertexCount; + const deform = deformArray; + const vertexAttachment = pose.attachment; + if (vertexAttachment.bones === null) { + const setupVertices = vertexAttachment.vertices; + for (let i = 0; i < vertexCount; i++) + deform[i] += (setupVertices[i] - deform[i]) * alpha; + } else { + alpha = 1 - alpha; + for (let i = 0; i < vertexCount; i++) + deform[i] *= alpha; + } + } + } + } + applyToSlot(slot, appliedPose, v1, v2, percent, vertexCount, alpha, from, add) { + if (!slot.bone.active) return; + const pose = appliedPose ? slot.appliedPose : slot.pose; + if (pose.attachment === null || pose.attachment.timelineAttachment !== this.attachment) return; + const vertexAttachment = pose.attachment; + const deform = pose.deform; + if (deform.length === 0) from = 1 /* setup */; + const fromSetup = from === 1 /* setup */; + deform.length = vertexCount; + if (v2 === null) { + if (alpha === 1) { + if (add && !fromSetup) { + if (!vertexAttachment.bones) { + const setupVertices = vertexAttachment.vertices; + for (let i = 0; i < vertexCount; i++) + deform[i] += v1[i] - setupVertices[i]; + } else { + for (let i = 0; i < vertexCount; i++) + deform[i] += v1[i]; + } + } else + Utils.arrayCopy(v1, 0, deform, 0, vertexCount); + } else if (fromSetup) { + if (!vertexAttachment.bones) { + const setupVertices = vertexAttachment.vertices; + for (let i = 0; i < vertexCount; i++) { + const setup = setupVertices[i]; + deform[i] = setup + (v1[i] - setup) * alpha; + } + } else { + for (let i = 0; i < vertexCount; i++) + deform[i] = v1[i] * alpha; + } + } else if (add) { + if (!vertexAttachment.bones) { + const setupVertices = vertexAttachment.vertices; + for (let i = 0; i < vertexCount; i++) + deform[i] += (v1[i] - setupVertices[i]) * alpha; + } else { + for (let i = 0; i < vertexCount; i++) + deform[i] += v1[i] * alpha; + } + } else { + for (let i = 0; i < vertexCount; i++) + deform[i] += (v1[i] - deform[i]) * alpha; + } + } else { + if (alpha === 1) { + if (add && !fromSetup) { + if (!vertexAttachment.bones) { + const setupVertices = vertexAttachment.vertices; + for (let i = 0; i < vertexCount; i++) { + const prev = v1[i]; + deform[i] += prev + (v2[i] - prev) * percent - setupVertices[i]; + } + } else { + for (let i = 0; i < vertexCount; i++) { + const prev = v1[i]; + deform[i] += prev + (v2[i] - prev) * percent; + } + } + } else if (percent === 0) + Utils.arrayCopy(v1, 0, deform, 0, vertexCount); + else { + for (let i = 0; i < vertexCount; i++) { + const prev = v1[i]; + deform[i] = prev + (v2[i] - prev) * percent; + } + } + } else if (fromSetup) { + if (!vertexAttachment.bones) { + const setupVertices = vertexAttachment.vertices; + for (let i = 0; i < vertexCount; i++) { + const prev = v1[i], setup = setupVertices[i]; + deform[i] = setup + (prev + (v2[i] - prev) * percent - setup) * alpha; + } + } else { + for (let i = 0; i < vertexCount; i++) { + const prev = v1[i]; + deform[i] = (prev + (v2[i] - prev) * percent) * alpha; + } + } + } else if (add) { + if (!vertexAttachment.bones) { + const setupVertices = vertexAttachment.vertices; + for (let i = 0; i < vertexCount; i++) { + const prev = v1[i]; + deform[i] += (prev + (v2[i] - prev) * percent - setupVertices[i]) * alpha; + } + } else { + for (let i = 0; i < vertexCount; i++) { + const prev = v1[i]; + deform[i] += (prev + (v2[i] - prev) * percent) * alpha; + } + } + } else { + for (let i = 0; i < vertexCount; i++) { + const prev = v1[i]; + deform[i] += (prev + (v2[i] - prev) * percent - deform[i]) * alpha; + } + } + } + } + }; + var SequenceTimeline = class _SequenceTimeline extends Timeline { + static ENTRIES = 3; + static MODE = 1; + static DELAY = 2; + slotIndex; + attachment; + constructor(frameCount, slotIndex, attachment) { + super(frameCount, `${29 /* sequence */}|${slotIndex}|${attachment.sequence.id}`); + this.slotIndex = slotIndex; + this.attachment = attachment; + this.instant = true; + } + getFrameEntries() { + return _SequenceTimeline.ENTRIES; + } + getSlotIndex() { + return this.slotIndex; + } + /** The attachment for which the {@link SlotPose.sequenceIndex} will be set. + * + * See {@link VertexAttachment.timelineAttachment}. */ + getAttachment() { + return this.attachment; + } + /** Sets the time, mode, index, and frame time for the specified frame. + * @param frame Between 0 and `frameCount`, inclusive. + * @param time Seconds between frames. */ + setFrame(frame, time, mode, index, delay) { + const frames = this.frames; + frame *= _SequenceTimeline.ENTRIES; + frames[frame] = time; + frames[frame + _SequenceTimeline.MODE] = mode | index << 4; + frames[frame + _SequenceTimeline.DELAY] = delay; + } + apply(skeleton, lastTime, time, events, alpha, from, add, out, appliedPose) { + const slots = skeleton.slots; + if (!this.attachment.isTimelineActive(slots, this.slotIndex, appliedPose)) return; + const timelineSlots = this.attachment.timelineSlots; + const frames = this.frames; + if (out || time < frames[0]) { + if (from !== 0 /* current */) { + this.setupPose(slots[this.slotIndex], appliedPose); + for (const slotIndex of timelineSlots) + this.setupPose(slots[slotIndex], appliedPose); + } + return; + } + const i = Timeline.search(frames, time, _SequenceTimeline.ENTRIES); + const before = frames[i]; + const modeAndIndex = frames[i + _SequenceTimeline.MODE]; + const delay = frames[i + _SequenceTimeline.DELAY]; + this.applyToSlot(slots[this.slotIndex], appliedPose, time, before, modeAndIndex, delay); + for (const slotIndex of timelineSlots) + this.applyToSlot(slots[slotIndex], appliedPose, time, before, modeAndIndex, delay); + } + setupPose(slot, appliedPose) { + if (!slot.bone.active) return; + const pose = appliedPose ? slot.appliedPose : slot.pose; + if (pose.attachment === null || pose.attachment.timelineAttachment !== this.attachment) return; + pose.sequenceIndex = -1; + } + applyToSlot(slot, appliedPose, time, before, modeAndIndex, delay) { + if (!slot.bone.active) return; + const pose = appliedPose ? slot.appliedPose : slot.pose; + if (pose.attachment === null || pose.attachment.timelineAttachment !== this.attachment) return; + let index = modeAndIndex >> 4, count = pose.attachment.sequence.regions.length; + const mode = SequenceModeValues[modeAndIndex & 15]; + if (mode !== 0 /* hold */) { + index += (time - before) / delay + 1e-5 | 0; + switch (mode) { + case 1 /* once */: + index = Math.min(count - 1, index); + break; + case 2 /* loop */: + index %= count; + break; + case 3 /* pingpong */: { + const n = (count << 1) - 2; + index = n === 0 ? 0 : index % n; + if (index >= count) index = n - index; + break; + } + case 4 /* onceReverse */: + index = Math.max(count - 1 - index, 0); + break; + case 5 /* loopReverse */: + index = count - 1 - index % count; + break; + case 6 /* pingpongReverse */: { + const n = (count << 1) - 2; + index = n === 0 ? 0 : (index + count - 1) % n; + if (index >= count) index = n - index; + } + } + } + pose.sequenceIndex = index; + } + }; + var EventTimeline = class _EventTimeline extends Timeline { + static propertyIds = [`${13 /* event */}`]; + /** The event for each key frame. */ + events; + constructor(frameCount) { + super(frameCount, ..._EventTimeline.propertyIds); + this.events = new Array(frameCount); + this.instant = true; + } + getFrameCount() { + return this.frames.length; + } + /** Sets the time in seconds and the event for the specified key frame. */ + setFrame(frame, event) { + this.frames[frame] = event.time; + this.events[frame] = event; + } + /** Fires events for frames > `lastTime` and <= `time`. */ + apply(skeleton, lastTime, time, firedEvents, alpha, from, add, out, appliedPose) { + if (!firedEvents) return; + const frames = this.frames; + const frameCount = this.frames.length; + if (lastTime > time) { + this.apply(null, lastTime, Number.MAX_VALUE, firedEvents, 0, from, false, false, false); + lastTime = -1; + } else if (lastTime >= frames[frameCount - 1]) + return; + if (time < frames[0]) return; + let i = 0; + if (lastTime < frames[0]) + i = 0; + else { + i = Timeline.search(frames, lastTime) + 1; + const frameTime = frames[i]; + while (i > 0) { + if (frames[i - 1] !== frameTime) break; + i--; + } + } + for (; i < frameCount && time >= frames[i]; i++) + firedEvents.push(this.events[i]); + } + }; + var DrawOrderTimeline = class _DrawOrderTimeline extends Timeline { + static propertyID = `${14 /* drawOrder */}`; + static propertyIds = [_DrawOrderTimeline.propertyID]; + /** The draw order for each key frame. See {@link setFrame}. */ + drawOrders; + constructor(frameCount) { + super(frameCount, ..._DrawOrderTimeline.propertyIds); + this.drawOrders = new Array(frameCount); + this.instant = true; + } + getFrameCount() { + return this.frames.length; + } + /** Sets the time in seconds and the draw order for the specified key frame. + * @param drawOrder Ordered {@link Skeleton.slots} indices, or null to use setup pose + * draw order. */ + setFrame(frame, time, drawOrder) { + this.frames[frame] = time; + this.drawOrders[frame] = drawOrder; + } + apply(skeleton, lastTime, time, firedEvents, alpha, from, add, out, appliedPose) { + const pose = appliedPose ? skeleton.drawOrder.appliedPose : skeleton.drawOrder.pose; + const setup = skeleton.slots; + if (out || time < this.frames[0]) { + if (from !== 0 /* current */) Utils.arrayCopy(setup, 0, pose, 0, skeleton.slots.length); + return; + } + const order = this.drawOrders[Timeline.search(this.frames, time)]; + if (!order) + Utils.arrayCopy(setup, 0, pose, 0, skeleton.slots.length); + else { + for (let i = 0, n = order.length; i < n; i++) + pose[i] = setup[order[i]]; + } + } + }; + var DrawOrderFolderTimeline = class _DrawOrderFolderTimeline extends Timeline { + static propertyID = `${15 /* drawOrderFolder */}`; + slots; + inFolder; + drawOrders; + /** @param slots {@link Skeleton.slots} indices controlled by this timeline, in setup order. + * @param slotCount The maximum number of slots in the skeleton. */ + constructor(frameCount, slots, slotCount) { + super(frameCount, ..._DrawOrderFolderTimeline.propertyIds(slots)); + this.slots = slots; + this.drawOrders = new Array(frameCount); + this.inFolder = new Array(slotCount); + for (const i of slots) + this.inFolder[i] = true; + this.instant = true; + } + static propertyIds(slots) { + const n = slots.length; + const ids = new Array(n); + for (let i = 0; i < n; i++) + ids[i] = `${_DrawOrderFolderTimeline.propertyID}|${slots[i]}`; + return ids; + } + getFrameCount() { + return this.frames.length; + } + /** The {@link Skeleton.getSlots} indices that this timeline affects, in setup order. */ + getSlots() { + return this.slots; + } + /** The draw order for each frame. See {@link setFrame}. */ + getDrawOrders() { + return this.drawOrders; + } + /** Sets the time and draw order for the specified frame. + * @param frame Between 0 and `frameCount`, inclusive. + * @param time The frame time in seconds. + * @param drawOrder Ordered {@link getSlots} indices, or null to use setup pose order. */ + setFrame(frame, time, drawOrder) { + this.frames[frame] = time; + this.drawOrders[frame] = drawOrder; + } + apply(skeleton, lastTime, time, events, alpha, from, add, out, appliedPose) { + const pose = appliedPose ? skeleton.drawOrder.appliedPose : skeleton.drawOrder.pose; + const setup = skeleton.slots; + if (out || time < this.frames[0]) { + if (from !== 0 /* current */) this.setup(pose, setup); + } else { + const order = this.drawOrders[Timeline.search(this.frames, time)]; + if (!order) + this.setup(pose, setup); + else { + const inFolder = this.inFolder; + const slots = this.slots; + for (let i = 0, found = 0, done = slots.length; ; i++) { + if (inFolder[pose[i].data.index]) { + pose[i] = setup[slots[order[found]]]; + if (++found === done) break; + } + } + } + } + } + setup(pose, setup) { + const { inFolder, slots } = this; + for (let i = 0, found = 0, done = slots.length; ; i++) { + if (inFolder[pose[i].data.index]) { + pose[i] = setup[slots[found]]; + if (++found === done) break; + } + } + } + }; + function isConstraintTimeline(obj) { + return typeof obj === "object" && obj !== null && typeof obj.constraintIndex === "number"; + } + var IkConstraintTimeline = class extends CurveTimeline { + constraintIndex = 0; + constructor(frameCount, bezierCount, constraintIndex) { + super(frameCount, bezierCount, `${16 /* ikConstraint */}|${constraintIndex}`); + this.constraintIndex = constraintIndex; + } + getFrameEntries() { + return 6; + } + /** Sets the time, mix, softness, bend direction, compress, and stretch for the specified frame. + * @param frame Between 0 and `frameCount`, inclusive. + * @param time The frame time in seconds. + * @param bendDirection 1 or -1. */ + setFrame(frame, time, mix, softness, bendDirection, compress, stretch) { + frame *= 6; + this.frames[frame] = time; + this.frames[ + frame + 1 + /*MIX*/ + ] = mix; + this.frames[ + frame + 2 + /*SOFTNESS*/ + ] = softness; + this.frames[ + frame + 3 + /*BEND_DIRECTION*/ + ] = bendDirection; + this.frames[ + frame + 4 + /*COMPRESS*/ + ] = compress ? 1 : 0; + this.frames[ + frame + 5 + /*STRETCH*/ + ] = stretch ? 1 : 0; + } + apply(skeleton, lastTime, time, firedEvents, alpha, from, add, out, appliedPose) { + const constraint = skeleton.constraints[this.constraintIndex]; + if (!constraint.active) return; + const pose = appliedPose ? constraint.appliedPose : constraint.pose; + const frames = this.frames; + if (time < frames[0]) { + const setup = constraint.data.setupPose; + switch (from) { + case 1 /* setup */: { + pose.mix = setup.mix; + pose.softness = setup.softness; + pose.bendDirection = setup.bendDirection; + pose.compress = setup.compress; + pose.stretch = setup.stretch; + break; + } + case 2 /* first */: { + pose.mix += (setup.mix - pose.mix) * alpha; + pose.softness += (setup.softness - pose.softness) * alpha; + pose.bendDirection = setup.bendDirection; + pose.compress = setup.compress; + pose.stretch = setup.stretch; + break; + } + } + return; + } + let mix = 0, softness = 0; + const i = Timeline.search( + frames, + time, + 6 + /*ENTRIES*/ + ); + const curveType = this.curves[ + i / 6 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: { + const before = frames[i]; + mix = frames[ + i + 1 + /*MIX*/ + ]; + softness = frames[ + i + 2 + /*SOFTNESS*/ + ]; + const t = (time - before) / (frames[ + i + 6 + /*ENTRIES*/ + ] - before); + mix += (frames[ + i + 6 + 1 + /*MIX*/ + ] - mix) * t; + softness += (frames[ + i + 6 + 2 + /*SOFTNESS*/ + ] - softness) * t; + break; + } + case 1: + mix = frames[ + i + 1 + /*MIX*/ + ]; + softness = frames[ + i + 2 + /*SOFTNESS*/ + ]; + break; + default: + mix = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + softness = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + } + const base = from === 1 /* setup */ ? constraint.data.setupPose : pose; + pose.mix = base.mix + (mix - base.mix) * alpha; + pose.softness = base.softness + (softness - base.softness) * alpha; + if (out) { + if (from === 1 /* setup */) { + pose.bendDirection = base.bendDirection; + pose.compress = base.compress; + pose.stretch = base.stretch; + } + } else { + pose.bendDirection = frames[ + i + 3 + /*BEND_DIRECTION*/ + ]; + pose.compress = frames[ + i + 4 + /*COMPRESS*/ + ] !== 0; + pose.stretch = frames[ + i + 5 + /*STRETCH*/ + ] !== 0; + } + } + }; + var TransformConstraintTimeline = class extends CurveTimeline { + /** The index of the transform constraint slot in {@link Skeleton.transformConstraints} that will be changed. */ + constraintIndex = 0; + constructor(frameCount, bezierCount, constraintIndex) { + super(frameCount, bezierCount, `${17 /* transformConstraint */}|${constraintIndex}`); + this.constraintIndex = constraintIndex; + this.additive = true; + } + getFrameEntries() { + return 7; + } + /** Sets the time, rotate mix, translate mix, scale mix, and shear mix for the specified frame. + * @param frame Between 0 and `frameCount`, inclusive. + * @param time The frame time in seconds. */ + setFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY) { + const frames = this.frames; + frame *= 7; + frames[frame] = time; + frames[ + frame + 1 + /*ROTATE*/ + ] = mixRotate; + frames[ + frame + 2 + /*X*/ + ] = mixX; + frames[ + frame + 3 + /*Y*/ + ] = mixY; + frames[ + frame + 4 + /*SCALEX*/ + ] = mixScaleX; + frames[ + frame + 5 + /*SCALEY*/ + ] = mixScaleY; + frames[ + frame + 6 + /*SHEARY*/ + ] = mixShearY; + } + apply(skeleton, lastTime, time, firedEvents, alpha, from, add, out, appliedPose) { + const constraint = skeleton.constraints[this.constraintIndex]; + if (!constraint.active) return; + const pose = appliedPose ? constraint.appliedPose : constraint.pose; + const frames = this.frames; + if (time < frames[0]) { + const setup = constraint.data.setupPose; + switch (from) { + case 1 /* setup */: { + pose.mixRotate = setup.mixRotate; + pose.mixX = setup.mixX; + pose.mixY = setup.mixY; + pose.mixScaleX = setup.mixScaleX; + pose.mixScaleY = setup.mixScaleY; + pose.mixShearY = setup.mixShearY; + break; + } + case 2 /* first */: { + pose.mixRotate += (setup.mixRotate - pose.mixRotate) * alpha; + pose.mixX += (setup.mixX - pose.mixX) * alpha; + pose.mixY += (setup.mixY - pose.mixY) * alpha; + pose.mixScaleX += (setup.mixScaleX - pose.mixScaleX) * alpha; + pose.mixScaleY += (setup.mixScaleY - pose.mixScaleY) * alpha; + pose.mixShearY += (setup.mixShearY - pose.mixShearY) * alpha; + break; + } + } + return; + } + let rotate, x, y, scaleX, scaleY, shearY; + const i = Timeline.search( + frames, + time, + 7 + /*ENTRIES*/ + ); + const curveType = this.curves[ + i / 7 + /*ENTRIES*/ + ]; + switch (curveType) { + case 0: { + const before = frames[i]; + rotate = frames[ + i + 1 + /*ROTATE*/ + ]; + x = frames[ + i + 2 + /*X*/ + ]; + y = frames[ + i + 3 + /*Y*/ + ]; + scaleX = frames[ + i + 4 + /*SCALEX*/ + ]; + scaleY = frames[ + i + 5 + /*SCALEY*/ + ]; + shearY = frames[ + i + 6 + /*SHEARY*/ + ]; + const t = (time - before) / (frames[ + i + 7 + /*ENTRIES*/ + ] - before); + rotate += (frames[ + i + 7 + 1 + /*ROTATE*/ + ] - rotate) * t; + x += (frames[ + i + 7 + 2 + /*X*/ + ] - x) * t; + y += (frames[ + i + 7 + 3 + /*Y*/ + ] - y) * t; + scaleX += (frames[ + i + 7 + 4 + /*SCALEX*/ + ] - scaleX) * t; + scaleY += (frames[ + i + 7 + 5 + /*SCALEY*/ + ] - scaleY) * t; + shearY += (frames[ + i + 7 + 6 + /*SHEARY*/ + ] - shearY) * t; + break; + } + case 1: + rotate = frames[ + i + 1 + /*ROTATE*/ + ]; + x = frames[ + i + 2 + /*X*/ + ]; + y = frames[ + i + 3 + /*Y*/ + ]; + scaleX = frames[ + i + 4 + /*SCALEX*/ + ]; + scaleY = frames[ + i + 5 + /*SCALEY*/ + ]; + shearY = frames[ + i + 6 + /*SHEARY*/ + ]; + break; + default: + rotate = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + x = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + y = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + scaleX = this.getBezierValue( + time, + i, + 4, + curveType + 18 * 3 - 2 + /*BEZIER*/ + ); + scaleY = this.getBezierValue( + time, + i, + 5, + curveType + 18 * 4 - 2 + /*BEZIER*/ + ); + shearY = this.getBezierValue( + time, + i, + 6, + curveType + 18 * 5 - 2 + /*BEZIER*/ + ); + } + const base = from === 1 /* setup */ ? constraint.data.setupPose : pose; + if (add) { + pose.mixRotate = base.mixRotate + rotate * alpha; + pose.mixX = base.mixX + x * alpha; + pose.mixY = base.mixY + y * alpha; + pose.mixScaleX = base.mixScaleX + scaleX * alpha; + pose.mixScaleY = base.mixScaleY + scaleY * alpha; + pose.mixShearY = base.mixShearY + shearY * alpha; + } else { + pose.mixRotate = base.mixRotate + (rotate - base.mixRotate) * alpha; + pose.mixX = base.mixX + (x - base.mixX) * alpha; + pose.mixY = base.mixY + (y - base.mixY) * alpha; + pose.mixScaleX = base.mixScaleX + (scaleX - base.mixScaleX) * alpha; + pose.mixScaleY = base.mixScaleY + (scaleY - base.mixScaleY) * alpha; + pose.mixShearY = base.mixShearY + (shearY - base.mixShearY) * alpha; + } + } + }; + var ConstraintTimeline1 = class extends CurveTimeline1 { + constraintIndex; + constructor(frameCount, bezierCount, constraintIndex, property) { + super(frameCount, bezierCount, `${property}|${constraintIndex}`); + this.constraintIndex = constraintIndex; + } + }; + var PathConstraintPositionTimeline = class extends ConstraintTimeline1 { + constructor(frameCount, bezierCount, constraintIndex) { + super(frameCount, bezierCount, constraintIndex, 18 /* pathConstraintPosition */); + this.additive = true; + } + apply(skeleton, lastTime, time, firedEvents, alpha, from, add, out, appliedPose) { + const constraint = skeleton.constraints[this.constraintIndex]; + if (constraint.active) { + const pose = appliedPose ? constraint.appliedPose : constraint.pose; + pose.position = this.getAbsoluteValue(time, alpha, from, add, pose.position, constraint.data.setupPose.position); + } + } + }; + var PathConstraintSpacingTimeline = class extends ConstraintTimeline1 { + constructor(frameCount, bezierCount, constraintIndex) { + super(frameCount, bezierCount, constraintIndex, 19 /* pathConstraintSpacing */); + } + apply(skeleton, lastTime, time, firedEvents, alpha, from, add, out, appliedPose) { + const constraint = skeleton.constraints[this.constraintIndex]; + if (constraint.active) { + const pose = appliedPose ? constraint.appliedPose : constraint.pose; + pose.spacing = this.getAbsoluteValue( + time, + alpha, + from, + false, + pose.spacing, + constraint.data.setupPose.spacing + ); + } + } + }; + var PathConstraintMixTimeline = class extends CurveTimeline { + constraintIndex; + constructor(frameCount, bezierCount, constraintIndex) { + super(frameCount, bezierCount, `${20 /* pathConstraintMix */}|${constraintIndex}`); + this.constraintIndex = constraintIndex; + } + getFrameEntries() { + return 4; + } + /** Sets the time and color for the specified frame. + * @param frame Between 0 and `frameCount`, inclusive. + * @param time The frame time in seconds. */ + setFrame(frame, time, mixRotate, mixX, mixY) { + const frames = this.frames; + frame <<= 2; + frames[frame] = time; + frames[ + frame + 1 + /*ROTATE*/ + ] = mixRotate; + frames[ + frame + 2 + /*X*/ + ] = mixX; + frames[ + frame + 3 + /*Y*/ + ] = mixY; + } + apply(skeleton, lastTime, time, firedEvents, alpha, from, add, out, appliedPose) { + const constraint = skeleton.constraints[this.constraintIndex]; + if (!constraint.active) return; + const pose = appliedPose ? constraint.appliedPose : constraint.pose; + const frames = this.frames; + if (time < frames[0]) { + const setup = constraint.data.setupPose; + switch (from) { + case 1 /* setup */: { + pose.mixRotate = setup.mixRotate; + pose.mixX = setup.mixX; + pose.mixY = setup.mixY; + break; + } + case 2 /* first */: { + pose.mixRotate += (setup.mixRotate - pose.mixRotate) * alpha; + pose.mixX += (setup.mixX - pose.mixX) * alpha; + pose.mixY += (setup.mixY - pose.mixY) * alpha; + break; + } + } + return; + } + let rotate, x, y; + const i = Timeline.search( + frames, + time, + 4 + /*ENTRIES*/ + ); + const curveType = this.curves[i >> 2]; + switch (curveType) { + case 0: { + const before = frames[i]; + rotate = frames[ + i + 1 + /*ROTATE*/ + ]; + x = frames[ + i + 2 + /*X*/ + ]; + y = frames[ + i + 3 + /*Y*/ + ]; + const t = (time - before) / (frames[ + i + 4 + /*ENTRIES*/ + ] - before); + rotate += (frames[ + i + 4 + 1 + /*ROTATE*/ + ] - rotate) * t; + x += (frames[ + i + 4 + 2 + /*X*/ + ] - x) * t; + y += (frames[ + i + 4 + 3 + /*Y*/ + ] - y) * t; + break; + } + case 1: + rotate = frames[ + i + 1 + /*ROTATE*/ + ]; + x = frames[ + i + 2 + /*X*/ + ]; + y = frames[ + i + 3 + /*Y*/ + ]; + break; + default: + rotate = this.getBezierValue( + time, + i, + 1, + curveType - 2 + /*BEZIER*/ + ); + x = this.getBezierValue( + time, + i, + 2, + curveType + 18 - 2 + /*BEZIER*/ + ); + y = this.getBezierValue( + time, + i, + 3, + curveType + 18 * 2 - 2 + /*BEZIER*/ + ); + } + const base = from === 1 /* setup */ ? constraint.data.setupPose : pose; + if (add) { + pose.mixRotate = base.mixRotate + rotate * alpha; + pose.mixX = base.mixX + x * alpha; + pose.mixY = base.mixY + y * alpha; + } else { + pose.mixRotate = base.mixRotate + (rotate - base.mixRotate) * alpha; + pose.mixX = base.mixX + (x - base.mixX) * alpha; + pose.mixY = base.mixY + (y - base.mixY) * alpha; + } + } + }; + var PhysicsConstraintTimeline = class extends ConstraintTimeline1 { + /** @param constraintIndex -1 for all physics constraints in the skeleton. */ + constructor(frameCount, bezierCount, constraintIndex, property) { + super(frameCount, bezierCount, constraintIndex, property); + } + apply(skeleton, lastTime, time, firedEvents, alpha, from, add, out, appliedPose) { + if (add && !this.additive) add = false; + if (this.constraintIndex === -1) { + const value = time >= this.frames[0] ? this.getCurveValue(time) : 0; + const constraints = skeleton.physics; + for (const constraint of constraints) { + if (constraint.active && this.global(constraint.data)) { + const pose = appliedPose ? constraint.appliedPose : constraint.pose; + this.set(pose, this.getAbsoluteValue(time, alpha, from, add, this.get(pose), this.get(constraint.data.setupPose), value)); + } + } + } else { + const constraint = skeleton.constraints[this.constraintIndex]; + if (constraint.active) { + const pose = appliedPose ? constraint.appliedPose : constraint.pose; + this.set(pose, this.getAbsoluteValue(time, alpha, from, add, this.get(pose), this.get(constraint.data.setupPose))); + } + } + } + }; + var PhysicsConstraintInertiaTimeline = class extends PhysicsConstraintTimeline { + constructor(frameCount, bezierCount, constraintIndex) { + super(frameCount, bezierCount, constraintIndex, 21 /* physicsConstraintInertia */); + } + get(pose) { + return pose.inertia; + } + set(pose, value) { + pose.inertia = value; + } + global(constraint) { + return constraint.inertiaGlobal; + } + }; + var PhysicsConstraintStrengthTimeline = class extends PhysicsConstraintTimeline { + constructor(frameCount, bezierCount, constraintIndex) { + super(frameCount, bezierCount, constraintIndex, 22 /* physicsConstraintStrength */); + } + get(pose) { + return pose.strength; + } + set(pose, value) { + pose.strength = value; + } + global(constraint) { + return constraint.strengthGlobal; + } + }; + var PhysicsConstraintDampingTimeline = class extends PhysicsConstraintTimeline { + constructor(frameCount, bezierCount, constraintIndex) { + super(frameCount, bezierCount, constraintIndex, 23 /* physicsConstraintDamping */); + } + get(pose) { + return pose.damping; + } + set(pose, value) { + pose.damping = value; + } + global(constraint) { + return constraint.dampingGlobal; + } + }; + var PhysicsConstraintMassTimeline = class extends PhysicsConstraintTimeline { + constructor(frameCount, bezierCount, constraintIndex) { + super(frameCount, bezierCount, constraintIndex, 24 /* physicsConstraintMass */); + } + get(pose) { + return 1 / pose.massInverse; + } + set(pose, value) { + pose.massInverse = 1 / value; + } + global(constraint) { + return constraint.massGlobal; + } + }; + var PhysicsConstraintWindTimeline = class extends PhysicsConstraintTimeline { + constructor(frameCount, bezierCount, constraintIndex) { + super(frameCount, bezierCount, constraintIndex, 25 /* physicsConstraintWind */); + this.additive = true; + } + get(pose) { + return pose.wind; + } + set(pose, value) { + pose.wind = value; + } + global(constraint) { + return constraint.windGlobal; + } + }; + var PhysicsConstraintGravityTimeline = class extends PhysicsConstraintTimeline { + constructor(frameCount, bezierCount, constraintIndex) { + super(frameCount, bezierCount, constraintIndex, 26 /* physicsConstraintGravity */); + this.additive = true; + } + get(pose) { + return pose.gravity; + } + set(pose, value) { + pose.gravity = value; + } + global(constraint) { + return constraint.gravityGlobal; + } + }; + var PhysicsConstraintMixTimeline = class extends PhysicsConstraintTimeline { + constructor(frameCount, bezierCount, constraintIndex) { + super(frameCount, bezierCount, constraintIndex, 27 /* physicsConstraintMix */); + } + get(pose) { + return pose.mix; + } + set(pose, value) { + pose.mix = value; + } + global(constraint) { + return constraint.mixGlobal; + } + }; + var PhysicsConstraintResetTimeline = class _PhysicsConstraintResetTimeline extends Timeline { + static propertyIds = [28 /* physicsConstraintReset */.toString()]; + /** The index of the physics constraint in {@link Skeleton.contraints} that will be reset when this timeline is + * applied, or -1 if all physics constraints in the skeleton will be reset. */ + constraintIndex; + /** @param constraintIndex -1 for all physics constraints in the skeleton. */ + constructor(frameCount, constraintIndex) { + super(frameCount, ..._PhysicsConstraintResetTimeline.propertyIds); + this.constraintIndex = constraintIndex; + this.instant = true; + } + getFrameCount() { + return this.frames.length; + } + /** Sets the time for the specified frame. + * @param frame Between 0 and `frameCount`, inclusive. */ + setFrame(frame, time) { + this.frames[frame] = time; + } + /** Resets the physics constraint when frames > `lastTime` and <= `time`. */ + apply(skeleton, lastTime, time, firedEvents, alpha, from, add, out, appliedPose) { + let constraint; + if (this.constraintIndex !== -1) { + constraint = skeleton.constraints[this.constraintIndex]; + if (!constraint.active) return; + } + const frames = this.frames; + if (lastTime > time) { + this.apply(skeleton, lastTime, Number.MAX_VALUE, [], alpha, from, false, false, false); + lastTime = -1; + } else if (lastTime >= frames[frames.length - 1]) + return; + if (time < frames[0]) return; + if (lastTime < frames[0] || time >= frames[Timeline.search(frames, lastTime) + 1]) { + if (constraint != null) + constraint.reset(skeleton); + else { + for (const constraint2 of skeleton.physics) { + if (constraint2.active) constraint2.reset(skeleton); + } + } + } + } + }; + var SliderTimeline = class extends ConstraintTimeline1 { + constructor(frameCount, bezierCount, constraintIndex) { + super(frameCount, bezierCount, constraintIndex, 30 /* sliderTime */); + } + apply(skeleton, lastTime, time, firedEvents, alpha, from, add, out, appliedPose) { + const constraint = skeleton.constraints[this.constraintIndex]; + if (constraint.active) { + const pose = appliedPose ? constraint.appliedPose : constraint.pose; + pose.time = this.getAbsoluteValue(time, alpha, from, add, pose.time, constraint.data.setupPose.time); + } + } + }; + var SliderMixTimeline = class extends ConstraintTimeline1 { + constructor(frameCount, bezierCount, constraintIndex) { + super(frameCount, bezierCount, constraintIndex, 31 /* sliderMix */); + this.additive = true; + } + apply(skeleton, lastTime, time, firedEvents, alpha, from, add, out, appliedPose) { + const constraint = skeleton.constraints[this.constraintIndex]; + if (constraint.active) { + const pose = appliedPose ? constraint.appliedPose : constraint.pose; + pose.mix = this.getAbsoluteValue(time, alpha, from, add, pose.mix, constraint.data.setupPose.mix); + } + } + }; + + // spine-core/src/AnimationState.ts + var AnimationState = class _AnimationState { + static emptyAnimation = new Animation("", [], 0); + /** The AnimationStateData to look up mix durations. */ + data; + /** The list of tracks that have had animations. May contain null entries for tracks that currently have no animation. */ + tracks = []; + /** Multiplier for the delta time when the animation state is updated, causing time for all animations and mixes to play slower + * or faster. Defaults to 1. + * + * See {@link TrackEntry.timeScale} to affect a single animation. */ + timeScale = 1; + unkeyedState = 0; + events = []; + listeners = []; + queue = new EventQueue(this); + propertyIds = /* @__PURE__ */ new Map(); + animationsChanged = false; + trackEntryPool = new Pool(() => new TrackEntry()); + constructor(data) { + this.data = data; + } + /** Increments each track entry {@link TrackEntry.trackTime}, setting queued animations as current if needed. */ + update(delta) { + delta *= this.timeScale; + const tracks = this.tracks; + for (let i = 0, n = tracks.length; i < n; i++) { + const current = tracks[i]; + if (!current) continue; + current.animationLast = current.nextAnimationLast; + current.trackLast = current.nextTrackLast; + let currentDelta = delta * current.timeScale; + if (current.delay > 0) { + current.delay -= currentDelta; + if (current.delay > 0) continue; + currentDelta = -current.delay; + current.delay = 0; + } + let next = current.next; + if (next) { + const 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.setTrack(i, next, true); + while (next.mixingFrom) { + next.mixTime += delta; + next = next.mixingFrom; + } + continue; + } + } else if (current.trackLast >= current.trackEnd && !current.mixingFrom) { + tracks[i] = null; + this.queue.end(current); + this.clearNext(current); + continue; + } + if (current.mixingFrom && this.updateMixingFrom(current, delta)) { + let from = current.mixingFrom; + current.mixingFrom = null; + if (from) from.mixingTo = null; + while (from) { + this.queue.end(from); + from = from.mixingFrom; + } + } + current.trackTime += currentDelta; + } + this.queue.drain(); + } + /** Returns true when all mixing from entries are complete. */ + updateMixingFrom(to, delta) { + const from = to.mixingFrom; + if (!from) return true; + const finished = this.updateMixingFrom(from, delta); + from.animationLast = from.nextAnimationLast; + from.trackLast = from.nextTrackLast; + if (to.nextTrackLast !== -1 && to.mixTime >= to.mixDuration) { + if (from.totalAlpha === 0 || to.mixDuration === 0) { + to.mixingFrom = from.mixingFrom; + if (from.mixingFrom != null) from.mixingFrom.mixingTo = to; + if (from.totalAlpha === 0) { + for (let next = to; next.mixingTo != null; next = next.mixingTo) + next.keepHold = true; + } + this.queue.end(from); + } + return finished; + } + from.trackTime += delta * from.timeScale; + to.mixTime += delta; + return false; + } + /** Poses the skeleton using the track entry animations. The animation state is not changed, so can be applied to multiple + * skeletons to pose them identically. + * @returns True if any animations were applied. */ + apply(skeleton) { + if (!skeleton) throw new Error("skeleton cannot be null."); + if (this.animationsChanged) this._animationsChanged(); + const events = this.events; + const tracks = this.tracks; + let applied = false; + for (let i = 0, n = tracks.length; i < n; i++) { + const current = tracks[i]; + if (!current || current.delay > 0) continue; + applied = true; + let alpha = current.alpha; + if (current.mixingFrom) + alpha *= this.applyMixingFrom(current, skeleton); + else if (current.trackTime >= current.trackEnd && !current.next) + alpha = 0; + let animationLast = current.animationLast, animationTime = current.getAnimationTime(), applyTime = animationTime; + let applyEvents = events; + if (current.reverse) { + applyTime = current.animation.duration - applyTime; + applyEvents = null; + } + const timelines = current.animation.timelines; + const timelineCount = timelines.length; + if (i === 0 && alpha === 1) { + for (let ii = 0; ii < timelineCount; ii++) { + Utils.webkit602BugfixHelper(alpha); + const timeline = timelines[ii]; + if (timeline instanceof AttachmentTimeline) + this.applyAttachmentTimeline(timeline, skeleton, applyTime, 1 /* setup */, true); + else + timeline.apply(skeleton, animationLast, applyTime, applyEvents, alpha, 1 /* setup */, false, false, false); + } + } else { + const timelineMode = current.timelineMode; + const retainAttachments = alpha >= current.alphaAttachmentThreshold; + const add = current.additive, shortestRotation = add || current.shortestRotation; + const firstFrame = !shortestRotation && current.timelinesRotation.length !== timelineCount << 1; + if (firstFrame) current.timelinesRotation.length = timelineCount << 1; + for (let ii = 0; ii < timelineCount; ii++) { + const timeline = timelines[ii]; + const from = timelineMode[ii] & MODE; + if (!shortestRotation && timeline instanceof RotateTimeline) { + this.applyRotateTimeline(timeline, skeleton, applyTime, alpha, from, current.timelinesRotation, ii << 1, firstFrame); + } else if (timeline instanceof AttachmentTimeline) { + this.applyAttachmentTimeline(timeline, skeleton, applyTime, from, retainAttachments); + } else { + Utils.webkit602BugfixHelper(alpha); + timeline.apply(skeleton, animationLast, applyTime, applyEvents, alpha, from, add, false, false); + } + } + } + if (current.reverse) this.eventsReverse(current, animationLast, animationTime); + this.queueEvents(current, animationTime); + events.length = 0; + current.nextAnimationLast = animationTime; + current.nextTrackLast = current.trackTime; + } + const setupState = this.unkeyedState + ATTACH_SETUP; + const slots = skeleton.slots; + for (let i = 0, n = skeleton.slots.length; i < n; i++) { + const slot = slots[i]; + if (slot.attachmentState === setupState) { + const attachmentName = slot.data.attachmentName; + slot.pose.setAttachment(!attachmentName ? null : skeleton.getAttachment(slot.data.index, attachmentName)); + } + } + this.unkeyedState += 2; + this.queue.drain(); + return applied; + } + applyMixingFrom(to, skeleton) { + const from = to.mixingFrom; + const fromMix = from.mixingFrom !== null ? this.applyMixingFrom(from, skeleton) : 1; + const mix = to.mix(); + const a = from.alpha * fromMix, keep = 1 - mix * to.alpha; + const alphaMix = a * (1 - mix), alphaHold = keep > 0 ? alphaMix / keep : a; + const timelines = from.animation.timelines; + const timelineCount = timelines.length; + const timelineMode = from.timelineMode; + const timelineHoldMix = from.timelineHoldMix; + const retainAttachments = mix < from.mixAttachmentThreshold, drawOrder = mix < from.mixDrawOrderThreshold; + const add = from.additive, shortestRotation = add || from.shortestRotation; + const firstFrame = !shortestRotation && from.timelinesRotation.length !== timelineCount << 1; + if (firstFrame) from.timelinesRotation.length = timelineCount << 1; + const timelinesRotation = from.timelinesRotation; + let animationLast = from.animationLast, animationTime = from.getAnimationTime(), applyTime = animationTime; + let events = null; + if (from.reverse) + applyTime = from.animation.duration - applyTime; + else if (mix < from.eventThreshold) + events = this.events; + from.totalAlpha = 0; + for (let i = 0; i < timelineCount; i++) { + const timeline = timelines[i]; + const mode = timelineMode[i]; + const mixFrom = mode & MODE; + let alpha = 0; + if ((mode & HOLD) !== 0) { + const holdMix = timelineHoldMix[i]; + alpha = holdMix == null ? alphaHold : alphaHold * (1 - holdMix.mix()); + } else { + if (!drawOrder && timeline instanceof DrawOrderTimeline && mixFrom === 0 /* current */) continue; + alpha = alphaMix; + } + from.totalAlpha += alpha; + if (!shortestRotation && timeline instanceof RotateTimeline) { + this.applyRotateTimeline(timeline, skeleton, applyTime, alpha, mixFrom, timelinesRotation, i << 1, firstFrame); + } else if (timeline instanceof AttachmentTimeline) + this.applyAttachmentTimeline( + timeline, + skeleton, + applyTime, + mixFrom, + retainAttachments && alpha >= from.alphaAttachmentThreshold + ); + else { + const out = !drawOrder || !(timeline instanceof DrawOrderTimeline) || mixFrom === 0 /* current */; + timeline.apply(skeleton, animationLast, applyTime, events, alpha, mixFrom, add, out, false); + } + } + if (from.reverse && mix < from.eventThreshold) this.eventsReverse(from, animationLast, animationTime); + if (to.mixDuration > 0) this.queueEvents(from, animationTime); + this.events.length = 0; + from.nextAnimationLast = animationTime; + from.nextTrackLast = from.trackTime; + return mix; + } + /** Applies the attachment timeline and sets {@link Slot.attachmentState}. + * @param retain True if the attachment remains after apply, false if temporary for deform timelines. */ + applyAttachmentTimeline(timeline, skeleton, time, from, retain) { + const slot = skeleton.slots[timeline.slotIndex]; + if (!slot.bone.active) return; + if (!retain && slot.attachmentState === this.unkeyedState + ATTACH_RETAIN) return; + let setup = time < timeline.frames[0]; + let name = null; + if (!setup) { + name = timeline.attachmentNames[Timeline.search(timeline.frames, time)]; + setup = !retain && name == null; + } + if (setup) { + if (from === 0 /* current */) return; + name = slot.data.attachmentName; + } + slot.pose.setAttachment(name == null ? null : skeleton.getAttachment(slot.data.index, name)); + if (retain) + slot.attachmentState = this.unkeyedState + ATTACH_RETAIN; + else if (!setup) + slot.attachmentState = this.unkeyedState + ATTACH_SETUP; + } + /** Applies the rotate timeline, mixing with the current pose while keeping the same rotation direction chosen as the shortest + * the first time the mixing was applied. */ + applyRotateTimeline(timeline, skeleton, time, alpha, from, timelinesRotation, i, firstFrame) { + if (firstFrame) timelinesRotation[i] = 0; + if (alpha === 1) { + timeline.apply(skeleton, 0, time, null, 1, from, false, false, false); + return; + } + const bone = skeleton.bones[timeline.boneIndex]; + if (!bone.active) return; + const pose = bone.pose, setup = bone.data.setupPose; + const frames = timeline.frames; + let r1, r2; + if (time < frames[0]) { + switch (from) { + case 1 /* setup */: { + pose.rotation = setup.rotation; + return; + } + case 0 /* current */: { + return; + } + } + r1 = pose.rotation; + r2 = setup.rotation; + } else { + r1 = from === 1 /* setup */ ? setup.rotation : pose.rotation; + r2 = setup.rotation + timeline.getCurveValue(time); + } + let total = 0, diff = r2 - r1; + diff -= Math.ceil(diff / 360 - 0.5) * 360; + if (diff === 0) { + total = timelinesRotation[i]; + } else { + let lastTotal = 0, lastDiff = 0; + if (firstFrame) { + lastTotal = 0; + lastDiff = diff; + } else { + lastTotal = timelinesRotation[i]; + lastDiff = timelinesRotation[i + 1]; + } + const loops = lastTotal - lastTotal % 360; + total = diff + loops; + let current = diff >= 0, dir = lastTotal >= 0; + if (Math.abs(lastDiff) <= 90 && MathUtils.signum(lastDiff) !== MathUtils.signum(diff)) { + if (Math.abs(lastTotal - loops) > 180) { + total += 360 * MathUtils.signum(lastTotal); + dir = current; + } else if (loops !== 0) + total -= 360 * MathUtils.signum(lastTotal); + else + dir = current; + } + if (dir !== current) total += 360 * MathUtils.signum(lastTotal); + timelinesRotation[i] = total; + } + timelinesRotation[i + 1] = diff; + pose.rotation = r1 + total * alpha; + } + queueEvents(entry, animationTime) { + const animationStart = entry.animationStart, animationEnd = entry.animationEnd, duration = animationEnd - animationStart; + const reverse = entry.reverse; + let split = entry.trackLast % duration; + if (reverse) split = duration - split; + const events = this.events; + let i = 0, n = events.length; + for (; i < n; i++) { + const event = events[i]; + if (event.time < split !== reverse) break; + if (event.time >= animationStart && event.time <= animationEnd) this.queue.event(entry, event); + } + let complete = false; + if (entry.loop) { + if (duration === 0) + complete = true; + else { + const cycles = Math.floor(entry.trackTime / duration); + complete = cycles > 0 && cycles > Math.floor(entry.trackLast / duration); + } + } else + complete = animationTime >= animationEnd && entry.animationLast < animationEnd; + if (complete) this.queue.complete(entry); + for (; i < n; i++) { + const event = events[i]; + if (event.time >= animationStart && event.time <= animationEnd) this.queue.event(entry, event); + } + } + eventsReverse(entry, animationLast, animationTime) { + const duration = entry.animation.duration, from = duration - animationLast, to = duration - animationTime; + const timelines = entry.animation.timelines; + for (let i = 0, n = entry.animation.timelines.length; i < n; i++) { + const eventTimeline = timelines[i]; + if (!(eventTimeline instanceof EventTimeline)) continue; + const timelineEvents = eventTimeline.events; + const frames = eventTimeline.frames; + const frameCount = frames.length; + if (from >= to) { + for (let ii = 0; ii < frameCount; ii++) { + if (frames[ii] < to) continue; + if (frames[ii] >= from) break; + this.events.push(timelineEvents[ii]); + } + } else { + for (let ii2 = 0; ii2 < frameCount; ii2++) { + if (frames[ii2] >= from) break; + this.events.push(timelineEvents[ii2]); + } + let ii = 0; + for (; ii < frameCount; ii++) + if (frames[ii] >= to) break; + for (; ii < frameCount; ii++) + this.events.push(timelineEvents[ii]); + } + } + } + /** Removes all animations from all tracks, leaving skeletons in their current pose. + * + * Usually you want to use {@link setEmptyAnimations} to mix the skeletons back to the setup pose, rather than leaving + * them in their current pose. */ + clearTracks() { + const oldDrainDisabled = this.queue.drainDisabled; + this.queue.drainDisabled = true; + for (let i = 0, n = this.tracks.length; i < n; i++) + this.clearTrack(i); + this.tracks.length = 0; + this.queue.drainDisabled = oldDrainDisabled; + this.queue.drain(); + } + /** Removes all animations from the track, leaving skeletons in their current pose. + * + * Usually you want to use {@link setEmptyAnimation} to mix the skeletons back to the setup pose, rather than + * leaving them in their current pose. */ + clearTrack(trackIndex) { + if (trackIndex < 0) throw new Error("trackIndex must be >= 0."); + if (trackIndex >= this.tracks.length) return; + const current = this.tracks[trackIndex]; + if (!current) return; + this.queue.end(current); + this.clearNext(current); + let entry = current; + while (true) { + const from = entry.mixingFrom; + if (!from) break; + this.queue.end(from); + entry.mixingFrom = null; + entry.mixingTo = null; + entry = from; + } + this.tracks[current.trackIndex] = null; + this.queue.drain(); + } + setTrack(index, current, interrupt) { + const from = this.expandToIndex(index); + this.tracks[index] = current; + current.previous = null; + if (from) { + from.next = null; + if (interrupt) this.queue.interrupt(from); + current.mixingFrom = from; + from.mixingTo = current; + current.mixTime = 0; + from.timelinesRotation.length = 0; + } + this.queue.start(current); + } + setAnimation(trackIndex, animationNameOrAnimation, loop = false) { + if (typeof animationNameOrAnimation === "string") + return this.setAnimation1(trackIndex, animationNameOrAnimation, loop); + return this.setAnimation2(trackIndex, animationNameOrAnimation, loop); + } + setAnimation1(trackIndex, animationName, loop = false) { + const animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) throw new Error(`Animation not found: ${animationName}`); + return this.setAnimation2(trackIndex, animation, loop); + } + /** Sets the current animation for a track, discarding any queued animations. + * + * If the formerly current track entry is for the same animation and was never applied to a skeleton, it is replaced (not mixed + * from). + * @param loop If true, the animation will repeat. If false it will not, instead its last frame is applied if played beyond its + * duration. In either case {@link TrackEntry.getTrackEnd} determines when the track is cleared. + * @return A track entry to allow further customization of animation playback. References to the track entry must not be kept + * after the {@link AnimationStateListener.dispose} event occurs. */ + setAnimation2(trackIndex, animation, loop = false) { + if (trackIndex < 0) throw new Error("trackIndex must be >= 0."); + if (!animation) throw new Error("animation cannot be null."); + let interrupt = true; + let current = this.expandToIndex(trackIndex); + if (current) { + if (current.nextTrackLast === -1 && current.animation === animation) { + this.tracks[trackIndex] = current.mixingFrom; + this.queue.interrupt(current); + this.queue.end(current); + this.clearNext(current); + current = current.mixingFrom; + interrupt = false; + } else + this.clearNext(current); + } + const entry = this.trackEntry(trackIndex, animation, loop, current); + this.setTrack(trackIndex, entry, interrupt); + this.queue.drain(); + return entry; + } + addAnimation(trackIndex, animationNameOrAnimation, loop = false, delay = 0) { + if (typeof animationNameOrAnimation === "string") + return this.addAnimation1(trackIndex, animationNameOrAnimation, loop, delay); + return this.addAnimation2(trackIndex, animationNameOrAnimation, loop, delay); + } + addAnimation1(trackIndex, animationName, loop = false, delay = 0) { + const animation = this.data.skeletonData.findAnimation(animationName); + if (!animation) throw new Error(`Animation not found: ${animationName}`); + return this.addAnimation2(trackIndex, animation, loop, delay); + } + addAnimation2(trackIndex, animation, loop = false, delay = 0) { + if (trackIndex < 0) throw new Error("trackIndex must be >= 0."); + if (!animation) throw new Error("animation cannot be null."); + let last = this.expandToIndex(trackIndex); + if (last) { + while (last.next) + last = last.next; + } + const entry = this.trackEntry(trackIndex, animation, loop, last); + if (!last) { + this.setTrack(trackIndex, entry, true); + this.queue.drain(); + if (delay < 0) delay = 0; + } else { + last.next = entry; + entry.previous = last; + if (delay <= 0) delay = Math.max(delay + last.getTrackComplete() - entry.mixDuration, 0); + } + entry.delay = delay; + return entry; + } + /** Sets an empty animation for a track, discarding any queued animations, and sets the track entry's + * {@link TrackEntry.mixduration}. An empty animation has no timelines and serves as a placeholder for mixing in or out. + * + * Mixing out is done by setting an empty animation with a mix duration using either {@link setEmptyAnimation}, + * {@link setEmptyAnimations}, or {@link addEmptyAnimation}. Mixing to an empty animation causes + * the previous animation to be applied less and less over the mix duration. Properties keyed in the previous animation + * transition to the value from lower tracks or to the setup pose value if no lower tracks key the property. A mix duration of + * 0 still needs to be applied one more time to mix out, so the properties it was animating are reverted. + * + * Mixing in is done by first setting an empty animation, then adding an animation using + * {@link addAnimation} with the desired delay (an empty animation has a duration of 0) and on + * the returned track entry, set the {@link TrackEntry.setMixDuration}. Mixing from an empty animation causes the new + * animation to be applied more and more over the mix duration. Properties keyed in the new animation transition from the value + * from lower tracks or from the setup pose value if no lower tracks key the property to the value keyed in the new animation. + * + * See Empty animations in the Spine + * Runtimes Guide. */ + setEmptyAnimation(trackIndex, mixDuration = 0) { + const entry = this.setAnimation(trackIndex, _AnimationState.emptyAnimation, false); + entry.mixDuration = mixDuration; + entry.trackEnd = mixDuration; + return entry; + } + /** Adds an empty animation to be played after the current or last queued animation for a track, and sets the track entry's + * {@link TrackEntry.mixDuration}. If the track has no entries, it is equivalent to calling + * {@link setEmptyAnimation}. + * + * See {@link setEmptyAnimation} and + * Empty animations in the Spine Runtimes + * Guide. + * @param delay If > 0, sets {@link TrackEntry.delay}. If <= 0, the delay set is the duration of the previous track entry minus + * any mix duration plus the specified `delay` (ie the mix ends at (when `delay` = 0) or before + * (when `delay` < 0) the previous track entry duration). If the previous entry is looping, its next loop + * completion is used instead of its duration. + * @return A track entry to allow further customization of animation playback. References to the track entry must not be kept + * after the {@link AnimationStateListener.dispose} event occurs. */ + addEmptyAnimation(trackIndex, mixDuration = 0, delay = 0) { + const entry = this.addAnimation(trackIndex, _AnimationState.emptyAnimation, false, delay); + if (delay <= 0) entry.delay = Math.max(entry.delay + entry.mixDuration - mixDuration, 0); + entry.mixDuration = mixDuration; + entry.trackEnd = mixDuration; + return entry; + } + /** Sets an empty animation for every track, discarding any queued animations, and mixes to it over the specified mix duration. + * + * See Empty animations in the Spine + * Runtimes Guide. */ + setEmptyAnimations(mixDuration = 0) { + const oldDrainDisabled = this.queue.drainDisabled; + this.queue.drainDisabled = true; + for (let i = 0, n = this.tracks.length; i < n; i++) { + const current = this.tracks[i]; + if (current) this.setEmptyAnimation(current.trackIndex, mixDuration); + } + this.queue.drainDisabled = oldDrainDisabled; + this.queue.drain(); + } + expandToIndex(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 last May be null. */ + trackEntry(trackIndex, animation, loop, last) { + const entry = this.trackEntryPool.obtain(); + entry.reset(); + entry.trackIndex = trackIndex; + entry.animation = animation; + entry.loop = loop; + entry.additive = false; + entry.reverse = false; + entry.shortestRotation = false; + entry.eventThreshold = 0; + entry.alphaAttachmentThreshold = 0; + entry.mixAttachmentThreshold = 0; + entry.mixDrawOrderThreshold = 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.mixTime = 0; + entry.mixDuration = !last ? 0 : this.data.getMix(last.animation, animation); + entry.totalAlpha = 0; + entry.keepHold = false; + return entry; + } + /** Removes {@link TrackEntry.next} and all entries after it for the specified entry. */ + clearNext(entry) { + let next = entry.next; + while (next) { + this.queue.dispose(next); + next = next.next; + } + entry.next = null; + } + _animationsChanged() { + this.animationsChanged = false; + const tracks = this.tracks; + for (let i = 0, n = tracks.length; i < n; i++) { + const track = tracks[i]; + if (!track) continue; + let entry = track; + while (entry.mixingFrom) + entry = entry.mixingFrom; + do { + this.computeHold(entry, track); + entry = entry.mixingTo; + } while (entry); + } + this.propertyIds.clear(); + } + computeHold(entry, track) { + const timelines = entry.animation.timelines; + const timelinesCount = entry.animation.timelines.length; + const timelineMode = entry.timelineMode; + timelineMode.length = timelinesCount; + const timelineHoldMix = entry.timelineHoldMix; + timelineHoldMix.length = 0; + const add = entry.additive, keepHold = entry.keepHold; + const to = entry.mixingTo; + for (let i = 0; i < timelinesCount; i++) { + const timeline = timelines[i]; + const ids = timeline.propertyIds; + const from = this.from(track, timeline, ids); + if (add && timeline.additive) { + timelineMode[i] = from; + continue; + } + let mode; + if (to === null || timeline.instant || to.additive && timeline.additive || !to.animation?.hasTimeline(ids)) + mode = from; + else { + mode = from | HOLD; + for (let next = to.mixingTo; next != null; next = next.mixingTo) { + if (next.additive && timeline.additive || !next.animation?.hasTimeline(ids)) { + if (next.mixDuration > 0) timelineHoldMix[i] = next; + break; + } + } + } + if (keepHold) mode = mode & ~HOLD | timelineMode[i] & HOLD; + timelineMode[i] = mode; + } + } + from(track, timeline, ids) { + const propertyIds = this.propertyIds; + let from = SETUP; + for (let i = 0, n = ids.length; i < n; i++) { + const owner = propertyIds.get(ids[i]); + if (owner === void 0) { + propertyIds.set(ids[i], track); + } else { + if (owner !== track) { + while (++i < n) + if (!propertyIds.has(ids[i])) propertyIds.set(ids[i], track); + return CURRENT; + } + from = FIRST; + } + } + if (timeline instanceof DrawOrderFolderTimeline) { + const first = propertyIds.get(DrawOrderTimeline.propertyID); + if (first != null) return first !== track ? CURRENT : FIRST; + } + return from; + } + /** Returns the track entry for the animation currently playing on the track, or null if no animation is currently playing. */ + getTrack(trackIndex) { + if (trackIndex < 0) throw new Error("trackIndex must be >= 0."); + if (trackIndex >= this.tracks.length) return null; + return this.tracks[trackIndex]; + } + /** Adds a listener to receive events for all track entries. */ + addListener(listener) { + if (!listener) throw new Error("listener cannot be null."); + this.listeners.push(listener); + } + /** Removes the listener added with {@link addListener}. */ + removeListener(listener) { + const index = this.listeners.indexOf(listener); + if (index >= 0) this.listeners.splice(index, 1); + } + /** Removes all listeners added with {@link addListener}. */ + clearListeners() { + this.listeners.length = 0; + } + /** Discards all listener notifications that have not yet been delivered. This can be useful to call from an + * {@link AnimationStateListener} when it is known that further notifications that may have been already queued for delivery + * are not wanted because new animations are being set. */ + clearListenerNotifications() { + this.queue.clear(); + } + }; + var TrackEntry = class { + /** The animation to apply for this track entry. */ + animation = null; + previous = null; + /** The animation queued to start after this animation, or null. `next` makes up a linked list. */ + next = null; + /** The track entry for the previous animation when mixing to this animation, or null if no mixing is currently occurring. + * When mixing from multiple animations, `mixingFrom` makes up a doubly linked list. */ + mixingFrom = null; + /** The track entry for the next animation when mixing from this animation, or null if no mixing is currently occurring. + * When mixing to multiple animations, `mixingTo` makes up a doubly linked list. */ + mixingTo = null; + /** The listener for events generated by this track entry, or null. + * + * A track entry returned from {@link AnimationState.setAnimation} is already the current animation + * for the track, so the callback for listener {@link AnimationStateListener.start} will not be called. */ + listener = null; + /** The index of the track where this track entry is either current or queued. + * + * See {@link AnimationState.getTrack}. */ + trackIndex = 0; + /** If true, the animation will repeat. If false it will not, instead its last frame is applied if played beyond its + * duration. */ + loop = false; + /** When true, timelines in this animation that support additive have their values added to the setup or current pose values + * instead of replacing them. Additive can be set for a new track entry only before {@link AnimationState.apply} + * is next called. */ + additive = false; + /** If true, the animation will be applied in reverse. */ + reverse = false; + /** If true, mixing rotation between tracks always uses the shortest rotation direction. If the rotation is animated, the + * shortest rotation direction may change during the mix. + * + * If false, the shortest rotation direction is remembered when the mix starts and the same direction is used for the rest + * of the mix. Defaults to false. + * + * See {@link resetRotationDirections}. */ + shortestRotation = false; + keepHold = false; + /** When the interpolated mix percentage is less than the `eventThreshold` , event timelines are applied while + * this animation is being mixed out. Defaults to 0, so event timelines are not applied while this animation is being mixed + * out. */ + eventThreshold = 0; + /** When the interpolated mix percentage is less than the `mixAttachmentThreshold`, attachment timelines are + * applied while this animation is being mixed out. Defaults to 0, so attachment timelines are not applied while this + * animation is being mixed out. */ + mixAttachmentThreshold = 0; + /** When the computed alpha is greater than `alphaAttachmentThreshold`, attachment timelines are applied. The + * computed alpha includes {@link alpha} and the interpolated mix percentage. Defaults to 0, so attachment timelines are + * always applied. */ + alphaAttachmentThreshold = 0; + /** When the interpolated mix percentage is less than the `mixAttachmentThreshold`, attachment timelines are + * applied while this animation is being mixed out. Defaults to 0, so attachment timelines are not applied while this + * animation is being mixed out. */ + mixDrawOrderThreshold = 0; + /** The time in seconds for the first frame of this animation, both initially and after looping. Defaults to 0. + * + * When setting `animationStart` time, {@link animationLast} can be set to the same value to avoid firing events + * from the start of the animation. */ + animationStart = 0; + /** The time in seconds for the last frame of this animation. Past this time, non-looping animations hold the pose at this + * time while looping animations will loop back to {@link animationStart}. Defaults to the {@link Animation.duration}. */ + animationEnd = 0; + /** The time in seconds this animation was last applied. Some timelines use this for one-time triggers. For example, when + * this animation is applied, event timelines will fire all events between the `animationLast` time (exclusive) + * and `animationTime` (inclusive). Defaults to -1 to ensure triggers on frame 0 happen the first time this + * animation is applied. */ + animationLast = 0; + nextAnimationLast = 0; + /** Seconds to postpone playing the animation. Must be >= 0. When this track entry is the current track entry, + * `delay` postpones incrementing the {@link trackTime}. When this track entry is queued, `delay` is + * the time from the start of the previous animation to when this track entry will become the current track entry (ie when + * the previous track entry {@link trackTime} >= this track entry's `delay`). + * + * {@link timeScale} affects the delay. + * + * When passing `delay` <= 0 to {@link AnimationState.addAnimation} this + * `delay` is set using a mix duration from {@link AnimationStateData}. To change the {@link mixDuration} + * afterward, use {@link setMixDuration} so this `delay` is adjusted. */ + delay = 0; + /** The time in seconds this track entry has been the current track entry, starting at 0 and increasing forever. Compare to + * {@link getAnimationTime}, which is always between {@link animationStart} and {@link animationEnd}. + * + * The track time can be set to start the animation at a time other than 0, without affecting looping. When doing so, + * {@link animationLast} can be set to the same value to avoid firing events from the start of the animation. + * + * To set the time an animation starts and loops, use {@link animationStart} and {@link animationEnd}. */ + trackTime = 0; + trackLast = 0; + nextTrackLast = 0; + /** The track time in seconds when this animation will be removed from the track. Defaults to the highest possible float + * value, meaning the animation will be applied until a new animation is set or the track is cleared. If the track end time + * is reached, no other animations are queued for playback, and mixing from any previous animations is complete, then the + * properties keyed by the animation are set to the setup pose and the track is cleared. + * + * Usually you want to use {@link AnimationState.addEmptyAnimation} rather than have the animation + * abruptly cease being applied, leaving the current pose. */ + trackEnd = 0; + /** Multiplier for the delta time when this track entry is updated, causing time for this animation to pass slower or + * faster. Defaults to 1. + * + * Values < 0 are not supported. To play an animation in reverse, use {@link reverse}. + * + * {@link mixTime} is not affected by track entry time scale, so {@link mixDuration} may need to be adjusted to match the + * animation speed. + * + * When using {@link AnimationState.addAnimation} with a `delay` <= 0, the + * {@link delay} is set using the mix duration from {@link AnimationState.data}, assuming time scale to be 1. If the time + * scale is not 1, the delay may need to be adjusted. + * + * See {@link AnimationState.timeScale} to affect all animations. */ + timeScale = 0; + /** Values < 1 mix this animation with the skeleton's current pose (either the setup pose or the pose from lower tracks). + * Defaults to 1, which overwrites the skeleton's current pose with this animation. + * + * Alpha should be 1 on track 0. + * + * See {@link getAlphaAttachmentThreshold}. */ + alpha = 0; + /** Seconds elapsed from 0 to the {@link mixDuration} when mixing from the previous animation to this animation. May + * be slightly more than `mixDuration` when the mix is complete. */ + mixTime = 0; + /** Seconds for mixing from the previous animation to this animation. Defaults to the value provided by + * {@link AnimationStateData.getMix} based on the animation before this animation (if any). + * + * A mix duration of 0 still needs to be applied one more time to mix out, so the the properties it was animating are + * reverted. A mix duration of 0 can be set at any time to end the mix on the next + * {@link AnimationState.update | update}. + * + * The `mixDuration` can be set manually rather than use the value from + * {@link AnimationStateData.getMix}. In that case, the `mixDuration` can be set for a new + * track entry only before {@link AnimationState.update} is next called. + * + * When using {@link AnimationState.addAnimation} with a `delay` <= 0, the + * {@link getDelay} is set using the mix duration from {@link AnimationState.data}. If `mixDuration` is set + * afterward, the delay needs to be adjusted: + * + *

+     * entry.mixDuration = 0.25;
+ * entry.delay = entry.previous.getTrackComplete() - entry.mixDuration + 0; + *
+ * + * Alternatively, use {@link setMixDuration} to set both the mix duration and recompute the delay:
+ * + *
+      entry.setMixDuration(0.25f, 0); // mixDuration, delay
+     * 
+ */ + mixDuration = 0; + totalAlpha = 0; + mixInterpolation = Interpolation.linear; + /** Sets both {@link getMixDuration} and {@link getDelay}. + * @param delay If > 0, sets {@link getDelay}. If <= 0, the delay set is the duration of the previous track entry minus + * the specified mix duration plus the specified `delay` (ie the mix ends at (when `delay` = + * 0) or before (when `delay` < 0) the previous track entry duration). If the previous entry is + * looping, its next loop completion is used instead of its duration. */ + setMixDuration(mixDuration, delay) { + this.mixDuration = mixDuration; + if (delay !== void 0) { + if (delay <= 0) delay = this.previous == null ? 0 : Math.max(delay + this.previous.getTrackComplete() - mixDuration, 0); + this.delay = delay; + } + } + /** The interpolation to apply to the mix percentage ({@link mixTime} / {@link mixDuration}) when mixing from the previous + * animation to this animation. Defaults to linear. */ + setMixInterpolation(mixInterpolation) { + if (!mixInterpolation) throw new Error("mixInterpolation cannot be null."); + this.mixInterpolation = mixInterpolation; + } + mix() { + if (this.mixDuration === 0) return 1; + let mix = this.mixTime / this.mixDuration; + if (mix >= 1) return 1; + if (this.mixInterpolation === Interpolation.linear) return mix; + mix = this.mixInterpolation.apply(mix); + if (mix < 0) return 0; + if (mix > 1) return 1; + return mix; + } + /** For each timeline: + * - Bits 0-1: MixFrom. + * - Bit 2, HOLD: 0 = mix out using alphaMix, 1 = apply full alpha to prevent dipping. Timeline is first on its track to + * set the property and the next entry (mixingTo) also sets it. When held, timelineHoldMix's mix controls how the hold fades + * out (for 3+ entry chains where the chain eventually stops setting the property). */ + timelineMode = []; + timelineHoldMix = []; + timelinesRotation = []; + reset() { + this.next = null; + this.previous = null; + this.mixingFrom = null; + this.mixingTo = null; + this.mixInterpolation = Interpolation.linear; + this.animation = null; + this.listener = null; + this.timelineMode.length = 0; + this.timelineHoldMix.length = 0; + this.timelinesRotation.length = 0; + } + /** Uses {@link trackTime} to compute the `animationTime`, which is always between {@link animationStart} and + * {@link animationEnd}. When `trackTime` is 0, `animationTime` is equal to the + * `animationStart` time. */ + getAnimationTime() { + if (!this.loop) return Math.min(this.trackTime + this.animationStart, this.animationEnd); + const duration = this.animationEnd - this.animationStart; + if (duration === 0) return this.animationStart; + return this.trackTime % duration + this.animationStart; + } + setAnimationLast(animationLast) { + this.animationLast = animationLast; + this.nextAnimationLast = animationLast; + } + /** Returns true if at least one loop has been completed. + * + * See {@link AnimationStateListener.complete}. */ + isComplete() { + return this.trackTime >= this.animationEnd - this.animationStart; + } + /** When {@link shortestRotation} is false, this clears the directions for mixing this entry's rotation. This can be useful + * to avoid bones rotating the long way around when using {@link getAlpha} and starting animations on other tracks. + * + * Mixing involves finding a rotation between two others. There are two possible solutions: the short or the long way + * around. When the two rotations change over time, which direction is the short or long way can also change. If the short + * way was always chosen, bones flip to the other side when that direction became the long way. TrackEntry chooses the short + * way the first time it is applied and remembers that direction. Resetting that direction makes it choose a new short way + * on the next apply. */ + resetRotationDirections() { + this.timelinesRotation.length = 0; + } + /** If this track entry is non-looping, this is the track time in seconds when {@link animationEnd} is reached, or the + * current {@link trackTime} if it has already been reached. + * + * If this track entry is looping, this is the track time when this animation will reach its next {@link animationEnd} (the + * next loop completion). */ + getTrackComplete() { + const duration = this.animationEnd - this.animationStart; + if (duration !== 0) { + if (this.loop) return duration * (1 + (this.trackTime / duration | 0)); + if (this.trackTime < duration) return duration; + } + return this.trackTime; + } + /** Returns true if this track entry has been applied at least once. + * + * See {@link AnimationState.apply}. */ + wasApplied() { + return this.nextTrackLast !== -1; + } + /** Returns true if there is a {@link next} track entry and it will become the current track entry during the next + * {@link AnimationState.update}. */ + isNextReady() { + return this.next != null && this.nextTrackLast - this.next.delay >= 0; + } + }; + var EventQueue = class { + objects = []; + drainDisabled = false; + animState; + constructor(animState) { + this.animState = animState; + } + start(entry) { + this.objects.push(0 /* start */); + this.objects.push(entry); + this.animState.animationsChanged = true; + } + interrupt(entry) { + this.objects.push(1 /* interrupt */); + this.objects.push(entry); + } + end(entry) { + this.objects.push(2 /* end */); + this.objects.push(entry); + this.animState.animationsChanged = true; + } + dispose(entry) { + this.objects.push(3 /* dispose */); + this.objects.push(entry); + } + complete(entry) { + this.objects.push(4 /* complete */); + this.objects.push(entry); + } + event(entry, event) { + this.objects.push(5 /* event */); + this.objects.push(entry); + this.objects.push(event); + } + drain() { + if (this.drainDisabled) return; + this.drainDisabled = true; + for (let i = 0; i < this.objects.length; i += 2) { + const objects = this.objects; + const type = objects[i]; + const entry = objects[i + 1]; + const listeners = this.animState.listeners.slice(); + switch (type) { + case 0 /* start */: + if (entry.listener?.start) entry.listener.start(entry); + for (let ii = 0; ii < listeners.length; ii++) { + const listener = listeners[ii]; + if (listener.start) listener.start(entry); + } + break; + case 1 /* interrupt */: + if (entry.listener?.interrupt) entry.listener.interrupt(entry); + for (let ii = 0; ii < listeners.length; ii++) { + const listener = listeners[ii]; + if (listener.interrupt) listener.interrupt(entry); + } + break; + // biome-ignore lint/suspicious/noFallthroughSwitchClause: reference runtime does fall through + case 2 /* end */: + if (entry.listener?.end) entry.listener.end(entry); + for (let ii = 0; ii < listeners.length; ii++) { + const listener = listeners[ii]; + if (listener.end) listener.end(entry); + } + // Fall through. + case 3 /* dispose */: + if (entry.listener?.dispose) entry.listener.dispose(entry); + for (let ii = 0; ii < listeners.length; ii++) { + const listener = listeners[ii]; + if (listener.dispose) listener.dispose(entry); + } + this.animState.trackEntryPool.free(entry); + break; + case 4 /* complete */: + if (entry.listener?.complete) entry.listener.complete(entry); + for (let ii = 0; ii < listeners.length; ii++) { + const listener = listeners[ii]; + if (listener.complete) listener.complete(entry); + } + break; + case 5 /* event */: { + const event = objects[i++ + 2]; + if (entry.listener?.event) entry.listener.event(entry, event); + for (let ii = 0; ii < listeners.length; ii++) { + const listener = listeners[ii]; + if (listener.event) listener.event(entry, event); + } + break; + } + } + } + this.clear(); + this.drainDisabled = false; + } + clear() { + this.objects.length = 0; + } + }; + var EventType = /* @__PURE__ */ ((EventType2) => { + EventType2[EventType2["start"] = 0] = "start"; + EventType2[EventType2["interrupt"] = 1] = "interrupt"; + EventType2[EventType2["end"] = 2] = "end"; + EventType2[EventType2["dispose"] = 3] = "dispose"; + EventType2[EventType2["complete"] = 4] = "complete"; + EventType2[EventType2["event"] = 5] = "event"; + return EventType2; + })(EventType || {}); + var AnimationStateAdapter = class { + start(entry) { + } + interrupt(entry) { + } + end(entry) { + } + dispose(entry) { + } + complete(entry) { + } + event(entry, event) { + } + }; + var CURRENT = 0; + var SETUP = 1; + var FIRST = 2; + var MODE = 3; + var HOLD = 4; + var ATTACH_SETUP = 1; + var ATTACH_RETAIN = 2; + + // spine-core/src/AnimationStateData.ts + var AnimationStateData = class { + /** The SkeletonData to look up animations when they are specified by name. */ + skeletonData; + animationToMixTime = {}; + /** The mix duration to use when no mix duration has been defined between two animations. */ + defaultMix = 0; + constructor(skeletonData) { + if (!skeletonData) throw new Error("skeletonData cannot be null."); + this.skeletonData = skeletonData; + } + setMix(from, to, duration) { + if (typeof from === "string") + return this.setMix1(from, to, duration); + return this.setMix2(from, to, duration); + } + setMix1(fromName, toName, duration) { + const from = this.skeletonData.findAnimation(fromName); + if (!from) throw new Error(`Animation not found: ${fromName}`); + const to = this.skeletonData.findAnimation(toName); + if (!to) throw new Error(`Animation not found: ${toName}`); + this.setMix2(from, to, duration); + } + setMix2(from, to, duration) { + if (!from) throw new Error("from cannot be null."); + if (!to) throw new Error("to cannot be null."); + const key = `${from.name}.${to.name}`; + this.animationToMixTime[key] = duration; + } + /** Returns the mix duration to use when changing from the specified animation to the other on the same track, or the + * {@link defaultMix} if no mix duration has been set. */ + getMix(from, to) { + const key = `${from.name}.${to.name}`; + const value = this.animationToMixTime[key]; + return value === void 0 ? this.defaultMix : value; + } + }; + + // spine-core/src/AssetManagerBase.ts + var AssetManagerBase = class { + constructor(textureLoader, pathPrefix = "", downloader = new Downloader(), cache = new AssetCache()) { + this.textureLoader = textureLoader; + this.pathPrefix = pathPrefix; + this.downloader = downloader; + this.cache = cache; + } + errors = {}; + toLoad = 0; + loaded = 0; + texturePmaInfo = {}; + start(path) { + this.toLoad++; + return this.pathPrefix + path; + } + success(callback, path, asset) { + this.toLoad--; + this.loaded++; + this.cache.assets[path] = asset; + this.cache.assetsRefCount[path] = (this.cache.assetsRefCount[path] || 0) + 1; + if (callback) callback(path, asset); + } + error(callback, path, message) { + this.toLoad--; + this.loaded++; + this.errors[path] = message; + if (callback) callback(path, message); + } + loadAll() { + const promise = new Promise((resolve, reject) => { + const check = () => { + if (this.isLoadingComplete()) { + if (this.hasErrors()) reject(this.errors); + else resolve(this); + return; + } + requestAnimationFrame(check); + }; + requestAnimationFrame(check); + }); + return promise; + } + setRawDataURI(path, data) { + this.downloader.rawDataUris[this.pathPrefix + path] = data; + } + loadBinary(path, success = () => { + }, error = () => { + }) { + path = this.start(path); + if (this.reuseAssets(path, success, error)) return; + this.cache.assetsLoaded[path] = new Promise((resolve, reject) => { + this.downloader.downloadBinary(path, (data) => { + this.success(success, path, data); + resolve(data); + }, (status, responseText) => { + const errorMsg = `Couldn't load binary ${path}: status ${status}, ${responseText}`; + this.error(error, path, errorMsg); + reject(errorMsg); + }); + }); + } + loadText(path, success = () => { + }, error = () => { + }) { + path = this.start(path); + this.downloader.downloadText(path, (data) => { + this.success(success, path, data); + }, (status, responseText) => { + this.error(error, path, `Couldn't load text ${path}: status ${status}, ${responseText}`); + }); + } + loadJson(path, success = () => { + }, error = () => { + }) { + path = this.start(path); + if (this.reuseAssets(path, success, error)) return; + this.cache.assetsLoaded[path] = new Promise((resolve, reject) => { + this.downloader.downloadJson(path, (data) => { + this.success(success, path, data); + resolve(data); + }, (status, responseText) => { + const errorMsg = `Couldn't load JSON ${path}: status ${status}, ${responseText}`; + this.error(error, path, errorMsg); + reject(errorMsg); + }); + }); + } + reuseAssets(path, success = () => { + }, error = () => { + }) { + const loadedStatus = this.cache.getAsset(path); + const alreadyExistsOrLoading = loadedStatus !== void 0; + if (alreadyExistsOrLoading) { + this.cache.assetsLoaded[path] = loadedStatus.then((data) => { + data = data instanceof Image || data instanceof ImageBitmap ? this.textureLoader(data) : data; + this.success(success, path, data); + return data; + }).catch((errorMsg) => { + this.error(error, path, errorMsg); + return void 0; + }); + } + return alreadyExistsOrLoading; + } + loadTexture(path, success = () => { + }, error = () => { + }) { + path = this.start(path); + if (this.reuseAssets(path, success, error)) return; + const pma = this.texturePmaInfo[path]; + this.cache.assetsLoaded[path] = new Promise((resolve, reject) => { + const isBrowser = !!(typeof window !== "undefined" && typeof navigator !== "undefined" && window.document); + const isWebWorker = !isBrowser; + if (isWebWorker) { + fetch(path, { mode: "cors" }).then((response) => { + if (response.ok) return response.blob(); + const errorMsg = `Couldn't load image: ${path}`; + this.error(error, path, `Couldn't load image: ${path}`); + reject(errorMsg); + }).then((blob) => { + return blob ? createImageBitmap(blob, { premultiplyAlpha: "none", colorSpaceConversion: "none" }) : null; + }).then((bitmap) => { + if (bitmap) { + const texture = this.createTexture(path, pma, bitmap); + this.success(success, path, texture); + resolve(texture); + } + ; + }); + } else { + const image = new Image(); + image.crossOrigin = "anonymous"; + image.onload = () => { + const texture = this.createTexture(path, pma, image); + this.success(success, path, texture); + resolve(texture); + }; + image.onerror = () => { + const errorMsg = `Couldn't load image: ${path}`; + this.error(error, path, errorMsg); + reject(errorMsg); + }; + if (this.downloader.rawDataUris[path]) path = this.downloader.rawDataUris[path]; + image.src = path; + } + }); + } + loadTextureAtlas(path, success = () => { + }, error = () => { + }, fileAlias) { + const index = path.lastIndexOf("/"); + const parent = index >= 0 ? path.substring(0, index + 1) : ""; + path = this.start(path); + if (this.reuseAssets(path, success, error)) return; + this.cache.assetsLoaded[path] = new Promise((resolve, reject) => { + this.downloader.downloadText(path, (atlasText) => { + try { + const atlas = this.createTextureAtlas(atlasText, parent, path, fileAlias); + let toLoad = atlas.pages.length, abort = false; + if (toLoad === 0) { + this.success(success, path, atlas); + resolve(atlas); + return; + } + for (const page of atlas.pages) { + this.loadTexture( + this.texturePath(parent, page.name, fileAlias), + (imagePath, texture) => { + if (!abort) { + page.setTexture(texture); + if (--toLoad === 0) { + this.success(success, path, atlas); + resolve(atlas); + } + } + }, + (imagePath, message) => { + if (!abort) { + const errorMsg = `Couldn't load texture ${path} page image: ${imagePath}`; + this.error(error, path, errorMsg); + reject(errorMsg); + } + abort = true; + } + ); + } + } catch (e) { + const errorMsg = `Couldn't parse texture atlas ${path}: ${e.message}`; + this.error(error, path, errorMsg); + reject(errorMsg); + } + }, (status, responseText) => { + const errorMsg = `Couldn't load texture atlas ${path}: status ${status}, ${responseText}`; + this.error(error, path, errorMsg); + reject(errorMsg); + }); + }); + } + loadTextureAtlasButNoTextures(path, success = () => { + }, error = () => { + }) { + const index = path.lastIndexOf("/"); + const parent = index >= 0 ? path.substring(0, index + 1) : ""; + path = this.start(path); + if (this.reuseAssets(path, success, error)) return; + this.cache.assetsLoaded[path] = new Promise((resolve, reject) => { + this.downloader.downloadText(path, (atlasText) => { + try { + const atlas = this.createTextureAtlas(atlasText, parent, path); + this.success(success, path, atlas); + resolve(atlas); + } catch (e) { + const errorMsg = `Couldn't parse texture atlas ${path}: ${e.message}`; + this.error(error, path, errorMsg); + reject(errorMsg); + } + }, (status, responseText) => { + const errorMsg = `Couldn't load texture atlas ${path}: status ${status}, ${responseText}`; + this.error(error, path, errorMsg); + reject(errorMsg); + }); + }); + } + async loadBinaryAsync(path) { + return new Promise((resolve, reject) => { + this.loadBinary( + path, + (_, binary) => resolve(binary), + (_, message) => reject(message) + ); + }); + } + async loadJsonAsync(path) { + return new Promise((resolve, reject) => { + this.loadJson( + path, + (_, object) => resolve(object), + (_, message) => reject(message) + ); + }); + } + async loadTextureAsync(path) { + return new Promise((resolve, reject) => { + this.loadTexture( + path, + (_, texture) => resolve(texture), + (_, message) => reject(message) + ); + }); + } + async loadTextureAtlasAsync(path) { + return new Promise((resolve, reject) => { + this.loadTextureAtlas( + path, + (_, atlas) => resolve(atlas), + (_, message) => reject(message) + ); + }); + } + async loadTextureAtlasButNoTexturesAsync(path) { + return new Promise((resolve, reject) => { + this.loadTextureAtlasButNoTextures( + path, + (_, atlas) => resolve(atlas), + (_, message) => reject(message) + ); + }); + } + setCache(cache) { + this.cache = cache; + } + get(path) { + return this.cache.assets[this.pathPrefix + path]; + } + require(path) { + path = this.pathPrefix + path; + const asset = this.cache.assets[path]; + if (asset) return asset; + const error = this.errors[path]; + throw Error(`Asset not found: ${path}${error ? ` +${error}` : ""}`); + } + remove(path) { + path = this.pathPrefix + path; + const asset = this.cache.assets[path]; + if (asset.dispose) asset.dispose(); + delete this.cache.assets[path]; + delete this.cache.assetsRefCount[path]; + delete this.cache.assetsLoaded[path]; + return asset; + } + removeAll() { + for (const path in this.cache.assets) { + const asset = this.cache.assets[path]; + if (asset.dispose) asset.dispose(); + } + this.cache.assets = {}; + this.cache.assetsLoaded = {}; + this.cache.assetsRefCount = {}; + } + isLoadingComplete() { + return this.toLoad === 0; + } + getToLoad() { + return this.toLoad; + } + getLoaded() { + return this.loaded; + } + dispose() { + this.removeAll(); + } + // dispose asset only if it's not used by others + disposeAsset(path) { + const asset = this.cache.assets[path]; + if (asset instanceof TextureAtlas) { + asset.dispose(); + return; + } + this.disposeAssetInternal(path); + } + hasErrors() { + return Object.keys(this.errors).length > 0; + } + getErrors() { + return this.errors; + } + disposeAssetInternal(path) { + if (this.cache.assetsRefCount[path] > 0 && --this.cache.assetsRefCount[path] === 0) { + return this.remove(path); + } + } + createTextureAtlas(atlasText, parentPath, path, fileAlias) { + const atlas = new TextureAtlas(atlasText); + atlas.dispose = () => { + if (this.cache.assetsRefCount[path] <= 0) return; + this.disposeAssetInternal(path); + for (const page of atlas.pages) { + page.texture?.dispose(); + } + }; + for (const page of atlas.pages) { + const texturePath = this.texturePath(parentPath, page.name, fileAlias); + this.texturePmaInfo[this.pathPrefix + texturePath] = page.pma; + } + return atlas; + } + createTexture(path, pma, image) { + const texture = this.textureLoader(image, pma); + const textureDispose = texture.dispose.bind(texture); + texture.dispose = () => { + if (this.disposeAssetInternal(path)) textureDispose(); + }; + return texture; + } + texturePath(parentPath, pageName, fileAlias) { + if (!fileAlias) return parentPath + pageName; + return fileAlias[pageName]; + } + }; + var AssetCache = class _AssetCache { + assets = {}; + assetsRefCount = {}; + assetsLoaded = {}; + static AVAILABLE_CACHES = /* @__PURE__ */ new Map(); + static getCache(id) { + const cache = _AssetCache.AVAILABLE_CACHES.get(id); + if (cache) return cache; + const newCache = new _AssetCache(); + _AssetCache.AVAILABLE_CACHES.set(id, newCache); + return newCache; + } + async addAsset(path, asset) { + this.assetsLoaded[path] = Promise.resolve(asset); + this.assets[path] = asset; + return asset; + } + getAsset(path) { + return this.assetsLoaded[path]; + } + }; + var Downloader = class { + callbacks = {}; + rawDataUris = {}; + dataUriToString(dataUri) { + if (!dataUri.startsWith("data:")) { + throw new Error("Not a data URI."); + } + let base64Idx = dataUri.indexOf("base64,"); + if (base64Idx !== -1) { + base64Idx += "base64,".length; + return atob(dataUri.substr(base64Idx)); + } else { + return dataUri.substr(dataUri.indexOf(",") + 1); + } + } + base64ToUint8Array(base64) { + var binary_string = window.atob(base64); + var len = binary_string.length; + var bytes = new Uint8Array(len); + for (let i = 0; i < len; i++) { + bytes[i] = binary_string.charCodeAt(i); + } + return bytes; + } + dataUriToUint8Array(dataUri) { + if (!dataUri.startsWith("data:")) { + throw new Error("Not a data URI."); + } + let base64Idx = dataUri.indexOf("base64,"); + if (base64Idx === -1) throw new Error("Not a binary data URI."); + base64Idx += "base64,".length; + return this.base64ToUint8Array(dataUri.substr(base64Idx)); + } + downloadText(url, success, error) { + if (this.start(url, success, error)) return; + const rawDataUri = this.rawDataUris[url]; + if (rawDataUri && !rawDataUri.includes(".")) { + try { + this.finish(url, 200, this.dataUriToString(rawDataUri)); + } catch (e) { + this.finish(url, 400, JSON.stringify(e)); + } + return; + } + const request = new XMLHttpRequest(); + request.overrideMimeType("text/html"); + request.open("GET", rawDataUri ? rawDataUri : url, true); + const done = () => { + this.finish(url, request.status, request.responseText); + }; + request.onload = done; + request.onerror = done; + request.send(); + } + downloadJson(url, success, error) { + this.downloadText(url, (data) => { + success(JSON.parse(data)); + }, error); + } + downloadBinary(url, success, error) { + if (this.start(url, success, error)) return; + const rawDataUri = this.rawDataUris[url]; + if (rawDataUri && !rawDataUri.includes(".")) { + try { + this.finish(url, 200, this.dataUriToUint8Array(rawDataUri)); + } catch (e) { + this.finish(url, 400, JSON.stringify(e)); + } + return; + } + const request = new XMLHttpRequest(); + request.open("GET", rawDataUri ? rawDataUri : url, true); + request.responseType = "arraybuffer"; + const onerror = () => { + this.finish(url, request.status, request.response); + }; + request.onload = () => { + if (request.status === 200 || request.status === 0) + this.finish(url, 200, new Uint8Array(request.response)); + else + onerror(); + }; + request.onerror = onerror; + request.send(); + } + start(url, success, error) { + let callbacks = this.callbacks[url]; + try { + if (callbacks) return true; + this.callbacks[url] = callbacks = []; + } finally { + callbacks.push(success, error); + } + } + finish(url, status, data) { + const callbacks = this.callbacks[url]; + delete this.callbacks[url]; + if (status === 200 || status === 0) { + for (let i = 0, n = callbacks.length; i < n; i += 2) + callbacks[i](data); + } else { + for (let i = 1, n = callbacks.length; i < n; i += 2) + callbacks[i](status, data); + } + } + }; + + // spine-core/src/attachments/BoundingBoxAttachment.ts + var BoundingBoxAttachment = class _BoundingBoxAttachment extends VertexAttachment { + color = new Color(1, 1, 1, 1); + constructor(name) { + super(name); + } + copy() { + const copy = new _BoundingBoxAttachment(this.name); + this.copyTo(copy); + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/attachments/ClippingAttachment.ts + var ClippingAttachment = class _ClippingAttachment extends VertexAttachment { + /** Clipping is performed between the clipping attachment's slot and the end slot. If null, clipping is done until the end of + * the skeleton's rendering. */ + endSlot = null; + /** When true the clipping polygon is treated as convex for more efficient clipping. If the polygon deforms to concave then the + * convex hull is used. When false the clipping polygon can be concave and if so has an additional CPU cost. Inverse clipping + * always uses convex. */ + convex = false; + /** When false, everything inside the clipping polygon is visible. When true, everything outside the clipping polygon is + * visible and clipping is convex. */ + inverse = false; + // Nonessential. + /** The color of the clipping polygon as it was in Spine. Available only when nonessential data was exported. Clipping polygons + * are not usually rendered at runtime. */ + color = new Color(0.2275, 0.2275, 0.8078, 1); + // ce3a3aff + constructor(name) { + super(name); + } + copy() { + const copy = new _ClippingAttachment(this.name); + this.copyTo(copy); + copy.endSlot = this.endSlot; + copy.convex = this.convex; + copy.inverse = this.inverse; + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/attachments/PathAttachment.ts + var PathAttachment = class _PathAttachment extends VertexAttachment { + /** The lengths along the path in the setup pose from the start of the path to the end of each Bezier curve. */ + lengths = []; + /** If true, the start and end knots are connected. */ + closed = false; + /** If true, additional calculations are performed to make computing positions along the path more accurate so movement along + * the path has a constant speed. */ + constantSpeed = false; + /** The color of the path as it was in Spine. Available only when nonessential data was exported. Paths are not usually + * rendered at runtime. */ + color = new Color(1, 1, 1, 1); + constructor(name) { + super(name); + } + copy() { + const copy = new _PathAttachment(this.name); + this.copyTo(copy); + copy.lengths = []; + Utils.arrayCopy(this.lengths, 0, copy.lengths, 0, this.lengths.length); + copy.closed = this.closed; + copy.constantSpeed = this.constantSpeed; + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/attachments/PointAttachment.ts + var PointAttachment = class _PointAttachment extends VertexAttachment { + /** The local x position. */ + x = 0; + /** The local y position. */ + y = 0; + /** The local rotation in degrees, counter clockwise. */ + rotation = 0; + /** The color of the point attachment as it was in Spine. Available only when nonessential data was exported. Point attachments + * are not usually rendered at runtime. */ + color = new Color(0.38, 0.94, 0, 1); + constructor(name) { + super(name); + } + /** Computes the world position from the local position. */ + computeWorldPosition(bone, point) { + point.x = this.x * bone.a + this.y * bone.b + bone.worldX; + point.y = this.x * bone.c + this.y * bone.d + bone.worldY; + return point; + } + /** Computes the world rotation from the local rotation. */ + computeWorldRotation(bone) { + const r = this.rotation * MathUtils.degRad, cos = Math.cos(r), sin = Math.sin(r); + const x = cos * bone.a + sin * bone.b; + const y = cos * bone.c + sin * bone.d; + return MathUtils.atan2Deg(y, x); + } + copy() { + const copy = new _PointAttachment(this.name); + copy.x = this.x; + copy.y = this.y; + copy.rotation = this.rotation; + copy.color.setFromColor(this.color); + return copy; + } + }; + + // spine-core/src/AtlasAttachmentLoader.ts + var AtlasAttachmentLoader = class { + atlas; + allowMissingRegions; + constructor(atlas, allowMissingRegions = false) { + this.atlas = atlas; + this.allowMissingRegions = allowMissingRegions; + } + /** Sets each {@link Sequence.regions} by calling {@link findRegion} for each texture region using + * {@link Sequence.getPath}. */ + findRegions(name, basePath, sequence) { + const regions = sequence.regions; + for (let i = 0, n = regions.length; i < n; i++) + regions[i] = this.findRegion(name, sequence.getPath(basePath, i)); + } + /** Looks for the region with the specified path. If not found and {@link allowMissingRegions} is false, an error is + * raised. */ + findRegion(name, path) { + const region = this.atlas.findRegion(path); + if (!region && !this.allowMissingRegions) + throw new Error(`Region not found in atlas: ${path} (attachment: ${name})`); + return region; + } + newRegionAttachment(skin, placeholder, name, path, sequence) { + this.findRegions(name, path, sequence); + return new RegionAttachment(name, sequence); + } + newMeshAttachment(skin, placeholder, name, path, sequence) { + this.findRegions(name, path, sequence); + return new MeshAttachment(name, sequence); + } + newBoundingBoxAttachment(skin, placeholder, name) { + return new BoundingBoxAttachment(name); + } + newPathAttachment(skin, placeholder, name) { + return new PathAttachment(name); + } + newPointAttachment(skin, placeholder, name) { + return new PointAttachment(name); + } + newClippingAttachment(skin, placeholder, name) { + return new ClippingAttachment(name); + } + }; + + // spine-core/src/PosedData.ts + var PosedData = class { + name; + setupPose; + /** When true, {@link Skeleton.updateWorldTransform} only updates this constraint if the {@link Skeleton.skin} + * contains this constraint. + * + * See {@link Skin.constraints}. */ + skinRequired = false; + constructor(name, setupPose) { + if (name == null) throw new Error("name cannot be null."); + this.name = name; + this.setupPose = setupPose; + } + }; + + // spine-core/src/BoneData.ts + var BoneData = class _BoneData extends PosedData { + /** The index of the bone in {@link Skeleton.bones}. */ + index = 0; + /** The parent bone, or null if this bone is the root. */ + parent = null; + /** The bone's length. */ + length = 0; + // Nonessential. + /** The color of the bone as it was in Spine. Available only when nonessential data was exported. Bones are not usually + * rendered at runtime. */ + color = new Color(); + /** The bone icon name as it was in Spine, or null if nonessential data was not exported. */ + icon; + /** The bone icon's display size scale, or 1 if nonessential data was not exported. */ + iconSize = 1; + /** The bone icon's display rotation in degrees, or 0 if nonessential data was not exported. */ + iconRotation = 0; + /** False if the bone was hidden in Spine and nonessential data was exported. Does not affect runtime rendering. */ + visible = false; + constructor(index, name, parent) { + super(name, new BonePose()); + if (index < 0) throw new Error("index must be >= 0."); + if (!name) throw new Error("name cannot be null."); + this.index = index; + this.parent = parent; + } + copy(parent) { + const copy = new _BoneData(this.index, this.name, parent); + copy.length = this.length; + copy.setupPose.set(this.setupPose); + return copy; + } + }; + var Inherit = /* @__PURE__ */ ((Inherit2) => { + Inherit2[Inherit2["Normal"] = 0] = "Normal"; + Inherit2[Inherit2["OnlyTranslation"] = 1] = "OnlyTranslation"; + Inherit2[Inherit2["NoRotationOrReflection"] = 2] = "NoRotationOrReflection"; + Inherit2[Inherit2["NoScale"] = 3] = "NoScale"; + Inherit2[Inherit2["NoScaleOrReflection"] = 4] = "NoScaleOrReflection"; + return Inherit2; + })(Inherit || {}); + + // spine-core/src/BonePose.ts + var BonePose = class { + bone; + /** The local x translation. */ + x = 0; + /** The local y translation. */ + y = 0; + /** The local rotation in degrees, counter clockwise. */ + rotation = 0; + /** The local scaleX. */ + scaleX = 0; + /** The local scaleY. */ + scaleY = 0; + /** The local shearX. */ + shearX = 0; + /** The local shearY. */ + shearY = 0; + inherit = 0 /* Normal */; + /** The world transform `[a b][c d]` x-axis x component. */ + a = 0; + /** The world transform `[a b][c d]` y-axis x component. */ + b = 0; + /** The world transform `[a b][c d]` x-axis y component. */ + c = 0; + /** The world transform `[a b][c d]` y-axis y component. */ + d = 0; + /** The world X position. If changed, {@link updateLocalTransform} should be called. */ + worldY = 0; + /** The world Y position. If changed, {@link updateLocalTransform} should be called. */ + worldX = 0; + world = 0; + local = 0; + set(pose) { + if (pose == null) throw new Error("pose cannot be null."); + this.x = pose.x; + this.y = pose.y; + this.rotation = pose.rotation; + this.scaleX = pose.scaleX; + this.scaleY = pose.scaleY; + this.shearX = pose.shearX; + this.shearY = pose.shearY; + this.inherit = pose.inherit; + } + setPosition(x, y) { + this.x = x; + this.y = y; + } + setScale(scaleOrX, scaleY) { + this.scaleX = scaleOrX; + this.scaleY = scaleY === void 0 ? scaleOrX : scaleY; + } + /** Determines how parent world transforms affect this bone. */ + getInherit() { + return this.inherit; + } + setInherit(inherit) { + if (inherit == null) throw new Error("inherit cannot be null."); + this.inherit = inherit; + } + /** Called by {@link Skeleton.updateCache} to compute the world transform, if needed. */ + update(skeleton, physics) { + if (this.world !== skeleton._update) this.updateWorldTransform(skeleton); + } + /** Computes the world transform using the parent bone's world transform and this applied local pose. Child bones are not + * updated. + * + * See World transforms in the Spine + * Runtimes Guide. */ + updateWorldTransform(skeleton) { + if (this.local === skeleton._update) + this.updateLocalTransform(skeleton); + else + this.world = skeleton._update; + const rotation = this.rotation; + const scaleX = this.scaleX; + const scaleY = this.scaleY; + const shearX = this.shearX; + const shearY = this.shearY; + if (!this.bone.parent) { + const sx = skeleton.scaleX, sy = skeleton.scaleY; + const rx = (rotation + shearX) * MathUtils.degRad; + const ry = (rotation + 90 + shearY) * MathUtils.degRad; + this.a = Math.cos(rx) * scaleX * sx; + this.b = Math.cos(ry) * scaleY * sx; + this.c = Math.sin(rx) * scaleX * sy; + this.d = Math.sin(ry) * scaleY * sy; + this.worldX = this.x * sx + skeleton.x; + this.worldY = this.y * sy + skeleton.y; + return; + } + const parent = this.bone.parent.appliedPose; + let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + this.worldX = pa * this.x + pb * this.y + parent.worldX; + this.worldY = pc * this.x + pd * this.y + parent.worldY; + switch (this.inherit) { + case 0 /* Normal */: { + const rx = (rotation + shearX) * MathUtils.degRad; + const ry = (rotation + 90 + shearY) * MathUtils.degRad; + const la = Math.cos(rx) * scaleX; + const lb = Math.cos(ry) * scaleY; + const lc = Math.sin(rx) * scaleX; + const ld = Math.sin(ry) * scaleY; + this.a = pa * la + pb * lc; + this.b = pa * lb + pb * ld; + this.c = pc * la + pd * lc; + this.d = pc * lb + pd * ld; + return; + } + case 1 /* OnlyTranslation */: { + const sx = skeleton.scaleX, sy = skeleton.scaleY; + const rx = (rotation + shearX) * MathUtils.degRad; + const ry = (rotation + 90 + shearY) * MathUtils.degRad; + this.a = Math.cos(rx) * scaleX * sx; + this.b = Math.cos(ry) * scaleY * sx; + this.c = Math.sin(rx) * scaleX * sy; + this.d = Math.sin(ry) * scaleY * sy; + break; + } + case 2 /* NoRotationOrReflection */: { + const sx = skeleton.scaleX, sy = skeleton.scaleY, sxi = 1 / sx, syi = 1 / sy; + pa *= sxi; + pc *= syi; + let s = pa * pa + pc * pc; + let r = 0; + if (s > MathUtils.epsilon2) { + s = Math.abs(pa * pd * syi - pb * sxi * pc) / s; + pb = pc * s; + pd = pa * s; + r = rotation - MathUtils.atan2Deg(pc, pa); + } else { + pa = 0; + pc = 0; + r = rotation - 90 + MathUtils.atan2Deg(pd, pb); + } + const rx = (r + shearX) * MathUtils.degRad; + const ry = (r + shearY + 90) * MathUtils.degRad; + const la = Math.cos(rx) * scaleX; + const lb = Math.cos(ry) * scaleY; + const lc = Math.sin(rx) * scaleX; + const ld = Math.sin(ry) * scaleY; + this.a = (pa * la - pb * lc) * sx; + this.b = (pa * lb - pb * ld) * sx; + this.c = (pc * la + pd * lc) * sy; + this.d = (pc * lb + pd * ld) * sy; + break; + } + case 3 /* NoScale */: + case 4 /* NoScaleOrReflection */: { + const sx = skeleton.scaleX, sy = skeleton.scaleY, sxi = 1 / sx, syi = 1 / sy; + const r = rotation * MathUtils.degRad, cos = Math.cos(r), sin = Math.sin(r); + let za = (pa * cos + pb * sin) * sxi; + let zc = (pc * cos + pd * sin) * syi; + const s = 1 / Math.sqrt(za * za + zc * zc); + za *= s; + zc *= s; + let zb = -zc, zd = za; + if (this.inherit === 3 /* NoScale */ && pa * pd - pb * pc < 0 !== (sx < 0 !== sy < 0)) { + zb = -zb; + zd = -zd; + } + const rx = shearX * MathUtils.degRad; + const ry = (90 + shearY) * MathUtils.degRad; + const la = Math.cos(rx) * scaleX; + const lb = Math.cos(ry) * scaleY; + const lc = Math.sin(rx) * scaleX; + const ld = Math.sin(ry) * scaleY; + this.a = (za * la + zb * lc) * sx; + this.b = (za * lb + zb * ld) * sx; + this.c = (zc * la + zd * lc) * sy; + this.d = (zc * lb + zd * ld) * sy; + break; + } + } + } + /** Computes the local transform values from the world transform. + * + * If the world transform is modified (by a constraint, {@link rotateWorld}, etc) then this method should be called so + * the local transform matches the world transform. The local transform may be needed by other code (eg to apply another + * constraint). + * + * Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. The local transform after + * calling this method is equivalent to the local transform used to compute the world transform, but may not be identical. */ + updateLocalTransform(skeleton) { + this.local = 0; + this.world = skeleton._update; + const sx = skeleton.scaleX, sy = skeleton.scaleY; + if (!this.bone.parent) { + const sxi = 1 / sx, syi = 1 / sy; + this.x = (this.worldX - skeleton.x) * sxi; + this.y = (this.worldY - skeleton.y) * syi; + this.set5(this.a * sxi, this.b * sxi, this.c * syi, this.d * syi, 0); + return; + } + const parent = this.bone.parent.appliedPose; + let pa = parent.a, pb = parent.b, pc = parent.c, pd = parent.d; + const pad = pa * pd - pb * pc, pid = 1 / (pa * pd - pb * pc); + const ia = pd * pid, ib = pb * pid, ic = pc * pid, id = pa * pid; + const dx = this.worldX - parent.worldX, dy = this.worldY - parent.worldY; + this.x = dx * ia - dy * ib; + this.y = dy * id - dx * ic; + switch (this.inherit) { + case 0 /* Normal */: + this.set5(ia * this.a - ib * this.c, ia * this.b - ib * this.d, id * this.c - ic * this.a, id * this.d - ic * this.b, 0); + break; + case 1 /* OnlyTranslation */: { + const sxi = 1 / sx, syi = 1 / sy; + this.set5(this.a * sxi, this.b * sxi, this.c * syi, this.d * syi, 0); + break; + } + case 2 /* NoRotationOrReflection */: { + const sxi = 1 / sx, syi = 1 / sy; + pa *= sxi; + pc *= syi; + const wa = this.a * sxi, wb = this.b * sxi, wc = this.c * syi, wd = this.d * syi; + const s = 1 / (pa * pa + pc * pc), det = 1 / Math.abs(pad * sxi * syi); + this.set5( + (pa * wa + pc * wc) * s, + (pa * wb + pc * wd) * s, + (pa * wc - pc * wa) * det, + (pa * wd - pc * wb) * det, + MathUtils.atan2Deg(pc, pa) + ); + break; + } + case 3 /* NoScale */: + case 4 /* NoScaleOrReflection */: { + const sxi = 1 / sx, syi = 1 / sy; + const wa = this.a * sxi, wb = this.b * sxi, wc = this.c * syi, wd = this.d * syi; + let tx = pd * this.a - pb * this.c, ty = pa * this.c - pc * this.a; + if (pad < 0) { + tx = -tx; + ty = -ty; + } + let r = MathUtils.atan2Deg(ty, tx); + this.rotation = r; + r *= MathUtils.degRad; + const cos = Math.cos(r), sin = Math.sin(r); + let za = (pa * cos + pb * sin) * sxi; + let zc = (pc * cos + pd * sin) * syi; + const s = 1 / Math.sqrt(za * za + zc * zc); + za *= s; + zc *= s; + const si = this.inherit === 3 /* NoScale */ && pad < 0 !== (sx < 0 !== sy < 0) ? -1 : 1; + this.set4(za * wa + zc * wc, za * wb + zc * wd, (za * wc - zc * wa) * si, (za * wd - zc * wb) * si); + } + } + } + set4(ra, rb, rc, rd) { + const x = ra * ra + rc * rc, y = rb * rb + rd * rd; + if (x > MathUtils.epsilon2) { + this.shearX = MathUtils.atan2Deg(rc, ra); + this.scaleX = Math.sqrt(x); + } else { + this.shearX = 0; + this.scaleX = 0; + } + this.scaleY = Math.sqrt(y); + if (y > MathUtils.epsilon2) { + this.shearY = MathUtils.atan2Deg(rd, rb); + if (ra * rd - rb * rc < 0) { + this.scaleY = -this.scaleY; + this.shearY += 90; + } else + this.shearY -= 90; + if (this.shearY > 180) + this.shearY -= 360; + else if (this.shearY <= -180) + this.shearY += 360; + } else + this.shearY = 0; + } + set5(ra, rb, rc, rd, ro) { + this.shearX = 0; + const x = ra * ra + rc * rc, y = rb * rb + rd * rd; + if (x > MathUtils.epsilon2) { + const r = MathUtils.atan2Deg(rc, ra); + this.rotation = r + ro; + this.scaleX = Math.sqrt(x); + this.scaleY = Math.sqrt(y); + if (y > MathUtils.epsilon2) { + this.shearY = MathUtils.atan2Deg(rd, rb); + if (ra * rd - rb * rc < 0) { + this.scaleY = -this.scaleY; + this.shearY += 90 - r; + } else + this.shearY -= 90 + r; + if (this.shearY > 180) + this.shearY -= 360; + else if (this.shearY <= -180) + this.shearY += 360; + } else + this.shearY = 0; + } else { + this.scaleX = 0; + this.scaleY = Math.sqrt(y); + this.shearY = 0; + this.rotation = y > MathUtils.epsilon2 ? MathUtils.atan2Deg(rd, rb) - 90 + ro : ro; + } + } + /** If the world transform has been modified by constraints and the local transform no longer matches, + * {@link updateLocalTransform} is called. Call this after {@link Skeleton.updateWorldTransform} before + * using the applied local transform. */ + validateLocalTransform(skeleton) { + if (this.local === skeleton._update) this.updateLocalTransform(skeleton); + } + modifyLocal(skeleton) { + if (this.local === skeleton._update) this.updateLocalTransform(skeleton); + this.world = 0; + this.resetWorld(skeleton, skeleton._update); + } + modifyWorld(skeleton) { + const update = skeleton._update; + this.local = update; + this.world = update; + this.resetWorld(skeleton, update); + } + resetWorld(skeleton, update) { + const children = this.bone.children; + for (let i = 0, n = children.length; i < n; i++) { + const child = children[i].appliedPose; + if (child.world === update) { + if (child.local === update) child.updateLocalTransform(skeleton); + child.world = 0; + child.resetWorld(skeleton, update); + } + } + } + /** The world rotation for the X axis, calculated using {@link a} and {@link c}. This is the direction the bone is + * pointing. */ + getWorldRotationX() { + return MathUtils.atan2Deg(this.c, this.a); + } + /** The world rotation for the Y axis, calculated using {@link b} and {@link d}. */ + getWorldRotationY() { + return MathUtils.atan2Deg(this.d, this.b); + } + /** The magnitude (always positive) of the world scale X, calculated using {@link a} and {@link c}. */ + getWorldScaleX() { + return Math.sqrt(this.a * this.a + this.c * this.c); + } + /** The magnitude (always positive) of the world scale Y, calculated using {@link b} and {@link d}. */ + getWorldScaleY() { + return Math.sqrt(this.b * this.b + this.d * this.d); + } + // public Matrix3 getWorldTransform (Matrix3 worldTransform) { + // if (worldTransform == null) throw new IllegalArgumentException("worldTransform cannot be null."); + // float[] val = worldTransform.val; + // val[M00] = a; + // val[M01] = b; + // val[M10] = c; + // val[M11] = d; + // val[M02] = worldX; + // val[M12] = worldY; + // val[M20] = 0; + // val[M21] = 0; + // val[M22] = 1; + // return worldTransform; + // } + /** Transforms a point from world coordinates to the bone's local coordinates. */ + worldToLocal(world) { + if (world == null) throw new Error("world cannot be null."); + const det = this.a * this.d - this.b * this.c; + const x = world.x - this.worldX, y = world.y - this.worldY; + world.x = (x * this.d - y * this.b) / det; + world.y = (y * this.a - x * this.c) / det; + return world; + } + /** Transforms a point from the bone's local coordinates to world coordinates. */ + localToWorld(local) { + if (local == null) throw new Error("local cannot be null."); + const x = local.x, y = local.y; + local.x = x * this.a + y * this.b + this.worldX; + local.y = x * this.c + y * this.d + this.worldY; + return local; + } + /** Transforms a point from world coordinates to the parent bone's local coordinates. */ + worldToParent(world) { + if (world == null) throw new Error("world cannot be null."); + return this.bone.parent == null ? world : this.bone.parent.appliedPose.worldToLocal(world); + } + /** Transforms a point from the parent bone's coordinates to world coordinates. */ + parentToWorld(world) { + if (world == null) throw new Error("world cannot be null."); + return this.bone.parent == null ? world : this.bone.parent.appliedPose.localToWorld(world); + } + /** Transforms a world rotation to a local rotation. */ + worldToLocalRotation(worldRotation) { + worldRotation *= MathUtils.degRad; + const sin = Math.sin(worldRotation), cos = Math.cos(worldRotation); + return MathUtils.atan2Deg(this.a * sin - this.c * cos, this.d * cos - this.b * sin) + this.rotation - this.shearX; + } + /** Transforms a local rotation to a world rotation. */ + localToWorldRotation(localRotation) { + localRotation = (localRotation - this.rotation - this.shearX) * MathUtils.degRad; + const sin = Math.sin(localRotation), cos = Math.cos(localRotation); + return MathUtils.atan2Deg(cos * this.c + sin * this.d, cos * this.a + sin * this.b); + } + /** Rotates the world transform the specified amount. */ + rotateWorld(degrees) { + degrees *= MathUtils.degRad; + const sin = Math.sin(degrees), cos = Math.cos(degrees); + const ra = this.a, rb = this.b; + this.a = cos * ra - sin * this.c; + this.b = cos * rb - sin * this.d; + this.c = sin * ra + cos * this.c; + this.d = sin * rb + cos * this.d; + } + }; + + // spine-core/src/Posed.ts + var Posed = class { + /** The constraint's setup pose data. */ + data; + pose; + constrainedPose; + appliedPose; + constructor(data, pose, constrainedPose) { + if (data == null) throw new Error("data cannot be null."); + this.data = data; + this.pose = pose; + this.constrainedPose = constrainedPose; + this.appliedPose = pose; + } + /** Sets the unconstrained pose to the setup pose. */ + setupPose() { + this.pose.set(this.data.setupPose); + } + /** The setup pose data. May be shared with multiple instances. */ + getData() { + return this.data; + } + /** The unconstrained pose for this object, set by animations and application code. */ + getPose() { + return this.pose; + } + /** The pose to use for rendering. If no constraints modify this pose, this is the same as {@link pose}. Otherwise it is a + * copy of {@link pose} modified by constraints. */ + getAppliedPose() { + return this.appliedPose; + } + /** Sets the applied pose to the unconstrained pose, for when no constraints will modify the pose. */ + unconstrained() { + this.appliedPose = this.pose; + } + /** Sets the applied pose to the constrained pose, in anticipation of the applied pose being modified by constraints. */ + constrained() { + this.appliedPose = this.constrainedPose; + } + /** Sets the constrained pose to the unconstrained pose, as a starting point for constraints to be applied. */ + resetConstrained() { + this.constrainedPose.set(this.pose); + } + }; + + // spine-core/src/PosedActive.ts + var PosedActive = class extends Posed { + active = false; + constructor(data, pose, constrained) { + super(data, pose, constrained); + this.setupPose(); + } + /** Returns false when this constraint won't be updated by + * {@link Skeleton.updateWorldTransform} because a skin is required and the + * {@link Skeleton.skin active skin} does not contain this item. See {@link Skin.bones}, {@link Skin.constraints}, + * {@link PosedData.skinRequired}, and {@link Skeleton.updateCache}. */ + isActive() { + return this.active; + } + }; + + // spine-core/src/Bone.ts + var Bone = class _Bone extends PosedActive { + /** The parent bone, or null if this is the root bone. */ + parent = null; + /** The immediate children of this bone. */ + children = []; + sorted = false; + constructor(data, parent) { + super(data, new BonePose(), new BonePose()); + this.parent = parent; + this.appliedPose.bone = this; + this.constrainedPose.bone = this; + } + /** Copy constructor. Does not copy the {@link children} bones. */ + copy(parent) { + const copy = new _Bone(this.data, parent); + copy.pose.set(this.pose); + return copy; + } + }; + + // spine-core/src/Constraint.ts + var Constraint = class extends PosedActive { + constructor(data, pose, constrained) { + super(data, pose, constrained); + } + isSourceActive() { + return true; + } + }; + + // spine-core/src/DrawOrder.ts + var DrawOrder = class { + _setupPose; + /** The unconstrained draw order, set by animations and application code. */ + pose; + constrainedPose; + /** The constrained draw order for rendering. If no constraints modify the draw order, this is the same as {@link pose}. + * Otherwise it is a copy of {@link pose} modified by constraints. */ + appliedPose; + constructor(setupPose) { + this._setupPose = setupPose; + this.pose = [...setupPose]; + this.constrainedPose = []; + this.appliedPose = this.pose; + } + /** Sets the unconstrained draw order to the setup pose order. */ + setupPose() { + this.pose.length = this._setupPose.length; + Utils.arrayCopy(this._setupPose, 0, this.pose, 0, this._setupPose.length); + } + /** Sets the applied pose to the unconstrained pose, for when no constraints will modify the draw order. */ + unconstrained() { + this.appliedPose = this.pose; + } + /** Sets the applied pose to the constrained pose, in anticipation of the applied pose being modified by constraints. */ + constrained() { + this.appliedPose = this.constrainedPose; + } + /** Copies the unconstrained pose to the constrained pose, as a starting point for constraints to be applied. */ + resetConstrained() { + this.constrainedPose.length = this.pose.length; + Utils.arrayCopy(this.pose, 0, this.constrainedPose, 0, this.pose.length); + } + }; + + // spine-core/src/ConstraintData.ts + var ConstraintData = class extends PosedData { + constructor(name, setup) { + super(name, setup); + } + }; + var ScaleYMode = /* @__PURE__ */ ((ScaleYMode2) => { + ScaleYMode2[ScaleYMode2["None"] = 0] = "None"; + ScaleYMode2[ScaleYMode2["Uniform"] = 1] = "Uniform"; + ScaleYMode2[ScaleYMode2["Volume"] = 2] = "Volume"; + return ScaleYMode2; + })(ScaleYMode || {}); + + // spine-core/src/Event.ts + var Event = class { + /** The animation time this event was keyed, or -1 for the setup pose. */ + time = 0; + data; + /** The integer payload for this event. */ + intValue = 0; + /** The float payload for this event. */ + floatValue = 0; + stringValue = null; + /** If an audio path is set, the volume for the audio. */ + volume = 0; + /** If an audio path is set, the left/right balance for the audio. */ + balance = 0; + constructor(time, data) { + if (!data) throw new Error("data cannot be null."); + this.time = time; + this.data = data; + } + }; + + // spine-core/src/EventData.ts + var EventData = class { + /** The name of the event, unique across all events in the skeleton. + * + * See {@link SkeletonData.findEvent}. */ + name; + _audioPath = null; + /** Path to an audio file relative to the audio folder as defined in Spine. */ + get audioPath() { + return this._audioPath; + } + set audioPath(audioPath) { + if (audioPath == null) throw new Error("audioPath cannot be null."); + this._audioPath = audioPath; + } + /** The setup values that are shared by all events with this data. */ + setupPose = new Event(-1, this); + constructor(name) { + this.name = name; + } + }; + + // spine-core/src/IkConstraintPose.ts + var IkConstraintPose = class { + /** For two bone IK, controls the bend direction of the IK bones, either 1 or -1. */ + bendDirection = 0; + /** For one bone IK, when true and the target is too close, the bone is scaled to reach it. */ + compress = false; + /** When true and the target is out of range, the parent bone is scaled to reach it. + * + * For two bone IK: 1) the child bone's local Y translation is set to 0, 2) stretch is not applied if {@link softness} is > 0, + * and 3) if the parent bone has local nonuniform scale, stretch is not applied. */ + stretch = false; + /** A percentage (0-1) that controls the mix between the constrained and unconstrained rotation. + * + * For two bone IK: if the parent bone has local nonuniform scale, the child bone's local Y translation is set to 0. */ + mix = 0; + /** For two bone IK, the target bone's distance from the maximum reach of the bones where rotation begins to slow. The bones + * will not straighten completely until the target is this far out of range. */ + softness = 0; + set(pose) { + this.mix = pose.mix; + this.softness = pose.softness; + this.bendDirection = pose.bendDirection; + this.compress = pose.compress; + this.stretch = pose.stretch; + } + }; + + // spine-core/src/IkConstraint.ts + var IkConstraint = class _IkConstraint extends Constraint { + /** The 1 or 2 bones that will be modified by this IK constraint. */ + bones; + /** The bone that is the IK target. */ + target; + constructor(data, skeleton) { + super(data, new IkConstraintPose(), new IkConstraintPose()); + if (!skeleton) throw new Error("skeleton cannot be null."); + this.bones = []; + for (const boneData of data.bones) + this.bones.push(skeleton.bones[boneData.index].constrainedPose); + this.target = skeleton.bones[data.target.index]; + } + copy(skeleton) { + var copy = new _IkConstraint(this.data, skeleton); + copy.pose.set(this.pose); + return copy; + } + update(skeleton, physics) { + const p = this.appliedPose; + if (p.mix === 0) return; + const target = this.target.appliedPose; + const bones = this.bones; + switch (bones.length) { + case 1: + _IkConstraint.apply(skeleton, bones[0], target.worldX, target.worldY, p.compress, p.stretch, this.data.scaleYMode, p.mix); + break; + case 2: + _IkConstraint.apply( + skeleton, + bones[0], + bones[1], + target.worldX, + target.worldY, + p.bendDirection, + p.stretch, + this.data.scaleYMode, + p.softness, + p.mix + ); + break; + } + } + sort(skeleton) { + skeleton.sortBone(this.target); + const parent = this.bones[0].bone; + skeleton.sortBone(parent); + skeleton._updateCache.push(this); + parent.sorted = false; + skeleton.sortReset(parent.children); + skeleton.constrained(parent); + if (this.bones.length > 1) skeleton.constrained(this.bones[1].bone); + } + isSourceActive() { + return this.target.active; + } + static apply(skeleton, boneOrParent, targetXorChild, targetYOrTargetX, compressOrTargetY, stretchOrBendDir, scaleYModeOrStretch, mixOrScaleYMode, softness, mix) { + if (typeof targetXorChild === "number") + _IkConstraint.apply1(skeleton, boneOrParent, targetXorChild, targetYOrTargetX, compressOrTargetY, stretchOrBendDir, scaleYModeOrStretch, mixOrScaleYMode); + else + _IkConstraint.apply2( + skeleton, + boneOrParent, + targetXorChild, + targetYOrTargetX, + compressOrTargetY, + stretchOrBendDir, + scaleYModeOrStretch, + mixOrScaleYMode, + softness, + mix + ); + } + static apply1(skeleton, bone, targetX, targetY, compress, stretch, scaleYMode, mix) { + bone.modifyLocal(skeleton); + const p = bone.bone.parent.appliedPose; + let pa = p.a, pb = p.b, pc = p.c, pd = p.d; + let rotationIK = -bone.shearX - bone.rotation, tx = 0, ty = 0; + switch (bone.inherit) { + case 1 /* OnlyTranslation */: + tx = (targetX - bone.worldX) * MathUtils.signum(skeleton.scaleX); + ty = (targetY - bone.worldY) * MathUtils.signum(skeleton.scaleY); + break; + // biome-ignore lint/suspicious/noFallthroughSwitchClause: reference runtime + case 2 /* NoRotationOrReflection */: { + const s = Math.abs(pa * pd - pb * pc) / Math.max(MathUtils.epsilon, pa * pa + pc * pc); + const sa = pa / skeleton.scaleX; + const sc = pc / skeleton.scaleY; + pb = -sc * s * skeleton.scaleX; + pd = sa * s * skeleton.scaleY; + rotationIK += MathUtils.atan2Deg(sc, sa); + } + // Fall through + default: { + const x = targetX - p.worldX, y = targetY - p.worldY; + const d = pa * pd - pb * pc; + if (Math.abs(d) <= MathUtils.epsilon) { + tx = 0; + ty = 0; + } else { + tx = (x * pd - y * pb) / d - bone.x; + ty = (y * pa - x * pc) / d - bone.y; + } + } + } + rotationIK += MathUtils.atan2Deg(ty, tx); + if (bone.scaleX < 0) rotationIK += 180; + if (rotationIK > 180) + rotationIK -= 360; + else if (rotationIK <= -180) + rotationIK += 360; + bone.rotation += rotationIK * mix; + if (compress || stretch) { + switch (bone.inherit) { + case 3 /* NoScale */: + case 4 /* NoScaleOrReflection */: + tx = targetX - bone.worldX; + ty = targetY - bone.worldY; + } + const b = bone.bone.data.length * bone.scaleX; + if (b > MathUtils.epsilon) { + const dd = tx * tx + ty * ty; + if (compress && dd < b * b || stretch && dd > b * b) { + const s = (Math.sqrt(dd) / b - 1) * mix + 1; + bone.scaleX *= s; + switch (scaleYMode) { + case 1 /* Uniform */: + bone.scaleY *= s; + break; + case 2 /* Volume */: + bone.scaleY /= s < 0.7 ? 0.25 + 0.642857 * s : s; + } + } + } + } + } + /** Applies 2 bone IK. The target is specified in the world coordinate system. + * @param child A direct descendant of the parent bone. */ + static apply2(skeleton, parent, child, targetX, targetY, bendDir, stretch, scaleYMode, softness, mix) { + if (parent.inherit !== 0 /* Normal */ || child.inherit !== 0 /* Normal */) return; + parent.modifyLocal(skeleton); + child.modifyLocal(skeleton); + let px = parent.x, py = parent.y, psx = parent.scaleX, psy = parent.scaleY, csx = child.scaleX; + let os1 = 0, os2 = 0, s2 = 0; + if (psx < 0) { + psx = -psx; + os1 = 180; + s2 = -1; + } else { + os1 = 0; + s2 = 1; + } + if (psy < 0) { + psy = -psy; + s2 = -s2; + } + if (csx < 0) { + csx = -csx; + os2 = 180; + } else + os2 = 0; + let cwx = 0, cwy = 0, a = parent.a, b = parent.b, c = parent.c, d = parent.d; + const u = Math.abs(psx - psy) <= MathUtils.epsilon; + if (!u || stretch) { + child.y = 0; + cwx = a * child.x + parent.worldX; + cwy = c * child.x + parent.worldY; + } else { + cwx = a * child.x + b * child.y + parent.worldX; + cwy = c * child.x + d * child.y + parent.worldY; + } + const pp = parent.bone.parent.appliedPose; + a = pp.a; + b = pp.b; + c = pp.c; + d = pp.d; + let id = a * d - b * c, x = cwx - pp.worldX, y = cwy - pp.worldY; + id = Math.abs(id) <= MathUtils.epsilon ? 0 : 1 / id; + const dx = (x * d - y * b) * id - px, dy = (y * a - x * c) * id - py; + let l1 = Math.sqrt(dx * dx + dy * dy), l2 = child.bone.data.length * csx, a1, a2; + if (l1 < MathUtils.epsilon) { + _IkConstraint.apply(skeleton, parent, targetX, targetY, false, stretch, 0 /* None */, mix); + child.rotation = 0; + return; + } + x = targetX - pp.worldX; + y = targetY - pp.worldY; + let tx = (x * d - y * b) * id - px, ty = (y * a - x * c) * id - py; + let dd = tx * tx + ty * ty; + if (softness !== 0) { + softness *= psx * (csx + 1) * 0.5; + const td = Math.sqrt(dd), sd = td - l1 - l2 * psx + softness; + if (sd > 0) { + let p = Math.min(1, sd / (softness * 2)) - 1; + p = (sd - softness * (1 - p * p)) / td; + tx -= p * tx; + ty -= p * ty; + dd = tx * tx + ty * ty; + } + } + outer: + if (u) { + l2 *= psx; + let cos = (dd - l1 * l1 - l2 * l2) / (2 * l1 * l2); + if (cos < -1) { + cos = -1; + a2 = Math.PI * bendDir; + } else if (cos > 1) { + cos = 1; + a2 = 0; + if (stretch) { + a = (Math.sqrt(dd) / (l1 + l2) - 1) * mix + 1; + parent.scaleX *= a; + switch (scaleYMode) { + case 1 /* Uniform */: + parent.scaleY *= a; + break; + case 2 /* Volume */: + parent.scaleY /= a < 0.7 ? 0.25 + 0.642857 * a : a; + } + } + } else + a2 = Math.acos(cos) * bendDir; + a = l1 + l2 * cos; + b = l2 * Math.sin(a2); + a1 = Math.atan2(ty * a - tx * b, tx * a + ty * b); + } else { + a = psx * l2; + b = psy * l2; + const aa = a * a, bb = b * b, ta = Math.atan2(ty, tx); + c = bb * l1 * l1 + aa * dd - aa * bb; + const c1 = -2 * bb * l1, c2 = bb - aa; + d = c1 * c1 - 4 * c2 * c; + if (d >= 0) { + let q = Math.sqrt(d); + if (c1 < 0) q = -q; + q = -(c1 + q) * 0.5; + let r0 = q / c2, r1 = c / q; + const r = Math.abs(r0) < Math.abs(r1) ? r0 : r1; + r0 = dd - r * r; + if (r0 >= 0) { + y = Math.sqrt(r0) * bendDir; + a1 = ta - Math.atan2(y, r); + a2 = Math.atan2(y / psy, (r - l1) / psx); + break outer; + } + } + let minAngle = MathUtils.PI, minX = l1 - a, minDist = minX * minX, minY = 0; + let maxAngle = 0, maxX = l1 + a, maxDist = maxX * maxX, maxY = 0; + c = -a * l1 / (aa - bb); + if (c >= -1 && c <= 1) { + c = Math.acos(c); + x = a * Math.cos(c) + l1; + y = b * Math.sin(c); + d = x * x + y * y; + if (d < minDist) { + minAngle = c; + minDist = d; + minX = x; + minY = y; + } + if (d > maxDist) { + maxAngle = c; + maxDist = d; + maxX = x; + maxY = y; + } + } + if (dd <= (minDist + maxDist) * 0.5) { + a1 = ta - Math.atan2(minY * bendDir, minX); + a2 = minAngle * bendDir; + } else { + a1 = ta - Math.atan2(maxY * bendDir, maxX); + a2 = maxAngle * bendDir; + } + } + const os = Math.atan2(child.y, child.x) * s2; + a1 = (a1 - os) * MathUtils.radDeg + os1 - parent.rotation; + if (a1 > 180) + a1 -= 360; + else if (a1 <= -180) + a1 += 360; + parent.rotation += a1 * mix; + a2 = ((a2 + os) * MathUtils.radDeg - child.shearX) * s2 + os2 - child.rotation; + if (a2 > 180) + a2 -= 360; + else if (a2 <= -180) + a2 += 360; + child.rotation += a2 * mix; + } + }; + + // spine-core/src/IkConstraintData.ts + var IkConstraintData = class extends ConstraintData { + /** The bones that are constrained by this IK constraint. */ + bones = []; + _target = null; + /** The bone that is the IK target. */ + set target(boneData) { + this._target = boneData; + } + get target() { + if (!this._target) throw new Error("target cannot be null."); + return this._target; + } + /** Determines how the {@link BonePose.scaleY} changes when {@link IkConstraintPose.compress} or + * {@link IkConstraintPose.stretch} set {@link BonePose.scaleX}. */ + _scaleYMode = 0 /* None */; + set scaleYMode(scaleYMode) { + this._scaleYMode = scaleYMode; + } + get scaleYMode() { + if (this._scaleYMode == null) throw new Error("scaleYMode cannot be null."); + return this._scaleYMode; + } + constructor(name) { + super(name, new IkConstraintPose()); + } + create(skeleton) { + return new IkConstraint(this, skeleton); + } + }; + + // spine-core/src/PathConstraintPose.ts + var PathConstraintPose = class { + /** The position along the path. */ + position = 0; + /** The spacing between bones. */ + spacing = 0; + /** A percentage (0-1) that controls the mix between the constrained and unconstrained rotation. */ + mixRotate = 0; + /** A percentage (0-1) that controls the mix between the constrained and unconstrained translation X. */ + mixX = 0; + /** A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y. */ + mixY = 0; + set(pose) { + this.position = pose.position; + this.spacing = pose.spacing; + this.mixRotate = pose.mixRotate; + this.mixX = pose.mixX; + this.mixY = pose.mixY; + } + }; + + // spine-core/src/PathConstraintData.ts + var PathConstraintData = class extends ConstraintData { + /** The bones that will be modified by this path constraint. */ + bones = []; + /** The slot whose path attachment will be used to constrained the bones. */ + set slot(slotData) { + this._slot = slotData; + } + get slot() { + if (!this._slot) throw new Error("SlotData not set."); + else return this._slot; + } + _slot = null; + /** The mode for positioning the first bone on the path. */ + positionMode = 0 /* Fixed */; + /** The mode for positioning the bones after the first bone on the path. */ + spacingMode = 1 /* Fixed */; + /** The mode for adjusting the rotation of the bones. */ + rotateMode = 1 /* Chain */; + /** An offset added to the constrained bone rotation. */ + offsetRotation = 0; + constructor(name) { + super(name, new PathConstraintPose()); + } + create(skeleton) { + return new PathConstraint(this, skeleton); + } + }; + var PositionMode = /* @__PURE__ */ ((PositionMode2) => { + PositionMode2[PositionMode2["Fixed"] = 0] = "Fixed"; + PositionMode2[PositionMode2["Percent"] = 1] = "Percent"; + return PositionMode2; + })(PositionMode || {}); + var SpacingMode = /* @__PURE__ */ ((SpacingMode2) => { + SpacingMode2[SpacingMode2["Length"] = 0] = "Length"; + SpacingMode2[SpacingMode2["Fixed"] = 1] = "Fixed"; + SpacingMode2[SpacingMode2["Percent"] = 2] = "Percent"; + SpacingMode2[SpacingMode2["Proportional"] = 3] = "Proportional"; + return SpacingMode2; + })(SpacingMode || {}); + var RotateMode = /* @__PURE__ */ ((RotateMode2) => { + RotateMode2[RotateMode2["Tangent"] = 0] = "Tangent"; + RotateMode2[RotateMode2["Chain"] = 1] = "Chain"; + RotateMode2[RotateMode2["ChainScale"] = 2] = "ChainScale"; + return RotateMode2; + })(RotateMode || {}); + + // spine-core/src/PathConstraint.ts + var PathConstraint = class _PathConstraint extends Constraint { + static NONE = -1; + static BEFORE = -2; + static AFTER = -3; + /** The path constraint's setup pose data. */ + data; + /** The bones that will be modified by this path constraint. */ + bones; + /** The slot whose path attachment will be used to constrained the bones. */ + slot; + spaces = []; + positions = []; + world = []; + curves = []; + lengths = []; + segments = []; + constructor(data, skeleton) { + super(data, new PathConstraintPose(), new PathConstraintPose()); + if (!skeleton) throw new Error("skeleton cannot be null."); + this.data = data; + this.bones = []; + for (const boneData of this.data.bones) + this.bones.push(skeleton.bones[boneData.index].constrainedPose); + this.slot = skeleton.slots[data.slot.index]; + } + copy(skeleton) { + var copy = new _PathConstraint(this.data, skeleton); + copy.pose.set(this.pose); + return copy; + } + update(skeleton, physics) { + const attachment = this.slot.appliedPose.attachment; + if (!(attachment instanceof PathAttachment)) return; + const p = this.appliedPose; + const mixRotate = p.mixRotate, mixX = p.mixX, mixY = p.mixY; + if (mixRotate === 0 && mixX === 0 && mixY === 0) return; + const data = this.data; + const tangents = data.rotateMode === 0 /* Tangent */, scale = data.rotateMode === 2 /* ChainScale */; + const bones = this.bones; + const boneCount = bones.length, spacesCount = tangents ? boneCount : boneCount + 1; + const spaces = Utils.setArraySize(this.spaces, spacesCount), lengths = scale ? this.lengths = Utils.setArraySize(this.lengths, boneCount) : []; + const spacing = p.spacing; + switch (data.spacingMode) { + case 2 /* Percent */: + if (scale) { + for (let i = 0, n = spacesCount - 1; i < n; i++) { + const bone = bones[i]; + const setupLength = bone.bone.data.length; + const x = setupLength * bone.a, y = setupLength * bone.c; + lengths[i] = Math.sqrt(x * x + y * y); + } + } + Utils.arrayFill(spaces, 1, spacesCount, spacing); + break; + case 3 /* Proportional */: { + let sum = 0; + for (let i = 0, n = spacesCount - 1; i < n; ) { + const bone = bones[i]; + const setupLength = bone.bone.data.length; + if (setupLength < MathUtils.epsilon) { + if (scale) lengths[i] = 0; + spaces[++i] = spacing; + } else { + const x = setupLength * bone.a, y = setupLength * bone.c; + const length = Math.sqrt(x * x + y * y); + if (scale) lengths[i] = length; + spaces[++i] = length; + sum += length; + } + } + if (sum > 0) { + sum = spacesCount / sum * spacing; + for (let i = 1; i < spacesCount; i++) + spaces[i] *= sum; + } + break; + } + default: { + const lengthSpacing = data.spacingMode === 0 /* Length */; + for (let i = 0, n = spacesCount - 1; i < n; ) { + const bone = bones[i]; + const setupLength = bone.bone.data.length; + if (setupLength < MathUtils.epsilon) { + if (scale) lengths[i] = 0; + spaces[++i] = spacing; + } else { + const x = setupLength * bone.a, y = setupLength * bone.c; + const length = Math.sqrt(x * x + y * y); + if (scale) lengths[i] = length; + spaces[++i] = (lengthSpacing ? Math.max(0, setupLength + spacing) : spacing) * length / setupLength; + } + } + } + } + const positions = this.computeWorldPositions(skeleton, attachment, spacesCount, tangents); + let boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation; + let tip = false; + if (offsetRotation === 0) + tip = data.rotateMode === 1 /* Chain */; + else { + tip = false; + const bone = this.slot.bone.appliedPose; + offsetRotation *= bone.a * bone.d - bone.b * bone.c > 0 ? MathUtils.degRad : -MathUtils.degRad; + } + for (let i = 0, ip = 3; i < boneCount; i++, ip += 3) { + const bone = bones[i]; + bone.modifyWorld(skeleton); + bone.worldX += (boneX - bone.worldX) * mixX; + bone.worldY += (boneY - bone.worldY) * mixY; + const x = positions[ip], y = positions[ip + 1], dx = x - boneX, dy = y - boneY; + if (scale) { + const length = lengths[i]; + if (length !== 0) { + const s = (Math.sqrt(dx * dx + dy * dy) / length - 1) * mixRotate + 1; + bone.a *= s; + bone.c *= s; + } + } + boneX = x; + boneY = y; + if (mixRotate > 0) { + let a = bone.a, b = bone.b, c = bone.c, d = bone.d, r = 0, cos = 0, sin = 0; + if (tangents) + r = positions[ip - 1]; + else if (spaces[i + 1] === 0) + r = positions[ip + 2]; + else + r = Math.atan2(dy, dx); + r -= Math.atan2(c, a); + if (tip) { + cos = Math.cos(r); + sin = Math.sin(r); + const length = bone.bone.data.length; + boneX += (length * (cos * a - sin * c) - dx) * mixRotate; + boneY += (length * (sin * a + cos * c) - dy) * mixRotate; + } else { + r += offsetRotation; + } + if (r > MathUtils.PI) + r -= MathUtils.PI2; + else if (r < -MathUtils.PI) + r += MathUtils.PI2; + r *= mixRotate; + cos = Math.cos(r); + sin = Math.sin(r); + bone.a = cos * a - sin * c; + bone.b = cos * b - sin * d; + bone.c = sin * a + cos * c; + bone.d = sin * b + cos * d; + } + } + } + computeWorldPositions(skeleton, path, spacesCount, tangents) { + const slot = this.slot; + let position = this.appliedPose.position; + let spaces = this.spaces, out = Utils.setArraySize(this.positions, spacesCount * 3 + 2), world = this.world; + const closed = path.closed; + let verticesLength = path.worldVerticesLength, curveCount = verticesLength / 6, prevCurve = _PathConstraint.NONE; + if (!path.constantSpeed) { + const lengths = path.lengths; + curveCount -= closed ? 1 : 2; + const pathLength2 = lengths[curveCount]; + if (this.data.positionMode === 1 /* Percent */) position *= pathLength2; + let multiplier2; + switch (this.data.spacingMode) { + case 2 /* Percent */: + multiplier2 = pathLength2; + break; + case 3 /* Proportional */: + multiplier2 = pathLength2 / spacesCount; + break; + default: + multiplier2 = 1; + } + world = Utils.setArraySize(this.world, 8); + for (let i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) { + const space = spaces[i] * multiplier2; + position += space; + let p = position; + if (closed) { + p %= pathLength2; + if (p < 0) p += pathLength2; + curve = 0; + } else if (p < 0) { + if (prevCurve !== _PathConstraint.BEFORE) { + prevCurve = _PathConstraint.BEFORE; + path.computeWorldVertices(skeleton, slot, 2, 4, world, 0, 2); + } + this.addBeforePosition(p, world, 0, out, o); + continue; + } else if (p > pathLength2) { + if (prevCurve !== _PathConstraint.AFTER) { + prevCurve = _PathConstraint.AFTER; + path.computeWorldVertices(skeleton, slot, verticesLength - 6, 4, world, 0, 2); + } + this.addAfterPosition(p - pathLength2, world, 0, out, o); + continue; + } + for (; ; curve++) { + const length = lengths[curve]; + if (p > length) continue; + if (curve === 0) + p /= length; + else { + const prev = lengths[curve - 1]; + p = (p - prev) / (length - prev); + } + break; + } + if (curve !== prevCurve) { + prevCurve = curve; + if (closed && curve === curveCount) { + path.computeWorldVertices(skeleton, slot, verticesLength - 4, 4, world, 0, 2); + path.computeWorldVertices(skeleton, slot, 0, 4, world, 4, 2); + } else + path.computeWorldVertices(skeleton, slot, curve * 6 + 2, 8, world, 0, 2); + } + this.addCurvePosition( + p, + world[0], + world[1], + world[2], + world[3], + world[4], + world[5], + world[6], + world[7], + out, + o, + tangents || i > 0 && space === 0 + ); + } + return out; + } + if (closed) { + verticesLength += 2; + world = Utils.setArraySize(this.world, verticesLength); + path.computeWorldVertices(skeleton, slot, 2, verticesLength - 4, world, 0, 2); + path.computeWorldVertices(skeleton, slot, 0, 2, world, verticesLength - 4, 2); + world[verticesLength - 2] = world[0]; + world[verticesLength - 1] = world[1]; + } else { + curveCount--; + verticesLength -= 4; + world = Utils.setArraySize(this.world, verticesLength); + path.computeWorldVertices(skeleton, slot, 2, verticesLength, world, 0, 2); + } + const curves = Utils.setArraySize(this.curves, curveCount); + let pathLength = 0; + let x1 = world[0], y1 = world[1], cx1 = 0, cy1 = 0, cx2 = 0, cy2 = 0, x2 = 0, y2 = 0; + let tmpx = 0, tmpy = 0, dddfx = 0, dddfy = 0, ddfx = 0, ddfy = 0, dfx = 0, dfy = 0; + for (let i = 0, w = 2; i < curveCount; i++, w += 6) { + cx1 = world[w]; + cy1 = world[w + 1]; + cx2 = world[w + 2]; + cy2 = world[w + 3]; + x2 = world[w + 4]; + y2 = world[w + 5]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.1875; + tmpy = (y1 - cy1 * 2 + cy2) * 0.1875; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx; + dfy += ddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + pathLength += Math.sqrt(dfx * dfx + dfy * dfy); + curves[i] = pathLength; + x1 = x2; + y1 = y2; + } + if (this.data.positionMode === 1 /* Percent */) position *= pathLength; + let multiplier; + switch (this.data.spacingMode) { + case 2 /* Percent */: + multiplier = pathLength; + break; + case 3 /* Proportional */: + multiplier = pathLength / spacesCount; + break; + default: + multiplier = 1; + } + const segments = this.segments; + let curveLength = 0; + for (let i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) { + const space = spaces[i] * multiplier; + position += space; + let p = position; + if (closed) { + p %= pathLength; + if (p < 0) p += pathLength; + curve = 0; + segment = 0; + } else if (p < 0) { + this.addBeforePosition(p, world, 0, out, o); + continue; + } else if (p > pathLength) { + this.addAfterPosition(p - pathLength, world, verticesLength - 4, out, o); + continue; + } + for (; ; curve++) { + const length = curves[curve]; + if (p > length) continue; + if (curve === 0) + p /= length; + else { + const prev = curves[curve - 1]; + p = (p - prev) / (length - prev); + } + break; + } + if (curve !== prevCurve) { + prevCurve = curve; + let ii = curve * 6; + x1 = world[ii]; + y1 = world[ii + 1]; + cx1 = world[ii + 2]; + cy1 = world[ii + 3]; + cx2 = world[ii + 4]; + cy2 = world[ii + 5]; + x2 = world[ii + 6]; + y2 = world[ii + 7]; + tmpx = (x1 - cx1 * 2 + cx2) * 0.03; + tmpy = (y1 - cy1 * 2 + cy2) * 0.03; + dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 6e-3; + dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 6e-3; + ddfx = tmpx * 2 + dddfx; + ddfy = tmpy * 2 + dddfy; + dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667; + dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667; + curveLength = Math.sqrt(dfx * dfx + dfy * dfy); + segments[0] = curveLength; + for (ii = 1; ii < 8; ii++) { + dfx += ddfx; + dfy += ddfy; + ddfx += dddfx; + ddfy += dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[ii] = curveLength; + } + dfx += ddfx; + dfy += ddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[8] = curveLength; + dfx += ddfx + dddfx; + dfy += ddfy + dddfy; + curveLength += Math.sqrt(dfx * dfx + dfy * dfy); + segments[9] = curveLength; + segment = 0; + } + p *= curveLength; + for (; ; segment++) { + const length = segments[segment]; + if (p > length) continue; + if (segment === 0) + p /= length; + else { + const prev = segments[segment - 1]; + p = segment + (p - prev) / (length - prev); + } + break; + } + this.addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || i > 0 && space === 0); + } + return out; + } + addBeforePosition(p, temp, i, out, o) { + const x1 = temp[i], y1 = temp[i + 1], dx = temp[i + 2] - x1, dy = temp[i + 3] - y1, r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + } + addAfterPosition(p, temp, i, out, o) { + const x1 = temp[i + 2], y1 = temp[i + 3], dx = x1 - temp[i], dy = y1 - temp[i + 1], r = Math.atan2(dy, dx); + out[o] = x1 + p * Math.cos(r); + out[o + 1] = y1 + p * Math.sin(r); + out[o + 2] = r; + } + addCurvePosition(p, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents) { + if (p === 0 || Number.isNaN(p)) { + out[o] = x1; + out[o + 1] = y1; + out[o + 2] = Math.atan2(cy1 - y1, cx1 - x1); + return; + } + const tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u; + const ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p; + const x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt; + out[o] = x; + out[o + 1] = y; + if (tangents) { + if (p < 1e-3) + out[o + 2] = Math.atan2(cy1 - y1, cx1 - x1); + else + out[o + 2] = Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt)); + } + } + sort(skeleton) { + const slotIndex = this.slot.data.index; + const slotBone = this.slot.bone; + if (skeleton.skin != null) this.sortPathSlot(skeleton, skeleton.skin, slotIndex, slotBone); + if (skeleton.data.defaultSkin != null && skeleton.data.defaultSkin !== skeleton.skin) + this.sortPathSlot(skeleton, skeleton.data.defaultSkin, slotIndex, slotBone); + this.sortPath(skeleton, this.slot.pose.attachment, slotBone); + const bones = this.bones; + const boneCount = this.bones.length; + for (let i = 0; i < boneCount; i++) { + const bone = bones[i].bone; + skeleton.sortBone(bone); + skeleton.constrained(bone); + } + skeleton._updateCache.push(this); + for (let i = 0; i < boneCount; i++) + skeleton.sortReset(bones[i].bone.children); + for (let i = 0; i < boneCount; i++) + bones[i].bone.sorted = true; + } + sortPathSlot(skeleton, skin, slotIndex, slotBone) { + const entries = skin.getAttachments(); + for (let i = 0, n = entries.length; i < n; i++) { + const entry = entries[i]; + if (entry.slotIndex === slotIndex) this.sortPath(skeleton, entry.attachment, slotBone); + } + } + sortPath(skeleton, attachment, slotBone) { + if (!(attachment instanceof PathAttachment)) return; + const pathBones = attachment.bones; + if (pathBones == null) + skeleton.sortBone(slotBone); + else { + const bones = skeleton.bones; + for (let i = 0, n = pathBones.length; i < n; ) { + let nn = pathBones[i++]; + nn += i; + while (i < nn) + skeleton.sortBone(bones[pathBones[i++]]); + } + } + } + isSourceActive() { + return this.slot.bone.active; + } + }; + + // spine-core/src/Physics.ts + var Physics = /* @__PURE__ */ ((Physics2) => { + Physics2[Physics2["none"] = 0] = "none"; + Physics2[Physics2["reset"] = 1] = "reset"; + Physics2[Physics2["update"] = 2] = "update"; + Physics2[Physics2["pose"] = 3] = "pose"; + return Physics2; + })(Physics || {}); + + // spine-core/src/PhysicsConstraintPose.ts + var PhysicsConstraintPose = class { + /** Controls how much bone movement is converted into physics movement. */ + inertia = 0; + /** The amount of force used to return properties to the unconstrained value. */ + strength = 0; + /** Reduces the speed of physics movements, with more of a reduction at higher speeds. */ + damping = 0; + /** Determines susceptibility to acceleration. */ + massInverse = 0; + /** Applies a constant force along the {@link Skeleton.windX}, {@link Skeleton.windY} vector. */ + wind = 0; + /** Applies a constant force along the {@link Skeleton.gravityX}, {@link Skeleton.gravityY} vector. */ + gravity = 0; + /** A percentage (0+) that controls the mix between the constrained and unconstrained poses. */ + mix = 0; + set(pose) { + this.inertia = pose.inertia; + this.strength = pose.strength; + this.damping = pose.damping; + this.massInverse = pose.massInverse; + this.wind = pose.wind; + this.gravity = pose.gravity; + this.mix = pose.mix; + } + }; + + // spine-core/src/SlotPose.ts + var SlotPose = class { + /** The color used to tint the slot's attachment. If {@link darkColor} is set, this is used as the light color for two color + * tinting. */ + color = new Color(1, 1, 1, 1); + /** The dark color used to tint the slot's attachment for two color tinting, or null if two color tinting is not used. The dark + * color's alpha is not used. */ + darkColor = null; + /** The current attachment for the slot, or null if the slot has no attachment. */ + attachment = null; + // Not used in setup pose. + /** The index of the texture region to display when the slot's attachment has a {@link Sequence}. -1 represents the + * {@link Sequence.getSetupIndex}. */ + sequenceIndex = 0; + /** Values to deform the slot's attachment. For an unweighted mesh, the entries are local positions for each vertex. For a + * weighted mesh, the entries are an offset for each vertex which will be added to the mesh's local vertex positions. + * + * See {@link VertexAttachment.computeWorldVertices} and + * {@link DeformTimeline}. */ + deform = []; + SlotPose() { + } + set(pose) { + if (pose == null) throw new Error("pose cannot be null."); + this.color.setFromColor(pose.color); + if (this.darkColor != null && pose.darkColor != null) this.darkColor.setFromColor(pose.darkColor); + this.attachment = pose.attachment; + this.sequenceIndex = pose.sequenceIndex; + this.deform.length = 0; + this.deform.push(...pose.deform); + } + /** The current attachment for the slot, or null if the slot has no attachment. */ + getAttachment() { + return this.attachment; + } + /** Sets the slot's attachment and, if the attachment changed, resets {@link sequenceIndex} and clears the {@link deform}. + * The deform is not cleared if the old attachment has the same {@link VertexAttachment.getTimelineAttachment} as the + * specified attachment. */ + setAttachment(attachment) { + if (this.attachment === attachment) return; + if (!(attachment instanceof VertexAttachment) || !(this.attachment instanceof VertexAttachment) || attachment.timelineAttachment !== this.attachment.timelineAttachment) { + this.deform.length = 0; + } + this.attachment = attachment; + this.sequenceIndex = -1; + } + }; + + // spine-core/src/Slot.ts + var Slot = class _Slot extends Posed { + skeleton; + /** The bone this slot belongs to. */ + bone; + attachmentState = 0; + constructor(data, skeleton) { + super(data, new SlotPose(), new SlotPose()); + if (!skeleton) throw new Error("skeleton cannot be null."); + this.skeleton = skeleton; + this.bone = skeleton.bones[data.boneData.index]; + if (data.setupPose.darkColor != null) { + this.pose.darkColor = new Color(); + this.constrainedPose.darkColor = new Color(); + } + this.setupPose(); + } + /** Copy constructor. */ + copy(slot, bone, skeleton) { + const copy = new _Slot(slot.data, this.skeleton); + if (this.data.setupPose.darkColor != null) { + copy.pose.darkColor = new Color(); + copy.constrainedPose.darkColor = new Color(); + } + copy.pose.set(slot.pose); + return copy; + } + setupPose() { + this.pose.color.setFromColor(this.data.setupPose.color); + if (this.pose.darkColor) this.pose.darkColor.setFromColor(this.data.setupPose.darkColor); + this.pose.sequenceIndex = this.data.setupPose.sequenceIndex; + if (!this.data.attachmentName) + this.pose.setAttachment(null); + else { + this.pose.attachment = null; + this.pose.setAttachment(this.skeleton.getAttachment(this.data.index, this.data.attachmentName)); + } + } + }; + + // spine-core/src/Skeleton.ts + var Skeleton = class _Skeleton { + static quadTriangles = [0, 1, 2, 2, 3, 0]; + static yDown = false; + static get yDir() { + return _Skeleton.yDown ? -1 : 1; + } + /** The skeleton's setup pose data. */ + data; + /** The skeleton's bones, sorted parent first. The root bone is always the first bone. */ + bones; + /** The skeleton's slots. To add a slot, also add it to {@link DrawOrder.pose}. */ + slots; + /** The skeleton's draw order. Use {@link DrawOrder.appliedPose} for rendering and {@link DrawOrder.pose} for changing the draw + * order. */ + drawOrder; + /** The skeleton's constraints. */ + // biome-ignore lint/suspicious/noExplicitAny: reference runtime does not restrict to specific types + constraints; + /** The skeleton's physics constraints. */ + physics; + /** The list of bones and constraints, sorted in the order they should be updated, as computed by {@link updateCache}. */ + // biome-ignore lint/suspicious/noExplicitAny: reference runtime does not restrict to specific types + _updateCache = []; + // biome-ignore lint/suspicious/noExplicitAny: reference runtime does not restrict to specific types + resetCache = []; + /** The skeleton's current skin. May be null. */ + skin = null; + /** The color to tint all the skeleton's attachments. */ + color; + /** Scales the entire skeleton on the X axis. + * + * Bones that do not inherit scale are still affected by this property. */ + scaleX = 1; + _scaleY = 1; + /** Scales the entire skeleton on the Y axis. + * + * Bones that do not inherit scale are still affected by this property. */ + get scaleY() { + return this._scaleY * _Skeleton.yDir; + } + set scaleY(scaleY) { + this._scaleY = scaleY; + } + /** Sets the skeleton X position, which is added to the root bone worldX position. + * + * Bones that do not inherit translation are still affected by this property. */ + x = 0; + /** Sets the skeleton Y position, which is added to the root bone worldY position. + * + * Bones that do not inherit translation are still affected by this property. */ + y = 0; + /** Returns the skeleton's time, is used for time-based manipulations, such as {@link PhysicsConstraint}. + * + * See {@link _update}. */ + time = 0; + /** The x component of a vector that defines the direction {@link PhysicsConstraintPose.wind} is applied. */ + windX = 1; + /** The y component of a vector that defines the direction {@link PhysicsConstraintPose.wind} is applied. */ + windY = 0; + /** The x component of a vector that defines the direction {@link PhysicsConstraintPose.gravity} is applied. */ + gravityX = 0; + /** The y component of a vector that defines the direction {@link PhysicsConstraintPose.gravity} is applied. */ + gravityY = 1; + _update = 0; + constructor(data) { + if (!data) throw new Error("data cannot be null."); + this.data = data; + this.bones = []; + for (let i = 0; i < data.bones.length; i++) { + const boneData = data.bones[i]; + let bone; + if (!boneData.parent) + bone = new Bone(boneData, null); + else { + const parent = this.bones[boneData.parent.index]; + bone = new Bone(boneData, parent); + parent.children.push(bone); + } + this.bones.push(bone); + } + this.slots = []; + for (const slotData of this.data.slots) + this.slots.push(new Slot(slotData, this)); + this.drawOrder = new DrawOrder(this.slots); + this.physics = []; + this.constraints = []; + for (const constraintData of this.data.constraints) { + const constraint = constraintData.create(this); + if (constraint instanceof PhysicsConstraint) this.physics.push(constraint); + this.constraints.push(constraint); + } + this.color = new Color(1, 1, 1, 1); + this.updateCache(); + } + /** Caches information about bones and constraints. Must be called if the {@link skin} is modified or if bones, constraints, + * or weighted path attachments are added or removed. */ + updateCache() { + this._updateCache.length = 0; + this.resetCache.length = 0; + this.drawOrder.unconstrained(); + const slots = this.slots; + for (let i = 0, n2 = slots.length; i < n2; i++) + slots[i].unconstrained(); + const bones = this.bones; + const boneCount = bones.length; + for (let i = 0, n2 = boneCount; i < n2; i++) { + const bone = bones[i]; + bone.sorted = bone.data.skinRequired; + bone.active = !bone.sorted; + bone.unconstrained(); + } + if (this.skin) { + const skinBones = this.skin.bones; + for (let i = 0, n2 = this.skin.bones.length; i < n2; i++) { + let bone = this.bones[skinBones[i].index]; + do { + bone.sorted = false; + bone.active = true; + bone = bone.parent; + } while (bone); + } + } + const constraints = this.constraints; + let n = this.constraints.length; + for (let i = 0; i < n; i++) + constraints[i].unconstrained(); + for (let i = 0; i < n; i++) { + const constraint = constraints[i]; + constraint.active = constraint.isSourceActive() && (!constraint.data.skinRequired || this.skin != null && this.skin.constraints.includes(constraint.data)); + if (constraint.active) constraint.sort(this); + } + for (let i = 0; i < boneCount; i++) + this.sortBone(bones[i]); + n = this._updateCache.length; + for (let i = 0; i < n; i++) { + const updateable = this._updateCache[i]; + if (updateable instanceof Bone) this._updateCache[i] = updateable.appliedPose; + } + } + // biome-ignore lint/suspicious/noExplicitAny: reference runtime does not restrict to specific types + constrained(object) { + if (object.pose === object.appliedPose) { + object.constrained(); + this.resetCache.push(object); + } + } + sortBone(bone) { + if (bone.sorted || !bone.active) return; + const parent = bone.parent; + if (parent) this.sortBone(parent); + bone.sorted = true; + this._updateCache.push(bone); + } + sortReset(bones) { + for (let i = 0, n = bones.length; i < n; i++) { + const bone = bones[i]; + if (bone.active) { + if (bone.sorted) this.sortReset(bone.children); + bone.sorted = false; + } + } + } + /** Updates the world transform for each bone and applies all constraints. + * + * See World transforms in the Spine + * Runtimes Guide. */ + updateWorldTransform(physics) { + this._update++; + if (this.drawOrder.appliedPose === this.drawOrder.constrainedPose) this.drawOrder.resetConstrained(); + const resetCache = this.resetCache; + for (let i = 0, n = this.resetCache.length; i < n; i++) + resetCache[i].resetConstrained(); + const updateCache = this._updateCache; + for (let i = 0, n = this._updateCache.length; i < n; i++) + updateCache[i].update(this, physics); + } + /** Sets the bones, constraints, and slots to their setup pose values. */ + setupPose() { + this.setupPoseBones(); + this.setupPoseSlots(); + } + /** Sets the bones and constraints to their setup pose values. */ + setupPoseBones() { + const bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) + bones[i].setupPose(); + const constraints = this.constraints; + for (let i = 0, n = constraints.length; i < n; i++) + constraints[i].setupPose(); + } + /** Sets the slots and draw order to their setup pose values. */ + setupPoseSlots() { + this.drawOrder.setupPose(); + const slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) + slots[i].setupPose(); + } + /** Returns the root bone, or null if the skeleton has no bones. */ + getRootBone() { + if (this.bones.length === 0) return null; + return this.bones[0]; + } + /** Finds a bone by comparing each bone's name. It is more efficient to cache the results of this method than to call it + * repeatedly. */ + findBone(boneName) { + if (!boneName) throw new Error("boneName cannot be null."); + const bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) + if (bones[i].data.name === boneName) return bones[i]; + return null; + } + /** Finds a slot by comparing each slot's name. It is more efficient to cache the results of this method than to call it + * repeatedly. */ + findSlot(slotName) { + if (!slotName) throw new Error("slotName cannot be null."); + const slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) + if (slots[i].data.name === slotName) return slots[i]; + return null; + } + setSkin(newSkin) { + if (typeof newSkin === "string") + this.setSkinByName(newSkin); + else + this.setSkinBySkin(newSkin); + } + setSkinByName(skinName) { + const skin = this.data.findSkin(skinName); + if (!skin) throw new Error(`Skin not found: ${skinName}`); + this.setSkin(skin); + } + setSkinBySkin(newSkin) { + if (newSkin === this.skin) return; + if (newSkin) { + if (this.skin) + newSkin.attachAll(this, this.skin); + else { + const slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) { + const slot = slots[i]; + const name = slot.data.attachmentName; + if (name) { + const attachment = newSkin.getAttachment(i, name); + if (attachment) slot.pose.setAttachment(attachment); + } + } + } + } + this.skin = newSkin; + this.updateCache(); + } + getAttachment(slotNameOrIndex, placeholder) { + if (typeof slotNameOrIndex === "string") + return this.getAttachmentByName(slotNameOrIndex, placeholder); + return this.getAttachmentByIndex(slotNameOrIndex, placeholder); + } + /** Finds an attachment by looking in the {@link skin} and {@link SkeletonData.defaultSkin} using the slot name and attachment + * name. + * + * See {@link getAttachment}. + * @returns May be null. */ + getAttachmentByName(slotName, placeholder) { + const slot = this.data.findSlot(slotName); + if (!slot) throw new Error(`Can't find slot with name ${slotName}`); + return this.getAttachment(slot.index, placeholder); + } + /** Finds an attachment by looking in the {@link skin} and {@link SkeletonData.defaultSkin} using the slot index and + * attachment name. First the skin is checked and if the attachment was not found, the default skin is checked. + * + * See [Runtime skins](http://esotericsoftware.com/spine-runtime-skins) in the Spine Runtimes Guide. + * @returns May be null. */ + getAttachmentByIndex(slotIndex, placeholder) { + if (!placeholder) throw new Error("placeholder cannot be null."); + if (this.skin) { + const attachment = this.skin.getAttachment(slotIndex, placeholder); + if (attachment) return attachment; + } + if (this.data.defaultSkin) return this.data.defaultSkin.getAttachment(slotIndex, placeholder); + return null; + } + /** A convenience method to set an attachment by finding the slot with {@link findSlot}, finding the attachment with + * {@link getAttachment}, then setting the slot's {@link Slot.attachment}. + * @param placeholder May be null to clear the slot's attachment. */ + setAttachment(slotName, placeholder) { + if (!slotName) throw new Error("slotName cannot be null."); + const slot = this.findSlot(slotName); + if (!slot) throw new Error(`Slot not found: ${slotName}`); + let attachment = null; + if (placeholder) { + attachment = this.getAttachment(slot.data.index, placeholder); + if (!attachment) + throw new Error(`Attachment not found: ${placeholder}, for slot: ${slotName}`); + } + slot.pose.setAttachment(attachment); + } + /** Finds a constraint of the specified type by comparing each constraints's name. It is more efficient to cache the results of + * this method than to call it multiple times. */ + // biome-ignore lint/suspicious/noExplicitAny: reference runtime does not restrict to specific types + findConstraint(constraintName, type) { + if (constraintName == null) throw new Error("constraintName cannot be null."); + if (type == null) throw new Error("type cannot be null."); + const constraints = this.constraints; + for (let i = 0, n = constraints.length; i < n; i++) { + const constraint = constraints[i]; + if (constraint instanceof type && constraint.data.name === constraintName) return constraint; + } + return null; + } + /** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the applied pose. + * @param offset An output value, the distance from the skeleton origin to the bottom left corner of the AABB. + * @param size An output value, the width and height of the AABB. + * @param temp Working memory to temporarily store attachments' computed world vertices. */ + getBoundsRect(clipper) { + const offset = new Vector2(); + const size = new Vector2(); + this.getBounds(offset, size, void 0, clipper); + return { x: offset.x, y: offset.y, width: size.x, height: size.y }; + } + /** Returns the axis aligned bounding box (AABB) of the region and mesh attachments for the applied pose. Optionally applies + * clipping. + * @param offset An output value, the distance from the skeleton origin to the bottom left corner of the AABB. + * @param size An output value, the width and height of the AABB. + * @param temp Working memory to temporarily store attachments' computed world vertices. + * @param clipper {@link SkeletonClipping} to use. If `null`, no clipping is applied. */ + getBounds(offset, size, temp = new Array(2), clipper = null) { + if (!offset) throw new Error("offset cannot be null."); + if (!size) throw new Error("size cannot be null."); + const drawOrder = this.drawOrder.appliedPose; + const slots = drawOrder; + let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + for (let i = 0, n = drawOrder.length; i < n; i++) { + const slot = slots[i]; + if (!slot.bone.active) continue; + let verticesLength = 0; + let vertices = null; + let triangles = null; + const attachment = slot.appliedPose.attachment; + if (attachment) { + if (attachment instanceof RegionAttachment) { + verticesLength = 8; + vertices = Utils.setArraySize(temp, verticesLength, 0); + attachment.computeWorldVertices(slot, attachment.getOffsets(slot.appliedPose), vertices, 0, 2); + triangles = _Skeleton.quadTriangles; + } else if (attachment instanceof MeshAttachment) { + verticesLength = attachment.worldVerticesLength; + vertices = Utils.setArraySize(temp, verticesLength, 0); + attachment.computeWorldVertices(this, slot, 0, verticesLength, vertices, 0, 2); + triangles = attachment.triangles; + } else if (attachment instanceof ClippingAttachment && clipper) { + clipper.clipEnd(slot); + clipper.clipStart(this, slot, attachment); + continue; + } + if (vertices && triangles) { + if (clipper?.isClipping() && clipper.clipTriangles(vertices, triangles, triangles.length)) { + vertices = clipper.clippedVertices; + verticesLength = clipper.clippedVertices.length; + } + for (let ii = 0, nn = vertices.length; ii < nn; ii += 2) { + const x = vertices[ii], y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + } + if (clipper) clipper.clipEnd(slot); + } + if (clipper) clipper.clipEnd(); + offset.set(minX, minY); + size.set(maxX - minX, maxY - minY); + } + /** Scales the entire skeleton on the X and Y axes. + * + * Bones that do not inherit scale are still affected by this property. */ + setScale(scaleX, scaleY) { + this.scaleX = scaleX; + this.scaleY = scaleY; + } + /** Sets the skeleton X and Y position, which is added to the root bone worldX and worldY position. + * + * Bones that do not inherit translation are still affected by this property. */ + setPosition(x, y) { + this.x = x; + this.y = y; + } + /** Increments the skeleton's {@link time}. */ + update(delta) { + this.time += delta; + } + /** Calls {@link PhysicsConstraint.translate} for each physics constraint. */ + physicsTranslate(x, y) { + const constraints = this.physics; + for (let i = 0, n = constraints.length; i < n; i++) + constraints[i].translate(x, y); + } + /** Calls {@link PhysicsConstraint.rotate} for each physics constraint. */ + physicsRotate(x, y, degrees) { + const constraints = this.physics; + for (let i = 0, n = constraints.length; i < n; i++) + constraints[i].rotate(x, y, degrees); + } + }; + + // spine-core/src/PhysicsConstraint.ts + var PhysicsConstraint = class _PhysicsConstraint extends Constraint { + bone; + _reset = true; + ux = 0; + uy = 0; + cx = 0; + cy = 0; + tx = 0; + ty = 0; + xOffset = 0; + xLag = 0; + xVelocity = 0; + yOffset = 0; + yLag = 0; + yVelocity = 0; + rotateOffset = 0; + rotateLag = 0; + rotateVelocity = 0; + scaleOffset = 0; + scaleLag = 0; + scaleVelocity = 0; + remaining = 0; + lastTime = 0; + constructor(data, skeleton) { + super(data, new PhysicsConstraintPose(), new PhysicsConstraintPose()); + if (skeleton == null) throw new Error("skeleton cannot be null."); + this.bone = skeleton.bones[data.bone.index].constrainedPose; + } + copy(skeleton) { + var copy = new _PhysicsConstraint(this.data, skeleton); + copy.pose.set(this.pose); + return copy; + } + /** Resets all physics state that was the result of previous movement. Use this after moving a bone to prevent physics from + * reacting to the movement. */ + reset(skeleton) { + this.remaining = 0; + this.lastTime = skeleton.time; + this._reset = true; + this.xOffset = 0; + this.xLag = 0; + this.xVelocity = 0; + this.yOffset = 0; + this.yLag = 0; + this.yVelocity = 0; + this.rotateOffset = 0; + this.rotateLag = 0; + this.rotateVelocity = 0; + this.scaleOffset = 0; + this.scaleLag = 0; + this.scaleVelocity = 0; + } + /** Translates the physics constraint so the next {@link update} forces are applied as if the bone moved an + * additional amount in world space. */ + translate(x, y) { + this.ux -= x; + this.uy -= y; + this.cx -= x; + this.cy -= y; + } + /** Rotates the physics constraint so the next {@link update} forces are applied as if the bone rotated + * around the specified point in world space. */ + rotate(x, y, degrees) { + const r = degrees * MathUtils.degRad, cos = Math.cos(r), sin = Math.sin(r); + const dx = this.cx - x, dy = this.cy - y; + this.translate(dx * cos - dy * sin - dx, dx * sin + dy * cos - dy); + } + /** Applies the constraint to the constrained bones. */ + update(skeleton, physics) { + const p = this.appliedPose; + const mix = p.mix; + if (mix === 0) return; + const x = this.data.x > 0, y = this.data.y > 0, rotateOrShearX = this.data.rotate > 0 || this.data.shearX > 0, scaleX = this.data.scaleX > 0; + const bone = this.bone; + let l = bone.bone.data.length, t = this.data.step, z = 0; + if (physics === 0 /* none */) return; + bone.modifyWorld(skeleton); + switch (physics) { + // biome-ignore lint/suspicious/noFallthroughSwitchClause: fall through expected + case 1 /* reset */: + this.reset(skeleton); + // Fall through. + case 2 /* update */: { + const delta = Math.max(skeleton.time - this.lastTime, 0), aa = this.remaining; + this.remaining += delta; + this.lastTime = skeleton.time; + const bx = bone.worldX, by = bone.worldY; + if (this._reset) { + this._reset = false; + this.ux = bx; + this.uy = by; + } else { + let a = this.remaining, i = p.inertia, f = skeleton.data.referenceScale, d = -1, m = 0, e = 0, qx = this.data.limit * delta, qy = qx * Math.abs(skeleton.scaleY); + qx *= Math.abs(skeleton.scaleX); + if (x || y) { + if (x) { + const u = (this.ux - bx) * i; + this.xOffset += u > qx ? qx : u < -qx ? -qx : u; + this.ux = bx; + } + if (y) { + const u = (this.uy - by) * i; + this.yOffset += u > qy ? qy : u < -qy ? -qy : u; + this.uy = by; + } + if (a >= t) { + const xs = this.xOffset, ys = this.yOffset; + d = p.damping ** (60 * t); + m = t * p.massInverse; + e = p.strength; + const w = f * p.wind, g = f * p.gravity; + const ax = (w * skeleton.windX + g * skeleton.gravityX) * skeleton.scaleX; + const ay = (w * skeleton.windY + g * skeleton.gravityY) * skeleton.scaleY; + do { + if (x) { + this.xVelocity += (ax - this.xOffset * e) * m; + this.xOffset += this.xVelocity * t; + this.xVelocity *= d; + } + if (y) { + this.yVelocity -= (ay + this.yOffset * e) * m; + this.yOffset += this.yVelocity * t; + this.yVelocity *= d; + } + a -= t; + } while (a >= t); + this.xLag = this.xOffset - xs; + this.yLag = this.yOffset - ys; + } + z = Math.max(0, 1 - a / t); + if (x) bone.worldX += (this.xOffset - this.xLag * z) * mix * this.data.x; + if (y) bone.worldY += (this.yOffset - this.yLag * z) * mix * this.data.y; + } + if (rotateOrShearX || scaleX) { + let ca = Math.atan2(bone.c, bone.a), c = 0, s = 0, mr = 0, dx = this.cx - bone.worldX, dy = this.cy - bone.worldY; + if (dx > qx) + dx = qx; + else if (dx < -qx) + dx = -qx; + if (dy > qy) + dy = qy; + else if (dy < -qy) + dy = -qy; + a = this.remaining; + if (rotateOrShearX) { + mr = (this.data.rotate + this.data.shearX) * mix; + z = this.rotateLag * Math.max(0, 1 - aa / t); + let r = Math.atan2(dy + this.ty, dx + this.tx) - ca - (this.rotateOffset - z) * mr; + this.rotateOffset += (r - Math.ceil(r * MathUtils.invPI2 - 0.5) * MathUtils.PI2) * i; + r = (this.rotateOffset - z) * mr + ca; + c = Math.cos(r); + s = Math.sin(r); + if (scaleX) { + r = l * bone.getWorldScaleX(); + if (r > 0) this.scaleOffset += (dx * c + dy * s) * i / r; + } + } else { + c = Math.cos(ca); + s = Math.sin(ca); + const r = l * bone.getWorldScaleX() - this.scaleLag * Math.max(0, 1 - aa / t); + if (r > 0) this.scaleOffset += (dx * c + dy * s) * i / r; + } + if (a >= t) { + if (d === -1) { + d = p.damping ** (60 * t); + m = t * p.massInverse; + e = p.strength; + } + const ax = p.wind * skeleton.windX + p.gravity * skeleton.gravityX; + const ay = (p.wind * skeleton.windY + p.gravity * skeleton.gravityY) * Skeleton.yDir; + const rs = this.rotateOffset, ss = this.scaleOffset, h = l / f; + while (true) { + a -= t; + if (scaleX) { + this.scaleVelocity += (ax * c - ay * s - this.scaleOffset * e) * m; + this.scaleOffset += this.scaleVelocity * t; + this.scaleVelocity *= d; + } + if (rotateOrShearX) { + this.rotateVelocity -= ((ax * s + ay * c) * h + this.rotateOffset * e) * m; + this.rotateOffset += this.rotateVelocity * t; + this.rotateVelocity *= d; + if (a < t) break; + const r = this.rotateOffset * mr + ca; + c = Math.cos(r); + s = Math.sin(r); + } else if (a < t) + break; + } + this.rotateLag = this.rotateOffset - rs; + this.scaleLag = this.scaleOffset - ss; + } + z = Math.max(0, 1 - a / t); + } + this.remaining = a; + } + this.cx = bone.worldX; + this.cy = bone.worldY; + break; + } + case 3 /* pose */: + z = Math.max(0, 1 - this.remaining / t); + if (x) bone.worldX += (this.xOffset - this.xLag * z) * mix * this.data.x; + if (y) bone.worldY += (this.yOffset - this.yLag * z) * mix * this.data.y; + } + if (rotateOrShearX) { + let o = (this.rotateOffset - this.rotateLag * z) * mix, s = 0, c = 0, a = 0; + if (this.data.shearX > 0) { + let r = 0; + if (this.data.rotate > 0) { + r = o * this.data.rotate; + s = Math.sin(r); + c = Math.cos(r); + a = bone.b; + bone.b = c * a - s * bone.d; + bone.d = s * a + c * bone.d; + } + r += o * this.data.shearX; + s = Math.sin(r); + c = Math.cos(r); + a = bone.a; + bone.a = c * a - s * bone.c; + bone.c = s * a + c * bone.c; + } else { + o *= this.data.rotate; + s = Math.sin(o); + c = Math.cos(o); + a = bone.a; + bone.a = c * a - s * bone.c; + bone.c = s * a + c * bone.c; + a = bone.b; + bone.b = c * a - s * bone.d; + bone.d = s * a + c * bone.d; + } + } + if (scaleX) { + let s = 1 + (this.scaleOffset - this.scaleLag * z) * mix * this.data.scaleX; + bone.a *= s; + bone.c *= s; + switch (this.data.scaleYMode) { + case 1 /* Uniform */: + bone.b *= s; + bone.d *= s; + break; + case 2 /* Volume */: + s = Math.abs(s); + s = s >= 0.7 ? 1 / s : 4 - 3.67347 * s; + bone.b *= s; + bone.d *= s; + } + } + if (physics !== 3 /* pose */) { + this.tx = l * bone.a; + this.ty = l * bone.c; + } + } + sort(skeleton) { + const bone = this.bone.bone; + skeleton.sortBone(bone); + skeleton._updateCache.push(this); + skeleton.sortReset(bone.children); + skeleton.constrained(bone); + } + isSourceActive() { + return this.bone.bone.active; + } + }; + + // spine-core/src/PhysicsConstraintData.ts + var PhysicsConstraintData = class extends ConstraintData { + /** The bone constrained by this physics constraint. */ + set bone(boneData) { + this._bone = boneData; + } + get bone() { + if (!this._bone) throw new Error("BoneData not set."); + else return this._bone; + } + _bone = null; + /** Physics influence on x translation, 0-1. */ + x = 0; + /** Physics influence on y translation, 0-1. */ + y = 0; + /** Physics influence on rotation, 0-1. */ + rotate = 0; + /** Physics influence on scaleX, 0-1. */ + scaleX = 0; + /** Physics influence on shearX, 0-1. */ + shearX = 0; + /** Movement greater than the limit will not have a greater affect on physics. */ + limit = 0; + /** The time in milliseconds required to advanced the physics simulation one step. */ + step = 0; + /** True when this constraint's inertia is controlled by global slider timelines. */ + inertiaGlobal = false; + /** True when this constraint's strength is controlled by global slider timelines. */ + strengthGlobal = false; + /** True when this constraint's damping is controlled by global slider timelines. */ + dampingGlobal = false; + /** True when this constraint's mass is controlled by global slider timelines. */ + massGlobal = false; + /** True when this constraint's wind is controlled by global slider timelines. */ + windGlobal = false; + /** True when this constraint's gravity is controlled by global slider timelines. */ + gravityGlobal = false; + /** True when this constraint's mix is controlled by global slider timelines. */ + mixGlobal = false; + /** Determines how the {@link BonePose.scaleY} changes when {@link BonePose.scaleX} sets + * {@link BonePose.scaleX}. */ + _scaleYMode = 0 /* None */; + get scaleYMode() { + return this._scaleYMode; + } + set scaleYMode(scaleYMode) { + if (scaleYMode == null) throw new Error("scaleYMode cannot be null."); + this._scaleYMode = scaleYMode; + } + constructor(name) { + super(name, new PhysicsConstraintPose()); + } + create(skeleton) { + return new PhysicsConstraint(this, skeleton); + } + }; + + // spine-core/src/polyfills.ts + (() => { + if (typeof Math.fround === "undefined") { + Math.fround = /* @__PURE__ */ ((array) => (x) => { + array[0] = x; + return array[0]; + })(new Float32Array(1)); + } + })(); + + // spine-core/src/SliderPose.ts + var SliderPose = class { + /** The time in the {@link SliderData.animation} to apply the animation. */ + time = 0; + /** A percentage (unbounded) that controls the mix between the constrained and unconstrained poses. */ + mix = 0; + set(pose) { + this.time = pose.time; + this.mix = pose.mix; + } + }; + + // spine-core/src/Slider.ts + var Slider = class _Slider extends Constraint { + static offsets = [0, 0, 0, 0, 0, 0]; + /** When set, the bone's transform property is used to set the slider's {@link SliderPose.time}. */ + bone = null; + constructor(data, skeleton) { + super(data, new SliderPose(), new SliderPose()); + if (!skeleton) throw new Error("skeleton cannot be null."); + if (data.bone != null) this.bone = skeleton.bones[data.bone.index]; + } + copy(skeleton) { + var copy = new _Slider(this.data, skeleton); + copy.pose.set(this.pose); + return copy; + } + update(skeleton, physics) { + const p = this.appliedPose; + if (p.mix === 0) return; + const data = this.data, animation = data.animation, bone = this.bone; + if (bone !== null) { + if (!bone.active) return; + if (data.local) bone.appliedPose.validateLocalTransform(skeleton); + p.time = data.offset + (data.property.value(skeleton, bone.appliedPose, data.local, _Slider.offsets) - data.property.offset) * data.scale; + if (data.loop) + p.time = animation.duration + p.time % animation.duration; + else + p.time = Math.max(0, p.time); + } + const bones = skeleton.bones; + const indices = animation.bones; + for (let i = 0, n = animation.bones.length; i < n; i++) + bones[indices[i]].appliedPose.modifyLocal(skeleton); + animation.apply(skeleton, p.time, p.time, data.loop, null, p.mix, 0 /* current */, data.additive, false, true); + } + sort(skeleton) { + const bone = this.bone; + const data = this.data; + if (bone && !data.local) skeleton.sortBone(bone); + skeleton._updateCache.push(this); + const bones = skeleton.bones; + const indices = data.animation.bones; + for (let i = 0, n = data.animation.bones.length; i < n; i++) { + const bone2 = bones[indices[i]]; + bone2.sorted = false; + skeleton.sortReset(bone2.children); + skeleton.constrained(bone2); + } + const timelines = data.animation.timelines; + const slots = skeleton.slots; + const constraints = skeleton.constraints; + const physics = skeleton.physics; + const physicsCount = skeleton.physics.length; + for (let i = 0, n = data.animation.timelines.length; i < n; i++) { + const t = timelines[i]; + if (isSlotTimeline(t)) + skeleton.constrained(slots[t.slotIndex]); + else if (t instanceof DrawOrderTimeline || t instanceof DrawOrderFolderTimeline) + skeleton.drawOrder.constrained(); + else if (t instanceof PhysicsConstraintTimeline) { + if (t.constraintIndex === -1) { + for (let ii = 0; ii < physicsCount; ii++) + skeleton.constrained(physics[ii]); + } else + skeleton.constrained(constraints[t.constraintIndex]); + } else if (isConstraintTimeline(t)) { + const constraintIndex = t.constraintIndex; + if (constraintIndex !== -1) skeleton.constrained(constraints[constraintIndex]); + } + } + } + }; + + // spine-core/src/SliderData.ts + var SliderData = class extends ConstraintData { + /** The animation the slider will apply. */ + animation; + /** When true, the animation is applied by adding it to the current pose rather than overwriting it. */ + additive = false; + /** When true, the animation repeats after its duration, otherwise the last frame is used. */ + loop = false; + /** When set, the bone's transform property is used to set the slider's {@link SliderPose.time}. */ + bone = null; + /** When a bone is set, the specified transform property is used to set the slider's {@link SliderPose.time}. */ + property; + /** When a bone is set, this is the scale of the {@link property} value in relation to the slider time. */ + scale = 0; + /** When a bone is set, the offset is added to the property. */ + offset = 0; + /** When true and a bone is set, the bone's local transform property is read instead of its world transform. */ + local = false; + // Nonessential. + /** When a bone is set, the maximum slider time for the bone property range, or 0 if nonessential data was not exported. */ + max = 0; + constructor(name) { + super(name, new SliderPose()); + } + create(skeleton) { + return new Slider(this, skeleton); + } + }; + + // spine-core/src/SkeletonData.ts + var SkeletonData = class { + /** The skeleton's name, which by default is the name of the skeleton data file, if possible. May be null. */ + name = null; + /** The skeleton's bones, sorted parent first. The root bone is always the first bone. */ + bones = []; + // Ordered parents first. + /** The skeleton's slots in the setup pose draw order. */ + slots = []; + // Setup pose draw order. + skins = []; + /** The skeleton's default skin. By default this skin contains all attachments that were not in a skin in Spine. + * + * See {@link Skeleton.getAttachmentByName}. + * May be null. */ + defaultSkin = null; + /** The skeleton's events. */ + events = []; + /** The skeleton's animations. */ + animations = []; + /** The skeleton's IK constraints. */ + // biome-ignore lint/suspicious/noExplicitAny: reference runtime does not restrict to specific types + constraints = []; + /** The X coordinate of the skeleton's axis aligned bounding box in the setup pose. */ + x = 0; + /** The Y coordinate of the skeleton's axis aligned bounding box in the setup pose. */ + y = 0; + /** The width of the skeleton's axis aligned bounding box in the setup pose. */ + width = 0; + /** The height of the skeleton's axis aligned bounding box in the setup pose. */ + height = 0; + /** Baseline scale factor for applying distance-dependent effects on non-scalable properties, such as angle or scale. Default + * is 100. */ + referenceScale = 100; + /** The Spine version used to export the skeleton data, or null. */ + version = null; + /** The skeleton data hash. This value will change if any of the skeleton data has changed. May be null. */ + hash = null; + // Nonessential + /** The dopesheet FPS in Spine. Available only when nonessential data was exported. */ + fps = 30; + /** The path to the images folder as defined in Spine. Available only when nonessential data was exported. May be null. */ + imagesPath = null; + /** The path to the audio folder as defined in Spine. Available only when nonessential data was exported. May be null. */ + audioPath = null; + /** Finds a bone by comparing each bone's name. It is more efficient to cache the results of this method than to call it + * multiple times. + * @returns May be null. */ + findBone(boneName) { + if (!boneName) throw new Error("boneName cannot be null."); + const bones = this.bones; + for (let i = 0, n = bones.length; i < n; i++) + if (bones[i].name === boneName) return bones[i]; + return null; + } + /** Finds a slot by comparing each slot's name. It is more efficient to cache the results of this method than to call it + * multiple times. + * @returns May be null. */ + findSlot(slotName) { + if (!slotName) throw new Error("slotName cannot be null."); + const slots = this.slots; + for (let i = 0, n = slots.length; i < n; i++) + if (slots[i].name === slotName) return slots[i]; + return null; + } + /** Finds a skin by comparing each skin's name. It is more efficient to cache the results of this method than to call it + * multiple times. + * @returns May be null. */ + findSkin(skinName) { + if (!skinName) throw new Error("skinName cannot be null."); + const skins = this.skins; + for (let i = 0, n = skins.length; i < n; i++) + if (skins[i].name === skinName) return skins[i]; + return null; + } + /** Finds an event by comparing each events's name. It is more efficient to cache the results of this method than to call it + * multiple times. + * @returns May be null. */ + findEvent(eventDataName) { + if (!eventDataName) throw new Error("eventDataName cannot be null."); + const events = this.events; + for (let i = 0, n = events.length; i < n; i++) + if (events[i].name === eventDataName) return events[i]; + return null; + } + /** Collects animations used by {@link SliderData slider constraints}. + * + * Slider animations are designed to be applied by slider constraints rather than on their own. Applications that have a user + * choose an animation may want to exclude them. */ + findSliderAnimations(animations) { + const constraints = this.constraints; + for (let i = 0, n = this.constraints.length; i < n; i++) { + const data = constraints[i]; + if (data instanceof SliderData && data.animation != null) animations.push(data.animation); + } + return animations; + } + /** Finds an animation by comparing each animation's name. It is more efficient to cache the results of this method than to + * call it multiple times. + * @returns May be null. */ + findAnimation(animationName) { + if (!animationName) throw new Error("animationName cannot be null."); + const animations = this.animations; + for (let i = 0, n = animations.length; i < n; i++) + if (animations[i].name === animationName) return animations[i]; + return null; + } + // --- Constraints. + /** Finds a constraint of the specified type by comparing each constraints's name. It is more efficient to cache the results of + * this method than to call it multiple times. */ + // biome-ignore lint/suspicious/noExplicitAny: reference runtime does not restrict to specific types + findConstraint(constraintName, type) { + if (!constraintName) throw new Error("constraintName cannot be null."); + if (type == null) throw new Error("type cannot be null."); + const constraints = this.constraints; + for (let i = 0, n = this.constraints.length; i < n; i++) { + const constraint = constraints[i]; + if (constraint instanceof type && constraint.name === constraintName) return constraint; + } + return null; + } + }; + + // spine-core/src/Skin.ts + var SkinEntry = class { + /** The {@link Skeleton.slots} index. */ + slotIndex = 0; + placeholder; + /** The attachment for this skin entry. */ + attachment; + constructor(slotIndex = 0, placeholder, attachment) { + this.slotIndex = slotIndex; + this.placeholder = placeholder; + this.attachment = attachment; + } + }; + var Skin = class { + /** The skin's name, unique across all skins in the skeleton. + * + * See {@link SkeletonData.findSkin}. */ + name; + attachments = []; + bones = []; + // biome-ignore lint/suspicious/noExplicitAny: reference runtime does not restrict to specific types + constraints = []; + /** The color of the skin as it was in Spine, or a default color if nonessential data was not exported. */ + color = new Color(0.99607843, 0.61960787, 0.30980393, 1); + // fe9e4fff + constructor(name) { + if (!name) throw new Error("name cannot be null."); + this.name = name; + } + /** Adds an attachment to the skin for the specified slot index and name. */ + setAttachment(slotIndex, placeholder, attachment) { + if (!attachment) throw new Error("attachment cannot be null."); + const attachments = this.attachments; + if (slotIndex >= attachments.length) attachments.length = slotIndex + 1; + if (!attachments[slotIndex]) attachments[slotIndex] = {}; + attachments[slotIndex][placeholder] = attachment; + } + /** Adds all attachments, bones, and constraints from the specified skin to this skin. */ + addSkin(skin) { + for (let i = 0; i < skin.bones.length; i++) { + const bone = skin.bones[i]; + let contained = false; + for (let ii = 0; ii < this.bones.length; ii++) { + if (this.bones[ii] === bone) { + contained = true; + break; + } + } + if (!contained) this.bones.push(bone); + } + for (let i = 0; i < skin.constraints.length; i++) { + const constraint = skin.constraints[i]; + let contained = false; + for (let ii = 0; ii < this.constraints.length; ii++) { + if (this.constraints[ii] === constraint) { + contained = true; + break; + } + } + if (!contained) this.constraints.push(constraint); + } + const attachments = skin.getAttachments(); + for (let i = 0; i < attachments.length; i++) { + const attachment = attachments[i]; + this.setAttachment(attachment.slotIndex, attachment.placeholder, attachment.attachment); + } + } + /** Adds all bones and constraints and copies of all attachments from the specified skin to this skin. Mesh attachments are not + * copied, instead a new linked mesh is created. The attachment copies can be modified without affecting the originals. */ + copySkin(skin) { + for (let i = 0; i < skin.bones.length; i++) { + const bone = skin.bones[i]; + let contained = false; + for (let ii = 0; ii < this.bones.length; ii++) { + if (this.bones[ii] === bone) { + contained = true; + break; + } + } + if (!contained) this.bones.push(bone); + } + for (let i = 0; i < skin.constraints.length; i++) { + const constraint = skin.constraints[i]; + let contained = false; + for (let ii = 0; ii < this.constraints.length; ii++) { + if (this.constraints[ii] === constraint) { + contained = true; + break; + } + } + if (!contained) this.constraints.push(constraint); + } + const attachments = skin.getAttachments(); + for (let i = 0; i < attachments.length; i++) { + const attachment = attachments[i]; + if (!attachment.attachment) continue; + if (attachment.attachment instanceof MeshAttachment) { + attachment.attachment = attachment.attachment.newLinkedMesh(); + this.setAttachment(attachment.slotIndex, attachment.placeholder, attachment.attachment); + } else { + attachment.attachment = attachment.attachment.copy(); + this.setAttachment(attachment.slotIndex, attachment.placeholder, attachment.attachment); + } + } + } + /** Returns the attachment for the specified slot index and placeholder, or null. */ + getAttachment(slotIndex, placeholder) { + const dictionary = this.attachments[slotIndex]; + return dictionary ? dictionary[placeholder] : null; + } + /** Removes the attachment in the skin for the specified slot index and placeholder, if any. */ + removeAttachment(slotIndex, placeholder) { + const dictionary = this.attachments[slotIndex]; + if (dictionary) delete dictionary[placeholder]; + } + /** Returns all attachments in this skin. */ + getAttachments() { + const entries = []; + for (let i = 0; i < this.attachments.length; i++) { + const slotAttachments = this.attachments[i]; + if (slotAttachments) { + for (const name in slotAttachments) { + const attachment = slotAttachments[name]; + if (attachment) entries.push(new SkinEntry(i, name, attachment)); + } + } + } + return entries; + } + /** Returns all attachments in this skin for the specified slot index. */ + getAttachmentsForSlot(slotIndex, attachments) { + const slotAttachments = this.attachments[slotIndex]; + if (slotAttachments) { + for (const name in slotAttachments) { + const attachment = slotAttachments[name]; + if (attachment) attachments.push(new SkinEntry(slotIndex, name, attachment)); + } + } + } + /** Clears all attachments, bones, and constraints. */ + clear() { + this.attachments.length = 0; + this.bones.length = 0; + this.constraints.length = 0; + } + /** Attach each attachment in this skin if the corresponding attachment in the old skin is currently attached. */ + attachAll(skeleton, oldSkin) { + let slotIndex = 0; + for (let i = 0; i < skeleton.slots.length; i++) { + const slot = skeleton.slots[i]; + const slotAttachment = slot.pose.getAttachment(); + if (slotAttachment && slotIndex < oldSkin.attachments.length) { + const dictionary = oldSkin.attachments[slotIndex]; + for (const placeholder in dictionary) { + const skinAttachment = dictionary[placeholder]; + if (slotAttachment === skinAttachment) { + const attachment = this.getAttachment(slotIndex, placeholder); + if (attachment) slot.pose.setAttachment(attachment); + break; + } + } + } + slotIndex++; + } + } + }; + + // spine-core/src/SlotData.ts + var SlotData = class extends PosedData { + /** The index of the slot in {@link Skeleton.slots}. */ + index = 0; + /** The bone this slot belongs to. */ + boneData; + /** The name of the attachment that is visible for this slot in the setup pose, or null if no attachment is visible. */ + attachmentName = null; + /** The blend mode for drawing the slot's attachment. */ + blendMode = 0 /* Normal */; + // Nonessential. + /** False if the slot was hidden in Spine and nonessential data was exported. Does not affect runtime rendering. */ + visible = true; + constructor(index, name, boneData) { + super(name, new SlotPose()); + if (index < 0) throw new Error("index must be >= 0."); + if (!boneData) throw new Error("boneData cannot be null."); + this.index = index; + this.boneData = boneData; + } + }; + var BlendMode = /* @__PURE__ */ ((BlendMode2) => { + BlendMode2[BlendMode2["Normal"] = 0] = "Normal"; + BlendMode2[BlendMode2["Additive"] = 1] = "Additive"; + BlendMode2[BlendMode2["Multiply"] = 2] = "Multiply"; + BlendMode2[BlendMode2["Screen"] = 3] = "Screen"; + return BlendMode2; + })(BlendMode || {}); + + // spine-core/src/TransformConstraintPose.ts + var TransformConstraintPose = class { + /** A percentage (unbounded) that controls the mix between the constrained and unconstrained rotation. */ + mixRotate = 0; + /** A percentage (unbounded) that controls the mix between the constrained and unconstrained translation X. */ + mixX = 0; + /** A percentage (unbounded) that controls the mix between the constrained and unconstrained translation Y. */ + mixY = 0; + /** A percentage (unbounded) that controls the mix between the constrained and unconstrained scale X. */ + mixScaleX = 0; + /** A percentage (unbounded) that controls the mix between the constrained and unconstrained scale Y. */ + mixScaleY = 0; + /** A percentage (unbounded) that controls the mix between the constrained and unconstrained shear Y. */ + mixShearY = 0; + set(pose) { + this.mixRotate = pose.mixRotate; + this.mixX = pose.mixX; + this.mixY = pose.mixY; + this.mixScaleX = pose.mixScaleX; + this.mixScaleY = pose.mixScaleY; + this.mixShearY = pose.mixShearY; + } + }; + + // spine-core/src/TransformConstraint.ts + var TransformConstraint = class _TransformConstraint extends Constraint { + /** The bones that will be modified by this transform constraint. */ + bones; + /** The bone whose world transform will be copied to the constrained bones. */ + source; + constructor(data, skeleton) { + super(data, new TransformConstraintPose(), new TransformConstraintPose()); + if (!skeleton) throw new Error("skeleton cannot be null."); + this.bones = []; + for (const boneData of data.bones) + this.bones.push(skeleton.bones[boneData.index].constrainedPose); + const source = skeleton.bones[data.source.index]; + if (source == null) throw new Error("source cannot be null."); + this.source = source; + } + copy(skeleton) { + var copy = new _TransformConstraint(this.data, skeleton); + copy.pose.set(this.pose); + return copy; + } + update(skeleton, physics) { + const p = this.appliedPose; + if (p.mixRotate === 0 && p.mixX === 0 && p.mixY === 0 && p.mixScaleX === 0 && p.mixScaleY === 0 && p.mixShearY === 0) return; + const data = this.data; + const localSource = data.localSource, localTarget = data.localTarget, additive = data.additive, clamp = data.clamp; + const offsets = data.offsets; + const source = this.source.appliedPose; + if (localSource) source.validateLocalTransform(skeleton); + const fromItems = data.properties; + const fn = data.properties.length; + const bones = this.bones; + for (let i = 0, n = this.bones.length; i < n; i++) { + const bone = bones[i]; + if (localTarget) + bone.modifyLocal(skeleton); + else + bone.modifyWorld(skeleton); + for (let f = 0; f < fn; f++) { + const from = fromItems[f]; + const value = from.value(skeleton, source, localSource, offsets) - from.offset; + const toItems = from.to; + for (let t = 0, tn = from.to.length; t < tn; t++) { + const to = toItems[t]; + if (to.mix(p) !== 0) { + let clamped = to.offset + value * to.scale; + if (clamp) { + if (to.offset < to.max) + clamped = MathUtils.clamp(clamped, to.offset, to.max); + else + clamped = MathUtils.clamp(clamped, to.max, to.offset); + } + to.apply(skeleton, p, bone, clamped, localTarget, additive); + } + } + } + } + } + sort(skeleton) { + if (!this.data.localSource) skeleton.sortBone(this.source); + const bones = this.bones; + const boneCount = this.bones.length; + const worldTarget = !this.data.localTarget; + if (worldTarget) { + for (let i = 0; i < boneCount; i++) + skeleton.sortBone(bones[i].bone); + } + skeleton._updateCache.push(this); + for (let i = 0; i < boneCount; i++) { + const bone = bones[i].bone; + skeleton.sortReset(bone.children); + skeleton.constrained(bone); + } + for (let i = 0; i < boneCount; i++) + bones[i].bone.sorted = worldTarget; + } + isSourceActive() { + return this.source.active; + } + }; + + // spine-core/src/TransformConstraintData.ts + var TransformConstraintData = class _TransformConstraintData extends ConstraintData { + static ROTATION = 0; + static X = 1; + static Y = 2; + static SCALEX = 3; + static SCALEY = 4; + static SHEARY = 5; + /** The bones that will be modified by this transform constraint. */ + bones = []; + /** The bone whose world transform will be copied to the constrained bones. */ + set source(source) { + this._source = source; + } + get source() { + if (!this._source) throw new Error("BoneData not set."); + else return this._source; + } + _source = null; + offsets = [0, 0, 0, 0, 0, 0]; + /** An offset added to the constrained bone X translation. */ + offsetX = 0; + /** An offset added to the constrained bone Y translation. */ + offsetY = 0; + /** Reads the source bone's local transform instead of its world transform. */ + localSource = false; + /** Sets the constrained bones' local transforms instead of their world transforms. */ + localTarget = false; + /** Adds the source bone transform to the constrained bones instead of setting it absolutely. */ + additive = false; + /** Prevents constrained bones from exceeding the ranged defined by {@link ToProperty.offset} and {@link ToProperty.max}. */ + clamp = false; + /** The mapping of transform properties to other transform properties. */ + properties = []; + constructor(name) { + super(name, new TransformConstraintPose()); + } + create(skeleton) { + return new TransformConstraint(this, skeleton); + } + /** An offset added to the constrained bone rotation. */ + getOffsetRotation() { + return this.offsets[_TransformConstraintData.ROTATION]; + } + setOffsetRotation(offsetRotation) { + this.offsets[_TransformConstraintData.ROTATION] = offsetRotation; + } + /** An offset added to the constrained bone X translation. */ + getOffsetX() { + return this.offsets[_TransformConstraintData.X]; + } + setOffsetX(offsetX) { + this.offsets[_TransformConstraintData.X] = offsetX; + } + /** An offset added to the constrained bone Y translation. */ + getOffsetY() { + return this.offsets[_TransformConstraintData.Y]; + } + setOffsetY(offsetY) { + this.offsets[_TransformConstraintData.Y] = offsetY; + } + /** An offset added to the constrained bone scaleX. */ + getOffsetScaleX() { + return this.offsets[_TransformConstraintData.SCALEX]; + } + setOffsetScaleX(offsetScaleX) { + this.offsets[_TransformConstraintData.SCALEX] = offsetScaleX; + } + /** An offset added to the constrained bone scaleY. */ + getOffsetScaleY() { + return this.offsets[_TransformConstraintData.SCALEY]; + } + setOffsetScaleY(offsetScaleY) { + this.offsets[_TransformConstraintData.SCALEY] = offsetScaleY; + } + /** An offset added to the constrained bone shearY. */ + getOffsetShearY() { + return this.offsets[_TransformConstraintData.SHEARY]; + } + setOffsetShearY(offsetShearY) { + this.offsets[_TransformConstraintData.SHEARY] = offsetShearY; + } + }; + var FromProperty = class { + /** The value of this property that corresponds to {@link ToProperty.offset}. */ + offset = 0; + /** Constrained properties. */ + to = []; + }; + var ToProperty = class { + /** The value of this property that corresponds to {@link FromProperty.offset}. */ + offset = 0; + /** The maximum value of this property when {@link TransformConstraintData.clamp clamped}. */ + max = 0; + /** The scale of the {@link FromProperty} value in relation to this property. */ + scale = 0; + }; + var FromRotate = class extends FromProperty { + value(skeleton, source, local, offsets) { + if (local) return source.rotation + offsets[TransformConstraintData.ROTATION]; + const sx = skeleton.scaleX, sy = skeleton.scaleY; + let value = Math.atan2(source.c / sy, source.a / sx) * MathUtils.radDeg + ((source.a * source.d - source.b * source.c) * sx * sy > 0 ? offsets[TransformConstraintData.ROTATION] : -offsets[TransformConstraintData.ROTATION]); + if (value < 0) value += 360; + return value; + } + }; + var ToRotate = class extends ToProperty { + mix(pose) { + return pose.mixRotate; + } + apply(skeleton, pose, bone, value, local, additive) { + if (local) + bone.rotation += (additive ? value : value - bone.rotation) * pose.mixRotate; + else { + const sx = skeleton.scaleX, sy = skeleton.scaleY, ix = 1 / sx, iy = 1 / sy; + const a = bone.a * ix, b = bone.b * ix, c = bone.c * iy, d = bone.d * iy; + value *= MathUtils.degRad; + if (!additive) value -= Math.atan2(c, a); + if (value > MathUtils.PI) + value -= MathUtils.PI2; + else if (value < -MathUtils.PI) + value += MathUtils.PI2; + value *= pose.mixRotate; + const cos = Math.cos(value), sin = Math.sin(value); + bone.a = (cos * a - sin * c) * sx; + bone.b = (cos * b - sin * d) * sx; + bone.c = (sin * a + cos * c) * sy; + bone.d = (sin * b + cos * d) * sy; + } + } + }; + var FromX = class extends FromProperty { + value(skeleton, source, local, offsets) { + return local ? source.x + offsets[TransformConstraintData.X] : (offsets[TransformConstraintData.X] * source.a + offsets[TransformConstraintData.Y] * source.b + source.worldX) / skeleton.scaleX; + } + }; + var ToX = class extends ToProperty { + mix(pose) { + return pose.mixX; + } + apply(skeleton, pose, bone, value, local, additive) { + if (local) + bone.x += (additive ? value : value - bone.x) * pose.mixX; + else { + if (!additive) value -= bone.worldX / skeleton.scaleX; + bone.worldX += value * pose.mixX * skeleton.scaleX; + } + } + }; + var FromY = class extends FromProperty { + value(skeleton, source, local, offsets) { + return local ? source.y + offsets[TransformConstraintData.Y] : (offsets[TransformConstraintData.X] * source.c + offsets[TransformConstraintData.Y] * source.d + source.worldY) / skeleton.scaleY; + } + }; + var ToY = class extends ToProperty { + mix(pose) { + return pose.mixY; + } + apply(skeleton, pose, bone, value, local, additive) { + if (local) + bone.y += (additive ? value : value - bone.y) * pose.mixY; + else { + if (!additive) value -= bone.worldY / skeleton.scaleY; + bone.worldY += value * pose.mixY * skeleton.scaleY; + } + } + }; + var FromScaleX = class extends FromProperty { + value(skeleton, source, local, offsets) { + if (local) return source.scaleX + offsets[TransformConstraintData.SCALEX]; + const a = source.a / skeleton.scaleX, c = source.c / skeleton.scaleY; + return Math.sqrt(a * a + c * c) + offsets[TransformConstraintData.SCALEX]; + } + }; + var ToScaleX = class extends ToProperty { + mix(pose) { + return pose.mixScaleX; + } + apply(skeleton, pose, bone, value, local, additive) { + if (local) { + if (additive) + bone.scaleX *= 1 + (value - 1) * pose.mixScaleX; + else if (bone.scaleX !== 0) + bone.scaleX += (value - bone.scaleX) * pose.mixScaleX; + } else if (additive) { + const s = 1 + (value - 1) * pose.mixScaleX; + bone.a *= s; + bone.c *= s; + } else { + let a = bone.a / skeleton.scaleX, c = bone.c / skeleton.scaleY, s = Math.sqrt(a * a + c * c); + if (s !== 0) { + s = 1 + (value - s) * pose.mixScaleX / s; + bone.a *= s; + bone.c *= s; + } + } + } + }; + var FromScaleY = class extends FromProperty { + value(skeleton, source, local, offsets) { + if (local) return source.scaleY + offsets[TransformConstraintData.SCALEY]; + const b = source.b / skeleton.scaleX, d = source.d / skeleton.scaleY; + return Math.sqrt(b * b + d * d) + offsets[TransformConstraintData.SCALEY]; + } + }; + var ToScaleY = class extends ToProperty { + mix(pose) { + return pose.mixScaleY; + } + apply(skeleton, pose, bone, value, local, additive) { + if (local) { + if (additive) + bone.scaleY *= 1 + (value - 1) * pose.mixScaleY; + else if (bone.scaleY !== 0) + bone.scaleY += (value - bone.scaleY) * pose.mixScaleY; + } else if (additive) { + const s = 1 + (value - 1) * pose.mixScaleY; + bone.b *= s; + bone.d *= s; + } else { + let b = bone.b / skeleton.scaleX, d = bone.d / skeleton.scaleY, s = Math.sqrt(b * b + d * d); + if (s !== 0) { + s = 1 + (value - s) * pose.mixScaleY / s; + bone.b *= s; + bone.d *= s; + } + } + } + }; + var FromShearY = class extends FromProperty { + value(skeleton, source, local, offsets) { + if (local) return source.shearY + offsets[TransformConstraintData.SHEARY]; + const ix = 1 / skeleton.scaleX, iy = 1 / skeleton.scaleY; + return (Math.atan2(source.d * iy, source.b * ix) - Math.atan2(source.c * iy, source.a * ix)) * MathUtils.radDeg - 90 + offsets[TransformConstraintData.SHEARY]; + } + }; + var ToShearY = class extends ToProperty { + mix(pose) { + return pose.mixShearY; + } + apply(skeleton, pose, bone, value, local, additive) { + if (local) { + if (!additive) value -= bone.shearY; + bone.shearY += value * pose.mixShearY; + } else { + const sx = skeleton.scaleX, sy = skeleton.scaleY, b = bone.b / sx, d = bone.d / sy, by = Math.atan2(d, b); + value = (value + 90) * MathUtils.degRad; + if (additive) + value -= MathUtils.PI / 2; + else { + value -= by - Math.atan2(bone.c / sy, bone.a / sx); + if (value > MathUtils.PI) + value -= MathUtils.PI2; + else if (value < -MathUtils.PI) + value += MathUtils.PI2; + } + value = by + value * pose.mixShearY; + const s = Math.sqrt(b * b + d * d); + bone.b = Math.cos(value) * s * sx; + bone.d = Math.sin(value) * s * sy; + } + } + }; + + // spine-core/src/SkeletonBinary.ts + var SkeletonBinary = class { + /** Scales bone positions, image sizes, and translations as they are loaded. This allows different size images to be used at + * runtime than were used in Spine. + * + * See [Scaling](http://esotericsoftware.com/spine-loading-skeleton-data#Scaling) in the Spine Runtimes Guide. */ + scale = 1; + attachmentLoader; + linkedMeshes = []; + constructor(attachmentLoader) { + this.attachmentLoader = attachmentLoader; + } + readSkeletonData(binary) { + const scale = this.scale; + const skeletonData = new SkeletonData(); + skeletonData.name = ""; + const input = new BinaryInput(binary); + const lowHash = input.readInt32(); + const highHash = input.readInt32(); + skeletonData.hash = highHash === 0 && lowHash === 0 ? null : highHash.toString(16) + lowHash.toString(16); + skeletonData.version = input.readString(); + skeletonData.x = input.readFloat(); + skeletonData.y = input.readFloat(); + skeletonData.width = input.readFloat(); + skeletonData.height = input.readFloat(); + skeletonData.referenceScale = input.readFloat() * scale; + const nonessential = input.readBoolean(); + if (nonessential) { + skeletonData.fps = input.readFloat(); + skeletonData.imagesPath = input.readString(); + skeletonData.audioPath = input.readString(); + } + let n = 0; + n = input.readInt(true); + for (let i = 0; i < n; i++) { + const str = input.readString(); + if (!str) throw new Error("String in string table must not be null."); + input.strings.push(str); + } + const bones = skeletonData.bones; + n = input.readInt(true); + for (let i = 0; i < n; i++) { + const name = input.readString(); + if (!name) throw new Error("Bone name must not be null."); + const parent = i === 0 ? null : bones[input.readInt(true)]; + const data = new BoneData(i, name, parent); + const setup = data.setupPose; + setup.rotation = input.readFloat(); + setup.x = input.readFloat() * scale; + setup.y = input.readFloat() * scale; + setup.scaleX = input.readFloat(); + setup.scaleY = input.readFloat(); + setup.shearX = input.readFloat(); + setup.shearY = input.readFloat(); + setup.inherit = input.readByte(); + data.length = input.readFloat() * scale; + data.skinRequired = input.readBoolean(); + if (nonessential) { + Color.rgba8888ToColor(data.color, input.readInt32()); + data.icon = input.readString() ?? void 0; + data.iconSize = input.readFloat(); + data.iconRotation = input.readFloat(); + data.visible = input.readBoolean(); + } + bones.push(data); + } + n = input.readInt(true); + for (let i = 0; i < n; i++) { + const slotName = input.readString(); + if (!slotName) throw new Error("Slot name must not be null."); + const boneData = bones[input.readInt(true)]; + const data = new SlotData(i, slotName, boneData); + Color.rgba8888ToColor(data.setupPose.color, input.readInt32()); + const darkColor = input.readInt32(); + if (darkColor !== -1) Color.rgb888ToColor(data.setupPose.darkColor = new Color(), darkColor); + data.attachmentName = input.readStringRef(); + data.blendMode = input.readInt(true); + if (nonessential) data.visible = input.readBoolean(); + skeletonData.slots.push(data); + } + const constraints = skeletonData.constraints; + const constraintCount = input.readInt(true); + for (let i = 0; i < constraintCount; i++) { + const name = input.readString(); + if (!name) throw new Error("Constraint data name must not be null."); + let nn; + switch (input.readByte()) { + case CONSTRAINT_IK: { + const data = new IkConstraintData(name); + nn = input.readInt(true); + for (let ii = 0; ii < nn; ii++) + data.bones.push(bones[input.readInt(true)]); + data.target = bones[input.readInt(true)]; + const flags = input.readByte(); + data.skinRequired = (flags & 1) !== 0; + if ((flags & 2) !== 0) data.scaleYMode = input.readUnsignedByte(); + const setup = data.setupPose; + setup.bendDirection = (flags & 4) !== 0 ? -1 : 1; + setup.compress = (flags & 8) !== 0; + setup.stretch = (flags & 16) !== 0; + if ((flags & 32) !== 0) setup.mix = (flags & 64) !== 0 ? input.readFloat() : 1; + if ((flags & 128) !== 0) setup.softness = input.readFloat() * scale; + constraints.push(data); + break; + } + case CONSTRAINT_TRANSFORM: { + const data = new TransformConstraintData(name); + nn = input.readInt(true); + for (let ii = 0; ii < nn; ii++) + data.bones.push(bones[input.readInt(true)]); + data.source = bones[input.readInt(true)]; + let flags = input.readUnsignedByte(); + data.skinRequired = (flags & 1) !== 0; + data.localSource = (flags & 2) !== 0; + data.localTarget = (flags & 4) !== 0; + data.additive = (flags & 8) !== 0; + data.clamp = (flags & 16) !== 0; + nn = flags >> 5; + for (let ii = 0, tn; ii < nn; ii++) { + let fromScale = 1; + let from; + switch (input.readByte()) { + case 0: + from = new FromRotate(); + break; + case 1: { + fromScale = scale; + from = new FromX(); + break; + } + case 2: { + fromScale = scale; + from = new FromY(); + break; + } + case 3: + from = new FromScaleX(); + break; + case 4: + from = new FromScaleY(); + break; + case 5: + from = new FromShearY(); + break; + default: + from = null; + } + if (!from) continue; + from.offset = input.readFloat() * fromScale; + tn = input.readByte(); + for (let t = 0; t < tn; t++) { + let toScale = 1; + let to; + switch (input.readByte()) { + case 0: + to = new ToRotate(); + break; + case 1: { + toScale = scale; + to = new ToX(); + break; + } + case 2: { + toScale = scale; + to = new ToY(); + break; + } + case 3: + to = new ToScaleX(); + break; + case 4: + to = new ToScaleY(); + break; + case 5: + to = new ToShearY(); + break; + default: + to = null; + } + if (!to) continue; + to.offset = input.readFloat() * toScale; + to.max = input.readFloat() * toScale; + to.scale = input.readFloat() * toScale / fromScale; + from.to[t] = to; + } + data.properties[ii] = from; + } + flags = input.readByte(); + if ((flags & 1) !== 0) data.offsets[TransformConstraintData.ROTATION] = input.readFloat(); + if ((flags & 2) !== 0) data.offsets[TransformConstraintData.X] = input.readFloat() * scale; + if ((flags & 4) !== 0) data.offsets[TransformConstraintData.Y] = input.readFloat() * scale; + if ((flags & 8) !== 0) data.offsets[TransformConstraintData.SCALEX] = input.readFloat(); + if ((flags & 16) !== 0) data.offsets[TransformConstraintData.SCALEY] = input.readFloat(); + if ((flags & 32) !== 0) data.offsets[TransformConstraintData.SHEARY] = input.readFloat(); + flags = input.readByte(); + const setup = data.setupPose; + if ((flags & 1) !== 0) setup.mixRotate = input.readFloat(); + if ((flags & 2) !== 0) setup.mixX = input.readFloat(); + if ((flags & 4) !== 0) setup.mixY = input.readFloat(); + if ((flags & 8) !== 0) setup.mixScaleX = input.readFloat(); + if ((flags & 16) !== 0) setup.mixScaleY = input.readFloat(); + if ((flags & 32) !== 0) setup.mixShearY = input.readFloat(); + constraints.push(data); + break; + } + case CONSTRAINT_PATH: { + const data = new PathConstraintData(name); + nn = input.readInt(true); + for (let ii = 0; ii < nn; ii++) + data.bones.push(bones[input.readInt(true)]); + data.slot = skeletonData.slots[input.readInt(true)]; + const flags = input.readByte(); + data.skinRequired = (flags & 1) !== 0; + data.positionMode = flags >> 1 & 1; + data.spacingMode = flags >> 2 & 3; + data.rotateMode = flags >> 4 & 3; + if ((flags & 128) !== 0) data.offsetRotation = input.readFloat(); + const setup = data.setupPose; + setup.position = input.readFloat(); + if (data.positionMode === 0 /* Fixed */) setup.position *= scale; + setup.spacing = input.readFloat(); + if (data.spacingMode === 0 /* Length */ || data.spacingMode === 1 /* Fixed */) setup.spacing *= scale; + setup.mixRotate = input.readFloat(); + setup.mixX = input.readFloat(); + setup.mixY = input.readFloat(); + constraints.push(data); + break; + } + case CONSTRAINT_PHYSICS: { + const data = new PhysicsConstraintData(name); + data.bone = bones[input.readInt(true)]; + let flags = input.readByte(); + data.skinRequired = (flags & 1) !== 0; + if ((flags & 2) !== 0) data.x = input.readFloat(); + if ((flags & 4) !== 0) data.y = input.readFloat(); + if ((flags & 8) !== 0) data.rotate = input.readFloat(); + if ((flags & 16) !== 0) { + let scaleX = input.readFloat(); + if (scaleX < -2) { + data.scaleYMode = 2 /* Volume */; + scaleX = -2 - scaleX; + } else if (scaleX < 0) { + data.scaleYMode = 1 /* Uniform */; + scaleX = -1 - scaleX; + } + data.scaleX = scaleX; + } + if ((flags & 32) !== 0) data.shearX = input.readFloat(); + data.limit = ((flags & 64) !== 0 ? input.readFloat() : 5e3) * scale; + data.step = 1 / input.readUnsignedByte(); + const setup = data.setupPose; + setup.inertia = input.readFloat(); + setup.strength = input.readFloat(); + setup.damping = input.readFloat(); + setup.massInverse = (flags & 128) !== 0 ? input.readFloat() : 1; + setup.wind = input.readFloat(); + setup.gravity = input.readFloat(); + flags = input.readByte(); + if ((flags & 1) !== 0) data.inertiaGlobal = true; + if ((flags & 2) !== 0) data.strengthGlobal = true; + if ((flags & 4) !== 0) data.dampingGlobal = true; + if ((flags & 8) !== 0) data.massGlobal = true; + if ((flags & 16) !== 0) data.windGlobal = true; + if ((flags & 32) !== 0) data.gravityGlobal = true; + if ((flags & 64) !== 0) data.mixGlobal = true; + setup.mix = (flags & 128) !== 0 ? input.readFloat() : 1; + constraints.push(data); + break; + } + case CONSTRAINT_SLIDER: { + const data = new SliderData(name); + const flags = input.readByte(); + data.skinRequired = (flags & 1) !== 0; + data.loop = (flags & 2) !== 0; + data.additive = (flags & 4) !== 0; + if ((flags & 8) !== 0) { + const value = input.readFloat(); + if (nonessential && (flags & 64) !== 0) + data.max = value; + else + data.setupPose.time = value; + } + if ((flags & 16) !== 0) data.setupPose.mix = (flags & 32) !== 0 ? input.readFloat() : 1; + if ((flags & 64) !== 0) { + data.local = (flags & 128) !== 0; + data.bone = bones[input.readInt(true)]; + const offset = input.readFloat(); + let propertyScale = 1; + switch (input.readByte()) { + case 0: + data.property = new FromRotate(); + break; + case 1: { + propertyScale = scale; + data.property = new FromX(); + break; + } + case 2: { + propertyScale = scale; + data.property = new FromY(); + break; + } + case 3: + data.property = new FromScaleX(); + break; + case 4: + data.property = new FromScaleY(); + break; + case 5: + data.property = new FromShearY(); + break; + default: + continue; + } + ; + data.property.offset = offset * propertyScale; + data.offset = input.readFloat(); + data.scale = input.readFloat() / propertyScale; + } + constraints.push(data); + break; + } + } + } + const defaultSkin = this.readSkin(input, skeletonData, true, nonessential); + if (defaultSkin) { + skeletonData.defaultSkin = defaultSkin; + skeletonData.skins.push(defaultSkin); + } + { + let i = skeletonData.skins.length; + Utils.setArraySize(skeletonData.skins, n = i + input.readInt(true)); + for (; i < n; i++) { + const skin = this.readSkin(input, skeletonData, false, nonessential); + if (!skin) throw new Error("readSkin() should not have returned null."); + skeletonData.skins[i] = skin; + } + } + n = this.linkedMeshes.length; + for (let i = 0; i < n; i++) { + const linkedMesh = this.linkedMeshes[i]; + const skin = skeletonData.skins[linkedMesh.skinIndex]; + if (!linkedMesh.source) throw new Error("Linked mesh parent must not be null"); + const source = skin.getAttachment(linkedMesh.sourceIndex, linkedMesh.source); + if (!source) throw new Error(`Source mesh not found: ${linkedMesh.source}`); + linkedMesh.mesh.timelineAttachment = linkedMesh.inheritTimelines ? source : linkedMesh.mesh; + linkedMesh.mesh.setSourceMesh(source); + linkedMesh.mesh.updateSequence(); + } + this.linkedMeshes.length = 0; + n = input.readInt(true); + for (let i = 0; i < n; i++) { + const eventName = input.readString(); + if (!eventName) throw new Error("Event data name must not be null"); + const data = new EventData(eventName); + const setup = data.setupPose; + setup.intValue = input.readInt(false); + setup.floatValue = input.readFloat(); + setup.stringValue = input.readString(); + data._audioPath = input.readString(); + if (data.audioPath) { + setup.volume = input.readFloat(); + setup.balance = input.readFloat(); + } + skeletonData.events.push(data); + } + const animations = skeletonData.animations; + n = input.readInt(true); + for (let i = 0; i < n; i++) { + const animationName = input.readString(); + if (!animationName) throw new Error("Animation name must not be null."); + animations.push(this.readAnimation(input, animationName, skeletonData, nonessential)); + } + for (let i = 0; i < constraintCount; i++) { + const constraint = constraints[i]; + if (constraint instanceof SliderData) constraint.animation = animations[input.readInt(true)]; + } + return skeletonData; + } + readSkin(input, skeletonData, defaultSkin, nonessential) { + let skin = null; + let slotCount = 0; + if (defaultSkin) { + slotCount = input.readInt(true); + if (slotCount === 0) return null; + skin = new Skin("default"); + } else { + const skinName = input.readString(); + if (!skinName) throw new Error("Skin name must not be null."); + skin = new Skin(skinName); + if (nonessential) Color.rgba8888ToColor(skin.color, input.readInt32()); + let n = input.readInt(true); + let from = skeletonData.bones, to = skin.bones; + for (let i = 0; i < n; i++) + to[i] = from[input.readInt(true)]; + n = input.readInt(true); + from = skeletonData.constraints; + to = skin.constraints; + for (let i = 0; i < n; i++) + to[i] = from[input.readInt(true)]; + slotCount = input.readInt(true); + } + for (let i = 0; i < slotCount; i++) { + const slotIndex = input.readInt(true); + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + const placeholder = input.readStringRef(); + if (!placeholder) + throw new Error("Attachment name must not be null"); + const attachment = this.readAttachment(input, skeletonData, skin, slotIndex, placeholder, nonessential); + if (attachment) skin.setAttachment(slotIndex, placeholder, attachment); + } + } + return skin; + } + readAttachment(input, skeletonData, skin, slotIndex, placeholder, nonessential) { + const scale = this.scale; + const flags = input.readByte(); + const name = (flags & 8) !== 0 ? input.readStringRef() : placeholder; + if (!name) throw new Error("Attachment name must not be null"); + switch (flags & 7) { + // BUG? + case 0 /* Region */: { + let path = (flags & 16) !== 0 ? input.readStringRef() : null; + const color = (flags & 32) !== 0 ? input.readInt32() : 4294967295; + const sequence = this.readSequence(input, (flags & 64) !== 0); + const rotation = (flags & 128) !== 0 ? input.readFloat() : 0; + const x = input.readFloat(); + const y = input.readFloat(); + const scaleX = input.readFloat(); + const scaleY = input.readFloat(); + const width = input.readFloat(); + const height = input.readFloat(); + if (!path) path = name; + const region = this.attachmentLoader.newRegionAttachment(skin, placeholder, name, path, sequence); + if (!region) return null; + region.path = path; + region.x = x * scale; + region.y = y * scale; + region.scaleX = scaleX; + region.scaleY = scaleY; + region.rotation = rotation; + region.width = width * scale; + region.height = height * scale; + Color.rgba8888ToColor(region.color, color); + region.updateSequence(); + return region; + } + case 1 /* BoundingBox */: { + const vertices = this.readVertices(input, (flags & 16) !== 0); + const color = nonessential ? input.readInt32() : 0; + const box = this.attachmentLoader.newBoundingBoxAttachment(skin, placeholder, name); + if (!box) return null; + box.worldVerticesLength = vertices.length; + box.vertices = vertices.vertices; + box.bones = vertices.bones; + if (nonessential) Color.rgba8888ToColor(box.color, color); + return box; + } + case 2 /* Mesh */: { + let path = (flags & 16) !== 0 ? input.readStringRef() : name; + const color = (flags & 32) !== 0 ? input.readInt32() : 4294967295; + const sequence = this.readSequence(input, (flags & 64) !== 0); + const hullLength = input.readInt(true); + const vertices = this.readVertices(input, (flags & 128) !== 0); + const uvs = this.readFloatArray(input, vertices.length, 1); + const triangles = this.readShortArray(input, (vertices.length - hullLength - 2) * 3); + const slotCount = input.readInt(true); + let timelineSlots = null; + if (slotCount > 0) { + timelineSlots = []; + for (let i = 0; i < slotCount; i++) + timelineSlots[i] = input.readInt(true); + } + let edges = []; + let width = 0, height = 0; + if (nonessential) { + edges = this.readShortArray(input, input.readInt(true)); + width = input.readFloat(); + height = input.readFloat(); + } + if (!path) path = name; + const mesh = this.attachmentLoader.newMeshAttachment(skin, placeholder, name, path, sequence); + if (!mesh) return null; + mesh.path = path; + Color.rgba8888ToColor(mesh.color, color); + mesh.hullLength = hullLength << 1; + mesh.bones = vertices.bones; + mesh.vertices = vertices.vertices; + mesh.worldVerticesLength = vertices.length; + mesh.regionUVs = uvs; + mesh.triangles = triangles; + if (timelineSlots) mesh.timelineSlots = timelineSlots; + if (nonessential) { + mesh.edges = edges; + mesh.width = width * scale; + mesh.height = height * scale; + } + mesh.updateSequence(); + return mesh; + } + case 3 /* LinkedMesh */: { + const path = (flags & 16) !== 0 ? input.readStringRef() : name; + if (path == null) throw new Error("Path of linked mesh must not be null"); + const color = (flags & 32) !== 0 ? input.readInt32() : 4294967295; + const sequence = this.readSequence(input, (flags & 64) !== 0); + const inheritTimelines = (flags & 128) !== 0; + const sourceIndex = input.readInt(true); + const skinIndex = input.readInt(true); + const source = input.readStringRef(); + let width = 0, height = 0; + if (nonessential) { + width = input.readFloat(); + height = input.readFloat(); + } + const mesh = this.attachmentLoader.newMeshAttachment(skin, placeholder, name, path, sequence); + if (!mesh) return null; + mesh.path = path; + Color.rgba8888ToColor(mesh.color, color); + if (nonessential) { + mesh.width = width * scale; + mesh.height = height * scale; + } + this.linkedMeshes.push(new LinkedMesh(mesh, skinIndex, slotIndex, sourceIndex, source, inheritTimelines)); + return mesh; + } + case 4 /* Path */: { + const closed = (flags & 16) !== 0; + const constantSpeed = (flags & 32) !== 0; + const vertices = this.readVertices(input, (flags & 64) !== 0); + const lengths = this.readFloatArray(input, vertices.length / 6, scale); + const color = nonessential ? input.readInt32() : 0; + const path = this.attachmentLoader.newPathAttachment(skin, placeholder, name); + if (!path) return null; + path.closed = closed; + path.constantSpeed = constantSpeed; + path.worldVerticesLength = vertices.length; + path.vertices = vertices.vertices; + path.bones = vertices.bones; + path.lengths = lengths; + if (nonessential) Color.rgba8888ToColor(path.color, color); + return path; + } + case 5 /* Point */: { + const rotation = input.readFloat(); + const x = input.readFloat(); + const y = input.readFloat(); + const color = nonessential ? input.readInt32() : 0; + const point = this.attachmentLoader.newPointAttachment(skin, placeholder, name); + if (!point) return null; + point.x = x * scale; + point.y = y * scale; + point.rotation = rotation; + if (nonessential) Color.rgba8888ToColor(point.color, color); + return point; + } + case 6 /* Clipping */: { + const endSlotIndex = input.readInt(true); + const vertices = this.readVertices(input, (flags & 16) !== 0); + const color = nonessential ? input.readInt32() : 0; + const clip = this.attachmentLoader.newClippingAttachment(skin, placeholder, name); + if (!clip) return null; + clip.endSlot = skeletonData.slots[endSlotIndex]; + clip.convex = (flags & 32) !== 0; + clip.inverse = (flags & 64) !== 0; + clip.worldVerticesLength = vertices.length; + clip.vertices = vertices.vertices; + clip.bones = vertices.bones; + if (nonessential) Color.rgba8888ToColor(clip.color, color); + return clip; + } + } + } + readSequence(input, hasPathSuffix) { + if (!hasPathSuffix) return new Sequence(1, false); + const sequence = new Sequence(input.readInt(true), true); + sequence.start = input.readInt(true); + sequence.digits = input.readInt(true); + sequence.setupIndex = input.readInt(true); + return sequence; + } + readVertices(input, weighted) { + const scale = this.scale; + const vertexCount = input.readInt(true); + const length = vertexCount << 1; + if (!weighted) + return new Vertices(null, this.readFloatArray(input, length, scale), length); + const n = input.readInt(true); + const bones = []; + const weights = []; + for (let b = 0, w = 0; b < n; ) { + const boneCount = input.readInt(true); + bones[b++] = boneCount; + for (let ii = 0; ii < boneCount; ii++, w += 3) { + bones[b++] = input.readInt(true); + weights[w] = input.readFloat() * scale; + weights[w + 1] = input.readFloat() * scale; + weights[w + 2] = input.readFloat(); + } + } + return new Vertices(bones, Utils.toFloatArray(weights), length); + } + readFloatArray(input, n, scale) { + const array = []; + if (scale === 1) { + for (let i = 0; i < n; i++) + array[i] = input.readFloat(); + } else { + for (let i = 0; i < n; i++) + array[i] = input.readFloat() * scale; + } + return array; + } + readShortArray(input, n) { + const array = []; + for (let i = 0; i < n; i++) + array[i] = input.readInt(true); + return array; + } + readAnimation(input, name, skeletonData, nonessential) { + input.readInt(true); + const timelines = []; + const scale = this.scale; + for (let i = 0, n = input.readInt(true); i < n; i++) { + const slotIndex = input.readInt(true); + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + const timelineType = input.readByte(); + const frameCount = input.readInt(true); + const frameLast = frameCount - 1; + switch (timelineType) { + case SLOT_ATTACHMENT: { + const timeline = new AttachmentTimeline(frameCount, slotIndex); + for (let frame = 0; frame < frameCount; frame++) + timeline.setFrame(frame, input.readFloat(), input.readStringRef()); + timelines.push(timeline); + break; + } + case SLOT_RGBA: { + const bezierCount = input.readInt(true); + const timeline = new RGBATimeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + let a = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b, a); + if (frame === frameLast) break; + const time2 = input.readFloat(); + const r2 = input.readUnsignedByte() / 255; + const g2 = input.readUnsignedByte() / 255; + const b2 = input.readUnsignedByte() / 255; + const a2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, r2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, g2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, b2, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, a, a2, 1); + } + time = time2; + r = r2; + g = g2; + b = b2; + a = a2; + } + timelines.push(timeline); + break; + } + case SLOT_RGB: { + const bezierCount = input.readInt(true); + const timeline = new RGBTimeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b); + if (frame === frameLast) break; + const time2 = input.readFloat(); + const r2 = input.readUnsignedByte() / 255; + const g2 = input.readUnsignedByte() / 255; + const b2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, r2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, g2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, b2, 1); + } + time = time2; + r = r2; + g = g2; + b = b2; + } + timelines.push(timeline); + break; + } + case SLOT_RGBA2: { + const bezierCount = input.readInt(true); + const timeline = new RGBA2Timeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + let a = input.readUnsignedByte() / 255; + let r2 = input.readUnsignedByte() / 255; + let g2 = input.readUnsignedByte() / 255; + let b2 = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b, a, r2, g2, b2); + if (frame === frameLast) break; + const time2 = input.readFloat(); + const nr = input.readUnsignedByte() / 255; + const ng = input.readUnsignedByte() / 255; + const nb = input.readUnsignedByte() / 255; + const na = input.readUnsignedByte() / 255; + const nr2 = input.readUnsignedByte() / 255; + const ng2 = input.readUnsignedByte() / 255; + const nb2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, nr, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, ng, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, nb, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, a, na, 1); + setBezier(input, timeline, bezier++, frame, 4, time, time2, r2, nr2, 1); + setBezier(input, timeline, bezier++, frame, 5, time, time2, g2, ng2, 1); + setBezier(input, timeline, bezier++, frame, 6, time, time2, b2, nb2, 1); + } + time = time2; + r = nr; + g = ng; + b = nb; + a = na; + r2 = nr2; + g2 = ng2; + b2 = nb2; + } + timelines.push(timeline); + break; + } + case SLOT_RGB2: { + const bezierCount = input.readInt(true); + const timeline = new RGB2Timeline(frameCount, bezierCount, slotIndex); + let time = input.readFloat(); + let r = input.readUnsignedByte() / 255; + let g = input.readUnsignedByte() / 255; + let b = input.readUnsignedByte() / 255; + let r2 = input.readUnsignedByte() / 255; + let g2 = input.readUnsignedByte() / 255; + let b2 = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, r, g, b, r2, g2, b2); + if (frame === frameLast) break; + const time2 = input.readFloat(); + const nr = input.readUnsignedByte() / 255; + const ng = input.readUnsignedByte() / 255; + const nb = input.readUnsignedByte() / 255; + const nr2 = input.readUnsignedByte() / 255; + const ng2 = input.readUnsignedByte() / 255; + const nb2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, r, nr, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, g, ng, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, b, nb, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, r2, nr2, 1); + setBezier(input, timeline, bezier++, frame, 4, time, time2, g2, ng2, 1); + setBezier(input, timeline, bezier++, frame, 5, time, time2, b2, nb2, 1); + } + time = time2; + r = nr; + g = ng; + b = nb; + r2 = nr2; + g2 = ng2; + b2 = nb2; + } + timelines.push(timeline); + break; + } + case SLOT_ALPHA: { + const timeline = new AlphaTimeline(frameCount, input.readInt(true), slotIndex); + let time = input.readFloat(), a = input.readUnsignedByte() / 255; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, a); + if (frame === frameLast) break; + const time2 = input.readFloat(); + const a2 = input.readUnsignedByte() / 255; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, a, a2, 1); + } + time = time2; + a = a2; + } + timelines.push(timeline); + } + } + } + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + const boneIndex = input.readInt(true); + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + const type = input.readByte(), frameCount = input.readInt(true); + if (type === BONE_INHERIT) { + const timeline = new InheritTimeline(frameCount, boneIndex); + for (let frame = 0; frame < frameCount; frame++) { + timeline.setFrame(frame, input.readFloat(), input.readByte()); + } + timelines.push(timeline); + continue; + } + const bezierCount = input.readInt(true); + switch (type) { + case BONE_ROTATE: + readTimeline(input, timelines, new RotateTimeline(frameCount, bezierCount, boneIndex), 1); + break; + case BONE_TRANSLATE: + readTimeline(input, timelines, new TranslateTimeline(frameCount, bezierCount, boneIndex), scale); + break; + case BONE_TRANSLATEX: + readTimeline(input, timelines, new TranslateXTimeline(frameCount, bezierCount, boneIndex), scale); + break; + case BONE_TRANSLATEY: + readTimeline(input, timelines, new TranslateYTimeline(frameCount, bezierCount, boneIndex), scale); + break; + case BONE_SCALE: + readTimeline(input, timelines, new ScaleTimeline(frameCount, bezierCount, boneIndex), 1); + break; + case BONE_SCALEX: + readTimeline(input, timelines, new ScaleXTimeline(frameCount, bezierCount, boneIndex), 1); + break; + case BONE_SCALEY: + readTimeline(input, timelines, new ScaleYTimeline(frameCount, bezierCount, boneIndex), 1); + break; + case BONE_SHEAR: + readTimeline(input, timelines, new ShearTimeline(frameCount, bezierCount, boneIndex), 1); + break; + case BONE_SHEARX: + readTimeline(input, timelines, new ShearXTimeline(frameCount, bezierCount, boneIndex), 1); + break; + case BONE_SHEARY: + readTimeline(input, timelines, new ShearYTimeline(frameCount, bezierCount, boneIndex), 1); + break; + } + } + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + const index = input.readInt(true), frameCount = input.readInt(true), frameLast = frameCount - 1; + const timeline = new IkConstraintTimeline(frameCount, input.readInt(true), index); + let flags = input.readByte(); + let time = input.readFloat(), mix = (flags & 1) !== 0 ? (flags & 2) !== 0 ? input.readFloat() : 1 : 0; + let softness = (flags & 4) !== 0 ? input.readFloat() * scale : 0; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mix, softness, (flags & 8) !== 0 ? 1 : -1, (flags & 16) !== 0, (flags & 32) !== 0); + if (frame === frameLast) break; + flags = input.readByte(); + const time2 = input.readFloat(), mix2 = (flags & 1) !== 0 ? (flags & 2) !== 0 ? input.readFloat() : 1 : 0; + const softness2 = (flags & 4) !== 0 ? input.readFloat() * scale : 0; + if ((flags & 64) !== 0) { + timeline.setStepped(frame); + } else if ((flags & 128) !== 0) { + setBezier(input, timeline, bezier++, frame, 0, time, time2, mix, mix2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, softness, softness2, scale); + } + time = time2; + mix = mix2; + softness = softness2; + } + timelines.push(timeline); + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + const index = input.readInt(true), frameCount = input.readInt(true), frameLast = frameCount - 1; + const timeline = new TransformConstraintTimeline(frameCount, input.readInt(true), index); + let time = input.readFloat(), mixRotate = input.readFloat(), mixX = input.readFloat(), mixY = input.readFloat(), mixScaleX = input.readFloat(), mixScaleY = input.readFloat(), mixShearY = input.readFloat(); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY); + if (frame === frameLast) break; + const time2 = input.readFloat(), mixRotate2 = input.readFloat(), mixX2 = input.readFloat(), mixY2 = input.readFloat(), mixScaleX2 = input.readFloat(), mixScaleY2 = input.readFloat(), mixShearY2 = input.readFloat(); + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, mixY, mixY2, 1); + setBezier(input, timeline, bezier++, frame, 3, time, time2, mixScaleX, mixScaleX2, 1); + setBezier(input, timeline, bezier++, frame, 4, time, time2, mixScaleY, mixScaleY2, 1); + setBezier(input, timeline, bezier++, frame, 5, time, time2, mixShearY, mixShearY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + mixScaleX = mixScaleX2; + mixScaleY = mixScaleY2; + mixShearY = mixShearY2; + } + timelines.push(timeline); + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + const index = input.readInt(true); + const data = skeletonData.constraints[index]; + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + const type = input.readByte(), frameCount = input.readInt(true), bezierCount = input.readInt(true); + switch (type) { + case PATH_POSITION: + readTimeline( + input, + timelines, + new PathConstraintPositionTimeline(frameCount, bezierCount, index), + data.positionMode === 0 /* Fixed */ ? scale : 1 + ); + break; + case PATH_SPACING: + readTimeline( + input, + timelines, + new PathConstraintSpacingTimeline(frameCount, bezierCount, index), + data.spacingMode === 0 /* Length */ || data.spacingMode === 1 /* Fixed */ ? scale : 1 + ); + break; + case PATH_MIX: { + const timeline = new PathConstraintMixTimeline(frameCount, bezierCount, index); + let time = input.readFloat(), mixRotate = input.readFloat(), mixX = input.readFloat(), mixY = input.readFloat(); + for (let frame = 0, bezier = 0, frameLast = timeline.getFrameCount() - 1; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY); + if (frame === frameLast) break; + const time2 = input.readFloat(), mixRotate2 = input.readFloat(), mixX2 = input.readFloat(), mixY2 = input.readFloat(); + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1); + setBezier(input, timeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1); + setBezier(input, timeline, bezier++, frame, 2, time, time2, mixY, mixY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + } + timelines.push(timeline); + } + } + } + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + const index = input.readInt(true) - 1; + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + const type = input.readByte(), frameCount = input.readInt(true); + if (type === PHYSICS_RESET) { + const timeline = new PhysicsConstraintResetTimeline(frameCount, index); + for (let frame = 0; frame < frameCount; frame++) + timeline.setFrame(frame, input.readFloat()); + timelines.push(timeline); + continue; + } + const bezierCount = input.readInt(true); + switch (type) { + case PHYSICS_INERTIA: + readTimeline(input, timelines, new PhysicsConstraintInertiaTimeline(frameCount, bezierCount, index), 1); + break; + case PHYSICS_STRENGTH: + readTimeline(input, timelines, new PhysicsConstraintStrengthTimeline(frameCount, bezierCount, index), 1); + break; + case PHYSICS_DAMPING: + readTimeline(input, timelines, new PhysicsConstraintDampingTimeline(frameCount, bezierCount, index), 1); + break; + case PHYSICS_MASS: + readTimeline(input, timelines, new PhysicsConstraintMassTimeline(frameCount, bezierCount, index), 1); + break; + case PHYSICS_WIND: + readTimeline(input, timelines, new PhysicsConstraintWindTimeline(frameCount, bezierCount, index), 1); + break; + case PHYSICS_GRAVITY: + readTimeline(input, timelines, new PhysicsConstraintGravityTimeline(frameCount, bezierCount, index), 1); + break; + case PHYSICS_MIX: + readTimeline(input, timelines, new PhysicsConstraintMixTimeline(frameCount, bezierCount, index), 1); + break; + default: + throw new Error("Unknown physics timeline type."); + } + } + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + const index = input.readInt(true); + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + const type = input.readByte(), frameCount = input.readInt(true), bezierCount = input.readInt(true); + switch (type) { + case SLIDER_TIME: + readTimeline(input, timelines, new SliderTimeline(frameCount, bezierCount, index), 1); + break; + case SLIDER_MIX: + readTimeline(input, timelines, new SliderMixTimeline(frameCount, bezierCount, index), 1); + break; + default: + throw new Error(`Uknown slider type: ${type}`); + } + } + } + for (let i = 0, n = input.readInt(true); i < n; i++) { + const skin = skeletonData.skins[input.readInt(true)]; + for (let ii = 0, nn = input.readInt(true); ii < nn; ii++) { + const slotIndex = input.readInt(true); + for (let iii = 0, nnn = input.readInt(true); iii < nnn; iii++) { + const attachmentName = input.readStringRef(); + if (!attachmentName) throw new Error("attachmentName must not be null."); + const attachment = skin.getAttachment(slotIndex, attachmentName); + const timelineType = input.readByte(); + const frameCount = input.readInt(true); + const frameLast = frameCount - 1; + switch (timelineType) { + case ATTACHMENT_DEFORM: { + const vertexAttachment = attachment; + const weighted = vertexAttachment.bones; + const vertices = vertexAttachment.vertices; + const deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + const bezierCount = input.readInt(true); + const timeline = new DeformTimeline(frameCount, bezierCount, slotIndex, vertexAttachment); + let time = input.readFloat(); + for (let frame = 0, bezier = 0; ; frame++) { + let deform; + let end = input.readInt(true); + if (end === 0) + deform = weighted ? Utils.newFloatArray(deformLength) : vertices; + else { + deform = Utils.newFloatArray(deformLength); + const start = input.readInt(true); + end += start; + if (scale === 1) { + for (let v = start; v < end; v++) + deform[v] = input.readFloat(); + } else { + for (let v = start; v < end; v++) + deform[v] = input.readFloat() * scale; + } + if (!weighted) { + for (let v = 0, vn = deform.length; v < vn; v++) + deform[v] += vertices[v]; + } + } + timeline.setFrame(frame, time, deform); + if (frame === frameLast) break; + const time2 = input.readFloat(); + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, 0, 1, 1); + } + time = time2; + } + timelines.push(timeline); + break; + } + case ATTACHMENT_SEQUENCE: { + const timeline = new SequenceTimeline(frameCount, slotIndex, attachment); + for (let frame = 0; frame < frameCount; frame++) { + const time = input.readFloat(); + const modeAndIndex = input.readInt32(); + timeline.setFrame( + frame, + time, + SequenceModeValues[modeAndIndex & 15], + modeAndIndex >> 4, + input.readFloat() + ); + } + timelines.push(timeline); + break; + } + } + } + } + } + const slotCount = skeletonData.slots.length; + const drawOrderCount = input.readInt(true); + if (drawOrderCount > 0) { + const timeline = new DrawOrderTimeline(drawOrderCount); + for (let i = 0; i < drawOrderCount; i++) + timeline.setFrame(i, input.readFloat(), readDrawOrder(input, slotCount)); + timelines.push(timeline); + } + const folderCount = input.readInt(true); + for (let i = 0; i < folderCount; i++) { + const folderSlotCount = input.readInt(true); + const folderSlots = new Array(folderSlotCount); + for (let ii = 0; ii < folderSlotCount; ii++) + folderSlots[ii] = input.readInt(true); + const keyCount = input.readInt(true); + const timeline = new DrawOrderFolderTimeline(keyCount, folderSlots, slotCount); + for (let ii = 0; ii < keyCount; ii++) + timeline.setFrame(ii, input.readFloat(), readDrawOrder(input, folderSlotCount)); + timelines.push(timeline); + } + const eventCount = input.readInt(true); + if (eventCount > 0) { + const timeline = new EventTimeline(eventCount); + for (let i = 0; i < eventCount; i++) { + const time = input.readFloat(); + const eventData = skeletonData.events[input.readInt(true)]; + const event = new Event(time, eventData); + event.intValue = input.readInt(false); + event.floatValue = input.readFloat(); + event.stringValue = input.readString(); + if (event.stringValue == null) event.stringValue = eventData.setupPose.stringValue; + if (event.data.audioPath) { + event.volume = input.readFloat(); + event.balance = input.readFloat(); + } + timeline.setFrame(i, event); + } + timelines.push(timeline); + } + let duration = 0; + for (let i = 0, n = timelines.length; i < n; i++) + duration = Math.max(duration, timelines[i].getDuration()); + const animation = new Animation(name, timelines, duration); + if (nonessential) Color.rgba8888ToColor(animation.color, input.readInt32()); + return animation; + } + }; + var BinaryInput = class { + constructor(data, strings = [], index = 0, buffer = new DataView(data instanceof ArrayBuffer ? data : data.buffer)) { + this.strings = strings; + this.index = index; + this.buffer = buffer; + } + readByte() { + return this.buffer.getInt8(this.index++); + } + readUnsignedByte() { + return this.buffer.getUint8(this.index++); + } + readShort() { + const value = this.buffer.getInt16(this.index); + this.index += 2; + return value; + } + readInt32() { + const value = this.buffer.getInt32(this.index); + this.index += 4; + return value; + } + readInt(optimizePositive) { + let b = this.readByte(); + let result = b & 127; + if ((b & 128) !== 0) { + b = this.readByte(); + result |= (b & 127) << 7; + if ((b & 128) !== 0) { + b = this.readByte(); + result |= (b & 127) << 14; + if ((b & 128) !== 0) { + b = this.readByte(); + result |= (b & 127) << 21; + if ((b & 128) !== 0) { + b = this.readByte(); + result |= (b & 127) << 28; + } + } + } + } + return optimizePositive ? result : result >>> 1 ^ -(result & 1); + } + readStringRef() { + const index = this.readInt(true); + return index === 0 ? null : this.strings[index - 1]; + } + readString() { + let byteCount = this.readInt(true); + switch (byteCount) { + case 0: + return null; + case 1: + return ""; + } + byteCount--; + let chars = ""; + for (let i = 0; i < byteCount; ) { + const b = this.readUnsignedByte(); + switch (b >> 4) { + case 12: + case 13: + chars += String.fromCharCode((b & 31) << 6 | this.readByte() & 63); + i += 2; + break; + case 14: + chars += String.fromCharCode((b & 15) << 12 | (this.readByte() & 63) << 6 | this.readByte() & 63); + i += 3; + break; + default: + chars += String.fromCharCode(b); + i++; + } + } + return chars; + } + readFloat() { + const value = this.buffer.getFloat32(this.index); + this.index += 4; + return value; + } + readBoolean() { + return this.readByte() !== 0; + } + }; + var LinkedMesh = class { + source; + skinIndex; + slotIndex; + sourceIndex; + mesh; + inheritTimelines; + constructor(mesh, skinIndex, slotIndex, sourceIndex, source, inheritTimelines) { + this.mesh = mesh; + this.skinIndex = skinIndex; + this.slotIndex = slotIndex; + this.sourceIndex = sourceIndex; + this.source = source; + this.inheritTimelines = inheritTimelines; + } + }; + var Vertices = class { + constructor(bones = null, vertices, length = 0) { + this.bones = bones; + this.vertices = vertices; + this.length = length; + } + }; + function readTimeline(input, timelines, timeline, scale) { + if (timeline instanceof CurveTimeline1) + readTimeline1(input, timelines, timeline, scale); + else + readTimeline2(input, timelines, timeline, scale); + } + function readTimeline1(input, timelines, timeline, scale) { + let time = input.readFloat(), value = input.readFloat() * scale; + for (let frame = 0, bezier = 0, frameLast = timeline.getFrameCount() - 1; ; frame++) { + timeline.setFrame(frame, time, value); + if (frame === frameLast) break; + const time2 = input.readFloat(), value2 = input.readFloat() * scale; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, value, value2, scale); + } + time = time2; + value = value2; + } + timelines.push(timeline); + } + function readTimeline2(input, timelines, timeline, scale) { + let time = input.readFloat(), value1 = input.readFloat() * scale, value2 = input.readFloat() * scale; + for (let frame = 0, bezier = 0, frameLast = timeline.getFrameCount() - 1; ; frame++) { + timeline.setFrame(frame, time, value1, value2); + if (frame === frameLast) break; + const time2 = input.readFloat(), nvalue1 = input.readFloat() * scale, nvalue2 = input.readFloat() * scale; + switch (input.readByte()) { + case CURVE_STEPPED: + timeline.setStepped(frame); + break; + case CURVE_BEZIER: + setBezier(input, timeline, bezier++, frame, 0, time, time2, value1, nvalue1, scale); + setBezier(input, timeline, bezier++, frame, 1, time, time2, value2, nvalue2, scale); + } + time = time2; + value1 = nvalue1; + value2 = nvalue2; + } + timelines.push(timeline); + } + function readDrawOrder(input, slotCount) { + const changeCount = input.readInt(true); + if (changeCount === 0) return null; + const drawOrder = new Array(slotCount).fill(-1); + const unchanged = new Array(slotCount - changeCount); + let originalIndex = 0, unchangedIndex = 0; + for (let i = 0; i < changeCount; i++) { + const slotIndex = input.readInt(true); + while (originalIndex !== slotIndex) + unchanged[unchangedIndex++] = originalIndex++; + drawOrder[originalIndex + input.readInt(true)] = originalIndex++; + } + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + for (let i = slotCount - 1; i >= 0; i--) + if (drawOrder[i] === -1) drawOrder[i] = unchanged[--unchangedIndex]; + return drawOrder; + } + function setBezier(input, timeline, bezier, frame, value, time1, time2, value1, value2, scale) { + timeline.setBezier(bezier, frame, value, time1, value1, input.readFloat(), input.readFloat() * scale, input.readFloat(), input.readFloat() * scale, time2, value2); + } + var BONE_ROTATE = 0; + var BONE_TRANSLATE = 1; + var BONE_TRANSLATEX = 2; + var BONE_TRANSLATEY = 3; + var BONE_SCALE = 4; + var BONE_SCALEX = 5; + var BONE_SCALEY = 6; + var BONE_SHEAR = 7; + var BONE_SHEARX = 8; + var BONE_SHEARY = 9; + var BONE_INHERIT = 10; + var SLOT_ATTACHMENT = 0; + var SLOT_RGBA = 1; + var SLOT_RGB = 2; + var SLOT_RGBA2 = 3; + var SLOT_RGB2 = 4; + var SLOT_ALPHA = 5; + var CONSTRAINT_IK = 0; + var CONSTRAINT_PATH = 1; + var CONSTRAINT_TRANSFORM = 2; + var CONSTRAINT_PHYSICS = 3; + var CONSTRAINT_SLIDER = 4; + var ATTACHMENT_DEFORM = 0; + var ATTACHMENT_SEQUENCE = 1; + var PATH_POSITION = 0; + var PATH_SPACING = 1; + var PATH_MIX = 2; + var PHYSICS_INERTIA = 0; + var PHYSICS_STRENGTH = 1; + var PHYSICS_DAMPING = 2; + var PHYSICS_MASS = 4; + var PHYSICS_WIND = 5; + var PHYSICS_GRAVITY = 6; + var PHYSICS_MIX = 7; + var PHYSICS_RESET = 8; + var SLIDER_TIME = 0; + var SLIDER_MIX = 1; + var CURVE_STEPPED = 1; + var CURVE_BEZIER = 2; + + // spine-core/src/SkeletonBounds.ts + var SkeletonBounds = class { + /** The left edge of the axis aligned bounding box. */ + minX = 0; + /** The bottom edge of the axis aligned bounding box. */ + minY = 0; + /** The right edge of the axis aligned bounding box. */ + maxX = 0; + /** The top edge of the axis aligned bounding box. */ + maxY = 0; + /** The visible bounding boxes. */ + boundingBoxes = []; + /** The world vertices for the bounding box polygons. */ + polygons = []; + polygonPool = new Pool(() => { + return Utils.newFloatArray(16); + }); + /** Clears any previous polygons, finds all visible bounding box attachments, and computes the world vertices for each bounding + * box's polygon. + * @param updateAabb If true, the axis aligned bounding box containing all the polygons is computed. If false, the + * SkeletonBounds AABB methods will always return true. */ + update(skeleton, updateAabb) { + if (!skeleton) throw new Error("skeleton cannot be null."); + const boundingBoxes = this.boundingBoxes; + const polygons = this.polygons; + const polygonPool = this.polygonPool; + const slots = skeleton.slots; + const slotCount = slots.length; + boundingBoxes.length = 0; + polygonPool.freeAll(polygons); + polygons.length = 0; + for (let i = 0; i < slotCount; i++) { + const slot = slots[i]; + if (!slot.bone.active) continue; + const attachment = slot.appliedPose.attachment; + if (attachment instanceof BoundingBoxAttachment) { + boundingBoxes.push(attachment); + let polygon = polygonPool.obtain(); + if (polygon.length !== attachment.worldVerticesLength) { + polygon = Utils.newFloatArray(attachment.worldVerticesLength); + } + polygons.push(polygon); + attachment.computeWorldVertices(skeleton, slot, 0, attachment.worldVerticesLength, polygon, 0, 2); + } + } + if (updateAabb) { + this.aabbCompute(); + } else { + this.minX = Number.POSITIVE_INFINITY; + this.minY = Number.POSITIVE_INFINITY; + this.maxX = Number.NEGATIVE_INFINITY; + this.maxY = Number.NEGATIVE_INFINITY; + } + } + aabbCompute() { + let minX = Number.POSITIVE_INFINITY, minY = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY, maxY = Number.NEGATIVE_INFINITY; + const polygons = this.polygons; + for (let i = 0, n = polygons.length; i < n; i++) { + const polygon = polygons[i]; + const vertices = polygon; + for (let ii = 0, nn = polygon.length; ii < nn; ii += 2) { + const x = vertices[ii]; + const y = vertices[ii + 1]; + minX = Math.min(minX, x); + minY = Math.min(minY, y); + maxX = Math.max(maxX, x); + maxY = Math.max(maxY, y); + } + } + this.minX = minX; + this.minY = minY; + this.maxX = maxX; + this.maxY = maxY; + } + /** Returns true if the axis aligned bounding box contains the point. */ + aabbContainsPoint(x, y) { + return x >= this.minX && x <= this.maxX && y >= this.minY && y <= this.maxY; + } + /** Returns true if the axis aligned bounding box intersects the line segment. */ + aabbIntersectsSegment(x1, y1, x2, y2) { + const minX = this.minX; + const minY = this.minY; + const maxX = this.maxX; + const maxY = this.maxY; + if (x1 <= minX && x2 <= minX || y1 <= minY && y2 <= minY || x1 >= maxX && x2 >= maxX || y1 >= maxY && y2 >= maxY) + return false; + const m = (y2 - y1) / (x2 - x1); + let y = m * (minX - x1) + y1; + if (y > minY && y < maxY) return true; + y = m * (maxX - x1) + y1; + if (y > minY && y < maxY) return true; + let x = (minY - y1) / m + x1; + if (x > minX && x < maxX) return true; + x = (maxY - y1) / m + x1; + if (x > minX && x < maxX) return true; + return false; + } + /** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */ + aabbIntersectsSkeleton(bounds) { + return this.minX < bounds.maxX && this.maxX > bounds.minX && this.minY < bounds.maxY && this.maxY > bounds.minY; + } + /** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more + * efficient to only call this method if {@link aabbContainsPoint} returns true. */ + containsPoint(x, y) { + const polygons = this.polygons; + for (let i = 0, n = polygons.length; i < n; i++) + if (this.containsPointPolygon(polygons[i], x, y)) return this.boundingBoxes[i]; + return null; + } + /** Returns true if the polygon contains the point. */ + containsPointPolygon(polygon, x, y) { + const vertices = polygon; + const nn = polygon.length; + let prevIndex = nn - 2; + let inside = false; + for (let ii = 0; ii < nn; ii += 2) { + const vertexY = vertices[ii + 1]; + const prevY = vertices[prevIndex + 1]; + if (vertexY < y && prevY >= y || prevY < y && vertexY >= y) { + const vertexX = vertices[ii]; + if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside; + } + prevIndex = ii; + } + return inside; + } + /** Returns the first bounding box attachment that contains any part of the line segment, or null. When doing many checks, it + * is usually more efficient to only call this method if {@link aabbIntersectsSegment} returns + * true. */ + intersectsSegment(x1, y1, x2, y2) { + const polygons = this.polygons; + for (let i = 0, n = polygons.length; i < n; i++) + if (this.intersectsSegmentPolygon(polygons[i], x1, y1, x2, y2)) return this.boundingBoxes[i]; + return null; + } + /** Returns true if the polygon contains any part of the line segment. */ + intersectsSegmentPolygon(polygon, x1, y1, x2, y2) { + const vertices = polygon; + const nn = polygon.length; + const width12 = x1 - x2, height12 = y1 - y2; + const det1 = x1 * y2 - y1 * x2; + let x3 = vertices[nn - 2], y3 = vertices[nn - 1]; + for (let ii = 0; ii < nn; ii += 2) { + const x4 = vertices[ii], y4 = vertices[ii + 1]; + const det2 = x3 * y4 - y3 * x4; + const width34 = x3 - x4, height34 = y3 - y4; + const det3 = width12 * height34 - height12 * width34; + const x = (det1 * width34 - width12 * det2) / det3; + if ((x >= x3 && x <= x4 || x >= x4 && x <= x3) && (x >= x1 && x <= x2 || x >= x2 && x <= x1)) { + const y = (det1 * height34 - height12 * det2) / det3; + if ((y >= y3 && y <= y4 || y >= y4 && y <= y3) && (y >= y1 && y <= y2 || y >= y2 && y <= y1)) return true; + } + x3 = x4; + y3 = y4; + } + return false; + } + /** Returns the polygon for the specified bounding box, or null. */ + getPolygon(boundingBox) { + if (!boundingBox) throw new Error("boundingBox cannot be null."); + const index = this.boundingBoxes.indexOf(boundingBox); + return index === -1 ? null : this.polygons[index]; + } + /** The width of the axis aligned bounding box. */ + getWidth() { + return this.maxX - this.minX; + } + /** The height of the axis aligned bounding box. */ + getHeight() { + return this.maxY - this.minY; + } + }; + + // spine-core/src/Triangulator.ts + var Triangulator = class _Triangulator { + convexPolygons = []; + convexPolygonsIndices = []; + indicesArray = []; + isConcaveArray = []; + triangles = []; + polygonPool = new Pool(() => { + return []; + }); + polygonIndicesPool = new Pool(() => { + return []; + }); + triangulate(verticesArray) { + const vertices = verticesArray; + let vertexCount = verticesArray.length >> 1; + const indices = this.indicesArray; + indices.length = 0; + for (let i = 0; i < vertexCount; i++) + indices[i] = i; + const isConcave = this.isConcaveArray; + isConcave.length = 0; + for (let i = 0; i < vertexCount; i++) + isConcave[i] = _Triangulator.isConcave(i, vertexCount, vertices, indices); + const triangles = this.triangles; + triangles.length = 0; + while (vertexCount > 3) { + let previous = vertexCount - 1, i = 0, next = 1; + while (true) { + outer: + if (!isConcave[i]) { + const p1 = indices[previous] << 1, p2 = indices[i] << 1, p3 = indices[next] << 1; + const p1x = vertices[p1], p1y = vertices[p1 + 1]; + const p2x = vertices[p2], p2y = vertices[p2 + 1]; + const p3x = vertices[p3], p3y = vertices[p3 + 1]; + for (let ii = next + 1 < vertexCount ? next + 1 : 0; ii !== previous; ) { + if (isConcave[ii]) { + const v = indices[ii] << 1; + const vx = vertices[v], vy = vertices[v + 1]; + if (_Triangulator.positiveArea(p3x, p3y, p1x, p1y, vx, vy) && _Triangulator.positiveArea(p1x, p1y, p2x, p2y, vx, vy) && _Triangulator.positiveArea(p2x, p2y, p3x, p3y, vx, vy)) break outer; + } + if (++ii === vertexCount) ii = 0; + } + break; + } + if (next === 0) { + do { + if (!isConcave[i]) break; + i--; + } while (i > 0); + previous = i > 0 ? i - 1 : vertexCount - 1; + next = i + 1 < vertexCount ? i + 1 : 0; + break; + } + previous = i; + i = next; + if (++next === vertexCount) next = 0; + } + triangles.push(indices[previous], indices[i], indices[next]); + indices.splice(i, 1); + isConcave.splice(i, 1); + vertexCount--; + const previousIndex = i > 0 ? i - 1 : vertexCount - 1; + const nextIndex = i < vertexCount ? i : 0; + isConcave[previousIndex] = _Triangulator.isConcave(previousIndex, vertexCount, vertices, indices); + isConcave[nextIndex] = _Triangulator.isConcave(nextIndex, vertexCount, vertices, indices); + } + if (vertexCount === 3) triangles.push(indices[2], indices[0], indices[1]); + return triangles; + } + decompose(verticesArray, triangles) { + const vertices = verticesArray; + const convexPolygons = this.convexPolygons; + this.polygonPool.freeAll(convexPolygons); + convexPolygons.length = 0; + const convexPolygonsIndices = this.convexPolygonsIndices; + this.polygonIndicesPool.freeAll(convexPolygonsIndices); + convexPolygonsIndices.length = 0; + let polygonIndices = this.polygonIndicesPool.obtain(); + polygonIndices.length = 0; + let polygon = this.polygonPool.obtain(); + polygon.length = 0; + let fanBaseIndex = -1, lastWinding = 0; + for (let i = 0, n = triangles.length; i < n; i += 3) { + const t1 = triangles[i] << 1, t2 = triangles[i + 1] << 1, t3 = triangles[i + 2] << 1; + const x1 = vertices[t1], y1 = vertices[t1 + 1]; + const x2 = vertices[t2], y2 = vertices[t2 + 1]; + const x3 = vertices[t3], y3 = vertices[t3 + 1]; + if (fanBaseIndex === t1) { + const o = polygon.length - 4; + if (_Triangulator.winding(polygon[o], polygon[o + 1], polygon[o + 2], polygon[o + 3], x3, y3) === lastWinding && _Triangulator.winding(x3, y3, polygon[0], polygon[1], polygon[2], polygon[3]) === lastWinding) { + polygon.push(x3, y3); + polygonIndices.push(t3); + continue; + } + } + if (polygon.length > 0) { + convexPolygons.push(polygon); + convexPolygonsIndices.push(polygonIndices); + polygon = this.polygonPool.obtain(); + polygonIndices = this.polygonIndicesPool.obtain(); + } + polygon.length = 0; + polygon.push(x1, y1, x2, y2); + polygon.push(x3, y3); + polygonIndices.length = 0; + polygonIndices.push(t1, t2, t3); + lastWinding = _Triangulator.winding(x1, y1, x2, y2, x3, y3); + fanBaseIndex = t1; + } + if (polygon.length > 0) { + convexPolygons.push(polygon); + convexPolygonsIndices.push(polygonIndices); + } + for (let i = 0, n = convexPolygons.length; i < n; i++) { + polygonIndices = convexPolygonsIndices[i]; + if (polygonIndices.length === 0) continue; + const firstIndex = polygonIndices[0]; + let lastIndex = polygonIndices[polygonIndices.length - 1]; + polygon = convexPolygons[i]; + const o = polygon.length - 4; + let prevPrevX = polygon[o], prevPrevY = polygon[o + 1]; + let prevX = polygon[o + 2], prevY = polygon[o + 3]; + const firstX = polygon[0], firstY = polygon[1]; + const secondX = polygon[2], secondY = polygon[3]; + const winding = _Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, firstX, firstY); + for (let ii = 0; ii < n; ii++) { + if (ii === i) continue; + const otherIndices = convexPolygonsIndices[ii]; + if (otherIndices.length !== 3) continue; + const otherFirstIndex = otherIndices[0]; + const otherSecondIndex = otherIndices[1]; + const otherLastIndex = otherIndices[2]; + const otherPoly = convexPolygons[ii]; + const x3 = otherPoly[otherPoly.length - 2], y3 = otherPoly[otherPoly.length - 1]; + if (otherFirstIndex !== firstIndex || otherSecondIndex !== lastIndex) continue; + if (_Triangulator.winding(prevPrevX, prevPrevY, prevX, prevY, x3, y3) === winding && _Triangulator.winding(x3, y3, firstX, firstY, secondX, secondY) === winding) { + otherPoly.length = 0; + otherIndices.length = 0; + polygon.push(x3, y3); + polygonIndices.push(otherLastIndex); + lastIndex = otherLastIndex; + prevPrevX = prevX; + prevPrevY = prevY; + prevX = x3; + prevY = y3; + ii = -1; + } + } + } + for (let i = convexPolygons.length - 1; i >= 0; i--) { + polygon = convexPolygons[i]; + if (polygon.length === 0) { + convexPolygons.splice(i, 1); + this.polygonPool.free(polygon); + polygonIndices = convexPolygonsIndices[i]; + convexPolygonsIndices.splice(i, 1); + this.polygonIndicesPool.free(polygonIndices); + } else + polygon.push(polygon[0], polygon[1]); + } + return convexPolygons; + } + static isConcave(index, vertexCount, vertices, indices) { + const previous = indices[index > 0 ? index - 1 : vertexCount - 1] << 1; + const current = indices[index] << 1; + const next = indices[index + 1 < vertexCount ? index + 1 : 0] << 1; + return !_Triangulator.positiveArea( + vertices[previous], + vertices[previous + 1], + vertices[current], + vertices[current + 1], + vertices[next], + vertices[next + 1] + ); + } + static positiveArea(p1x, p1y, p2x, p2y, p3x, p3y) { + return p1x * (p3y - p2y) + p2x * (p1y - p3y) + p3x * (p2y - p1y) >= 0; + } + static winding(p1x, p1y, p2x, p2y, p3x, p3y) { + return p1x * (p3y - p2y) + p2x * (p1y - p3y) + p3x * (p2y - p1y) >= 0 ? 1 : -1; + } + }; + + // spine-core/src/SkeletonClipping.ts + var SkeletonClipping = class { + triangulator = null; + clippingPolygon = []; + clippingPolygons = []; + clipOutput = []; + clippedVertices = []; + /** An empty array unless {@link clipTrianglesUnpacked} was used. **/ + clippedUVs = []; + clippedTriangles = []; + inverseVertices = []; + _clippedVerticesTyped = new Float32Array(1024); + _clippedUVsTyped = new Float32Array(1024); + _clippedTrianglesTyped = new Uint16Array(1024); + clippedVerticesTyped = new Float32Array(0); + clippedUVsTyped = new Float32Array(0); + clippedTrianglesTyped = new Uint16Array(0); + clippedVerticesLength = 0; + clippedUVsLength = 0; + clippedTrianglesLength = 0; + scratch = []; + inverse = false; + clipAttachment = null; + clipStart(skeleton, slot, clip) { + if (this.clipAttachment) return; + const n = clip.worldVerticesLength; + this.clipAttachment = clip; + this.inverse = clip.inverse; + const vertices = Utils.setArraySize(this.clippingPolygon, n); + clip.computeWorldVertices(skeleton, slot, 0, n, vertices, 0, 2); + const clippingPolygon = this.clippingPolygon; + const convex = this.makeClockwise(clippingPolygon); + if (convex || this.inverse || clip.convex) { + if (!convex) this.makeConvex(clippingPolygon); + this.clippingPolygon.push(clippingPolygon[0], clippingPolygon[1]); + this.clippingPolygons.push(clippingPolygon); + } else { + if (this.triangulator === null) this.triangulator = new Triangulator(); + this.clippingPolygons.push(...this.triangulator.decompose(clippingPolygon, this.triangulator.triangulate(clippingPolygon))); + } + } + clipEnd(slot) { + if (!this.clipAttachment) return; + if (slot && this.clipAttachment.endSlot !== slot.data) return; + this.clipAttachment = null; + this.clippingPolygons.length = 0; + } + isClipping() { + return this.clipAttachment != null; + } + clipTriangles(vertices, triangles, trianglesLength, uvs, light, dark, twoColor, stride) { + return uvs && light && dark && typeof twoColor === "boolean" && typeof stride === "number" ? this.clipTrianglesRender(vertices, triangles, trianglesLength, uvs, light, dark, twoColor, stride) : this.clipTrianglesNoRender(vertices, triangles, trianglesLength); + } + clipTrianglesNoRender(vertices, triangles, trianglesLength) { + const clippedVertices = this.clippedVertices; + clippedVertices.length = 0; + const clippedTriangles = this.clippedTriangles; + clippedTriangles.length = 0; + let index = 0; + if (this.inverse) { + const polygon = this.clippingPolygons[0]; + for (let i = 0; i < trianglesLength; i += 3) { + let t = triangles[i] << 1; + const x1 = vertices[t], y1 = vertices[t + 1]; + t = triangles[i + 1] << 1; + const x2 = vertices[t], y2 = vertices[t + 1]; + t = triangles[i + 2] << 1; + const x3 = vertices[t], y3 = vertices[t + 1]; + this.clipInverse(x1, y1, x2, y2, x3, y3, polygon); + const iv = this.inverseVertices; + for (let offset = 0, nn = this.inverseVertices.length; offset < nn; ) { + const polygonSize = iv[offset++]; + let vertexCount = polygonSize >> 1, s = clippedVertices.length; + const cv = Utils.setArraySize(clippedVertices, s + polygonSize); + Utils.arrayCopy(iv, offset, cv, s, polygonSize); + s = clippedTriangles.length; + const ct = Utils.setArraySize(clippedTriangles, s + 3 * (vertexCount - 2)); + for (let ii = 1; ii < vertexCount - 1; ii++, s += 3) { + ct[s] = index; + ct[s + 1] = index + ii; + ct[s + 2] = index + ii + 1; + } + index += vertexCount; + offset += polygonSize; + } + } + return true; + } + const clipOutput = this.clipOutput; + const polygons = this.clippingPolygons; + const polygonsCount = polygons.length; + let clipOutputItems = null; + for (let i = 0; i < trianglesLength; i += 3) { + let t = triangles[i] << 1; + const x1 = vertices[t], y1 = vertices[t + 1]; + t = triangles[i + 1] << 1; + const x2 = vertices[t], y2 = vertices[t + 1]; + t = triangles[i + 2] << 1; + const x3 = vertices[t], y3 = vertices[t + 1]; + for (let p = 0; p < polygonsCount; p++) { + let s = clippedVertices.length; + if (this.clip(x1, y1, x2, y2, x3, y3, polygons[p])) { + clipOutputItems = this.clipOutput; + const clipOutputLength = clipOutput.length; + if (clipOutputLength === 0) continue; + let clipOutputCount = clipOutputLength >> 1; + const cv = Utils.setArraySize(clippedVertices, s + clipOutputLength); + Utils.arrayCopy(clipOutputItems, 0, cv, s, clipOutputLength); + s = clippedTriangles.length; + const ct = Utils.setArraySize(clippedTriangles, s + 3 * (clipOutputCount - 2)); + clipOutputCount--; + for (let ii = 1; ii < clipOutputCount; ii++, s += 3) { + ct[s] = index; + ct[s + 1] = index + ii; + ct[s + 2] = index + ii + 1; + } + index += clipOutputCount; + } else { + const cv = Utils.setArraySize(clippedVertices, s + 3 * 2); + cv[s] = x1; + cv[s + 1] = y1; + cv[s + 2] = x2; + cv[s + 3] = y2; + cv[s + 4] = x3; + cv[s + 5] = y3; + s = clippedTriangles.length; + const ct = Utils.setArraySize(clippedTriangles, s + 3); + ct[s] = index; + ct[s + 1] = index + 1; + ct[s + 2] = index + 2; + index += 3; + break; + } + } + } + return clipOutputItems != null; + } + clipTrianglesRender(vertices, triangles, trianglesLength, uvs, light, dark, twoColor, stride) { + const clippedVertices = this.clippedVertices; + clippedVertices.length = 0; + const clippedTriangles = this.clippedTriangles; + clippedTriangles.length = 0; + let index = 0; + if (this.inverse) { + const polygon = this.clippingPolygons[0]; + for (let i = 0; i < trianglesLength; i += 3) { + let t0 = triangles[i], t1 = triangles[i + 1], t2 = triangles[i + 2]; + const x1 = vertices[t0 * stride], y1 = vertices[t0 * stride + 1]; + const x2 = vertices[t1 * stride], y2 = vertices[t1 * stride + 1]; + const x3 = vertices[t2 * stride], y3 = vertices[t2 * stride + 1]; + this.clipInverse(x1, y1, x2, y2, x3, y3, polygon); + const nn = this.inverseVertices.length; + if (nn === 0) continue; + const u1 = uvs[t0 <<= 1], v1 = uvs[t0 + 1]; + const u2 = uvs[t1 <<= 1], v2 = uvs[t1 + 1]; + const u3 = uvs[t2 <<= 1], v3 = uvs[t2 + 1]; + const d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1, d = 1 / (d0 * d2 + d1 * (y1 - y3)); + const iv = this.inverseVertices; + for (let offset = 0; offset < nn; ) { + const polygonSize = iv[offset++]; + const vertexCount = polygonSize >> 1; + let s = clippedVertices.length; + const cv = Utils.setArraySize(clippedVertices, s + vertexCount * stride); + for (let ii = 0; ii < polygonSize; ii += 2, s += stride) { + const x = iv[offset + ii], y = iv[offset + ii + 1]; + cv[s] = x; + cv[s + 1] = y; + cv[s + 2] = light.r; + cv[s + 3] = light.g; + cv[s + 4] = light.b; + cv[s + 5] = light.a; + const c0 = x - x3, c1 = y - y3, a = (d0 * c0 + d1 * c1) * d, b = (d4 * c0 + d2 * c1) * d, c = 1 - a - b; + cv[s + 6] = u1 * a + u2 * b + u3 * c; + cv[s + 7] = v1 * a + v2 * b + v3 * c; + if (twoColor) { + cv[s + 8] = dark.r; + cv[s + 9] = dark.g; + cv[s + 10] = dark.b; + cv[s + 11] = dark.a; + } + } + s = clippedTriangles.length; + const ct = Utils.setArraySize(clippedTriangles, s + 3 * (vertexCount - 2)); + for (let ii = 1; ii < vertexCount - 1; ii++, s += 3) { + ct[s] = index; + ct[s + 1] = index + ii; + ct[s + 2] = index + ii + 1; + } + index += vertexCount; + offset += polygonSize; + } + } + return true; + } + const clipOutput = this.clipOutput; + const polygons = this.clippingPolygons; + const polygonsCount = this.clippingPolygons.length; + let clipOutputItems = null; + for (let i = 0; i < trianglesLength; i += 3) { + let t = triangles[i]; + const x1 = vertices[t * stride], y1 = vertices[t * stride + 1]; + const u1 = uvs[t << 1], v1 = uvs[(t << 1) + 1]; + t = triangles[i + 1]; + const x2 = vertices[t * stride], y2 = vertices[t * stride + 1]; + const u2 = uvs[t << 1], v2 = uvs[(t << 1) + 1]; + t = triangles[i + 2]; + const x3 = vertices[t * stride], y3 = vertices[t * stride + 1]; + const u3 = uvs[t << 1], v3 = uvs[(t << 1) + 1]; + let d0 = 0, d1 = 0, d2 = 0, d4 = 0, d = 0; + for (let p = 0; p < polygonsCount; p++) { + let s = clippedVertices.length; + if (this.clip(x1, y1, x2, y2, x3, y3, polygons[p])) { + clipOutputItems = this.clipOutput; + const clipOutputLength = clipOutput.length; + if (clipOutputLength === 0) continue; + let clipOutputCount = clipOutputLength >> 1; + if (d === 0) { + d0 = y2 - y3; + d1 = x3 - x2; + d2 = x1 - x3; + d4 = y3 - y1; + d = 1 / (d0 * d2 - d1 * d4); + } + const cv = Utils.setArraySize(clippedVertices, s + clipOutputCount * stride); + for (let ii = 0; ii < clipOutputLength; ii += 2, s += stride) { + const x = clipOutputItems[ii], y = clipOutputItems[ii + 1]; + cv[s] = x; + cv[s + 1] = y; + cv[s + 2] = light.r; + cv[s + 3] = light.g; + cv[s + 4] = light.b; + cv[s + 5] = light.a; + const c0 = x - x3, c1 = y - y3, a = (d0 * c0 + d1 * c1) * d, b = (d4 * c0 + d2 * c1) * d, c = 1 - a - b; + cv[s + 6] = u1 * a + u2 * b + u3 * c; + cv[s + 7] = v1 * a + v2 * b + v3 * c; + if (twoColor) { + cv[s + 8] = dark.r; + cv[s + 9] = dark.g; + cv[s + 10] = dark.b; + cv[s + 11] = dark.a; + } + } + s = clippedTriangles.length; + const ct = Utils.setArraySize(clippedTriangles, s + 3 * (clipOutputCount - 2)); + clipOutputCount--; + for (let ii = 1; ii < clipOutputCount; ii++, s += 3) { + ct[s] = index; + ct[s + 1] = index + ii; + ct[s + 2] = index + ii + 1; + } + index += clipOutputCount + 1; + } else { + const cv = Utils.setArraySize(clippedVertices, s + 3 * stride); + cv[s] = x1; + cv[s + 1] = y1; + cv[s + 2] = light.r; + cv[s + 3] = light.g; + cv[s + 4] = light.b; + cv[s + 5] = light.a; + if (!twoColor) { + cv[s + 6] = u1; + cv[s + 7] = v1; + cv[s + 8] = x2; + cv[s + 9] = y2; + cv[s + 10] = light.r; + cv[s + 11] = light.g; + cv[s + 12] = light.b; + cv[s + 13] = light.a; + cv[s + 14] = u2; + cv[s + 15] = v2; + cv[s + 16] = x3; + cv[s + 17] = y3; + cv[s + 18] = light.r; + cv[s + 19] = light.g; + cv[s + 20] = light.b; + cv[s + 21] = light.a; + cv[s + 22] = u3; + cv[s + 23] = v3; + } else { + cv[s + 6] = u1; + cv[s + 7] = v1; + cv[s + 8] = dark.r; + cv[s + 9] = dark.g; + cv[s + 10] = dark.b; + cv[s + 11] = dark.a; + cv[s + 12] = x2; + cv[s + 13] = y2; + cv[s + 14] = light.r; + cv[s + 15] = light.g; + cv[s + 16] = light.b; + cv[s + 17] = light.a; + cv[s + 18] = u2; + cv[s + 19] = v2; + cv[s + 20] = dark.r; + cv[s + 21] = dark.g; + cv[s + 22] = dark.b; + cv[s + 23] = dark.a; + cv[s + 24] = x3; + cv[s + 25] = y3; + cv[s + 26] = light.r; + cv[s + 27] = light.g; + cv[s + 28] = light.b; + cv[s + 29] = light.a; + cv[s + 30] = u3; + cv[s + 31] = v3; + cv[s + 32] = dark.r; + cv[s + 33] = dark.g; + cv[s + 34] = dark.b; + cv[s + 35] = dark.a; + } + s = clippedTriangles.length; + const ct = Utils.setArraySize(clippedTriangles, s + 3); + ct[s] = index; + ct[s + 1] = index + 1; + ct[s + 2] = index + 2; + index += 3; + break; + } + } + } + return clipOutputItems != null; + } + clipTrianglesUnpacked(vertices, vertexStart, triangles, trianglesLength, uvs, stride = 2) { + let clippedVertices = this._clippedVerticesTyped; + let clippedUVs = this._clippedUVsTyped; + let clippedTriangles = this._clippedTrianglesTyped; + let index = 0; + this.clippedVerticesLength = 0; + this.clippedUVsLength = 0; + this.clippedTrianglesLength = 0; + if (this.inverse) { + const polygon = this.clippingPolygons[0]; + for (let i = 0; i < trianglesLength; i += 3) { + let v = triangles[i] * stride; + const x1 = vertices[vertexStart + v], y1 = vertices[vertexStart + v + 1]; + let uv = triangles[i] << 1; + const u1 = uvs[uv], v1 = uvs[uv + 1]; + v = triangles[i + 1] * stride; + const x2 = vertices[vertexStart + v], y2 = vertices[vertexStart + v + 1]; + uv = triangles[i + 1] << 1; + const u2 = uvs[uv], v2 = uvs[uv + 1]; + v = triangles[i + 2] * stride; + const x3 = vertices[vertexStart + v], y3 = vertices[vertexStart + v + 1]; + uv = triangles[i + 2] << 1; + const u3 = uvs[uv], v3 = uvs[uv + 1]; + this.clipInverse(x1, y1, x2, y2, x3, y3, polygon); + const nn = this.inverseVertices.length; + if (nn === 0) continue; + const d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1, d = 1 / (d0 * d2 + d1 * (y1 - y3)); + const iv = this.inverseVertices; + for (let offset = 0; offset < nn; ) { + const polygonSize = iv[offset++]; + const vertexCount = polygonSize >> 1; + let s = this.clippedVerticesLength; + const newLength = s + vertexCount * stride; + const newUVLength = this.clippedUVsLength + vertexCount * 2; + if (clippedVertices.length < newLength) { + this._clippedVerticesTyped = new Float32Array(newLength * 2); + this._clippedVerticesTyped.set(clippedVertices.subarray(0, s)); + clippedVertices = this._clippedVerticesTyped; + } + if (clippedUVs.length < newUVLength) { + this._clippedUVsTyped = new Float32Array(newUVLength * 2); + this._clippedUVsTyped.set(clippedUVs.subarray(0, this.clippedUVsLength)); + clippedUVs = this._clippedUVsTyped; + } + this.clippedVerticesLength = newLength; + this.clippedUVsLength = newUVLength; + const cv = this._clippedVerticesTyped; + const cu = this._clippedUVsTyped; + let uvIndex = newUVLength - vertexCount * 2; + for (let ii = 0; ii < polygonSize; ii += 2, s += stride, uvIndex += 2) { + const x = iv[offset + ii], y = iv[offset + ii + 1]; + cv[s] = x; + cv[s + 1] = y; + const c0 = x - x3, c1 = y - y3, a = (d0 * c0 + d1 * c1) * d, b = (d4 * c0 + d2 * c1) * d, c = 1 - a - b; + cu[uvIndex] = u1 * a + u2 * b + u3 * c; + cu[uvIndex + 1] = v1 * a + v2 * b + v3 * c; + } + s = this.clippedTrianglesLength; + const newLengthTriangles = s + 3 * (vertexCount - 2); + if (clippedTriangles.length < newLengthTriangles) { + this._clippedTrianglesTyped = new Uint16Array(newLengthTriangles * 2); + this._clippedTrianglesTyped.set(clippedTriangles.subarray(0, s)); + clippedTriangles = this._clippedTrianglesTyped; + } + this.clippedTrianglesLength = newLengthTriangles; + const ct = clippedTriangles; + for (let ii = 1; ii < vertexCount - 1; ii++, s += 3) { + ct[s] = index; + ct[s + 1] = index + ii; + ct[s + 2] = index + ii + 1; + } + index += vertexCount; + offset += polygonSize; + } + } + this.clippedVerticesTyped = this._clippedVerticesTyped.subarray(0, this.clippedVerticesLength); + this.clippedUVsTyped = this._clippedUVsTyped.subarray(0, this.clippedUVsLength); + this.clippedTrianglesTyped = this._clippedTrianglesTyped.subarray(0, this.clippedTrianglesLength); + return true; + } + const clipOutput = this.clipOutput; + const polygons = this.clippingPolygons; + const polygonsCount = this.clippingPolygons.length; + let clipOutputItems = null; + for (let i = 0; i < trianglesLength; i += 3) { + let t = triangles[i]; + let v = t * stride; + const x1 = vertices[vertexStart + v], y1 = vertices[vertexStart + v + 1]; + let uv = t << 1; + const u1 = uvs[uv], v1 = uvs[uv + 1]; + t = triangles[i + 1]; + v = t * stride; + const x2 = vertices[vertexStart + v], y2 = vertices[vertexStart + v + 1]; + uv = t << 1; + const u2 = uvs[uv], v2 = uvs[uv + 1]; + t = triangles[i + 2]; + v = t * stride; + const x3 = vertices[vertexStart + v], y3 = vertices[vertexStart + v + 1]; + uv = t << 1; + const u3 = uvs[uv], v3 = uvs[uv + 1]; + let d0 = 0, d1 = 0, d2 = 0, d4 = 0, d = 0; + for (let p = 0; p < polygonsCount; p++) { + let s = this.clippedVerticesLength; + if (this.clip(x1, y1, x2, y2, x3, y3, polygons[p])) { + clipOutputItems = clipOutput; + const clipOutputLength = clipOutput.length; + if (clipOutputLength === 0) continue; + let clipOutputCount = clipOutputLength >> 1; + if (d === 0) { + d0 = y2 - y3; + d1 = x3 - x2; + d2 = x1 - x3; + d4 = y3 - y1; + d = 1 / (d0 * d2 - d1 * d4); + } + const newLength = s + clipOutputCount * stride; + if (clippedVertices.length < newLength) { + this._clippedVerticesTyped = new Float32Array(newLength * 2); + this._clippedVerticesTyped.set(clippedVertices.subarray(0, s)); + this._clippedUVsTyped = new Float32Array((this.clippedUVsLength + clipOutputCount * 2) * 2); + this._clippedUVsTyped.set(clippedUVs.subarray(0, this.clippedUVsLength)); + clippedVertices = this._clippedVerticesTyped; + clippedUVs = this._clippedUVsTyped; + } + const cv = clippedVertices; + const cu = clippedUVs; + this.clippedVerticesLength = newLength; + let uvIndex = this.clippedUVsLength; + this.clippedUVsLength = uvIndex + clipOutputCount * 2; + for (let ii = 0; ii < clipOutputLength; ii += 2, s += stride, uvIndex += 2) { + const x = clipOutputItems[ii], y = clipOutputItems[ii + 1]; + cv[s] = x; + cv[s + 1] = y; + const c0 = x - x3, c1 = y - y3, a = (d0 * c0 + d1 * c1) * d, b = (d4 * c0 + d2 * c1) * d, c = 1 - a - b; + cu[uvIndex] = u1 * a + u2 * b + u3 * c; + cu[uvIndex + 1] = v1 * a + v2 * b + v3 * c; + } + s = this.clippedTrianglesLength; + const newLengthTriangles = s + 3 * (clipOutputCount - 2); + if (clippedTriangles.length < newLengthTriangles) { + this._clippedTrianglesTyped = new Uint16Array(newLengthTriangles * 2); + this._clippedTrianglesTyped.set(clippedTriangles.subarray(0, s)); + clippedTriangles = this._clippedTrianglesTyped; + } + this.clippedTrianglesLength = newLengthTriangles; + const ct = clippedTriangles; + clipOutputCount--; + for (let ii = 1; ii < clipOutputCount; ii++, s += 3) { + ct[s] = index; + ct[s + 1] = index + ii; + ct[s + 2] = index + ii + 1; + } + index += clipOutputCount + 1; + } else { + let newLength = s + 3 * stride; + if (clippedVertices.length < newLength) { + this._clippedVerticesTyped = new Float32Array(newLength * 2); + this._clippedVerticesTyped.set(clippedVertices.subarray(0, s)); + clippedVertices = this._clippedVerticesTyped; + } + clippedVertices[s] = x1; + clippedVertices[s + 1] = y1; + clippedVertices[s + stride] = x2; + clippedVertices[s + stride + 1] = y2; + clippedVertices[s + stride * 2] = x3; + clippedVertices[s + stride * 2 + 1] = y3; + const uvLength = this.clippedUVsLength + 3 * 2; + if (clippedUVs.length < uvLength) { + this._clippedUVsTyped = new Float32Array(uvLength * 2); + this._clippedUVsTyped.set(clippedUVs.subarray(0, this.clippedUVsLength)); + clippedUVs = this._clippedUVsTyped; + } + const uvIndex = this.clippedUVsLength; + clippedUVs[uvIndex] = u1; + clippedUVs[uvIndex + 1] = v1; + clippedUVs[uvIndex + 2] = u2; + clippedUVs[uvIndex + 3] = v2; + clippedUVs[uvIndex + 4] = u3; + clippedUVs[uvIndex + 5] = v3; + this.clippedVerticesLength = newLength; + this.clippedUVsLength = uvLength; + s = this.clippedTrianglesLength; + newLength = s + 3; + if (clippedTriangles.length < newLength) { + this._clippedTrianglesTyped = new Uint16Array(newLength * 2); + this._clippedTrianglesTyped.set(clippedTriangles.subarray(0, s)); + clippedTriangles = this._clippedTrianglesTyped; + } + const ct = clippedTriangles; + ct[s] = index; + ct[s + 1] = index + 1; + ct[s + 2] = index + 2; + index += 3; + this.clippedTrianglesLength = newLength; + break; + } + } + } + this.clippedVerticesTyped = this._clippedVerticesTyped.subarray(0, this.clippedVerticesLength); + this.clippedUVsTyped = this._clippedUVsTyped.subarray(0, this.clippedUVsLength); + this.clippedTrianglesTyped = this._clippedTrianglesTyped.subarray(0, this.clippedTrianglesLength); + return clipOutputItems !== null; + } + clip(x1, y1, x2, y2, x3, y3, polygon) { + const originalOutput = this.clipOutput; + let clipped = false; + let input, output; + if (polygon.length % 4 >= 2) { + input = this.clipOutput; + output = this.scratch; + } else { + input = this.scratch; + output = this.clipOutput; + } + const v = polygon; + input.length = 8; + const iv = input; + iv[0] = x1; + iv[1] = y1; + iv[2] = x2; + iv[3] = y2; + iv[4] = x3; + iv[5] = y3; + iv[6] = x1; + iv[7] = y1; + output.length = 0; + const last = polygon.length - 4; + for (let i = 0; ; i += 2) { + const edgeX = v[i], edgeY = v[i + 1], ex = edgeX - v[i + 2], ey = edgeY - v[i + 3]; + const outputStart = output.length; + const iv2 = input; + x1 = iv2[0]; + y1 = iv2[1]; + let s1 = ey * (edgeX - x1) - ex * (edgeY - y1); + for (let ii = 2, nn = input.length - 2; ii <= nn; ii += 2) { + x2 = iv2[ii]; + y2 = iv2[ii + 1]; + const s2 = ey * (edgeX - x2) - ex * (edgeY - y2); + if (s1 > 0) { + if (s2 > 0) + output.push(x2, y2); + else { + const ix = x2 - x1, iy = y2 - y1, t = s1 / (ix * ey - iy * ex); + if (t >= 0 && t <= 1) { + output.push(x1 + ix * t, y1 + iy * t); + clipped = true; + } else + output.push(x2, y2); + } + } else if (s2 > 0) { + const ix = x2 - x1, iy = y2 - y1, t = s1 / (ix * ey - iy * ex); + if (t >= 0 && t <= 1) { + output.push(x1 + ix * t, y1 + iy * t, x2, y2); + clipped = true; + } else + output.push(x2, y2); + } else + clipped = true; + x1 = x2; + y1 = y2; + s1 = s2; + } + if (outputStart === output.length) { + originalOutput.length = 0; + return true; + } + output.push(output[0], output[1]); + if (i === last) break; + const temp = output; + output = input; + output.length = 0; + input = temp; + } + if (originalOutput !== output) { + originalOutput.length = 0; + for (let i = 0, n = output.length - 2; i < n; i++) + originalOutput[i] = output[i]; + } else + originalOutput.length = originalOutput.length - 2; + return clipped; + } + clipInverse(x1, y1, x2, y2, x3, y3, polygon) { + this.inverseVertices.length = 0; + const vLast = polygon.length - 4; + let input, output; + if (polygon.length % 4 >= 2) { + input = this.clipOutput; + output = this.scratch; + } else { + input = this.scratch; + output = this.clipOutput; + } + input.length = 8; + let v = polygon, iv = input; + iv[0] = x1; + iv[1] = y1; + iv[2] = x2; + iv[3] = y2; + iv[4] = x3; + iv[5] = y3; + iv[6] = x1; + iv[7] = y1; + output.length = 0; + for (let i = 0; ; i += 2) { + const edgeX = v[i], edgeY = v[i + 1], ex = edgeX - v[i + 2], ey = edgeY - v[i + 3]; + const outputStart = output.length, fragmentStart = this.inverseVertices.length; + this.inverseVertices.push(0); + iv = input; + x1 = iv[0]; + y1 = iv[1]; + let s1 = ey * (edgeX - x1) - ex * (edgeY - y1); + for (let ii = 2, nn = input.length - 2; ii <= nn; ii += 2) { + x2 = iv[ii]; + y2 = iv[ii + 1]; + const s2 = ey * (edgeX - x2) - ex * (edgeY - y2); + if (s1 > 0) { + if (s2 > 0) + output.push(x2, y2); + else { + const ix = x2 - x1, iy = y2 - y1, t = s1 / (ix * ey - iy * ex); + if (t >= 0 && t <= 1) { + const cx = x1 + ix * t, cy = y1 + iy * t; + output.push(cx, cy); + this.inverseVertices.push(cx, cy, x2, y2); + } else + output.push(x2, y2); + } + } else if (s2 > 0) { + const ix = x2 - x1, iy = y2 - y1, t = s1 / (ix * ey - iy * ex); + if (t >= 0 && t <= 1) { + const cx = x1 + ix * t, cy = y1 + iy * t; + this.inverseVertices.push(cx, cy); + output.push(cx, cy, x2, y2); + } else + output.push(x2, y2); + } else + this.inverseVertices.push(x2, y2); + x1 = x2; + y1 = y2; + s1 = s2; + } + const fragmentSize = this.inverseVertices.length - fragmentStart - 1; + if (fragmentSize >= 6) + this.inverseVertices[fragmentStart] = fragmentSize; + else + this.inverseVertices.length = fragmentStart; + if (outputStart === output.length) break; + output.push(output[0], output[1]); + if (i === vLast) break; + const temp = output; + output = input; + output.length = 0; + input = temp; + } + } + makeClockwise(polygon) { + const v = polygon; + const n = polygon.length; + let noCW = true, noCCW = true; + let area = 0, prevX = v[n - 2], prevY = v[n - 1], currX = v[0], currY = v[1]; + for (let i = 2; i < n; i += 2) { + const nextX = v[i], nextY = v[i + 1]; + area += currX * nextY - nextX * currY; + const cross2 = (currX - prevX) * (nextY - currY) - (currY - prevY) * (nextX - currX); + noCCW = noCCW && cross2 <= 0; + noCW = noCW && cross2 >= 0; + prevX = currX; + prevY = currY; + currX = nextX; + currY = nextY; + } + area += currX * v[1] - v[0] * currY; + const cross = (currX - prevX) * (v[1] - currY) - (currY - prevY) * (v[0] - currX); + noCCW = noCCW && cross <= 0; + noCW = noCW && cross >= 0; + if (area >= 0) { + for (let i = 0, lastX = n - 2, half = n >> 1; i < half; i += 2) { + const x = v[i], y = v[i + 1]; + const other = lastX - i; + v[i] = v[other]; + v[i + 1] = v[other + 1]; + v[other] = x; + v[other + 1] = y; + } + return noCW; + } + return noCCW; + } + makeConvex(polygon) { + const n = polygon.length; + const v = polygon; + this.clipOutput.length = n; + const sorted = this.clipOutput; + sorted[0] = v[0]; + sorted[1] = v[1]; + for (let i = 2; i < n; i += 2) { + const x = v[i], y = v[i + 1]; + let p = i - 2; + for (; p >= 0 && (sorted[p] > x || sorted[p] === x && sorted[p + 1] > y); p -= 2) { + sorted[p + 2] = sorted[p]; + sorted[p + 3] = sorted[p + 1]; + } + sorted[p + 2] = x; + sorted[p + 3] = y; + } + v[0] = sorted[0]; + v[1] = sorted[1]; + v[2] = sorted[2]; + v[3] = sorted[3]; + let s = 4; + for (let i = 4; i < n; i += 2, s += 2) { + const x = sorted[i], y = sorted[i + 1]; + while ((v[s - 2] - v[s - 4]) * (y - v[s - 3]) - (v[s - 1] - v[s - 3]) * (x - v[s - 4]) >= 0) { + s -= 2; + if (s === 2) break; + } + v[s] = x; + v[s + 1] = y; + } + v[s] = sorted[n - 4]; + v[s + 1] = sorted[n - 3]; + const t = s; + s += 2; + for (let i = n - 6; i >= 0; i -= 2, s += 2) { + const x = sorted[i], y = sorted[i + 1]; + while ((v[s - 2] - v[s - 4]) * (y - v[s - 3]) - (v[s - 1] - v[s - 3]) * (x - v[s - 4]) >= 0) { + s -= 2; + if (s === t) break; + } + v[s] = x; + v[s + 1] = y; + } + polygon.length = s - 2; + } + }; + + // spine-core/src/SkeletonJson.ts + var SkeletonJson = class { + attachmentLoader; + /** Scales bone positions, image sizes, and translations as they are loaded. This allows different size images to be used at + * runtime than were used in Spine. + * + * See [Scaling](http://esotericsoftware.com/spine-loading-skeleton-data#Scaling) in the Spine Runtimes Guide. */ + scale = 1; + linkedMeshes = []; + constructor(attachmentLoader) { + this.attachmentLoader = attachmentLoader; + } + // biome-ignore lint/suspicious/noExplicitAny: it is any until we define a schema + readSkeletonData(json) { + const scale = this.scale; + const skeletonData = new SkeletonData(); + const root = typeof json === "string" ? JSON.parse(json) : json; + const skeletonMap = root.skeleton; + if (skeletonMap) { + skeletonData.hash = skeletonMap.hash; + skeletonData.version = skeletonMap.spine; + skeletonData.x = skeletonMap.x; + skeletonData.y = skeletonMap.y; + skeletonData.width = skeletonMap.width; + skeletonData.height = skeletonMap.height; + skeletonData.referenceScale = getValue(skeletonMap, "referenceScale", 100) * scale; + skeletonData.fps = skeletonMap.fps; + skeletonData.imagesPath = skeletonMap.images ?? null; + skeletonData.audioPath = skeletonMap.audio ?? null; + } + if (root.bones) { + for (let i = 0; i < root.bones.length; i++) { + const boneMap = root.bones[i]; + let parent = null; + const parentName = getValue(boneMap, "parent", null); + if (parentName) parent = skeletonData.findBone(parentName); + const data = new BoneData(skeletonData.bones.length, boneMap.name, parent); + data.length = getValue(boneMap, "length", 0) * scale; + const setup = data.setupPose; + setup.x = getValue(boneMap, "x", 0) * scale; + setup.y = getValue(boneMap, "y", 0) * scale; + setup.rotation = getValue(boneMap, "rotation", 0); + setup.scaleX = getValue(boneMap, "scaleX", 1); + setup.scaleY = getValue(boneMap, "scaleY", 1); + setup.shearX = getValue(boneMap, "shearX", 0); + setup.shearY = getValue(boneMap, "shearY", 0); + setup.inherit = Utils.enumValue(Inherit, getValue(boneMap, "inherit", "Normal")); + data.skinRequired = getValue(boneMap, "skin", false); + const color = getValue(boneMap, "color", null); + if (color) data.color.setFromString(color); + data.icon = getValue(boneMap, "icon", void 0); + data.iconSize = getValue(boneMap, "iconSize", 1); + data.iconRotation = getValue(boneMap, "iconRotation", 0); + skeletonData.bones.push(data); + } + } + if (root.slots) { + for (let i = 0; i < root.slots.length; i++) { + const slotMap = root.slots[i]; + const slotName = slotMap.name; + const boneData = skeletonData.findBone(slotMap.bone); + if (!boneData) throw new Error(`Couldn't find bone ${slotMap.bone} for slot ${slotName}`); + const data = new SlotData(skeletonData.slots.length, slotName, boneData); + const color = getValue(slotMap, "color", null); + if (color) data.setupPose.color.setFromString(color); + const dark = getValue(slotMap, "dark", null); + if (dark) data.setupPose.darkColor = Color.fromString(dark); + data.attachmentName = getValue(slotMap, "attachment", null); + data.blendMode = Utils.enumValue(BlendMode, getValue(slotMap, "blend", "normal")); + data.visible = getValue(slotMap, "visible", true); + skeletonData.slots.push(data); + } + } + if (root.constraints) { + for (const constraintMap of root.constraints) { + const name = constraintMap.name; + const skinRequired = getValue(constraintMap, "skin", false); + switch (getValue(constraintMap, "type", false)) { + case "ik": { + const data = new IkConstraintData(name); + data.skinRequired = skinRequired; + for (let ii = 0; ii < constraintMap.bones.length; ii++) { + const bone = skeletonData.findBone(constraintMap.bones[ii]); + if (!bone) throw new Error(`Couldn't find bone ${constraintMap.bones[ii]} for IK constraint ${name}.`); + data.bones.push(bone); + } + const targetName = constraintMap.target; + const target = skeletonData.findBone(targetName); + if (!target) throw new Error(`Couldn't find target bone ${targetName} for IK constraint ${name}.`); + data.target = target; + const scaleY = getValue(constraintMap, "scaleY", null); + if (scaleY != null) data.scaleYMode = Utils.enumValue(ScaleYMode, scaleY); + const setup = data.setupPose; + setup.mix = getValue(constraintMap, "mix", 1); + setup.softness = getValue(constraintMap, "softness", 0) * scale; + setup.bendDirection = getValue(constraintMap, "bendPositive", true) ? 1 : -1; + setup.compress = getValue(constraintMap, "compress", false); + setup.stretch = getValue(constraintMap, "stretch", false); + skeletonData.constraints.push(data); + break; + } + case "transform": { + const data = new TransformConstraintData(name); + data.skinRequired = skinRequired; + for (let ii = 0; ii < constraintMap.bones.length; ii++) { + const boneName = constraintMap.bones[ii]; + const bone = skeletonData.findBone(boneName); + if (!bone) throw new Error(`Couldn't find bone ${boneName} for transform constraint ${constraintMap.name}.`); + data.bones.push(bone); + } + const sourceName = constraintMap.source; + const source = skeletonData.findBone(sourceName); + if (!source) throw new Error(`Couldn't find source bone ${sourceName} for transform constraint ${constraintMap.name}.`); + data.source = source; + data.localSource = getValue(constraintMap, "localSource", false); + data.localTarget = getValue(constraintMap, "localTarget", false); + data.additive = getValue(constraintMap, "additive", false); + data.clamp = getValue(constraintMap, "clamp", false); + let rotate = false, x = false, y = false, scaleX = false, scaleY = false, shearY = false; + const fromEntries = Object.entries(getValue(constraintMap, "properties", {})); + for (const [name2, fromEntry] of fromEntries) { + const from = this.fromProperty(name2); + const fromScale = this.propertyScale(name2, scale); + from.offset = getValue(fromEntry, "offset", 0) * fromScale; + const toEntries = Object.entries(getValue(fromEntry, "to", {})); + for (const [name3, toEntry] of toEntries) { + let toScale = 1; + let to; + switch (name3) { + case "rotate": { + rotate = true; + to = new ToRotate(); + break; + } + case "x": { + x = true; + to = new ToX(); + toScale = scale; + break; + } + case "y": { + y = true; + to = new ToY(); + toScale = scale; + break; + } + case "scaleX": { + scaleX = true; + to = new ToScaleX(); + break; + } + case "scaleY": { + scaleY = true; + to = new ToScaleY(); + break; + } + case "shearY": { + shearY = true; + to = new ToShearY(); + break; + } + default: + throw new Error(`Invalid transform constraint to property: ${name3}`); + } + to.offset = getValue(toEntry, "offset", 0) * toScale; + to.max = getValue(toEntry, "max", 1) * toScale; + to.scale = getValue(toEntry, "scale", 1) * toScale / fromScale; + from.to.push(to); + } + if (from.to.length > 0) data.properties.push(from); + } + data.offsets[TransformConstraintData.ROTATION] = getValue(constraintMap, "rotation", 0); + data.offsets[TransformConstraintData.X] = getValue(constraintMap, "x", 0) * scale; + data.offsets[TransformConstraintData.Y] = getValue(constraintMap, "y", 0) * scale; + data.offsets[TransformConstraintData.SCALEX] = getValue(constraintMap, "scaleX", 0); + data.offsets[TransformConstraintData.SCALEY] = getValue(constraintMap, "scaleY", 0); + data.offsets[TransformConstraintData.SHEARY] = getValue(constraintMap, "shearY", 0); + const setup = data.setupPose; + if (rotate) setup.mixRotate = getValue(constraintMap, "mixRotate", 1); + if (x) setup.mixX = getValue(constraintMap, "mixX", 1); + if (y) setup.mixY = getValue(constraintMap, "mixY", setup.mixX); + if (scaleX) setup.mixScaleX = getValue(constraintMap, "mixScaleX", 1); + if (scaleY) setup.mixScaleY = getValue(constraintMap, "mixScaleY", setup.mixScaleX); + if (shearY) setup.mixShearY = getValue(constraintMap, "mixShearY", 1); + skeletonData.constraints.push(data); + break; + } + case "path": { + const data = new PathConstraintData(name); + data.skinRequired = skinRequired; + for (let ii = 0; ii < constraintMap.bones.length; ii++) { + const boneName = constraintMap.bones[ii]; + const bone = skeletonData.findBone(boneName); + if (!bone) throw new Error(`Couldn't find bone ${boneName} for path constraint ${constraintMap.name}.`); + data.bones.push(bone); + } + const slotName = constraintMap.slot; + const slot = skeletonData.findSlot(slotName); + if (!slot) throw new Error(`Couldn't find slot ${slotName} for path constraint ${constraintMap.name}.`); + data.slot = slot; + data.positionMode = Utils.enumValue(PositionMode, getValue(constraintMap, "positionMode", "Percent")); + data.spacingMode = Utils.enumValue(SpacingMode, getValue(constraintMap, "spacingMode", "Length")); + data.rotateMode = Utils.enumValue(RotateMode, getValue(constraintMap, "rotateMode", "Tangent")); + data.offsetRotation = getValue(constraintMap, "rotation", 0); + const setup = data.setupPose; + setup.position = getValue(constraintMap, "position", 0); + if (data.positionMode === 0 /* Fixed */) setup.position *= scale; + setup.spacing = getValue(constraintMap, "spacing", 0); + if (data.spacingMode === 0 /* Length */ || data.spacingMode === 1 /* Fixed */) setup.spacing *= scale; + setup.mixRotate = getValue(constraintMap, "mixRotate", 1); + setup.mixX = getValue(constraintMap, "mixX", 1); + setup.mixY = getValue(constraintMap, "mixY", setup.mixX); + skeletonData.constraints.push(data); + break; + } + case "physics": { + const data = new PhysicsConstraintData(name); + data.skinRequired = skinRequired; + const boneName = constraintMap.bone; + const bone = skeletonData.findBone(boneName); + if (bone == null) throw new Error(`Physics bone not found: ${boneName}`); + data.bone = bone; + data.x = getValue(constraintMap, "x", 0); + data.y = getValue(constraintMap, "y", 0); + data.rotate = getValue(constraintMap, "rotate", 0); + data.scaleX = getValue(constraintMap, "scaleX", 0); + const scaleY = getValue(constraintMap, "scaleY", null); + if (scaleY != null) data.scaleYMode = Utils.enumValue(ScaleYMode, scaleY); + data.shearX = getValue(constraintMap, "shearX", 0); + data.limit = getValue(constraintMap, "limit", 5e3) * scale; + data.step = 1 / getValue(constraintMap, "fps", 60); + const setup = data.setupPose; + setup.inertia = getValue(constraintMap, "inertia", 0.5); + setup.strength = getValue(constraintMap, "strength", 100); + setup.damping = getValue(constraintMap, "damping", 0.85); + setup.massInverse = 1 / getValue(constraintMap, "mass", 1); + setup.wind = getValue(constraintMap, "wind", 0); + setup.gravity = getValue(constraintMap, "gravity", 0); + setup.mix = getValue(constraintMap, "mix", 1); + data.inertiaGlobal = getValue(constraintMap, "inertiaGlobal", false); + data.strengthGlobal = getValue(constraintMap, "strengthGlobal", false); + data.dampingGlobal = getValue(constraintMap, "dampingGlobal", false); + data.massGlobal = getValue(constraintMap, "massGlobal", false); + data.windGlobal = getValue(constraintMap, "windGlobal", false); + data.gravityGlobal = getValue(constraintMap, "gravityGlobal", false); + data.mixGlobal = getValue(constraintMap, "mixGlobal", false); + skeletonData.constraints.push(data); + break; + } + case "slider": { + const data = new SliderData(name); + data.skinRequired = skinRequired; + data.additive = getValue(constraintMap, "additive", false); + data.loop = getValue(constraintMap, "loop", false); + data.setupPose.mix = getValue(constraintMap, "mix", 1); + const boneName = constraintMap.bone; + if (boneName) { + data.bone = skeletonData.findBone(boneName); + if (!data.bone) throw new Error(`Slider bone not found: ${boneName}`); + const property = constraintMap.property; + data.property = this.fromProperty(property); + const propertyScale = this.propertyScale(property, scale); + data.property.offset = getValue(constraintMap, "from", 0) * propertyScale; + data.offset = getValue(constraintMap, "to", 0); + data.scale = getValue(constraintMap, "scale", 1) / propertyScale; + data.max = getValue(constraintMap, "max", 0); + data.local = getValue(constraintMap, "local", false); + } else + data.setupPose.time = getValue(constraintMap, "time", 0); + skeletonData.constraints.push(data); + break; + } + } + } + } + if (root.skins) { + for (let i = 0; i < root.skins.length; i++) { + const skinMap = root.skins[i]; + const skin = new Skin(skinMap.name); + if (skinMap.bones) { + for (let ii = 0; ii < skinMap.bones.length; ii++) { + const boneName = skinMap.bones[ii]; + const bone = skeletonData.findBone(boneName); + if (!bone) throw new Error(`Couldn't find bone ${boneName} for skin ${skinMap.name}.`); + skin.bones.push(bone); + } + } + if (skinMap.ik) { + for (let ii = 0; ii < skinMap.ik.length; ii++) { + const constraintName = skinMap.ik[ii]; + const constraint = skeletonData.findConstraint(constraintName, IkConstraintData); + if (!constraint) throw new Error(`Couldn't find IK constraint ${constraintName} for skin ${skinMap.name}.`); + skin.constraints.push(constraint); + } + } + if (skinMap.transform) { + for (let ii = 0; ii < skinMap.transform.length; ii++) { + const constraintName = skinMap.transform[ii]; + const constraint = skeletonData.findConstraint(constraintName, TransformConstraintData); + if (!constraint) throw new Error(`Couldn't find transform constraint ${constraintName} for skin ${skinMap.name}.`); + skin.constraints.push(constraint); + } + } + if (skinMap.path) { + for (let ii = 0; ii < skinMap.path.length; ii++) { + const constraintName = skinMap.path[ii]; + const constraint = skeletonData.findConstraint(constraintName, PathConstraintData); + if (!constraint) throw new Error(`Couldn't find path constraint ${constraintName} for skin ${skinMap.name}.`); + skin.constraints.push(constraint); + } + } + if (skinMap.physics) { + for (let ii = 0; ii < skinMap.physics.length; ii++) { + const constraintName = skinMap.physics[ii]; + const constraint = skeletonData.findConstraint(constraintName, PhysicsConstraintData); + if (!constraint) throw new Error(`Couldn't find physics constraint ${constraintName} for skin ${skinMap.name}.`); + skin.constraints.push(constraint); + } + } + if (skinMap.slider) { + for (let ii = 0; ii < skinMap.slider.length; ii++) { + const constraintName = skinMap.slider[ii]; + const constraint = skeletonData.findConstraint(constraintName, SliderData); + if (!constraint) throw new Error(`Couldn't find slider constraint ${constraintName} for skin ${skinMap.name}.`); + skin.constraints.push(constraint); + } + } + for (const slotName in skinMap.attachments) { + const slot = skeletonData.findSlot(slotName); + if (!slot) throw new Error(`Couldn't find skin slot ${slotName} for skin ${skinMap.name}.`); + const slotMap = skinMap.attachments[slotName]; + for (const entryName in slotMap) { + const attachment = this.readAttachment(slotMap[entryName], skin, slot.index, entryName, skeletonData); + if (attachment) skin.setAttachment(slot.index, entryName, attachment); + } + } + skeletonData.skins.push(skin); + if (skin.name === "default") skeletonData.defaultSkin = skin; + } + } + for (let i = 0, n = this.linkedMeshes.length; i < n; i++) { + const linkedMesh = this.linkedMeshes[i]; + const skin = !linkedMesh.skin ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin); + if (!skin) throw new Error(`Skin not found: ${linkedMesh.skin}`); + const source = skin.getAttachment(linkedMesh.sourceIndex, linkedMesh.source); + if (!source) throw new Error(`Source mesh not found: ${linkedMesh.source}`); + linkedMesh.mesh.timelineAttachment = linkedMesh.inheritTimelines ? source : linkedMesh.mesh; + linkedMesh.mesh.setSourceMesh(source); + linkedMesh.mesh.updateSequence(); + outer: + if (linkedMesh.inheritTimelines && linkedMesh.slotIndex !== linkedMesh.sourceIndex) { + const slots = source.timelineSlots; + for (const existing of slots) + if (existing === linkedMesh.slotIndex) break outer; + const newSlots = [...slots]; + newSlots[slots.length] = linkedMesh.slotIndex; + source.timelineSlots = newSlots; + } + } + this.linkedMeshes.length = 0; + if (root.events) { + for (const eventName in root.events) { + const eventMap = root.events[eventName]; + const data = new EventData(eventName); + const setup = data.setupPose; + setup.intValue = getValue(eventMap, "int", 0); + setup.floatValue = getValue(eventMap, "float", 0); + setup.stringValue = getValue(eventMap, "string", ""); + data._audioPath = getValue(eventMap, "audio", null); + if (data.audioPath) { + setup.volume = getValue(eventMap, "volume", setup.volume); + setup.balance = getValue(eventMap, "balance", setup.balance); + } + skeletonData.events.push(data); + } + } + if (root.animations) { + for (const animationName in root.animations) { + const animationMap = root.animations[animationName]; + this.readAnimation(animationMap, animationName, skeletonData); + } + } + if (root.constraints) { + for (const animationName in root.constraints) { + const animationMap = root.constraints[animationName]; + if (animationMap.type === "slider") { + const data = skeletonData.findConstraint(animationMap.name, SliderData); + const animationName2 = animationMap.animation; + const animation = skeletonData.findAnimation(animationName2); + if (!animation) throw new Error(`Slider animation not found: ${animationName2}`); + data.animation = animation; + } + } + } + return skeletonData; + } + fromProperty(type) { + let from; + switch (type) { + case "rotate": + from = new FromRotate(); + break; + case "x": + from = new FromX(); + break; + case "y": + from = new FromY(); + break; + case "scaleX": + from = new FromScaleX(); + break; + case "scaleY": + from = new FromScaleY(); + break; + case "shearY": + from = new FromShearY(); + break; + default: + throw new Error(`Invalid transform constraint from property: ${type}`); + } + return from; + } + propertyScale(type, scale) { + switch (type) { + case "x": + case "y": + return scale; + default: + return 1; + } + } + // biome-ignore lint/suspicious/noExplicitAny: it is any until we define a schema + readAttachment(map, skin, slotIndex, placeholder, skeletonData) { + const scale = this.scale; + const name = getValue(map, "name", placeholder); + switch (getValue(map, "type", "region")) { + case "region": { + const path = getValue(map, "path", name); + const sequence = this.readSequence(getValue(map, "sequence", null)); + const region = this.attachmentLoader.newRegionAttachment(skin, placeholder, name, path, sequence); + if (!region) return null; + region.path = path; + region.x = getValue(map, "x", 0) * scale; + region.y = getValue(map, "y", 0) * scale; + region.scaleX = getValue(map, "scaleX", 1); + region.scaleY = getValue(map, "scaleY", 1); + region.rotation = getValue(map, "rotation", 0); + region.width = map.width * scale; + region.height = map.height * scale; + const color = getValue(map, "color", null); + if (color) region.color.setFromString(color); + region.updateSequence(); + return region; + } + case "boundingbox": { + const box = this.attachmentLoader.newBoundingBoxAttachment(skin, placeholder, name); + if (!box) return null; + this.readVertices(map, box, map.vertexCount << 1); + const color = getValue(map, "color", null); + if (color) box.color.setFromString(color); + return box; + } + case "mesh": + case "linkedmesh": { + const path = getValue(map, "path", name); + const sequence = this.readSequence(getValue(map, "sequence", null)); + const mesh = this.attachmentLoader.newMeshAttachment(skin, placeholder, name, path, sequence); + if (!mesh) return null; + mesh.path = path; + const color = getValue(map, "color", null); + if (color) mesh.color.setFromString(color); + mesh.width = getValue(map, "width", 0) * scale; + mesh.height = getValue(map, "height", 0) * scale; + const source = getValue(map, "source", null); + if (source) { + let sourceIndex = slotIndex; + const slot = getValue(map, "slot", null); + if (slot) { + const sourceSlot = skeletonData.findSlot(slot); + if (!sourceSlot) throw new Error(`Source mesh slot not found: ${slot}`); + sourceIndex = sourceSlot.index; + } + this.linkedMeshes.push(new LinkedMesh2( + mesh, + getValue(map, "skin", null), + slotIndex, + sourceIndex, + source, + getValue(map, "timelines", true) + )); + return mesh; + } + const uvs = map.uvs; + this.readVertices(map, mesh, uvs.length); + mesh.triangles = map.triangles; + mesh.regionUVs = uvs; + mesh.edges = getValue(map, "edges", null); + mesh.hullLength = getValue(map, "hull", 0) * 2; + mesh.updateSequence(); + return mesh; + } + case "path": { + const path = this.attachmentLoader.newPathAttachment(skin, placeholder, name); + if (!path) return null; + path.closed = getValue(map, "closed", false); + path.constantSpeed = getValue(map, "constantSpeed", true); + const vertexCount = map.vertexCount; + this.readVertices(map, path, vertexCount << 1); + const lengths = Utils.newArray(vertexCount / 3, 0); + for (let i = 0; i < map.lengths.length; i++) + lengths[i] = map.lengths[i] * scale; + path.lengths = lengths; + const color = getValue(map, "color", null); + if (color) path.color.setFromString(color); + return path; + } + case "point": { + const point = this.attachmentLoader.newPointAttachment(skin, placeholder, name); + if (!point) return null; + point.x = getValue(map, "x", 0) * scale; + point.y = getValue(map, "y", 0) * scale; + point.rotation = getValue(map, "rotation", 0); + const color = getValue(map, "color", null); + if (color) point.color.setFromString(color); + return point; + } + case "clipping": { + const clip = this.attachmentLoader.newClippingAttachment(skin, placeholder, name); + if (!clip) return null; + const end = getValue(map, "end", null); + if (end) clip.endSlot = skeletonData.findSlot(end); + clip.convex = getValue(map, "convex", false); + clip.inverse = getValue(map, "inverse", false); + const vertexCount = map.vertexCount; + this.readVertices(map, clip, vertexCount << 1); + const color = getValue(map, "color", null); + if (color) clip.color.setFromString(color); + return clip; + } + } + return null; + } + readSequence(map) { + if (map == null) return new Sequence(1, false); + const sequence = new Sequence(getValue(map, "count", 0), true); + sequence.start = getValue(map, "start", 1); + sequence.digits = getValue(map, "digits", 0); + sequence.setupIndex = getValue(map, "setup", 0); + return sequence; + } + // biome-ignore lint/suspicious/noExplicitAny: it is any until we define a schema + readVertices(map, attachment, verticesLength) { + const scale = this.scale; + attachment.worldVerticesLength = verticesLength; + const vertices = map.vertices; + if (verticesLength === vertices.length) { + const scaledVertices = Utils.toFloatArray(vertices); + if (scale !== 1) { + for (let i = 0, n = vertices.length; i < n; i++) + scaledVertices[i] *= scale; + } + attachment.vertices = scaledVertices; + return; + } + const weights = []; + const bones = []; + for (let i = 0, n = vertices.length; i < n; ) { + const boneCount = vertices[i++]; + bones.push(boneCount); + for (let nn = i + boneCount * 4; i < nn; i += 4) { + bones.push(vertices[i]); + weights.push(vertices[i + 1] * scale); + weights.push(vertices[i + 2] * scale); + weights.push(vertices[i + 3]); + } + } + attachment.bones = bones; + attachment.vertices = Utils.toFloatArray(weights); + } + // biome-ignore lint/suspicious/noExplicitAny: it is any untile we define a schema + readAnimation(map, name, skeletonData) { + const scale = this.scale; + const timelines = []; + if (map.slots) { + for (const slotName in map.slots) { + const slotMap = map.slots[slotName]; + const slot = skeletonData.findSlot(slotName); + if (!slot) throw new Error(`Slot not found: ${slotName}`); + const slotIndex = slot.index; + for (const timelineName in slotMap) { + const timelineMap = slotMap[timelineName]; + if (!timelineMap) continue; + const frames = timelineMap.length; + switch (timelineName) { + case "attachment": { + const timeline = new AttachmentTimeline(frames, slotIndex); + for (let frame = 0; frame < frames; frame++) { + const keyMap = timelineMap[frame]; + timeline.setFrame(frame, getValue(keyMap, "time", 0), getValue(keyMap, "name", null)); + } + timelines.push(timeline); + break; + } + case "rgba": { + const timeline = new RGBATimeline(frames, frames << 2, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color2 = Color.fromString(keyMap.color); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color2.r, color2.g, color2.b, color2.a); + const nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + const time2 = getValue(nextMap, "time", 0); + const newColor = Color.fromString(nextMap.color); + const curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color2.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color2.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color2.b, newColor.b, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, color2.a, newColor.a, 1); + } + time = time2; + color2 = newColor; + keyMap = nextMap; + } + timelines.push(timeline); + break; + } + case "rgb": { + const timeline = new RGBTimeline(frames, frames * 3, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color2 = Color.fromString(keyMap.color); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color2.r, color2.g, color2.b); + const nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + const time2 = getValue(nextMap, "time", 0); + const newColor = Color.fromString(nextMap.color); + const curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color2.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color2.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color2.b, newColor.b, 1); + } + time = time2; + color2 = newColor; + keyMap = nextMap; + } + timelines.push(timeline); + break; + } + case "alpha": { + readTimeline12(timelines, timelineMap, new AlphaTimeline(frames, frames, slotIndex), 0, 1); + break; + } + case "rgba2": { + const timeline = new RGBA2Timeline(frames, frames * 7, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color2 = Color.fromString(keyMap.light); + let color22 = Color.fromString(keyMap.dark); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color2.r, color2.g, color2.b, color2.a, color22.r, color22.g, color22.b); + const nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + const time2 = getValue(nextMap, "time", 0); + const newColor = Color.fromString(nextMap.light); + const newColor2 = Color.fromString(nextMap.dark); + const curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color2.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color2.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color2.b, newColor.b, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, color2.a, newColor.a, 1); + bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, color22.r, newColor2.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, color22.g, newColor2.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 6, time, time2, color22.b, newColor2.b, 1); + } + time = time2; + color2 = newColor; + color22 = newColor2; + keyMap = nextMap; + } + timelines.push(timeline); + break; + } + case "rgb2": { + const timeline = new RGB2Timeline(frames, frames * 6, slotIndex); + let keyMap = timelineMap[0]; + let time = getValue(keyMap, "time", 0); + let color2 = Color.fromString(keyMap.light); + let color22 = Color.fromString(keyMap.dark); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, color2.r, color2.g, color2.b, color22.r, color22.g, color22.b); + const nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + const time2 = getValue(nextMap, "time", 0); + const newColor = Color.fromString(nextMap.light); + const newColor2 = Color.fromString(nextMap.dark); + const curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, color2.r, newColor.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, color2.g, newColor.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, color2.b, newColor.b, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, color22.r, newColor2.r, 1); + bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, color22.g, newColor2.g, 1); + bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, color22.b, newColor2.b, 1); + } + time = time2; + color2 = newColor; + color22 = newColor2; + keyMap = nextMap; + } + timelines.push(timeline); + break; + } + default: + throw new Error(`Invalid timeline type for a slot: ${timelineMap.name} (${slotMap.name})`); + } + } + } + } + if (map.bones) { + for (const boneName in map.bones) { + const boneMap = map.bones[boneName]; + const bone = skeletonData.findBone(boneName); + if (!bone) throw new Error(`Bone not found: ${boneName}`); + const boneIndex = bone.index; + for (const timelineName in boneMap) { + const timelineMap = boneMap[timelineName]; + const frames = timelineMap.length; + if (frames === 0) continue; + switch (timelineName) { + case "rotate": + readTimeline12(timelines, timelineMap, new RotateTimeline(frames, frames, boneIndex), 0, 1); + break; + case "translate": + readTimeline22(timelines, timelineMap, new TranslateTimeline(frames, frames << 1, boneIndex), "x", "y", 0, scale); + break; + case "translatex": + readTimeline12(timelines, timelineMap, new TranslateXTimeline(frames, frames, boneIndex), 0, scale); + break; + case "translatey": + readTimeline12(timelines, timelineMap, new TranslateYTimeline(frames, frames, boneIndex), 0, scale); + break; + case "scale": + readTimeline22(timelines, timelineMap, new ScaleTimeline(frames, frames << 1, boneIndex), "x", "y", 1, 1); + break; + case "scalex": + readTimeline12(timelines, timelineMap, new ScaleXTimeline(frames, frames, boneIndex), 1, 1); + break; + case "scaley": + readTimeline12(timelines, timelineMap, new ScaleYTimeline(frames, frames, boneIndex), 1, 1); + break; + case "shear": + readTimeline22(timelines, timelineMap, new ShearTimeline(frames, frames << 1, boneIndex), "x", "y", 0, 1); + break; + case "shearx": + readTimeline12(timelines, timelineMap, new ShearXTimeline(frames, frames, boneIndex), 0, 1); + break; + case "sheary": + readTimeline12(timelines, timelineMap, new ShearYTimeline(frames, frames, boneIndex), 0, 1); + break; + case "inherit": { + const timeline = new InheritTimeline(frames, bone.index); + for (let frame = 0; frame < timelineMap.length; frame++) { + const aFrame = timelineMap[frame]; + timeline.setFrame(frame, getValue(aFrame, "time", 0), Utils.enumValue(Inherit, getValue(aFrame, "inherit", "Normal"))); + } + timelines.push(timeline); + break; + } + default: + throw new Error(`Invalid timeline type for a bone: ${timelineMap.name} (${boneMap.name})`); + } + } + } + } + if (map.ik) { + for (const constraintName in map.ik) { + const constraintMap = map.ik[constraintName]; + let keyMap = constraintMap[0]; + if (!keyMap) continue; + const constraint = skeletonData.findConstraint(constraintName, IkConstraintData); + if (!constraint) throw new Error(`IK Constraint not found: ${constraintName}`); + const timeline = new IkConstraintTimeline( + constraintMap.length, + constraintMap.length << 1, + skeletonData.constraints.indexOf(constraint) + ); + let time = getValue(keyMap, "time", 0); + let mix = getValue(keyMap, "mix", 1); + let softness = getValue(keyMap, "softness", 0) * scale; + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mix, softness, getValue(keyMap, "bendPositive", true) ? 1 : -1, getValue(keyMap, "compress", false), getValue(keyMap, "stretch", false)); + const nextMap = constraintMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + const time2 = getValue(nextMap, "time", 0); + const mix2 = getValue(nextMap, "mix", 1); + const softness2 = getValue(nextMap, "softness", 0) * scale; + const curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mix, mix2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, softness, softness2, scale); + } + time = time2; + mix = mix2; + softness = softness2; + keyMap = nextMap; + } + timelines.push(timeline); + } + } + if (map.transform) { + for (const constraintName in map.transform) { + const timelineMap = map.transform[constraintName]; + let keyMap = timelineMap[0]; + if (!keyMap) continue; + const constraint = skeletonData.findConstraint(constraintName, TransformConstraintData); + if (!constraint) throw new Error(`Transform constraint not found: ${constraintName}`); + const timeline = new TransformConstraintTimeline( + timelineMap.length, + timelineMap.length * 6, + skeletonData.constraints.indexOf(constraint) + ); + let time = getValue(keyMap, "time", 0); + let mixRotate = getValue(keyMap, "mixRotate", 1); + let mixX = getValue(keyMap, "mixX", 1), mixY = getValue(keyMap, "mixY", mixX); + let mixScaleX = getValue(keyMap, "mixScaleX", 1), mixScaleY = getValue(keyMap, "mixScaleY", 1); + let mixShearY = getValue(keyMap, "mixShearY", 1); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY); + const nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + const time2 = getValue(nextMap, "time", 0); + const mixRotate2 = getValue(nextMap, "mixRotate", 1); + const mixX2 = getValue(nextMap, "mixX", 1), mixY2 = getValue(nextMap, "mixY", mixX2); + const mixScaleX2 = getValue(nextMap, "mixScaleX", 1), mixScaleY2 = getValue(nextMap, "mixScaleY", 1); + const mixShearY2 = getValue(nextMap, "mixShearY", 1); + const curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mixRotate, mixRotate2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, mixX, mixX2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, mixY, mixY2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 3, time, time2, mixScaleX, mixScaleX2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 4, time, time2, mixScaleY, mixScaleY2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 5, time, time2, mixShearY, mixShearY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + mixScaleX = mixScaleX2; + mixScaleY = mixScaleY2; + mixShearY = mixShearY2; + keyMap = nextMap; + } + timelines.push(timeline); + } + } + if (map.path) { + for (const constraintName in map.path) { + const constraintMap = map.path[constraintName]; + const constraint = skeletonData.findConstraint(constraintName, PathConstraintData); + if (!constraint) throw new Error(`Path constraint not found: ${constraintName}`); + const index = skeletonData.constraints.indexOf(constraint); + for (const timelineName in constraintMap) { + const timelineMap = constraintMap[timelineName]; + let keyMap = timelineMap[0]; + if (!keyMap) continue; + const frames = timelineMap.length; + switch (timelineName) { + case "position": { + const timeline = new PathConstraintPositionTimeline(frames, frames, index); + readTimeline12(timelines, timelineMap, timeline, 0, constraint.positionMode === 0 /* Fixed */ ? scale : 1); + break; + } + case "spacing": { + const timeline = new PathConstraintSpacingTimeline(frames, frames, index); + readTimeline12(timelines, timelineMap, timeline, 0, constraint.spacingMode === 0 /* Length */ || constraint.spacingMode === 1 /* Fixed */ ? scale : 1); + break; + } + case "mix": { + const timeline = new PathConstraintMixTimeline(frames, frames * 3, index); + let time = getValue(keyMap, "time", 0); + let mixRotate = getValue(keyMap, "mixRotate", 1); + let mixX = getValue(keyMap, "mixX", 1); + let mixY = getValue(keyMap, "mixY", mixX); + for (let frame = 0, bezier = 0; ; frame++) { + timeline.setFrame(frame, time, mixRotate, mixX, mixY); + const nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + const time2 = getValue(nextMap, "time", 0); + const mixRotate2 = getValue(nextMap, "mixRotate", 1); + const mixX2 = getValue(nextMap, "mixX", 1); + const mixY2 = getValue(nextMap, "mixY", mixX2); + const curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, mixRotate, mixRotate2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, mixX, mixX2, 1); + bezier = readCurve(curve, timeline, bezier, frame, 2, time, time2, mixY, mixY2, 1); + } + time = time2; + mixRotate = mixRotate2; + mixX = mixX2; + mixY = mixY2; + keyMap = nextMap; + } + timelines.push(timeline); + break; + } + } + } + } + } + if (map.physics) { + for (const constraintName in map.physics) { + const constraintMap = map.physics[constraintName]; + let index = -1; + if (constraintName.length > 0) { + const constraint = skeletonData.findConstraint(constraintName, PhysicsConstraintData); + if (!constraint) throw new Error(`Physics constraint not found: ${constraintName}`); + index = skeletonData.constraints.indexOf(constraint); + } + for (const timelineName in constraintMap) { + const timelineMap = constraintMap[timelineName]; + let keyMap = timelineMap[0]; + if (!keyMap) continue; + const frames = timelineMap.length; + let timeline; + let defaultValue = 0; + if (timelineName === "reset") { + const resetTimeline = new PhysicsConstraintResetTimeline(frames, index); + for (let frame = 0; keyMap != null; keyMap = timelineMap[frame + 1], frame++) + resetTimeline.setFrame(frame, getValue(keyMap, "time", 0)); + timelines.push(resetTimeline); + continue; + } + switch (timelineName) { + case "inertia": + timeline = new PhysicsConstraintInertiaTimeline(frames, frames, index); + break; + case "strength": + timeline = new PhysicsConstraintStrengthTimeline(frames, frames, index); + break; + case "damping": + timeline = new PhysicsConstraintDampingTimeline(frames, frames, index); + break; + case "mass": + timeline = new PhysicsConstraintMassTimeline(frames, frames, index); + break; + case "wind": + timeline = new PhysicsConstraintWindTimeline(frames, frames, index); + break; + case "gravity": + timeline = new PhysicsConstraintGravityTimeline(frames, frames, index); + break; + case "mix": { + defaultValue = 1; + timeline = new PhysicsConstraintMixTimeline(frames, frames, index); + break; + } + default: + continue; + } + readTimeline12(timelines, timelineMap, timeline, defaultValue, 1); + } + } + } + if (map.slider) { + for (const constraintName in map.slider) { + const constraintMap = map.slider[constraintName]; + const constraint = skeletonData.findConstraint(constraintName, SliderData); + if (!constraint) throw new Error(`Slider not found: ${constraintName}`); + const index = skeletonData.constraints.indexOf(constraint); + for (const timelineName in constraintMap) { + const timelineMap = constraintMap[timelineName]; + const keyMap = timelineMap[0]; + if (!keyMap) continue; + const frames = timelineMap.length; + switch (timelineName) { + case "time": + readTimeline12(timelines, timelineMap, new SliderTimeline(frames, frames, index), 1, 1); + break; + case "mix": + readTimeline12(timelines, timelineMap, new SliderMixTimeline(frames, frames, index), 1, 1); + break; + } + } + } + } + if (map.attachments) { + for (const attachmentsName in map.attachments) { + const attachmentsMap = map.attachments[attachmentsName]; + const skin = skeletonData.findSkin(attachmentsName); + if (!skin) throw new Error(`Skin not found: ${attachmentsName}`); + for (const slotMapName in attachmentsMap) { + const slotMap = attachmentsMap[slotMapName]; + const slot = skeletonData.findSlot(slotMapName); + if (!slot) throw new Error(`Attachment slot not found: ${slotMapName}`); + const slotIndex = slot.index; + for (const attachmentMapName in slotMap) { + const attachmentMap = slotMap[attachmentMapName]; + const attachment = skin.getAttachment(slotIndex, attachmentMapName); + if (!attachment) throw new Error(`Timeline attachment not found: ${attachmentMapName}`); + for (const timelineMapName in attachmentMap) { + const timelineMap = attachmentMap[timelineMapName]; + let keyMap = timelineMap[0]; + if (!keyMap) continue; + if (timelineMapName === "deform") { + const weighted = attachment.bones; + const vertices = attachment.vertices; + const deformLength = weighted ? vertices.length / 3 * 2 : vertices.length; + const timeline = new DeformTimeline(timelineMap.length, timelineMap.length, slotIndex, attachment); + let time = getValue(keyMap, "time", 0); + for (let frame = 0, bezier = 0; ; frame++) { + let deform; + const verticesValue = getValue(keyMap, "vertices", null); + if (!verticesValue) + deform = weighted ? Utils.newFloatArray(deformLength) : vertices; + else { + deform = Utils.newFloatArray(deformLength); + const start = getValue(keyMap, "offset", 0); + Utils.arrayCopy(verticesValue, 0, deform, start, verticesValue.length); + if (scale !== 1) { + for (let i = start, n = i + verticesValue.length; i < n; i++) + deform[i] *= scale; + } + if (!weighted) { + for (let i = 0; i < deformLength; i++) + deform[i] += vertices[i]; + } + } + timeline.setFrame(frame, time, deform); + const nextMap = timelineMap[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + break; + } + const time2 = getValue(nextMap, "time", 0); + const curve = keyMap.curve; + if (curve) bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, 0, 1, 1); + time = time2; + keyMap = nextMap; + } + timelines.push(timeline); + } else if (timelineMapName === "sequence") { + const timeline = new SequenceTimeline(timelineMap.length, slotIndex, attachment); + let lastDelay = 0; + for (let frame = 0; frame < timelineMap.length; frame++) { + const delay = getValue(keyMap, "delay", lastDelay); + const time = getValue(keyMap, "time", 0); + const mode = SequenceMode[getValue(keyMap, "mode", "hold")]; + const index = getValue(keyMap, "index", 0); + timeline.setFrame(frame, time, mode, index, delay); + lastDelay = delay; + keyMap = timelineMap[frame + 1]; + } + timelines.push(timeline); + } + } + } + } + } + } + if (map.drawOrder) { + const timeline = new DrawOrderTimeline(map.drawOrder.length); + const slotCount = skeletonData.slots.length; + let frame = 0; + for (const drawOrderMap of map.drawOrder) { + timeline.setFrame(frame++, getValue(drawOrderMap, "time", 0), readDrawOrder2(skeletonData, drawOrderMap, slotCount, null)); + } + timelines.push(timeline); + } + if (map.drawOrderFolder) { + for (const timelineMap of map.drawOrderFolder) { + const slotEntries = getValue(timelineMap, "slots", []); + const folderSlots = new Array(slotEntries.length); + let ii = 0; + for (const slotEntry of slotEntries) { + const slot = skeletonData.findSlot(slotEntry); + if (!slot) throw new Error(`Draw order folder slot not found: ${slotEntry}`); + folderSlots[ii++] = slot.index; + } + const drawOrderFolderEntries = getValue(timelineMap, "keys", []); + const timeline = new DrawOrderFolderTimeline(drawOrderFolderEntries.length, folderSlots, skeletonData.slots.length); + let frame = 0; + for (const drawOrderFolderMap of drawOrderFolderEntries) { + timeline.setFrame(frame++, getValue(drawOrderFolderMap, "time", 0), readDrawOrder2(skeletonData, drawOrderFolderMap, folderSlots.length, folderSlots)); + } + timelines.push(timeline); + } + } + if (map.events) { + const timeline = new EventTimeline(map.events.length); + let frame = 0; + for (let i = 0; i < map.events.length; i++, frame++) { + const eventMap = map.events[i]; + const data = skeletonData.findEvent(eventMap.name); + if (!data) throw new Error(`Event not found: ${eventMap.name}`); + const setup = data.setupPose; + const event = new Event(Utils.toSinglePrecision(getValue(eventMap, "time", 0)), data); + event.intValue = getValue(eventMap, "int", setup.intValue); + event.floatValue = getValue(eventMap, "float", setup.floatValue); + event.stringValue = getValue(eventMap, "string", setup.stringValue); + if (event.data.audioPath) { + event.volume = getValue(eventMap, "volume", setup.volume); + event.balance = getValue(eventMap, "balance", setup.volume); + } + timeline.setFrame(frame, event); + } + timelines.push(timeline); + } + let duration = 0; + for (let i = 0, n = timelines.length; i < n; i++) + duration = Math.max(duration, timelines[i].getDuration()); + const animation = new Animation(name, timelines, duration); + const color = getValue(map, "color", null); + if (color !== null) animation.color.setFromString(color); + skeletonData.animations.push(animation); + } + }; + var LinkedMesh2 = class { + source; + skin; + slotIndex; + sourceIndex; + mesh; + inheritTimelines; + constructor(mesh, skin, slotIndex, sourceIndex, source, inheritTimelines) { + this.mesh = mesh; + this.skin = skin; + this.slotIndex = slotIndex; + this.sourceIndex = sourceIndex; + this.source = source; + this.inheritTimelines = inheritTimelines; + } + }; + function readTimeline12(timelines, keys, timeline, defaultValue, scale) { + let keyMap = keys[0]; + let time = keyMap.time ?? 0; + let value = (keyMap.value ?? defaultValue) * scale; + let bezier = 0; + for (let frame = 0; ; frame++) { + timeline.setFrame(frame, time, value); + const nextMap = keys[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + timelines.push(timeline); + return; + } + const time2 = nextMap.time ?? 0; + const value2 = (nextMap.value ?? defaultValue) * scale; + if (keyMap.curve) bezier = readCurve(keyMap.curve, timeline, bezier, frame, 0, time, time2, value, value2, scale); + time = time2; + value = value2; + keyMap = nextMap; + } + } + function readTimeline22(timelines, keys, timeline, name1, name2, defaultValue, scale) { + let keyMap = keys[0]; + let time = keyMap.time ?? 0; + let value1 = (keyMap[name1] ?? defaultValue) * scale; + let value2 = (keyMap[name2] ?? defaultValue) * scale; + let bezier = 0; + for (let frame = 0; ; frame++) { + timeline.setFrame(frame, time, value1, value2); + const nextMap = keys[frame + 1]; + if (!nextMap) { + timeline.shrink(bezier); + timelines.push(timeline); + return; + } + const time2 = nextMap.time ?? 0; + const nvalue1 = (nextMap[name1] ?? defaultValue) * scale; + const nvalue2 = (nextMap[name2] ?? defaultValue) * scale; + const curve = keyMap.curve; + if (curve) { + bezier = readCurve(curve, timeline, bezier, frame, 0, time, time2, value1, nvalue1, scale); + bezier = readCurve(curve, timeline, bezier, frame, 1, time, time2, value2, nvalue2, scale); + } + time = time2; + value1 = nvalue1; + value2 = nvalue2; + keyMap = nextMap; + } + } + function readDrawOrder2(skeletonData, keys, slotCount, folderSlots) { + const changes = keys.offsets; + if (!changes) return null; + const drawOrder = new Array(slotCount).fill(-1); + const unchanged = new Array(slotCount - changes.length); + let originalIndex = 0, unchangedIndex = 0; + for (const offsetMap of changes) { + const slot = skeletonData.findSlot(offsetMap.slot); + if (slot == null) throw new Error(`Draw order slot not found: ${offsetMap.slot}`); + let index = 0; + if (!folderSlots) + index = slot.index; + else { + index = -1; + for (let i = 0; i < slotCount; i++) { + if (folderSlots[i] === slot.index) { + index = i; + break; + } + } + if (index === -1) throw new Error(`Slot not in folder: ${offsetMap.slot}`); + } + while (originalIndex !== index) + unchanged[unchangedIndex++] = originalIndex++; + drawOrder[originalIndex + offsetMap.offset] = originalIndex++; + } + while (originalIndex < slotCount) + unchanged[unchangedIndex++] = originalIndex++; + for (let i = slotCount - 1; i >= 0; i--) + if (drawOrder[i] === -1) drawOrder[i] = unchanged[--unchangedIndex]; + return drawOrder; + } + function readCurve(curve, timeline, bezier, frame, value, time1, time2, value1, value2, scale) { + if (curve === "stepped") { + timeline.setStepped(frame); + return bezier; + } + const i = value << 2; + const cx1 = curve[i]; + const cy1 = curve[i + 1] * scale; + const cx2 = curve[i + 2]; + const cy2 = curve[i + 3] * scale; + timeline.setBezier(bezier, frame, value, time1, value1, cx1, cy1, cx2, cy2, time2, value2); + return bezier + 1; + } + function getValue(map, property, defaultValue) { + return map[property] !== void 0 ? map[property] : defaultValue; + } + + // spine-core/src/SkeletonPhysicsMovement.ts + var SkeletonPhysicsMovement = class { + /** + * Creates a movement tracker for a skeleton displayed by a host runtime object. + * @param skeleton The skeleton whose physics constraints receive inherited movement. + * @param adapter Runtime-specific hooks used to read and convert the host object's transform. + * @param options Initial movement inheritance values. + */ + constructor(skeleton, adapter, options = {}) { + this.skeleton = skeleton; + this.adapter = adapter; + this.positionInheritanceFactorX = options.positionInheritanceX ?? 0; + this.positionInheritanceFactorY = options.positionInheritanceY ?? 0; + this.rotationInheritanceFactor = options.rotationInheritance ?? 0; + } + positionInheritanceFactorX = 0; + positionInheritanceFactorY = 0; + rotationInheritanceFactor = 0; + hasLastTransform = false; + lastX = 0; + lastY = 0; + lastZ = 0; + lastRotation = 0; + currentTransform = { x: 0, y: 0, z: 0, rotation: 0 }; + currentPosition = { x: 0, y: 0, z: 0 }; + lastPosition = { x: 0, y: 0, z: 0 }; + /** Horizontal position inheritance factor. `0` disables horizontal position inheritance. */ + get positionInheritanceX() { + return this.positionInheritanceFactorX; + } + /** Vertical position inheritance factor. `0` disables vertical position inheritance. */ + get positionInheritanceY() { + return this.positionInheritanceFactorY; + } + /** + * Sets how much host object translation is inherited by skeleton physics constraints. + * Use `(1, 1)` for normal inheritance, or `(0, 0)` to disable position inheritance. + * @param x The horizontal position inheritance factor. + * @param y The vertical position inheritance factor. + */ + setPositionInheritance(x, y) { + const wasDisabled = this.positionInheritanceFactorX === 0 && this.positionInheritanceFactorY === 0; + const isEnabled = x !== 0 || y !== 0; + this.positionInheritanceFactorX = x; + this.positionInheritanceFactorY = y; + if (wasDisabled && isEnabled) this.resetPosition(); + } + /** Rotation inheritance factor. `0` disables rotation inheritance. */ + get rotationInheritance() { + return this.rotationInheritanceFactor; + } + /** + * Sets how much host object rotation is inherited by skeleton physics constraints. + * @param value The rotation inheritance factor. + */ + set rotationInheritance(value) { + const wasDisabled = this.rotationInheritanceFactor === 0; + this.rotationInheritanceFactor = value; + if (wasDisabled && value !== 0) this.resetRotation(); + } + /** Resets the previous position used to calculate inherited translation. */ + resetPosition() { + const transform = this.currentTransform; + const readRotation = !this.hasLastTransform && this.rotationInheritanceFactor !== 0; + this.adapter.readTransform(transform, readRotation); + this.lastX = transform.x; + this.lastY = transform.y; + this.lastZ = transform.z; + if (readRotation) this.lastRotation = transform.rotation; + this.hasLastTransform = true; + } + /** Resets the previous rotation used to calculate inherited rotation. */ + resetRotation() { + const transform = this.currentTransform; + this.adapter.readTransform(transform, true); + this.lastRotation = transform.rotation; + if (!this.hasLastTransform) { + this.lastX = transform.x; + this.lastY = transform.y; + this.lastZ = transform.z; + } + this.hasLastTransform = true; + } + /** Resets both previous position and previous rotation. */ + resetTransform() { + const transform = this.currentTransform; + this.adapter.readTransform(transform, true); + this.setLastTransform(transform.x, transform.y, transform.z, transform.rotation); + } + /** + * Applies host object transform movement since the previous call to the skeleton's physics constraints. + * + * The first call records the current transform as the baseline and does not apply movement. + */ + applyTransformMovement() { + const inheritPosition = this.positionInheritanceFactorX !== 0 || this.positionInheritanceFactorY !== 0; + const inheritRotation = this.rotationInheritanceFactor !== 0; + if (!inheritPosition && !inheritRotation) return; + const transform = this.currentTransform; + this.adapter.readTransform(transform, inheritRotation); + const { x, y, z } = transform; + const currentRotation = inheritRotation ? transform.rotation : this.lastRotation; + const positionChanged = x !== this.lastX || y !== this.lastY || z !== this.lastZ; + if (this.hasLastTransform) { + if (!positionChanged && currentRotation === this.lastRotation) return; + if (inheritPosition && positionChanged) this.applyPositionMovement(x, y, z); + if (inheritRotation && currentRotation !== this.lastRotation) this.applyRotationMovement(currentRotation); + } + this.setLastTransform(x, y, z, currentRotation); + } + applyPositionMovement(currentX, currentY, currentZ) { + const currentPosition = this.currentPosition; + currentPosition.x = currentX; + currentPosition.y = currentY; + currentPosition.z = currentZ; + this.adapter.worldToSkeleton(currentPosition); + const lastPosition = this.lastPosition; + lastPosition.x = this.lastX; + lastPosition.y = this.lastY; + lastPosition.z = this.lastZ; + this.adapter.worldToSkeleton(lastPosition); + this.skeleton.physicsTranslate( + (currentPosition.x - lastPosition.x) * this.positionInheritanceFactorX, + (currentPosition.y - lastPosition.y) * this.positionInheritanceFactorY + ); + } + applyRotationMovement(currentRotation) { + const rotationFactor = this.rotationInheritanceFactor; + if (rotationFactor === 0) return; + this.skeleton.physicsRotate(0, 0, this.getRotationDelta(currentRotation, this.lastRotation) * rotationFactor); + } + setLastTransform(x, y, z, rotation) { + this.lastX = x; + this.lastY = y; + this.lastZ = z; + this.lastRotation = rotation; + this.hasLastTransform = true; + } + getRotationDelta(current, previous) { + let delta = current - previous; + delta = (delta + 180) % 360 - 180; + return delta < -180 ? delta + 360 : delta; + } + }; + + // spine-core/src/SkeletonRendererCore.ts + var SkeletonRendererCore = class { + commandPool = new CommandPool(); + worldVertices = new Float32Array(12 * 1024); + quadIndices = new Uint16Array([0, 1, 2, 2, 3, 0]); + clipping = new SkeletonClipping(); + renderCommands = []; + render(skeleton, pma = false, inColor, stride = 2, slotZOffset = 0) { + this.commandPool.reset(); + this.renderCommands.length = 0; + const clipper = this.clipping; + let z = 0; + const drawOrder = skeleton.drawOrder.appliedPose; + for (let i = 0, n = drawOrder.length; i < n; i++) { + const slot = drawOrder[i]; + if (!slot.bone.active) { + clipper.clipEnd(slot); + continue; + } + const pose = slot.appliedPose; + const attachment = pose.attachment; + if (!attachment) { + clipper.clipEnd(slot); + continue; + } + const slotColor = pose.color; + const alpha = slotColor.a; + if (alpha === 0 && !(attachment instanceof ClippingAttachment)) { + clipper.clipEnd(slot); + continue; + } + let vertices; + let verticesCount; + let uvs; + let indices; + let indicesCount; + let attachmentColor; + let texture; + if (attachment instanceof RegionAttachment) { + attachmentColor = attachment.color; + if (attachmentColor.a === 0) { + clipper.clipEnd(slot); + continue; + } + const sequence = attachment.sequence; + const sequenceIndex = sequence.resolveIndex(pose); + attachment.computeWorldVertices(slot, attachment.getOffsets(pose), this.worldVertices, 0, stride); + vertices = this.worldVertices; + verticesCount = 4; + uvs = sequence.getUVs(sequenceIndex); + indices = this.quadIndices; + indicesCount = 6; + texture = sequence.regions[sequenceIndex]?.texture; + } else if (attachment instanceof MeshAttachment) { + attachmentColor = attachment.color; + if (attachmentColor.a === 0) { + clipper.clipEnd(slot); + continue; + } + if (this.worldVertices.length < attachment.worldVerticesLength) + this.worldVertices = new Float32Array(attachment.worldVerticesLength); + attachment.computeWorldVertices(skeleton, slot, 0, attachment.worldVerticesLength, this.worldVertices, 0, stride); + vertices = this.worldVertices; + verticesCount = attachment.worldVerticesLength >> 1; + const sequence = attachment.sequence; + const sequenceIndex = sequence.resolveIndex(pose); + uvs = sequence.getUVs(sequenceIndex); + indices = attachment.triangles; + indicesCount = indices.length; + texture = sequence.regions[sequenceIndex]?.texture; + } else if (attachment instanceof ClippingAttachment) { + clipper.clipEnd(slot); + clipper.clipStart(skeleton, slot, attachment); + continue; + } else { + clipper.clipEnd(slot); + continue; + } + if (!texture) { + clipper.clipEnd(slot); + continue; + } + const skelColor = skeleton.color; + let color, darkColor; + if (pma) { + let a; + if (inColor) { + a = Math.floor(inColor[3] * skelColor.a * slotColor.a * attachmentColor.a * 255); + const r = Math.floor(a * inColor[0] * skelColor.r * slotColor.r * attachmentColor.r); + const g = Math.floor(a * inColor[1] * skelColor.g * slotColor.g * attachmentColor.g); + const b = Math.floor(a * inColor[2] * skelColor.b * slotColor.b * attachmentColor.b); + color = a << 24 | r << 16 | g << 8 | b; + } else { + a = Math.floor(skelColor.a * slotColor.a * attachmentColor.a * 255); + const r = Math.floor(a * skelColor.r * slotColor.r * attachmentColor.r); + const g = Math.floor(a * skelColor.g * slotColor.g * attachmentColor.g); + const b = Math.floor(a * skelColor.b * slotColor.b * attachmentColor.b); + color = a << 24 | r << 16 | g << 8 | b; + } + darkColor = 4278190080; + if (pose.darkColor) { + const { r, g, b } = pose.darkColor; + darkColor = 4278190080 | Math.floor(r * a) << 16 | Math.floor(g * a) << 8 | Math.floor(b * a); + } + } else { + if (inColor) { + const a = Math.floor(inColor[3] * skelColor.a * slotColor.a * attachmentColor.a * 255); + const r = Math.floor(inColor[0] * skelColor.r * slotColor.r * attachmentColor.r * 255); + const g = Math.floor(inColor[1] * skelColor.g * slotColor.g * attachmentColor.g * 255); + const b = Math.floor(inColor[2] * skelColor.b * slotColor.b * attachmentColor.b * 255); + color = a << 24 | r << 16 | g << 8 | b; + } else { + const a = Math.floor(skelColor.a * slotColor.a * attachmentColor.a * 255); + const r = Math.floor(skelColor.r * slotColor.r * attachmentColor.r * 255); + const g = Math.floor(skelColor.g * slotColor.g * attachmentColor.g * 255); + const b = Math.floor(skelColor.b * slotColor.b * attachmentColor.b * 255); + color = a << 24 | r << 16 | g << 8 | b; + } + darkColor = 0; + if (pose.darkColor) { + const { r, g, b } = pose.darkColor; + darkColor = Math.floor(r * 255) << 16 | Math.floor(g * 255) << 8 | Math.floor(b * 255); + } + } + if (clipper.isClipping()) { + clipper.clipTrianglesUnpacked(vertices, 0, indices, indicesCount, uvs, stride); + vertices = clipper.clippedVerticesTyped; + verticesCount = clipper.clippedVerticesLength / stride; + uvs = clipper.clippedUVsTyped; + indices = clipper.clippedTrianglesTyped; + indicesCount = clipper.clippedTrianglesLength; + } + const cmd = this.commandPool.getCommand(verticesCount, indicesCount, stride); + cmd.blendMode = slot.data.blendMode; + cmd.texture = texture; + cmd.positions.set(vertices.subarray(0, verticesCount * stride)); + if (stride >= 3) { + for (let j = 2, n2 = verticesCount * stride; j < n2; j += stride) + cmd.positions[j] = z; + } + cmd.uvs.set(uvs.subarray(0, verticesCount << 1)); + for (let j = 0; j < verticesCount; j++) { + cmd.colors[j] = color; + cmd.darkColors[j] = darkColor; + } + if (indices instanceof Uint16Array) { + cmd.indices.set(indices.subarray(0, indicesCount)); + } else { + cmd.indices.set(indices.slice(0, indicesCount)); + } + this.renderCommands.push(cmd); + z += slotZOffset; + clipper.clipEnd(slot); + } + clipper.clipEnd(); + return this.batchCommands(stride); + } + batchSubCommands(commands, first, last, numVertices, numIndices, stride) { + const firstCmd = commands[first]; + const batched = this.commandPool.getCommand(numVertices, numIndices, stride); + batched.blendMode = firstCmd.blendMode; + batched.texture = firstCmd.texture; + let positionsOffset = 0; + let uvsOffset = 0; + let colorsOffset = 0; + let indicesOffset = 0; + let vertexOffset = 0; + for (let i = first; i <= last; i++) { + const cmd = commands[i]; + batched.positions.set(cmd.positions, positionsOffset); + positionsOffset += cmd.numVertices * stride; + batched.uvs.set(cmd.uvs, uvsOffset); + uvsOffset += cmd.numVertices << 1; + batched.colors.set(cmd.colors, colorsOffset); + batched.darkColors.set(cmd.darkColors, colorsOffset); + colorsOffset += cmd.numVertices; + for (let j = 0; j < cmd.numIndices; j++) + batched.indices[indicesOffset + j] = cmd.indices[j] + vertexOffset; + indicesOffset += cmd.numIndices; + vertexOffset += cmd.numVertices; + } + return batched; + } + batchCommands(stride) { + if (this.renderCommands.length === 0) return void 0; + let root; + let last; + let first = this.renderCommands[0]; + let startIndex = 0; + let i = 1; + let numVertices = first.numVertices; + let numIndices = first.numIndices; + while (i <= this.renderCommands.length) { + const cmd = i < this.renderCommands.length ? this.renderCommands[i] : null; + if (cmd && cmd.numVertices === 0 && cmd.numIndices === 0) { + i++; + continue; + } + const canBatch = cmd !== null && cmd.texture === first.texture && cmd.blendMode === first.blendMode && cmd.colors[0] === first.colors[0] && cmd.darkColors[0] === first.darkColors[0] && numIndices + cmd.numIndices < 65535; + if (canBatch) { + numVertices += cmd.numVertices; + numIndices += cmd.numIndices; + } else { + const batched = this.batchSubCommands( + this.renderCommands, + startIndex, + i - 1, + numVertices, + numIndices, + stride + ); + if (!last) { + root = last = batched; + } else { + last.next = batched; + last = batched; + } + if (i === this.renderCommands.length) break; + first = this.renderCommands[i]; + startIndex = i; + numVertices = first.numVertices; + numIndices = first.numIndices; + } + i++; + } + return root; + } + }; + var CommandPool = class { + pool = []; + inUse = []; + getCommand(numVertices, numIndices, stride) { + let cmd; + for (const c of this.pool) { + if (c._positions.length >= numVertices * stride && c._indices.length >= numIndices) { + cmd = c; + break; + } + } + if (!cmd) { + const _positions = new Float32Array(numVertices * stride); + const _uvs = new Float32Array(numVertices << 1); + const _colors = new Uint32Array(numVertices); + const _darkColors = new Uint32Array(numVertices); + const _indices = new Uint16Array(numIndices); + cmd = { + positions: _positions, + uvs: _uvs, + colors: _colors, + darkColors: _darkColors, + indices: _indices, + _positions, + _uvs, + _colors, + _darkColors, + _indices, + numVertices, + numIndices, + blendMode: 0 /* Normal */, + texture: null + }; + } else { + this.pool.splice(this.pool.indexOf(cmd), 1); + cmd.next = void 0; + cmd.numVertices = numVertices; + cmd.numIndices = numIndices; + cmd.positions = cmd._positions.subarray(0, numVertices * stride); + cmd.uvs = cmd._uvs.subarray(0, numVertices << 1); + cmd.colors = cmd._colors.subarray(0, numVertices); + cmd.darkColors = cmd._darkColors.subarray(0, numVertices); + cmd.indices = cmd._indices.subarray(0, numIndices); + } + this.inUse.push(cmd); + return cmd; + } + reset() { + this.pool.push(...this.inUse); + this.inUse.length = 0; + } + }; + + // spine-canvas/src/CanvasTexture.ts + var CanvasTexture = class extends Texture { + constructor(image) { + super(image); + } + setFilters(minFilter, magFilter) { + } + setWraps(uWrap, vWrap) { + } + dispose() { + } + }; + + // spine-canvas/src/AssetManager.ts + var AssetManager = class extends AssetManagerBase { + constructor(pathPrefix = "", downloader = new Downloader()) { + super((image) => { + return new CanvasTexture(image); + }, pathPrefix, downloader); + } + }; + + // spine-canvas/src/SkeletonRenderer.ts + var worldVertices = Utils.newFloatArray(8); + var SkeletonRenderer = class _SkeletonRenderer { + static QUAD_TRIANGLES = [0, 1, 2, 2, 3, 0]; + static VERTEX_SIZE = 2 + 2 + 4; + ctx; + triangleRendering = false; + debugRendering = false; + vertices = Utils.newFloatArray(8 * 1024); + tempColor = new Color(); + constructor(context) { + this.ctx = context; + } + draw(skeleton) { + if (this.triangleRendering) this.drawTriangles(skeleton); + else this.drawImages(skeleton); + } + drawImages(skeleton) { + const ctx = this.ctx; + const color = this.tempColor; + const skeletonColor = skeleton.color; + const drawOrder = skeleton.drawOrder.appliedPose; + if (this.debugRendering) ctx.strokeStyle = "green"; + for (let i = 0, n = drawOrder.length; i < n; i++) { + const slot = drawOrder[i]; + const bone = slot.bone; + if (!bone.active) continue; + const pose = slot.appliedPose; + const attachment = pose.attachment; + if (!(attachment instanceof RegionAttachment)) continue; + const sequence = attachment.sequence; + const sequenceIndex = sequence.resolveIndex(pose); + attachment.computeWorldVertices(slot, attachment.getOffsets(pose), worldVertices, 0, 2); + const region = sequence.regions[sequenceIndex]; + const image = region.texture.getImage(); + const slotColor = pose.color; + const regionColor = attachment.color; + color.set( + skeletonColor.r * slotColor.r * regionColor.r, + skeletonColor.g * slotColor.g * regionColor.g, + skeletonColor.b * slotColor.b * regionColor.b, + skeletonColor.a * slotColor.a * regionColor.a + ); + ctx.save(); + const boneApplied = bone.appliedPose; + ctx.transform(boneApplied.a, boneApplied.c, boneApplied.b, boneApplied.d, boneApplied.worldX, boneApplied.worldY); + const offsets = attachment.getOffsets(pose); + ctx.translate(offsets[0], offsets[1]); + ctx.rotate(attachment.rotation * Math.PI / 180); + const atlasScale = attachment.width / region.originalWidth; + ctx.scale(atlasScale * attachment.scaleX, atlasScale * attachment.scaleY); + let w = region.width, h = region.height; + ctx.translate(w / 2, h / 2); + if (region.degrees === 90) { + const t = w; + w = h; + h = t; + ctx.rotate(-Math.PI / 2); + } + ctx.scale(1, -1); + ctx.translate(-w / 2, -h / 2); + ctx.globalAlpha = color.a; + ctx.drawImage(image, image.width * region.u, image.height * region.v, w, h, 0, 0, w, h); + if (this.debugRendering) ctx.strokeRect(0, 0, w, h); + ctx.restore(); + } + } + drawTriangles(skeleton) { + const ctx = this.ctx; + const color = this.tempColor; + const skeletonColor = skeleton.color; + const drawOrder = skeleton.drawOrder.appliedPose; + let blendMode = null; + let vertices = this.vertices; + let triangles = null; + for (let i = 0, n = drawOrder.length; i < n; i++) { + const slot = drawOrder[i]; + const pose = slot.appliedPose; + const attachment = pose.attachment; + let texture; + if (attachment instanceof RegionAttachment) { + const sequence = attachment.sequence; + const sequenceIndex = sequence.resolveIndex(pose); + const uvs = sequence.getUVs(sequenceIndex); + const offsets = attachment.getOffsets(pose); + vertices = this.computeRegionVertices(slot, attachment, offsets, uvs, false); + triangles = _SkeletonRenderer.QUAD_TRIANGLES; + texture = (sequence.regions[sequenceIndex]?.texture).getImage(); + } else if (attachment instanceof MeshAttachment) { + const sequence = attachment.sequence; + const sequenceIndex = sequence.resolveIndex(pose); + const uvs = sequence.getUVs(sequenceIndex); + vertices = this.computeMeshVertices(slot, attachment, uvs, false); + triangles = attachment.triangles; + texture = (sequence.regions[sequenceIndex]?.texture).getImage(); + } else + continue; + if (texture) { + if (slot.data.blendMode !== blendMode) blendMode = slot.data.blendMode; + const slotColor = pose.color; + const attachmentColor = attachment.color; + color.set( + skeletonColor.r * slotColor.r * attachmentColor.r, + skeletonColor.g * slotColor.g * attachmentColor.g, + skeletonColor.b * slotColor.b * attachmentColor.b, + skeletonColor.a * slotColor.a * attachmentColor.a + ); + ctx.globalAlpha = color.a; + for (let j = 0; j < triangles.length; j += 3) { + const t1 = triangles[j] * 8, t2 = triangles[j + 1] * 8, t3 = triangles[j + 2] * 8; + const x0 = vertices[t1], y0 = vertices[t1 + 1], u0 = vertices[t1 + 6], v0 = vertices[t1 + 7]; + const x1 = vertices[t2], y1 = vertices[t2 + 1], u1 = vertices[t2 + 6], v1 = vertices[t2 + 7]; + const x2 = vertices[t3], y2 = vertices[t3 + 1], u2 = vertices[t3 + 6], v2 = vertices[t3 + 7]; + this.drawTriangle(texture, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2); + if (this.debugRendering) { + ctx.strokeStyle = "green"; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.lineTo(x0, y0); + ctx.stroke(); + } + } + } + } + this.ctx.globalAlpha = 1; + } + // Adapted from http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 + // Apache 2 licensed + drawTriangle(img, x0, y0, u0, v0, x1, y1, u1, v1, x2, y2, u2, v2) { + const ctx = this.ctx; + const width = img.width - 1; + const height = img.height - 1; + u0 *= width; + v0 *= height; + u1 *= width; + v1 *= height; + u2 *= width; + v2 *= height; + ctx.beginPath(); + ctx.moveTo(x0, y0); + ctx.lineTo(x1, y1); + ctx.lineTo(x2, y2); + ctx.closePath(); + x1 -= x0; + y1 -= y0; + x2 -= x0; + y2 -= y0; + u1 -= u0; + v1 -= v0; + u2 -= u0; + v2 -= v0; + let det = u1 * v2 - u2 * v1; + if (det === 0) return; + det = 1 / det; + const a = (v2 * x1 - v1 * x2) * det; + const b = (v2 * y1 - v1 * y2) * det; + const c = (u1 * x2 - u2 * x1) * det; + const d = (u1 * y2 - u2 * y1) * det; + const e = x0 - a * u0 - c * v0; + const f = y0 - b * u0 - d * v0; + ctx.save(); + ctx.transform(a, b, c, d, e, f); + ctx.clip(); + ctx.drawImage(img, 0, 0); + ctx.restore(); + } + computeRegionVertices(slot, region, offsets, uvs, pma) { + const skeletonColor = slot.skeleton.color; + const slotColor = slot.appliedPose.color; + const regionColor = region.color; + const alpha = skeletonColor.a * slotColor.a * regionColor.a; + const multiplier = pma ? alpha : 1; + const color = this.tempColor; + color.set( + skeletonColor.r * slotColor.r * regionColor.r * multiplier, + skeletonColor.g * slotColor.g * regionColor.g * multiplier, + skeletonColor.b * slotColor.b * regionColor.b * multiplier, + alpha + ); + region.computeWorldVertices(slot, offsets, this.vertices, 0, _SkeletonRenderer.VERTEX_SIZE); + const vertices = this.vertices; + vertices[RegionAttachment.C1R] = color.r; + vertices[RegionAttachment.C1G] = color.g; + vertices[RegionAttachment.C1B] = color.b; + vertices[RegionAttachment.C1A] = color.a; + vertices[RegionAttachment.U1] = uvs[0]; + vertices[RegionAttachment.V1] = uvs[1]; + vertices[RegionAttachment.C2R] = color.r; + vertices[RegionAttachment.C2G] = color.g; + vertices[RegionAttachment.C2B] = color.b; + vertices[RegionAttachment.C2A] = color.a; + vertices[RegionAttachment.U2] = uvs[2]; + vertices[RegionAttachment.V2] = uvs[3]; + vertices[RegionAttachment.C3R] = color.r; + vertices[RegionAttachment.C3G] = color.g; + vertices[RegionAttachment.C3B] = color.b; + vertices[RegionAttachment.C3A] = color.a; + vertices[RegionAttachment.U3] = uvs[4]; + vertices[RegionAttachment.V3] = uvs[5]; + vertices[RegionAttachment.C4R] = color.r; + vertices[RegionAttachment.C4G] = color.g; + vertices[RegionAttachment.C4B] = color.b; + vertices[RegionAttachment.C4A] = color.a; + vertices[RegionAttachment.U4] = uvs[6]; + vertices[RegionAttachment.V4] = uvs[7]; + return vertices; + } + computeMeshVertices(slot, mesh, uvs, pma) { + const skeleton = slot.skeleton; + const skeletonColor = skeleton.color; + const slotColor = slot.appliedPose.color; + const regionColor = mesh.color; + const alpha = skeletonColor.a * slotColor.a * regionColor.a; + const multiplier = pma ? alpha : 1; + const color = this.tempColor; + color.set( + skeletonColor.r * slotColor.r * regionColor.r * multiplier, + skeletonColor.g * slotColor.g * regionColor.g * multiplier, + skeletonColor.b * slotColor.b * regionColor.b * multiplier, + alpha + ); + const vertexCount = mesh.worldVerticesLength / 2; + let vertices = this.vertices; + if (vertices.length < mesh.worldVerticesLength) this.vertices = vertices = Utils.newFloatArray(mesh.worldVerticesLength); + mesh.computeWorldVertices(skeleton, slot, 0, mesh.worldVerticesLength, vertices, 0, _SkeletonRenderer.VERTEX_SIZE); + for (let i = 0, u = 0, v = 2; i < vertexCount; i++) { + vertices[v++] = color.r; + vertices[v++] = color.g; + vertices[v++] = color.b; + vertices[v++] = color.a; + vertices[v++] = uvs[u++]; + vertices[v++] = uvs[u++]; + v += 2; + } + return vertices; + } + }; + return __toCommonJS(index_exports); +})(); +//# sourceMappingURL=spine-canvas.js.map diff --git a/logo.png b/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..9b14334655073c7017d10cfcedcf79488dfad5a9 GIT binary patch literal 15726 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.BcY@yq=w~0RdKMCFP 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 10" + }, + "optionalDependencies": { + "@napi-rs/canvas-android-arm64": "0.1.66", + "@napi-rs/canvas-darwin-arm64": "0.1.66", + "@napi-rs/canvas-darwin-x64": "0.1.66", + "@napi-rs/canvas-linux-arm-gnueabihf": "0.1.66", + "@napi-rs/canvas-linux-arm64-gnu": "0.1.66", + "@napi-rs/canvas-linux-arm64-musl": "0.1.66", + "@napi-rs/canvas-linux-riscv64-gnu": "0.1.66", + "@napi-rs/canvas-linux-x64-gnu": "0.1.66", + "@napi-rs/canvas-linux-x64-musl": "0.1.66", + "@napi-rs/canvas-win32-x64-msvc": "0.1.66" + } + }, + "node_modules/@napi-rs/canvas-android-arm64": { + "version": "0.1.66", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-android-arm64/-/canvas-android-arm64-0.1.66.tgz", + "integrity": "sha512-77Yq9yaUYN90zCovYOpw7LhidJiswU9wLIWWBGF6iiEJyQdt6tkiXpGRZpOMJVO70afkcdc4T7532cxMIBhk0Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-arm64": { + "version": "0.1.66", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-arm64/-/canvas-darwin-arm64-0.1.66.tgz", + "integrity": "sha512-cz3aJ06b8BZGtwRxKTiE0OVUlB17MH8j+BnE4A5+wD9aD1guCCqECsz+k7tpXdAdTAYKRIz2pq6ZuiJ76NyUbQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-darwin-x64": { + "version": "0.1.66", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-darwin-x64/-/canvas-darwin-x64-0.1.66.tgz", + "integrity": "sha512-szIWqJgFm2OTyGzM+hSiJOaOtjI73VYRC2KN30zZTt7i1+0sgpm5exK5ltDBPOmCdnLt7SbUfpInLj8VvxYlKA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm-gnueabihf": { + "version": "0.1.66", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm-gnueabihf/-/canvas-linux-arm-gnueabihf-0.1.66.tgz", + "integrity": "sha512-h/TZJFc6JLvp8FwbA5mu+yXiblN0iKqshU7xzd6L+ks5uNYgjS7XWLkNiyPQkMaXQgVczOJfZy7r4NSPK3V8Hg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-gnu": { + "version": "0.1.66", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-gnu/-/canvas-linux-arm64-gnu-0.1.66.tgz", + "integrity": "sha512-RGFUdBdi0Xmf+TfwZcB89Ap6hDYh4nzyJhXhNJIgve6ELrIPFhf7sDHvUHxjgW0YzczGoo+ophyCm03cJggu+w==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-arm64-musl": { + "version": "0.1.66", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-arm64-musl/-/canvas-linux-arm64-musl-0.1.66.tgz", + "integrity": "sha512-2cFViDIZ0xQlAHyJmyym+rj3p04V16vgAiz64sCAfwOOiW6e19agv1HQWHUsro3G2lF3PaHGAnp0WRPXGqLOfg==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-riscv64-gnu": { + "version": "0.1.66", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-riscv64-gnu/-/canvas-linux-riscv64-gnu-0.1.66.tgz", + "integrity": "sha512-Vm5ZWS2RDPeBpnfx83eJpZfJT07xl0jqp8d83PklKqiDNa3BmDZZ/uuI40/ICgejGLymXXYo5N21b7oAxhRTSA==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-gnu": { + "version": "0.1.66", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-gnu/-/canvas-linux-x64-gnu-0.1.66.tgz", + "integrity": "sha512-/ptGBhErNBCgWff3khtuEjhiiYWf70oWvBPRj8y5EMB0nLYpve7RxxFnavVvxN49kJ0MQHRIwgfyd47RSOOKPw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-linux-x64-musl": { + "version": "0.1.66", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-linux-x64-musl/-/canvas-linux-x64-musl-0.1.66.tgz", + "integrity": "sha512-XunvXisTkIG+bpq6BcXmsUstoLX3RLS6N9Uz9Pg9RpWIMeM6ObR5shr3NgpGRJq93769I1hS4mJW0DX2Au3WBw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/canvas-win32-x64-msvc": { + "version": "0.1.66", + "resolved": "https://registry.npmjs.org/@napi-rs/canvas-win32-x64-msvc/-/canvas-win32-x64-msvc-0.1.66.tgz", + "integrity": "sha512-3n34watNFqpwACDA+pt4jfQD6zR8PzfK86FBajdsgDVVZhSp6ohgbbJv+eUrXM08VUtjxTq7+U4sWspTu9+4Ug==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..42840a8 --- /dev/null +++ b/package.json @@ -0,0 +1,11 @@ +{ + "name": "spineviewer", + "version": "1.0.0", + "description": "Eagle 插件:离线预览 Spine 导出的骨骼动画(skel / skel.bytes / json / atlas / atlas.txt / png / jpg / jpeg / webp)", + "main": "thumbnail/spine.js", + "private": true, + "type": "commonjs", + "dependencies": { + "@napi-rs/canvas": "^0.1.66" + } +} diff --git a/realdur.js b/realdur.js new file mode 100644 index 0000000..5ced7dd --- /dev/null +++ b/realdur.js @@ -0,0 +1,26 @@ +const fs=require('fs'); +const path=require('path'); +const utils=require('./js/spine-utils.js'); +const render=require('./js/spine-render.js'); +const base='/Users/tianmokeji/Desktop/特效/特效.library/images'; +// 找一个有效的 json +const j=base+'/MTS9A4QKK0ALE.info/spineboy-pro.json'; +const a=utils.discoverAssets(j); +if(!a.skeletonPath){console.log('未找到骨骼');process.exit(1);} +console.log('使用骨骼:', a.skeletonPath); +console.log('图集:', a.atlasPath); +(async()=>{ + const v=utils.detectVersion(a.skeletonPath); + const rd=utils.chooseRuntimeDir(v,a.isBinary); + console.log('version:', v, 'runtimeDir:', rd); + const spine=render.loadRuntime(rd); + const atlas=await render.buildTextureAtlas(spine, fs.readFileSync(a.atlasPath,'utf8'), path.dirname(a.skeletonPath), a.texturePaths); + const sd=render.readSkeletonData(spine, a.skeletonPath, atlas, a.isBinary); + console.log('动画数量:', sd.animations.length); + for(const anim of sd.animations){ + console.log(' - '+anim.name+' duration='+anim.duration+'s'); + } + if(sd.animations[0]){ + console.log('第一个动画名:', sd.animations[0].name, ' duration:', sd.animations[0].duration); + } +})(); diff --git a/test-atlas.js b/test-atlas.js new file mode 100644 index 0000000..f64efd9 --- /dev/null +++ b/test-atlas.js @@ -0,0 +1,17 @@ +const fs=require('fs'); +const thumb=require('./thumbnail/spine.js'); +const base='/Users/tianmokeji/Desktop/特效/特效.library/images'; +(async()=>{ + const atlas=base+'/MTS71AFMHS8JW.info/spineboy.atlas'; + const json=base+'/MTS71AFLNZODR.info/spineboy-pro.json'; + for(let i=1;i<=4;i++){ + for(const [tag,src] of [['atlas',atlas],['json',json]]){ + const dest='/tmp/shot-'+tag+'-'+i+'.png'; + const item={width:0,height:0}; + try{ + await thumb({src,dest,item}); + console.log('run',i,tag,'OK',fs.statSync(dest).size+'b'); + }catch(e){ console.log('run',i,tag,'REJECT',e.message); } + } + } +})(); diff --git a/test-conc.js b/test-conc.js new file mode 100644 index 0000000..9fc61c2 --- /dev/null +++ b/test-conc.js @@ -0,0 +1,15 @@ +const fs=require('fs'); +const thumb=require('./thumbnail/spine.js'); +const base='/Users/tianmokeji/Desktop/特效/特效.library/images'; +const atlas=base+'/MTS71AFMHS8JW.info/spineboy.atlas'; +const json=base+'/MTS71AFLNZODR.info/spineboy-pro.json'; +(async()=>{ + for(let i=1;i<=6;i++){ + // 并发同时生成 atlas + json(模拟 Eagle 同时为两个文件生成缩略图) + const results=await Promise.all([ + thumb({src:atlas,dest:'/tmp/c-atlas-'+i+'.png',item:{width:0,height:0}}).then(()=>({n:'atlas',ok:true})).catch(e=>({n:'atlas',ok:false,err:e.message})), + thumb({src:json,dest:'/tmp/c-json-'+i+'.png',item:{width:0,height:0}}).then(()=>({n:'json',ok:true})).catch(e=>({n:'json',ok:false,err:e.message})), + ]); + console.log('round',i,'->', results.map(r=>(r.n+':'+(r.ok?'OK':'FAIL('+r.err+')'))).join(' ')); + } +})(); diff --git a/test.icns b/test.icns new file mode 100644 index 0000000000000000000000000000000000000000..50bd2bd3669001b3c1f4da48ef9de07757422403 GIT binary patch literal 413833 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

qB?Qsvvv*MW8o^w5 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Ă}z+WKLP4KkQsfmGXFLHEnwqV-^Y`l)8j1$+4 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 literal 0 HcmV?d00001 diff --git a/thumbnail/icns.js b/thumbnail/icns.js new file mode 100644 index 0000000..cafbcf5 --- /dev/null +++ b/thumbnail/icns.js @@ -0,0 +1,28 @@ +const fs = require('fs'); +const icns = require('./../js/icns-util.js'); +const imageSize = require('./../js/image-size.js'); + +module.exports = async ({ src, dest, item }) => { + return new Promise(async (resolve, reject) => { + try { + // 1. parsing and generate thumbnail file to dest + await icns.icns2png(src, dest); + let size = await imageSize(dest); + + // 2. Check if the result is correct + if (!fs.existsSync(dest) || size.width === 0) { + return reject(new Error(`icns file thumbnail generate fail.`)); + } + + // 3. update the item dimensions + item.height = size?.height || item.height; + item.width = size?.width || item.width; + + // 4. return the result + return resolve(item); + } + catch (err) { + return reject(err); + } + }); +} \ No newline at end of file diff --git a/thumbnail/spine.js b/thumbnail/spine.js new file mode 100644 index 0000000..9263951 --- /dev/null +++ b/thumbnail/spine.js @@ -0,0 +1,227 @@ +const fs = require('fs'); +const path = require('path'); +const zlib = require('zlib'); +const utils = require('./../js/spine-utils.js'); +const render = require('./../js/spine-render.js'); + +/** 简易日志(写入插件目录 thumbnails.log,便于诊断 Eagle 中的间歇失败) */ +function log(msg) { + try { + const logPath = path.join(__dirname, '..', 'thumbnails.log'); + fs.appendFileSync(logPath, '[' + new Date().toISOString() + '] ' + msg + '\n'); + } catch (e) { /* ignore */ } +} + +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); + +/** 插件代码版本:每次改动递增,用于确认 Eagle 是否加载到最新代码 */ +const VERSION = 'v4'; + +/** 发现配套资源;带重试,以应对 Eagle 导入时“多文件分批写入库”的时序问题。 + * 同伴文件(骨骼/图集)可能在 Atlas 的缩略图生成后才落盘,故需等待。 + * 一旦发现即立即返回(不会傻等满窗口),窗口仅作为最坏情况的上限。 + * 采用 10 次 × 150ms ≈ 1.5 秒;间隔更密、最快感知同伴落盘。 */ +async function discoverWithRetry(src, retries = 10, delay = 150) { + let assets = null; + for (let i = 0; i < retries; i++) { + assets = utils.discoverAssets(src); + if (assets.skeletonPath && assets.atlasPath) return assets; + await sleep(delay); + } + return assets; +} + +/** 渲染缩略图;失败时重试一次(应对偶发渲染错误) */ +async function renderWithRetry(opts) { + try { + return await render.renderThumbnail(opts); + } catch (e) { + log('renderThumbnail 首次失败: ' + (e && e.message) + ',重试...'); + await sleep(150); + return await render.renderThumbnail(opts); + } +} + +/** + * Eagle 格式扩展缩略图处理函数。 + * 参数:{ src, dest, item } + * - src : 原始文件路径(skel/skel.bytes/json/atlas/atlas.txt) + * - dest : 需要生成的缩略图 PNG 路径 + * - item : 当前 item 对象(可更新宽高) + */ +module.exports = async ({ src, dest, item }) => { + try { + // 记录 Eagle 传入的关键信息,便于诊断 src/item 的实际形态 + log('HIT ' + VERSION + ' src=' + src + ' (isTexture=' + utils.isTextureFile(src) + ')'); + try { + log(' item keys=' + Object.keys(item || {}).join(',') + ' | name=' + (item && item.name) + ' | id=' + (item && item.id) + ' | ext=' + (item && item.ext) + ' | isDeleted=' + (item && item.isDeleted)); + } catch (e) { /* ignore */ } + + // —— 守护:若 src 文件在库中不存在(可能是回收站 isDeleted 残留 / 临时 id), + // 且 item 标记为已删除,则跳过,避免生成破碎/占位缩略图,交由 Eagle 自身处理。 + if (item && item.isDeleted) { + log(' skip: item.isDeleted=true'); + return resolve(item); + } + + // —— 防御:若 src 是图片(png/jpg/jpeg/webp),不生成占位图, + // 而是把原始图片复制/转换为缩略图,交由系统展示真实内容。 + const srcExt = utils.extOf(path.basename(src)); + if (utils.isTextureFile(src) || srcExt === '.png' || srcExt === '.jpg' || srcExt === '.jpeg' || srcExt === '.webp') { + await copyImageAsThumb(src, dest); + try { const s = imageSizeOf(dest); item.width = s.width || item.width; item.height = s.height || item.height; } catch (e) {} + return resolve(item); + } + + const assets = await discoverWithRetry(src); + + // 找不到配套 Spine 资源 + if (!assets.skeletonPath || !assets.atlasPath) { + log('未找到配套资源: ' + src + ' (skeleton=' + !!assets.skeletonPath + ', atlas=' + !!assets.atlasPath + ')'); + await writePlaceholder(dest, path.basename(src, utils.extOf(path.basename(src)) || '')); + item.width = 400; item.height = 400; + return resolve(item); + } + + const version = utils.detectVersion(assets.skeletonPath); + const runtimeDir = utils.chooseRuntimeDir(version, assets.isBinary); + + if (!runtimeDir) { + await writePlaceholder(dest, path.basename(assets.skeletonPath, path.extname(assets.skeletonPath))); + item.width = 400; item.height = 400; + return resolve(item); + } + + // 渲染首帧到 PNG + const png = await renderWithRetry({ + skeletonPath: assets.skeletonPath, + atlasPath: assets.atlasPath, + texturePaths: assets.texturePaths, + version, + runtimeDir, + size: 400, + }); + + fs.writeFileSync(dest, png); + + try { + const size = imageSizeOf(dest); + item.width = size.width || 400; + item.height = size.height || 400; + } catch (e) { /* ignore */ } + + return Promise.resolve(item); + } catch (err) { + // 兜底:总是生成一张有效 PNG,绝不 reject,避免 Eagle 显示默认图标 + log('缩略图处理异常: ' + (err && err.message) + '\n' + ((err && err.stack) || '')); + try { + await writePlaceholder(dest, 'Spine'); + item.width = 400; + item.height = 400; + return resolve(item); + } catch (e2) { + // 最后兜底:写入一张最小 1x1 PNG + try { fs.writeFileSync(dest, Buffer.from('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNk+M8AAAMBAQDJ/pLvAAAAAElFTkSuQmCC', 'base64')); } catch (e3) {} + item.width = 400; item.height = 400; + return resolve(item); + } + } +}; + +function resolve(item) { + return item; +} + +/** 将任意图片作为缩略图复制/转换为 PNG(PNG 直接拷贝,JPG/WebP 用 @napi-rs/canvas 转换) */ +async function copyImageAsThumb(src, dest) { + const ext = path.extname(src).toLowerCase(); + if (ext === '.png') { + fs.copyFileSync(src, dest); + return; + } + if (render.canvasLib) { + try { + const img = await render.canvasLib.loadImage(src); + const w = img.width, h = img.height; + const canvas = render.canvasLib.createCanvas(w, h); + const ctx = canvas.getContext('2d'); + ctx.drawImage(img, 0, 0, w, h); + fs.writeFileSync(dest, canvas.toBuffer('image/png')); + return; + } catch (e) { /* fall through */ } + } + fs.copyFileSync(src, dest); +} + +/** 读取 PNG 宽高(仅支持 PNG 头部) */ +function imageSizeOf(file) { + const buf = fs.readFileSync(file); + if (buf.slice(0, 8).toString('hex') === '89504e470d0a1a0a') { + return { width: buf.readUInt32BE(16), height: buf.readUInt32BE(20) }; + } + return { width: 0, height: 0 }; +} + +/** 生成一个纯 JS 占位 PNG(无需外部依赖),作为兜底 */ +async function writePlaceholder(dest, text) { + const w = 400, h = 400; + // 深色底 + const pixels = Buffer.alloc(w * h * 4); + for (let y = 0; y < h; y++) { + for (let x = 0; x < w; x++) { + const i = (y * w + x) * 4; + pixels[i] = 30; pixels[i + 1] = 30; pixels[i + 2] = 34; pixels[i + 3] = 255; + } + } + // 简单的斜线纹理,让占位图不单调 + for (let i = 0; i < w + h; i += 8) { + for (let k = 0; k < 3; k++) { + const x = Math.min(w - 1, i - k); + const y = Math.min(h - 1, k); + const idx = (y * w + x) * 4; + pixels[idx] = 60; pixels[idx + 1] = 62; pixels[idx + 2] = 68; + } + } + fs.writeFileSync(dest, encodePng(w, h, pixels)); +} + +/** 最小 PNG 编码器(纯 JS,使用 zlib deflate) */ +function encodePng(width, height, rgba) { + const sig = Buffer.from([137, 80, 78, 71, 13, 10, 26, 10]); + const ihdr = Buffer.alloc(13); + ihdr.writeUInt32BE(width, 0); + ihdr.writeUInt32BE(height, 4); + ihdr[8] = 8; // bit depth + ihdr[9] = 6; // color type RGBA + ihdr[10] = 0; ihdr[11] = 0; ihdr[12] = 0; + const ihdrChunk = chunk('IHDR', ihdr); + + const raw = Buffer.alloc((width * 4 + 1) * height); + for (let y = 0; y < height; y++) { + raw[y * (width * 4 + 1)] = 0; // filter type 0 + rgba.copy(raw, y * (width * 4 + 1) + 1, y * width * 4, (y + 1) * width * 4); + } + const idat = zlib.deflateSync(raw); + const idatChunk = chunk('IDAT', idat); + const iend = chunk('IEND', Buffer.alloc(0)); + return Buffer.concat([sig, ihdrChunk, idatChunk, iend]); +} + +function chunk(type, data) { + const len = Buffer.alloc(4); + len.writeUInt32BE(data.length, 0); + const typeBuf = Buffer.from(type, 'ascii'); + const crcBuf = Buffer.alloc(4); + crcBuf.writeUInt32BE(crc32(Buffer.concat([typeBuf, data])), 0); + return Buffer.concat([len, typeBuf, data, crcBuf]); +} + +function crc32(buf) { + let c, crc = 0xFFFFFFFF; + for (let i = 0; i < buf.length; i++) { + c = (crc ^ buf[i]) & 0xFF; + for (let k = 0; k < 8; k++) c = c & 1 ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1); + crc = (crc >>> 8) ^ c; + } + return (crc ^ 0xFFFFFFFF) >>> 0; +} diff --git a/viewer/icns.html b/viewer/icns.html new file mode 100644 index 0000000..177f730 --- /dev/null +++ b/viewer/icns.html @@ -0,0 +1,48 @@ + + + + + ICNS Viewer + + + + + + + \ No newline at end of file diff --git a/viewer/spine.html b/viewer/spine.html new file mode 100644 index 0000000..a2d9700 --- /dev/null +++ b/viewer/spine.html @@ -0,0 +1,797 @@ + + + + + + Spine 预览 + + + +

+ + + +