@gmvjs/xray-v1 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +77 -2
  3. package/dist/db.d.ts +12 -0
  4. package/dist/db.js +134 -0
  5. package/dist/db.js.map +1 -0
  6. package/dist/details.d.ts +42 -0
  7. package/dist/details.js +210 -0
  8. package/dist/details.js.map +1 -0
  9. package/dist/export.d.ts +38 -0
  10. package/dist/export.js +241 -0
  11. package/dist/export.js.map +1 -0
  12. package/dist/games/cop.d.ts +7 -0
  13. package/dist/games/cop.js +11 -0
  14. package/dist/games/cop.js.map +1 -0
  15. package/dist/games/cs.d.ts +7 -0
  16. package/dist/games/cs.js +11 -0
  17. package/dist/games/cs.js.map +1 -0
  18. package/dist/games/sdk.d.ts +7 -0
  19. package/dist/games/sdk.js +10 -0
  20. package/dist/games/sdk.js.map +1 -0
  21. package/dist/games/soc.d.ts +9 -0
  22. package/dist/games/soc.js +13 -0
  23. package/dist/games/soc.js.map +1 -0
  24. package/dist/i18n.d.ts +2 -0
  25. package/dist/i18n.js +48 -0
  26. package/dist/i18n.js.map +1 -0
  27. package/dist/index.d.ts +5 -0
  28. package/dist/index.js +131 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/level.d.ts +39 -0
  31. package/dist/level.js +234 -0
  32. package/dist/level.js.map +1 -0
  33. package/dist/load.d.ts +5 -0
  34. package/dist/load.js +126 -0
  35. package/dist/load.js.map +1 -0
  36. package/dist/lzhuf.d.ts +2 -0
  37. package/dist/lzhuf.js +136 -0
  38. package/dist/lzhuf.js.map +1 -0
  39. package/dist/motion.d.ts +28 -0
  40. package/dist/motion.js +20 -0
  41. package/dist/motion.js.map +1 -0
  42. package/dist/object.d.ts +138 -0
  43. package/dist/object.js +361 -0
  44. package/dist/object.js.map +1 -0
  45. package/dist/ogf.d.ts +93 -0
  46. package/dist/ogf.js +418 -0
  47. package/dist/ogf.js.map +1 -0
  48. package/dist/scene.d.ts +28 -0
  49. package/dist/scene.js +141 -0
  50. package/dist/scene.js.map +1 -0
  51. package/dist/skeleton.d.ts +34 -0
  52. package/dist/skeleton.js +252 -0
  53. package/dist/skeleton.js.map +1 -0
  54. package/dist/smotion.d.ts +44 -0
  55. package/dist/smotion.js +283 -0
  56. package/dist/smotion.js.map +1 -0
  57. package/dist/soc-key.d.ts +18 -0
  58. package/dist/soc-key.js +125 -0
  59. package/dist/soc-key.js.map +1 -0
  60. package/dist/thm.d.ts +26 -0
  61. package/dist/thm.js +69 -0
  62. package/dist/thm.js.map +1 -0
  63. package/dist/write-object.d.ts +31 -0
  64. package/dist/write-object.js +228 -0
  65. package/dist/write-object.js.map +1 -0
  66. package/dist/write-omf.d.ts +47 -0
  67. package/dist/write-scene.d.ts +26 -0
  68. package/dist/write-scene.js +114 -0
  69. package/dist/write-scene.js.map +1 -0
  70. package/package.json +70 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene.js","sources":["../src/scene.ts"],"sourcesContent":["// X-Ray SDK 0.7 level scene (CoP): text .level files and rawdata/levels/<level>/*.part parts (ini format).\n// scene_object.part: [object_N] objects with reference_name (a path in rawdata/objects without .object), position, rotation, scale.\nimport { boundsOf } from '@gmvjs/core/geometry';\nimport type { LoadContext } from '@gmvjs/core/plugin';\nimport type { Mesh, Model, VFile } from '@gmvjs/core/types';\nimport { objectMeshes, parseObject, type XrObjectMesh } from './object';\n\nexport type Ini = Map<string, Map<string, string>>;\n\n/** X-Ray ini parsing (sections, \"key = value\", \";\" comments). */\nexport function parseIni(text: string): Ini {\n const out: Ini = new Map();\n let cur: Map<string, string> | null = null;\n for (const raw of text.split(/\\r?\\n/)) {\n const line = raw.replace(/;.*$/, '').trim();\n if (!line) continue;\n const sec = /^\\[([^\\]]+)\\]/.exec(line);\n if (sec) { cur = new Map(); out.set(sec[1]!.trim(), cur); continue; }\n const eq = line.indexOf('=');\n if (cur && eq > 0) cur.set(line.slice(0, eq).trim(), line.slice(eq + 1).trim());\n }\n return out;\n}\n\nexport interface SceneObjectRef { name: string; reference: string; position: number[]; rotation: number[]; scale: number[]; flags: number }\n\nconst vec = (s: string | undefined, d: number[]) => (s ? s.split(',').map((x) => +x.trim()) : d);\n\n/** Objects from scene_object.part. */\nexport function sceneObjects(ini: Ini): SceneObjectRef[] {\n const out: SceneObjectRef[] = [];\n for (const [name, sec] of ini) {\n if (!/^object_\\d+$/.test(name) || !sec.get('reference_name')) continue;\n out.push({\n name: sec.get('name') ?? name, reference: sec.get('reference_name')!, flags: +(sec.get('flags') ?? 0),\n position: vec(sec.get('position'), [0, 0, 0]), rotation: vec(sec.get('rotation'), [0, 0, 0]), scale: vec(sec.get('scale'), [1, 1, 1]),\n });\n }\n return out;\n}\n\n/**\n * Scene object rotation matrix (row vectors: v' = v·R). Verified on labx8 (CoP): the vertices of 40 out of 40 rotated scene objects\n * matched the compiled level geometry exactly with R = transpose(setHPB(y, x, z)); other angle interpretations did not.\n */\nexport function sceneRotation(rot: number[]): number[] {\n const h = rot[1]!, p = rot[0]!, b = rot[2]!;\n const sh = Math.sin(h), ch = Math.cos(h), sp = Math.sin(p), cp = Math.cos(p), sb = Math.sin(b), cb = Math.cos(b);\n const cc = ch * cb, cs = ch * sb, sc = sh * cb, ss = sh * sb;\n const m = [cc - sp * ss, cs + sp * sc, -cp * sh, -cp * sb, cp * cb, sp, sc + sp * cs, ss - sp * cc, cp * ch];\n return [m[0]!, m[3]!, m[6]!, m[1]!, m[4]!, m[7]!, m[2]!, m[5]!, m[8]!];\n}\n\n/** Object mesh vertices into the scene world: v·S·R + P (row vectors). */\nexport function placeMesh(m: XrObjectMesh, ref: SceneObjectRef): { pos: Float32Array; nor: Float32Array } {\n const R = sceneRotation(ref.rotation), [sx, sy, sz] = ref.scale as [number, number, number], [px, py, pz] = ref.position as [number, number, number];\n const n = m.pos.length / 3, pos = new Float32Array(n * 3), nor = new Float32Array(n * 3);\n for (let i = 0; i < n; i++) {\n const x = m.pos[i * 3]! * sx, y = m.pos[i * 3 + 1]! * sy, z = m.pos[i * 3 + 2]! * sz;\n pos[i * 3] = x * R[0]! + y * R[3]! + z * R[6]! + px;\n pos[i * 3 + 1] = x * R[1]! + y * R[4]! + z * R[7]! + py;\n pos[i * 3 + 2] = x * R[2]! + y * R[5]! + z * R[8]! + pz;\n // normal: with non-uniform scale, through the inverse scale\n const a = m.nor[i * 3]! / sx, b = m.nor[i * 3 + 1]! / sy, c = m.nor[i * 3 + 2]! / sz;\n let nx = a * R[0]! + b * R[3]! + c * R[6]!, ny = a * R[1]! + b * R[4]! + c * R[7]!, nz = a * R[2]! + b * R[5]! + c * R[8]!;\n const l = Math.hypot(nx, ny, nz) || 1; nx /= l; ny /= l; nz /= l;\n nor[i * 3] = nx; nor[i * 3 + 1] = ny; nor[i * 3 + 2] = nz;\n }\n return { pos, nor };\n}\n\n/** Find a file by a rawdata/… path (in open folders/archives the path may start higher: editors/rawdata, sdk/editors/rawdata). */\nasync function readRaw(ctx: LoadContext, rel: string): Promise<Uint8Array | null> {\n const want = rel.toLowerCase().replace(/\\\\/g, '/');\n for (const a of ctx.archives) {\n const e = a.lookup(want) ?? a.entries.find((x) => x.path.endsWith('/' + want));\n if (e) return a.read(e);\n }\n return null;\n}\n\n/** SDK level: .level + scene_object.part + objects. Meshes are merged by texture and shader. */\nexport async function loadSceneLevel(main: VFile, ctx: LoadContext): Promise<Model> {\n const level = parseIni(new TextDecoder('windows-1251').decode(await main.arrayBuffer()));\n const opts = level.get('level_options'), name = main.name.replace(/\\.level$/i, '');\n const dir = (main.path ?? '').replace(/[^/]*$/, '');\n const partPath = `${dir}${name}/scene_object.part`;\n let part = await ctx.readPath(partPath).catch(() => null);\n if (!part) part = await readRaw(ctx, `rawdata/levels/${name}/scene_object.part`);\n if (!part) throw new Error(`Нет ${name}/scene_object.part рядом с ${main.name}: откройте папку SDK (editors/rawdata) целиком`);\n const refs = sceneObjects(parseIni(new TextDecoder('windows-1251').decode(part)));\n const cache = new Map<string, XrObjectMesh[] | null>(), missing = new Set<string>();\n const groups = new Map<string, { texture: string; shader: string; material?: string; pos: number[]; nor: number[]; uv: number[]; idx: number[] }>();\n let placed = 0;\n for (const ref of refs) {\n let list = cache.get(ref.reference);\n if (list === undefined) {\n const raw = await readRaw(ctx, `rawdata/objects/${ref.reference}.object`);\n try { list = raw ? objectMeshes(parseObject(raw.buffer.slice(raw.byteOffset, raw.byteOffset + raw.byteLength) as ArrayBuffer)) : null; } catch { list = null; }\n cache.set(ref.reference, list);\n }\n if (!list) { missing.add(ref.reference); continue; }\n placed++;\n for (const m of list) {\n const s = m.surface, key = `${s?.texture ?? ''}|${s?.eshader ?? ''}`;\n let g = groups.get(key);\n if (!g) groups.set(key, (g = { texture: s?.texture ?? '', shader: s?.eshader ?? '', material: s?.gamemtl, pos: [], nor: [], uv: [], idx: [] }));\n const { pos, nor } = placeMesh(m, ref), base = g.pos.length / 3;\n for (let i = 0; i < pos.length; i++) { g.pos.push(pos[i]!); g.nor.push(nor[i]!); }\n for (let i = 0; i < m.uv.length; i++) g.uv.push(m.uv[i]!);\n for (let i = 0; i < m.indices.length; i++) g.idx.push(m.indices[i]! + base);\n }\n }\n const meshes: Mesh[] = [...groups.values()].map((g) => {\n const n = g.pos.length / 3;\n return {\n name: `${g.texture || '(без текстуры)'} · ${g.shader}`, texture: g.texture, shader: g.shader, material: g.material, vertexCount: n,\n pos: Float32Array.from(g.pos), nor: Float32Array.from(g.nor), uv: Float32Array.from(g.uv),\n bone: new Float32Array(n * 4), weight: new Float32Array(n * 4).map((_, i) => (i % 4 === 0 ? 1 : 0)), indices: Uint32Array.from(g.idx), skinned: false,\n };\n });\n if (!meshes.length) throw new Error(`Объекты уровня не найдены (${missing.size} ссылок): откройте папку SDK с rawdata/objects`);\n const info = [`Уровень SDK: ${opts?.get('level_path') ?? name}, объектов ${refs.length}, показано ${placed}, мешей (по текстурам) ${meshes.length}`];\n if (missing.size) info.push(`Нет файлов объектов (${missing.size}): ${[...missing].slice(0, 6).join(', ')}${missing.size > 6 ? '…' : ''}`);\n return { meshes, skeleton: null, motions: [], bounds: boundsOf(meshes), flipZ: true, info };\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ import type { Mesh, Motion, SkeletonRuntime } from '@gmvjs/core/types';
