rig-play 0.8.0 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/NOTICE.md +50 -23
  2. package/README.md +511 -456
  3. package/dist/CanvasRenderer.d.ts +139 -0
  4. package/dist/CanvasRenderer.d.ts.map +1 -0
  5. package/dist/{SpineHtmlRenderer.d.ts → DomRenderer.d.ts} +70 -65
  6. package/dist/DomRenderer.d.ts.map +1 -0
  7. package/dist/DomTexture.d.ts +34 -14
  8. package/dist/DomTexture.d.ts.map +1 -1
  9. package/dist/MeshGlBlitter.d.ts +67 -1
  10. package/dist/MeshGlBlitter.d.ts.map +1 -1
  11. package/dist/index.d.ts +6 -4
  12. package/dist/index.d.ts.map +1 -1
  13. package/dist/index.js +7470 -5
  14. package/dist/index.js.map +1 -1
  15. package/dist/loadModel.d.ts +92 -0
  16. package/dist/loadModel.d.ts.map +1 -0
  17. package/dist/player.d.ts +198 -0
  18. package/dist/player.d.ts.map +1 -0
  19. package/dist/posedFrame.d.ts +99 -0
  20. package/dist/posedFrame.d.ts.map +1 -0
  21. package/package.json +13 -19
  22. package/dist/DomTexture.js +0 -520
  23. package/dist/DomTexture.js.map +0 -1
  24. package/dist/MeshGlBlitter.js +0 -365
  25. package/dist/MeshGlBlitter.js.map +0 -1
  26. package/dist/SpineHtmlRenderer.d.ts.map +0 -1
  27. package/dist/SpineHtmlRenderer.js +0 -1107
  28. package/dist/SpineHtmlRenderer.js.map +0 -1
  29. package/dist/binary.d.ts +0 -48
  30. package/dist/binary.d.ts.map +0 -1
  31. package/dist/binary.js +0 -29
  32. package/dist/binary.js.map +0 -1
  33. package/dist/coreCompat.d.ts +0 -153
  34. package/dist/coreCompat.d.ts.map +0 -1
  35. package/dist/coreCompat.js +0 -136
  36. package/dist/coreCompat.js.map +0 -1
  37. package/dist/loadAtlasAssets.d.ts +0 -73
  38. package/dist/loadAtlasAssets.d.ts.map +0 -1
  39. package/dist/loadAtlasAssets.js +0 -75
  40. package/dist/loadAtlasAssets.js.map +0 -1
  41. package/dist/loadSkeletonAssets.d.ts +0 -88
  42. package/dist/loadSkeletonAssets.d.ts.map +0 -1
  43. package/dist/loadSkeletonAssets.js +0 -79
  44. package/dist/loadSkeletonAssets.js.map +0 -1
