@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.
- package/LICENSE +21 -0
- package/README.md +71 -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 (.object, «EOBJ»): меши с вершинами, гранями, UV-картами (vmap) и группами сглаживания,\n// поверхности (шейдер движка, шейдер компилятора, игровой материал, текстура). Координаты X-Ray: левосторонние, Y вверх.\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/** Чанки кости (BONES2): версия, имя/родитель/весовая карта, bind-поза (позиция, углы setXYZi, длина). */\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/** Флаги объекта (EditObject): динамический, прогрессивный, LOD, HOM, многократное использование, глушитель звука, HQ-экспорт. */\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 значений. */\n data: Float32Array;\n vertices: Uint32Array;\n /** Для «поли»-карт: номер грани каждой записи. */\n faces: Uint32Array | null;\n}\nexport interface XrEditMesh {\n name: string; flags: number; options: [number, number];\n points: Float32Array;\n /** По 3 угла на грань: [точка, vmref]. */\n faces: Uint32Array;\n sg: Uint32Array | null;\n /** vmref -> список [номер vmap, индекс в vmap]. */\n vmrefs: Array<Array<[number, number]>>;\n /** Поверхность -> номера граней. */\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 /** Чанки верхнего уровня, которые читатель не разбирает (кости, анимации…): сохраняются как есть. */\n extra: Array<{ id: number; data: Uint8Array }>;\n}\n\n/** Символ Windows-1251 (строки SDK: имена текстур и материалов бывают русскими). */\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/** Чанки [id u32, размер u32] в диапазоне. */\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 // старые объекты (SDK ТЧ ранних версий): в VMAPS1 нет списка вершин — карта индексируется только через 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(); // число наборов UV\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/** Меш для показа: по грани на угол — точка + UV из vmref; нормали по группам сглаживания. */\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 // нормали граней\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 // нормаль = (b − a) × (c − a): так же, как у скомпилированного уровня (сверено на labx8: обход граней сохраняется)\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 // грани вокруг точки\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 // ЗП (SDK 0.7): в sg по биту на ребро грани (бит k — ребро k→k+1 жёсткое); ТЧ/ЧН: маска групп сглаживания.\n // Флага формата в файле нет: значения меньше 8 у всех граней считаем рёбрами (как выяснено на объектах SDK 0.7).\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 /** Грани, нормали которых сглаживаются с гранью f в точке 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/** Кость объекта: имя, родитель (номер), имя весовой карты вершин, bind-поза. */\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/** Кости (0x0921), части тела (0x0923/0x0919), анимации (0x0916, как .skls) и ссылки на .omf (0x0926) из чанков объекта. */\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 // ЗП: u32 число + строки; старые SDK — одна строка через запятую\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/** Веса вершин угла грани (vmref): до 4 костей по весовым картам (vmap типа 1), нормированные. */\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
|
+
/** Сжатые (LZHUF, старший бит id) чанки — распаковываются в отдельный буфер; остальные остаются как есть. */
|
|
64
|
+
export declare function unpackChunks(buf: ArrayBuffer, chunks: OgfChunk[]): {
|
|
65
|
+
buf: ArrayBuffer;
|
|
66
|
+
chunks: OgfChunk[];
|
|
67
|
+
};
|
|
68
|
+
/** Описание анимации из S_SMPARAMS: флаги (esmFX = 1 — «эффект» на одну кость), часть тела или кость, номер анимации. */
|
|
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: части тела, порядок треков и описания анимаций. Треки в S_MOTIONS идут по номеру m_idx,
|
|
87
|
+
* а кость определяется по имени (как в motions_value::load движка), поэтому порядок костей модели и анимации может различаться.
|
|
88
|
+
* Анимация части (ноги, торс, голова) управляет только костями своей части — остальные треки в файле не значимы.
|
|
89
|
+
*/
|
|
90
|
+
export declare function parseSMParams(buf: ArrayBuffer, c: OgfChunk): XraySMParams | null;
|
|
91
|
+
/** Внешние анимации .omf для модели с костями bones (сопоставление треков по именам костей). */
|
|
92
|
+
export declare function parseOMF(buf: ArrayBuffer, bones: readonly OgfBone[]): XrayMotion[];
|
|
93
|
+
export declare function parseOGF(buf0: ArrayBuffer): OgfModel;
|