@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.
- package/LICENSE +21 -0
- package/README.md +77 -2
- package/dist/db.d.ts +12 -0
- package/dist/db.js +134 -0
- package/dist/db.js.map +1 -0
- package/dist/details.d.ts +42 -0
- package/dist/details.js +210 -0
- package/dist/details.js.map +1 -0
- package/dist/export.d.ts +38 -0
- package/dist/export.js +241 -0
- package/dist/export.js.map +1 -0
- package/dist/games/cop.d.ts +7 -0
- package/dist/games/cop.js +11 -0
- package/dist/games/cop.js.map +1 -0
- package/dist/games/cs.d.ts +7 -0
- package/dist/games/cs.js +11 -0
- package/dist/games/cs.js.map +1 -0
- package/dist/games/sdk.d.ts +7 -0
- package/dist/games/sdk.js +10 -0
- package/dist/games/sdk.js.map +1 -0
- package/dist/games/soc.d.ts +9 -0
- package/dist/games/soc.js +13 -0
- package/dist/games/soc.js.map +1 -0
- package/dist/i18n.d.ts +2 -0
- package/dist/i18n.js +48 -0
- package/dist/i18n.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +131 -0
- package/dist/index.js.map +1 -0
- package/dist/level.d.ts +39 -0
- package/dist/level.js +234 -0
- package/dist/level.js.map +1 -0
- package/dist/load.d.ts +5 -0
- package/dist/load.js +126 -0
- package/dist/load.js.map +1 -0
- package/dist/lzhuf.d.ts +2 -0
- package/dist/lzhuf.js +136 -0
- package/dist/lzhuf.js.map +1 -0
- package/dist/motion.d.ts +28 -0
- package/dist/motion.js +20 -0
- package/dist/motion.js.map +1 -0
- package/dist/object.d.ts +138 -0
- package/dist/object.js +361 -0
- package/dist/object.js.map +1 -0
- package/dist/ogf.d.ts +93 -0
- package/dist/ogf.js +418 -0
- package/dist/ogf.js.map +1 -0
- package/dist/scene.d.ts +28 -0
- package/dist/scene.js +141 -0
- package/dist/scene.js.map +1 -0
- package/dist/skeleton.d.ts +34 -0
- package/dist/skeleton.js +252 -0
- package/dist/skeleton.js.map +1 -0
- package/dist/smotion.d.ts +44 -0
- package/dist/smotion.js +283 -0
- package/dist/smotion.js.map +1 -0
- package/dist/soc-key.d.ts +18 -0
- package/dist/soc-key.js +125 -0
- package/dist/soc-key.js.map +1 -0
- package/dist/thm.d.ts +26 -0
- package/dist/thm.js +69 -0
- package/dist/thm.js.map +1 -0
- package/dist/write-object.d.ts +31 -0
- package/dist/write-object.js +228 -0
- package/dist/write-object.js.map +1 -0
- package/dist/write-omf.d.ts +47 -0
- package/dist/write-scene.d.ts +26 -0
- package/dist/write-scene.js +114 -0
- package/dist/write-scene.js.map +1 -0
- package/package.json +70 -4
package/dist/object.js
ADDED
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
const EOBJ = {
|
|
2
|
+
MAIN: 30583,
|
|
3
|
+
VERSION: 2304,
|
|
4
|
+
FLAGS: 2307,
|
|
5
|
+
SURFACES2: 2310,
|
|
6
|
+
SURFACES3: 2311,
|
|
7
|
+
MESHES: 2320,
|
|
8
|
+
USERDATA: 2322,
|
|
9
|
+
SMOTIONS: 2326,
|
|
10
|
+
BONES: 2337,
|
|
11
|
+
REVISION: 2338,
|
|
12
|
+
BONEPARTS2: 2339,
|
|
13
|
+
LOD_REF: 2341,
|
|
14
|
+
SMOTION_REFS: 2342
|
|
15
|
+
};
|
|
16
|
+
const BONE = { DEF: 2, BIND_POSE: 3 };
|
|
17
|
+
const EMESH = {
|
|
18
|
+
VERSION: 4096,
|
|
19
|
+
NAME: 4097,
|
|
20
|
+
FLAGS: 4098,
|
|
21
|
+
BBOX: 4100,
|
|
22
|
+
VERTS: 4101,
|
|
23
|
+
FACES: 4102,
|
|
24
|
+
VMREFS: 4104,
|
|
25
|
+
SFACE: 4105,
|
|
26
|
+
OPTIONS: 4112,
|
|
27
|
+
VMAPS1: 4113,
|
|
28
|
+
VMAPS2: 4114,
|
|
29
|
+
SG: 4115
|
|
30
|
+
};
|
|
31
|
+
const cp1251 = (c) => String.fromCharCode(c < 128 ? c : c >= 192 ? c + 848 : c === 168 ? 1025 : c === 184 ? 1105 : c);
|
|
32
|
+
class R {
|
|
33
|
+
constructor(buf, pos, end) {
|
|
34
|
+
this.buf = buf;
|
|
35
|
+
this.pos = pos;
|
|
36
|
+
this.end = end;
|
|
37
|
+
this.dv = new DataView(buf);
|
|
38
|
+
this.u8 = new Uint8Array(buf);
|
|
39
|
+
}
|
|
40
|
+
buf;
|
|
41
|
+
pos;
|
|
42
|
+
end;
|
|
43
|
+
dv;
|
|
44
|
+
u8;
|
|
45
|
+
b() {
|
|
46
|
+
return this.dv.getUint8(this.pos++);
|
|
47
|
+
}
|
|
48
|
+
w() {
|
|
49
|
+
const v = this.dv.getUint16(this.pos, true);
|
|
50
|
+
this.pos += 2;
|
|
51
|
+
return v;
|
|
52
|
+
}
|
|
53
|
+
d() {
|
|
54
|
+
const v = this.dv.getUint32(this.pos, true);
|
|
55
|
+
this.pos += 4;
|
|
56
|
+
return v;
|
|
57
|
+
}
|
|
58
|
+
f() {
|
|
59
|
+
const v = this.dv.getFloat32(this.pos, true);
|
|
60
|
+
this.pos += 4;
|
|
61
|
+
return v;
|
|
62
|
+
}
|
|
63
|
+
sz() {
|
|
64
|
+
let s = "";
|
|
65
|
+
while (this.pos < this.end) {
|
|
66
|
+
const c = this.u8[this.pos++];
|
|
67
|
+
if (!c) break;
|
|
68
|
+
s += cp1251(c);
|
|
69
|
+
}
|
|
70
|
+
return s;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function chunksOf(buf, start, end) {
|
|
74
|
+
const dv = new DataView(buf), out = [];
|
|
75
|
+
let p = start;
|
|
76
|
+
while (p + 8 <= end) {
|
|
77
|
+
const id = dv.getUint32(p, true), size = dv.getUint32(p + 4, true);
|
|
78
|
+
if (p + 8 + size > end) throw new Error(`.object: чанк 0x${id.toString(16)} выходит за границы`);
|
|
79
|
+
out.push({ id, start: p + 8, end: p + 8 + size });
|
|
80
|
+
p += 8 + size;
|
|
81
|
+
}
|
|
82
|
+
return out;
|
|
83
|
+
}
|
|
84
|
+
function parseMesh(buf, start, end) {
|
|
85
|
+
const m = { name: "", flags: 0, options: [0, 0], points: new Float32Array(0), faces: new Uint32Array(0), sg: null, vmrefs: [], sfaces: [], vmaps: [] };
|
|
86
|
+
for (const c of chunksOf(buf, start, end)) {
|
|
87
|
+
const r = new R(buf, c.start, c.end);
|
|
88
|
+
switch (c.id) {
|
|
89
|
+
case EMESH.NAME:
|
|
90
|
+
m.name = r.sz();
|
|
91
|
+
break;
|
|
92
|
+
case EMESH.FLAGS:
|
|
93
|
+
m.flags = r.b();
|
|
94
|
+
break;
|
|
95
|
+
case EMESH.OPTIONS:
|
|
96
|
+
m.options = [r.d(), r.d()];
|
|
97
|
+
break;
|
|
98
|
+
case EMESH.VERTS: {
|
|
99
|
+
const n = r.d();
|
|
100
|
+
m.points = new Float32Array(n * 3);
|
|
101
|
+
for (let k = 0; k < n * 3; k++) m.points[k] = r.f();
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
case EMESH.FACES: {
|
|
105
|
+
const n = r.d();
|
|
106
|
+
m.faces = new Uint32Array(n * 6);
|
|
107
|
+
for (let k = 0; k < n * 6; k++) m.faces[k] = r.d();
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
case EMESH.SG: {
|
|
111
|
+
const n = c.end - c.start >> 2;
|
|
112
|
+
m.sg = new Uint32Array(n);
|
|
113
|
+
for (let k = 0; k < n; k++) m.sg[k] = r.d();
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
case EMESH.VMREFS: {
|
|
117
|
+
const n = r.d();
|
|
118
|
+
for (let k = 0; k < n; k++) {
|
|
119
|
+
const cnt = r.b(), ref = [];
|
|
120
|
+
for (let i = 0; i < cnt; i++) ref.push([r.d(), r.d()]);
|
|
121
|
+
m.vmrefs.push(ref);
|
|
122
|
+
}
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
case EMESH.SFACE: {
|
|
126
|
+
const n = r.w();
|
|
127
|
+
for (let k = 0; k < n; k++) {
|
|
128
|
+
const surface = r.sz(), cnt = r.d(), faces = new Uint32Array(cnt);
|
|
129
|
+
for (let i = 0; i < cnt; i++) faces[i] = r.d();
|
|
130
|
+
m.sfaces.push({ surface, faces });
|
|
131
|
+
}
|
|
132
|
+
break;
|
|
133
|
+
}
|
|
134
|
+
case EMESH.VMAPS2:
|
|
135
|
+
case EMESH.VMAPS1: {
|
|
136
|
+
const read = (withVerts) => {
|
|
137
|
+
const q = new R(buf, c.start, c.end), n = q.d(), list2 = [];
|
|
138
|
+
for (let k = 0; k < n; k++) {
|
|
139
|
+
const name = q.sz(), dim = q.b(), poly = c.id === EMESH.VMAPS2 ? q.b() !== 0 : false, type = q.b(), size = q.d();
|
|
140
|
+
if (q.pos + size * dim * 4 > c.end) return null;
|
|
141
|
+
const data = new Float32Array(size * dim);
|
|
142
|
+
for (let i = 0; i < size * dim; i++) data[i] = q.f();
|
|
143
|
+
const vertices = new Uint32Array(withVerts ? size : 0);
|
|
144
|
+
if (withVerts) {
|
|
145
|
+
if (q.pos + size * 4 > c.end) return null;
|
|
146
|
+
for (let i = 0; i < size; i++) vertices[i] = q.d();
|
|
147
|
+
}
|
|
148
|
+
let faces = null;
|
|
149
|
+
if (poly) {
|
|
150
|
+
if (q.pos + size * 4 > c.end) return null;
|
|
151
|
+
faces = new Uint32Array(size);
|
|
152
|
+
for (let i = 0; i < size; i++) faces[i] = q.d();
|
|
153
|
+
}
|
|
154
|
+
list2.push({ name, dim, poly, type, data, vertices, faces });
|
|
155
|
+
}
|
|
156
|
+
return q.pos === c.end ? list2 : null;
|
|
157
|
+
};
|
|
158
|
+
const list = read(true) ?? (c.id === EMESH.VMAPS1 ? read(false) : null);
|
|
159
|
+
if (!list) throw new Error(`.object: чанк меша 0x${c.id.toString(16)} разобран неверно`);
|
|
160
|
+
m.vmaps.push(...list);
|
|
161
|
+
r.pos = c.end;
|
|
162
|
+
break;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
if (r.pos > c.end) throw new Error(`.object: чанк меша 0x${c.id.toString(16)} разобран неверно`);
|
|
166
|
+
}
|
|
167
|
+
return m;
|
|
168
|
+
}
|
|
169
|
+
function parseObject(buf) {
|
|
170
|
+
const top = chunksOf(buf, 0, buf.byteLength).find((c) => c.id === EOBJ.MAIN);
|
|
171
|
+
if (!top) throw new Error("Не объект X-Ray SDK (.object): нет чанка 0x7777");
|
|
172
|
+
const o = { version: 0, flags: 0, userdata: "", lodRef: "", surfaces: [], meshes: [], revision: null, extra: [] };
|
|
173
|
+
for (const c of chunksOf(buf, top.start, top.end)) {
|
|
174
|
+
const r = new R(buf, c.start, c.end);
|
|
175
|
+
switch (c.id) {
|
|
176
|
+
case EOBJ.VERSION:
|
|
177
|
+
o.version = r.w();
|
|
178
|
+
break;
|
|
179
|
+
case EOBJ.FLAGS:
|
|
180
|
+
o.flags = r.d();
|
|
181
|
+
break;
|
|
182
|
+
case EOBJ.USERDATA:
|
|
183
|
+
o.userdata = r.sz();
|
|
184
|
+
break;
|
|
185
|
+
case EOBJ.LOD_REF:
|
|
186
|
+
o.lodRef = r.sz();
|
|
187
|
+
break;
|
|
188
|
+
case EOBJ.MESHES:
|
|
189
|
+
for (const mc of chunksOf(buf, c.start, c.end)) o.meshes.push(parseMesh(buf, mc.start, mc.end));
|
|
190
|
+
break;
|
|
191
|
+
case EOBJ.SURFACES3:
|
|
192
|
+
case EOBJ.SURFACES2: {
|
|
193
|
+
const n = r.d();
|
|
194
|
+
for (let k = 0; k < n; k++) {
|
|
195
|
+
const s = { name: r.sz(), eshader: r.sz(), cshader: r.sz(), gamemtl: c.id === EOBJ.SURFACES3 ? r.sz() : "default", texture: r.sz(), vmap: r.sz(), flags: r.d(), fvf: r.d() };
|
|
196
|
+
r.d();
|
|
197
|
+
o.surfaces.push(s);
|
|
198
|
+
}
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
case EOBJ.REVISION:
|
|
202
|
+
o.revision = { owner: r.sz(), created: r.d(), modifier: r.sz(), modified: r.d() };
|
|
203
|
+
break;
|
|
204
|
+
default:
|
|
205
|
+
o.extra.push({ id: c.id, data: new Uint8Array(buf.slice(c.start, c.end)) });
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
if (o.version !== 16) throw new Error(`.object версии 0x${o.version.toString(16)} не поддерживается (нужна 0x10, SDK ТЧ/ЧН/ЗП)`);
|
|
209
|
+
return o;
|
|
210
|
+
}
|
|
211
|
+
function objectMeshes(o, smoothing = "auto", boneOfMap) {
|
|
212
|
+
const out = [];
|
|
213
|
+
for (const m of o.meshes) {
|
|
214
|
+
const nf = m.faces.length / 6, P = m.points;
|
|
215
|
+
const fn = new Float32Array(nf * 3);
|
|
216
|
+
for (let f = 0; f < nf; f++) {
|
|
217
|
+
const a = m.faces[f * 6] * 3, b = m.faces[f * 6 + 2] * 3, c = m.faces[f * 6 + 4] * 3;
|
|
218
|
+
const ux = P[b] - P[a], uy = P[b + 1] - P[a + 1], uz = P[b + 2] - P[a + 2], vx = P[c] - P[a], vy = P[c + 1] - P[a + 1], vz = P[c + 2] - P[a + 2];
|
|
219
|
+
let nx = uy * vz - uz * vy, ny = uz * vx - ux * vz, nz = ux * vy - uy * vx;
|
|
220
|
+
const l = Math.hypot(nx, ny, nz) || 1;
|
|
221
|
+
nx /= l;
|
|
222
|
+
ny /= l;
|
|
223
|
+
nz /= l;
|
|
224
|
+
fn[f * 3] = nx;
|
|
225
|
+
fn[f * 3 + 1] = ny;
|
|
226
|
+
fn[f * 3 + 2] = nz;
|
|
227
|
+
}
|
|
228
|
+
const around = Array.from({ length: P.length / 3 }, () => []);
|
|
229
|
+
for (let f = 0; f < nf; f++) for (let k = 0; k < 3; k++) around[m.faces[f * 6 + k * 2]].push(f);
|
|
230
|
+
const sgv = m.sg, copEdges = smoothing === "cop" || smoothing === "auto" && !!sgv && sgv.every((v) => v < 8);
|
|
231
|
+
const hard = /* @__PURE__ */ new Set();
|
|
232
|
+
if (copEdges) {
|
|
233
|
+
for (let f = 0; f < nf; f++) for (let k = 0; k < 3; k++) if (sgv[f] >> k & 1) {
|
|
234
|
+
const a = m.faces[f * 6 + k * 2], b = m.faces[f * 6 + (k + 1) % 3 * 2];
|
|
235
|
+
hard.add(a < b ? `${a}_${b}` : `${b}_${a}`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
const others = (f, pt) => {
|
|
239
|
+
const r = [];
|
|
240
|
+
for (let k = 0; k < 3; k++) {
|
|
241
|
+
const q = m.faces[f * 6 + k * 2];
|
|
242
|
+
if (q !== pt) r.push(q);
|
|
243
|
+
}
|
|
244
|
+
return r;
|
|
245
|
+
};
|
|
246
|
+
const smoothFan = (f, pt) => {
|
|
247
|
+
if (!sgv) return around[pt];
|
|
248
|
+
if (!copEdges) {
|
|
249
|
+
const g0 = sgv[f];
|
|
250
|
+
return g0 ? around[pt].filter((g) => g === f || (sgv[g] & g0) !== 0) : [f];
|
|
251
|
+
}
|
|
252
|
+
const seen = /* @__PURE__ */ new Set([f]), stack = [f];
|
|
253
|
+
while (stack.length) {
|
|
254
|
+
const g = stack.pop();
|
|
255
|
+
for (const q of others(g, pt)) {
|
|
256
|
+
if (hard.has(pt < q ? `${pt}_${q}` : `${q}_${pt}`)) continue;
|
|
257
|
+
for (const h of around[pt]) if (!seen.has(h) && others(h, pt).includes(q)) {
|
|
258
|
+
seen.add(h);
|
|
259
|
+
stack.push(h);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
return [...seen];
|
|
264
|
+
};
|
|
265
|
+
const uvOf = (vmref) => {
|
|
266
|
+
const ref = m.vmrefs[vmref];
|
|
267
|
+
if (!ref) return [0, 0];
|
|
268
|
+
for (const [vm, idx] of ref) {
|
|
269
|
+
const map = m.vmaps[vm];
|
|
270
|
+
if (map && map.type === 0 && map.dim === 2) return [map.data[idx * 2], map.data[idx * 2 + 1]];
|
|
271
|
+
}
|
|
272
|
+
return [0, 0];
|
|
273
|
+
};
|
|
274
|
+
for (const sf of m.sfaces.length ? m.sfaces : [{ surface: o.surfaces[0]?.name ?? "", faces: Uint32Array.from({ length: nf }, (_, i) => i) }]) {
|
|
275
|
+
const pos = [], nor = [], uv = [], idx = [], key = /* @__PURE__ */ new Map();
|
|
276
|
+
for (const f of sf.faces) {
|
|
277
|
+
for (let k = 0; k < 3; k++) {
|
|
278
|
+
const pt = m.faces[f * 6 + k * 2], vr = m.faces[f * 6 + k * 2 + 1];
|
|
279
|
+
let nx = 0, ny = 0, nz = 0;
|
|
280
|
+
for (const g of smoothFan(f, pt)) {
|
|
281
|
+
nx += fn[g * 3];
|
|
282
|
+
ny += fn[g * 3 + 1];
|
|
283
|
+
nz += fn[g * 3 + 2];
|
|
284
|
+
}
|
|
285
|
+
const l = Math.hypot(nx, ny, nz) || 1;
|
|
286
|
+
nx /= l;
|
|
287
|
+
ny /= l;
|
|
288
|
+
nz /= l;
|
|
289
|
+
const [u, v] = uvOf(vr), k2 = `${pt}|${u}|${v}|${nx.toFixed(3)}|${ny.toFixed(3)}|${nz.toFixed(3)}`;
|
|
290
|
+
let vi = key.get(k2);
|
|
291
|
+
if (vi === void 0) {
|
|
292
|
+
vi = pos.length / 3;
|
|
293
|
+
key.set(k2, vi);
|
|
294
|
+
pos.push(P[pt * 3], P[pt * 3 + 1], P[pt * 3 + 2]);
|
|
295
|
+
nor.push(nx, ny, nz);
|
|
296
|
+
uv.push(u, v);
|
|
297
|
+
}
|
|
298
|
+
idx.push(vi);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
if (idx.length) out.push({ name: `${m.name}: ${sf.surface}`, surface: o.surfaces.find((s) => s.name === sf.surface), pos: Float32Array.from(pos), nor: Float32Array.from(nor), uv: Float32Array.from(uv), indices: Uint32Array.from(idx), ...{} });
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return out;
|
|
305
|
+
}
|
|
306
|
+
function objectSkeleton(o) {
|
|
307
|
+
const get = (id) => o.extra.find((c) => c.id === id)?.data;
|
|
308
|
+
const bc = get(EOBJ.BONES);
|
|
309
|
+
if (!bc) return null;
|
|
310
|
+
const buf = bc.buffer.slice(bc.byteOffset, bc.byteOffset + bc.byteLength);
|
|
311
|
+
const raw = [];
|
|
312
|
+
for (const b of chunksOf(buf, 0, buf.byteLength)) {
|
|
313
|
+
const sub = chunksOf(buf, b.start, b.end), def = sub.find((c) => c.id === BONE.DEF), bp = sub.find((c) => c.id === BONE.BIND_POSE);
|
|
314
|
+
if (!def) continue;
|
|
315
|
+
const r = new R(buf, def.start, def.end), name = r.sz(), parent = r.sz(), wmap = r.sz();
|
|
316
|
+
let pos = [0, 0, 0], rot = [0, 0, 0];
|
|
317
|
+
if (bp && bp.end - bp.start >= 24) {
|
|
318
|
+
const q = new R(buf, bp.start, bp.end);
|
|
319
|
+
pos = [q.f(), q.f(), q.f()];
|
|
320
|
+
rot = [q.f(), q.f(), q.f()];
|
|
321
|
+
}
|
|
322
|
+
raw.push({ name, parent, wmap, rot, pos });
|
|
323
|
+
}
|
|
324
|
+
if (!raw.length) return null;
|
|
325
|
+
const at = new Map(raw.map((b, i) => [b.name.toLowerCase(), i]));
|
|
326
|
+
const bones = raw.map((b) => ({ name: b.name, parent: b.parent ? at.get(b.parent.toLowerCase()) ?? -1 : -1, wmap: b.wmap || b.name, rot: b.rot, pos: b.pos }));
|
|
327
|
+
const parts = [];
|
|
328
|
+
const pc = get(EOBJ.BONEPARTS2);
|
|
329
|
+
if (pc) {
|
|
330
|
+
try {
|
|
331
|
+
const pb = pc.buffer.slice(pc.byteOffset, pc.byteOffset + pc.byteLength), r = new R(pb, 0, pb.byteLength), n = r.d();
|
|
332
|
+
for (let i = 0; i < n; i++) {
|
|
333
|
+
const name = r.sz(), k = r.d(), list = [];
|
|
334
|
+
for (let j = 0; j < k; j++) list.push(r.sz());
|
|
335
|
+
parts.push({ name, bones: list });
|
|
336
|
+
}
|
|
337
|
+
} catch {
|
|
338
|
+
parts.length = 0;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
const motionRefs = [];
|
|
342
|
+
const rc = get(EOBJ.SMOTION_REFS);
|
|
343
|
+
if (rc) {
|
|
344
|
+
const rb = rc.buffer.slice(rc.byteOffset, rc.byteOffset + rc.byteLength), r = new R(rb, 0, rb.byteLength);
|
|
345
|
+
const n = rb.byteLength >= 4 ? new DataView(rb).getUint32(0, true) : 0;
|
|
346
|
+
if (n > 0 && n < 1e3) {
|
|
347
|
+
r.d();
|
|
348
|
+
for (let i = 0; i < n && r.pos < r.end; i++) motionRefs.push(r.sz());
|
|
349
|
+
} else motionRefs.push(...r.sz().split(",").map((x) => x.trim()).filter(Boolean));
|
|
350
|
+
}
|
|
351
|
+
return { bones, parts, motions: get(EOBJ.SMOTIONS) ?? null, motionRefs };
|
|
352
|
+
}
|
|
353
|
+
export {
|
|
354
|
+
EMESH,
|
|
355
|
+
EOBJ,
|
|
356
|
+
chunksOf,
|
|
357
|
+
objectMeshes,
|
|
358
|
+
objectSkeleton,
|
|
359
|
+
parseObject
|
|
360
|
+
};
|
|
361
|
+
//# sourceMappingURL=object.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"object.js","sources":["../src/object.ts"],"sourcesContent":["// X-Ray SDK source object (.object, \"EOBJ\"): meshes with vertices, faces, UV maps (vmap) and smoothing groups,\n// surfaces (engine shader, compiler shader, game material, texture). X-Ray coordinates: left-handed, Y up.\nexport const EOBJ = {\n MAIN: 0x7777, VERSION: 0x0900, FLAGS: 0x0903, SURFACES: 0x0905, SURFACES2: 0x0906, SURFACES3: 0x0907, MESHES: 0x0910,\n USERDATA: 0x0912, SMOTIONS: 0x0916, BONEPARTS: 0x0919, BONES: 0x0921, REVISION: 0x0922, BONEPARTS2: 0x0923, LOD_REF: 0x0925, SMOTION_REFS: 0x0926,\n} as const;\n/** Bone chunks (BONES2): version, name/parent/weight map, bind pose (position, setXYZi angles, length). */\nconst BONE = { DEF: 0x0002, BIND_POSE: 0x0003 } as const;\nexport const EMESH = {\n VERSION: 0x1000, NAME: 0x1001, FLAGS: 0x1002, BBOX: 0x1004, VERTS: 0x1005, FACES: 0x1006, VMREFS: 0x1008, SFACE: 0x1009,\n OPTIONS: 0x1010, VMAPS1: 0x1011, VMAPS2: 0x1012, SG: 0x1013,\n} as const;\n\n/** Object flags (EditObject): dynamic, progressive, LOD, HOM, multiple usage, sound occluder, HQ export. */\nexport const EOBJ_FLAG = { DYNAMIC: 1, PROGRESSIVE: 2, USING_LOD: 4, HOM: 8, MULTIPLE_USAGE: 16, SOUND_OCCLUDER: 32, HQ_EXPORT: 64 } as const;\n\nexport interface XrSurface {\n name: string; eshader: string; cshader: string; gamemtl: string; texture: string; vmap: string; flags: number; fvf: number;\n}\nexport interface XrVmap {\n name: string; dim: number; poly: boolean; type: number;\n /** size × dim values. */\n data: Float32Array;\n vertices: Uint32Array;\n /** For \"poly\" maps: the face number of every record. */\n faces: Uint32Array | null;\n}\nexport interface XrEditMesh {\n name: string; flags: number; options: [number, number];\n points: Float32Array;\n /** 3 corners per face: [point, vmref]. */\n faces: Uint32Array;\n sg: Uint32Array | null;\n /** vmref -> a list of [vmap number, index in the vmap]. */\n vmrefs: Array<Array<[number, number]>>;\n /** Surface -> face numbers. */\n sfaces: Array<{ surface: string; faces: Uint32Array }>;\n vmaps: XrVmap[];\n}\nexport interface XrObject {\n version: number; flags: number; userdata: string; lodRef: string;\n surfaces: XrSurface[]; meshes: XrEditMesh[];\n revision: { owner: string; created: number; modifier: string; modified: number } | null;\n /** Top-level chunks the reader does not parse (bones, animations…): kept as is. */\n extra: Array<{ id: number; data: Uint8Array }>;\n}\n\n/** A Windows-1251 character (SDK strings: texture and material names may be in Russian). */\nconst cp1251 = (c: number) => String.fromCharCode(c < 128 ? c : c >= 0xc0 ? c + 0x350 : c === 0xa8 ? 0x401 : c === 0xb8 ? 0x451 : c);\n\nclass R {\n readonly dv: DataView; readonly u8: Uint8Array;\n constructor(readonly buf: ArrayBuffer, public pos: number, public end: number) { this.dv = new DataView(buf); this.u8 = new Uint8Array(buf); }\n b() { return this.dv.getUint8(this.pos++); }\n w() { const v = this.dv.getUint16(this.pos, true); this.pos += 2; return v; }\n d() { const v = this.dv.getUint32(this.pos, true); this.pos += 4; return v; }\n f() { const v = this.dv.getFloat32(this.pos, true); this.pos += 4; return v; }\n sz() { let s = ''; while (this.pos < this.end) { const c = this.u8[this.pos++]!; if (!c) break; s += cp1251(c); } return s; }\n}\n\n/** Chunks [id u32, size u32] within a range. */\nexport function chunksOf(buf: ArrayBuffer, start: number, end: number): Array<{ id: number; start: number; end: number }> {\n const dv = new DataView(buf), out: Array<{ id: number; start: number; end: number }> = [];\n let p = start;\n while (p + 8 <= end) {\n const id = dv.getUint32(p, true), size = dv.getUint32(p + 4, true);\n if (p + 8 + size > end) throw new Error(`.object: чанк 0x${id.toString(16)} выходит за границы`);\n out.push({ id, start: p + 8, end: p + 8 + size });\n p += 8 + size;\n }\n return out;\n}\n\nfunction parseMesh(buf: ArrayBuffer, start: number, end: number): XrEditMesh {\n const m: XrEditMesh = { name: '', flags: 0, options: [0, 0], points: new Float32Array(0), faces: new Uint32Array(0), sg: null, vmrefs: [], sfaces: [], vmaps: [] };\n for (const c of chunksOf(buf, start, end)) {\n const r = new R(buf, c.start, c.end);\n switch (c.id) {\n case EMESH.NAME: m.name = r.sz(); break;\n case EMESH.FLAGS: m.flags = r.b(); break;\n case EMESH.OPTIONS: m.options = [r.d(), r.d()]; break;\n case EMESH.VERTS: { const n = r.d(); m.points = new Float32Array(n * 3); for (let k = 0; k < n * 3; k++) m.points[k] = r.f(); break; }\n case EMESH.FACES: { const n = r.d(); m.faces = new Uint32Array(n * 6); for (let k = 0; k < n * 6; k++) m.faces[k] = r.d(); break; }\n case EMESH.SG: { const n = (c.end - c.start) >> 2; m.sg = new Uint32Array(n); for (let k = 0; k < n; k++) m.sg[k] = r.d(); break; }\n case EMESH.VMREFS: {\n const n = r.d();\n for (let k = 0; k < n; k++) { const cnt = r.b(), ref: Array<[number, number]> = []; for (let i = 0; i < cnt; i++) ref.push([r.d(), r.d()]); m.vmrefs.push(ref); }\n break;\n }\n case EMESH.SFACE: {\n const n = r.w();\n for (let k = 0; k < n; k++) { const surface = r.sz(), cnt = r.d(), faces = new Uint32Array(cnt); for (let i = 0; i < cnt; i++) faces[i] = r.d(); m.sfaces.push({ surface, faces }); }\n break;\n }\n case EMESH.VMAPS2: case EMESH.VMAPS1: {\n // old objects (early SoC SDK): VMAPS1 has no vertex list, the map is indexed only through vmref\n const read = (withVerts: boolean) => {\n const q = new R(buf, c.start, c.end), n = q.d(), list: XrVmap[] = [];\n for (let k = 0; k < n; k++) {\n const name = q.sz(), dim = q.b(), poly = c.id === EMESH.VMAPS2 ? q.b() !== 0 : false, type = q.b(), size = q.d();\n if (q.pos + size * dim * 4 > c.end) return null;\n const data = new Float32Array(size * dim);\n for (let i = 0; i < size * dim; i++) data[i] = q.f();\n const vertices = new Uint32Array(withVerts ? size : 0);\n if (withVerts) { if (q.pos + size * 4 > c.end) return null; for (let i = 0; i < size; i++) vertices[i] = q.d(); }\n let faces: Uint32Array | null = null;\n if (poly) { if (q.pos + size * 4 > c.end) return null; faces = new Uint32Array(size); for (let i = 0; i < size; i++) faces[i] = q.d(); }\n list.push({ name, dim, poly, type, data, vertices, faces });\n }\n return q.pos === c.end ? list : null;\n };\n const list = read(true) ?? (c.id === EMESH.VMAPS1 ? read(false) : null);\n if (!list) throw new Error(`.object: чанк меша 0x${c.id.toString(16)} разобран неверно`);\n m.vmaps.push(...list);\n r.pos = c.end;\n break;\n }\n }\n if (r.pos > c.end) throw new Error(`.object: чанк меша 0x${c.id.toString(16)} разобран неверно`);\n }\n return m;\n}\n\nexport function parseObject(buf: ArrayBuffer): XrObject {\n const top = chunksOf(buf, 0, buf.byteLength).find((c) => c.id === EOBJ.MAIN);\n if (!top) throw new Error('Не объект X-Ray SDK (.object): нет чанка 0x7777');\n const o: XrObject = { version: 0, flags: 0, userdata: '', lodRef: '', surfaces: [], meshes: [], revision: null, extra: [] };\n for (const c of chunksOf(buf, top.start, top.end)) {\n const r = new R(buf, c.start, c.end);\n switch (c.id) {\n case EOBJ.VERSION: o.version = r.w(); break;\n case EOBJ.FLAGS: o.flags = r.d(); break;\n case EOBJ.USERDATA: o.userdata = r.sz(); break;\n case EOBJ.LOD_REF: o.lodRef = r.sz(); break;\n case EOBJ.MESHES: for (const mc of chunksOf(buf, c.start, c.end)) o.meshes.push(parseMesh(buf, mc.start, mc.end)); break;\n case EOBJ.SURFACES3: case EOBJ.SURFACES2: {\n const n = r.d();\n for (let k = 0; k < n; k++) {\n const s: XrSurface = { name: r.sz(), eshader: r.sz(), cshader: r.sz(), gamemtl: c.id === EOBJ.SURFACES3 ? r.sz() : 'default', texture: r.sz(), vmap: r.sz(), flags: r.d(), fvf: r.d(), };\n r.d(); // number of UV sets\n o.surfaces.push(s);\n }\n break;\n }\n case EOBJ.REVISION: o.revision = { owner: r.sz(), created: r.d(), modifier: r.sz(), modified: r.d() }; break;\n default: o.extra.push({ id: c.id, data: new Uint8Array(buf.slice(c.start, c.end)) });\n }\n }\n if (o.version !== 0x10) throw new Error(`.object версии 0x${o.version.toString(16)} не поддерживается (нужна 0x10, SDK ТЧ/ЧН/ЗП)`);\n return o;\n}\n\n/** Display mesh: per face corner, a point + UV from vmref; normals by smoothing groups. */\nexport interface XrObjectMesh { name: string; surface: XrSurface | undefined; pos: Float32Array; nor: Float32Array; uv: Float32Array; indices: Uint32Array; bone?: Float32Array; weight?: Float32Array }\n\nexport function objectMeshes(o: XrObject, smoothing: 'auto' | 'cop' | 'soc' = 'auto', boneOfMap?: Map<string, number>): XrObjectMesh[] {\n const out: XrObjectMesh[] = [];\n for (const m of o.meshes) {\n const nf = m.faces.length / 6, P = m.points;\n // face normals\n const fn = new Float32Array(nf * 3);\n for (let f = 0; f < nf; f++) {\n const a = m.faces[f * 6]! * 3, b = m.faces[f * 6 + 2]! * 3, c = m.faces[f * 6 + 4]! * 3;\n const ux = P[b]! - P[a]!, uy = P[b + 1]! - P[a + 1]!, uz = P[b + 2]! - P[a + 2]!, vx = P[c]! - P[a]!, vy = P[c + 1]! - P[a + 1]!, vz = P[c + 2]! - P[a + 2]!;\n // normal = (b − a) × (c − a): the same as for a compiled level (checked on labx8: face winding is preserved)\n let nx = uy * vz - uz * vy, ny = uz * vx - ux * vz, nz = ux * vy - uy * vx;\n const l = Math.hypot(nx, ny, nz) || 1; nx /= l; ny /= l; nz /= l;\n fn[f * 3] = nx; fn[f * 3 + 1] = ny; fn[f * 3 + 2] = nz;\n }\n // faces around a point\n const around: number[][] = Array.from({ length: P.length / 3 }, () => []);\n for (let f = 0; f < nf; f++) for (let k = 0; k < 3; k++) around[m.faces[f * 6 + k * 2]!]!.push(f);\n // CoP (SDK 0.7): sg has one bit per face edge (bit k = edge k→k+1 is hard); SoC/CS: a smoothing group mask.\n // The file has no format flag: values below 8 on all faces are treated as edges (as found on SDK 0.7 objects).\n const sgv = m.sg, copEdges = smoothing === 'cop' || (smoothing === 'auto' && !!sgv && sgv.every((v) => v < 8));\n const hard = new Set<string>();\n if (copEdges) for (let f = 0; f < nf; f++) for (let k = 0; k < 3; k++) if ((sgv![f]! >> k) & 1) {\n const a = m.faces[f * 6 + k * 2]!, b = m.faces[f * 6 + ((k + 1) % 3) * 2]!;\n hard.add(a < b ? `${a}_${b}` : `${b}_${a}`);\n }\n const others = (f: number, pt: number) => { const r: number[] = []; for (let k = 0; k < 3; k++) { const q = m.faces[f * 6 + k * 2]!; if (q !== pt) r.push(q); } return r; };\n /** Faces whose normals are smoothed with face f at point pt. */\n const smoothFan = (f: number, pt: number): number[] => {\n if (!sgv) return around[pt]!;\n if (!copEdges) { const g0 = sgv[f]!; return g0 ? around[pt]!.filter((g) => g === f || (sgv[g]! & g0) !== 0) : [f]; }\n const seen = new Set([f]), stack = [f];\n while (stack.length) {\n const g = stack.pop()!;\n for (const q of others(g, pt)) {\n if (hard.has(pt < q ? `${pt}_${q}` : `${q}_${pt}`)) continue;\n for (const h of around[pt]!) if (!seen.has(h) && others(h, pt).includes(q)) { seen.add(h); stack.push(h); }\n }\n }\n return [...seen];\n };\n const uvOf = (vmref: number): [number, number] => {\n const ref = m.vmrefs[vmref];\n if (!ref) return [0, 0];\n for (const [vm, idx] of ref) { const map = m.vmaps[vm]; if (map && map.type === 0 && map.dim === 2) return [map.data[idx * 2]!, map.data[idx * 2 + 1]!]; }\n return [0, 0];\n };\n for (const sf of m.sfaces.length ? m.sfaces : [{ surface: o.surfaces[0]?.name ?? '', faces: Uint32Array.from({ length: nf }, (_, i) => i) }]) {\n const pos: number[] = [], nor: number[] = [], uv: number[] = [], idx: number[] = [], key = new Map<string, number>(), bone: number[] = [], weight: number[] = [];\n for (const f of sf.faces) {\n for (let k = 0; k < 3; k++) {\n const pt = m.faces[f * 6 + k * 2]!, vr = m.faces[f * 6 + k * 2 + 1]!;\n let nx = 0, ny = 0, nz = 0;\n for (const g of smoothFan(f, pt)) { nx += fn[g * 3]!; ny += fn[g * 3 + 1]!; nz += fn[g * 3 + 2]!; }\n const l = Math.hypot(nx, ny, nz) || 1;\n nx /= l; ny /= l; nz /= l;\n const [u, v] = uvOf(vr), k2 = `${pt}|${u}|${v}|${nx.toFixed(3)}|${ny.toFixed(3)}|${nz.toFixed(3)}`;\n let vi = key.get(k2);\n if (vi === undefined) {\n vi = pos.length / 3; key.set(k2, vi);\n pos.push(P[pt * 3]!, P[pt * 3 + 1]!, P[pt * 3 + 2]!); nor.push(nx, ny, nz); uv.push(u, v);\n if (boneOfMap) { const [bi, w] = cornerWeights(m, vr, boneOfMap); bone.push(...bi); weight.push(...w); }\n }\n idx.push(vi);\n }\n }\n if (idx.length) out.push({ name: `${m.name}: ${sf.surface}`, surface: o.surfaces.find((s) => s.name === sf.surface), pos: Float32Array.from(pos), nor: Float32Array.from(nor), uv: Float32Array.from(uv), indices: Uint32Array.from(idx), ...(boneOfMap ? { bone: Float32Array.from(bone), weight: Float32Array.from(weight) } : {}) });\n }\n }\n return out;\n}\n\n/** Object bone: name, parent (number), vertex weight map name, bind pose. */\nexport interface XrObjectBone { name: string; parent: number; wmap: string; rot: number[]; pos: number[] }\nexport interface XrObjectSkeleton { bones: XrObjectBone[]; parts: Array<{ name: string; bones: string[] }>; motions: Uint8Array | null; motionRefs: string[] }\n\n/** Bones (0x0921), body parts (0x0923/0x0919), animations (0x0916, like .skls) and .omf references (0x0926) from the object chunks. */\nexport function objectSkeleton(o: XrObject): XrObjectSkeleton | null {\n const get = (id: number) => o.extra.find((c) => c.id === id)?.data;\n const bc = get(EOBJ.BONES);\n if (!bc) return null;\n const buf = bc.buffer.slice(bc.byteOffset, bc.byteOffset + bc.byteLength) as ArrayBuffer;\n const raw: Array<{ name: string; parent: string; wmap: string; rot: number[]; pos: number[] }> = [];\n for (const b of chunksOf(buf, 0, buf.byteLength)) {\n const sub = chunksOf(buf, b.start, b.end), def = sub.find((c) => c.id === BONE.DEF), bp = sub.find((c) => c.id === BONE.BIND_POSE);\n if (!def) continue;\n const r = new R(buf, def.start, def.end), name = r.sz(), parent = r.sz(), wmap = r.sz();\n let pos = [0, 0, 0], rot = [0, 0, 0];\n if (bp && bp.end - bp.start >= 24) { const q = new R(buf, bp.start, bp.end); pos = [q.f(), q.f(), q.f()]; rot = [q.f(), q.f(), q.f()]; }\n raw.push({ name, parent, wmap, rot, pos });\n }\n if (!raw.length) return null;\n const at = new Map(raw.map((b, i) => [b.name.toLowerCase(), i]));\n const bones = raw.map((b) => ({ name: b.name, parent: b.parent ? at.get(b.parent.toLowerCase()) ?? -1 : -1, wmap: b.wmap || b.name, rot: b.rot, pos: b.pos }));\n const parts: XrObjectSkeleton['parts'] = [];\n const pc = get(EOBJ.BONEPARTS2);\n if (pc) {\n try {\n const pb = pc.buffer.slice(pc.byteOffset, pc.byteOffset + pc.byteLength) as ArrayBuffer, r = new R(pb, 0, pb.byteLength), n = r.d();\n for (let i = 0; i < n; i++) { const name = r.sz(), k = r.d(), list: string[] = []; for (let j = 0; j < k; j++) list.push(r.sz()); parts.push({ name, bones: list }); }\n } catch { parts.length = 0; }\n }\n const motionRefs: string[] = [];\n const rc = get(EOBJ.SMOTION_REFS);\n if (rc) {\n const rb = rc.buffer.slice(rc.byteOffset, rc.byteOffset + rc.byteLength) as ArrayBuffer, r = new R(rb, 0, rb.byteLength);\n // CoP: u32 count + strings; older SDKs: one comma-separated string\n const n = rb.byteLength >= 4 ? new DataView(rb).getUint32(0, true) : 0;\n if (n > 0 && n < 1000) { r.d(); for (let i = 0; i < n && r.pos < r.end; i++) motionRefs.push(r.sz()); }\n else motionRefs.push(...r.sz().split(',').map((x) => x.trim()).filter(Boolean));\n }\n return { bones, parts, motions: get(EOBJ.SMOTIONS) ?? null, motionRefs };\n}\n\n/** Vertex weights of a face corner (vmref): up to 4 bones from weight maps (type-1 vmaps), normalized. */\nexport function cornerWeights(m: XrEditMesh, vmref: number, boneOfMap: Map<string, number>): [number[], number[]] {\n const list: Array<[number, number]> = [];\n for (const [vm, idx] of m.vmrefs[vmref] ?? []) {\n const map = m.vmaps[vm];\n if (!map || map.type !== 1) continue;\n const b = boneOfMap.get(map.name.toLowerCase());\n if (b !== undefined) list.push([b, map.data[idx]!]);\n }\n if (!list.length) return [[0, 0, 0, 0], [1, 0, 0, 0]];\n list.sort((a, b) => b[1] - a[1]);\n const top = list.slice(0, 4), sum = top.reduce((a, x) => a + x[1], 0) || 1;\n const bi = [0, 0, 0, 0], w = [0, 0, 0, 0];\n top.forEach(([b, x], i) => { bi[i] = b; w[i] = x / sum; });\n if (top.length === 1) w[0] = 1;\n return [bi, w];\n}\n"],"names":["list"],"mappings":"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"}
|
package/dist/ogf.d.ts
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type { Bounds } from '@gmvjs/core/types';
|
|
2
|
+
import type { XrayMotion } from './motion';
|
|
3
|
+
export declare const OGF: {
|
|
4
|
+
readonly HEADER: 1;
|
|
5
|
+
readonly TEXTURE: 2;
|
|
6
|
+
readonly VERTICES: 3;
|
|
7
|
+
readonly INDICES: 4;
|
|
8
|
+
readonly CHILDREN: 9;
|
|
9
|
+
readonly S_BONE_NAMES: 13;
|
|
10
|
+
readonly S_MOTIONS: 14;
|
|
11
|
+
readonly S_SMPARAMS: 15;
|
|
12
|
+
readonly S_IKDATA: 16;
|
|
13
|
+
readonly S_USERDATA: 17;
|
|
14
|
+
readonly S_DESC: 18;
|
|
15
|
+
readonly S_MOTION_REFS0: 19;
|
|
16
|
+
readonly S_MOTION_REFS1: 24;
|
|
17
|
+
};
|
|
18
|
+
export declare const FPS = 30;
|
|
19
|
+
export interface OgfChunk {
|
|
20
|
+
id: number;
|
|
21
|
+
comp: boolean;
|
|
22
|
+
offset: number;
|
|
23
|
+
size: number;
|
|
24
|
+
}
|
|
25
|
+
export interface OgfBone {
|
|
26
|
+
name: string;
|
|
27
|
+
parent: number;
|
|
28
|
+
rot: number[];
|
|
29
|
+
pos: number[];
|
|
30
|
+
}
|
|
31
|
+
export interface OgfMesh {
|
|
32
|
+
texture: string;
|
|
33
|
+
shader: string;
|
|
34
|
+
vertexCount: number;
|
|
35
|
+
pos: Float32Array;
|
|
36
|
+
nor: Float32Array;
|
|
37
|
+
uv: Float32Array;
|
|
38
|
+
bone: Float32Array;
|
|
39
|
+
weight: Float32Array;
|
|
40
|
+
indices: Uint16Array;
|
|
41
|
+
skinned: boolean;
|
|
42
|
+
stride: number;
|
|
43
|
+
name?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface OgfModel {
|
|
46
|
+
info: {
|
|
47
|
+
type: string;
|
|
48
|
+
tris: number;
|
|
49
|
+
ikOk: boolean;
|
|
50
|
+
motionRefs: string[];
|
|
51
|
+
desc: {
|
|
52
|
+
source: string;
|
|
53
|
+
tool: string;
|
|
54
|
+
owner?: string;
|
|
55
|
+
} | null;
|
|
56
|
+
};
|
|
57
|
+
meshes: OgfMesh[];
|
|
58
|
+
bones: OgfBone[];
|
|
59
|
+
motions: XrayMotion[];
|
|
60
|
+
bounds: Bounds;
|
|
61
|
+
}
|
|
62
|
+
export declare function readChunks(buf: ArrayBuffer, start: number, end: number): OgfChunk[];
|
|
63
|
+
/** Compressed chunks (LZHUF, the top bit of the id) are unpacked into a separate buffer; the rest stay as is. */
|
|
64
|
+
export declare function unpackChunks(buf: ArrayBuffer, chunks: OgfChunk[]): {
|
|
65
|
+
buf: ArrayBuffer;
|
|
66
|
+
chunks: OgfChunk[];
|
|
67
|
+
};
|
|
68
|
+
/** Animation description from S_SMPARAMS: flags (esmFX = 1 = an "effect" on one bone), body part or bone, animation number. */
|
|
69
|
+
export interface XrayMotionDef {
|
|
70
|
+
name: string;
|
|
71
|
+
flags: number;
|
|
72
|
+
boneOrPart: number;
|
|
73
|
+
motion: number;
|
|
74
|
+
speed: number;
|
|
75
|
+
}
|
|
76
|
+
export interface XraySMParams {
|
|
77
|
+
version: number;
|
|
78
|
+
trackBones: string[];
|
|
79
|
+
parts: Array<{
|
|
80
|
+
name: string;
|
|
81
|
+
bones: string[];
|
|
82
|
+
}>;
|
|
83
|
+
defs: XrayMotionDef[];
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* S_SMPARAMS: body parts, track order and animation descriptions. Tracks in S_MOTIONS go by m_idx,
|
|
87
|
+
* and the bone is determined by name (as in the engine's motions_value::load), so the bone order of the model and the animation may differ.
|
|
88
|
+
* A part animation (legs, torso, head) drives only its part's bones; the other tracks in the file are not significant.
|
|
89
|
+
*/
|
|
90
|
+
export declare function parseSMParams(buf: ArrayBuffer, c: OgfChunk): XraySMParams | null;
|
|
91
|
+
/** External .omf animations for a model with bones `bones` (tracks matched by bone name). */
|
|
92
|
+
export declare function parseOMF(buf: ArrayBuffer, bones: readonly OgfBone[]): XrayMotion[];
|
|
93
|
+
export declare function parseOGF(buf0: ArrayBuffer): OgfModel;
|