@@ -1,520 +0,0 @@
1
- import { Texture, } from '@esotericsoftware/spine-core';
2
- /**
3
- * Minimal Texture implementation for the DOM renderer. spine-core only needs
4
- * it as a handle attached to atlas pages; filtering/wrapping are GPU concepts
5
- * with no DOM equivalent, so they are no-ops.
6
- */
7
- export class DomTexture extends Texture {
8
- setFilters(_minFilter, _magFilter) { }
9
- setWraps(_uWrap, _vWrap) { }
10
- dispose() { }
11
- }
12
- /**
13
- * Blob URLs minted by unpackRegions, i.e. the ones this module owns.
14
- *
15
- * Ownership has to be tracked because a RegionImage map is not necessarily
16
- * ours: callers may hand the renderer a map built from their own URLs (loose
17
- * part PNGs need no unpacking at all). revokeRegions() therefore frees only
18
- * what is listed here and leaves caller-owned URLs untouched.
19
- */
20
- const ownedUrls = new Set();
21
- /** Revokes `url` if unpackRegions minted it. Idempotent, caller-safe. */
22
- function revokeOwned(url) {
23
- if (!ownedUrls.delete(url))
24
- return;
25
- URL.revokeObjectURL(url);
26
- }
27
- /**
28
- * Straight-alpha derivations of `pma: true` page images, one per image.
29
- *
30
- * Spine's texture packer premultiplies by default, and an atlas says so with a
31
- * `pma: true` page line: the file's RGB is already multiplied by its alpha. The
32
- * DOM and canvas 2D have no such mode — an <img> and `drawImage` composite
33
- * straight alpha by definition, so they multiply by alpha again and every
34
- * semi-transparent texel comes out darker than it was authored (#37). Both
35
- * consumers of that convention here — the region cuts below and the canvas2d
36
- * mesh raster in SpineHtmlRenderer — therefore read this derivation instead of
37
- * the page, and it is *shared*: deriving per consumer would pay for the same
38
- * page once per renderer and once again for the load.
39
- *
40
- * (The GL mesh backend needs no derivation. It consumes premultiplied texels by
41
- * construction, so it just skips `UNPACK_PREMULTIPLY_ALPHA_WEBGL` at upload —
42
- * lossless, and the reason the two backends differ at all on such a page.)
43
- *
44
- * Weak by the page image, exactly like the GL texture cache: this package never
45
- * pins the caller's image, and a page the caller drops takes its derivation
46
- * with it. So nothing has to be freed by hand and `dispose()` stays out of it —
47
- * the ownership boundary is the same one `revokeRegions` respects.
48
- *
49
- * **What it costs while alive:** one page-sized canvas per `pma` page image
50
- * (4 bytes/px — 1 MiB for a 1024×256 page, 16 MiB for a 2048×2048 one), held
51
- * for as long as the caller holds the page. It is deliberately *not* charged to
52
- * the cut-backing budget below: that budget bounds the canvases in flight
53
- * during a load, a peak that appears and drains, while this sits alongside the
54
- * decoded page itself for the page's whole life — the same category as the
55
- * decoded pages the budget already documents as resident throughout.
56
- */
57
- const straightAlphaPages = new WeakMap();
58
- /** Derivations performed since load — see straightAlphaDerivations(). */
59
- let derivationCount = 0;
60
- /**
61
- * How many straight-alpha page derivations have been built in this document.
62
- *
63
- * Deterministic (no GC in the path) and monotonic, so a test reads it before
64
- * and after and asserts the *difference*. Exported for the tests only — it is
65
- * not re-exported from index.ts and the `exports` map denies deep imports, so
66
- * it is not package API. (The same arrangement as `liveTextureCount` on the GL
67
- * blitter, and for the same reason: a cache that works is invisible.)
68
- */
69
- export function straightAlphaDerivations() {
70
- return derivationCount;
71
- }
72
- /**
73
- * The page as a straight-alpha source: the image itself when `pma` is false,
74
- * otherwise its (cached) un-premultiplied derivation.
75
- *
76
- * `rgb = round(rgb * 255 / a)`, clamped, with `a === 0` left at (0,0,0,0) —
77
- * there is no colour to recover from a fully transparent texel.
78
- *
79
- * **Precision.** The division is done in 8 bits and cannot be done anywhere
80
- * else: a 2D canvas stores premultiplied colour, so `getImageData` hands back
81
- * `round(round(u * a / 255) * 255 / a)` for a file value `u`, already quantized
82
- * by the read (measured on both engines: put→get moves a value by up to 127 at
83
- * a = 1). The colour a low-alpha texel composites to is therefore off by at
84
- * most ~min(a, 127.5/a + 0.5) of 255 — nothing at a = 255 or a = 0, ≤ 1 above
85
- * a = 128, worst ~12 around a = 11, and bounded by `a` below that. Writing the
86
- * values back is exact, not a second premultiply: the canvas quantizer is
87
- * idempotent, so putting a value that came out of it stores it unchanged
88
- * (measured: a second round trip moves nothing on either engine). The remaining
89
- * error is one-way rounding on near-invisible texels, against a defect that
90
- * darkened every semi-transparent texel by up to 59 luma.
91
- *
92
- * A page image that cannot be read — no 2D context, or a cross-origin image
93
- * without CORS, where `getImageData` throws — falls back to the page itself and
94
- * caches *that*: the colour is then as wrong as it is today, but it happens
95
- * once per image instead of once per frame, and no frame throws. (The cut path
96
- * already fails on such an image at `toBlob`, so only the mesh tier can get
97
- * here.) An image that has not decoded yet is left uncached, so the derivation
98
- * happens once it has.
99
- */
100
- export function straightAlphaSource(page, pma) {
101
- if (!pma)
102
- return page;
103
- const cached = straightAlphaPages.get(page);
104
- if (cached)
105
- return cached;
106
- const width = page.naturalWidth;
107
- const height = page.naturalHeight;
108
- // Nothing to read yet: decide later rather than caching an empty canvas.
109
- if (!(width > 0) || !(height > 0))
110
- return page;
111
- const derived = unpremultiply(page, width, height);
112
- straightAlphaPages.set(page, derived);
113
- if (derived !== page)
114
- derivationCount++;
115
- return derived;
116
- }
117
- /** The pixel pass behind straightAlphaSource; `page` back on any read failure. */
118
- function unpremultiply(page, width, height) {
119
- const canvas = document.createElement('canvas');
120
- canvas.width = width;
121
- canvas.height = height;
122
- // No willReadFrequently: this reads once and is then a drawImage *source*
123
- // for the rest of its life, which wants the accelerated surface.
124
- const ctx = canvas.getContext('2d');
125
- if (!ctx)
126
- return page;
127
- ctx.drawImage(page, 0, 0);
128
- let pixels;
129
- try {
130
- pixels = ctx.getImageData(0, 0, width, height);
131
- }
132
- catch {
133
- // Tainted canvas (cross-origin page image, no CORS).
134
- return page;
135
- }
136
- const data = pixels.data;
137
- for (let i = 0; i < data.length; i += 4) {
138
- const a = data[i + 3];
139
- if (a === 255)
140
- continue;
141
- if (a === 0) {
142
- // Nothing to divide by, and nothing there to see.
143
- data[i] = 0;
144
- data[i + 1] = 0;
145
- data[i + 2] = 0;
146
- continue;
147
- }
148
- const scale = 255 / a;
149
- // Rounded explicitly: assigning a fraction to a Uint8ClampedArray rounds
150
- // half-to-even, which is not the rule stated above.
151
- data[i] = Math.min(255, Math.round(data[i] * scale));
152
- data[i + 1] = Math.min(255, Math.round(data[i + 1] * scale));
153
- data[i + 2] = Math.min(255, Math.round(data[i + 2] * scale));
154
- }
155
- ctx.putImageData(pixels, 0, 0);
156
- return canvas;
157
- }
158
- /**
159
- * Backing pixels the cuts still waiting for their PNG encode may hold at once.
160
- *
161
- * A started cut keeps its canvas alive until `toBlob` calls back, so starting
162
- * every region at once peaks at Σ(cut area) of canvas backing — on top of the
163
- * decoded pages, which stay resident throughout. A cut is allocated at the
164
- * page image's own resolution, so what is charged here is that area, not the
165
- * region's atlas-unit area: a half-resolution page costs a quarter of it, an
166
- * @2x page four times it. Measured by counting the simultaneously-alive cut
167
- * canvases and their backing at `toBlob` (chromium, 1:1 pages):
168
- * the demo's 40-region 1024×256 atlas peaks at all 40 cuts and 194,742 px
169
- * (0.19 Mpx ≈ 0.74 MiB), which is nothing; a synthetic 256-region atlas on
170
- * four 2048×2048 pages peaks at 16.78 Mpx ≈ 64 MiB, which doubles that
171
- * atlas's resident cost for the length of the load.
172
- *
173
- * So the cuts are started against a budget rather than all at once. 4 Mpx is
174
- * one 2048×2048 page's worth (≈ 16 MiB at 4 bytes/px): small atlases still run
175
- * every region concurrently (spineboy: all 40, budget never engaged), and the
176
- * synthetic one runs 64 cuts at a time — 4 waves instead of 256 serial
177
- * encodes, for a quarter of the peak. A single region bigger than the budget
178
- * is started anyway when nothing else is in flight, so the budget can never
179
- * starve a cut.
180
- */
181
- const CUT_BACKING_BUDGET_PX = 4 * 1024 * 1024;
182
- /**
183
- * Locates a region on its page image.
184
- *
185
- * **The rect is read in the image's own frame, not in declared atlas pixels.**
186
- * An atlas `size:` line and the image that ships for the page need not agree:
187
- * projects export textures at half resolution (or @2x) and leave the atlas
188
- * alone. Every official Spine runtime absorbs that for free, because
189
- * spine-core turns a region's bounds into *normalized* UVs against the
190
- * declared page size (`region.u = region.x / page.width`) and a GPU samples
191
- * normalized coordinates at whatever resolution the texture happens to have.
192
- * So the rect here is the region's bounds relative to the declared page size,
193
- * times the image's natural size — the continuous `uv * size` frame both mesh
194
- * backends already address texels in. No `size - 1`, no half-texel term: this
195
- * maps a rect, it does not sample.
196
- *
197
- * With a page that does ship at its declared size the scale is exactly 1 and
198
- * every number below is the region's own integer bounds, unchanged.
199
- *
200
- * Rotation: a region packed at 90° lies on its side, so it occupies a
201
- * `height × width` rect on the page — which is how spine-core reads it too
202
- * (`u2 = (x + height) / page.width` when `degrees === 90`). The cut canvas is
203
- * the rect turned back upright, so the bitmap comes out in artwork
204
- * orientation. *Which way* back is `cutRegion`'s, derived there from the UVs
205
- * spine-core assigns such a region and not from this plan.
206
- *
207
- * Rounding: each *edge* is rounded to the nearest image pixel, rather than the
208
- * width being rounded on its own. Neighbouring regions share an edge, so
209
- * rounding the edge keeps their cuts tiling the image exactly — no gap, no
210
- * overlap, and at most half a pixel of either region's own content given up on
211
- * a boundary that falls mid-pixel. Rounding outward would instead pull a whole
212
- * neighbouring pixel into every cut on every side, which is bleed the caller
213
- * can see. A rect that scales down below one pixel still gets a 1×1 bitmap,
214
- * since a zero-sized canvas is not one.
215
- *
216
- * The alternative was measured, not argued away (#35): sampling the
217
- * *fractional* rect with interpolation — what a GPU does with normalized UVs —
218
- * buys exact placement with a resample of the whole bitmap. Both rules drew
219
- * the same frozen rigid-only pose from a rescaled page, diffed against that
220
- * pose drawn from the 1:1 page. The result is split, so the lossless copy
221
- * stays: sampling lowers the raw difference and the peak channel delta, while
222
- * rounding lowers the count of pixels with no in-tolerance match anywhere in
223
- * the reference's 3×3 — rounding displaces the picture, which a shift-tolerant
224
- * compare forgives, and sampling blurs it, which it does not. On that
225
- * shift-tolerant count at 0.5×, the common case, rounding is ahead in every
226
- * cell measured, by 1.3× to 2.2× (chromium 638 vs 1238, webkit 1443 vs 1888) —
227
- * an ordering rather than a count, since the counts themselves move with the
228
- * raster. At an integer page scale the two rules come out bit-identical, there
229
- * being no fractional part to disagree about, so an @2x page never had a
230
- * question to answer. `tests/cut-rule.spec.ts` holds the 0.5× half of this.
231
- */
232
- function planCut(region, image) {
233
- const iw = image.naturalWidth;
234
- const ih = image.naturalHeight;
235
- // A page with no `size:` line (or a malformed one) declares nothing, so the
236
- // image is taken to be its own declared size — which is what this did for
237
- // every page before the frame above existed.
238
- const pageW = region.page.width > 0 ? region.page.width : iw;
239
- const pageH = region.page.height > 0 ? region.page.height : ih;
240
- const rotated = region.degrees === 90;
241
- const packedW = rotated ? region.height : region.width;
242
- const packedH = rotated ? region.width : region.height;
243
- // Whole-page pass-through: an unrotated region covering its entire page
244
- // would be cut into a pixel-for-pixel copy of the page image, so reuse the
245
- // page URL instead — no canvas, no PNG re-encode, no second decoded copy in
246
- // memory, and nothing to revoke afterwards. Atlases written as one part per
247
- // page (the loose-part-PNG workflow, where every part is declared its own
248
- // page) hit this for every single region.
249
- //
250
- // The test is against the declared page size, at any image resolution: a
251
- // whole page is a whole page whether it ships at 1×, half or double, and the
252
- // cut would copy the image either way. (It used to be tested against the
253
- // image, which was the same rule as long as the two always agreed.)
254
- //
255
- // Except on a premultiplied page, where the page URL is exactly what must not
256
- // be handed through: those pixels are premultiplied and an <img> composites
257
- // straight alpha, so passing the URL along would ship the defect to the one
258
- // atlas shape that never even allocates a canvas (one part per page). Such a
259
- // region is cut like any other — from the straight-alpha derivation — and the
260
- // blob it mints is owned and revoked like any other.
261
- if (!region.page.pma &&
262
- !rotated &&
263
- region.x === 0 &&
264
- region.y === 0 &&
265
- packedW === pageW &&
266
- packedH === pageH) {
267
- return { passThrough: true, sx: 0, sy: 0, sw: iw, sh: ih, cw: iw, ch: ih };
268
- }
269
- const scaleX = iw / pageW;
270
- const scaleY = ih / pageH;
271
- const x0 = Math.round(region.x * scaleX);
272
- const y0 = Math.round(region.y * scaleY);
273
- const sw = Math.max(1, Math.round((region.x + packedW) * scaleX) - x0);
274
- const sh = Math.max(1, Math.round((region.y + packedH) * scaleY) - y0);
275
- return {
276
- passThrough: false,
277
- sx: x0,
278
- sy: y0,
279
- sw,
280
- sh,
281
- cw: rotated ? sh : sw,
282
- ch: rotated ? sw : sh,
283
- };
284
- }
285
- /** Backing pixels one cut allocates — the charge against the budget above. */
286
- function cutBackingPixels(region, pageImages) {
287
- const image = pageImages.get(region.page.name);
288
- // No image: this region is about to fail in the cut. Charging its atlas
289
- // units keeps the walk moving until it does.
290
- if (!image)
291
- return region.width * region.height;
292
- const plan = planCut(region, image);
293
- return plan.cw * plan.ch;
294
- }
295
- /**
296
- * One region's bitmap: the whole-page pass-through, or a cut canvas encoded to
297
- * a blob URL this module then owns.
298
- *
299
- * The cut is a **1:1 copy of the source rect** planCut located — never a
300
- * resample — so the bitmap has the native resolution of those pixels, while
301
- * the `RegionImage` sizes reported alongside it stay in atlas units. A page
302
- * shipped at half resolution therefore costs a quarter of the cut pixels and
303
- * still poses identically; upscaling the cut back to declared size would only
304
- * quadruple the pixels and add a resample.
305
- *
306
- * Everything before the `toBlob` await runs synchronously, so calling this is
307
- * what "starts" a cut: the canvas is painted and the encode is handed to the
308
- * browser before control comes back.
309
- */
310
- async function cutRegion(region, pageImages) {
311
- const image = pageImages.get(region.page.name);
312
- if (!image)
313
- throw new Error(`Missing page image: ${region.page.name}`);
314
- const w = region.width;
315
- const h = region.height;
316
- const plan = planCut(region, image);
317
- if (plan.passThrough)
318
- return { url: image.src, width: w, height: h };
319
- const canvas = document.createElement('canvas');
320
- canvas.width = plan.cw;
321
- canvas.height = plan.ch;
322
- const ctx = canvas.getContext('2d');
323
- if (!ctx)
324
- throw new Error('2d context unavailable');
325
- if (region.degrees === 90) {
326
- // The region is packed rotated. Turn the destination frame back so the
327
- // source rect, drawn at its own size, lands upright and fills the canvas —
328
- // and turn it *clockwise*, which is derived from spine-core's UVs rather
329
- // than from anything this file does.
330
- //
331
- // `TextureAtlas` takes `u`/`v` from the packed rect's top-left corner and,
332
- // at `degrees === 90`, `u2`/`v2` from `x + height` / `y + width` — the
333
- // rect's far edges. `RegionAttachment` then hands the artwork's corners out
334
- // in the rigid tier's own order, BL, UL, UR, BR, as
335
- //
336
- // BL (u2, v2) UL (u, v2) UR (u, v) BR (u2, v)
337
- //
338
- // so the artwork's top-left corner is the packed rect's *bottom-left* and
339
- // its top-right is the rect's *top-left*: the artwork's top edge runs up
340
- // the rect's left edge, which is a packer that turned it counter-clockwise.
341
- //
342
- // `translate(cw, 0); rotate(+π/2)` maps a pixel (x, y) of the source rect —
343
- // sw × sh on the page, and cw = sh, ch = sw — to canvas (cw − y, x), which
344
- // is that turn undone:
345
- //
346
- // packed bottom-left (0, sh) → (0, 0) the cut's top-left = UL
347
- // packed top-left (0, 0) → (cw, 0) the cut's top-right = UR
348
- // packed top-right (sw, 0) → (cw, ch) the cut's bottom-right = BR
349
- // packed bottom-right (sw, sh) → (0, ch) the cut's bottom-left = BL
350
- //
351
- // Until #49 this was `translate(0, ch); rotate(−π/2)`, mapping (x, y) to
352
- // (y, ch − x): a *second* counter-clockwise turn, landing the artwork's
353
- // top-left at the cut's bottom-right. The bitmap came out 180° round, and
354
- // since `renderRegion` pins a bitmap's top-left to the attachment's UL
355
- // corner either way, every rotated rigid part was drawn inverted — from the
356
- // first commit of this package to 0.7.0. The mesh tier never was: it
357
- // samples the page through the UVs above.
358
- ctx.translate(plan.cw, 0);
359
- ctx.rotate(Math.PI / 2);
360
- }
361
- // Straight alpha on a premultiplied page, since the cut is encoded to a PNG
362
- // and shown in an <img>. The rect was planned against the image, and the
363
- // derivation is that image's own size, so the coordinates carry over
364
- // unchanged — including on a page that ships at another resolution.
365
- const source = straightAlphaSource(image, region.page.pma);
366
- ctx.drawImage(source, plan.sx, plan.sy, plan.sw, plan.sh, 0, 0, plan.sw, plan.sh);
367
- const blob = await new Promise((resolve, reject) => {
368
- canvas.toBlob((b) => (b ? resolve(b) : reject(new Error('toBlob failed'))), 'image/png');
369
- });
370
- const url = URL.createObjectURL(blob);
371
- ownedUrls.add(url);
372
- return { url, width: w, height: h };
373
- }
374
- /**
375
- * Cuts every atlas region out of the page image into its own bitmap once at
376
- * load time, restoring 90° packing rotation, so the per-frame path never
377
- * touches a canvas. Returns image URLs keyed by region name.
378
- *
379
- * This is a loading-pipeline step, not a rendering step: after this runs,
380
- * rendering is pure DOM (one <img> per slot, one CSS matrix write per frame).
381
- *
382
- * A region that covers its whole page unrotated skips the cut and reuses the
383
- * page image URL — see the pass-through in planCut.
384
- *
385
- * **A page may ship at a resolution its atlas does not declare.** Half-size
386
- * texture builds and @2x variants are normal, and no option is needed for
387
- * them: a region's bounds are read relative to the declared page size and
388
- * scaled onto the image's natural size, which is exactly how spine-core
389
- * derives the UVs the mesh tier already samples with. Each bitmap comes out at
390
- * the native resolution of the pixels it was cut from, and the `RegionImage`
391
- * sizes beside it stay in atlas units, so nothing downstream has to know.
392
- *
393
- * *Behaviour change (0.5.1 → next).* An atlas whose `size:` line is simply
394
- * wrong — bounds written in image pixels under a page declared some other size
395
- * — used to be cut "as the coordinates say", because the cut read the image
396
- * directly. It is now read the way every other Spine runtime reads it:
397
- * relative to the declared size. Such an atlas rendered with a skewed mesh
398
- * tier and an intact rigid tier before; now both tiers agree, and the fix is
399
- * to correct the `size:` line.
400
- *
401
- * **The cuts run concurrently.** PNG encoding is asynchronous and the browser
402
- * does it off the main thread, so the encodes are started together and awaited
403
- * together instead of one `toBlob` per iteration: awaited in series a load
404
- * costs the *sum* of every encode, which a throttled document turns into one
405
- * full throttle period per region (measured: a single 8×8 `toBlob` took 7.5 s
406
- * to call back in a hidden desktop Chromium pane). How many run at once is
407
- * bounded by CUT_BACKING_BUDGET_PX above, not by an option.
408
- *
409
- * Concurrency changes nothing a caller can observe:
410
- *
411
- * - **Order.** The returned map is keyed in `atlas.regions` order whatever
412
- * order the blobs arrive in — the map is built after the cuts settle, from
413
- * the region list, not from the arrivals.
414
- * - **Duplicate names.** The last region of a given name in atlas order wins,
415
- * and the shadowed URL is revoked (and dropped from the ledger) rather than
416
- * stranded.
417
- * - **Failure.** Every URL this call minted is revoked before the error
418
- * propagates, *including cuts that were still in flight when the first
419
- * failure happened* — their blobs arrive later, and a load that walked away
420
- * from them would mint owned URLs nobody could ever revoke. So a failure
421
- * stops new cuts from starting but still waits for the started ones, and the
422
- * error it raises is the one from the earliest region in atlas order (what
423
- * the serial loop used to throw). Nothing here rejects unobserved.
424
- *
425
- * The blob URLs stay alive until revokeRegions() frees them — a document-wide
426
- * allocation the GC cannot reclaim on its own. Callers that load and unload
427
- * skeletons repeatedly (cutscenes, level transitions) must pair every
428
- * unpackRegions() with a revokeRegions(); a caller that loads once for the
429
- * page lifetime can ignore it.
430
- */
431
- export async function unpackRegions(atlas, pageImages) {
432
- const regions = atlas.regions;
433
- const cuts = new Array(regions.length);
434
- // The earliest-in-atlas-order failure is the one that propagates, so that a
435
- // broken atlas reports the same region whichever encode happens to land
436
- // first.
437
- let failedIndex = -1;
438
- let failure;
439
- let inFlight = [];
440
- let inFlightPixels = 0;
441
- for (let index = 0; index < regions.length && failedIndex === -1; index++) {
442
- const region = regions[index];
443
- if (!region)
444
- continue;
445
- // A pass-through allocates no canvas, but it also resolves without waiting
446
- // for anything, so charging it the page's area costs at most one drain.
447
- const pixels = cutBackingPixels(region, pageImages);
448
- while (inFlight.length > 0 && inFlightPixels + pixels > CUT_BACKING_BUDGET_PX) {
449
- await Promise.race(inFlight.map((job) => job.promise));
450
- inFlight = inFlight.filter((job) => !job.done);
451
- if (failedIndex !== -1)
452
- break;
453
- }
454
- if (failedIndex !== -1)
455
- break;
456
- inFlightPixels += pixels;
457
- const job = { done: false, promise: Promise.resolve() };
458
- // Jobs settle, they never reject: the failure is recorded here so that
459
- // nothing is left for an unhandled-rejection handler to find.
460
- job.promise = (async () => {
461
- try {
462
- cuts[index] = await cutRegion(region, pageImages);
463
- }
464
- catch (error) {
465
- if (failedIndex === -1 || index < failedIndex) {
466
- failedIndex = index;
467
- failure = error;
468
- }
469
- }
470
- finally {
471
- inFlightPixels -= pixels;
472
- job.done = true;
473
- }
474
- })();
475
- inFlight.push(job);
476
- }
477
- // Every cut this call started is settled after this, so the cleanup below
478
- // reaches the blobs that arrived after the first failure too.
479
- await Promise.all(inFlight.map((job) => job.promise));
480
- if (failedIndex !== -1) {
481
- for (const cut of cuts)
482
- if (cut)
483
- revokeOwned(cut.url);
484
- throw failure;
485
- }
486
- const result = new Map();
487
- for (let index = 0; index < regions.length; index++) {
488
- const region = regions[index];
489
- const cut = cuts[index];
490
- if (!region || !cut)
491
- continue;
492
- // Duplicate region names would otherwise strand the shadowed URL in the
493
- // ledger with nothing left pointing at it. Map.set keeps the key where it
494
- // first appeared, so atlas order survives the overwrite.
495
- const shadowed = result.get(region.name);
496
- if (shadowed)
497
- revokeOwned(shadowed.url);
498
- result.set(region.name, cut);
499
- }
500
- return result;
501
- }
502
- /**
503
- * Frees the blob URLs unpackRegions minted for `images` — the counterpart of
504
- * unpackRegions, to call once the skeletons using them are gone (after
505
- * `renderer.dispose()`, since a live <img> would keep pointing at a dead URL).
506
- *
507
- * Only URLs this module created are revoked: entries the caller supplied
508
- * itself (a hand-built map of loose part PNGs) and page images reused
509
- * verbatim by the whole-page pass-through are left alone. Idempotent —
510
- * revoking twice is a no-op, so it is safe on a map that is shared or
511
- * partially reused.
512
- *
513
- * The map keeps its entries; drop the reference (or reload) afterwards, since
514
- * the URLs no longer resolve.
515
- */
516
- export function revokeRegions(images) {
517
- for (const image of images.values())
518
- revokeOwned(image.url);
519
- }
520
- //# sourceMappingURL=DomTexture.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"DomTexture.js","sourceRoot":"","sources":["../src/DomTexture.ts"],"names":[],"mappings":"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"}