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.
- package/NOTICE.md +50 -23
- package/README.md +511 -456
- package/dist/CanvasRenderer.d.ts +139 -0
- package/dist/CanvasRenderer.d.ts.map +1 -0
- package/dist/{SpineHtmlRenderer.d.ts → DomRenderer.d.ts} +70 -65
- package/dist/DomRenderer.d.ts.map +1 -0
- package/dist/DomTexture.d.ts +34 -14
- package/dist/DomTexture.d.ts.map +1 -1
- package/dist/MeshGlBlitter.d.ts +67 -1
- package/dist/MeshGlBlitter.d.ts.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7470 -5
- package/dist/index.js.map +1 -1
- package/dist/loadModel.d.ts +92 -0
- package/dist/loadModel.d.ts.map +1 -0
- package/dist/player.d.ts +198 -0
- package/dist/player.d.ts.map +1 -0
- package/dist/posedFrame.d.ts +99 -0
- package/dist/posedFrame.d.ts.map +1 -0
- package/package.json +13 -19
- package/dist/DomTexture.js +0 -520
- package/dist/DomTexture.js.map +0 -1
- package/dist/MeshGlBlitter.js +0 -365
- package/dist/MeshGlBlitter.js.map +0 -1
- package/dist/SpineHtmlRenderer.d.ts.map +0 -1
- package/dist/SpineHtmlRenderer.js +0 -1107
- package/dist/SpineHtmlRenderer.js.map +0 -1
- package/dist/binary.d.ts +0 -48
- package/dist/binary.d.ts.map +0 -1
- package/dist/binary.js +0 -29
- package/dist/binary.js.map +0 -1
- package/dist/coreCompat.d.ts +0 -153
- package/dist/coreCompat.d.ts.map +0 -1
- package/dist/coreCompat.js +0 -136
- package/dist/coreCompat.js.map +0 -1
- package/dist/loadAtlasAssets.d.ts +0 -73
- package/dist/loadAtlasAssets.d.ts.map +0 -1
- package/dist/loadAtlasAssets.js +0 -75
- package/dist/loadAtlasAssets.js.map +0 -1
- package/dist/loadSkeletonAssets.d.ts +0 -88
- package/dist/loadSkeletonAssets.d.ts.map +0 -1
- package/dist/loadSkeletonAssets.js +0 -79
- package/dist/loadSkeletonAssets.js.map +0 -1
package/dist/DomTexture.js
DELETED
|
@@ -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
|
package/dist/DomTexture.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DomTexture.js","sourceRoot":"","sources":["../src/DomTexture.ts"],"names":[],"mappings":"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"}
|