reze-engine 0.54.16 → 0.55.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 (49) hide show
  1. package/dist/engine.d.ts +210 -0
  2. package/dist/engine.d.ts.map +1 -1
  3. package/dist/engine.js +1063 -11
  4. package/dist/graph/presets/pool_floor.d.ts +3 -0
  5. package/dist/graph/presets/pool_floor.d.ts.map +1 -0
  6. package/dist/graph/presets/pool_floor.js +42 -0
  7. package/dist/graph/presets/water.d.ts +3 -0
  8. package/dist/graph/presets/water.d.ts.map +1 -0
  9. package/dist/graph/presets/water.js +31 -0
  10. package/dist/index.d.ts +3 -0
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +8 -0
  13. package/dist/model.d.ts.map +1 -1
  14. package/dist/model.js +10 -0
  15. package/dist/overlay.d.ts +200 -0
  16. package/dist/overlay.d.ts.map +1 -0
  17. package/dist/overlay.js +806 -0
  18. package/dist/physics/autofit.d.ts +147 -0
  19. package/dist/physics/autofit.d.ts.map +1 -0
  20. package/dist/physics/autofit.js +501 -0
  21. package/dist/pmx-document.d.ts +218 -0
  22. package/dist/pmx-document.d.ts.map +1 -0
  23. package/dist/pmx-document.js +685 -0
  24. package/dist/shaders/passes/field-blit.d.ts +26 -0
  25. package/dist/shaders/passes/field-blit.d.ts.map +1 -0
  26. package/dist/shaders/passes/field-blit.js +65 -0
  27. package/dist/shaders/passes/ground-noise.d.ts +7 -0
  28. package/dist/shaders/passes/ground-noise.d.ts.map +1 -0
  29. package/dist/shaders/passes/ground-noise.js +88 -0
  30. package/dist/shaders/passes/overlay.d.ts +3 -0
  31. package/dist/shaders/passes/overlay.d.ts.map +1 -0
  32. package/dist/shaders/passes/overlay.js +164 -0
  33. package/dist/shaders/passes/sim.d.ts +34 -0
  34. package/dist/shaders/passes/sim.d.ts.map +1 -0
  35. package/dist/shaders/passes/sim.js +169 -0
  36. package/dist/shaders/passes/wireframe.d.ts +2 -0
  37. package/dist/shaders/passes/wireframe.d.ts.map +1 -0
  38. package/dist/shaders/passes/wireframe.js +107 -0
  39. package/dist/shaders/score-api.d.ts +10 -0
  40. package/dist/shaders/score-api.d.ts.map +1 -0
  41. package/dist/shaders/score-api.js +114 -0
  42. package/package.json +1 -1
  43. package/src/engine.ts +1147 -13
  44. package/src/index.ts +50 -0
  45. package/src/model.ts +9 -0
  46. package/src/overlay.ts +1000 -0
  47. package/src/pmx-document.ts +882 -0
  48. package/src/shaders/passes/overlay.ts +166 -0
  49. package/src/shaders/passes/wireframe.ts +108 -0