2
+ import type { XrayMotion } from './motion';
3
+ import { type OgfBone } from './ogf';
4
+ type M16 = Float32Array;
5
+ export declare class XraySkeleton implements SkeletonRuntime {
6
+ readonly transposeBind: boolean;
7
+ readonly n: number;
8
+ readonly parent: number[];
9
+ readonly order: number[];
10
+ readonly bindLocal: Float32Array;
11
+ readonly bindWorld: Float32Array;
12
+ readonly invBind: Float32Array;
13
+ readonly world: Float32Array;
14
+ readonly skin: Float32Array;
15
+ readonly bindLocalV: M16[];
16
+ readonly bindWorldV: M16[];
17
+ readonly invV: M16[];
18
+ readonly worldV: M16[];
19
+ readonly skinV: M16[];
20
+ private readonly scratch;
21
+ bindVariant: string;
22
+ bindErr: [number, number];
23
+ constructor(bones: OgfBone[], transposeBind?: boolean);
24
+ /** Bone matrix from setXYZi angles and position, interpreted the same way as the bind pose (for SDK animations). */
25
+ local(rot: number[], pos: number[], o: Float32Array): void;
26
+ /** Choose the angle interpretation: vertices must lie near their bones. */
27
+ static auto(bones: OgfBone[], meshes: readonly Mesh[]): XraySkeleton;
28
+ pose(motion: Motion | null, time: number, loop: boolean, invQ?: boolean): void;
29
+ /** Automatic quaternion sign selection: with the right variant, mesh edge lengths barely change. */
30
+ detectInvert(meshes: readonly Mesh[], motion: XrayMotion): boolean;
31
+ /** Mesh distortion by an animation: the mean relative edge length error over three frames (0 = edges do not stretch). */
32
+ motionError(meshes: readonly Mesh[], motion: XrayMotion, inv: boolean): number;
33
+ }
34
+ export {};
@@ -0,0 +1,252 @@
1
+ import { FPS } from "./ogf.js";
2
+ const Q = 1 / 32767;
3
+ function mulRow(a, b, o) {
4
+ for (let r = 0; r < 4; r++)
5
+ for (let c = 0; c < 4; c++)
6
+ o[r * 4 + c] = a[r * 4] * b[c] + a[r * 4 + 1] * b[4 + c] + a[r * 4 + 2] * b[8 + c] + a[r * 4 + 3] * b[12 + c];
7
+ }
8
+ function rigidInv(a, o) {
9
+ for (let r = 0; r < 3; r++) for (let c = 0; c < 3; c++) o[r * 4 + c] = a[c * 4 + r];
10
+ for (let c = 0; c < 3; c++) o[12 + c] = -(a[12] * a[c * 4] + a[13] * a[c * 4 + 1] + a[14] * a[c * 4 + 2]);
11
+ o[3] = o[7] = o[11] = 0;
12
+ o[15] = 1;
13
+ }
14
+ function eulerLocal(rot, pos, o, transpose) {
15
+ const cx = Math.cos(rot[0]), sx = Math.sin(rot[0]), cy = Math.cos(rot[1]), sy = Math.sin(rot[1]), cz = Math.cos(rot[2]), sz = Math.sin(rot[2]);
16
+ const m = [cz * cy + sz * sx * sy, sz * cx, -cz * sy + sz * sx * cy, -sz * cy + cz * sx * sy, cz * cx, sz * sy + cz * sx * cy, cx * sy, -sx, cx * cy];
17
+ for (let r = 0; r < 3; r++) for (let c = 0; c < 3; c++) o[r * 4 + c] = transpose ? m[c * 3 + r] : m[r * 3 + c];
18
+ o[3] = o[7] = o[11] = 0;
19
+ o[12] = pos[0];
20
+ o[13] = pos[1];
21
+ o[14] = pos[2];
22
+ o[15] = 1;
23
+ }
24
+ function quatLocal(x, y, z, w, tx, ty, tz, o) {
25
+ const xx = x * x, yy = y * y, zz = z * z, xy = x * y, xz = x * z, yz = y * z, wx = w * x, wy = w * y, wz = w * z;
26
+ o[0] = 1 - 2 * (yy + zz);
27
+ o[1] = 2 * (xy - wz);
28
+ o[2] = 2 * (xz + wy);
29
+ o[3] = 0;
30
+ o[4] = 2 * (xy + wz);
31
+ o[5] = 1 - 2 * (xx + zz);
32
+ o[6] = 2 * (yz - wx);
33
+ o[7] = 0;
34
+ o[8] = 2 * (xz - wy);
35
+ o[9] = 2 * (yz + wx);
36
+ o[10] = 1 - 2 * (xx + yy);
37
+ o[11] = 0;
38
+ o[12] = tx;
39
+ o[13] = ty;
40
+ o[14] = tz;
41
+ o[15] = 1;
42
+ }
43
+ function trackLocal(t, f0, f1, a, invQ, o) {
44
+ const R = t.rot;
45
+ let x, y, z, w;
46
+ if (R.length === 4) {
47
+ x = R[0] * Q;
48
+ y = R[1] * Q;
49
+ z = R[2] * Q;
50
+ w = R[3] * Q;
51
+ } else {
52
+ const i = f0 * 4, j = f1 * 4;
53
+ const x0 = R[i] * Q, y0 = R[i + 1] * Q, z0 = R[i + 2] * Q, w0 = R[i + 3] * Q;
54
+ let x1 = R[j] * Q, y1 = R[j + 1] * Q, z1 = R[j + 2] * Q, w1 = R[j + 3] * Q;
55
+ if (x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1 < 0) {
56
+ x1 = -x1;
57
+ y1 = -y1;
58
+ z1 = -z1;
59
+ w1 = -w1;
60
+ }
61
+ x = x0 + (x1 - x0) * a;
62
+ y = y0 + (y1 - y0) * a;
63
+ z = z0 + (z1 - z0) * a;
64
+ w = w0 + (w1 - w0) * a;
65
+ }
66
+ const l = Math.hypot(x, y, z, w) || 1;
67
+ x /= l;
68
+ y /= l;
69
+ z /= l;
70
+ w /= l;
71
+ if (invQ) {
72
+ x = -x;
73
+ y = -y;
74
+ z = -z;
75
+ }
76
+ const T = t.trans;
77
+ let tx, ty, tz;
78
+ if (T.length === 3) {
79
+ tx = T[0];
80
+ ty = T[1];
81
+ tz = T[2];
82
+ } else {
83
+ const i = f0 * 3, j = f1 * 3;
84
+ tx = T[i] + (T[j] - T[i]) * a;
85
+ ty = T[i + 1] + (T[j + 1] - T[i + 1]) * a;
86
+ tz = T[i + 2] + (T[j + 2] - T[i + 2]) * a;
87
+ }
88
+ quatLocal(x, y, z, w, tx, ty, tz, o);
89
+ }
90
+ class XraySkeleton {
91
+ constructor(bones, transposeBind = false) {
92
+ this.transposeBind = transposeBind;
93
+ const n = this.n = bones.length;
94
+ this.parent = bones.map((b) => b.parent);
95
+ const order = [], seen = new Uint8Array(n);
96
+ const visit = (i) => {
97
+ if (seen[i]) return;
98
+ seen[i] = 1;
99
+ if (this.parent[i] >= 0) visit(this.parent[i]);
100
+ order.push(i);
101
+ };
102
+ for (let i = 0; i < n; i++) visit(i);
103
+ this.order = order;
104
+ const mk = () => new Float32Array(16 * n), view = (arr) => Array.from({ length: n }, (_, i) => arr.subarray(16 * i, 16 * i + 16));
105
+ this.bindLocal = mk();
106
+ this.bindWorld = mk();
107
+ this.invBind = mk();
108
+ this.world = mk();
109
+ this.skin = mk();
110
+ this.bindLocalV = view(this.bindLocal);
111
+ this.bindWorldV = view(this.bindWorld);
112
+ this.invV = view(this.invBind);
113
+ this.worldV = view(this.world);
114
+ this.skinV = view(this.skin);
115
+ for (const i of order) {
116
+ eulerLocal(bones[i].rot, bones[i].pos, this.bindLocalV[i], transposeBind);
117
+ const p = this.parent[i];
118
+ if (p < 0) this.bindWorldV[i].set(this.bindLocalV[i]);
119
+ else mulRow(this.bindLocalV[i], this.bindWorldV[p], this.bindWorldV[i]);
120
+ rigidInv(this.bindWorldV[i], this.invV[i]);
121
+ }
122
+ for (let k = 0; k < 16 * n; k++) this.skin[k] = k % 16 % 5 === 0 ? 1 : 0;
123
+ this.world.set(this.bindWorld);
124
+ }
125
+ transposeBind;
126
+ n;
127
+ parent;
128
+ order;
129
+ bindLocal;
130
+ bindWorld;
131
+ invBind;
132
+ world;
133
+ skin;
134
+ bindLocalV;
135
+ bindWorldV;
136
+ invV;
137
+ worldV;
138
+ skinV;
139
+ scratch = new Float32Array(16);
140
+ bindVariant = "";
141
+ bindErr = [0, 0];
142
+ /** Bone matrix from setXYZi angles and position, interpreted the same way as the bind pose (for SDK animations). */
143
+ local(rot, pos, o) {
144
+ eulerLocal(rot, pos, o, this.transposeBind);
145
+ }
146
+ /** Choose the angle interpretation: vertices must lie near their bones. */
147
+ static auto(bones, meshes) {
148
+ const a = new XraySkeleton(bones, false);
149
+ if (!a.n) return a;
150
+ const b = new XraySkeleton(bones, true);
151
+ const err = (s2) => {
152
+ let e = 0, c = 0;
153
+ for (const m of meshes) {
154
+ if (!m.skinned) continue;
155
+ const step = Math.max(1, Math.floor(m.vertexCount / 1500));
156
+ for (let v = 0; v < m.vertexCount; v += step) {
157
+ let bi = m.bone[v * 4], bw = m.weight[v * 4];
158
+ for (let k = 1; k < 4; k++) if (m.weight[v * 4 + k] > bw) {
159
+ bw = m.weight[v * 4 + k];
160
+ bi = m.bone[v * 4 + k];
161
+ }
162
+ const W = s2.bindWorldV[bi];
163
+ e += Math.hypot(m.pos[v * 3] - W[12], m.pos[v * 3 + 1] - W[13], m.pos[v * 3 + 2] - W[14]);
164
+ c++;
165
+ }
166
+ }
167
+ return c ? e / c : 0;
168
+ };
169
+ const ea = err(a), eb = err(b);
170
+ const s = eb < ea * 0.98 ? b : a;
171
+ s.bindVariant = s === b ? "B (транспонированный)" : "A";
172
+ s.bindErr = [ea, eb];
173
+ return s;
174
+ }
175
+ pose(motion, time, loop, invQ = false) {
176
+ if (!this.n) return;
177
+ const m = motion && motion.kind === "xray" ? motion : null;
178
+ const frame = (x, lp) => {
179
+ const F = x.frames;
180
+ let fr = time * FPS;
181
+ fr = lp ? (fr % F + F) % F : Math.min(Math.max(fr, 0), F - 1);
182
+ const f0 = Math.floor(fr);
183
+ return [f0, lp ? (f0 + 1) % F : Math.min(f0 + 1, F - 1), fr - f0];
184
+ };
185
+ const list = m ? [[m, ...frame(m, loop)], ...(m.layers ?? []).map((x) => [x, ...frame(x, true)])] : [];
186
+ for (const i of this.order) {
187
+ const L = this.scratch;
188
+ let done = false;
189
+ for (const [x, f0, f1, a] of list) {
190
+ const tr = x.tracks[i];
191
+ if (tr) {
192
+ trackLocal(tr, f0, f1, a, invQ, L);
193
+ done = true;
194
+ break;
195
+ }
196
+ }
197
+ if (!done) L.set(this.bindLocalV[i]);
198
+ const p = this.parent[i];
199
+ if (p < 0) this.worldV[i].set(L);
200
+ else mulRow(L, this.worldV[p], this.worldV[i]);
201
+ mulRow(this.invV[i], this.worldV[i], this.skinV[i]);
202
+ }
203
+ }
204
+ /** Automatic quaternion sign selection: with the right variant, mesh edge lengths barely change. */
205
+ detectInvert(meshes, motion) {
206
+ const s0 = this.motionError(meshes, motion, false), s1 = this.motionError(meshes, motion, true);
207
+ return s1 < s0 * 0.9;
208
+ }
209
+ /** Mesh distortion by an animation: the mean relative edge length error over three frames (0 = edges do not stretch). */
210
+ motionError(meshes, motion, inv) {
211
+ const edges = [];
212
+ for (const m of meshes) {
213
+ if (!m.skinned) continue;
214
+ const tc = m.indices.length / 3, step = Math.max(1, Math.floor(tc / 1500));
215
+ for (let t = 0; t < tc; t += step) edges.push([m, m.indices[t * 3], m.indices[t * 3 + 1]]);
216
+ }
217
+ if (!edges.length) return 0;
218
+ const sk = (m, v, o) => {
219
+ const x = m.pos[v * 3], y = m.pos[v * 3 + 1], z = m.pos[v * 3 + 2];
220
+ o[0] = o[1] = o[2] = 0;
221
+ for (let k = 0; k < 4; k++) {
222
+ const w = m.weight[v * 4 + k];
223
+ if (!w) continue;
224
+ const M = this.skinV[m.bone[v * 4 + k]];
225
+ o[0] += w * (x * M[0] + y * M[4] + z * M[8] + M[12]);
226
+ o[1] += w * (x * M[1] + y * M[5] + z * M[9] + M[13]);
227
+ o[2] += w * (x * M[2] + y * M[6] + z * M[10] + M[14]);
228
+ }
229
+ };
230
+ const A = [0, 0, 0], B = [0, 0, 0];
231
+ const score = (inv2) => {
232
+ let d = 0, l = 0;
233
+ for (const fr of [0, Math.floor(motion.frames / 2), motion.frames - 1]) {
234
+ this.pose(motion, fr / FPS, false, inv2);
235
+ for (const [m, a, b] of edges) {
236
+ sk(m, a, A);
237
+ sk(m, b, B);
238
+ const l1 = Math.hypot(A[0] - B[0], A[1] - B[1], A[2] - B[2]);
239
+ const l0 = Math.hypot(m.pos[a * 3] - m.pos[b * 3], m.pos[a * 3 + 1] - m.pos[b * 3 + 1], m.pos[a * 3 + 2] - m.pos[b * 3 + 2]);
240
+ d += Math.abs(l1 - l0);
241
+ l += l0;
242
+ }
243
+ }
244
+ return d / (l || 1);
245
+ };
246
+ return score(inv);
247
+ }
248
+ }
249
+ export {
250
+ XraySkeleton
251
+ };
252
+ //# sourceMappingURL=skeleton.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skeleton.js","sources":["../src/skeleton.ts"],"sourcesContent":["// X-Ray skeleton: bind pose angles from IK data, animations as quantized quaternions (row-vector matrices, as in the engine).\nimport type { Mesh, Motion, SkeletonRuntime } from '@gmvjs/core/types';\nimport type { XrayMotion, XrayTrack } from './motion';\nimport { FPS, type OgfBone } from './ogf';\n\nconst Q = 1 / 32767;\ntype M16 = Float32Array;\n\nfunction mulRow(a: M16, b: M16, o: M16): void { // row vectors: a first, then b\n for (let r = 0; r < 4; r++)\n for (let c = 0; c < 4; c++)\n o[r * 4 + c] = a[r * 4]! * b[c]! + a[r * 4 + 1]! * b[4 + c]! + a[r * 4 + 2]! * b[8 + c]! + a[r * 4 + 3]! * b[12 + c]!;\n}\nfunction rigidInv(a: M16, o: M16): void {\n for (let r = 0; r < 3; r++) for (let c = 0; c < 3; c++) o[r * 4 + c] = a[c * 4 + r]!;\n for (let c = 0; c < 3; c++) o[12 + c] = -(a[12]! * a[c * 4]! + a[13]! * a[c * 4 + 1]! + a[14]! * a[c * 4 + 2]!);\n o[3] = o[7] = o[11] = 0; o[15] = 1;\n}\nfunction eulerLocal(rot: number[], pos: number[], o: M16, transpose: boolean): void {\n // Fmatrix::setXYZi(x, y, z) = setHPB(−y, −x, −z): for a row vector, rotation about Z first, then X, then Y\n // (roll, pitch, heading). Verified on CoP skinning: mesh edge lengths are preserved in animations only with this order.\n const cx = Math.cos(rot[0]!), sx = Math.sin(rot[0]!), cy = Math.cos(rot[1]!), sy = Math.sin(rot[1]!), cz = Math.cos(rot[2]!), sz = Math.sin(rot[2]!);\n const m = [cz * cy + sz * sx * sy, sz * cx, -cz * sy + sz * sx * cy, -sz * cy + cz * sx * sy, cz * cx, sz * sy + cz * sx * cy, cx * sy, -sx, cx * cy];\n for (let r = 0; r < 3; r++) for (let c = 0; c < 3; c++) o[r * 4 + c] = transpose ? m[c * 3 + r]! : m[r * 3 + c]!;\n o[3] = o[7] = o[11] = 0; o[12] = pos[0]!; o[13] = pos[1]!; o[14] = pos[2]!; o[15] = 1;\n}\nfunction quatLocal(x: number, y: number, z: number, w: number, tx: number, ty: number, tz: number, o: M16): void { // Fmatrix::rotation(Fquaternion) + translate_over\n const xx = x * x, yy = y * y, zz = z * z, xy = x * y, xz = x * z, yz = y * z, wx = w * x, wy = w * y, wz = w * z;\n o[0] = 1 - 2 * (yy + zz); o[1] = 2 * (xy - wz); o[2] = 2 * (xz + wy); o[3] = 0;\n o[4] = 2 * (xy + wz); o[5] = 1 - 2 * (xx + zz); o[6] = 2 * (yz - wx); o[7] = 0;\n o[8] = 2 * (xz - wy); o[9] = 2 * (yz + wx); o[10] = 1 - 2 * (xx + yy); o[11] = 0;\n o[12] = tx; o[13] = ty; o[14] = tz; o[15] = 1;\n}\nfunction trackLocal(t: XrayTrack, f0: number, f1: number, a: number, invQ: boolean, o: M16): void {\n const R = t.rot;\n let x: number, y: number, z: number, w: number;\n if (R.length === 4) { x = R[0]! * Q; y = R[1]! * Q; z = R[2]! * Q; w = R[3]! * Q; }\n else {\n const i = f0 * 4, j = f1 * 4;\n const x0 = R[i]! * Q, y0 = R[i + 1]! * Q, z0 = R[i + 2]! * Q, w0 = R[i + 3]! * Q;\n let x1 = R[j]! * Q, y1 = R[j + 1]! * Q, z1 = R[j + 2]! * Q, w1 = R[j + 3]! * Q;\n if (x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1 < 0) { x1 = -x1; y1 = -y1; z1 = -z1; w1 = -w1; }\n x = x0 + (x1 - x0) * a; y = y0 + (y1 - y0) * a; z = z0 + (z1 - z0) * a; w = w0 + (w1 - w0) * a;\n }\n const l = Math.hypot(x, y, z, w) || 1;\n x /= l; y /= l; z /= l; w /= l;\n if (invQ) { x = -x; y = -y; z = -z; }\n const T = t.trans;\n let tx: number, ty: number, tz: number;\n if (T.length === 3) { tx = T[0]!; ty = T[1]!; tz = T[2]!; }\n else { const i = f0 * 3, j = f1 * 3; tx = T[i]! + (T[j]! - T[i]!) * a; ty = T[i + 1]! + (T[j + 1]! - T[i + 1]!) * a; tz = T[i + 2]! + (T[j + 2]! - T[i + 2]!) * a; }\n quatLocal(x, y, z, w, tx, ty, tz, o);\n}\n\nexport class XraySkeleton implements SkeletonRuntime {\n readonly n: number;\n readonly parent: number[];\n readonly order: number[];\n readonly bindLocal: Float32Array; readonly bindWorld: Float32Array; readonly invBind: Float32Array;\n readonly world: Float32Array; readonly skin: Float32Array;\n readonly bindLocalV: M16[]; readonly bindWorldV: M16[]; readonly invV: M16[]; readonly worldV: M16[]; readonly skinV: M16[];\n private readonly scratch = new Float32Array(16);\n bindVariant = '';\n bindErr: [number, number] = [0, 0];\n\n constructor(bones: OgfBone[], readonly transposeBind = false) {\n const n = (this.n = bones.length);\n this.parent = bones.map((b) => b.parent);\n const order: number[] = [], seen = new Uint8Array(n);\n const visit = (i: number) => { if (seen[i]) return; seen[i] = 1; if (this.parent[i]! >= 0) visit(this.parent[i]!); order.push(i); };\n for (let i = 0; i < n; i++) visit(i);\n this.order = order;\n const mk = () => new Float32Array(16 * n), view = (arr: Float32Array) => Array.from({ length: n }, (_, i) => arr.subarray(16 * i, 16 * i + 16));\n this.bindLocal = mk(); this.bindWorld = mk(); this.invBind = mk(); this.world = mk(); this.skin = mk();\n this.bindLocalV = view(this.bindLocal); this.bindWorldV = view(this.bindWorld); this.invV = view(this.invBind);\n this.worldV = view(this.world); this.skinV = view(this.skin);\n for (const i of order) {\n eulerLocal(bones[i]!.rot, bones[i]!.pos, this.bindLocalV[i]!, transposeBind);\n const p = this.parent[i]!;\n if (p < 0) this.bindWorldV[i]!.set(this.bindLocalV[i]!); else mulRow(this.bindLocalV[i]!, this.bindWorldV[p]!, this.bindWorldV[i]!);\n rigidInv(this.bindWorldV[i]!, this.invV[i]!);\n }\n for (let k = 0; k < 16 * n; k++) this.skin[k] = (k % 16) % 5 === 0 ? 1 : 0;\n this.world.set(this.bindWorld);\n }\n\n /** Bone matrix from setXYZi angles and position, interpreted the same way as the bind pose (for SDK animations). */\n local(rot: number[], pos: number[], o: Float32Array): void { eulerLocal(rot, pos, o, this.transposeBind); }\n\n /** Choose the angle interpretation: vertices must lie near their bones. */\n static auto(bones: OgfBone[], meshes: readonly Mesh[]): XraySkeleton {\n const a = new XraySkeleton(bones, false);\n if (!a.n) return a;\n const b = new XraySkeleton(bones, true);\n const err = (s: XraySkeleton) => {\n let e = 0, c = 0;\n for (const m of meshes) {\n if (!m.skinned) continue;\n const step = Math.max(1, Math.floor(m.vertexCount / 1500));\n for (let v = 0; v < m.vertexCount; v += step) {\n let bi = m.bone[v * 4]!, bw = m.weight[v * 4]!;\n for (let k = 1; k < 4; k++) if (m.weight[v * 4 + k]! > bw) { bw = m.weight[v * 4 + k]!; bi = m.bone[v * 4 + k]!; }\n const W = s.bindWorldV[bi]!;\n e += Math.hypot(m.pos[v * 3]! - W[12]!, m.pos[v * 3 + 1]! - W[13]!, m.pos[v * 3 + 2]! - W[14]!);\n c++;\n }\n }\n return c ? e / c : 0;\n };\n const ea = err(a), eb = err(b);\n const s = eb < ea * 0.98 ? b : a;\n s.bindVariant = s === b ? 'B (транспонированный)' : 'A';\n s.bindErr = [ea, eb];\n return s;\n }\n\n pose(motion: Motion | null, time: number, loop: boolean, invQ = false): void {\n if (!this.n) return;\n const m = motion && motion.kind === 'xray' ? motion : null;\n // frames of the main animation and of the layers (each has its own length; layers always loop)\n const frame = (x: XrayMotion, lp: boolean): [number, number, number] => {\n const F = x.frames;\n let fr = time * FPS;\n fr = lp ? ((fr % F) + F) % F : Math.min(Math.max(fr, 0), F - 1);\n const f0 = Math.floor(fr);\n return [f0, lp ? (f0 + 1) % F : Math.min(f0 + 1, F - 1), fr - f0];\n };\n const list: Array<[XrayMotion, number, number, number]> = m ? [[m, ...frame(m, loop)], ...(m.layers ?? []).map((x): [XrayMotion, number, number, number] => [x, ...frame(x, true)])] : [];\n for (const i of this.order) {\n const L = this.scratch;\n let done = false;\n for (const [x, f0, f1, a] of list) { const tr = x.tracks[i]; if (tr) { trackLocal(tr, f0, f1, a, invQ, L); done = true; break; } }\n if (!done) L.set(this.bindLocalV[i]!);\n const p = this.parent[i]!;\n if (p < 0) this.worldV[i]!.set(L); else mulRow(L, this.worldV[p]!, this.worldV[i]!);\n mulRow(this.invV[i]!, this.worldV[i]!, this.skinV[i]!);\n }\n }\n\n /** Automatic quaternion sign selection: with the right variant, mesh edge lengths barely change. */\n detectInvert(meshes: readonly Mesh[], motion: XrayMotion): boolean {\n const s0 = this.motionError(meshes, motion, false), s1 = this.motionError(meshes, motion, true);\n return s1 < s0 * 0.9;\n }\n\n /** Mesh distortion by an animation: the mean relative edge length error over three frames (0 = edges do not stretch). */\n motionError(meshes: readonly Mesh[], motion: XrayMotion, inv: boolean): number {\n const edges: Array<[Mesh, number, number]> = [];\n for (const m of meshes) {\n if (!m.skinned) continue;\n const tc = m.indices.length / 3, step = Math.max(1, Math.floor(tc / 1500));\n for (let t = 0; t < tc; t += step) edges.push([m, m.indices[t * 3]!, m.indices[t * 3 + 1]!]);\n }\n if (!edges.length) return 0;\n const sk = (m: Mesh, v: number, o: number[]) => {\n const x = m.pos[v * 3]!, y = m.pos[v * 3 + 1]!, z = m.pos[v * 3 + 2]!;\n o[0] = o[1] = o[2] = 0;\n for (let k = 0; k < 4; k++) {\n const w = m.weight[v * 4 + k]!;\n if (!w) continue;\n const M = this.skinV[m.bone[v * 4 + k]!]!;\n o[0] += w * (x * M[0]! + y * M[4]! + z * M[8]! + M[12]!); o[1] += w * (x * M[1]! + y * M[5]! + z * M[9]! + M[13]!); o[2] += w * (x * M[2]! + y * M[6]! + z * M[10]! + M[14]!);\n }\n };\n const A = [0, 0, 0], B = [0, 0, 0];\n const score = (inv: boolean) => {\n let d = 0, l = 0;\n for (const fr of [0, Math.floor(motion.frames / 2), motion.frames - 1]) {\n this.pose(motion, fr / FPS, false, inv);\n for (const [m, a, b] of edges) {\n sk(m, a, A); sk(m, b, B);\n const l1 = Math.hypot(A[0]! - B[0]!, A[1]! - B[1]!, A[2]! - B[2]!);\n const l0 = Math.hypot(m.pos[a * 3]! - m.pos[b * 3]!, m.pos[a * 3 + 1]! - m.pos[b * 3 + 1]!, m.pos[a * 3 + 2]! - m.pos[b * 3 + 2]!);\n d += Math.abs(l1 - l0); l += l0;\n }\n }\n return d / (l || 1);\n };\n return score(inv);\n }\n}\n\n"],"names":["s","inv"],"mappings":";AAKA,MAAM,IAAI,IAAI;AAGd,SAAS,OAAO,GAAQ,GAAQ,GAAc;AAC5C,WAAS,IAAI,GAAG,IAAI,GAAG;AACrB,aAAS,IAAI,GAAG,IAAI,GAAG;AACrB,QAAE,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAK,EAAE,CAAC,IAAK,EAAE,IAAI,IAAI,CAAC,IAAK,EAAE,IAAI,CAAC,IAAK,EAAE,IAAI,IAAI,CAAC,IAAK,EAAE,IAAI,CAAC,IAAK,EAAE,IAAI,IAAI,CAAC,IAAK,EAAE,KAAK,CAAC;AACzH;AACA,SAAS,SAAS,GAAQ,GAAc;AACtC,WAAS,IAAI,GAAG,IAAI,GAAG,IAAK,UAAS,IAAI,GAAG,IAAI,GAAG,IAAK,GAAE,IAAI,IAAI,CAAC,IAAI,EAAE,IAAI,IAAI,CAAC;AAClF,WAAS,IAAI,GAAG,IAAI,GAAG,IAAK,GAAE,KAAK,CAAC,IAAI,EAAE,EAAE,EAAE,IAAK,EAAE,IAAI,CAAC,IAAK,EAAE,EAAE,IAAK,EAAE,IAAI,IAAI,CAAC,IAAK,EAAE,EAAE,IAAK,EAAE,IAAI,IAAI,CAAC;AAC5G,IAAE,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,IAAI;AAAG,IAAE,EAAE,IAAI;AACnC;AACA,SAAS,WAAW,KAAe,KAAe,GAAQ,WAA0B;AAGlF,QAAM,KAAK,KAAK,IAAI,IAAI,CAAC,CAAE,GAAG,KAAK,KAAK,IAAI,IAAI,CAAC,CAAE,GAAG,KAAK,KAAK,IAAI,IAAI,CAAC,CAAE,GAAG,KAAK,KAAK,IAAI,IAAI,CAAC,CAAE,GAAG,KAAK,KAAK,IAAI,IAAI,CAAC,CAAE,GAAG,KAAK,KAAK,IAAI,IAAI,CAAC,CAAE;AACnJ,QAAM,IAAI,CAAC,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,CAAC,KAAK,KAAK,KAAK,KAAK,IAAI,CAAC,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,CAAC,IAAI,KAAK,EAAE;AACpJ,WAAS,IAAI,GAAG,IAAI,GAAG,cAAc,IAAI,GAAG,IAAI,GAAG,IAAK,GAAE,IAAI,IAAI,CAAC,IAAI,YAAY,EAAE,IAAI,IAAI,CAAC,IAAK,EAAE,IAAI,IAAI,CAAC;AAC9G,IAAE,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,IAAI;AAAG,IAAE,EAAE,IAAI,IAAI,CAAC;AAAI,IAAE,EAAE,IAAI,IAAI,CAAC;AAAI,IAAE,EAAE,IAAI,IAAI,CAAC;AAAI,IAAE,EAAE,IAAI;AACtF;AACA,SAAS,UAAU,GAAW,GAAW,GAAW,GAAW,IAAY,IAAY,IAAY,GAAc;AAC/G,QAAM,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI;AAC/G,IAAE,CAAC,IAAI,IAAI,KAAK,KAAK;AAAK,IAAE,CAAC,IAAI,KAAK,KAAK;AAAK,IAAE,CAAC,IAAI,KAAK,KAAK;AAAK,IAAE,CAAC,IAAI;AAC7E,IAAE,CAAC,IAAI,KAAK,KAAK;AAAK,IAAE,CAAC,IAAI,IAAI,KAAK,KAAK;AAAK,IAAE,CAAC,IAAI,KAAK,KAAK;AAAK,IAAE,CAAC,IAAI;AAC7E,IAAE,CAAC,IAAI,KAAK,KAAK;AAAK,IAAE,CAAC,IAAI,KAAK,KAAK;AAAK,IAAE,EAAE,IAAI,IAAI,KAAK,KAAK;AAAK,IAAE,EAAE,IAAI;AAC/E,IAAE,EAAE,IAAI;AAAI,IAAE,EAAE,IAAI;AAAI,IAAE,EAAE,IAAI;AAAI,IAAE,EAAE,IAAI;AAC9C;AACA,SAAS,WAAW,GAAc,IAAY,IAAY,GAAW,MAAe,GAAc;AAChG,QAAM,IAAI,EAAE;AACZ,MAAI,GAAW,GAAW,GAAW;AACrC,MAAI,EAAE,WAAW,GAAG;AAAE,QAAI,EAAE,CAAC,IAAK;AAAG,QAAI,EAAE,CAAC,IAAK;AAAG,QAAI,EAAE,CAAC,IAAK;AAAG,QAAI,EAAE,CAAC,IAAK;AAAA,EAAG,OAC7E;AACH,UAAM,IAAI,KAAK,GAAG,IAAI,KAAK;AAC3B,UAAM,KAAK,EAAE,CAAC,IAAK,GAAG,KAAK,EAAE,IAAI,CAAC,IAAK,GAAG,KAAK,EAAE,IAAI,CAAC,IAAK,GAAG,KAAK,EAAE,IAAI,CAAC,IAAK;AAC/E,QAAI,KAAK,EAAE,CAAC,IAAK,GAAG,KAAK,EAAE,IAAI,CAAC,IAAK,GAAG,KAAK,EAAE,IAAI,CAAC,IAAK,GAAG,KAAK,EAAE,IAAI,CAAC,IAAK;AAC7E,QAAI,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,GAAG;AAAE,WAAK,CAAC;AAAI,WAAK,CAAC;AAAI,WAAK,CAAC;AAAI,WAAK,CAAC;AAAA,IAAI;AACzF,QAAI,MAAM,KAAK,MAAM;AAAG,QAAI,MAAM,KAAK,MAAM;AAAG,QAAI,MAAM,KAAK,MAAM;AAAG,QAAI,MAAM,KAAK,MAAM;AAAA,EAC/F;AACA,QAAM,IAAI,KAAK,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK;AACpC,OAAK;AAAG,OAAK;AAAG,OAAK;AAAG,OAAK;AAC7B,MAAI,MAAM;AAAE,QAAI,CAAC;AAAG,QAAI,CAAC;AAAG,QAAI,CAAC;AAAA,EAAG;AACpC,QAAM,IAAI,EAAE;AACZ,MAAI,IAAY,IAAY;AAC5B,MAAI,EAAE,WAAW,GAAG;AAAE,SAAK,EAAE,CAAC;AAAI,SAAK,EAAE,CAAC;AAAI,SAAK,EAAE,CAAC;AAAA,EAAI,OACrD;AAAE,UAAM,IAAI,KAAK,GAAG,IAAI,KAAK;AAAG,SAAK,EAAE,CAAC,KAAM,EAAE,CAAC,IAAK,EAAE,CAAC,KAAM;AAAG,SAAK,EAAE,IAAI,CAAC,KAAM,EAAE,IAAI,CAAC,IAAK,EAAE,IAAI,CAAC,KAAM;AAAG,SAAK,EAAE,IAAI,CAAC,KAAM,EAAE,IAAI,CAAC,IAAK,EAAE,IAAI,CAAC,KAAM;AAAA,EAAG;AACnK,YAAU,GAAG,GAAG,GAAG,GAAG,IAAI,IAAI,IAAI,CAAC;AACrC;AAEO,MAAM,aAAwC;AAAA,EAWnD,YAAY,OAA2B,gBAAgB,OAAO;AAAvB,SAAA,gBAAA;AACrC,UAAM,IAAK,KAAK,IAAI,MAAM;AAC1B,SAAK,SAAS,MAAM,IAAI,CAAC,MAAM,EAAE,MAAM;AACvC,UAAM,QAAkB,CAAA,GAAI,OAAO,IAAI,WAAW,CAAC;AACnD,UAAM,QAAQ,CAAC,MAAc;AAAE,UAAI,KAAK,CAAC,EAAG;AAAQ,WAAK,CAAC,IAAI;AAAG,UAAI,KAAK,OAAO,CAAC,KAAM,EAAG,OAAM,KAAK,OAAO,CAAC,CAAE;AAAG,YAAM,KAAK,CAAC;AAAA,IAAG;AAClI,aAAS,IAAI,GAAG,IAAI,GAAG,WAAW,CAAC;AACnC,SAAK,QAAQ;AACb,UAAM,KAAK,MAAM,IAAI,aAAa,KAAK,CAAC,GAAG,OAAO,CAAC,QAAsB,MAAM,KAAK,EAAE,QAAQ,EAAA,GAAK,CAAC,GAAG,MAAM,IAAI,SAAS,KAAK,GAAG,KAAK,IAAI,EAAE,CAAC;AAC9I,SAAK,YAAY,GAAA;AAAM,SAAK,YAAY,GAAA;AAAM,SAAK,UAAU,GAAA;AAAM,SAAK,QAAQ,GAAA;AAAM,SAAK,OAAO,GAAA;AAClG,SAAK,aAAa,KAAK,KAAK,SAAS;AAAG,SAAK,aAAa,KAAK,KAAK,SAAS;AAAG,SAAK,OAAO,KAAK,KAAK,OAAO;AAC7G,SAAK,SAAS,KAAK,KAAK,KAAK;AAAG,SAAK,QAAQ,KAAK,KAAK,IAAI;AAC3D,eAAW,KAAK,OAAO;AACrB,iBAAW,MAAM,CAAC,EAAG,KAAK,MAAM,CAAC,EAAG,KAAK,KAAK,WAAW,CAAC,GAAI,aAAa;AAC3E,YAAM,IAAI,KAAK,OAAO,CAAC;AACvB,UAAI,IAAI,EAAG,MAAK,WAAW,CAAC,EAAG,IAAI,KAAK,WAAW,CAAC,CAAE;AAAA,UAAQ,QAAO,KAAK,WAAW,CAAC,GAAI,KAAK,WAAW,CAAC,GAAI,KAAK,WAAW,CAAC,CAAE;AAClI,eAAS,KAAK,WAAW,CAAC,GAAI,KAAK,KAAK,CAAC,CAAE;AAAA,IAC7C;AACA,aAAS,IAAI,GAAG,IAAI,KAAK,GAAG,IAAK,MAAK,KAAK,CAAC,IAAK,IAAI,KAAM,MAAM,IAAI,IAAI;AACzE,SAAK,MAAM,IAAI,KAAK,SAAS;AAAA,EAC/B;AAAA,EAnBuC;AAAA,EAV9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAAkC;AAAA,EAAkC;AAAA,EACpE;AAAA,EAA8B;AAAA,EAC9B;AAAA,EAA4B;AAAA,EAA4B;AAAA,EAAsB;AAAA,EAAwB;AAAA,EAC9F,UAAU,IAAI,aAAa,EAAE;AAAA,EAC9C,cAAc;AAAA,EACd,UAA4B,CAAC,GAAG,CAAC;AAAA;AAAA,EAwBjC,MAAM,KAAe,KAAe,GAAuB;AAAE,eAAW,KAAK,KAAK,GAAG,KAAK,aAAa;AAAA,EAAG;AAAA;AAAA,EAG1G,OAAO,KAAK,OAAkB,QAAuC;AACnE,UAAM,IAAI,IAAI,aAAa,OAAO,KAAK;AACvC,QAAI,CAAC,EAAE,EAAG,QAAO;AACjB,UAAM,IAAI,IAAI,aAAa,OAAO,IAAI;AACtC,UAAM,MAAM,CAACA,OAAoB;AAC/B,UAAI,IAAI,GAAG,IAAI;AACf,iBAAW,KAAK,QAAQ;AACtB,YAAI,CAAC,EAAE,QAAS;AAChB,cAAM,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,EAAE,cAAc,IAAI,CAAC;AACzD,iBAAS,IAAI,GAAG,IAAI,EAAE,aAAa,KAAK,MAAM;AAC5C,cAAI,KAAK,EAAE,KAAK,IAAI,CAAC,GAAI,KAAK,EAAE,OAAO,IAAI,CAAC;AAC5C,mBAAS,IAAI,GAAG,IAAI,GAAG,IAAK,KAAI,EAAE,OAAO,IAAI,IAAI,CAAC,IAAK,IAAI;AAAE,iBAAK,EAAE,OAAO,IAAI,IAAI,CAAC;AAAI,iBAAK,EAAE,KAAK,IAAI,IAAI,CAAC;AAAA,UAAI;AACjH,gBAAM,IAAIA,GAAE,WAAW,EAAE;AACzB,eAAK,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,IAAK,EAAE,EAAE,GAAI,EAAE,IAAI,IAAI,IAAI,CAAC,IAAK,EAAE,EAAE,GAAI,EAAE,IAAI,IAAI,IAAI,CAAC,IAAK,EAAE,EAAE,CAAE;AAC9F;AAAA,QACF;AAAA,MACF;AACA,aAAO,IAAI,IAAI,IAAI;AAAA,IACrB;AACA,UAAM,KAAK,IAAI,CAAC,GAAG,KAAK,IAAI,CAAC;AAC7B,UAAM,IAAI,KAAK,KAAK,OAAO,IAAI;AAC/B,MAAE,cAAc,MAAM,IAAI,0BAA0B;AACpD,MAAE,UAAU,CAAC,IAAI,EAAE;AACnB,WAAO;AAAA,EACT;AAAA,EAEA,KAAK,QAAuB,MAAc,MAAe,OAAO,OAAa;AAC3E,QAAI,CAAC,KAAK,EAAG;AACb,UAAM,IAAI,UAAU,OAAO,SAAS,SAAS,SAAS;AAEtD,UAAM,QAAQ,CAAC,GAAe,OAA0C;AACtE,YAAM,IAAI,EAAE;AACZ,UAAI,KAAK,OAAO;AAChB,WAAK,MAAO,KAAK,IAAK,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,IAAI,CAAC;AAC9D,YAAM,KAAK,KAAK,MAAM,EAAE;AACxB,aAAO,CAAC,IAAI,MAAM,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,GAAG,IAAI,CAAC,GAAG,KAAK,EAAE;AAAA,IAClE;AACA,UAAM,OAAoD,IAAI,CAAC,CAAC,GAAG,GAAG,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,EAAE,UAAU,CAAA,GAAI,IAAI,CAAC,MAA4C,CAAC,GAAG,GAAG,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAA;AACvL,eAAW,KAAK,KAAK,OAAO;AAC1B,YAAM,IAAI,KAAK;AACf,UAAI,OAAO;AACX,iBAAW,CAAC,GAAG,IAAI,IAAI,CAAC,KAAK,MAAM;AAAE,cAAM,KAAK,EAAE,OAAO,CAAC;AAAG,YAAI,IAAI;AAAE,qBAAW,IAAI,IAAI,IAAI,GAAG,MAAM,CAAC;AAAG,iBAAO;AAAM;AAAA,QAAO;AAAA,MAAE;AACjI,UAAI,CAAC,KAAM,GAAE,IAAI,KAAK,WAAW,CAAC,CAAE;AACpC,YAAM,IAAI,KAAK,OAAO,CAAC;AACvB,UAAI,IAAI,EAAG,MAAK,OAAO,CAAC,EAAG,IAAI,CAAC;AAAA,UAAQ,QAAO,GAAG,KAAK,OAAO,CAAC,GAAI,KAAK,OAAO,CAAC,CAAE;AAClF,aAAO,KAAK,KAAK,CAAC,GAAI,KAAK,OAAO,CAAC,GAAI,KAAK,MAAM,CAAC,CAAE;AAAA,IACvD;AAAA,EACF;AAAA;AAAA,EAGA,aAAa,QAAyB,QAA6B;AACjE,UAAM,KAAK,KAAK,YAAY,QAAQ,QAAQ,KAAK,GAAG,KAAK,KAAK,YAAY,QAAQ,QAAQ,IAAI;AAC9F,WAAO,KAAK,KAAK;AAAA,EACnB;AAAA;AAAA,EAGA,YAAY,QAAyB,QAAoB,KAAsB;AAC7E,UAAM,QAAuC,CAAA;AAC7C,eAAW,KAAK,QAAQ;AACtB,UAAI,CAAC,EAAE,QAAS;AAChB,YAAM,KAAK,EAAE,QAAQ,SAAS,GAAG,OAAO,KAAK,IAAI,GAAG,KAAK,MAAM,KAAK,IAAI,CAAC;AACzE,eAAS,IAAI,GAAG,IAAI,IAAI,KAAK,KAAM,OAAM,KAAK,CAAC,GAAG,EAAE,QAAQ,IAAI,CAAC,GAAI,EAAE,QAAQ,IAAI,IAAI,CAAC,CAAE,CAAC;AAAA,IAC7F;AACA,QAAI,CAAC,MAAM,OAAQ,QAAO;AAC1B,UAAM,KAAK,CAAC,GAAS,GAAW,MAAgB;AAC9C,YAAM,IAAI,EAAE,IAAI,IAAI,CAAC,GAAI,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC,GAAI,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC;AACnE,QAAE,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI;AACrB,eAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,cAAM,IAAI,EAAE,OAAO,IAAI,IAAI,CAAC;AAC5B,YAAI,CAAC,EAAG;AACR,cAAM,IAAI,KAAK,MAAM,EAAE,KAAK,IAAI,IAAI,CAAC,CAAE;AACvC,UAAE,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,EAAE,EAAE;AAAK,UAAE,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,EAAE,EAAE;AAAK,UAAE,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,CAAC,IAAK,IAAI,EAAE,EAAE,IAAK,EAAE,EAAE;AAAA,MAC5K;AAAA,IACF;AACA,UAAM,IAAI,CAAC,GAAG,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,GAAG,CAAC;AACjC,UAAM,QAAQ,CAACC,SAAiB;AAC9B,UAAI,IAAI,GAAG,IAAI;AACf,iBAAW,MAAM,CAAC,GAAG,KAAK,MAAM,OAAO,SAAS,CAAC,GAAG,OAAO,SAAS,CAAC,GAAG;AACtE,aAAK,KAAK,QAAQ,KAAK,KAAK,OAAOA,IAAG;AACtC,mBAAW,CAAC,GAAG,GAAG,CAAC,KAAK,OAAO;AAC7B,aAAG,GAAG,GAAG,CAAC;AAAG,aAAG,GAAG,GAAG,CAAC;AACvB,gBAAM,KAAK,KAAK,MAAM,EAAE,CAAC,IAAK,EAAE,CAAC,GAAI,EAAE,CAAC,IAAK,EAAE,CAAC,GAAI,EAAE,CAAC,IAAK,EAAE,CAAC,CAAE;AACjE,gBAAM,KAAK,KAAK,MAAM,EAAE,IAAI,IAAI,CAAC,IAAK,EAAE,IAAI,IAAI,CAAC,GAAI,EAAE,IAAI,IAAI,IAAI,CAAC,IAAK,EAAE,IAAI,IAAI,IAAI,CAAC,GAAI,EAAE,IAAI,IAAI,IAAI,CAAC,IAAK,EAAE,IAAI,IAAI,IAAI,CAAC,CAAE;AACjI,eAAK,KAAK,IAAI,KAAK,EAAE;AAAG,eAAK;AAAA,QAC/B;AAAA,MACF;AACA,aAAO,KAAK,KAAK;AAAA,IACnB;AACA,WAAO,MAAM,GAAG;AAAA,EAClB;AACF;"}
@@ -0,0 +1,44 @@
1
+ import type { XrayMotion } from './motion';
2
+ export interface EnvKey {
3
+ value: number;
4
+ time: number;
5
+ shape: number;
6
+ tension: number;
7
+ continuity: number;
8
+ bias: number;
9
+ param: number[];
10
+ }
11
+ export interface Envelope {
12
+ behavior: [number, number];
13
+ keys: EnvKey[];
14
+ }
15
+ export interface SMotion {
16
+ name: string;
17
+ frameStart: number;
18
+ frameEnd: number;
19
+ fps: number;
20
+ version: number;
21
+ flags: number;
22
+ boneOrPart: number;
23
+ speed: number;
24
+ bones: Array<{
25
+ name: string;
26
+ flags: number;
27
+ envs: Envelope[];
28
+ }>;
29
+ }
30
+ /** Animation list: u32 count + animations (.skls, .object chunk 0x0916). */
31
+ export declare function parseSMotions(u: Uint8Array): SMotion[];
32
+ /** .skl: chunk 0x1200 with one animation. */
33
+ export declare function parseSkl(u: Uint8Array): SMotion;
34
+ export declare function evalEnvelope(env: Envelope, time: number): number;
35
+ /** Quaternion from a rotation matrix (rows, as in the X-Ray skeleton's quatLocal). */
36
+ export declare function quatOfRows(o: ArrayLike<number>): [number, number, number, number];
37
+ /**
38
+ * SDK animation → X-Ray tracks per model bone (by name): envelopes are evaluated at every frame, the rotation (setXYZi)
39
+ * is converted to a quaternion. local(rot, pos, out) is the bone matrix from angles, as for this skeleton's bind pose.
40
+ */
41
+ export declare function smotionToXray(sm: SMotion, boneNames: readonly string[], local: (rot: number[], pos: number[], o: Float32Array) => void, parts?: Array<{
42
+ name: string;
43
+ bones: string[];
44
+ }>): XrayMotion;