From a221d681ab280ed26f4d740e17c29d7b44e3307a Mon Sep 17 00:00:00 2001 From: Joywayer Date: Thu, 9 Apr 2026 17:31:46 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0spine=E7=9A=84=E6=94=AF?= =?UTF-8?q?=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- codes/games/client/Edit/Settings.ini | 20 +- codes/games/client/History.txt | 2 + .../Game_Surface_3/docs/Spine动画集成手册.md | 806 ++ .../Game_Surface_3/generated/spine_assets.js | 4 + .../Game_Surface_3/generated/spine_data.js | 5 + .../client/Projects/Game_Surface_3/index.html | 221 +- .../Projects/Game_Surface_3/js/SpineMgr.js | 416 + .../Game_Surface_3/js/spine-canvas.js | 11710 ++++++++++++++++ .../scripts/build_spine_data.cmd | 17 + .../scripts/build_spine_data.ps1 | 99 + .../games/client/Projects/Spine/FilesOrd.txt | 2 + codes/games/client/Projects/Spine/Project.txt | 6 + .../Projects/Spine/assets/bmp/00001.png | Bin 0 -> 1369170 bytes .../Projects/Spine/assets/bmp/00002.png | Bin 0 -> 1171740 bytes .../Projects/Spine/assets/bmp/gameabc_data.js | 255 + .../Spine/assets/bmp/gameabc_data.min.js | 1 + .../Spine/assets/spine/Zaijiezaili.atlas | 35 + .../Spine/assets/spine/Zaijiezaili.json | 1 + .../Spine/assets/spine/Zaijiezaili.png | Bin 0 -> 387372 bytes .../Spine/assets/spine/chipengganghu.atlas | 79 + .../Spine/assets/spine/chipengganghu.json | 1 + .../Spine/assets/spine/chipengganghu.png | Bin 0 -> 485153 bytes .../Spine/assets/spine/gamestart.atlas | 37 + .../Spine/assets/spine/gamestart.json | 1 + .../Projects/Spine/assets/spine/gamestart.png | Bin 0 -> 235589 bytes .../Projects/Spine/docs/Spine动画集成手册.md | 806 ++ .../Projects/Spine/generated/spine_assets.js | 6 + .../Projects/Spine/generated/spine_data.js | 9 + codes/games/client/Projects/Spine/index.html | 66 + .../client/Projects/Spine/js/SpineMgr.js | 416 + .../client/Projects/Spine/js/gameabc.min.js | 5544 ++++++++ .../client/Projects/Spine/js/gamemain.js | 165 + .../client/Projects/Spine/js/spine-canvas.js | 11710 ++++++++++++++++ .../Spine/output/gameabc_GameTxt.json | 3 + .../Spine/output/gameabc_GroupList.json | 3 + .../Projects/Spine/output/gameabc_Image.json | 24 + .../Projects/Spine/output/gameabc_Layer.json | 11 + .../Projects/Spine/output/gameabc_Object.json | 153 + .../Spine/output/gameabc_Project.json | 44 + .../Projects/Spine/output/gameabc_Voice.json | 3 + .../Projects/Spine/output/gameabc_data.js | 255 + .../Projects/Spine/output/gameabc_data.min.js | 1 + .../client/Projects/Spine/save/Layer00001.xml | 168 + .../client/Projects/Spine/save/Project.xml | 50 + .../client/Projects/Spine/save/ResImage.xml | 5 + .../Spine/scripts/build_spine_data.cmd | 17 + .../Spine/scripts/build_spine_data.ps1 | 99 + codes/games/client/Projects/Spine/server.html | 141 + .../server/games/erqiwang/class.arith.js | 1089 ++ .../games/server/games/erqiwang/class.desk.js | 185 + .../server/games/erqiwang/class.export.js | 273 + .../server/games/erqiwang/class.import.js | 30 + .../games/server/games/erqiwang/class.pai.js | 61 + .../server/games/erqiwang/class.paiju.js | 863 ++ codes/games/server/games/erqiwang/mod.js | 457 + .../server/games/erqiwang/二七王接口.xlsx | Bin 0 -> 23959 bytes tools/downloadWeb/index.html | 8 +- tools/downloadWeb2/css/download.css | 1508 ++ tools/downloadWeb2/css/main.css | 713 + tools/downloadWeb2/css/umi.css | 3 + tools/downloadWeb2/img/logo.png | Bin 0 -> 6217 bytes tools/downloadWeb2/index.html | 211 + tools/downloadWeb2/js/jquery-1.9.1.min.js | 5 + tools/downloadWeb2/picture/android.png | Bin 0 -> 26843 bytes tools/downloadWeb2/picture/click_btn.png | Bin 0 -> 21035 bytes tools/downloadWeb2/picture/menu.png | Bin 0 -> 22230 bytes tools/downloadWeb2/picture/menu_android.png | Bin 0 -> 21957 bytes tools/downloadWeb2/picture/safari.png | Bin 0 -> 26391 bytes tools/downloadWeb2/template/css/download.css | 1508 ++ 69 files changed, 40197 insertions(+), 134 deletions(-) create mode 100644 codes/games/client/Projects/Game_Surface_3/docs/Spine动画集成手册.md create mode 100644 codes/games/client/Projects/Game_Surface_3/generated/spine_assets.js create mode 100644 codes/games/client/Projects/Game_Surface_3/generated/spine_data.js create mode 100644 codes/games/client/Projects/Game_Surface_3/js/SpineMgr.js create mode 100644 codes/games/client/Projects/Game_Surface_3/js/spine-canvas.js create mode 100644 codes/games/client/Projects/Game_Surface_3/scripts/build_spine_data.cmd create mode 100644 codes/games/client/Projects/Game_Surface_3/scripts/build_spine_data.ps1 create mode 100644 codes/games/client/Projects/Spine/FilesOrd.txt create mode 100644 codes/games/client/Projects/Spine/Project.txt create mode 100644 codes/games/client/Projects/Spine/assets/bmp/00001.png create mode 100644 codes/games/client/Projects/Spine/assets/bmp/00002.png create mode 100644 codes/games/client/Projects/Spine/assets/bmp/gameabc_data.js create mode 100644 codes/games/client/Projects/Spine/assets/bmp/gameabc_data.min.js create mode 100644 codes/games/client/Projects/Spine/assets/spine/Zaijiezaili.atlas create mode 100644 codes/games/client/Projects/Spine/assets/spine/Zaijiezaili.json create mode 100644 codes/games/client/Projects/Spine/assets/spine/Zaijiezaili.png create mode 100644 codes/games/client/Projects/Spine/assets/spine/chipengganghu.atlas create mode 100644 codes/games/client/Projects/Spine/assets/spine/chipengganghu.json create mode 100644 codes/games/client/Projects/Spine/assets/spine/chipengganghu.png create mode 100644 codes/games/client/Projects/Spine/assets/spine/gamestart.atlas create mode 100644 codes/games/client/Projects/Spine/assets/spine/gamestart.json create mode 100644 codes/games/client/Projects/Spine/assets/spine/gamestart.png create mode 100644 codes/games/client/Projects/Spine/docs/Spine动画集成手册.md create mode 100644 codes/games/client/Projects/Spine/generated/spine_assets.js create mode 100644 codes/games/client/Projects/Spine/generated/spine_data.js create mode 100644 codes/games/client/Projects/Spine/index.html create mode 100644 codes/games/client/Projects/Spine/js/SpineMgr.js create mode 100644 codes/games/client/Projects/Spine/js/gameabc.min.js create mode 100644 codes/games/client/Projects/Spine/js/gamemain.js create mode 100644 codes/games/client/Projects/Spine/js/spine-canvas.js create mode 100644 codes/games/client/Projects/Spine/output/gameabc_GameTxt.json create mode 100644 codes/games/client/Projects/Spine/output/gameabc_GroupList.json create mode 100644 codes/games/client/Projects/Spine/output/gameabc_Image.json create mode 100644 codes/games/client/Projects/Spine/output/gameabc_Layer.json create mode 100644 codes/games/client/Projects/Spine/output/gameabc_Object.json create mode 100644 codes/games/client/Projects/Spine/output/gameabc_Project.json create mode 100644 codes/games/client/Projects/Spine/output/gameabc_Voice.json create mode 100644 codes/games/client/Projects/Spine/output/gameabc_data.js create mode 100644 codes/games/client/Projects/Spine/output/gameabc_data.min.js create mode 100644 codes/games/client/Projects/Spine/save/Layer00001.xml create mode 100644 codes/games/client/Projects/Spine/save/Project.xml create mode 100644 codes/games/client/Projects/Spine/save/ResImage.xml create mode 100644 codes/games/client/Projects/Spine/scripts/build_spine_data.cmd create mode 100644 codes/games/client/Projects/Spine/scripts/build_spine_data.ps1 create mode 100644 codes/games/client/Projects/Spine/server.html create mode 100644 codes/games/server/games/erqiwang/class.arith.js create mode 100644 codes/games/server/games/erqiwang/class.desk.js create mode 100644 codes/games/server/games/erqiwang/class.export.js create mode 100644 codes/games/server/games/erqiwang/class.import.js create mode 100644 codes/games/server/games/erqiwang/class.pai.js create mode 100644 codes/games/server/games/erqiwang/class.paiju.js create mode 100644 codes/games/server/games/erqiwang/mod.js create mode 100644 codes/games/server/games/erqiwang/二七王接口.xlsx create mode 100644 tools/downloadWeb2/css/download.css create mode 100644 tools/downloadWeb2/css/main.css create mode 100644 tools/downloadWeb2/css/umi.css create mode 100644 tools/downloadWeb2/img/logo.png create mode 100644 tools/downloadWeb2/index.html create mode 100644 tools/downloadWeb2/js/jquery-1.9.1.min.js create mode 100644 tools/downloadWeb2/picture/android.png create mode 100644 tools/downloadWeb2/picture/click_btn.png create mode 100644 tools/downloadWeb2/picture/menu.png create mode 100644 tools/downloadWeb2/picture/menu_android.png create mode 100644 tools/downloadWeb2/picture/safari.png create mode 100644 tools/downloadWeb2/template/css/download.css diff --git a/codes/games/client/Edit/Settings.ini b/codes/games/client/Edit/Settings.ini index 078f3de..bc93c87 100644 --- a/codes/games/client/Edit/Settings.ini +++ b/codes/games/client/Edit/Settings.ini @@ -123,16 +123,16 @@ DocumentTypeKeyWordsFile1= DocumentTypeFunctionRegExp1= [MRUFiles] -MRUItem1=G:\Works\YouleGames\games\games\Projects\clinet\gamehall\js\gamemain.js -MRUItem2=G:\Works\YouleGames\games\games\Projects\clinet\zpy\js\gamemain.js -MRUItem3=G:\Works\YouleGames\games\games\Projects\Project1\js\gamemain.js -MRUItem4=G:\Works\YouleGames\games\games\Projects\clinet\sangelaok\js\gamemain.js -MRUItem5=G:\Works\YouleGames\games\games\Projects\clinet\niuniu\js\gamemain.js -MRUItem6=G:\Works\YouleGames\games\games\Projects\clinet\guanpai-jx\js\gamemain.js -MRUItem7=G:\Works\YouleGames\games\games\Projects\clinet\doudizhu\js\gamemain.js -MRUItem8=G:\Works\JinXianProjects\JinXianMahjong\Projects\client\js\gamemain.js -MRUItem9=G:\Works\JinXianProjects\JinXianMahjong\Projects\Project1\js\gamemain.js -MRUItem10=G:\Works\JinXianProjects\JinXianMahjong\Projects\client\js\client_Event.js +MRUItem1=G:\Works\YouleGames\codes\games\client\Projects\Project1\js\gamemain.js +MRUItem2=G:\Works\YouleGames\codes\games\client\Projects\Spine\js\gamemain.js +MRUItem3=G:\Works\YouleGames\codes\games\client\Projects\Spine\index.html +MRUItem4=G:\Works\YouleGames\games\games\Projects\clinet\gamehall\js\gamemain.js +MRUItem5=G:\Works\YouleGames\games\games\Projects\clinet\zpy\js\gamemain.js +MRUItem6=G:\Works\YouleGames\games\games\Projects\Project1\js\gamemain.js +MRUItem7=G:\Works\YouleGames\games\games\Projects\clinet\sangelaok\js\gamemain.js +MRUItem8=G:\Works\YouleGames\games\games\Projects\clinet\niuniu\js\gamemain.js +MRUItem9=G:\Works\YouleGames\games\games\Projects\clinet\guanpai-jx\js\gamemain.js +MRUItem10=G:\Works\YouleGames\games\games\Projects\clinet\doudizhu\js\gamemain.js [MRUFindText] MRUItem1= diff --git a/codes/games/client/History.txt b/codes/games/client/History.txt index 7a17c9a..af6822f 100644 --- a/codes/games/client/History.txt +++ b/codes/games/client/History.txt @@ -1,3 +1,5 @@ +G:\Works\YouleGames\codes\games\client\Projects\Spine\ +G:\Works\YouleGames\codes\games\client\Projects\Project1\ G:\Works\YouleGames\games\games\Projects\clinet\gamehall\ G:\Works\YouleGames\games\games\Projects\clinet\zpy\ G:\Works\YouleGames\games\games\Projects\clinet\sangelaok\ diff --git a/codes/games/client/Projects/Game_Surface_3/docs/Spine动画集成手册.md b/codes/games/client/Projects/Game_Surface_3/docs/Spine动画集成手册.md new file mode 100644 index 0000000..e7398eb --- /dev/null +++ b/codes/games/client/Projects/Game_Surface_3/docs/Spine动画集成手册.md @@ -0,0 +1,806 @@ +# Spine 动画集成手册 + +> 本手册针对 **gameabc 引擎** 的 Spine 项目,说明如何在 Canvas 2D 游戏中加载、 +> 控制和管理 Spine 骨骼动画。 +> 运行时版本:**spine-canvas 4.2** | 引擎:**gameabc** + +--- + +## 目录 + +1. [项目结构总览](#1-项目结构总览) +2. [快速开始:5 分钟跑通](#2-快速开始5-分钟跑通) +3. [从 Spine 编辑器导出资源](#3-从-spine-编辑器导出资源) +4. [SpineMgr 完整 API 参考](#4-spinemgr-完整-api-参考) +5. [事件系统](#5-事件系统) +6. [常见用法示例](#6-常见用法示例) +7. [与 gameabc 精灵系统配合](#7-与-gameabc-精灵系统配合) +8. [性能优化建议](#8-性能优化建议) +9. [常见问题排查](#9-常见问题排查) +10. [附录:文件加载顺序](#10-附录文件加载顺序) + +--- + +## 1. 项目结构总览 + +``` +Projects/Spine/ +├── index.html ← 入口 HTML +├── js/ +│ ├── spine-canvas.js ← Spine Canvas 2D 运行时 (第三方库) +│ ├── gameabc.min.js ← gameabc 游戏引擎 +│ ├── SpineMgr.js ← ★ Spine 动画管理器(独立文件,自动挂钩渲染) +│ ├── gamemain.js ← 游戏主逻辑(无需修改) +│ ├── Spine_Event.js ← Spine 事件回调 (complete / event) +│ └── Project1_Event.js ← 精灵事件单元 +├── assets/ +│ ├── bmp/ ← gameabc 图片资源 +│ └── spine/ ← ★ Spine 资源目录 +│ ├── xxx.json ← 骨骼数据 (Spine 编辑器导出) +│ ├── xxx.atlas ← 图集描述文件 +│ └── xxx.png ← 图集纹理图片 +├── output/ ← gameabc 编译输出的配置数据 +├── save/ ← gameabc 编辑器保存的 XML +└── docs/ ← 本文档所在目录 +``` + +### 关键文件说明 + +| 文件 | 作用 | 需要修改 | +|------|------|----------| +| `js/spine-canvas.js` | Spine 4.2 Canvas 渲染运行时 | ✗ 不要修改 | +| `js/SpineMgr.js` | Spine 动画管理器,自动初始化+自动渲染 | ✗ 不需要修改 | +| `js/gamemain.js` | 游戏主逻辑(保持原样) | ✗ 不需要修改 | +| `js/Spine_Event.js` | Spine 动画完成/自定义事件回调 | ✓ 处理动画事件 | +| `assets/spine/*` | Spine 导出的资源文件 | ✓ 放入你的资源 | + +--- + +## 2. 快速开始:5 分钟跑通 + +### 第一步:准备 Spine 资源 + +将 Spine 编辑器导出的 3 个文件复制到 `assets/spine/` 目录: + +``` +assets/spine/ +├── hero.json ← 骨骼 JSON +├── hero.atlas ← 图集描述 +└── hero.png ← 图集纹理 +``` + +### 第二步:在任意位置调用 API 播放动画 + +**无需手动 `load`**,直接调用 `setAnimation` 即可。如果该 Spine 实例尚未加载,会自动根据 id 查找资源(约定文件名 id.json / id.atlas)并创建实例。 +渲染也已自动挂钩到 `gameenddraw`,开发者无需编写任何渲染代码。 + +在任何 gameabc 事件回调中直接调用即可: + +```javascript +// 设置位置 + 播放动画,无需先 load +gameabc_face.spineMgr.setPosition("hero", 640, 500); +gameabc_face.spineMgr.setAnimation("hero", "idle", true); + +// 之后切换动画 +gameabc_face.spineMgr.setAnimation("hero", "attack", false); +``` + +> **约定**:id 必须与资源文件名一致(不含扩展名)。例如 id 为 `"hero"`, +> 则需要 `assets/spine/hero.json`、`hero.atlas`、`hero.png`。 +> +> **可选**:如果资源不在默认路径 `assets/spine/`,可手动调用一次 `init()`: +> ```javascript +> gameabc_face.spineMgr.init("other/path/"); +> ``` + +### 第三步:打开 index.html 即可运行 + +用浏览器打开 `index.html`(需要 HTTP 服务器环境,不能直接 `file://`): + +```bash +# 简易方法:在项目目录下启动 HTTP 服务 +cd codes/games/client/Projects/Spine +npx http-server -p 8080 +# 浏览器访问 http://localhost:8080 +``` + +或者使用 gameabc 自带的预览环境。 + +--- + +## 3. 从 Spine 编辑器导出资源 + +### 导出设置(Spine 编辑器 → Export) + +1. 打开 Spine 编辑器,加载你的 `.spine` 项目 +2. 点击菜单 **Spine → Export...** +3. 左侧选择 **JSON** 格式 +4. 配置项: + +| 设置项 | 推荐值 | 说明 | +|--------|--------|------| +| Output folder | `assets/spine/` | 直接导出到项目目录 | +| Extension | `.json` | 骨骼数据格式 | +| Create atlas | ✓ 勾选 | 同时生成图集 | +| Atlas extension | `.atlas` | 图集描述格式 | +| Images folder | (默认) | 纹理来源 | +| Max width/height | 2048 / 2048 | 图集纹理最大尺寸 | +| Pack settings → Power of two | ✓ 勾选 | 纹理尺寸为 2 的幂 | +| Pack settings → Premultiply alpha | ✗ 不勾选 | Canvas 2D 不需要预乘 | + +5. 点击 **Export** 按钮 + +### 导出后得到的文件 + +``` +hero.json ← 骨骼数据,包含骨骼、插槽、动画等 +hero.atlas ← 图集描述,记录每个区域在纹理中的位置 +hero.png ← 图集纹理图片 +``` + +> **注意**:如果图集很大被拆分成多张(`hero.png`、`hero2.png`),所有 `.png` +> 都需要放到 `assets/spine/` 目录中。`.atlas` 文件会自动引用它们。 + +--- + +## 4. SpineMgr 完整 API 参考 + +`SpineMgr` 挂载在 `gameabc_face.spineMgr` 上,所有调用形如: + +```javascript +gameabc_face.spineMgr.方法名(参数); +``` + +--- + +### 4.1 init(basePath) *(可选)* + +**手动设置资源根路径。通常无需调用——`load()` 会自动以默认路径 `"assets/spine/"` 初始化。** +仅在资源放在其他目录时才需要调用: + +```javascript +gameabc_face.spineMgr.init("other/spine/path/"); +``` + +| 参数 | 类型 | 说明 | +|------|------|------| +| `basePath` | string | Spine 资源文件的根目录路径,需要以 `/` 结尾。省略则使用默认值 `"assets/spine/"` | + +--- + +### 4.2 load(id, jsonFile, atlasFile, option) *(可选)* + +**手动加载一组 Spine 资源并注册为一个实例。通常无需调用——所有 API 在实例不存在时会自动加载。** + +仅在以下情况需要手动调用 `load()`: +- id 与文件名不一致(如 id 为 `"mj"` 但文件为 `mj_gangshangkaihua.json`) +- 需要在加载时指定 skin、scale 等初始参数 + +```javascript +gameabc_face.spineMgr.load("hero", "hero.json", "hero.atlas", { + x: 640, + y: 500, + scale: 0.5, + skin: "default", + animation: "idle", + loop: true, + mixDuration: 0.2 +}); +``` + +| 参数 | 类型 | 说明 | +|------|------|------| +| `id` | string | 唯一标识,后续所有操作通过此 id 引用 | +| `jsonFile` | string | 骨骼 JSON 文件名(相对于 basePath) | +| `atlasFile` | string | 图集 atlas 文件名(相对于 basePath) | +| `option` | object | 可选配置对象 | + +**option 字段:** + +| 字段 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `x` | number | 0 | Canvas X 坐标 | +| `y` | number | 0 | Canvas Y 坐标 | +| `scale` | number | 1 | 初始缩放比例 | +| `skin` | string | `"default"` | 初始皮肤名称 | +| `animation` | string | null | 加载完成后自动播放的动画名 | +| `loop` | boolean | true | 默认动画是否循环 | +| `mixDuration` | number | 0.2 | 动画切换时的过渡混合时长(秒) | + +--- + +### 4.3 setAnimation(id, animName, loop, track) + +**切换动画。立即替换指定轨道上的当前动画。如果实例尚未加载,会自动根据 id 加载资源并在就绪后播放。** + +```javascript +// 无需先 load,直接调用即可 +gameabc_face.spineMgr.setAnimation("hero", "attack", false); +gameabc_face.spineMgr.setAnimation("hero", "run", true, 0); +``` + +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `id` | string | - | 实例标识 | +| `animName` | string | - | 动画名称(必须在 Spine 中存在) | +| `loop` | boolean | true | 是否循环播放 | +| `track` | number | 0 | 轨道号(多轨道可叠加动画) | + +**返回值:** `TrackEntry` 对象,可用于进一步控制;加载未完成时返回 `null`。 + +--- + +### 4.4 addAnimation(id, animName, loop, delay, track) + +**将动画添加到播放队列,在当前动画结束后自动播放。** + +```javascript +// 先播放 attack,attack 完成后自动切换到 idle +gameabc_face.spineMgr.setAnimation("hero", "attack", false); +gameabc_face.spineMgr.addAnimation("hero", "idle", true, 0); +``` + +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `id` | string | - | 实例标识 | +| `animName` | string | - | 队列中的下一个动画 | +| `loop` | boolean | true | 是否循环 | +| `delay` | number | 0 | 延迟秒数(0 = 上一动画结束时立即开始) | +| `track` | number | 0 | 轨道号 | + +--- + +### 4.5 setPosition(id, x, y) + +**设置 Spine 实例在 Canvas 上的位置。** + +```javascript +gameabc_face.spineMgr.setPosition("hero", 640, 500); +``` + +> Spine 的坐标原点在骨骼的根骨骼处。Y 轴向上为正(与 Canvas 的 Y 轴方向相反), +> spine-canvas 运行时已做了内部转换。 + +--- + +### 4.6 setScale(id, sx, sy) + +**设置缩放。** + +```javascript +gameabc_face.spineMgr.setScale("hero", 0.5); // 等比缩放 +gameabc_face.spineMgr.setScale("hero", 0.5, 0.8); // 分别设置 X/Y +``` + +| 参数 | 类型 | 说明 | +|------|------|------| +| `sx` | number | X 方向缩放 | +| `sy` | number | Y 方向缩放(省略则等于 sx) | + +--- + +### 4.7 setFlip(id, flipX, flipY) + +**水平/垂直翻转。** + +```javascript +gameabc_face.spineMgr.setFlip("hero", true, false); // 水平翻转 +``` + +--- + +### 4.8 setVisible(id, visible) + +**显示或隐藏 Spine 实例。** + +```javascript +gameabc_face.spineMgr.setVisible("hero", false); // 隐藏 +gameabc_face.spineMgr.setVisible("hero", true); // 显示 +``` + +--- + +### 4.9 setSkin(id, skinName) + +**切换皮肤。** + +```javascript +gameabc_face.spineMgr.setSkin("hero", "warrior"); +``` + +> 切换皮肤后会自动重置插槽到 Setup Pose。皮肤名必须在 Spine 编辑器中预定义。 + +--- + +### 4.10 getAnimations(id) + +**获取该实例所有可用动画名称列表。** + +```javascript +var anims = gameabc_face.spineMgr.getAnimations("hero"); +// 返回: ["idle", "walk", "run", "attack", "die"] +logmessage("动画列表: " + anims.join(", ")); +``` + +--- + +### 4.11 getSkins(id) + +**获取该实例所有可用皮肤名称列表。** + +```javascript +var skins = gameabc_face.spineMgr.getSkins("hero"); +// 返回: ["default", "warrior", "mage"] +``` + +--- + +### 4.12 playOnce(id, animName, track) + +**播放一次动画后自动隐藏。** 自动显示实例、播放指定动画(不循环),动画完成后自动设置 `visible = false`。 + +```javascript +// 播放一次攻击动画,播完自动隐藏 +gameabc_face.spineMgr.playOnce("hero", "attack"); + +// 指定轨道 +gameabc_face.spineMgr.playOnce("hero", "attack", 0); +``` + +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `id` | string | - | 实例标识 | +| `animName` | string | - | 动画名称 | +| `track` | number | 0 | 轨道号 | + +--- + +### 4.13 playQueue(id, animList, hideOnComplete) + +**按顺序播放一组动画(队列),全部播完后可选择隐藏或保持显示。** 自动显示实例,队列中每个动画均播放一次(不循环),依次播放。 + +```javascript +// 播放 attack → die,全部播完后自动隐藏(默认) +gameabc_face.spineMgr.playQueue("hero", ["attack", "die"]); + +// 播放 intro → idle,全部播完后保持显示 +gameabc_face.spineMgr.playQueue("hero", ["intro", "idle"], false); +``` + +| 参数 | 类型 | 默认值 | 说明 | +|------|------|--------|------| +| `id` | string | - | 实例标识 | +| `animList` | string[] | - | 动画名称数组,按顺序依次播放 | +| `hideOnComplete` | boolean | true | `true` = 队列全部播完后自动隐藏;`false` = 保持显示 | + +--- + +### 4.14 remove(id) + +**销毁指定 Spine 实例,释放内存。** + +```javascript +gameabc_face.spineMgr.remove("hero"); +``` + +--- + +### 4.15 removeAll() + +**销毁所有 Spine 实例。** + +```javascript +gameabc_face.spineMgr.removeAll(); +``` + +### 4.16 spine_onComplete(spineId, animName, trackIndex) *(事件回调)* + +**动画完成回调。每次动画播放一轮结束时触发。** 在 `js/Spine_Event.js` 中定义。 + +```javascript +// 在 Spine_Event.js 中定义 +gameabc_face.spine_onComplete = function(spineId, animName, trackIndex) { + // 示例:攻击播完后恢复 idle + if (animName === "attack") { + gameabc_face.spineMgr.setAnimation(spineId, "idle", true); + } +}; +``` + +| 参数 | 类型 | 说明 | +|------|------|------| +| `spineId` | string | 实例标识(即 load / autoLoad 时的 id) | +| `animName` | string | 刚完成的动画名称 | +| `trackIndex` | number | 轨道号(通常为 0) | + +> **注意**:循环动画每播完一轮也会触发。`playOnce` / `playQueue` 的自动隐藏在此回调**之前**执行, +> 因此回调中可以检查 `visible` 状态或重新显示实例。 + +--- + +### 4.17 spine_onEvent(spineId, eventName, intValue, floatValue, stringValue) *(事件回调)* + +**自定义事件回调。当动画播放到 Spine 编辑器中定义的 Event 关键帧时触发。** 在 `js/Spine_Event.js` 中定义。 + +```javascript +// 在 Spine_Event.js 中定义 +gameabc_face.spine_onEvent = function(spineId, eventName, intValue, floatValue, stringValue) { + if (eventName === "footstep") { + // 播放脚步声 + } + if (eventName === "hit") { + // 产生伤害判定 + } +}; +``` + +| 参数 | 类型 | 说明 | +|------|------|------| +| `spineId` | string | 实例标识 | +| `eventName` | string | Spine 编辑器中定义的事件名 | +| `intValue` | number | 事件的整数参数 | +| `floatValue` | number | 事件的浮点参数 | +| `stringValue` | string | 事件的字符串参数 | + +> 事件需要在 Spine 编辑器的时间线中预先添加 Event Key,导出 JSON 后运行时自动解析。 + +--- + +## 5. 事件系统(详细说明) + +Spine 动画在运行时会触发两类事件,回调定义在 `js/Spine_Event.js` 中。 +API 签名见 [4.16](#416-spine_oncompletespineid-animname-trackindex--事件回调) 和 [4.17](#417-spine_oneventspineid-eventname-intvalue-floatvalue-stringvalue--事件回调)。 + +### 5.1 动画完成事件 spine_onComplete + +**每次动画循环播放一轮结束时触发。** + +```javascript +// 在 Spine_Event.js 中 +gameabc_face.spine_onComplete = function(spineId, animName, trackIndex) { + // spineId : load 时的唯一标识, 如 "hero" + // animName : 完成的动画名, 如 "attack" + // trackIndex : 轨道号 (通常为 0) + + // 示例:非循环攻击动画播完后恢复 idle + if (animName === "attack") { + gameabc_face.spineMgr.setAnimation(spineId, "idle", true); + } +}; +``` + +### 5.2 自定义事件 spine_onEvent + +**当动画播放到 Spine 编辑器中定义的 Event 关键帧时触发。** + +```javascript +// 在 Spine_Event.js 中 +gameabc_face.spine_onEvent = function(spineId, eventName, intValue, floatValue, stringValue) { + // spineId : 唯一标识 + // eventName : Spine 编辑器中定义的事件名 + // intValue : 整数参数 + // floatValue : 浮点参数 + // stringValue : 字符串参数 + + if (eventName === "footstep") { + // 播放脚步声 + } + if (eventName === "hit") { + // 产生伤害判定 + } +}; +``` + +### 如何在 Spine 编辑器中添加事件 + +1. 打开 Spine 编辑器,选中动画 +2. 在时间线底部点击右键 → **Add Event Key** +3. 在 **Tree** 面板中创建并命名事件(如 `hit`、`footstep`) +4. 可为事件设置 int / float / string 参数 +5. 导出 JSON 后,运行时会自动解析并触发回调 + +--- + +## 6. 常见用法示例 + +### 6.1 加载多个角色 + +```javascript +// 在 gamestart 或任意时机,直接设置位置并播放(自动加载) +gameabc_face.spineMgr.setPosition("hero", 640, 500); +gameabc_face.spineMgr.setAnimation("hero", "idle", true); + +gameabc_face.spineMgr.setPosition("npc", 300, 500); +gameabc_face.spineMgr.setAnimation("npc", "idle", true); + +gameabc_face.spineMgr.setPosition("monster", 900, 500); +gameabc_face.spineMgr.setAnimation("monster", "walk", true); +``` + +### 6.2 播放一次后隐藏 / 队列播放 + +```javascript +// 播放一次攻击动画,完成后自动隐藏 +gameabc_face.spineMgr.setPosition("effect", 640, 400); +gameabc_face.spineMgr.playOnce("effect", "explode"); + +// 队列播放:攻击 → 死亡,全部播完后自动隐藏 +gameabc_face.spineMgr.playQueue("monster", ["hit", "die"]); + +// 队列播放:入场 → 待机,全部播完后保持显示 +gameabc_face.spineMgr.playQueue("hero", ["intro", "idle"], false); +``` + +### 6.3 点击切换动画(攻击→恢复) + +```javascript +gameabc_face.mousedown = function(gameid, spid, downx, downy) { + // 点击播放攻击(非循环) + gameabc_face.spineMgr.setAnimation("hero", "attack", false); + // 攻击完自动切回 idle + gameabc_face.spineMgr.addAnimation("hero", "idle", true, 0); +}; +``` + +### 6.4 角色移动 + 动画联动 + +```javascript +var heroState = "idle"; + +gameabc_face.mousedown = function(gameid, spid, downx, downy) { + heroState = "run"; + gameabc_face.spineMgr.setAnimation("hero", "run", true); +}; + +gameabc_face.mouseup = function(gameid, spid_down, downx, downy, spid_up, upx, upy) { + heroState = "idle"; + gameabc_face.spineMgr.setAnimation("hero", "idle", true); +}; + +gameabc_face.mousemove = function(gameid, spid, downx, downy, movex, movey, timelong, offmovex, offmovey) { + // 通过拖拽移动角色 + var mgr = gameabc_face.spineMgr; + var entry = mgr._entries["hero"]; + if (entry) { + mgr.setPosition("hero", entry.x + offmovex, entry.y + offmovey); + // 根据移动方向翻转 + mgr.setFlip("hero", offmovex < 0, false); + } +}; +``` + +### 6.5 多轨道叠加(走路 + 射击) + +Spine 支持多轨道同时播放动画。低轨道(track 0)为基础动画,高轨道覆盖部分骨骼: + +```javascript +// track 0: 下半身走路 +gameabc_face.spineMgr.setAnimation("hero", "walk", true, 0); + +// track 1: 上半身射击(在 Spine 编辑器中只设置上半身骨骼的关键帧) +gameabc_face.spineMgr.setAnimation("hero", "shoot", false, 1); +``` + +### 6.6 动态切换皮肤(换装系统) + +```javascript +// 查看有哪些皮肤 +var skins = gameabc_face.spineMgr.getSkins("hero"); +logmessage("可用皮肤: " + skins.join(", ")); + +// 切换到战士皮肤 +gameabc_face.spineMgr.setSkin("hero", "warrior"); + +// 切换到法师皮肤 +gameabc_face.spineMgr.setSkin("hero", "mage"); +``` + +### 6.7 运行时查询动画列表 + +```javascript +gameabc_face.spine_onComplete = function(spineId, animName, trackIndex) { + var anims = gameabc_face.spineMgr.getAnimations(spineId); + logmessage(spineId + " 拥有的动画: " + anims.join(", ")); +}; +``` + +--- + +## 7. 与 gameabc 精灵系统配合 + +### 渲染时序 + +``` +gameabc 引擎循环 (每帧) + │ + ├── gamebegindraw() ← 帧开始 + ├── 遍历 Layer → 每个精灵: + │ ├── gamemydrawbegin() + │ ├── 精灵自绘 (图片/文字) + │ └── gamemydraw() + ├── gameenddraw() ← 用户自定义逻辑 + │ └── (自动) spineMgr.updateAndDraw(ctx) ← ★ 通过 defineProperty 自动追加 + └── 帧结束 +``` + +Spine 动画在 `gameenddraw` 末尾**自动渲染**(通过 `Object.defineProperty` 拦截实现, +无论开发者如何重新定义 `gameenddraw`,Spine 渲染都不会丢失), +因此会**覆盖在所有 gameabc 精灵之上**。 +开发者在 `gameenddraw` 中编写的自定义逻辑会先执行,Spine 渲染在其后自动执行。 + +### 如果需要 Spine 在精灵之下渲染 + +可以通过手动控制渲染时机来实现。在 `gamebegindraw` 中手动调用渲染,并禁用自动渲染: + +```javascript +// 方式:在 gamebegindraw 中手动渲染 +gameabc_face.gamebegindraw = function(gameid, spid, times, timelong) { + var ctx = gameabc_face.dc; + if (ctx) { + gameabc_face.spineMgr.updateAndDraw(ctx); + } + // 标记自动渲染跳过(因为已在此手动渲染) + gameabc_face.spineMgr._rendered = true; +}; +``` + +> 注意:当前自动挂钩在 gameenddraw 末尾,如需精细控制层级, +> 可将 SpineMgr._inited 临时置 false 跳过自动渲染,手动选择渲染时机。 + +### 让 Spine 跟随某个精灵移动 + +```javascript +gameabc_face.gamemydraw = function(gameid, spid, times, timelong) { + // 让 Spine 角色跟随精灵 1 的位置 + if (spid === 1) { + var sx = get_self(1, 18, 0, 0, 0); // 获取精灵 1 的 X + var sy = get_self(1, 19, 0, 0, 0); // 获取精灵 1 的 Y + gameabc_face.spineMgr.setPosition("hero", sx, sy); + } +}; +``` + +--- + +## 8. 性能优化建议 + +### 8.1 图集纹理 + +- 纹理尺寸建议不超过 **2048×2048** +- 导出时勾选 **Power of two** 确保尺寸为 2 的幂 +- 不要勾选 **Premultiply alpha**(Canvas 2D 不需要预乘 Alpha) + +### 8.2 控制实例数量 + +- Canvas 2D 渲染性能有限,建议同屏 Spine 实例不超过 **5-8 个** +- 不可见的实例调用 `setVisible(id, false)`,跳过渲染和更新 +- 不再需要的实例调用 `remove(id)` 释放内存 + +### 8.3 减少骨骼复杂度 + +- 骨骼数量建议控制在 **50 个**以内 +- 减少网格变形(Mesh Deform),对 Canvas 2D 影响较大 +- 使用裁剪(Clipping)时性能开销大,谨慎使用 + +### 8.4 动画混合时长 + +`mixDuration` 越长,过渡越平滑,但在切换瞬间需要同时计算两个动画。 +建议设为 **0.1 ~ 0.3 秒**。 + +--- + +## 9. 常见问题排查 + +### Q1: 画面上看不到 Spine 动画 + +**检查清单:** + +1. **文件路径是否正确?** + - 确认 `assets/spine/` 目录下有 `.json`、`.atlas`、`.png` + - 文件名大小写必须一致(Linux/Mac 服务器区分大小写) + +2. **是否通过 HTTP 访问?** + - `file://` 协议无法加载跨域资源,必须使用 HTTP 服务器 + +3. **打开浏览器控制台(F12)看报错** + - 404 错误:文件路径有误 + - JSON 解析错误:`.json` 文件格式异常 + - `spine is not defined`:`spine-canvas.js` 未正确加载 + +4. **坐标是否在可见范围内?** + - 项目设计尺寸为 1280×720,检查 `x` 和 `y` 是否在此范围 + +5. **logmessage 输出是否有 "[SpineMgr] xxx 构建完成"?** + - 有 → 加载成功,检查坐标和缩放 + - 有 "构建失败" → 查看具体错误信息 + - 没有 → 资源还在加载中或路径错误 + +### Q2: 动画显示位置不对 + +- Spine 编辑器中设置骨骼原点的位置会影响运行时的锚点 +- 调整 `setPosition` 的坐标,或在 Spine 编辑器中修改根骨骼位置 +- 注意 Spine 的 Y 轴与 Canvas Y 轴方向可能不同 + +### Q3: 动画速度太快或太慢 + +- 检查 `gameabc_Project` 中的 `fps` 设置(默认 30) +- SpineMgr 内部是用 `Date.now()` 计算真实时间差的,不依赖帧率 +- 如果需要倍速播放,修改 `state.timeScale`: + ```javascript + var entry = gameabc_face.spineMgr._entries["hero"]; + entry.state.timeScale = 2.0; // 2 倍速 + ``` + +### Q4: 切换动画时有跳帧 + +- 增大 `mixDuration`(加载时的 option 或修改 `stateData.defaultMix`) +- 使用 `addAnimation` 排队而不是直接 `setAnimation` 打断 + +### Q5: 多个 Spine 实例重叠时闪烁 + +- 确认没有同一个 id 加载两次 +- 检查 `ctx.save()` / `ctx.restore()` 是否配对(SpineMgr 内部已处理) + +### Q6: spine-canvas.js 版本与 Spine 编辑器版本不匹配 + +- **spine-canvas.js 4.2** 需搭配 **Spine 编辑器 4.2.x** 导出的数据 +- 如果使用 Spine 4.1 编辑器,请下载对应版本的运行时: + ``` + https://unpkg.com/@esotericsoftware/spine-canvas@4.1/dist/iife/spine-canvas.js + ``` + +--- + +## 10. 附录:文件加载顺序 + +`index.html` 中的 script 标签加载顺序至关重要: + +``` +1. spine-canvas.js ← 先加载 Spine 运行时 (定义 window.spine) +2. gameabc.min.js ← 再加载游戏引擎 +3. SpineMgr.js ← Spine 管理器 + defineProperty 自动挂钩渲染 +4. gamemain.js ← 游戏主逻辑(不需修改,直接调用 API 即可) +5. Spine_Event.js ← Spine 事件回调 (依赖 gameabc_face) +6. Project1_Event.js ← 精灵事件 +7. gameabc_data.min.js ← 项目配置数据 (引擎初始化) +``` + +> **不能调换顺序**,`SpineMgr.js` 必须在 `gamemain.js` 之前加载, +> 否则会出现 `spine is not defined` 或 `gameabc_face.spineMgr is undefined` 的错误。 + +--- + +## 附录:完整最小示例 gamemain.js + +`gamemain.js` **不需要任何修改**,保持原样即可。在任意事件回调中直接调用 `gameabc_face.spineMgr` 的 API: + +```javascript +// gamemain.js —— 无需修改框架,只需在回调中调用 API + +gameabc_face.gamestart = function(gameid) { + // 直接设置位置并播放动画(自动加载,无需 load) + gameabc_face.spineMgr.setPosition("mj_gangshangkaihua", 640, 500); + gameabc_face.spineMgr.setAnimation("mj_gangshangkaihua", "animation", true); +}; + +// gameenddraw 保持原样,Spine 渲染由 SpineMgr.js 自动处理 +gameabc_face.gameenddraw = function(gameid, spid, times, timelong) { + // 这里写其他自定义绘制逻辑,或留空 +}; + +gameabc_face.mousedown = function(gameid, spid, downx, downy) { + // 点击播放动画 + gameabc_face.spineMgr.setAnimation("mj_gangshangkaihua", "animation", false); +}; +``` + +> **重要**:`SpineMgr.js` 是独立文件,通过 `Object.defineProperty` 自动拦截 `gameenddraw`, +> 无论 `gamemain.js` 如何定义 `gameenddraw`,Spine 渲染都会自动追加在其后执行。 +> `gamemain.js` 完全不需要修改。 + +--- + +> **参考链接** +> - Spine 官方运行时文档: https://zh.esotericsoftware.com/spine-api-reference +> - Spine Player 在线演示: https://jp.esotericsoftware.com/spine-player +> - spine-canvas npm 包: https://www.npmjs.com/package/@esotericsoftware/spine-canvas diff --git a/codes/games/client/Projects/Game_Surface_3/generated/spine_assets.js b/codes/games/client/Projects/Game_Surface_3/generated/spine_assets.js new file mode 100644 index 0000000..6866ab1 --- /dev/null +++ b/codes/games/client/Projects/Game_Surface_3/generated/spine_assets.js @@ -0,0 +1,4 @@ +// Spine resource list (auto-generated, do not edit manually) +gameabc_face.spineAssets = [ + "gamestart" +]; diff --git a/codes/games/client/Projects/Game_Surface_3/generated/spine_data.js b/codes/games/client/Projects/Game_Surface_3/generated/spine_data.js new file mode 100644 index 0000000..26135da --- /dev/null +++ b/codes/games/client/Projects/Game_Surface_3/generated/spine_data.js @@ -0,0 +1,5 @@ +// Spine text data (auto-generated, do not edit manually) +// Embeds .json/.atlas content into JS to bypass file:// XHR CORS +gameabc_face.spineTextData = {}; +gameabc_face.spineTextData['gamestart.json'] = '{"skeleton":{"hash":"Cs22lzcwV3A","spine":"4.2.43","x":-862.3,"y":-188.35,"width":1724.6,"height":375.11,"images":"./0/","audio":"I:\\\\游戏素材收集\\\\棋牌\\\\闲来斗地主\\\\spine\\\\UI\\\\pipei_fx"},"bones":[{"name":"root"},{"name":"loading","parent":"root"},{"name":"pipeizhong","parent":"root"},{"name":"zhong","parent":"pipeizhong","length":35.15,"rotation":88.12,"x":97.58,"y":5.54},{"name":"pi","parent":"pipeizhong","x":-86.85,"y":2.78},{"name":"pei","parent":"pipeizhong","x":0.58,"y":-3.86},{"name":"lizi","parent":"root","length":9.44,"rotation":5.19,"x":187.44,"y":25.51},{"name":"lizi2","parent":"root","length":9.44,"rotation":5.19,"x":-235.41,"y":-103.34,"scaleX":0.9,"scaleY":0.9},{"name":"lizi3","parent":"root","length":9.44,"rotation":5.19,"x":91.71,"y":-113.98,"scaleX":0.8,"scaleY":0.8},{"name":"lizi4","parent":"root","length":9.44,"rotation":5.19,"x":-202.78,"y":94.66},{"name":"lizi5","parent":"root","length":9.44,"rotation":5.19,"x":167.97,"y":36.8,"scaleX":0.5,"scaleY":0.5},{"name":"lizi6","parent":"root","length":9.44,"rotation":5.19,"x":-162.19,"y":6.78,"scaleX":0.5,"scaleY":0.5},{"name":"taoxin_zong","parent":"root"},{"name":"glow_y","parent":"root"},{"name":"fangkuai","parent":"root","length":28.56,"x":343.36,"y":-3.03,"scaleX":0.8,"scaleY":0.8},{"name":"tiao_new","parent":"root"},{"name":"heitao","parent":"tiao_new"},{"name":"heitao2","parent":"tiao_new"},{"name":"lizi7","parent":"root","length":9.44,"rotation":5.19,"x":60.86,"y":77.88},{"name":"lizi8","parent":"root","length":9.44,"rotation":5.19,"x":-73.19,"y":-90.44,"scaleX":1.5,"scaleY":1.5},{"name":"glow_y2","parent":"root"},{"name":"star","parent":"root","length":17.48,"x":14.55,"y":40.7},{"name":"fangkuai2","parent":"root","length":28.56,"x":343.36,"y":-3.03,"scaleX":0.4,"scaleY":0.4},{"name":"fangkuai3","parent":"root","length":28.56,"x":343.36,"y":-3.03,"scaleX":0.6,"scaleY":0.6},{"name":"fangkuai4","parent":"root","length":28.56,"x":343.36,"y":-3.03,"scaleX":0.7,"scaleY":0.7},{"name":"lizi9","parent":"root","length":9.44,"rotation":5.19,"x":-92.32,"y":75.72,"scaleX":1.2,"scaleY":1.2},{"name":"fangkuai5","parent":"root","length":28.56,"x":343.36,"y":-3.03,"scaleX":0.6,"scaleY":0.6},{"name":"fangkuai6","parent":"root","length":28.56,"x":343.36,"y":-3.03,"scaleX":0.4,"scaleY":0.4},{"name":"fangkuai7","parent":"root","length":28.56,"x":343.36,"y":-3.03,"scaleX":0.5,"scaleY":0.5},{"name":"fangkuai8","parent":"root","length":28.56,"x":343.36,"y":-3.03},{"name":"fangkuai9","parent":"root","length":28.56,"x":343.36,"y":-3.03,"scaleX":0.8,"scaleY":0.8},{"name":"star4","parent":"root","length":17.48,"x":202.79,"y":-34.6},{"name":"lizi10","parent":"root","length":9.44,"rotation":5.19,"x":-179.89,"y":22.58,"scaleX":0.5,"scaleY":0.5},{"name":"glow_bian","parent":"tiao_new"},{"name":"glow_bian2","parent":"tiao_new"},{"name":"success2","parent":"root"},{"name":"dian","parent":"pipeizhong","x":203.82,"y":-32.74},{"name":"dian2","parent":"pipeizhong","x":203.82,"y":-32.74},{"name":"dian3","parent":"pipeizhong","x":203.82,"y":-32.74},{"name":"tiao","parent":"tiao_new","scaleX":1.2928}],"slots":[{"name":"BG","bone":"root"},{"name":"ck_new","bone":"root"},{"name":"new_tiao_orange","bone":"tiao","attachment":"new_tiao_orange"},{"name":"heitao_01","bone":"heitao","attachment":"heitao_01"},{"name":"heitao_2","bone":"heitao2","attachment":"heitao_02"},{"name":"glow_bian","bone":"glow_bian","blend":"additive"},{"name":"glow_bian2","bone":"glow_bian2","blend":"additive"},{"name":"loading_aixin","bone":"loading"},{"name":"pi","bone":"pi","attachment":"pi"},{"name":"pei","bone":"pei","attachment":"pei"},{"name":"zhong","bone":"zhong","attachment":"zhong"},{"name":"lizi_1","bone":"lizi","attachment":"lizi_1","blend":"additive"},{"name":"lizi_7","bone":"lizi7","attachment":"lizi_1","blend":"additive"},{"name":"lizi_9","bone":"lizi9","attachment":"lizi_1","blend":"additive"},{"name":"lizi_5","bone":"lizi5","attachment":"lizi_1","blend":"additive"},{"name":"lizi_10","bone":"lizi10","attachment":"lizi_1","blend":"additive"},{"name":"lizi_6","bone":"lizi6","attachment":"lizi_1","blend":"additive"},{"name":"lizi_3","bone":"lizi3","attachment":"lizi_1","blend":"additive"},{"name":"lizi_4","bone":"lizi4","attachment":"lizi_1","blend":"additive"},{"name":"lizi_8","bone":"lizi8","attachment":"lizi_1","blend":"additive"},{"name":"lizi_2","bone":"lizi2","attachment":"lizi_1","blend":"additive"},{"name":"lamp_glow3","bone":"glow_y","attachment":"lamp_glow","blend":"additive"},{"name":"fangkuai6","bone":"fangkuai","attachment":"fangkuai","blend":"additive"},{"name":"fangkuai5","bone":"fangkuai5","attachment":"fangkuai","blend":"additive"},{"name":"fangkuai4","bone":"fangkuai4","attachment":"fangkuai","blend":"additive"},{"name":"fangkuai11","bone":"fangkuai8","attachment":"fangkuai","blend":"additive"},{"name":"fangkuai12","bone":"fangkuai9","attachment":"fangkuai","blend":"additive"},{"name":"fangkuai2","bone":"fangkuai2","blend":"additive"},{"name":"fangkuai7","bone":"fangkuai6","attachment":"fangkuai","blend":"additive"},{"name":"fangkuai3","bone":"fangkuai3","blend":"additive"},{"name":"fangkuai9","bone":"fangkuai7","attachment":"fangkuai","blend":"additive"},{"name":"fangkuai_kuang6","bone":"fangkuai","attachment":"fangkuai_kuang","blend":"screen"},{"name":"fangkuai_kuang5","bone":"fangkuai5","attachment":"fangkuai_kuang","blend":"screen"},{"name":"fangkuai_kuang4","bone":"fangkuai4","attachment":"fangkuai_kuang","blend":"screen"},{"name":"fangkuai_kuang11","bone":"fangkuai8","attachment":"fangkuai_kuang","blend":"screen"},{"name":"fangkuai_kuang12","bone":"fangkuai9","attachment":"fangkuai_kuang","blend":"screen"},{"name":"fangkuai_kuang2","bone":"fangkuai2","attachment":"fangkuai_kuang","blend":"screen"},{"name":"fangkuai_kuang7","bone":"fangkuai6","attachment":"fangkuai_kuang","blend":"screen"},{"name":"fangkuai_kuang3","bone":"fangkuai3","attachment":"fangkuai_kuang","blend":"screen"},{"name":"fangkuai_kuang9","bone":"fangkuai7","attachment":"fangkuai_kuang","blend":"screen"},{"name":"duijukaishi","bone":"success2","attachment":"duijukaishi"},{"name":"duijukaishi2","bone":"success2","attachment":"duijukaishi","blend":"additive"},{"name":"lamp_glow4","bone":"glow_y2","attachment":"lamp_glow","blend":"additive"},{"name":"lamp_glow5","bone":"glow_y2","attachment":"lamp_glow","blend":"additive"},{"name":"star2","bone":"star","attachment":"xingguang","blend":"additive"},{"name":"star8","bone":"star4","attachment":"xingguang","blend":"additive"},{"name":"dian","bone":"dian","attachment":"dian"},{"name":"dian2","bone":"dian2","attachment":"dian"},{"name":"dian3","bone":"dian3","attachment":"dian"},{"name":"ck_waiting","bone":"root","color":"ffffff86"}],"skins":[{"name":"default","attachments":{"dian":{"dian":{"x":0.27,"y":1.25,"width":24,"height":22}},"dian2":{"dian":{"x":0.27,"y":1.25,"width":24,"height":22}},"dian3":{"dian":{"x":0.27,"y":1.25,"width":24,"height":22}},"duijukaishi":{"duijukaishi":{"width":380,"height":92}},"duijukaishi2":{"duijukaishi":{"width":380,"height":92}},"fangkuai2":{"fangkuai":{"width":32,"height":32}},"fangkuai3":{"fangkuai":{"width":32,"height":32}},"fangkuai4":{"fangkuai":{"width":32,"height":32}},"fangkuai5":{"fangkuai":{"width":32,"height":32}},"fangkuai6":{"fangkuai":{"width":32,"height":32}},"fangkuai7":{"fangkuai":{"width":32,"height":32}},"fangkuai9":{"fangkuai":{"width":32,"height":32}},"fangkuai11":{"fangkuai":{"width":32,"height":32}},"fangkuai12":{"fangkuai":{"width":32,"height":32}},"fangkuai_kuang2":{"fangkuai_kuang":{"width":32,"height":32}},"fangkuai_kuang3":{"fangkuai_kuang":{"width":32,"height":32}},"fangkuai_kuang4":{"fangkuai_kuang":{"width":32,"height":32}},"fangkuai_kuang5":{"fangkuai_kuang":{"width":32,"height":32}},"fangkuai_kuang6":{"fangkuai_kuang":{"width":32,"height":32}},"fangkuai_kuang7":{"fangkuai_kuang":{"width":32,"height":32}},"fangkuai_kuang9":{"fangkuai_kuang":{"width":32,"height":32}},"fangkuai_kuang11":{"fangkuai_kuang":{"width":32,"height":32}},"fangkuai_kuang12":{"fangkuai_kuang":{"width":32,"height":32}},"glow_bian":{"glow_bian":{"x":422.12,"y":-69.57,"scaleX":1.2,"scaleY":0.6,"width":330,"height":9}},"glow_bian2":{"glow_bian":{"x":422.12,"y":64.41,"scaleX":1.2,"scaleY":0.6,"width":330,"height":9}},"heitao_01":{"heitao_01":{"y":-1.9,"width":236,"height":218}},"heitao_2":{"heitao_02":{"y":-2.2,"width":442,"height":219}},"lamp_glow3":{"lamp_glow":{"x":-1.8,"y":-0.8,"scaleX":2.0276,"scaleY":2.0276,"width":198,"height":185}},"lamp_glow4":{"lamp_glow":{"x":-1.8,"y":-0.8,"scaleX":2.0276,"scaleY":2.0276,"width":198,"height":185}},"lamp_glow5":{"lamp_glow":{"x":-1.8,"y":-0.8,"scaleX":2.0276,"width":198,"height":185}},"lizi_1":{"lizi_1":{"x":0.05,"y":0.07,"rotation":-5.19,"width":19,"height":19}},"lizi_2":{"lizi_1":{"x":0.05,"y":0.07,"rotation":-5.19,"width":19,"height":19}},"lizi_3":{"lizi_1":{"x":0.05,"y":0.07,"rotation":-5.19,"width":19,"height":19}},"lizi_4":{"lizi_1":{"x":0.05,"y":0.07,"rotation":-5.19,"width":19,"height":19}},"lizi_5":{"lizi_1":{"x":0.05,"y":0.07,"rotation":-5.19,"width":19,"height":19}},"lizi_6":{"lizi_1":{"x":0.05,"y":0.07,"rotation":-5.19,"width":19,"height":19}},"lizi_7":{"lizi_1":{"x":0.05,"y":0.07,"rotation":-5.19,"width":19,"height":19}},"lizi_8":{"lizi_1":{"x":0.05,"y":0.07,"rotation":-5.19,"width":19,"height":19}},"lizi_9":{"lizi_1":{"x":0.05,"y":0.07,"rotation":-5.19,"width":19,"height":19}},"lizi_10":{"lizi_1":{"x":0.05,"y":0.07,"rotation":-5.19,"width":19,"height":19}},"loading_aixin":{"loading_aixin":{"x":103.12,"y":81.11,"width":28,"height":28}},"new_tiao_orange":{"new_tiao_orange":{"y":-2.26,"scaleX":2,"width":667,"height":217}},"pei":{"dai":{"x":5.24,"y":2.96,"width":96,"height":90},"pei":{"x":3.04,"y":2.96,"width":105,"height":92}},"pi":{"deng":{"x":-1.03,"y":-4.17,"width":101,"height":90},"pi":{"x":-1.03,"y":-4.17,"width":104,"height":89}},"star2":{"xingguang":{"x":0.34,"scaleX":0.3,"scaleY":0.3,"width":256,"height":256}},"star8":{"xingguang":{"scaleX":0.2,"scaleY":0.2,"width":256,"height":256}},"zhong":{"zhong":{"x":-6.91,"y":-0.76,"rotation":-88.12,"width":98,"height":93}}}}],"animations":{"start":{"slots":{"duijukaishi":{"rgba":[{"color":"ffffff00","curve":"stepped"},{"time":0.1667,"color":"ffffff00"},{"time":0.3,"color":"ffffffff"}]},"duijukaishi2":{"rgba":[{"color":"ffffff00","curve":"stepped"},{"time":0.3,"color":"ffffff00"},{"time":0.3333,"color":"ffffffff","curve":"stepped"},{"time":0.4,"color":"ffffffff"},{"time":0.6667,"color":"ffffff00"}]},"fangkuai2":{"rgba":[{"time":0.7,"color":"ffffffff"},{"time":0.8333,"color":"ffffff00"}],"attachment":[{"time":0.4667,"name":"fangkuai"},{"time":0.6}]},"fangkuai3":{"rgba":[{"time":0.6333,"color":"ffffffff"},{"time":0.8667,"color":"ffffff00"}],"attachment":[{"time":0.6333,"name":"fangkuai"},{"time":0.7667}]},"fangkuai4":{"rgba":[{"time":0.4333,"color":"ffffffff"},{"time":0.6667,"color":"ffffff00"}],"attachment":[{"time":0.3},{"time":0.4333,"name":"fangkuai"}]},"fangkuai5":{"rgba":[{"time":0.5333,"color":"ffffffff"},{"time":0.7667,"color":"ffffff00"}],"attachment":[{"time":0.4},{"time":0.5333,"name":"fangkuai"}]},"fangkuai6":{"rgba":[{"time":0.5333,"color":"ffffffff"},{"time":0.7667,"color":"ffffff00"}],"attachment":[{"time":0.5333},{"time":0.7,"name":"fangkuai"}]},"fangkuai7":{"rgba":[{"time":0.7,"color":"ffffffff"},{"time":0.8333,"color":"ffffff00"}],"attachment":[{"time":0.6}]},"fangkuai9":{"rgba":[{"time":0.6333,"color":"ffffffff"},{"time":0.8667,"color":"ffffff00"}],"attachment":[{"time":0.5},{"time":0.6333,"name":"fangkuai"}]},"fangkuai11":{"rgba":[{"time":0.4333,"color":"ffffffff"},{"time":0.6667,"color":"ffffff00"}],"attachment":[{"time":0.2667},{"time":0.4,"name":"fangkuai"},{"time":0.5333}]},"fangkuai12":{"rgba":[{"time":0.7333,"color":"ffffffff"},{"time":0.9667,"color":"ffffff00"}],"attachment":[{"time":0.5667},{"time":0.7,"name":"fangkuai"},{"time":0.8333}]},"fangkuai_kuang2":{"rgba":[{"time":0.7,"color":"ffffffff"},{"time":0.8333,"color":"ffffff00"}]},"fangkuai_kuang3":{"rgba":[{"time":0.6333,"color":"ffffffff"},{"time":0.8667,"color":"ffffff00"}]},"fangkuai_kuang4":{"rgba":[{"time":0.4333,"color":"ffffffff"},{"time":0.6667,"color":"ffffff00"}]},"fangkuai_kuang5":{"rgba":[{"time":0.5333,"color":"ffffffff"},{"time":0.7667,"color":"ffffff00"}]},"fangkuai_kuang6":{"rgba":[{"time":0.5333,"color":"ffffffff"},{"time":0.7667,"color":"ffffff00"}]},"fangkuai_kuang7":{"rgba":[{"time":0.7,"color":"ffffffff"},{"time":0.8333,"color":"ffffff00"}]},"fangkuai_kuang9":{"rgba":[{"time":0.6333,"color":"ffffffff"},{"time":0.8667,"color":"ffffff00"}]},"fangkuai_kuang11":{"rgba":[{"time":0.4333,"color":"ffffffff"},{"time":0.6667,"color":"ffffff00"}]},"fangkuai_kuang12":{"rgba":[{"time":0.7333,"color":"ffffffff"},{"time":0.9667,"color":"ffffff00"}]},"glow_bian":{"rgba":[{"time":0.7667,"color":"ffffffff"},{"time":0.9,"color":"ffffff00"}],"attachment":[{"time":0.3667,"name":"glow_bian"}]},"glow_bian2":{"rgba":[{"time":0.7667,"color":"ffffffff"},{"time":0.9,"color":"ffffff00"}],"attachment":[{"time":0.3667,"name":"glow_bian"}]},"heitao_01":{"rgba":[{"color":"ffffff00","curve":"stepped"},{"time":0.2,"color":"ffffff00","curve":[0.242,1,0.325,1,0.242,1,0.325,1,0.242,1,0.325,1,0.242,0,0.325,1]},{"time":0.3667,"color":"ffffffff"}]},"heitao_2":{"rgba":[{"color":"ffffff00","curve":"stepped"},{"time":0.3,"color":"ffffff00","curve":[0.342,1,0.425,1,0.342,1,0.425,1,0.342,1,0.425,1,0.342,0,0.425,1]},{"time":0.4667,"color":"ffffffff"}]},"lamp_glow3":{"rgba":[{"color":"ffffffb4","curve":"stepped"},{"time":0.0667,"color":"ffffffb4"},{"time":0.2,"color":"ffffff00"}],"attachment":[{}]},"lamp_glow4":{"rgba":[{"color":"ffffffb4","curve":"stepped"},{"time":0.4,"color":"ffffffb4"},{"time":0.5,"color":"ffffff00"}]},"lamp_glow5":{"rgba":[{"color":"ffffffb4","curve":"stepped"},{"time":0.4,"color":"ffffffb4"},{"time":0.5,"color":"ffffff00"}]},"lizi_7":{"rgba":[{"color":"ffdf63ff"}]},"lizi_8":{"rgba":[{"color":"ffdf63ff"}]},"lizi_9":{"rgba":[{"color":"ffdf64ff"}]},"lizi_10":{"attachment":[{}]},"new_tiao_orange":{"rgba":[{"color":"ffffff00","curve":"stepped"},{"time":0.0667,"color":"ffffff00"},{"time":0.1333,"color":"ffffffff"}]},"pei":{"attachment":[{"name":"dai"}]},"pi":{"attachment":[{"name":"deng"}]},"star2":{"attachment":[{},{"time":0.4333,"name":"xingguang"},{"time":0.7667}]},"star8":{"attachment":[{},{"time":0.6,"name":"xingguang"}]}},"bones":{"fangkuai5":{"rotate":[{"time":0.3},{"time":0.7667,"value":-44.88}],"translate":[{"x":-504.35,"y":11.18,"curve":"stepped"},{"time":0.3,"x":-504.35,"y":11.18},{"time":0.7667,"x":-599.14,"y":28.32}],"scale":[{"x":0,"y":0,"curve":"stepped"},{"time":0.3,"x":0,"y":0},{"time":0.4},{"time":0.5333,"x":0.5,"y":0.5},{"time":0.6333},{"time":0.7667,"x":0.5,"y":0.5}]},"fangkuai6":{"rotate":[{"value":-44.88,"curve":"stepped"},{"time":0.3667,"value":-44.88},{"time":0.8333}],"translate":[{"x":-517.09,"y":-15.18,"curve":"stepped"},{"time":0.3667,"x":-517.09,"y":-15.18},{"time":0.8333,"x":-624.16,"y":-31.78}],"scale":[{"x":0,"y":0,"curve":"stepped"},{"time":0.3667,"x":0,"y":0},{"time":0.4667},{"time":0.6,"x":0.5,"y":0.5},{"time":0.7},{"time":0.8333,"x":0.5,"y":0.5}]},"fangkuai7":{"rotate":[{"value":30,"curve":"stepped"},{"time":0.4,"value":30},{"time":0.8667,"value":-90}],"translate":[{"x":-498.9,"y":4.26,"curve":"stepped"},{"time":0.4,"x":-498.9,"y":4.26},{"time":0.8667,"x":-570.14,"y":-1.69}],"scale":[{"x":0,"y":0,"curve":"stepped"},{"time":0.4,"x":0,"y":0},{"time":0.5},{"time":0.6333,"x":0.5,"y":0.5},{"time":0.7333},{"time":0.8667,"x":0.5,"y":0.5}]},"success2":{"scale":[{"x":2.7,"y":2.2,"curve":"stepped"},{"time":0.1667,"x":2.7,"y":2.2},{"time":0.2,"x":2.51,"y":1.363},{"time":0.2333,"x":2.32,"y":1.92},{"time":0.3333,"x":0.8,"y":0.8},{"time":0.5,"x":1.06,"y":1.06},{"time":0.6667}]},"glow_y2":{"scale":[{"x":0,"y":0,"curve":"stepped"},{"time":0.2667,"x":0,"y":0},{"time":0.3333,"x":1.5,"y":1.2},{"time":0.5,"x":2,"y":0}]},"pei":{"translate":[{"x":-40.85}]},"star":{"rotate":[{"time":0.4333},{"time":0.7667,"value":-60}],"translate":[{"x":1.77,"y":0.73}],"scale":[{"time":0.4333},{"time":0.7667,"x":0,"y":0}]},"fangkuai3":{"rotate":[{"value":30,"curve":"stepped"},{"time":0.4,"value":30},{"time":0.8667,"value":-90}],"translate":[{"x":-148.5,"y":26.53,"curve":"stepped"},{"time":0.4,"x":-148.5,"y":26.53},{"time":0.8667,"x":-28.24,"y":27.97}],"scale":[{"x":0,"y":0,"curve":"stepped"},{"time":0.4,"x":0,"y":0},{"time":0.5},{"time":0.6333,"x":0.5,"y":0.5},{"time":0.7333},{"time":0.8667,"x":0.5,"y":0.5}]},"fangkuai2":{"rotate":[{"value":-44.88,"curve":"stepped"},{"time":0.3667,"value":-44.88},{"time":0.8333}],"translate":[{"x":-169.32,"y":-17.49,"curve":"stepped"},{"time":0.3667,"x":-169.32,"y":-17.49},{"time":0.8333,"x":-73.95,"y":-28.46}],"scale":[{"x":0,"y":0,"curve":"stepped"},{"time":0.3667,"x":0,"y":0},{"time":0.4667},{"time":0.6,"x":0.5,"y":0.5},{"time":0.7},{"time":0.8333,"x":0.5,"y":0.5}]},"fangkuai4":{"rotate":[{"time":0.2},{"time":0.6667,"value":-44.88}],"translate":[{"x":-135.94,"y":12.14,"curve":"stepped"},{"time":0.2,"x":-135.94,"y":12.14},{"time":0.6667,"x":0.5,"y":13.65}],"scale":[{"x":0,"y":0,"curve":"stepped"},{"time":0.2,"x":0,"y":0},{"time":0.3},{"time":0.4333,"x":0.5,"y":0.5},{"time":0.5333},{"time":0.6667,"x":0.5,"y":0.5}]},"star4":{"rotate":[{"value":-60,"curve":"stepped"},{"time":0.6,"value":-60},{"time":0.9333}],"translate":[{"x":-23.34,"y":-3.43}],"scale":[{"time":0.6},{"time":0.9333,"x":0,"y":0}]},"glow_y":{"scale":[{"x":0,"y":0},{"time":0.0667,"y":1.3},{"time":0.2,"x":2,"y":0}]},"fangkuai9":{"rotate":[{"time":0.5},{"time":0.9667,"value":-44.88}],"translate":[{"x":-510.8,"y":-9.98,"curve":"stepped"},{"time":0.5,"x":-510.8,"y":-9.98},{"time":0.9667,"x":-682.69,"y":-0.2}],"scale":[{"x":0,"y":0,"curve":"stepped"},{"time":0.5,"x":0,"y":0},{"time":0.6},{"time":0.7333,"x":0.5,"y":0.5},{"time":0.8333},{"time":0.9667,"x":0.5,"y":0.5}]},"lizi9":{"translate":[{"x":23.12,"y":-46.87,"curve":"stepped"},{"time":0.1333,"x":23.12,"y":-46.87},{"time":0.8,"x":-32.53,"y":36.07}],"scale":[{"x":0,"y":0,"curve":"stepped"},{"time":0.1333,"x":0,"y":0},{"time":0.3},{"time":0.4667,"x":0,"y":0},{"time":0.6333},{"time":0.8,"x":0,"y":0}]},"lizi7":{"translate":[{"x":27.53,"y":-8.06},{"time":0.9667,"x":78.87,"y":21.58}],"scale":[{"x":0,"y":0},{"time":0.1333},{"time":0.3,"x":0,"y":0},{"time":0.4667},{"time":0.6333,"x":0,"y":0},{"time":0.8},{"time":0.9667,"x":0,"y":0}]},"lizi8":{"translate":[{"x":40.95,"y":12.56},{"time":0.6333,"x":4.64,"y":-14.33}],"scale":[{"x":0,"y":0},{"time":0.1333},{"time":0.3,"x":0,"y":0},{"time":0.4667},{"time":0.6333,"x":0,"y":0}]},"glow_bian":{"translate":[{"x":-72.21,"curve":"stepped"},{"time":0.3667,"x":-72.21,"curve":[0.5,-72.21,0.767,-804.76,0.5,0,0.767,0]},{"time":0.9,"x":-804.76}]},"heitao":{"scale":[{"x":3,"curve":"stepped"},{"time":0.2,"x":3,"curve":[0.242,3,0.325,0.8,0.242,1,0.325,1]},{"time":0.3667,"x":0.8,"curve":[0.408,0.8,0.492,1.4,0.408,1,0.492,1]},{"time":0.5333,"x":1.4,"curve":[0.583,1.4,0.683,1,0.583,1,0.683,1]},{"time":0.7333}]},"glow_bian2":{"translate":[{"x":-656,"curve":"stepped"},{"time":0.3667,"x":-656,"curve":[0.5,-656,0.767,97.85,0.5,0,0.767,0]},{"time":0.9,"x":97.85}]},"pi":{"translate":[{"x":-41.74}]},"fangkuai8":{"rotate":[{"time":0.2},{"time":0.6667,"value":-44.88}],"translate":[{"x":-535.78,"y":-2.96,"curve":"stepped"},{"time":0.2,"x":-535.78,"y":-2.96},{"time":0.6667,"x":-641.17,"y":-6.75}],"scale":[{"x":0,"y":0,"curve":"stepped"},{"time":0.2,"x":0,"y":0},{"time":0.3},{"time":0.4333,"x":0.5,"y":0.5},{"time":0.5333},{"time":0.6667,"x":0.5,"y":0.5}]},"fangkuai":{"rotate":[{"time":0.3},{"time":0.7667,"value":-44.88}],"translate":[{"x":-153,"curve":"stepped"},{"time":0.3,"x":-153},{"time":0.7667,"x":-13.01}],"scale":[{"x":0,"y":0,"curve":"stepped"},{"time":0.3,"x":0,"y":0},{"time":0.4},{"time":0.5333,"x":0.5,"y":0.5},{"time":0.6333},{"time":0.7667,"x":0.5,"y":0.5}]},"heitao2":{"scale":[{"x":3,"curve":"stepped"},{"time":0.3,"x":3,"curve":[0.342,3,0.425,0.8,0.342,1,0.425,1]},{"time":0.4667,"x":0.8,"curve":[0.508,0.8,0.592,1.4,0.508,1,0.592,1]},{"time":0.6333,"x":1.4,"curve":[0.683,1.4,0.783,1,0.683,1,0.783,1]},{"time":0.8333}]},"lizi":{"scale":[{"x":0,"y":0}]},"lizi2":{"translate":[{"x":-3.71,"y":-20.79}],"scale":[{"x":0,"y":0}]},"lizi3":{"translate":[{"x":39.37,"y":-38.75}],"scale":[{"x":0,"y":0}]},"lizi4":{"scale":[{"x":0,"y":0}]},"lizi5":{"translate":[{"x":27.61,"y":27.45}],"scale":[{"x":0,"y":0}]},"lizi6":{"translate":[{"x":-51.66,"y":-60.09}],"scale":[{"x":0,"y":0}]},"pipeizhong":{"scale":[{},{"time":0.1,"x":0,"y":0}]},"tiao_new":{"scale":[{"x":0,"y":0,"curve":"stepped"},{"time":0.0667,"x":0,"y":0},{"time":0.1333,"y":0.1},{"time":0.2333,"y":1.3},{"time":0.3667,"y":0.9},{"time":0.5}]},"zhong":{"translate":[{"x":-41.29}]},"dian":{"translate":[{"x":-83.49,"y":2.22}]},"dian2":{"translate":[{"x":-57.12,"y":2.22}]},"dian3":{"translate":[{"x":-31.53,"y":2.22}]}}}}}'; +gameabc_face.spineTextData['gamestart.atlas'] = 'gamestart.png\nsize:2048,512\nfilter:Linear,Linear\ndai\nbounds:1521,395,96,90\ndeng\nbounds:1418,395,101,90\ndian\nbounds:1167,183,24,22\nduijukaishi\nbounds:929,393,380,92\nfangkuai\nbounds:446,47,32,32\nfangkuai_kuang\nbounds:2,2,32,32\nglow_bian\nbounds:2,36,330,9\nheitao_01\nbounds:929,173,236,218\nheitao_02\nbounds:2,47,442,219\nlamp_glow\nbounds:446,81,198,185\nlizi_1\nbounds:646,247,19,19\nloading_aixin\nbounds:1273,363,28,28\nnew_tiao_orange\nbounds:2,268,667,217\npei\nbounds:1311,393,105,92\npi\nbounds:1167,302,104,89\nxingguang\nbounds:671,229,256,256\nzhong\nbounds:1167,207,98,93\n'; diff --git a/codes/games/client/Projects/Game_Surface_3/index.html b/codes/games/client/Projects/Game_Surface_3/index.html index 848c1c2..9b80c86 100644 --- a/codes/games/client/Projects/Game_Surface_3/index.html +++ b/codes/games/client/Projects/Game_Surface_3/index.html @@ -1,144 +1,125 @@ + - - - - - -gameabc - + } + -
- -

