@gmvjs/xray-v1 0.0.0-stage → 0.1.0

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 +71 -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 + адаптивный Хаффман, схема Окумуры 1988): N = 4096, F = 60, порог 2.\n// В xrCore перестройка дерева — при частоте корня 0x4000 (а не 0x8000, как в исходном LZHUF.C); проверено на архивах Чистого неба.\n// В X-Ray так сжаты чанки с флагом 0x80000000 (заголовки архивов .db, части level-файлов). Вход: u32 размер + поток бит.\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// таблицы декодирования старших 6 бит позиции: коды длиной 3..8 бит (1, 3, 8, 12, 24, 16 кодов)\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/** Распаковать LZHUF. outSize — если размер известен заранее (иначе берётся из первых 4 байт). */\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 // зашифрованный или чужой поток даёт абсурдный размер: больше 64× сжатого считаем признаком шифрования\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
+ /** Треки по номеру кости модели; пропуск — кость не анимируется (остаётся в bind-позе). */
11
+ tracks: XrayTrack[];
12
+ /** Часть тела (ноги, торс, голова) или «эффект», если анимация управляет не всем скелетом. */
13
+ part?: string;
14
+ /** Анимации других частей тела, играющие одновременно (ноги + торс): кости без своего трека берутся из них. */
15
+ layers?: XrayMotion[];
16
+ }
17
+ declare module '@gmvjs/core/types' {
18
+ interface MotionKinds {
19
+ xray: XrayMotion;
20
+ }
21
+ }
22
+ /** Часть «эффект»: анимация одной кости поверх остальных (esmFX). */
23
+ export declare const XRAY_FX_PART = "\u044D\u0444\u0444\u0435\u043A\u0442";
24
+ /**
25
+ * Слои для анимации одной части тела (как в игре: ноги и торс играют разные анимации): для каждой другой части —
26
+ * её анимация с наибольшим числом общих слов в имени («norm_torso_2_walk_0» → «norm_walk_fwd_0»), при равенстве — «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 (OGF/OMF/SDK): квантованные кватернионы и позиции по кадрам, части тела (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 /** Треки по номеру кости модели; пропуск — кость не анимируется (остаётся в bind-позе). */\n tracks: XrayTrack[];\n /** Часть тела (ноги, торс, голова) или «эффект», если анимация управляет не всем скелетом. */\n part?: string;\n /** Анимации других частей тела, играющие одновременно (ноги + торс): кости без своего трека берутся из них. */\n layers?: XrayMotion[];\n}\n\ndeclare module '@gmvjs/core/types' {\n interface MotionKinds { xray: XrayMotion }\n}\n\n/** Часть «эффект»: анимация одной кости поверх остальных (esmFX). */\nexport const XRAY_FX_PART = 'эффект';\n\n/**\n * Слои для анимации одной части тела (как в игре: ноги и торс играют разные анимации): для каждой другой части —\n * её анимация с наибольшим числом общих слов в имени («norm_torso_2_walk_0» → «norm_walk_fwd_0»), при равенстве — «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
+ /** Флаги объекта (EditObject): динамический, прогрессивный, LOD, HOM, многократное использование, глушитель звука, HQ-экспорт. */
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 значений. */
58
+ data: Float32Array;
59
+ vertices: Uint32Array;
60
+ /** Для «поли»-карт: номер грани каждой записи. */
61
+ faces: Uint32Array | null;
62
+ }
63
+ export interface XrEditMesh {
64
+ name: string;
65
+ flags: number;
66
+ options: [number, number];
67
+ points: Float32Array;
68
+ /** По 3 угла на грань: [точка, vmref]. */
69
+ faces: Uint32Array;
70
+ sg: Uint32Array | null;
71
+ /** vmref -> список [номер vmap, индекс в vmap]. */
72
+ vmrefs: Array<Array<[number, number]>>;
73
+ /** Поверхность -> номера граней. */
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
+ /** Чанки верхнего уровня, которые читатель не разбирает (кости, анимации…): сохраняются как есть. */
94
+ extra: Array<{
95
+ id: number;
96
+ data: Uint8Array;
97
+ }>;
98
+ }
99
+ /** Чанки [id u32, размер u32] в диапазоне. */
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
+ /** Меш для показа: по грани на угол — точка + UV из vmref; нормали по группам сглаживания. */
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
+ /** Кость объекта: имя, родитель (номер), имя весовой карты вершин, bind-поза. */
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
+ /** Кости (0x0921), части тела (0x0923/0x0919), анимации (0x0916, как .skls) и ссылки на .omf (0x0926) из чанков объекта. */
136
+ export declare function objectSkeleton(o: XrObject): XrObjectSkeleton | null;
137
+ /** Веса вершин угла грани (vmref): до 4 костей по весовым картам (vmap типа 1), нормированные. */
138
+ export declare function cornerWeights(m: XrEditMesh, vmref: number, boneOfMap: Map<string, number>): [number[], number[]];