@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
package/dist/lzhuf.js ADDED
@@ -0,0 +1,136 @@
1
+ const N = 4096, F = 60, THRESHOLD = 2, N_CHAR = 256 - THRESHOLD + F, T = N_CHAR * 2 - 1, R = T - 1, MAX_FREQ = 16384;
2
+ const D_CODE = new Uint8Array(256), D_LEN = new Uint8Array(256);
3
+ {
4
+ let i = 0, code = 0;
5
+ [[3, 1], [4, 3], [5, 8], [6, 12], [7, 24], [8, 16]].forEach(([len, n]) => {
6
+ for (let k = 0; k < n; k++, code++) for (let r = 0; r < 1 << 8 - len; r++) {
7
+ D_CODE[i] = code;
8
+ D_LEN[i] = len;
9
+ i++;
10
+ }
11
+ });
12
+ }
13
+ function lzhufDecompress(src, outSize) {
14
+ let ip = 0;
15
+ const size = outSize ?? (src[0] | src[1] << 8 | src[2] << 16 | src[3] << 24) >>> 0;
16
+ if (outSize === void 0) ip = 4;
17
+ if (size > Math.max(1 << 16, src.length * 64)) throw new Error(`LZHUF: неправдоподобный размер ${size} (данные зашифрованы или повреждены)`);
18
+ const out = new Uint8Array(size);
19
+ const freq = new Uint32Array(T + 1), prnt = new Int32Array(T + N_CHAR), son = new Int32Array(T);
20
+ for (let i = 0; i < N_CHAR; i++) {
21
+ freq[i] = 1;
22
+ son[i] = i + T;
23
+ prnt[i + T] = i;
24
+ }
25
+ for (let i = 0, j = N_CHAR; j <= R; i += 2, j++) {
26
+ freq[j] = freq[i] + freq[i + 1];
27
+ son[j] = i;
28
+ prnt[i] = prnt[i + 1] = j;
29
+ }
30
+ freq[T] = 65535;
31
+ prnt[R] = 0;
32
+ let getbuf = 0, getlen = 0;
33
+ const fill = () => {
34
+ while (getlen <= 8) {
35
+ getbuf = (getbuf | (ip < src.length ? src[ip++] : 0) << 8 - getlen) & 65535;
36
+ getlen += 8;
37
+ }
38
+ };
39
+ const bit = () => {
40
+ fill();
41
+ const i = getbuf;
42
+ getbuf = getbuf << 1 & 65535;
43
+ getlen--;
44
+ return i >> 15 & 1;
45
+ };
46
+ const byte = () => {
47
+ fill();
48
+ const i = getbuf;
49
+ getbuf = getbuf << 8 & 65535;
50
+ getlen -= 8;
51
+ return i >> 8 & 255;
52
+ };
53
+ const reconst = () => {
54
+ let j = 0;
55
+ for (let i = 0; i < T; i++) if (son[i] >= T) {
56
+ freq[j] = freq[i] + 1 >> 1;
57
+ son[j] = son[i];
58
+ j++;
59
+ }
60
+ for (let i = 0, jj = N_CHAR; jj < T; i += 2, jj++) {
61
+ const f = freq[jj] = freq[i] + freq[i + 1];
62
+ let k = jj - 1;
63
+ while (f < freq[k]) k--;
64
+ k++;
65
+ freq.copyWithin(k + 1, k, jj);
66
+ freq[k] = f;
67
+ son.copyWithin(k + 1, k, jj);
68
+ son[k] = i;
69
+ }
70
+ for (let i = 0; i < T; i++) {
71
+ const k = son[i];
72
+ if (k >= T) prnt[k] = i;
73
+ else prnt[k] = prnt[k + 1] = i;
74
+ }
75
+ };
76
+ const update = (ch) => {
77
+ if (freq[R] === MAX_FREQ) reconst();
78
+ let c = prnt[ch + T];
79
+ do {
80
+ const k = ++freq[c];
81
+ let l = c + 1;
82
+ if (k > freq[l]) {
83
+ while (k > freq[++l]) ;
84
+ l--;
85
+ freq[c] = freq[l];
86
+ freq[l] = k;
87
+ const i = son[c];
88
+ prnt[i] = l;
89
+ if (i < T) prnt[i + 1] = l;
90
+ const j = son[l];
91
+ son[l] = i;
92
+ prnt[j] = c;
93
+ if (j < T) prnt[j + 1] = c;
94
+ son[c] = j;
95
+ c = l;
96
+ }
97
+ } while ((c = prnt[c]) !== 0);
98
+ };
99
+ const decodeChar = () => {
100
+ let c = son[R];
101
+ while (c < T) c = son[c + bit()];
102
+ c -= T;
103
+ update(c);
104
+ return c;
105
+ };
106
+ const decodePosition = () => {
107
+ let i = byte();
108
+ const c = D_CODE[i] << 6;
109
+ let j = D_LEN[i] - 2;
110
+ while (j--) i = (i << 1) + bit();
111
+ return c | i & 63;
112
+ };
113
+ const text = new Uint8Array(N).fill(32);
114
+ let r = N - F, o = 0;
115
+ while (o < size) {
116
+ const c = decodeChar();
117
+ if (c < 256) {
118
+ out[o++] = c;
119
+ text[r] = c;
120
+ r = r + 1 & N - 1;
121
+ } else {
122
+ const i = r - decodePosition() - 1 & N - 1, len = c - 255 + THRESHOLD;
123
+ for (let k = 0; k < len && o < size; k++) {
124
+ const b = text[i + k & N - 1];
125
+ out[o++] = b;
126
+ text[r] = b;
127
+ r = r + 1 & N - 1;
128
+ }
129
+ }
130
+ }
131
+ return out;
132
+ }
133
+ export {
134
+ lzhufDecompress
135
+ };
136
+ //# sourceMappingURL=lzhuf.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lzhuf.js","sources":["../src/lzhuf.ts"],"sourcesContent":["// LZHUF (LZSS + adaptive Huffman, Okumura's 1988 scheme): N = 4096, F = 60, threshold 2.\n// In xrCore the tree is rebuilt at a root frequency of 0x4000 (not 0x8000 as in the original LZHUF.C); verified on Clear Sky archives.\n// X-Ray compresses chunks with the 0x80000000 flag this way (.db archive headers, parts of level files). Input: u32 size + a bit stream.\nconst N = 4096, F = 60, THRESHOLD = 2, N_CHAR = 256 - THRESHOLD + F, T = N_CHAR * 2 - 1, R = T - 1, MAX_FREQ = 0x4000;\n\n// decoding tables for the top 6 bits of the position: codes of 3..8 bits (1, 3, 8, 12, 24, 16 codes)\nconst D_CODE = new Uint8Array(256), D_LEN = new Uint8Array(256);\n{\n let i = 0, code = 0;\n [[3, 1], [4, 3], [5, 8], [6, 12], [7, 24], [8, 16]].forEach(([len, n]) => {\n for (let k = 0; k < n!; k++, code++) for (let r = 0; r < 1 << (8 - len!); r++) { D_CODE[i] = code; D_LEN[i] = len!; i++; }\n });\n}\n\n/** Decompress LZHUF. outSize: if the size is known in advance (otherwise taken from the first 4 bytes). */\nexport function lzhufDecompress(src: Uint8Array, outSize?: number): Uint8Array {\n let ip = 0;\n const size = outSize ?? (src[0]! | (src[1]! << 8) | (src[2]! << 16) | (src[3]! << 24)) >>> 0;\n if (outSize === undefined) ip = 4;\n // an encrypted or foreign stream gives an absurd size: more than 64× the compressed size is treated as a sign of encryption\n if (size > Math.max(1 << 16, src.length * 64)) throw new Error(`LZHUF: неправдоподобный размер ${size} (данные зашифрованы или повреждены)`);\n const out = new Uint8Array(size);\n const freq = new Uint32Array(T + 1), prnt = new Int32Array(T + N_CHAR), son = new Int32Array(T);\n for (let i = 0; i < N_CHAR; i++) { freq[i] = 1; son[i] = i + T; prnt[i + T] = i; }\n for (let i = 0, j = N_CHAR; j <= R; i += 2, j++) { freq[j] = freq[i]! + freq[i + 1]!; son[j] = i; prnt[i] = prnt[i + 1] = j; }\n freq[T] = 0xffff; prnt[R] = 0;\n\n let getbuf = 0, getlen = 0;\n const fill = () => { while (getlen <= 8) { getbuf = (getbuf | ((ip < src.length ? src[ip++]! : 0) << (8 - getlen))) & 0xffff; getlen += 8; } };\n const bit = () => { fill(); const i = getbuf; getbuf = (getbuf << 1) & 0xffff; getlen--; return (i >> 15) & 1; };\n const byte = () => { fill(); const i = getbuf; getbuf = (getbuf << 8) & 0xffff; getlen -= 8; return (i >> 8) & 0xff; };\n\n const reconst = () => {\n let j = 0;\n for (let i = 0; i < T; i++) if (son[i]! >= T) { freq[j] = (freq[i]! + 1) >> 1; son[j] = son[i]!; j++; }\n for (let i = 0, jj = N_CHAR; jj < T; i += 2, jj++) {\n const f = (freq[jj] = freq[i]! + freq[i + 1]!);\n let k = jj - 1;\n while (f < freq[k]!) k--;\n k++;\n freq.copyWithin(k + 1, k, jj); freq[k] = f;\n son.copyWithin(k + 1, k, jj); son[k] = i;\n }\n for (let i = 0; i < T; i++) { const k = son[i]!; if (k >= T) prnt[k] = i; else prnt[k] = prnt[k + 1] = i; }\n };\n const update = (ch: number) => {\n if (freq[R] === MAX_FREQ) reconst();\n let c = prnt[ch + T]!;\n do {\n const k = ++freq[c]!;\n let l = c + 1;\n if (k > freq[l]!) {\n while (k > freq[++l]!);\n l--;\n freq[c] = freq[l]!; freq[l] = k;\n const i = son[c]!;\n prnt[i] = l; if (i < T) prnt[i + 1] = l;\n const j = son[l]!;\n son[l] = i;\n prnt[j] = c; if (j < T) prnt[j + 1] = c;\n son[c] = j;\n c = l;\n }\n } while ((c = prnt[c]!) !== 0);\n };\n const decodeChar = () => { let c = son[R]!; while (c < T) c = son[c + bit()]!; c -= T; update(c); return c; };\n const decodePosition = () => {\n let i = byte();\n const c = D_CODE[i]! << 6;\n let j = D_LEN[i]! - 2;\n while (j--) i = (i << 1) + bit();\n return c | (i & 0x3f);\n };\n\n const text = new Uint8Array(N).fill(0x20);\n let r = N - F, o = 0;\n while (o < size) {\n const c = decodeChar();\n if (c < 256) { out[o++] = c; text[r] = c; r = (r + 1) & (N - 1); }\n else {\n const i = (r - decodePosition() - 1) & (N - 1), len = c - 255 + THRESHOLD;\n for (let k = 0; k < len && o < size; k++) { const b = text[(i + k) & (N - 1)]!; out[o++] = b; text[r] = b; r = (r + 1) & (N - 1); }\n }\n }\n return out;\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { Motion, MotionBase } from '@gmvjs/core/types';
2
+ export interface XrayTrack {
3
+ rot: Int16Array;
4
+ trans: Float32Array;
5
+ constT?: boolean;
6
+ }
7
+ export interface XrayMotion extends MotionBase {
8
+ kind: 'xray';
9
+ frames: number;
10
+ /** Tracks by model bone number; a gap means the bone is not animated (it stays in the bind pose). */
11
+ tracks: XrayTrack[];
12
+ /** Body part (legs, torso, head) or "effect", if the animation does not drive the whole skeleton. */
13
+ part?: string;
14
+ /** Animations of other body parts playing at the same time (legs + torso): bones without their own track take it from them. */
15
+ layers?: XrayMotion[];
16
+ }
17
+ declare module '@gmvjs/core/types' {
18
+ interface MotionKinds {
19
+ xray: XrayMotion;
20
+ }
21
+ }
22
+ /** The "effect" part: an animation of one bone on top of the rest (esmFX). */
23
+ export declare const XRAY_FX_PART = "\u044D\u0444\u0444\u0435\u043A\u0442";
24
+ /**
25
+ * Layers for an animation of one body part (as in the game, legs and torso play different animations): for every other part,
26
+ * its animation sharing the most words in the name ("norm_torso_2_walk_0" → "norm_walk_fwd_0"), on a tie "idle"/"stand".
27
+ */
28
+ export declare function autoLayers(main: XrayMotion, list: readonly Motion[]): XrayMotion[];
package/dist/motion.js ADDED
@@ -0,0 +1,20 @@
1
+ const XRAY_FX_PART = "эффект";
2
+ function autoLayers(main, list) {
3
+ if (!main.part || main.part === XRAY_FX_PART) return [];
4
+ const words = (n) => n.toLowerCase().split(/[_\s]+/).filter((w) => w && !/^\d+$/.test(w) && !["norm", "torso", "legs", "head"].includes(w));
5
+ const mw = new Set(words(main.name));
6
+ const best = /* @__PURE__ */ new Map();
7
+ for (const x of list) {
8
+ if (x.kind !== "xray" || !x.part || x.part === main.part || x.part === XRAY_FX_PART || x.load) continue;
9
+ const w = words(x.name);
10
+ const score = w.filter((k) => mw.has(k)).length * 10 + (w.some((k) => k === "idle" || k === "stand") ? 2 : 0) - w.length * 0.1 - (x.name.endsWith("_") ? 1 : 0);
11
+ const cur = best.get(x.part);
12
+ if (!cur || score > cur[1]) best.set(x.part, [x, score]);
13
+ }
14
+ return [...best.values()].map(([x]) => x);
15
+ }
16
+ export {
17
+ XRAY_FX_PART,
18
+ autoLayers
19
+ };
20
+ //# sourceMappingURL=motion.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"motion.js","sources":["../src/motion.ts"],"sourcesContent":["// X-Ray animations (OGF/OMF/SDK): quantized per-frame quaternions and positions, body parts (S_SMPARAMS).\nimport type { Motion, MotionBase } from '@gmvjs/core/types';\n\nexport interface XrayTrack {\n rot: Int16Array;\n trans: Float32Array;\n constT?: boolean;\n}\nexport interface XrayMotion extends MotionBase {\n kind: 'xray';\n frames: number;\n /** Tracks by model bone number; a gap means the bone is not animated (it stays in the bind pose). */\n tracks: XrayTrack[];\n /** Body part (legs, torso, head) or \"effect\", if the animation does not drive the whole skeleton. */\n part?: string;\n /** Animations of other body parts playing at the same time (legs + torso): bones without their own track take it from them. */\n layers?: XrayMotion[];\n}\n\ndeclare module '@gmvjs/core/types' {\n interface MotionKinds { xray: XrayMotion }\n}\n\n/** The \"effect\" part: an animation of one bone on top of the rest (esmFX). */\nexport const XRAY_FX_PART = 'эффект';\n\n/**\n * Layers for an animation of one body part (as in the game, legs and torso play different animations): for every other part,\n * its animation sharing the most words in the name (\"norm_torso_2_walk_0\" → \"norm_walk_fwd_0\"), on a tie \"idle\"/\"stand\".\n */\nexport function autoLayers(main: XrayMotion, list: readonly Motion[]): XrayMotion[] {\n if (!main.part || main.part === XRAY_FX_PART) return [];\n const words = (n: string) => n.toLowerCase().split(/[_\\s]+/).filter((w) => w && !/^\\d+$/.test(w) && !['norm', 'torso', 'legs', 'head'].includes(w));\n const mw = new Set(words(main.name));\n const best = new Map<string, [XrayMotion, number]>();\n for (const x of list) {\n if (x.kind !== 'xray' || !x.part || x.part === main.part || x.part === XRAY_FX_PART || x.load) continue;\n const w = words(x.name);\n const score = w.filter((k) => mw.has(k)).length * 10 + (w.some((k) => k === 'idle' || k === 'stand') ? 2 : 0) - w.length * 0.1 - (x.name.endsWith('_') ? 1 : 0);\n const cur = best.get(x.part);\n if (!cur || score > cur[1]) best.set(x.part, [x, score]);\n }\n return [...best.values()].map(([x]) => x);\n}\n"],"names":[],"mappings":"AAwBO,MAAM,eAAe;AAMrB,SAAS,WAAW,MAAkB,MAAuC;AAClF,MAAI,CAAC,KAAK,QAAQ,KAAK,SAAS,qBAAqB,CAAA;AACrD,QAAM,QAAQ,CAAC,MAAc,EAAE,YAAA,EAAc,MAAM,QAAQ,EAAE,OAAO,CAAC,MAAM,KAAK,CAAC,QAAQ,KAAK,CAAC,KAAK,CAAC,CAAC,QAAQ,SAAS,QAAQ,MAAM,EAAE,SAAS,CAAC,CAAC;AAClJ,QAAM,KAAK,IAAI,IAAI,MAAM,KAAK,IAAI,CAAC;AACnC,QAAM,2BAAW,IAAA;AACjB,aAAW,KAAK,MAAM;AACpB,QAAI,EAAE,SAAS,UAAU,CAAC,EAAE,QAAQ,EAAE,SAAS,KAAK,QAAQ,EAAE,SAAS,gBAAgB,EAAE,KAAM;AAC/F,UAAM,IAAI,MAAM,EAAE,IAAI;AACtB,UAAM,QAAQ,EAAE,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC,EAAE,SAAS,MAAM,EAAE,KAAK,CAAC,MAAM,MAAM,UAAU,MAAM,OAAO,IAAI,IAAI,KAAK,EAAE,SAAS,OAAO,EAAE,KAAK,SAAS,GAAG,IAAI,IAAI;AAC7J,UAAM,MAAM,KAAK,IAAI,EAAE,IAAI;AAC3B,QAAI,CAAC,OAAO,QAAQ,IAAI,CAAC,EAAG,MAAK,IAAI,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC;AAAA,EACzD;AACA,SAAO,CAAC,GAAG,KAAK,OAAA,CAAQ,EAAE,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;AAC1C;"}
@@ -0,0 +1,138 @@
1
+ export declare const EOBJ: {
2
+ readonly MAIN: 30583;
3
+ readonly VERSION: 2304;
4
+ readonly FLAGS: 2307;
5
+ readonly SURFACES: 2309;
6
+ readonly SURFACES2: 2310;
7
+ readonly SURFACES3: 2311;
8
+ readonly MESHES: 2320;
9
+ readonly USERDATA: 2322;
10
+ readonly SMOTIONS: 2326;
11
+ readonly BONEPARTS: 2329;
12
+ readonly BONES: 2337;
13
+ readonly REVISION: 2338;
14
+ readonly BONEPARTS2: 2339;
15
+ readonly LOD_REF: 2341;
16
+ readonly SMOTION_REFS: 2342;
17
+ };
18
+ export declare const EMESH: {
19
+ readonly VERSION: 4096;
20
+ readonly NAME: 4097;
21
+ readonly FLAGS: 4098;
22
+ readonly BBOX: 4100;
23
+ readonly VERTS: 4101;
24
+ readonly FACES: 4102;
25
+ readonly VMREFS: 4104;
26
+ readonly SFACE: 4105;
27
+ readonly OPTIONS: 4112;
28
+ readonly VMAPS1: 4113;
29
+ readonly VMAPS2: 4114;
30
+ readonly SG: 4115;
31
+ };
32
+ /** Object flags (EditObject): dynamic, progressive, LOD, HOM, multiple usage, sound occluder, HQ export. */
33
+ export declare const EOBJ_FLAG: {
34
+ readonly DYNAMIC: 1;
35
+ readonly PROGRESSIVE: 2;
36
+ readonly USING_LOD: 4;
37
+ readonly HOM: 8;
38
+ readonly MULTIPLE_USAGE: 16;
39
+ readonly SOUND_OCCLUDER: 32;
40
+ readonly HQ_EXPORT: 64;
41
+ };
42
+ export interface XrSurface {
43
+ name: string;
44
+ eshader: string;
45
+ cshader: string;
46
+ gamemtl: string;
47
+ texture: string;
48
+ vmap: string;
49
+ flags: number;
50
+ fvf: number;
51
+ }
52
+ export interface XrVmap {
53
+ name: string;
54
+ dim: number;
55
+ poly: boolean;
56
+ type: number;
57
+ /** size × dim values. */
58
+ data: Float32Array;
59
+ vertices: Uint32Array;
60
+ /** For "poly" maps: the face number of every record. */
61
+ faces: Uint32Array | null;
62
+ }
63
+ export interface XrEditMesh {
64
+ name: string;
65
+ flags: number;
66
+ options: [number, number];
67
+ points: Float32Array;
68
+ /** 3 corners per face: [point, vmref]. */
69
+ faces: Uint32Array;
70
+ sg: Uint32Array | null;
71
+ /** vmref -> a list of [vmap number, index in the vmap]. */
72
+ vmrefs: Array<Array<[number, number]>>;
73
+ /** Surface -> face numbers. */
74
+ sfaces: Array<{
75
+ surface: string;
76
+ faces: Uint32Array;
77
+ }>;
78
+ vmaps: XrVmap[];
79
+ }
80
+ export interface XrObject {
81
+ version: number;
82
+ flags: number;
83
+ userdata: string;
84
+ lodRef: string;
85
+ surfaces: XrSurface[];
86
+ meshes: XrEditMesh[];
87
+ revision: {
88
+ owner: string;
89
+ created: number;
90
+ modifier: string;
91
+ modified: number;
92
+ } | null;
93
+ /** Top-level chunks the reader does not parse (bones, animations…): kept as is. */
94
+ extra: Array<{
95
+ id: number;
96
+ data: Uint8Array;
97
+ }>;
98
+ }
99
+ /** Chunks [id u32, size u32] within a range. */
100
+ export declare function chunksOf(buf: ArrayBuffer, start: number, end: number): Array<{
101
+ id: number;
102
+ start: number;
103
+ end: number;
104
+ }>;
105
+ export declare function parseObject(buf: ArrayBuffer): XrObject;
106
+ /** Display mesh: per face corner, a point + UV from vmref; normals by smoothing groups. */
107
+ export interface XrObjectMesh {
108
+ name: string;
109
+ surface: XrSurface | undefined;
110
+ pos: Float32Array;
111
+ nor: Float32Array;
112
+ uv: Float32Array;
113
+ indices: Uint32Array;
114
+ bone?: Float32Array;
115
+ weight?: Float32Array;
116
+ }
117
+ export declare function objectMeshes(o: XrObject, smoothing?: 'auto' | 'cop' | 'soc', boneOfMap?: Map<string, number>): XrObjectMesh[];
118
+ /** Object bone: name, parent (number), vertex weight map name, bind pose. */
119
+ export interface XrObjectBone {
120
+ name: string;
121
+ parent: number;
122
+ wmap: string;
123
+ rot: number[];
124
+ pos: number[];
125
+ }
126
+ export interface XrObjectSkeleton {
127
+ bones: XrObjectBone[];
128
+ parts: Array<{
129
+ name: string;
130
+ bones: string[];
131
+ }>;
132
+ motions: Uint8Array | null;
133
+ motionRefs: string[];
134
+ }
135
+ /** Bones (0x0921), body parts (0x0923/0x0919), animations (0x0916, like .skls) and .omf references (0x0926) from the object chunks. */
136
+ export declare function objectSkeleton(o: XrObject): XrObjectSkeleton | null;
137
+ /** Vertex weights of a face corner (vmref): up to 4 bones from weight maps (type-1 vmaps), normalized. */
138
+ export declare function cornerWeights(m: XrEditMesh, vmref: number, boneOfMap: Map<string, number>): [number[], number[]];