Your browser does not support the canvas element.

-
+
+ +

Your browser does not support the canvas element.

+
-
- -

Your browser does not support the canvas element.

-
+
+ +

Your browser does not support the canvas element.

+
-
- -

Your browser does not support the canvas element.

-
+
+ +

Your browser does not support the canvas element.

+
- -

Your browser does not support the canvas element.

-
+ +

Your browser does not support the canvas element.

+
- - - - - + - - - - - - - - - - - - + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + \ No newline at end of file diff --git a/codes/games/client/Projects/Game_Surface_3/js/SpineMgr.js b/codes/games/client/Projects/Game_Surface_3/js/SpineMgr.js new file mode 100644 index 0000000..db3fd98 --- /dev/null +++ b/codes/games/client/Projects/Game_Surface_3/js/SpineMgr.js @@ -0,0 +1,416 @@ +// ============================================================ +// SpineMgr —— Spine 动画管理器(独立文件) +// 集成到 gameabc Canvas 2D 绘制循环,零侵入 gamemain.js +// 在 index.html 中置于 gameabc.min.js 之后、gamemain.js 之前加载 +// ============================================================ +(function(){ + +var SpineMgr = { + + // --- 内部状态 --- + _entries: {}, // {id: EntryObject} + _assetManager: null, + _renderer: null, // spine.SkeletonRenderer (Canvas 2D) + _lastTime: 0, // 上一帧时间戳(ms) + _inited: false, + _loadedPaths: {}, // 已请求加载的资源路径,避免重复请求 + _pendingCmds: {}, // {id: [{method, args}]} 等待实例就绪后执行的命令队列 + + // 默认资源根路径(可通过 init 覆盖) + _basePath: "assets/spine/", + + // ---------------------------------------------------------- + // init(basePath) 手动初始化(可选) + // 如不调用,load 时会自动以默认路径 "assets/spine/" 初始化 + // ---------------------------------------------------------- + init: function(basePath) { + if (!window.spine) { + logmessage("[SpineMgr] spine-canvas.js 未加载,请检查引用"); + return; + } + this._basePath = basePath || this._basePath; + this._assetManager = new spine.AssetManager(this._basePath); + this._lastTime = Date.now(); + this._inited = true; + }, + + // (内部) 确保已初始化 + _ensureInit: function() { + if (!this._inited) { + this.init(this._basePath); + } + }, + + // (内部) 自动加载:根据 id 约定文件名 id.json / id.atlas + _autoLoad: function(id) { + if (this._entries[id]) return; + this.load(id, id + ".json", id + ".atlas", {}); + }, + + // (内部) 将命令加入等待队列 + _queueCmd: function(id, method, args) { + if (!this._pendingCmds[id]) this._pendingCmds[id] = []; + this._pendingCmds[id].push({method: method, args: args}); + }, + + // (内部) 实例就绪后执行队列中的命令 + _flushCmds: function(id) { + var cmds = this._pendingCmds[id]; + if (!cmds || cmds.length === 0) return; + delete this._pendingCmds[id]; + for (var i = 0; i < cmds.length; i++) { + var cmd = cmds[i]; + this[cmd.method].apply(this, [id].concat(cmd.args)); + } + }, + + // ---------------------------------------------------------- + // load(id, jsonFile, atlasFile, option) + // 加载一组 Spine 资源, id 为自定义标识 + // option: {x, y, scale, skin, animation, loop, mixDuration} + // ---------------------------------------------------------- + load: function(id, jsonFile, atlasFile, option) { + this._ensureInit(); + if (!this._inited) return; + var opt = option || {}; + // 只加载尚未请求过的资源(预加载过的会跳过) + if (!this._loadedPaths[jsonFile]) { + this._assetManager.loadText(jsonFile); + this._loadedPaths[jsonFile] = true; + } + if (!this._loadedPaths[atlasFile]) { + this._assetManager.loadTextureAtlas(atlasFile); + this._loadedPaths[atlasFile] = true; + } + this._entries[id] = { + jsonFile: jsonFile, + atlasFile: atlasFile, + skeleton: null, + state: null, + x: opt.x || 0, + y: opt.y || 0, + scale: opt.scale || 1, + skin: opt.skin || "default", + defAnim: opt.animation || null, + defLoop: opt.loop !== undefined ? opt.loop : true, + mixDur: opt.mixDuration || 0.2, + visible: true, + ready: false, + _hideOnComplete: false, // 播放完成后是否自动隐藏 + _hideAfterCompletes: 0 // 剩余多少次 complete 后触发隐藏 + }; + }, + + // ---------------------------------------------------------- + // (内部) 资源加载完成后实例化骨骼 + // ---------------------------------------------------------- + _buildEntry: function(entry) { + var atlas = this._assetManager.require(entry.atlasFile); + var loader = new spine.AtlasAttachmentLoader(atlas); + var skelJson = new spine.SkeletonJson(loader); + skelJson.scale = entry.scale; + + var skelData = skelJson.readSkeletonData( + this._assetManager.require(entry.jsonFile) + ); + entry.skeleton = new spine.Skeleton(skelData); + + // 设置皮肤 + if (entry.skin && entry.skin !== "default") { + entry.skeleton.setSkinByName(entry.skin); + } + entry.skeleton.setToSetupPose(); + + // AnimationState + var stateData = new spine.AnimationStateData(skelData); + stateData.defaultMix = entry.mixDur; + entry.state = new spine.AnimationState(stateData); + + // 绑定事件回调 —— 转发到 Spine_Event.js + entry.state.addListener({ + complete: function(trackEntry) { + // 自动隐藏:playOnce / playQueue 设置的计数器 + if (entry._hideOnComplete && !trackEntry.loop) { + entry._hideAfterCompletes--; + if (entry._hideAfterCompletes <= 0) { + entry.visible = false; + entry._hideOnComplete = false; + } + } + if (gameabc_face.spine_onComplete) { + gameabc_face.spine_onComplete(entry._id, trackEntry.animation.name, trackEntry.trackIndex); + } + }, + event: function(trackEntry, event) { + if (gameabc_face.spine_onEvent) { + gameabc_face.spine_onEvent(entry._id, event.data.name, event.intValue, event.floatValue, event.stringValue); + } + } + }); + + // 默认动画 + if (entry.defAnim) { + entry.state.setAnimation(0, entry.defAnim, entry.defLoop); + } + entry.ready = true; + }, + + // ---------------------------------------------------------- + // (内部) 每帧调用:确保所有资源就绪 + // ---------------------------------------------------------- + _tryBuild: function() { + if (!this._assetManager.isLoadingComplete()) return false; + for (var id in this._entries) { + var e = this._entries[id]; + if (!e.ready) { + e._id = id; + try { + this._buildEntry(e); + logmessage("[SpineMgr] " + id + " 构建完成"); + this._flushCmds(id); + } catch(err) { + logmessage("[SpineMgr] " + id + " 构建失败: " + err.message); + e.ready = false; + } + } + } + return true; + }, + + // ---------------------------------------------------------- + // updateAndDraw(ctx) 每帧自动调用 + // ctx: gameabc_face.dc (Canvas 2D Context) + // ---------------------------------------------------------- + updateAndDraw: function(ctx) { + if (!this._inited) return; + this._tryBuild(); + + var now = Date.now(); + var dt = (now - this._lastTime) / 1000; + this._lastTime = now; + if (dt <= 0 || dt > 0.5) dt = 1/30; + + if (!this._renderer) { + this._renderer = new spine.SkeletonRenderer(ctx); + this._renderer.triangleRendering = true; // ★ 启用三角形渲染以支持 Mesh 网格附件 + } + // 确保 renderer 用的是当前 ctx (gameabc可能重建) + this._renderer.ctx = ctx; + + for (var id in this._entries) { + var e = this._entries[id]; + if (!e.ready || !e.visible) continue; + + e.state.update(dt); + e.state.apply(e.skeleton); + // 骨骼位置归零,由 ctx.translate 控制实际位置 + e.skeleton.x = 0; + e.skeleton.y = 0; + e.skeleton.updateWorldTransform(spine.Physics.update); + + ctx.save(); + ctx.translate(e.x, e.y); + ctx.scale(1, -1); // ★ Spine Y-up → Canvas Y-down + this._renderer.draw(e.skeleton); + ctx.restore(); + } + }, + + // ========================================================== + // 公开控制 API + // ========================================================== + + setAnimation: function(id, animName, loop, track) { + var e = this._entries[id]; + if (!e) { + this._autoLoad(id); + this._queueCmd(id, "setAnimation", [animName, loop, track]); + return null; + } + if (!e.ready) { + this._queueCmd(id, "setAnimation", [animName, loop, track]); + return null; + } + return e.state.setAnimation(track || 0, animName, loop !== false); + }, + + addAnimation: function(id, animName, loop, delay, track) { + var e = this._entries[id]; + if (!e) { + this._autoLoad(id); + this._queueCmd(id, "addAnimation", [animName, loop, delay, track]); + return null; + } + if (!e.ready) { + this._queueCmd(id, "addAnimation", [animName, loop, delay, track]); + return null; + } + return e.state.addAnimation(track || 0, animName, loop !== false, delay || 0); + }, + + setPosition: function(id, x, y) { + var e = this._entries[id]; + if (!e) { + this._autoLoad(id); + e = this._entries[id]; + } + e.x = x; e.y = y; + }, + + setScale: function(id, sx, sy) { + var e = this._entries[id]; + if (!e) { + this._autoLoad(id); + this._queueCmd(id, "setScale", [sx, sy]); + return; + } + if (!e.skeleton) { + this._queueCmd(id, "setScale", [sx, sy]); + return; + } + e.skeleton.scaleX = sx; + e.skeleton.scaleY = sy !== undefined ? sy : sx; + }, + + setFlip: function(id, flipX, flipY) { + var e = this._entries[id]; + if (!e) { + this._autoLoad(id); + this._queueCmd(id, "setFlip", [flipX, flipY]); + return; + } + if (!e.skeleton) { + this._queueCmd(id, "setFlip", [flipX, flipY]); + return; + } + e.skeleton.scaleX = Math.abs(e.skeleton.scaleX) * (flipX ? -1 : 1); + e.skeleton.scaleY = Math.abs(e.skeleton.scaleY) * (flipY ? -1 : 1); + }, + + setVisible: function(id, visible) { + var e = this._entries[id]; + if (!e) { + this._autoLoad(id); + e = this._entries[id]; + } + e.visible = !!visible; + }, + + setSkin: function(id, skinName) { + var e = this._entries[id]; + if (!e) { + this._autoLoad(id); + this._queueCmd(id, "setSkin", [skinName]); + return; + } + if (!e.ready) { + this._queueCmd(id, "setSkin", [skinName]); + return; + } + e.skeleton.setSkinByName(skinName); + e.skeleton.setSlotsToSetupPose(); + }, + + getAnimations: function(id) { + var e = this._entries[id]; + if (!e) { this._autoLoad(id); return []; } + if (!e.ready) return []; + var anims = e.skeleton.data.animations; + var names = []; + for (var i = 0; i < anims.length; i++) names.push(anims[i].name); + return names; + }, + + getSkins: function(id) { + var e = this._entries[id]; + if (!e) { this._autoLoad(id); return []; } + if (!e.ready) return []; + var skins = e.skeleton.data.skins; + var names = []; + for (var i = 0; i < skins.length; i++) names.push(skins[i].name); + return names; + }, + + playOnce: function(id, animName, track) { + this.setVisible(id, true); + this.setAnimation(id, animName, false, track); + var e = this._entries[id]; + if (e) { + e._hideOnComplete = true; + e._hideAfterCompletes = 1; + } + }, + + playQueue: function(id, animList, hideOnComplete) { + if (!animList || animList.length === 0) return; + this.setVisible(id, true); + this.setAnimation(id, animList[0], false, 0); + for (var i = 1; i < animList.length; i++) { + this.addAnimation(id, animList[i], false, 0, 0); + } + var e = this._entries[id]; + if (e) { + e._hideOnComplete = hideOnComplete !== false; + e._hideAfterCompletes = animList.length; + } + }, + + remove: function(id) { + delete this._entries[id]; + }, + + removeAll: function() { + this._entries = {}; + } +}; + +// 挂载到 gameabc_face 上 +gameabc_face.spineMgr = SpineMgr; + +// ★ 自动预加载:读取 gameabc_face.spineAssets 清单,在引擎启动前预加载所有 Spine 资源 +// 如果存在 spineTextData(嵌入文本数据),则通过 setRawDataURI 注入, +// 彻底避免 file:// 协议下 XHR CORS 拦截问题 +if (gameabc_face.spineAssets && gameabc_face.spineAssets.length > 0) { + SpineMgr._ensureInit(); + var list = gameabc_face.spineAssets; + var textData = gameabc_face.spineTextData || {}; + for (var i = 0; i < list.length; i++) { + var name = list[i]; + var jsonKey = name + ".json"; + var atlasKey = name + ".atlas"; + // 将嵌入文本数据注册为 rawDataURI,Spine Downloader 会优先从内存读取 + if (textData[jsonKey]) { + SpineMgr._assetManager.setRawDataURI(jsonKey, "data:," + textData[jsonKey]); + } + if (textData[atlasKey]) { + SpineMgr._assetManager.setRawDataURI(atlasKey, "data:," + textData[atlasKey]); + } + SpineMgr._assetManager.loadText(jsonKey); + SpineMgr._loadedPaths[jsonKey] = true; + SpineMgr._assetManager.loadTextureAtlas(atlasKey); + SpineMgr._loadedPaths[atlasKey] = true; + } + logmessage("[SpineMgr] 预加载 " + list.length + " 组 Spine 资源" + + (Object.keys(textData).length > 0 ? "(使用嵌入数据)" : "(使用网络请求)")); +} + +// ★ 用 defineProperty 拦截 gameenddraw 赋值 +// 无论 gamemain.js 或其他代码如何定义 gameenddraw, +// Spine 渲染都会自动追加在用户逻辑之后 +var _userEndDraw = gameabc_face.gameenddraw || null; +var _wrappedEndDraw = function(gameid, spid, times, timelong) { + if (typeof _userEndDraw === "function") { + _userEndDraw(gameid, spid, times, timelong); + } + var ctx = gameabc_face.dc; + if (ctx && SpineMgr._inited) { + SpineMgr.updateAndDraw(ctx); + } +}; +Object.defineProperty(gameabc_face, "gameenddraw", { + configurable: true, + get: function() { return _wrappedEndDraw; }, + set: function(fn) { _userEndDraw = fn; } +}); + +})(); diff --git a/codes/games/client/Projects/Game_Surface_3/js/spine-canvas.js b/codes/games/client/Projects/Game_Surface_3/js/spine-canvas.js new file mode 100644 index 0000000..8690e14 --- /dev/null +++ b/codes/games/client/Projects/Game_Surface_3/js/spine-canvas.js @@ -0,0 +1,11710 @@ +"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; + 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 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(); + if (typeof location === "undefined" || location.protocol !== "file:") + 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; + 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.startsWith("data:")) { + 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; + 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.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/codes/games/client/Projects/Game_Surface_3/scripts/build_spine_data.cmd b/codes/games/client/Projects/Game_Surface_3/scripts/build_spine_data.cmd new file mode 100644 index 0000000..98bc802 --- /dev/null +++ b/codes/games/client/Projects/Game_Surface_3/scripts/build_spine_data.cmd @@ -0,0 +1,17 @@ +@echo off +chcp 65001 >nul +REM ============================================================ +REM Spine 资源数据生成脚本 +REM 扫描 assets/spine/ 目录,自动生成: +REM generated/spine_assets.js — 资源名清单 +REM generated/spine_data.js — .json/.atlas 文本内容嵌入 +REM +REM 用法:双击运行,或在命令行执行: +REM cd codes\games\client\Projects\Spine\scripts +REM build_spine_data.cmd +REM ============================================================ + +pushd "%~dp0" +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0build_spine_data.ps1" +popd +pause diff --git a/codes/games/client/Projects/Game_Surface_3/scripts/build_spine_data.ps1 b/codes/games/client/Projects/Game_Surface_3/scripts/build_spine_data.ps1 new file mode 100644 index 0000000..8d73558 --- /dev/null +++ b/codes/games/client/Projects/Game_Surface_3/scripts/build_spine_data.ps1 @@ -0,0 +1,99 @@ +# Spine resource data generation script +# Scans assets/spine/ directory and generates: +# generated/spine_assets.js - resource name list +# generated/spine_data.js - .json/.atlas text content embedded (file:// CORS fix) + +$ErrorActionPreference = "Stop" + +$scriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path +$projectDir = Split-Path -Parent $scriptDir +$spineDir = Join-Path $projectDir "assets\spine" +$outDir = Join-Path $projectDir "generated" +$assetsOut = Join-Path $outDir "spine_assets.js" +$dataOut = Join-Path $outDir "spine_data.js" + +if (-not (Test-Path $outDir)) { + New-Item -ItemType Directory -Path $outDir | Out-Null +} + +if (-not (Test-Path $spineDir)) { + Write-Host "[WARN] Spine assets directory not found: $spineDir — generating empty files" -ForegroundColor Yellow + $jsonFiles = @() +} else { + $jsonFiles = Get-ChildItem $spineDir -Filter "*.json" | Sort-Object Name +} + +if ($jsonFiles.Count -eq 0) { + Write-Host "[INFO] No .json files found — generating empty placeholder files" -ForegroundColor Yellow + + $utf8NoBom = New-Object System.Text.UTF8Encoding($false) + [System.IO.File]::WriteAllText($assetsOut, "// Spine resource list (auto-generated, do not edit manually)`ngameabc_face.spineAssets = [];`n", $utf8NoBom) + [System.IO.File]::WriteAllText($dataOut, "// Spine text data (auto-generated, do not edit manually)`ngameabc_face.spineTextData = {};`n", $utf8NoBom) + + Write-Host "[OK] $assetsOut (empty)" -ForegroundColor Green + Write-Host "[OK] $dataOut (empty)" -ForegroundColor Green + exit 0 +} + +$names = @() +foreach ($f in $jsonFiles) { + $names += $f.BaseName +} + +Write-Host "Found $($names.Count) Spine resource(s): $($names -join ', ')" -ForegroundColor Cyan + +# ==================== spine_assets.js ==================== +$assetsSB = [System.Text.StringBuilder]::new() +[void]$assetsSB.AppendLine('// Spine resource list (auto-generated, do not edit manually)') +[void]$assetsSB.Append('gameabc_face.spineAssets = [') + +for ($i = 0; $i -lt $names.Count; $i++) { + if ($i -gt 0) { [void]$assetsSB.Append(',') } + [void]$assetsSB.AppendLine('') + [void]$assetsSB.Append("`t`"$($names[$i])`"") +} + +[void]$assetsSB.AppendLine('') +[void]$assetsSB.AppendLine('];') + +$utf8NoBom = New-Object System.Text.UTF8Encoding($false) +[System.IO.File]::WriteAllText($assetsOut, $assetsSB.ToString(), $utf8NoBom) +Write-Host "[OK] $assetsOut" -ForegroundColor Green + +# ==================== spine_data.js ==================== +$dataSB = [System.Text.StringBuilder]::new() +[void]$dataSB.AppendLine('// Spine text data (auto-generated, do not edit manually)') +[void]$dataSB.AppendLine('// Embeds .json/.atlas content into JS to bypass file:// XHR CORS') +[void]$dataSB.AppendLine('gameabc_face.spineTextData = {};') + +$totalOriginal = 0 + +foreach ($name in $names) { + foreach ($ext in '.json', '.atlas') { + $filePath = Join-Path $spineDir "$name$ext" + if (-not (Test-Path $filePath)) { + Write-Host "[WARN] Missing file: $name$ext" -ForegroundColor Yellow + continue + } + + $raw = [System.IO.File]::ReadAllText($filePath, [System.Text.Encoding]::UTF8) + $totalOriginal += (Get-Item $filePath).Length + + $escaped = $raw.Replace('\', '\\').Replace("'", "\'") + $escaped = $escaped.Replace("`r`n", '\n').Replace("`n", '\n').Replace("`r", '') + + [void]$dataSB.AppendLine("gameabc_face.spineTextData['$name$ext'] = '$escaped';") + } +} + +[System.IO.File]::WriteAllText($dataOut, $dataSB.ToString(), $utf8NoBom) + +$dataSize = (Get-Item $dataOut).Length +$overhead = $dataSize - $totalOriginal + +Write-Host "[OK] $dataOut" -ForegroundColor Green +Write-Host '' +Write-Host '=== Summary ===' -ForegroundColor Cyan +Write-Host " Resources: $($names.Count)" +Write-Host " Original size: $([math]::Round($totalOriginal/1024, 1)) KB" +Write-Host " Output size: $([math]::Round($dataSize/1024, 1)) KB (overhead: $overhead bytes)" \ No newline at end of file diff --git a/codes/games/client/Projects/Spine/FilesOrd.txt b/codes/games/client/Projects/Spine/FilesOrd.txt new file mode 100644 index 0000000..6ab68d1 --- /dev/null +++ b/codes/games/client/Projects/Spine/FilesOrd.txt @@ -0,0 +1,2 @@ +G:\Works\YouleGames\codes\games\client\Projects\Project1\js\gamemain.js +G:\Works\YouleGames\codes\games\client\Projects\Project1\js\Project1_Event.js diff --git a/codes/games/client/Projects/Spine/Project.txt b/codes/games/client/Projects/Spine/Project.txt new file mode 100644 index 0000000..cff55f8 --- /dev/null +++ b/codes/games/client/Projects/Spine/Project.txt @@ -0,0 +1,6 @@ +LayerStartID=1 +SpiritStartID=1 +ImgResStartID=1 +TxtResStartID=1 +VoiResStartID=1 +OpenLayerList=1 diff --git a/codes/games/client/Projects/Spine/assets/bmp/00001.png b/codes/games/client/Projects/Spine/assets/bmp/00001.png new file mode 100644 index 0000000000000000000000000000000000000000..eafcedf387c28faa0d7ea09a120e0e24799dc95a GIT binary patch literal 1369170 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 z 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