@@ -0,0 +1,685 @@
1
+ // The PMX file, as data, losslessly.
2
+ //
3
+ // SEPARATE from Model on purpose. Model is what the renderer needs and drops
4
+ // everything else — English names, memos, display frames, additional UVs, SDEF
5
+ // and QDEF weights, per-vertex edge scale. That is correct for drawing: making
6
+ // Model lossless would make every viewer pay per-vertex costs for a scene it
7
+ // never edits. It is fatal for editing. A writer fed from Model would turn
8
+ // "rename a bone and save" into "rename a bone and lose every morph's panel
9
+ // assignment", and the user would rightly call that a broken editor.
10
+ //
11
+ // So this reads the file into a structure that mirrors it one for one, and
12
+ // writes that structure back. Read and write live in ONE module and each section
13
+ // keeps its reader and writer adjacent, because the only real failure mode here
14
+ // is the two drifting apart in field order — which the format cannot detect and
15
+ // which produces a file that loads as garbage.
16
+ //
17
+ // Round-tripping is checked byte-for-byte against real models in
18
+ // tests/pmx-roundtrip.test.mjs. That test is the product promise in executable
19
+ // form, so it is worth more than any of the code below.
20
+ // ──────────────────────────────────────────────────────────────────
21
+ // Bytes
22
+ class Cursor {
23
+ constructor(buffer) {
24
+ this.at = 0;
25
+ this.view = new DataView(buffer);
26
+ this.bytes = new Uint8Array(buffer);
27
+ }
28
+ u8() {
29
+ return this.view.getUint8(this.at++);
30
+ }
31
+ u16() {
32
+ const v = this.view.getUint16(this.at, true);
33
+ this.at += 2;
34
+ return v;
35
+ }
36
+ i32() {
37
+ const v = this.view.getInt32(this.at, true);
38
+ this.at += 4;
39
+ return v;
40
+ }
41
+ f32() {
42
+ const v = this.view.getFloat32(this.at, true);
43
+ this.at += 4;
44
+ return v;
45
+ }
46
+ vec2() {
47
+ return [this.f32(), this.f32()];
48
+ }
49
+ vec3() {
50
+ return [this.f32(), this.f32(), this.f32()];
51
+ }
52
+ vec4() {
53
+ return [this.f32(), this.f32(), this.f32(), this.f32()];
54
+ }
55
+ /** Unsigned — vertex indices only. */
56
+ uindex(size) {
57
+ if (size === 1)
58
+ return this.u8();
59
+ if (size === 2)
60
+ return this.u16();
61
+ return this.view.getUint32((this.at += 4) - 4, true);
62
+ }
63
+ /** Signed, with the all-ones pattern meaning "none". Every index but vertex. */
64
+ index(size) {
65
+ if (size === 1)
66
+ return this.view.getInt8(this.at++);
67
+ if (size === 2) {
68
+ const v = this.view.getInt16(this.at, true);
69
+ this.at += 2;
70
+ return v;
71
+ }
72
+ return this.i32();
73
+ }
74
+ text(encoding) {
75
+ const length = this.i32();
76
+ const slice = this.bytes.subarray(this.at, this.at + length);
77
+ this.at += length;
78
+ if (encoding === 1)
79
+ return new TextDecoder("utf-8").decode(slice);
80
+ return new TextDecoder("utf-16le").decode(slice);
81
+ }
82
+ }
83
+ class Sink {
84
+ constructor() {
85
+ this.chunks = [];
86
+ this.buf = new Uint8Array(65536);
87
+ this.view = new DataView(this.buf.buffer);
88
+ this.at = 0;
89
+ }
90
+ need(n) {
91
+ if (this.at + n <= this.buf.length)
92
+ return;
93
+ this.chunks.push(this.buf.subarray(0, this.at));
94
+ this.buf = new Uint8Array(Math.max(65536, n));
95
+ this.view = new DataView(this.buf.buffer);
96
+ this.at = 0;
97
+ }
98
+ u8(v) {
99
+ this.need(1);
100
+ this.view.setUint8(this.at++, v);
101
+ }
102
+ u16(v) {
103
+ this.need(2);
104
+ this.view.setUint16(this.at, v, true);
105
+ this.at += 2;
106
+ }
107
+ i32(v) {
108
+ this.need(4);
109
+ this.view.setInt32(this.at, v, true);
110
+ this.at += 4;
111
+ }
112
+ f32(v) {
113
+ this.need(4);
114
+ this.view.setFloat32(this.at, v, true);
115
+ this.at += 4;
116
+ }
117
+ vec(v) {
118
+ for (const n of v)
119
+ this.f32(n);
120
+ }
121
+ uindex(size, v) {
122
+ if (size === 1)
123
+ this.u8(v);
124
+ else if (size === 2)
125
+ this.u16(v);
126
+ else
127
+ this.i32(v | 0);
128
+ }
129
+ index(size, v) {
130
+ if (size === 1)
131
+ this.u8(v & 0xff);
132
+ else if (size === 2)
133
+ this.u16(v & 0xffff);
134
+ else
135
+ this.i32(v);
136
+ }
137
+ raw(v) {
138
+ this.need(v.length);
139
+ this.buf.set(v, this.at);
140
+ this.at += v.length;
141
+ }
142
+ text(encoding, v) {
143
+ const bytes = encoding === 1 ? new TextEncoder().encode(v) : utf16le(v);
144
+ this.i32(bytes.length);
145
+ this.raw(bytes);
146
+ }
147
+ finish() {
148
+ this.chunks.push(this.buf.subarray(0, this.at));
149
+ let total = 0;
150
+ for (const c of this.chunks)
151
+ total += c.length;
152
+ const out = new Uint8Array(total);
153
+ let at = 0;
154
+ for (const c of this.chunks) {
155
+ out.set(c, at);
156
+ at += c.length;
157
+ }
158
+ return out.buffer;
159
+ }
160
+ }
161
+ /** TextEncoder has no utf-16le, so the surrogate pairs are written by hand. */
162
+ function utf16le(s) {
163
+ const out = new Uint8Array(s.length * 2);
164
+ const view = new DataView(out.buffer);
165
+ for (let i = 0; i < s.length; i++)
166
+ view.setUint16(i * 2, s.charCodeAt(i), true);
167
+ return out;
168
+ }
169
+ // ──────────────────────────────────────────────────────────────────
170
+ // Read and write, one section at a time, each pair adjacent
171
+ /** Parses a PMX file into a document that writes back byte for byte. */
172
+ export function readPmxDocument(buffer) {
173
+ const c = new Cursor(buffer);
174
+ // Signature. "Pmx " appears in the wild alongside "PMX ", and PMD is the older
175
+ // format entirely — say which it was rather than "not a PMX file".
176
+ const sig = String.fromCharCode(c.u8(), c.u8(), c.u8(), c.u8());
177
+ if (sig.slice(0, 3).toUpperCase() !== "PMX") {
178
+ if (sig.slice(0, 3).toUpperCase() === "PMD") {
179
+ throw new Error("This is a PMD file (MMD's older format). Convert it to PMX in PMXEditor first.");
180
+ }
181
+ throw new Error(`Not a PMX file (signature "${sig.replace(/[^\x20-\x7e]/g, "?")}")`);
182
+ }
183
+ const version = c.f32();
184
+ const globalsCount = c.u8();
185
+ if (globalsCount < 8)
186
+ throw new Error(`PMX header declares ${globalsCount} globals, expected at least 8`);
187
+ const globals = {
188
+ encoding: c.u8(),
189
+ additionalUvCount: c.u8(),
190
+ vertexIndexSize: c.u8(),
191
+ textureIndexSize: c.u8(),
192
+ materialIndexSize: c.u8(),
193
+ boneIndexSize: c.u8(),
194
+ morphIndexSize: c.u8(),
195
+ rigidbodyIndexSize: c.u8(),
196
+ extra: [],
197
+ };
198
+ for (let i = 8; i < globalsCount; i++)
199
+ globals.extra.push(c.u8());
200
+ const e = globals.encoding;
201
+ const doc = {
202
+ version,
203
+ globals,
204
+ name: c.text(e),
205
+ nameEn: c.text(e),
206
+ comment: c.text(e),
207
+ commentEn: c.text(e),
208
+ vertices: [],
209
+ indices: new Uint32Array(0),
210
+ textures: [],
211
+ materials: [],
212
+ bones: [],
213
+ morphs: [],
214
+ displayFrames: [],
215
+ rigidbodies: [],
216
+ joints: [],
217
+ trailing: null,
218
+ };
219
+ // ── Vertices ──
220
+ const vertexCount = c.i32();
221
+ doc.vertices.length = vertexCount;
222
+ for (let i = 0; i < vertexCount; i++) {
223
+ const v = {
224
+ position: c.vec3(),
225
+ normal: c.vec3(),
226
+ uv: c.vec2(),
227
+ additionalUv: [],
228
+ weightType: 0,
229
+ bones: [],
230
+ weights: [],
231
+ edgeScale: 0,
232
+ };
233
+ for (let k = 0; k < globals.additionalUvCount; k++)
234
+ v.additionalUv.push(c.vec4());
235
+ v.weightType = c.u8();
236
+ const bi = globals.boneIndexSize;
237
+ switch (v.weightType) {
238
+ case 0:
239
+ v.bones = [c.index(bi)];
240
+ break;
241
+ case 1:
242
+ v.bones = [c.index(bi), c.index(bi)];
243
+ v.weights = [c.f32()];
244
+ break;
245
+ case 2:
246
+ case 4:
247
+ v.bones = [c.index(bi), c.index(bi), c.index(bi), c.index(bi)];
248
+ v.weights = [c.f32(), c.f32(), c.f32(), c.f32()];
249
+ break;
250
+ case 3:
251
+ v.bones = [c.index(bi), c.index(bi)];
252
+ v.weights = [c.f32()];
253
+ v.sdef = { c: c.vec3(), r0: c.vec3(), r1: c.vec3() };
254
+ break;
255
+ }
256
+ v.edgeScale = c.f32();
257
+ doc.vertices[i] = v;
258
+ }
259
+ // ── Faces ──
260
+ const indexCount = c.i32();
261
+ const indices = new Uint32Array(indexCount);
262
+ for (let i = 0; i < indexCount; i++)
263
+ indices[i] = c.uindex(globals.vertexIndexSize);
264
+ doc.indices = indices;
265
+ // ── Textures ──
266
+ const textureCount = c.i32();
267
+ for (let i = 0; i < textureCount; i++)
268
+ doc.textures.push(c.text(e));
269
+ // ── Materials ──
270
+ const materialCount = c.i32();
271
+ for (let i = 0; i < materialCount; i++) {
272
+ const m = {
273
+ name: c.text(e),
274
+ nameEn: c.text(e),
275
+ diffuse: c.vec4(),
276
+ specular: c.vec3(),
277
+ specularPower: c.f32(),
278
+ ambient: c.vec3(),
279
+ drawFlags: c.u8(),
280
+ edgeColor: c.vec4(),
281
+ edgeSize: c.f32(),
282
+ textureIndex: c.index(globals.textureIndexSize),
283
+ sphereIndex: c.index(globals.textureIndexSize),
284
+ sphereMode: c.u8(),
285
+ toonShared: c.u8(),
286
+ toonIndex: 0,
287
+ memo: "",
288
+ indexCount: 0,
289
+ };
290
+ m.toonIndex = m.toonShared === 1 ? c.u8() : c.index(globals.textureIndexSize);
291
+ m.memo = c.text(e);
292
+ m.indexCount = c.i32();
293
+ doc.materials.push(m);
294
+ }
295
+ // ── Bones ──
296
+ const boneCount = c.i32();
297
+ const bi = globals.boneIndexSize;
298
+ for (let i = 0; i < boneCount; i++) {
299
+ const b = {
300
+ name: c.text(e),
301
+ nameEn: c.text(e),
302
+ position: c.vec3(),
303
+ parentIndex: c.index(bi),
304
+ layer: c.i32(),
305
+ flags: c.u16(),
306
+ };
307
+ if (b.flags & 0x0001)
308
+ b.tailBoneIndex = c.index(bi);
309
+ else
310
+ b.tailPosition = c.vec3();
311
+ if (b.flags & 0x0300) {
312
+ b.appendParentIndex = c.index(bi);
313
+ b.appendRatio = c.f32();
314
+ }
315
+ if (b.flags & 0x0400)
316
+ b.fixedAxis = c.vec3();
317
+ if (b.flags & 0x0800) {
318
+ b.localAxisX = c.vec3();
319
+ b.localAxisZ = c.vec3();
320
+ }
321
+ if (b.flags & 0x2000)
322
+ b.externalKey = c.i32();
323
+ if (b.flags & 0x0020) {
324
+ const targetIndex = c.index(bi);
325
+ const loopCount = c.i32();
326
+ const limitAngle = c.f32();
327
+ const linkCount = c.i32();
328
+ const links = [];
329
+ for (let k = 0; k < linkCount; k++) {
330
+ const boneIndex = c.index(bi);
331
+ const hasLimit = c.u8() === 1;
332
+ links.push(hasLimit ? { boneIndex, hasLimit, limitMin: c.vec3(), limitMax: c.vec3() } : { boneIndex, hasLimit });
333
+ }
334
+ b.ik = { targetIndex, loopCount, limitAngle, links };
335
+ }
336
+ doc.bones.push(b);
337
+ }
338
+ // ── Morphs ──
339
+ const morphCount = c.i32();
340
+ for (let i = 0; i < morphCount; i++) {
341
+ const name = c.text(e);
342
+ const nameEn = c.text(e);
343
+ const panel = c.u8();
344
+ const type = c.u8();
345
+ const offsetCount = c.i32();
346
+ const offsets = [];
347
+ for (let k = 0; k < offsetCount; k++) {
348
+ switch (type) {
349
+ case 0:
350
+ offsets.push({ kind: "group", index: c.index(globals.morphIndexSize), influence: c.f32() });
351
+ break;
352
+ case 1:
353
+ offsets.push({ kind: "vertex", index: c.uindex(globals.vertexIndexSize), offset: c.vec3() });
354
+ break;
355
+ case 2:
356
+ offsets.push({ kind: "bone", index: c.index(bi), translation: c.vec3(), rotation: c.vec4() });
357
+ break;
358
+ case 3:
359
+ case 4:
360
+ case 5:
361
+ case 6:
362
+ case 7:
363
+ offsets.push({ kind: "uv", index: c.uindex(globals.vertexIndexSize), offset: c.vec4() });
364
+ break;
365
+ case 8:
366
+ offsets.push({
367
+ kind: "material",
368
+ index: c.index(globals.materialIndexSize),
369
+ operation: c.u8(),
370
+ diffuse: c.vec4(),
371
+ specular: c.vec3(),
372
+ specularPower: c.f32(),
373
+ ambient: c.vec3(),
374
+ edgeColor: c.vec4(),
375
+ edgeSize: c.f32(),
376
+ textureTint: c.vec4(),
377
+ sphereTint: c.vec4(),
378
+ toonTint: c.vec4(),
379
+ });
380
+ break;
381
+ case 9:
382
+ offsets.push({ kind: "flip", index: c.index(globals.morphIndexSize), influence: c.f32() });
383
+ break;
384
+ case 10:
385
+ offsets.push({
386
+ kind: "impulse",
387
+ index: c.index(globals.rigidbodyIndexSize),
388
+ local: c.u8(),
389
+ velocity: c.vec3(),
390
+ torque: c.vec3(),
391
+ });
392
+ break;
393
+ default:
394
+ throw new Error(`Morph "${name}" has unknown type ${type}`);
395
+ }
396
+ }
397
+ doc.morphs.push({ name, nameEn, panel, type, offsets });
398
+ }
399
+ // ── Display frames ──
400
+ const frameCount = c.i32();
401
+ for (let i = 0; i < frameCount; i++) {
402
+ const name = c.text(e);
403
+ const nameEn = c.text(e);
404
+ const special = c.u8();
405
+ const elementCount = c.i32();
406
+ const elements = [];
407
+ for (let k = 0; k < elementCount; k++) {
408
+ const type = c.u8();
409
+ elements.push({ type, index: c.index(type === 1 ? globals.morphIndexSize : bi) });
410
+ }
411
+ doc.displayFrames.push({ name, nameEn, special, elements });
412
+ }
413
+ // ── Rigidbodies ──
414
+ const bodyCount = c.i32();
415
+ for (let i = 0; i < bodyCount; i++) {
416
+ doc.rigidbodies.push({
417
+ name: c.text(e),
418
+ nameEn: c.text(e),
419
+ boneIndex: c.index(bi),
420
+ group: c.u8(),
421
+ nonCollideMask: c.u16(),
422
+ shape: c.u8(),
423
+ size: c.vec3(),
424
+ position: c.vec3(),
425
+ rotation: c.vec3(),
426
+ mass: c.f32(),
427
+ linearDamping: c.f32(),
428
+ angularDamping: c.f32(),
429
+ restitution: c.f32(),
430
+ friction: c.f32(),
431
+ physicsMode: c.u8(),
432
+ });
433
+ }
434
+ // ── Joints ──
435
+ const jointCount = c.i32();
436
+ const ri = globals.rigidbodyIndexSize;
437
+ for (let i = 0; i < jointCount; i++) {
438
+ doc.joints.push({
439
+ name: c.text(e),
440
+ nameEn: c.text(e),
441
+ type: c.u8(),
442
+ rigidbodyA: c.index(ri),
443
+ rigidbodyB: c.index(ri),
444
+ position: c.vec3(),
445
+ rotation: c.vec3(),
446
+ positionMin: c.vec3(),
447
+ positionMax: c.vec3(),
448
+ rotationMin: c.vec3(),
449
+ rotationMax: c.vec3(),
450
+ springPosition: c.vec3(),
451
+ springRotation: c.vec3(),
452
+ });
453
+ }
454
+ if (c.at < c.bytes.length)
455
+ doc.trailing = c.bytes.slice(c.at);
456
+ return doc;
457
+ }
458
+ /** Writes a document back to PMX bytes. */
459
+ export function writePmxDocument(doc) {
460
+ const w = new Sink();
461
+ const g = doc.globals;
462
+ const e = g.encoding;
463
+ const bi = g.boneIndexSize;
464
+ for (const ch of "PMX ")
465
+ w.u8(ch.charCodeAt(0));
466
+ w.f32(doc.version);
467
+ w.u8(8 + g.extra.length);
468
+ w.u8(g.encoding);
469
+ w.u8(g.additionalUvCount);
470
+ w.u8(g.vertexIndexSize);
471
+ w.u8(g.textureIndexSize);
472
+ w.u8(g.materialIndexSize);
473
+ w.u8(g.boneIndexSize);
474
+ w.u8(g.morphIndexSize);
475
+ w.u8(g.rigidbodyIndexSize);
476
+ for (const x of g.extra)
477
+ w.u8(x);
478
+ w.text(e, doc.name);
479
+ w.text(e, doc.nameEn);
480
+ w.text(e, doc.comment);
481
+ w.text(e, doc.commentEn);
482
+ w.i32(doc.vertices.length);
483
+ for (const v of doc.vertices) {
484
+ w.vec(v.position);
485
+ w.vec(v.normal);
486
+ w.vec(v.uv);
487
+ for (let k = 0; k < g.additionalUvCount; k++)
488
+ w.vec(v.additionalUv[k] ?? [0, 0, 0, 0]);
489
+ w.u8(v.weightType);
490
+ switch (v.weightType) {
491
+ case 0:
492
+ w.index(bi, v.bones[0]);
493
+ break;
494
+ case 1:
495
+ w.index(bi, v.bones[0]);
496
+ w.index(bi, v.bones[1]);
497
+ w.f32(v.weights[0]);
498
+ break;
499
+ case 2:
500
+ case 4:
501
+ for (let k = 0; k < 4; k++)
502
+ w.index(bi, v.bones[k]);
503
+ for (let k = 0; k < 4; k++)
504
+ w.f32(v.weights[k]);
505
+ break;
506
+ case 3:
507
+ w.index(bi, v.bones[0]);
508
+ w.index(bi, v.bones[1]);
509
+ w.f32(v.weights[0]);
510
+ w.vec(v.sdef.c);
511
+ w.vec(v.sdef.r0);
512
+ w.vec(v.sdef.r1);
513
+ break;
514
+ }
515
+ w.f32(v.edgeScale);
516
+ }
517
+ w.i32(doc.indices.length);
518
+ for (let i = 0; i < doc.indices.length; i++)
519
+ w.uindex(g.vertexIndexSize, doc.indices[i]);
520
+ w.i32(doc.textures.length);
521
+ for (const t of doc.textures)
522
+ w.text(e, t);
523
+ w.i32(doc.materials.length);
524
+ for (const m of doc.materials) {
525
+ w.text(e, m.name);
526
+ w.text(e, m.nameEn);
527
+ w.vec(m.diffuse);
528
+ w.vec(m.specular);
529
+ w.f32(m.specularPower);
530
+ w.vec(m.ambient);
531
+ w.u8(m.drawFlags);
532
+ w.vec(m.edgeColor);
533
+ w.f32(m.edgeSize);
534
+ w.index(g.textureIndexSize, m.textureIndex);
535
+ w.index(g.textureIndexSize, m.sphereIndex);
536
+ w.u8(m.sphereMode);
537
+ w.u8(m.toonShared);
538
+ if (m.toonShared === 1)
539
+ w.u8(m.toonIndex);
540
+ else
541
+ w.index(g.textureIndexSize, m.toonIndex);
542
+ w.text(e, m.memo);
543
+ w.i32(m.indexCount);
544
+ }
545
+ w.i32(doc.bones.length);
546
+ for (const b of doc.bones) {
547
+ w.text(e, b.name);
548
+ w.text(e, b.nameEn);
549
+ w.vec(b.position);
550
+ w.index(bi, b.parentIndex);
551
+ w.i32(b.layer);
552
+ w.u16(b.flags);
553
+ if (b.flags & 0x0001)
554
+ w.index(bi, b.tailBoneIndex);
555
+ else
556
+ w.vec(b.tailPosition);
557
+ if (b.flags & 0x0300) {
558
+ w.index(bi, b.appendParentIndex);
559
+ w.f32(b.appendRatio);
560
+ }
561
+ if (b.flags & 0x0400)
562
+ w.vec(b.fixedAxis);
563
+ if (b.flags & 0x0800) {
564
+ w.vec(b.localAxisX);
565
+ w.vec(b.localAxisZ);
566
+ }
567
+ if (b.flags & 0x2000)
568
+ w.i32(b.externalKey);
569
+ if (b.flags & 0x0020) {
570
+ const ik = b.ik;
571
+ w.index(bi, ik.targetIndex);
572
+ w.i32(ik.loopCount);
573
+ w.f32(ik.limitAngle);
574
+ w.i32(ik.links.length);
575
+ for (const l of ik.links) {
576
+ w.index(bi, l.boneIndex);
577
+ w.u8(l.hasLimit ? 1 : 0);
578
+ if (l.hasLimit) {
579
+ w.vec(l.limitMin);
580
+ w.vec(l.limitMax);
581
+ }
582
+ }
583
+ }
584
+ }
585
+ w.i32(doc.morphs.length);
586
+ for (const m of doc.morphs) {
587
+ w.text(e, m.name);
588
+ w.text(e, m.nameEn);
589
+ w.u8(m.panel);
590
+ w.u8(m.type);
591
+ w.i32(m.offsets.length);
592
+ for (const o of m.offsets) {
593
+ switch (o.kind) {
594
+ case "group":
595
+ w.index(g.morphIndexSize, o.index);
596
+ w.f32(o.influence);
597
+ break;
598
+ case "vertex":
599
+ w.uindex(g.vertexIndexSize, o.index);
600
+ w.vec(o.offset);
601
+ break;
602
+ case "bone":
603
+ w.index(bi, o.index);
604
+ w.vec(o.translation);
605
+ w.vec(o.rotation);
606
+ break;
607
+ case "uv":
608
+ w.uindex(g.vertexIndexSize, o.index);
609
+ w.vec(o.offset);
610
+ break;
611
+ case "material":
612
+ w.index(g.materialIndexSize, o.index);
613
+ w.u8(o.operation);
614
+ w.vec(o.diffuse);
615
+ w.vec(o.specular);
616
+ w.f32(o.specularPower);
617
+ w.vec(o.ambient);
618
+ w.vec(o.edgeColor);
619
+ w.f32(o.edgeSize);
620
+ w.vec(o.textureTint);
621
+ w.vec(o.sphereTint);
622
+ w.vec(o.toonTint);
623
+ break;
624
+ case "flip":
625
+ w.index(g.morphIndexSize, o.index);
626
+ w.f32(o.influence);
627
+ break;
628
+ case "impulse":
629
+ w.index(g.rigidbodyIndexSize, o.index);
630
+ w.u8(o.local);
631
+ w.vec(o.velocity);
632
+ w.vec(o.torque);
633
+ break;
634
+ }
635
+ }
636
+ }
637
+ w.i32(doc.displayFrames.length);
638
+ for (const f of doc.displayFrames) {
639
+ w.text(e, f.name);
640
+ w.text(e, f.nameEn);
641
+ w.u8(f.special);
642
+ w.i32(f.elements.length);
643
+ for (const el of f.elements) {
644
+ w.u8(el.type);
645
+ w.index(el.type === 1 ? g.morphIndexSize : bi, el.index);
646
+ }
647
+ }
648
+ w.i32(doc.rigidbodies.length);
649
+ for (const b of doc.rigidbodies) {
650
+ w.text(e, b.name);
651
+ w.text(e, b.nameEn);
652
+ w.index(bi, b.boneIndex);
653
+ w.u8(b.group);
654
+ w.u16(b.nonCollideMask);
655
+ w.u8(b.shape);
656
+ w.vec(b.size);
657
+ w.vec(b.position);
658
+ w.vec(b.rotation);
659
+ w.f32(b.mass);
660
+ w.f32(b.linearDamping);
661
+ w.f32(b.angularDamping);
662
+ w.f32(b.restitution);
663
+ w.f32(b.friction);
664
+ w.u8(b.physicsMode);
665
+ }
666
+ w.i32(doc.joints.length);
667
+ for (const j of doc.joints) {
668
+ w.text(e, j.name);
669
+ w.text(e, j.nameEn);
670
+ w.u8(j.type);
671
+ w.index(g.rigidbodyIndexSize, j.rigidbodyA);
672
+ w.index(g.rigidbodyIndexSize, j.rigidbodyB);
673
+ w.vec(j.position);
674
+ w.vec(j.rotation);
675
+ w.vec(j.positionMin);
676
+ w.vec(j.positionMax);
677
+ w.vec(j.rotationMin);
678
+ w.vec(j.rotationMax);
679
+ w.vec(j.springPosition);
680
+ w.vec(j.springRotation);
681
+ }
682
+ if (doc.trailing)
683
+ w.raw(doc.trailing);
684
+ return w.finish();
685
+ }
@@ -0,0 +1,26 @@
1
+ /**
2
+ * The field layer, drawn INTO the scene.
3
+ *
4
+ * Field effects render into their own targets at their own resolution — that
5
+ * part was always right. What was wrong was where the result landed: the
6
+ * composite sampled it AFTER tone mapping, which is why a field effect could
7
+ * never bloom, could never light anything, and tone mapped differently from the
8
+ * particle and ribbon mounts drawing the same kind of glow.
9
+ *
10
+ * Two draws inside the scene pass — background before any geometry, foreground
11
+ * after all of it — so the bloom pyramid sees field effects and one tone map
12
+ * covers the whole frame.
13
+ *
14
+ * NO DEPTH, neither written nor tested. A foreground is handed the scene's
15
+ * depth as a parameter and does its own occlusion; testing it here would
16
+ * occlude it a second time, and a background has nothing to test against.
17
+ *
18
+ * COVERAGE IS CLAMPED HERE. Additive field effects SUM their coverage into the
19
+ * layer (see FIELD_LAYER_BLEND_ADDITIVE), which is what stops the composite's
20
+ * unpremultiply from dividing colour by nothing — but N additive effects can
21
+ * sum past 1, and the layer is rgba16float so nothing stopped it on the way in.
22
+ * A coverage above 1 would darken what the layer is drawn over by more than
23
+ * fully covering it.
24
+ */
25
+ export declare function fieldBlitShaderWgsl(): string;
26
+ //# sourceMappingURL=field-blit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"field-blit.d.ts","sourceRoot":"","sources":["../../../src/shaders/passes/field-blit.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAuC5C"}