@swf2es/native 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 +202 -0
- package/LICENSE.third-party +313 -0
- package/README.md +489 -2
- package/dist/atf/binary.d.ts +2 -0
- package/dist/atf/binary.d.ts.map +1 -0
- package/dist/atf/binary.js +4 -0
- package/dist/atf/binary.js.map +1 -0
- package/dist/atf/index.d.ts +27 -0
- package/dist/atf/index.d.ts.map +1 -0
- package/dist/atf/index.js +158 -0
- package/dist/atf/index.js.map +1 -0
- package/dist/atf/jxr.d.ts +22 -0
- package/dist/atf/jxr.d.ts.map +1 -0
- package/dist/atf/jxr.js +60 -0
- package/dist/atf/jxr.js.map +1 -0
- package/dist/atf/parse.d.ts +65 -0
- package/dist/atf/parse.d.ts.map +1 -0
- package/dist/atf/parse.js +204 -0
- package/dist/atf/parse.js.map +1 -0
- package/dist/audio/binary.d.ts +2 -0
- package/dist/audio/binary.d.ts.map +1 -0
- package/dist/audio/binary.js +4 -0
- package/dist/audio/binary.js.map +1 -0
- package/dist/audio/index.d.ts +21 -0
- package/dist/audio/index.d.ts.map +1 -0
- package/dist/audio/index.js +73 -0
- package/dist/audio/index.js.map +1 -0
- package/dist/base64.d.ts +3 -0
- package/dist/base64.d.ts.map +1 -0
- package/dist/base64.js +10 -0
- package/dist/base64.js.map +1 -0
- package/dist/compress/binary.d.ts +2 -0
- package/dist/compress/binary.d.ts.map +1 -0
- package/dist/compress/binary.js +4 -0
- package/dist/compress/binary.js.map +1 -0
- package/dist/compress/index.d.ts +59 -0
- package/dist/compress/index.d.ts.map +1 -0
- package/dist/compress/index.js +146 -0
- package/dist/compress/index.js.map +1 -0
- package/dist/instance.d.ts +25 -0
- package/dist/instance.d.ts.map +1 -0
- package/dist/instance.js +50 -0
- package/dist/instance.js.map +1 -0
- package/dist/mp3/binary.d.ts +2 -0
- package/dist/mp3/binary.d.ts.map +1 -0
- package/dist/mp3/binary.js +4 -0
- package/dist/mp3/binary.js.map +1 -0
- package/dist/mp3/index.d.ts +20 -0
- package/dist/mp3/index.d.ts.map +1 -0
- package/dist/mp3/index.js +49 -0
- package/dist/mp3/index.js.map +1 -0
- package/dist/render/binary.d.ts +2 -0
- package/dist/render/binary.d.ts.map +1 -0
- package/dist/render/binary.js +4 -0
- package/dist/render/binary.js.map +1 -0
- package/dist/render/bitmap-kernel.d.ts +118 -0
- package/dist/render/bitmap-kernel.d.ts.map +1 -0
- package/dist/render/bitmap-kernel.js +592 -0
- package/dist/render/bitmap-kernel.js.map +1 -0
- package/dist/render/draw-kernel.d.ts +79 -0
- package/dist/render/draw-kernel.d.ts.map +1 -0
- package/dist/render/draw-kernel.js +205 -0
- package/dist/render/draw-kernel.js.map +1 -0
- package/dist/render/dxt-encoder.d.ts +19 -0
- package/dist/render/dxt-encoder.d.ts.map +1 -0
- package/dist/render/dxt-encoder.js +95 -0
- package/dist/render/dxt-encoder.js.map +1 -0
- package/dist/render/index.d.ts +6 -0
- package/dist/render/index.d.ts.map +1 -0
- package/dist/render/index.js +11 -0
- package/dist/render/index.js.map +1 -0
- package/dist/render/lines.d.ts +55 -0
- package/dist/render/lines.d.ts.map +1 -0
- package/dist/render/lines.js +123 -0
- package/dist/render/lines.js.map +1 -0
- package/dist/render/module.d.ts +11 -0
- package/dist/render/module.d.ts.map +1 -0
- package/dist/render/module.js +27 -0
- package/dist/render/module.js.map +1 -0
- package/dist/render/pixel-ops.d.ts +77 -0
- package/dist/render/pixel-ops.d.ts.map +1 -0
- package/dist/render/pixel-ops.js +236 -0
- package/dist/render/pixel-ops.js.map +1 -0
- package/dist/render/tessellator.d.ts +90 -0
- package/dist/render/tessellator.d.ts.map +1 -0
- package/dist/render/tessellator.js +251 -0
- package/dist/render/tessellator.js.map +1 -0
- package/package.json +53 -3
- package/src/atf/index.ts +212 -0
- package/src/atf/jxr.ts +83 -0
- package/src/atf/parse.ts +263 -0
- package/src/audio/index.ts +93 -0
- package/src/base64.ts +10 -0
- package/src/compress/index.ts +225 -0
- package/src/instance.ts +53 -0
- package/src/mp3/index.ts +71 -0
- package/src/render/bitmap-kernel.ts +856 -0
- package/src/render/draw-kernel.ts +268 -0
- package/src/render/dxt-encoder.ts +121 -0
- package/src/render/index.ts +37 -0
- package/src/render/lines.ts +161 -0
- package/src/render/module.ts +30 -0
- package/src/render/pixel-ops.ts +356 -0
- package/src/render/tessellator.ts +367 -0
- package/src/webassembly.d.ts +22 -0
|
@@ -0,0 +1,367 @@
|
|
|
1
|
+
import { LineBuilder } from "./lines.js";
|
|
2
|
+
import { renderInstance, renderModule } from "./module.js";
|
|
3
|
+
|
|
4
|
+
/** Buffers are owned by the caller; subsequent calls and disposal cannot change them. */
|
|
5
|
+
export interface FillGeometry {
|
|
6
|
+
vertices: Float64Array;
|
|
7
|
+
indices: Uint16Array | Uint32Array;
|
|
8
|
+
/**
|
|
9
|
+
* The vertex the indices count from: a layer's fills share its indices,
|
|
10
|
+
* each counted from the layer's first vertex (Tessellator.tessellate.layer).
|
|
11
|
+
*/
|
|
12
|
+
indexOffset?: number;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** A fill tessellated alone, and with the rest of its layer. */
|
|
16
|
+
export interface FillTessellate {
|
|
17
|
+
(contours: readonly (readonly number[])[], nonZero: boolean): FillGeometry | null;
|
|
18
|
+
/**
|
|
19
|
+
* Every fill of a layer in one native call, its contours as path
|
|
20
|
+
* commands (PATH_MOVE, PATH_LINE, PATH_CURVE, PATH_CUBIC) that the module
|
|
21
|
+
* flattens itself: each fill's geometry, or null for one it refused, all
|
|
22
|
+
* fills' positions and indices in one buffer each. Its output needs no checking: the module has checked
|
|
23
|
+
* every coordinate finite and every index in range.
|
|
24
|
+
*/
|
|
25
|
+
layer(
|
|
26
|
+
fills: readonly (readonly (readonly number[])[])[],
|
|
27
|
+
nonZero: readonly boolean[],
|
|
28
|
+
): (FillGeometry | null)[] | null;
|
|
29
|
+
/** A layer's lines in one call, their outlines filled by the same libtess2 (LineBuilder). */
|
|
30
|
+
lines: LineBuilder;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* The commands of a contour layer() takes, each followed by its
|
|
35
|
+
* coordinates: MOVE x y and LINE x y; CURVE cx cy x y, a quadratic from
|
|
36
|
+
* the pen; CUBIC c1x c1y c2x c2y x y. The pen starts each contour at 0, 0.
|
|
37
|
+
* Curves are flattened to within 0.02 of the curve, in at most 256 chords;
|
|
38
|
+
* repeated points are dropped, and contours of fewer than three points left out.
|
|
39
|
+
*/
|
|
40
|
+
export const PATH_MOVE = 1;
|
|
41
|
+
export const PATH_LINE = 2;
|
|
42
|
+
export const PATH_CURVE = 3;
|
|
43
|
+
export const PATH_CUBIC = 4;
|
|
44
|
+
|
|
45
|
+
interface NativeExports {
|
|
46
|
+
memory: WebAssembly.Memory;
|
|
47
|
+
reset(): void;
|
|
48
|
+
alloc(n: number): number;
|
|
49
|
+
run(coords: number, count: number, ends: number, contours: number, nonzero: number): number;
|
|
50
|
+
layer(
|
|
51
|
+
commands: number,
|
|
52
|
+
length: number,
|
|
53
|
+
ends: number,
|
|
54
|
+
contours: number,
|
|
55
|
+
fills: number,
|
|
56
|
+
rules: number,
|
|
57
|
+
count: number,
|
|
58
|
+
): number;
|
|
59
|
+
vertices(): number;
|
|
60
|
+
indices(): number;
|
|
61
|
+
vertexCount(): number;
|
|
62
|
+
triangleCount(): number;
|
|
63
|
+
highWater(): number;
|
|
64
|
+
setLimit(n: number): void;
|
|
65
|
+
bandsOnly(on: number): void;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface TessellatorOptions {
|
|
69
|
+
/** Maximum arena address, including the C stack; at most 128 MiB. */
|
|
70
|
+
memoryLimit?: number;
|
|
71
|
+
/** Drop instances larger than this after each call. Defaults to 8 MiB. */
|
|
72
|
+
retainMemory?: number;
|
|
73
|
+
/**
|
|
74
|
+
* Fill by the module's bands alone (bands.zig), as it does after libtess2
|
|
75
|
+
* has trapped, never by libtess2, the lines' outlines too: for tests of
|
|
76
|
+
* the bands.
|
|
77
|
+
*/
|
|
78
|
+
bands?: boolean;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** What root.zig takes of one fill; it rejects more too. */
|
|
82
|
+
const MOST_CONTOURS = 100000;
|
|
83
|
+
const MOST_POINTS = 1000000;
|
|
84
|
+
/** A rule root.zig rejects, for a fill whose arrays already show it would reject them. */
|
|
85
|
+
const REJECTED = 2;
|
|
86
|
+
/** The Int32s of root.zig's Layer, and of each fill's Range after it. */
|
|
87
|
+
const LAYER = 5;
|
|
88
|
+
const RANGE = 5;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Synchronous double-precision tessellator. It compiles the render module
|
|
92
|
+
* as it is made, and throws where the host refuses it. A fill it refuses
|
|
93
|
+
* (not finite, malformed, too large, or out of memory) is null.
|
|
94
|
+
*/
|
|
95
|
+
export class Tessellator {
|
|
96
|
+
private instance: NativeExports | null = null;
|
|
97
|
+
private readonly limit: number;
|
|
98
|
+
private readonly keep: number;
|
|
99
|
+
private readonly bands: boolean;
|
|
100
|
+
private readonly lines: LineBuilder;
|
|
101
|
+
|
|
102
|
+
constructor(options: TessellatorOptions = {}) {
|
|
103
|
+
this.limit = options.memoryLimit ?? 128 << 20;
|
|
104
|
+
this.keep = options.retainMemory ?? 8 << 20;
|
|
105
|
+
this.bands = options.bands ?? false;
|
|
106
|
+
if (
|
|
107
|
+
!Number.isInteger(this.limit) ||
|
|
108
|
+
this.limit < 0 ||
|
|
109
|
+
this.limit > 128 << 20 ||
|
|
110
|
+
!Number.isInteger(this.keep) ||
|
|
111
|
+
this.keep < 0 ||
|
|
112
|
+
this.keep > 128 << 20
|
|
113
|
+
) {
|
|
114
|
+
throw new RangeError("invalid tessellator memory limit");
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
renderModule();
|
|
118
|
+
this.lines = new LineBuilder({
|
|
119
|
+
memoryLimit: this.limit,
|
|
120
|
+
retainMemory: this.keep,
|
|
121
|
+
bands: this.bands,
|
|
122
|
+
});
|
|
123
|
+
this.tessellate = Object.assign(this.fill, { layer: this.layer, lines: this.lines });
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* Current retained Wasm capacity, the line builder's included. Arena reset
|
|
128
|
+
* alone does not shrink this memory.
|
|
129
|
+
*/
|
|
130
|
+
get capacity(): number {
|
|
131
|
+
return (this.instance?.memory.buffer.byteLength ?? 0) + this.lines.capacity;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
dispose(): void {
|
|
135
|
+
this.instance = null;
|
|
136
|
+
this.lines.dispose();
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** The instance, made on first use, its arena reset; filling by the bands alone where `bands`. */
|
|
140
|
+
private arena(bands: boolean): NativeExports {
|
|
141
|
+
this.instance ??= renderInstance(() => {
|
|
142
|
+
throw new Error("tessellation allocation failed");
|
|
143
|
+
}) as unknown as NativeExports;
|
|
144
|
+
const x = this.instance;
|
|
145
|
+
x.reset();
|
|
146
|
+
x.setLimit(this.limit);
|
|
147
|
+
x.bandsOnly(Number(bands));
|
|
148
|
+
return x;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/** A call that threw: a trapped instance is never used again. */
|
|
152
|
+
private failed(): void {
|
|
153
|
+
// In particular, longjmp unwinds through a throwing import: never resume that C instance. The
|
|
154
|
+
// line builder's instance is its own.
|
|
155
|
+
this.instance = null;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** An instance grown past what is kept, let go. */
|
|
159
|
+
private trim(): void {
|
|
160
|
+
if ((this.instance?.memory.buffer.byteLength ?? 0) > this.keep) {
|
|
161
|
+
this.instance = null;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** One fill. The module checks the coordinates; only the arrays' lengths are looked at here. */
|
|
166
|
+
private readonly fill = (
|
|
167
|
+
contours: readonly (readonly number[])[],
|
|
168
|
+
nonZero: boolean,
|
|
169
|
+
): FillGeometry | null => this.fillBy(contours, nonZero, this.bands);
|
|
170
|
+
|
|
171
|
+
/** One fill, by the bands alone where `bands`; again so in a new instance where libtess2 trapped. */
|
|
172
|
+
private fillBy(
|
|
173
|
+
contours: readonly (readonly number[])[],
|
|
174
|
+
nonZero: boolean,
|
|
175
|
+
bands: boolean,
|
|
176
|
+
): FillGeometry | null {
|
|
177
|
+
if (contours.length > MOST_CONTOURS) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
let count = 0;
|
|
182
|
+
for (const points of contours) {
|
|
183
|
+
if (points.length % 2 !== 0) {
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
count += points.length / 2;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (count > MOST_POINTS) {
|
|
191
|
+
return null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (count === 0) {
|
|
195
|
+
return { vertices: new Float64Array(), indices: new Uint16Array() };
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
try {
|
|
199
|
+
const x = this.arena(bands);
|
|
200
|
+
// One allocation: coordinates, then contours' ends.
|
|
201
|
+
const coordAt = x.alloc(count * 16 + contours.length * 4);
|
|
202
|
+
if (!coordAt) {
|
|
203
|
+
throw new Error("tessellation input allocation failed");
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const endsAt = coordAt + count * 16;
|
|
207
|
+
|
|
208
|
+
const coords = new Float64Array(x.memory.buffer, coordAt, count * 2);
|
|
209
|
+
const ends = new Uint32Array(x.memory.buffer, endsAt, contours.length);
|
|
210
|
+
let at = 0;
|
|
211
|
+
for (let i = 0; i < contours.length; i++) {
|
|
212
|
+
coords.set(contours[i], at);
|
|
213
|
+
at += contours[i].length;
|
|
214
|
+
ends[i] = at / 2;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (x.run(coordAt, count, endsAt, contours.length, Number(nonZero)) !== 0) {
|
|
218
|
+
return null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Growth can detach the input views. Cached geometry owns fresh copies of the final views.
|
|
222
|
+
const vertices = new Float64Array(x.memory.buffer, x.vertices(), x.vertexCount() * 2).slice();
|
|
223
|
+
const source = new Uint32Array(x.memory.buffer, x.indices(), x.triangleCount() * 3);
|
|
224
|
+
const indices = vertices.length / 2 <= 0x10000 ? new Uint16Array(source) : source.slice();
|
|
225
|
+
|
|
226
|
+
return { vertices, indices };
|
|
227
|
+
} catch {
|
|
228
|
+
this.failed();
|
|
229
|
+
return bands ? null : this.fillBy(contours, nonZero, true);
|
|
230
|
+
} finally {
|
|
231
|
+
this.trim();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** Each fill flattened and tessellated, as `fill` would make its polygons, in one call and one copy out. */
|
|
236
|
+
private readonly layer = (
|
|
237
|
+
fills: readonly (readonly (readonly number[])[])[],
|
|
238
|
+
nonZero: readonly boolean[],
|
|
239
|
+
): (FillGeometry | null)[] | null => this.layerBy(fills, nonZero, this.bands);
|
|
240
|
+
|
|
241
|
+
/** The layer, by the bands alone where `bands`; again so in a new instance where libtess2 trapped. */
|
|
242
|
+
private layerBy(
|
|
243
|
+
fills: readonly (readonly (readonly number[])[])[],
|
|
244
|
+
nonZero: readonly boolean[],
|
|
245
|
+
bands: boolean,
|
|
246
|
+
): (FillGeometry | null)[] | null {
|
|
247
|
+
let length = 0;
|
|
248
|
+
let contours = 0;
|
|
249
|
+
const rules = new Uint8Array(fills.length);
|
|
250
|
+
for (let i = 0; i < fills.length; i++) {
|
|
251
|
+
const fill = fills[i];
|
|
252
|
+
if (fill.length > MOST_CONTOURS) {
|
|
253
|
+
rules[i] = REJECTED;
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
for (let j = 0; j < fill.length; j++) {
|
|
258
|
+
length += fill[j].length;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
rules[i] = Number(nonZero[i]);
|
|
262
|
+
contours += fill.length;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
let ranges: Int32Array;
|
|
266
|
+
let vertices: Float64Array;
|
|
267
|
+
let indices: Uint16Array | Uint32Array;
|
|
268
|
+
try {
|
|
269
|
+
// One allocation: commands, contours' ends, each fill's last contour, then rules.
|
|
270
|
+
const x = this.arena(bands);
|
|
271
|
+
const commandAt = x.alloc(length * 8 + contours * 4 + fills.length * 5);
|
|
272
|
+
if (!commandAt) {
|
|
273
|
+
throw new Error("tessellation input allocation failed");
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const endsAt = commandAt + length * 8;
|
|
277
|
+
const fillsAt = endsAt + contours * 4;
|
|
278
|
+
const rulesAt = fillsAt + fills.length * 4;
|
|
279
|
+
|
|
280
|
+
const commands = new Float64Array(x.memory.buffer, commandAt, length);
|
|
281
|
+
const ends = new Uint32Array(x.memory.buffer, endsAt, contours);
|
|
282
|
+
const lasts = new Uint32Array(x.memory.buffer, fillsAt, fills.length);
|
|
283
|
+
new Uint8Array(x.memory.buffer, rulesAt, fills.length).set(rules);
|
|
284
|
+
let at = 0;
|
|
285
|
+
let contour = 0;
|
|
286
|
+
for (let i = 0; i < fills.length; i++) {
|
|
287
|
+
if (rules[i] !== REJECTED) {
|
|
288
|
+
const fill = fills[i];
|
|
289
|
+
for (let j = 0; j < fill.length; j++) {
|
|
290
|
+
commands.set(fill[j], at);
|
|
291
|
+
at += fill[j].length;
|
|
292
|
+
ends[contour++] = at;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
lasts[i] = contour;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const head = x.layer(commandAt, length, endsAt, contours, fillsAt, rulesAt, fills.length);
|
|
300
|
+
if (head === 0) {
|
|
301
|
+
// The layer's own output did not fit: a call a fill.
|
|
302
|
+
return fills.length === 1
|
|
303
|
+
? [null]
|
|
304
|
+
: fills.map((fill, i) => this.alone(fill, nonZero[i], bands));
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
// The one copy out, its ranges read before a retry resets the arena.
|
|
308
|
+
const buffer = x.memory.buffer;
|
|
309
|
+
ranges = new Int32Array(buffer, head, LAYER + fills.length * RANGE).slice();
|
|
310
|
+
vertices = new Float64Array(buffer, ranges[0], ranges[2] * 2).slice();
|
|
311
|
+
indices =
|
|
312
|
+
ranges[4] === 2
|
|
313
|
+
? new Uint16Array(buffer, ranges[1], ranges[3]).slice()
|
|
314
|
+
: new Uint32Array(buffer, ranges[1], ranges[3]).slice();
|
|
315
|
+
} catch {
|
|
316
|
+
this.failed();
|
|
317
|
+
if (bands) {
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// libtess2 trapped: each fill in a fresh instance, and one that traps alone again by the
|
|
322
|
+
// bands, which never trap.
|
|
323
|
+
return fills.length === 1
|
|
324
|
+
? this.layerBy(fills, nonZero, true)
|
|
325
|
+
: fills.map((fill, i) => this.alone(fill, nonZero[i], false));
|
|
326
|
+
} finally {
|
|
327
|
+
this.trim();
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
const out: (FillGeometry | null)[] = new Array(fills.length);
|
|
331
|
+
for (let i = 0; i < fills.length; i++) {
|
|
332
|
+
const range = LAYER + i * RANGE;
|
|
333
|
+
const status = ranges[range];
|
|
334
|
+
if (status === 0) {
|
|
335
|
+
const vertexStart = ranges[range + 1];
|
|
336
|
+
const indexStart = ranges[range + 3];
|
|
337
|
+
out[i] = {
|
|
338
|
+
vertices: vertices.subarray(vertexStart * 2, (vertexStart + ranges[range + 2]) * 2),
|
|
339
|
+
indices: indices.subarray(indexStart, indexStart + ranges[range + 4]),
|
|
340
|
+
indexOffset: vertexStart,
|
|
341
|
+
};
|
|
342
|
+
} else {
|
|
343
|
+
// Running out may be the layer's memory, where the fill alone fits.
|
|
344
|
+
out[i] = status === -1 && fills.length > 1 ? this.alone(fills[i], nonZero[i], bands) : null;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
return out;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/** One fill's commands as a layer of its own, in a fresh arena. */
|
|
352
|
+
private alone(
|
|
353
|
+
contours: readonly (readonly number[])[],
|
|
354
|
+
nonZero: boolean,
|
|
355
|
+
bands: boolean,
|
|
356
|
+
): FillGeometry | null {
|
|
357
|
+
const geometry = this.layerBy([contours], [nonZero], bands)?.[0] ?? null;
|
|
358
|
+
return geometry && { vertices: geometry.vertices, indices: geometry.indices };
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Use as RenderView's fillTessellator. A fill alone takes its contours
|
|
363
|
+
* flattened already; a layer takes them as path commands; and a layer's
|
|
364
|
+
* lines take the layer as the player packs it (`lines`).
|
|
365
|
+
*/
|
|
366
|
+
readonly tessellate: FillTessellate;
|
|
367
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// ES2022 has no WebAssembly types or atob, and this package loads neither
|
|
2
|
+
// DOM nor node types, as format, which uses it, does not. These are the
|
|
3
|
+
// parts the wrappers use; browsers and node both have them.
|
|
4
|
+
declare namespace WebAssembly {
|
|
5
|
+
// biome-ignore lint/suspicious/noEmptyInterface: an opaque handle, like the real Module type
|
|
6
|
+
interface Module {}
|
|
7
|
+
var Module: {
|
|
8
|
+
new (bytes: ArrayBufferView | ArrayBuffer): Module;
|
|
9
|
+
};
|
|
10
|
+
interface Memory {
|
|
11
|
+
readonly buffer: ArrayBuffer;
|
|
12
|
+
}
|
|
13
|
+
interface Instance {
|
|
14
|
+
readonly exports: Record<string, unknown>;
|
|
15
|
+
}
|
|
16
|
+
var Instance: {
|
|
17
|
+
new (module: Module, imports?: object): Instance;
|
|
18
|
+
};
|
|
19
|
+
function compile(bytes: ArrayBufferView | ArrayBuffer): Promise<Module>;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
declare function atob(data: string): string;
|