@weasel-js/core 1.4.3 → 1.4.4
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/CHANGELOG.md +367 -0
- package/dist/{pointSnapToGrid-D1bRdq-j.d.ts → autoPoseDescriptor-DF1SnnSx.d.ts} +18 -3
- package/dist/{builtins-CtGORLCG.d.ts → builtins-BXFBXegF.d.ts} +200 -100
- package/dist/{chunk-ORZNKVXM.js → chunk-2VXGHUVL.js} +3 -3
- package/dist/{chunk-ORZNKVXM.js.map → chunk-2VXGHUVL.js.map} +1 -1
- package/dist/{chunk-LEURURX3.js → chunk-BL65SHCX.js} +17 -5
- package/dist/chunk-BL65SHCX.js.map +1 -0
- package/dist/{chunk-BLJNRMKB.js → chunk-PRGBGMH3.js} +3 -3
- package/dist/{chunk-BLJNRMKB.js.map → chunk-PRGBGMH3.js.map} +1 -1
- package/dist/{chunk-WYPSGIYS.js → chunk-R3AWPTLZ.js} +1773 -1209
- package/dist/chunk-R3AWPTLZ.js.map +1 -0
- package/dist/{chunk-SBFC6J3C.js → chunk-WPM42WJP.js} +3 -3
- package/dist/{chunk-SBFC6J3C.js.map → chunk-WPM42WJP.js.map} +1 -1
- package/dist/clipboard.d.ts +2 -2
- package/dist/clone.d.ts +2 -2
- package/dist/{geometry-CHR36Ub_.d.ts → geometry-6fCNhAux.d.ts} +1 -1
- package/dist/{grid-Bw8cSde-.d.ts → grid-0Pbn5B2C.d.ts} +1 -14
- package/dist/index.d.ts +231 -74
- package/dist/index.js +5 -5
- package/dist/insert.d.ts +3 -3
- package/dist/insert.js +1 -1
- package/dist/move.d.ts +4 -4
- package/dist/move.js +2 -2
- package/dist/{options-DYfUlZxk.d.ts → options-DbYLImvq.d.ts} +1 -1
- package/dist/{registry-DnoTWGED.d.ts → registry-BY-wI9gm.d.ts} +4 -4
- package/dist/renderer.d.ts +2 -2
- package/dist/renderer.js +5 -5
- package/dist/resize.d.ts +5 -4
- package/dist/resize.js +2 -2
- package/dist/routing.d.ts +5 -5
- package/dist/routing.js +1 -1
- package/dist/{types-CoVTbo_y.d.ts → types-DEALFt5F.d.ts} +1 -6
- package/dist/{types-H7o6MaPo.d.ts → types-bcc7jcUy.d.ts} +96 -14
- package/dist/{types-BJqsTlXl.d.ts → types-ei3UMl9R.d.ts} +1 -1
- package/package.json +9 -9
- package/dist/chunk-LEURURX3.js.map +0 -1
- package/dist/chunk-WYPSGIYS.js.map +0 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { ActionDisabledReason, useOptionalDepRegistry, DepRegistryProvider, useActionsRegistry, ActionsScope, ActionsProvider, useDepRegistry, reportRouteConflicts, buildDepsFromRequires, useDepSource, actionBindings } from './chunk-
|
|
2
|
-
import { scratchKey, createReparentOp, createTransformOp, snap, getScratch, setScratch } from './chunk-
|
|
3
|
-
import { fixedCornerOf, DEFAULT_RESIZE_BEHAVIORS, CORNER_ANCHORS, cornerPoint } from './chunk-
|
|
4
|
-
import { AUTO_POSE_DESCRIPTOR, remapRotatedLeaf, PATH_Z, PATH_Q, PATH_C, PATH_L, PATH_M, resolveUnit, polylineFromPoints, starPath, regularPolygonPath, linePath, ellipsePath, rectPath, polygonFromPoints, RECT_POSE_DESCRIPTOR, PathBuilder, pathPoseDescriptor, withinPxRadius, boundsOfPath, DEFAULT_FLATTEN_TOLERANCE, flattenQuadratic, flattenCubic, pointInPath, strokeHitTest, transformPath, translatePath, pxExtent, withinPxBox, flattenCubicWithArcLen, flattenQuadraticWithArcLen, PATH_CMD_LENGTHS, pointToGridCell } from './chunk-
|
|
1
|
+
import { ActionDisabledReason, useOptionalDepRegistry, DepRegistryProvider, useActionsRegistry, ActionsScope, ActionsProvider, useDepRegistry, reportRouteConflicts, buildDepsFromRequires, useDepSource, actionBindings } from './chunk-BL65SHCX.js';
|
|
2
|
+
import { scratchKey, createReparentOp, createTransformOp, snap, getScratch, setScratch } from './chunk-2VXGHUVL.js';
|
|
3
|
+
import { fixedCornerOf, DEFAULT_RESIZE_BEHAVIORS, CORNER_ANCHORS, cornerPoint } from './chunk-PRGBGMH3.js';
|
|
4
|
+
import { AUTO_POSE_DESCRIPTOR, remapRotatedLeaf, PATH_Z, PATH_Q, PATH_C, PATH_L, PATH_M, resolveUnit, polylineFromPoints, starPath, regularPolygonPath, linePath, ellipsePath, rectPath, polygonFromPoints, RECT_POSE_DESCRIPTOR, PathBuilder, pathPoseDescriptor, withinPxRadius, boundsOfPath, DEFAULT_FLATTEN_TOLERANCE, flattenQuadratic, flattenCubic, pointInPath, strokeHitTest, transformPath, translatePath, pxExtent, withinPxBox, flattenCubicWithArcLen, flattenQuadraticWithArcLen, PATH_CMD_LENGTHS, pointToGridCell } from './chunk-WPM42WJP.js';
|
|
5
5
|
import { dispatchApplyBatch, dlog, dwarn, usePointerContext, PointerContextProvider, extractWeaselClipboardFromSvg, parseWeaselClipboardText, materializePaste, WEASEL_CLIPBOARD_MIME, WEASEL_CLIPBOARD_MIME_WEB, sniffWeaselClipboardText, applyOpsTo } from './chunk-T3UQ3F6R.js';
|
|
6
6
|
import { createSetSelectionOp } from './chunk-DOBSZOPR.js';
|
|
7
7
|
import { registerOpFactory, createInsertOp, createDeleteOp, rebuildOp } from './chunk-4RJP2N2L.js';
|
|
8
8
|
import { getTexture, chunks, dots, crosshatch, hatch } from './chunk-BJN5ZRIJ.js';
|
|
9
9
|
import { createContext, createElement, forwardRef, useMemo, useRef, useCallback, useState, useEffect, useImperativeHandle, useSyncExternalStore, useLayoutEffect, useContext, useId, useReducer } from 'react';
|
|
10
|
-
import { subscribeGlyphReady, DEFAULT_BAKE_BUDGET,
|
|
10
|
+
import { GLYPH_COVERAGE_GLSL, subscribeGlyphReady, DEFAULT_BAKE_BUDGET, markAllFontsNotUploaded, resetBakeBudget, syncDynamicPageTexture, ensureFontTexture, dynamicPageTextureId, textureCacheKey, GLYPH_MODE_R8, GLYPH_MODE_MSDF } from '@weasel-js/font';
|
|
11
11
|
export { canQueryLocalFonts, canQueryLocalFonts as canQueryLocalFonts2, enableLocalFontOutlines, enableLocalFontOutlines as enableLocalFontOutlines2, hasFontOutlines, hasFontOutlines as hasFontOutlines2, isCanvasFont, isCanvasFont as isCanvasFont2, listFontOutlines, listFontOutlines as listFontOutlines2, outlineStatus, outlineStatus as outlineStatus2, registerCanvasFont, registerCanvasFont as registerCanvasFont2, registerFont, registerFont as registerFont2, registerFontOutlines, registerFontOutlines as registerFontOutlines2, subscribeGlyphReady, subscribeGlyphReady as subscribeGlyphReady2, unregisterCanvasFont, unregisterCanvasFont as unregisterCanvasFont2, unregisterFontOutlines, unregisterFontOutlines as unregisterFontOutlines2 } from '@weasel-js/font';
|
|
12
12
|
import { resolveTextStyle, resolveAlign, resolveRuns, cachedLayoutRuns, verticalAlignOffset, runsToPlainText, toRuns, fontString, textLineBoxes } from '@weasel-js/text';
|
|
13
13
|
export { DEFAULT_TEXT_STYLE, MARKDOWN_RUN_GRAMMAR, SCRIPT_METRICS, cachedLayoutRuns, createMarkdownRenderer, fontString, layoutMarkdown, layoutRuns, markdownToRuns, measureText, measureTextBounds, measuredWidth, resolveAlign, resolveRuns, resolveTextStyle, runsToMarkdown, runsToPlainText, textLineBoxes, toRuns, verticalAlignOffset } from '@weasel-js/text';
|
|
@@ -25,7 +25,7 @@ import { createHistory } from '@weasel-js/history';
|
|
|
25
25
|
export * from '@weasel-js/history';
|
|
26
26
|
|
|
27
27
|
// src/version.ts
|
|
28
|
-
var VERSION = "1.4.
|
|
28
|
+
var VERSION = "1.4.4" ;
|
|
29
29
|
|
|
30
30
|
// src/features/grid/roundToCell.ts
|
|
31
31
|
function roundToCell(value, cellSize) {
|
|
@@ -258,63 +258,135 @@ void main() {
|
|
|
258
258
|
}
|
|
259
259
|
`
|
|
260
260
|
);
|
|
261
|
-
var
|
|
261
|
+
var IMAGE_FILL_UNIFORMS = [
|
|
262
|
+
"u_proj",
|
|
263
|
+
"u_model",
|
|
264
|
+
"u_sampler",
|
|
265
|
+
"u_opacity",
|
|
266
|
+
"u_alpha",
|
|
267
|
+
"u_colorMatrix",
|
|
268
|
+
"u_colorBias"
|
|
269
|
+
];
|
|
270
|
+
var IMAGE_FILL_ATTRIBUTES = ["a_position", "a_uv"];
|
|
271
|
+
var BATCH_TEXTURE_SLOTS = 8;
|
|
272
|
+
var WHITE_SLOT = 0;
|
|
273
|
+
var PAINT_MODE_PLAIN = 0;
|
|
274
|
+
var PAINT_MODE_RADIAL = 3;
|
|
275
|
+
var PAINT_MODE_CONIC = 4;
|
|
276
|
+
var INV_TAU = (1 / (2 * Math.PI)).toFixed(10);
|
|
277
|
+
function packSlot(slot, mode) {
|
|
278
|
+
return slot + BATCH_TEXTURE_SLOTS * mode;
|
|
279
|
+
}
|
|
280
|
+
function sampleChain(slots) {
|
|
281
|
+
const arms = [];
|
|
282
|
+
for (let i = 1; i < slots; i++) {
|
|
283
|
+
arms.push(` if (slot == ${i}) return texture(u_samplers[${i}], uv);`);
|
|
284
|
+
}
|
|
285
|
+
return arms.join("\n");
|
|
286
|
+
}
|
|
287
|
+
var BATCH_VERT_SRC = (
|
|
262
288
|
/* glsl */
|
|
263
289
|
`#version 300 es
|
|
264
290
|
in vec2 a_position;
|
|
291
|
+
in vec4 a_vertexColor;
|
|
265
292
|
in vec2 a_uv;
|
|
266
|
-
in float
|
|
293
|
+
in float a_post;
|
|
294
|
+
in float a_texSlot;
|
|
267
295
|
uniform mat3 u_proj;
|
|
268
296
|
uniform mat3 u_model;
|
|
297
|
+
out vec4 v_vertexColor;
|
|
269
298
|
out vec2 v_uv;
|
|
270
|
-
out float
|
|
299
|
+
out float v_post;
|
|
300
|
+
flat out int v_texSlot;
|
|
301
|
+
flat out float v_paintMode;
|
|
271
302
|
void main() {
|
|
272
303
|
vec3 screen = u_model * vec3(a_position, 1.0);
|
|
273
|
-
vec3 clip
|
|
304
|
+
vec3 clip = u_proj * vec3(screen.xy, 1.0);
|
|
274
305
|
gl_Position = vec4(clip.xy, 0.0, 1.0);
|
|
306
|
+
v_vertexColor = a_vertexColor;
|
|
275
307
|
v_uv = a_uv;
|
|
276
|
-
|
|
308
|
+
v_post = a_post;
|
|
309
|
+
// slot + 8 * mode, unpacked \u2014 see the file header for why they share a float.
|
|
310
|
+
int packed = int(a_texSlot + 0.5);
|
|
311
|
+
v_texSlot = packed % ${BATCH_TEXTURE_SLOTS};
|
|
312
|
+
v_paintMode = float(packed / ${BATCH_TEXTURE_SLOTS});
|
|
277
313
|
}
|
|
278
314
|
`
|
|
279
315
|
);
|
|
280
|
-
var
|
|
316
|
+
var BATCH_FRAG_SRC = (
|
|
281
317
|
/* glsl */
|
|
282
318
|
`#version 300 es
|
|
283
319
|
precision highp float;
|
|
320
|
+
in vec4 v_vertexColor;
|
|
284
321
|
in vec2 v_uv;
|
|
285
|
-
in float
|
|
286
|
-
|
|
322
|
+
in float v_post;
|
|
323
|
+
flat in int v_texSlot;
|
|
324
|
+
flat in float v_paintMode;
|
|
325
|
+
uniform sampler2D u_samplers[${BATCH_TEXTURE_SLOTS}];
|
|
326
|
+
uniform vec4 u_color;
|
|
287
327
|
uniform float u_alpha;
|
|
328
|
+
uniform float u_synthBold;
|
|
288
329
|
uniform mat4 u_colorMatrix;
|
|
289
330
|
uniform vec4 u_colorBias;
|
|
290
331
|
out vec4 outColor;
|
|
332
|
+
|
|
333
|
+
vec4 sampleSlot(int slot, vec2 uv) {
|
|
334
|
+
${sampleChain(BATCH_TEXTURE_SLOTS)}
|
|
335
|
+
return texture(u_samplers[0], uv);
|
|
336
|
+
}
|
|
337
|
+
${GLYPH_COVERAGE_GLSL}
|
|
291
338
|
void main() {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
339
|
+
float isGrad = step(2.5, v_paintMode);
|
|
340
|
+
// A radial or conic vertex carries a gradient-space coordinate rather than a
|
|
341
|
+
// texture coordinate, and its atlas row rather than an alpha. The sample is
|
|
342
|
+
// split across the branch rather than the coordinate selected before it: an
|
|
343
|
+
// arm that reads v_uv straight is a fetch the hardware can schedule against a
|
|
344
|
+
// varying, and one reading a coordinate the shader computed is not. Selecting
|
|
345
|
+
// the coordinate first and sampling once costs 65% of a fragment that is not
|
|
346
|
+
// a gradient; splitting it costs 5% (tests/perf/fill-rate.spec.ts).
|
|
347
|
+
//
|
|
348
|
+
// Branching at all is safe here where it would not be around the glyph math:
|
|
349
|
+
// v_paintMode is flat, so every fragment of a quad takes the same arm, and
|
|
350
|
+
// nothing in either arm is a derivative.
|
|
351
|
+
vec4 texel;
|
|
352
|
+
if (isGrad > 0.5) {
|
|
353
|
+
float t = v_paintMode > ${PAINT_MODE_CONIC - 0.5}
|
|
354
|
+
? fract(atan(v_uv.y, v_uv.x) * ${INV_TAU})
|
|
355
|
+
: length(v_uv);
|
|
356
|
+
texel = sampleSlot(v_texSlot, vec2(t, v_post));
|
|
357
|
+
} else {
|
|
358
|
+
texel = sampleSlot(v_texSlot, v_uv);
|
|
359
|
+
}
|
|
360
|
+
float isGlyph = step(0.5, v_paintMode) * step(v_paintMode, 2.5);
|
|
361
|
+
// Unconditional, and multiplied out afterwards rather than branched around:
|
|
362
|
+
// see the file header.
|
|
363
|
+
float coverage = glyphCoverage(texel, v_paintMode, u_synthBold);
|
|
364
|
+
// A glyph's texel is a distance field, so it takes no part in the color; a
|
|
365
|
+
// plain vertex multiplies its texel in as it always did.
|
|
366
|
+
vec4 src = mix(texel, vec4(1.0), isGlyph) * u_color * v_vertexColor;
|
|
367
|
+
vec4 mapped = clamp(u_colorMatrix * src + u_colorBias, 0.0, 1.0);
|
|
368
|
+
float a = mapped.a * u_alpha * mix(v_post, 1.0, isGrad) * mix(1.0, coverage, isGlyph);
|
|
295
369
|
outColor = vec4(mapped.rgb * a, a);
|
|
296
370
|
}
|
|
297
371
|
`
|
|
298
372
|
);
|
|
299
|
-
var
|
|
373
|
+
var BATCH_FILL_UNIFORMS = [
|
|
300
374
|
"u_proj",
|
|
301
375
|
"u_model",
|
|
302
|
-
"
|
|
303
|
-
"
|
|
376
|
+
"u_samplers",
|
|
377
|
+
"u_color",
|
|
304
378
|
"u_alpha",
|
|
379
|
+
"u_synthBold",
|
|
305
380
|
"u_colorMatrix",
|
|
306
381
|
"u_colorBias"
|
|
307
382
|
];
|
|
308
|
-
var
|
|
309
|
-
|
|
310
|
-
"
|
|
311
|
-
"
|
|
312
|
-
"
|
|
313
|
-
"
|
|
314
|
-
"u_colorMatrix",
|
|
315
|
-
"u_colorBias"
|
|
383
|
+
var BATCH_FILL_ATTRIBUTES = [
|
|
384
|
+
"a_position",
|
|
385
|
+
"a_vertexColor",
|
|
386
|
+
"a_uv",
|
|
387
|
+
"a_post",
|
|
388
|
+
"a_texSlot"
|
|
316
389
|
];
|
|
317
|
-
var IMAGE_VOPACITY_ATTRIBUTES = ["a_position", "a_uv", "a_opacity"];
|
|
318
390
|
|
|
319
391
|
// src/renderer/shaders/gradFill.ts
|
|
320
392
|
var GRAD_VERT_SRC = (
|
|
@@ -340,7 +412,10 @@ var GRAD_FRAG_SRC = (
|
|
|
340
412
|
precision highp float;
|
|
341
413
|
in vec2 v_world;
|
|
342
414
|
uniform sampler2D u_ramp;
|
|
415
|
+
uniform float u_rampV;
|
|
343
416
|
uniform float u_alpha;
|
|
417
|
+
uniform mat4 u_colorMatrix;
|
|
418
|
+
uniform vec4 u_colorBias;
|
|
344
419
|
uniform float u_opacity;
|
|
345
420
|
uniform int u_gradKind;
|
|
346
421
|
uniform vec2 u_gradP0;
|
|
@@ -364,9 +439,14 @@ void main() {
|
|
|
364
439
|
t = fract(a / (2.0 * PI));
|
|
365
440
|
}
|
|
366
441
|
t = clamp(t, 0.0, 1.0);
|
|
367
|
-
vec4 rampColor = texture(u_ramp, vec2(t,
|
|
368
|
-
|
|
369
|
-
|
|
442
|
+
vec4 rampColor = texture(u_ramp, vec2(t, u_rampV));
|
|
443
|
+
// Fill opacity into the alpha channel before the matrix, which is where the
|
|
444
|
+
// batch program's vertex alpha sits \u2014 the two have to agree, since a linear
|
|
445
|
+
// gradient goes through that one and a radial through this.
|
|
446
|
+
vec4 src = vec4(rampColor.rgb, rampColor.a * u_opacity);
|
|
447
|
+
vec4 mapped = clamp(u_colorMatrix * src + u_colorBias, 0.0, 1.0);
|
|
448
|
+
float a = mapped.a * u_alpha;
|
|
449
|
+
outColor = vec4(mapped.rgb * a, a);
|
|
370
450
|
}
|
|
371
451
|
`
|
|
372
452
|
);
|
|
@@ -375,8 +455,11 @@ var GRAD_FILL_UNIFORMS = [
|
|
|
375
455
|
"u_model",
|
|
376
456
|
"u_worldInv",
|
|
377
457
|
"u_ramp",
|
|
458
|
+
"u_rampV",
|
|
378
459
|
"u_alpha",
|
|
379
460
|
"u_opacity",
|
|
461
|
+
"u_colorMatrix",
|
|
462
|
+
"u_colorBias",
|
|
380
463
|
"u_gradKind",
|
|
381
464
|
"u_gradP0",
|
|
382
465
|
"u_gradDir",
|
|
@@ -684,6 +767,23 @@ var GLImageCache = class {
|
|
|
684
767
|
gl;
|
|
685
768
|
minification;
|
|
686
769
|
map = /* @__PURE__ */ new WeakMap();
|
|
770
|
+
/**
|
|
771
|
+
* MAG_FILTER each texture currently carries, so a redundant write can be
|
|
772
|
+
* skipped.
|
|
773
|
+
*
|
|
774
|
+
* The batch sets this per flush — the same bitmap can be drawn at both
|
|
775
|
+
* filters in one frame, and the value has to be right at the draw rather than
|
|
776
|
+
* at upload. Filtering is state on the *texture object*, though, not on the
|
|
777
|
+
* unit, so re-asserting a value it already has is a write to a live texture
|
|
778
|
+
* for no reason. On a large sheet that is not free: a consumer's wall samples
|
|
779
|
+
* a 5652px-square atlas, 122MB resident, and measured `sampling: 'nearest'`
|
|
780
|
+
* costing up to 8x `'linear'` there — where the linear pass re-asserts the
|
|
781
|
+
* upload default and the nearest pass changes state on every draw.
|
|
782
|
+
*
|
|
783
|
+
* Whether that is the cause is unproven (see `docs/TODO.md`), but the write
|
|
784
|
+
* was redundant either way.
|
|
785
|
+
*/
|
|
786
|
+
magFilters = /* @__PURE__ */ new WeakMap();
|
|
687
787
|
upload(key, source, repetition) {
|
|
688
788
|
const existing = this.map.get(key);
|
|
689
789
|
if (existing) return existing;
|
|
@@ -698,6 +798,7 @@ var GLImageCache = class {
|
|
|
698
798
|
this.minification === "mipmap" ? gl.LINEAR_MIPMAP_LINEAR : gl.LINEAR
|
|
699
799
|
);
|
|
700
800
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
801
|
+
this.magFilters.set(key, gl.LINEAR);
|
|
701
802
|
const [wrapS, wrapT] = wrapModes(gl, repetition);
|
|
702
803
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, wrapS);
|
|
703
804
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, wrapT);
|
|
@@ -713,6 +814,14 @@ var GLImageCache = class {
|
|
|
713
814
|
gl.activeTexture(gl.TEXTURE0 + unit2);
|
|
714
815
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
715
816
|
}
|
|
817
|
+
/** Set `key`'s MAG_FILTER, skipping the call when it already holds that
|
|
818
|
+
* value. Its texture must be bound to the active unit — callers pair this
|
|
819
|
+
* with `bind`. */
|
|
820
|
+
setMagFilter(key, filter) {
|
|
821
|
+
if (this.magFilters.get(key) === filter) return;
|
|
822
|
+
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, filter);
|
|
823
|
+
this.magFilters.set(key, filter);
|
|
824
|
+
}
|
|
716
825
|
};
|
|
717
826
|
function wrapModes(gl, rep) {
|
|
718
827
|
switch (rep) {
|
|
@@ -1194,14 +1303,16 @@ function gradientForBounds(kind, bounds, stops, units) {
|
|
|
1194
1303
|
return { fill: "conic-gradient", center, angle: 0, stops, units };
|
|
1195
1304
|
}
|
|
1196
1305
|
|
|
1197
|
-
// src/renderer/cache/
|
|
1198
|
-
var
|
|
1306
|
+
// src/renderer/cache/GradientRampAtlas.ts
|
|
1307
|
+
var RAMP_WIDTH = 256;
|
|
1308
|
+
var INITIAL_ROWS = 16;
|
|
1309
|
+
var RAMP_ATLAS_MAX_ROWS = 1024;
|
|
1199
1310
|
function buildGradientRamp(stops) {
|
|
1200
|
-
const data = new Uint8ClampedArray(
|
|
1311
|
+
const data = new Uint8ClampedArray(RAMP_WIDTH * 4);
|
|
1201
1312
|
if (stops.length === 0) return data;
|
|
1202
1313
|
const resolved = resolveGradientStops(stops);
|
|
1203
|
-
for (let i = 0; i <
|
|
1204
|
-
const [r, g, b, a] = sampleResolvedStops(resolved, i / (
|
|
1314
|
+
for (let i = 0; i < RAMP_WIDTH; i++) {
|
|
1315
|
+
const [r, g, b, a] = sampleResolvedStops(resolved, i / (RAMP_WIDTH - 1));
|
|
1205
1316
|
data[i * 4] = r * 255;
|
|
1206
1317
|
data[i * 4 + 1] = g * 255;
|
|
1207
1318
|
data[i * 4 + 2] = b * 255;
|
|
@@ -1209,51 +1320,76 @@ function buildGradientRamp(stops) {
|
|
|
1209
1320
|
}
|
|
1210
1321
|
return data;
|
|
1211
1322
|
}
|
|
1212
|
-
var
|
|
1323
|
+
var GradientRampAtlas = class {
|
|
1213
1324
|
constructor(gl) {
|
|
1214
1325
|
this.gl = gl;
|
|
1215
1326
|
}
|
|
1216
1327
|
gl;
|
|
1217
|
-
|
|
1328
|
+
/** Row per stop list, in least-recently-used order: a hit re-inserts, so the
|
|
1329
|
+
* first entry is the row a full atlas recycles. */
|
|
1330
|
+
rowByKey = /* @__PURE__ */ new Map();
|
|
1331
|
+
texture = null;
|
|
1332
|
+
rows = 0;
|
|
1333
|
+
/** Mirror of the texture, so growth can respecify it without re-baking every
|
|
1334
|
+
* ramp it already holds. */
|
|
1335
|
+
pixels = new Uint8ClampedArray(0);
|
|
1218
1336
|
totalQueries = 0;
|
|
1219
1337
|
cacheHits = 0;
|
|
1338
|
+
/** Rows the atlas currently holds — its texture height. */
|
|
1339
|
+
get height() {
|
|
1340
|
+
return this.rows;
|
|
1341
|
+
}
|
|
1342
|
+
/**
|
|
1343
|
+
* Bake `stops` into a row and return it, reusing the row an identical stop
|
|
1344
|
+
* list already holds.
|
|
1345
|
+
*
|
|
1346
|
+
* **A returned row outlives the frame only while the atlas has room.** Past
|
|
1347
|
+
* `RAMP_ATLAS_MAX_ROWS` an upload recycles the least recently used row, which
|
|
1348
|
+
* rewrites texels a row handed out earlier still names. Nothing that defers
|
|
1349
|
+
* its draw past this call may hold a row across another `upload` without
|
|
1350
|
+
* arranging to be flushed first.
|
|
1351
|
+
*/
|
|
1220
1352
|
upload(stops) {
|
|
1221
1353
|
const key = JSON.stringify(stops);
|
|
1222
1354
|
this.totalQueries++;
|
|
1223
|
-
|
|
1355
|
+
const existing = this.rowByKey.get(key);
|
|
1356
|
+
if (existing !== void 0) {
|
|
1224
1357
|
this.cacheHits++;
|
|
1225
|
-
|
|
1358
|
+
this.rowByKey.delete(key);
|
|
1359
|
+
this.rowByKey.set(key, existing);
|
|
1360
|
+
return existing;
|
|
1226
1361
|
}
|
|
1227
|
-
const
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
1232
|
-
gl.texImage2D(
|
|
1233
|
-
gl.TEXTURE_2D,
|
|
1234
|
-
0,
|
|
1235
|
-
gl.RGBA,
|
|
1236
|
-
RAMP_SIZE,
|
|
1237
|
-
1,
|
|
1238
|
-
0,
|
|
1239
|
-
gl.RGBA,
|
|
1240
|
-
gl.UNSIGNED_BYTE,
|
|
1241
|
-
ramp
|
|
1242
|
-
);
|
|
1243
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
1244
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
1245
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
1246
|
-
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
1247
|
-
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
1248
|
-
this.map.set(key, tex);
|
|
1249
|
-
return key;
|
|
1362
|
+
const row = this.claimRow();
|
|
1363
|
+
this.writeRow(row, buildGradientRamp(stops));
|
|
1364
|
+
this.rowByKey.set(key, row);
|
|
1365
|
+
return row;
|
|
1250
1366
|
}
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1367
|
+
/**
|
|
1368
|
+
* Whether uploading `stops` would move where existing rows sit — by growing
|
|
1369
|
+
* the atlas, which changes every row's `v`, or by recycling one, which
|
|
1370
|
+
* rewrites its texels.
|
|
1371
|
+
*
|
|
1372
|
+
* Anything holding a row past this call asks first and gets itself out of
|
|
1373
|
+
* the way, because neither can be undone once it has happened.
|
|
1374
|
+
*/
|
|
1375
|
+
wouldReshape(stops) {
|
|
1376
|
+
if (this.rowByKey.size === 0) return false;
|
|
1377
|
+
return !this.rowByKey.has(JSON.stringify(stops)) && this.rowByKey.size >= this.rows;
|
|
1378
|
+
}
|
|
1379
|
+
/**
|
|
1380
|
+
* The `v` a row is sampled at — its center.
|
|
1381
|
+
*
|
|
1382
|
+
* The center is load-bearing: the atlas filters LINEAR, so a `v` anywhere
|
|
1383
|
+
* else blends the ramp beside it into this one. At the center the neighbor's
|
|
1384
|
+
* weight is exactly zero.
|
|
1385
|
+
*/
|
|
1386
|
+
rowV(row) {
|
|
1387
|
+
return (row + 0.5) / (this.rows || 1);
|
|
1388
|
+
}
|
|
1389
|
+
bind(unit2) {
|
|
1254
1390
|
const gl = this.gl;
|
|
1255
1391
|
gl.activeTexture(gl.TEXTURE0 + unit2);
|
|
1256
|
-
gl.bindTexture(gl.TEXTURE_2D,
|
|
1392
|
+
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
|
1257
1393
|
}
|
|
1258
1394
|
hitRate() {
|
|
1259
1395
|
if (this.totalQueries === 0) return 0;
|
|
@@ -1264,19 +1400,79 @@ var GradientRampCache = class {
|
|
|
1264
1400
|
this.cacheHits = 0;
|
|
1265
1401
|
}
|
|
1266
1402
|
/**
|
|
1267
|
-
* Delete
|
|
1268
|
-
* `WeaselRenderer.dispose()`.
|
|
1269
|
-
*
|
|
1270
|
-
* `upload()` call and already gone by the time a ramp is cached. The
|
|
1271
|
-
* cache is unusable but refillable afterward (stats are left as-is; call
|
|
1403
|
+
* Delete the atlas texture and forget every row in it. Called by
|
|
1404
|
+
* `WeaselRenderer.dispose()`. The CPU mirror goes with it, so the atlas is
|
|
1405
|
+
* unusable but refillable afterward (stats are left as-is; call
|
|
1272
1406
|
* `resetStats()` separately if desired).
|
|
1273
1407
|
*/
|
|
1274
1408
|
free() {
|
|
1409
|
+
if (this.texture) this.gl.deleteTexture(this.texture);
|
|
1410
|
+
this.texture = null;
|
|
1411
|
+
this.rows = 0;
|
|
1412
|
+
this.pixels = new Uint8ClampedArray(0);
|
|
1413
|
+
this.rowByKey.clear();
|
|
1414
|
+
}
|
|
1415
|
+
/** The row the next ramp is written to: a free one, a taller atlas, or the
|
|
1416
|
+
* least recently used row of a full one. */
|
|
1417
|
+
claimRow() {
|
|
1418
|
+
if (this.rowByKey.size < this.rows) return this.rowByKey.size;
|
|
1419
|
+
if (this.rows < RAMP_ATLAS_MAX_ROWS) {
|
|
1420
|
+
this.resize(this.rows === 0 ? INITIAL_ROWS : this.rows * 2);
|
|
1421
|
+
return this.rowByKey.size;
|
|
1422
|
+
}
|
|
1423
|
+
const [lruKey, lruRow] = this.rowByKey.entries().next().value;
|
|
1424
|
+
this.rowByKey.delete(lruKey);
|
|
1425
|
+
return lruRow;
|
|
1426
|
+
}
|
|
1427
|
+
/** Grow to `rows`, keeping every row at the index it already had — a row
|
|
1428
|
+
* index is a stable name, and callers hold them. */
|
|
1429
|
+
resize(rows) {
|
|
1275
1430
|
const gl = this.gl;
|
|
1276
|
-
|
|
1277
|
-
|
|
1431
|
+
const next = new Uint8ClampedArray(RAMP_WIDTH * rows * 4);
|
|
1432
|
+
next.set(this.pixels);
|
|
1433
|
+
this.pixels = next;
|
|
1434
|
+
this.rows = rows;
|
|
1435
|
+
if (!this.texture) {
|
|
1436
|
+
const tex = gl.createTexture();
|
|
1437
|
+
if (!tex) throw new Error("GradientRampAtlas: createTexture failed");
|
|
1438
|
+
this.texture = tex;
|
|
1439
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
1440
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
1441
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
1442
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
1443
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
1444
|
+
} else {
|
|
1445
|
+
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
|
1278
1446
|
}
|
|
1279
|
-
|
|
1447
|
+
gl.texImage2D(
|
|
1448
|
+
gl.TEXTURE_2D,
|
|
1449
|
+
0,
|
|
1450
|
+
gl.RGBA,
|
|
1451
|
+
RAMP_WIDTH,
|
|
1452
|
+
rows,
|
|
1453
|
+
0,
|
|
1454
|
+
gl.RGBA,
|
|
1455
|
+
gl.UNSIGNED_BYTE,
|
|
1456
|
+
this.pixels
|
|
1457
|
+
);
|
|
1458
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
1459
|
+
}
|
|
1460
|
+
writeRow(row, ramp2) {
|
|
1461
|
+
const gl = this.gl;
|
|
1462
|
+
this.pixels.set(ramp2, row * RAMP_WIDTH * 4);
|
|
1463
|
+
gl.bindTexture(gl.TEXTURE_2D, this.texture);
|
|
1464
|
+
gl.texSubImage2D(
|
|
1465
|
+
gl.TEXTURE_2D,
|
|
1466
|
+
0,
|
|
1467
|
+
0,
|
|
1468
|
+
row,
|
|
1469
|
+
RAMP_WIDTH,
|
|
1470
|
+
1,
|
|
1471
|
+
gl.RGBA,
|
|
1472
|
+
gl.UNSIGNED_BYTE,
|
|
1473
|
+
ramp2
|
|
1474
|
+
);
|
|
1475
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
1280
1476
|
}
|
|
1281
1477
|
};
|
|
1282
1478
|
|
|
@@ -3076,47 +3272,78 @@ function strokeMesh(path, stroke, flattenTolerance) {
|
|
|
3076
3272
|
return mesh;
|
|
3077
3273
|
}
|
|
3078
3274
|
|
|
3079
|
-
// src/renderer/
|
|
3275
|
+
// src/renderer/drawBatch.ts
|
|
3080
3276
|
var MAX_VERTICES_PER_BATCH = 32768;
|
|
3081
|
-
var FLOATS_PER_VERTEX =
|
|
3277
|
+
var FLOATS_PER_VERTEX = 10;
|
|
3082
3278
|
var INITIAL_VERTICES = 256;
|
|
3083
3279
|
var INITIAL_INDICES = 384;
|
|
3280
|
+
var WHITE_U = 0.5;
|
|
3281
|
+
var WHITE_V = 0.5;
|
|
3282
|
+
var PLAIN_WHITE = packSlot(WHITE_SLOT, PAINT_MODE_PLAIN);
|
|
3084
3283
|
var SOLID_RING_SIZE = 64;
|
|
3085
|
-
var
|
|
3086
|
-
|
|
3284
|
+
var BATCH_TIERS = [
|
|
3285
|
+
{ vertices: 16, indices: 24 },
|
|
3286
|
+
{ vertices: 1024, indices: 3072 }
|
|
3287
|
+
];
|
|
3288
|
+
var SOLID_RING_SLOT_VERTICES = BATCH_TIERS[BATCH_TIERS.length - 1].vertices;
|
|
3087
3289
|
var SOLID_LARGE_RING_SIZE = 4;
|
|
3088
3290
|
function doubledTo(from, need) {
|
|
3089
3291
|
let capacity = from;
|
|
3090
3292
|
while (capacity < need) capacity *= 2;
|
|
3091
3293
|
return capacity;
|
|
3092
3294
|
}
|
|
3093
|
-
|
|
3295
|
+
function quadIndices(quads) {
|
|
3296
|
+
const out = new Uint32Array(quads * 6);
|
|
3297
|
+
for (let q = 0; q < quads; q++) {
|
|
3298
|
+
const b = q * 4;
|
|
3299
|
+
const j = q * 6;
|
|
3300
|
+
out[j] = b;
|
|
3301
|
+
out[j + 1] = b + 1;
|
|
3302
|
+
out[j + 2] = b + 2;
|
|
3303
|
+
out[j + 3] = b;
|
|
3304
|
+
out[j + 4] = b + 2;
|
|
3305
|
+
out[j + 5] = b + 3;
|
|
3306
|
+
}
|
|
3307
|
+
return out;
|
|
3308
|
+
}
|
|
3309
|
+
var DrawBatch = class {
|
|
3094
3310
|
gl;
|
|
3095
3311
|
aPos;
|
|
3096
3312
|
aColor;
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3313
|
+
aUv;
|
|
3314
|
+
aPost;
|
|
3315
|
+
aSlot;
|
|
3316
|
+
/** One ring per tier, cycled per flush. Slots are created on first use, so a
|
|
3317
|
+
* renderer that flushes rarely allocates as few as it flushes. */
|
|
3318
|
+
rings = BATCH_TIERS.map(() => new Array(SOLID_RING_SIZE).fill(void 0));
|
|
3319
|
+
nextInRing = BATCH_TIERS.map(() => 0);
|
|
3320
|
+
/** The same, for flushes past the largest tier; these sets grow to fit. */
|
|
3102
3321
|
largeRing = new Array(SOLID_LARGE_RING_SIZE).fill(void 0);
|
|
3103
3322
|
nextLarge = 0;
|
|
3104
3323
|
verts = new Float32Array(INITIAL_VERTICES * FLOATS_PER_VERTEX);
|
|
3105
3324
|
idx = new Uint32Array(INITIAL_INDICES);
|
|
3106
3325
|
nVerts = 0;
|
|
3107
3326
|
nIdx = 0;
|
|
3108
|
-
/** Whether the staged run is
|
|
3109
|
-
*
|
|
3327
|
+
/** Whether the staged run is quads alone, so its indices are the canonical
|
|
3328
|
+
* pattern and a slot already holding that pattern needs no upload. */
|
|
3110
3329
|
pureRects = true;
|
|
3111
3330
|
constructor(gl, prog) {
|
|
3112
3331
|
const aPos = prog.attribute("a_position");
|
|
3113
3332
|
const aColor = prog.attribute("a_vertexColor");
|
|
3114
|
-
|
|
3115
|
-
|
|
3333
|
+
const aUv = prog.attribute("a_uv");
|
|
3334
|
+
const aPost = prog.attribute("a_post");
|
|
3335
|
+
const aSlot = prog.attribute("a_texSlot");
|
|
3336
|
+
if (aPos === void 0 || aColor === void 0 || aUv === void 0 || aPost === void 0 || aSlot === void 0) {
|
|
3337
|
+
throw new Error(
|
|
3338
|
+
"DrawBatch: batch program is missing a_position / a_vertexColor / a_uv / a_post / a_texSlot"
|
|
3339
|
+
);
|
|
3116
3340
|
}
|
|
3117
3341
|
this.gl = gl;
|
|
3118
3342
|
this.aPos = aPos;
|
|
3119
3343
|
this.aColor = aColor;
|
|
3344
|
+
this.aUv = aUv;
|
|
3345
|
+
this.aPost = aPost;
|
|
3346
|
+
this.aSlot = aSlot;
|
|
3120
3347
|
}
|
|
3121
3348
|
get length() {
|
|
3122
3349
|
return this.nIdx;
|
|
@@ -3132,7 +3359,6 @@ var SolidBatch = class {
|
|
|
3132
3359
|
*/
|
|
3133
3360
|
pushRect(x, y, w, h, m, r, g, b, a) {
|
|
3134
3361
|
this.reserve(4, 6);
|
|
3135
|
-
const v = this.verts;
|
|
3136
3362
|
let i = this.nVerts * FLOATS_PER_VERTEX;
|
|
3137
3363
|
const ma = m[0], mb = m[1], mc = m[3], md = m[4], mtx = m[6], mty = m[7];
|
|
3138
3364
|
const x1 = x + w;
|
|
@@ -3141,40 +3367,161 @@ var SolidBatch = class {
|
|
|
3141
3367
|
const bx = ma * x1 + mc * y + mtx, by = mb * x1 + md * y + mty;
|
|
3142
3368
|
const cx = ma * x1 + mc * y1 + mtx, cy = mb * x1 + md * y1 + mty;
|
|
3143
3369
|
const dx = ma * x + mc * y1 + mtx, dy = mb * x + md * y1 + mty;
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3370
|
+
const P = PLAIN_WHITE;
|
|
3371
|
+
i = this.writeVertex(i, ax, ay, r, g, b, a, WHITE_U, WHITE_V, 1, P);
|
|
3372
|
+
i = this.writeVertex(i, bx, by, r, g, b, a, WHITE_U, WHITE_V, 1, P);
|
|
3373
|
+
i = this.writeVertex(i, cx, cy, r, g, b, a, WHITE_U, WHITE_V, 1, P);
|
|
3374
|
+
this.writeVertex(i, dx, dy, r, g, b, a, WHITE_U, WHITE_V, 1, P);
|
|
3375
|
+
this.pushQuadIndices();
|
|
3376
|
+
}
|
|
3377
|
+
/**
|
|
3378
|
+
* Append one image quad: the destination rect `(x, y, w, h)` mapped through
|
|
3379
|
+
* `m`, sampling `(u0, v0)`-`(u1, v1)`, every corner carrying `post` as the
|
|
3380
|
+
* after-the-color-matrix alpha factor.
|
|
3381
|
+
*
|
|
3382
|
+
* Corners wind top-left, top-right, bottom-right, bottom-left with UVs
|
|
3383
|
+
* following — the same winding `pushRect` uses, which is what lets a run of
|
|
3384
|
+
* mixed rects and quads keep the canonical index pattern. The flips a command
|
|
3385
|
+
* asks for are already in the `u` / `v` the caller passes.
|
|
3386
|
+
*
|
|
3387
|
+
* `slot` is the texture unit the corners sample, which `draw.ts` assigns per
|
|
3388
|
+
* bitmap within the run.
|
|
3389
|
+
*/
|
|
3390
|
+
pushQuad(x, y, w, h, m, u0, v0, u1, v1, post, slot) {
|
|
3391
|
+
this.reserve(4, 6);
|
|
3392
|
+
let i = this.nVerts * FLOATS_PER_VERTEX;
|
|
3393
|
+
const ma = m[0], mb = m[1], mc = m[3], md = m[4], mtx = m[6], mty = m[7];
|
|
3394
|
+
const x1 = x + w;
|
|
3395
|
+
const y1 = y + h;
|
|
3396
|
+
const ax = ma * x + mc * y + mtx, ay = mb * x + md * y + mty;
|
|
3397
|
+
const bx = ma * x1 + mc * y + mtx, by = mb * x1 + md * y + mty;
|
|
3398
|
+
const cx = ma * x1 + mc * y1 + mtx, cy = mb * x1 + md * y1 + mty;
|
|
3399
|
+
const dx = ma * x + mc * y1 + mtx, dy = mb * x + md * y1 + mty;
|
|
3400
|
+
const P = packSlot(slot, PAINT_MODE_PLAIN);
|
|
3401
|
+
i = this.writeVertex(i, ax, ay, 1, 1, 1, 1, u0, v0, post, P);
|
|
3402
|
+
i = this.writeVertex(i, bx, by, 1, 1, 1, 1, u1, v0, post, P);
|
|
3403
|
+
i = this.writeVertex(i, cx, cy, 1, 1, 1, 1, u1, v1, post, P);
|
|
3404
|
+
this.writeVertex(i, dx, dy, 1, 1, 1, 1, u0, v1, post, P);
|
|
3405
|
+
this.pushQuadIndices();
|
|
3406
|
+
}
|
|
3407
|
+
/**
|
|
3408
|
+
* Append one glyph quad: the box `(x0, y0)`-`(x1, y1)` mapped through `m`,
|
|
3409
|
+
* sampling `(u0, v0)`-`(u1, v1)` of the font atlas at `slot`, painted in
|
|
3410
|
+
* `rgba`.
|
|
3411
|
+
*
|
|
3412
|
+
* `mode` says which channels of that atlas carry the distance field, and
|
|
3413
|
+
* rides the vertices packed into the slot — so a run off a baked MSDF atlas
|
|
3414
|
+
* and one off the runtime canvas bake still share a draw. The synthetic-bold
|
|
3415
|
+
* threshold does not: it is `u_synthBold`, and `draw.ts` breaks the run when
|
|
3416
|
+
* it changes.
|
|
3417
|
+
*
|
|
3418
|
+
* **A synthetic oblique is sheared here rather than in the shader.** The old
|
|
3419
|
+
* text program carried the baseline per vertex and skewed against
|
|
3420
|
+
* `u_synthItalic`; the batch places its own corners, so the shear is one
|
|
3421
|
+
* multiply while they are being placed, and `tanItalic` is 0 for an upright
|
|
3422
|
+
* face. It has to happen before `m`, which is where the shader had it too.
|
|
3423
|
+
*
|
|
3424
|
+
* Corners wind top-left, top-right, bottom-right, bottom-left — `pushQuad`'s
|
|
3425
|
+
* winding, which is what lets a run of mixed rects, image quads and glyphs
|
|
3426
|
+
* keep the canonical index pattern.
|
|
3427
|
+
*/
|
|
3428
|
+
pushGlyph(x0, y0, x1, y1, baselineY, tanItalic, m, u0, v0, u1, v1, r, g, b, a, slot, mode) {
|
|
3429
|
+
this.reserve(4, 6);
|
|
3430
|
+
let i = this.nVerts * FLOATS_PER_VERTEX;
|
|
3431
|
+
const ma = m[0], mb = m[1], mc = m[3], md = m[4], mtx = m[6], mty = m[7];
|
|
3432
|
+
const topShift = (baselineY - y0) * tanItalic;
|
|
3433
|
+
const botShift = (baselineY - y1) * tanItalic;
|
|
3434
|
+
const tx0 = x0 + topShift, tx1 = x1 + topShift;
|
|
3435
|
+
const bx0 = x0 + botShift, bx1 = x1 + botShift;
|
|
3436
|
+
const ax = ma * tx0 + mc * y0 + mtx, ay = mb * tx0 + md * y0 + mty;
|
|
3437
|
+
const bx = ma * tx1 + mc * y0 + mtx, by = mb * tx1 + md * y0 + mty;
|
|
3438
|
+
const cx = ma * bx1 + mc * y1 + mtx, cy = mb * bx1 + md * y1 + mty;
|
|
3439
|
+
const dx = ma * bx0 + mc * y1 + mtx, dy = mb * bx0 + md * y1 + mty;
|
|
3440
|
+
const P = packSlot(slot, mode);
|
|
3441
|
+
i = this.writeVertex(i, ax, ay, r, g, b, a, u0, v0, 1, P);
|
|
3442
|
+
i = this.writeVertex(i, bx, by, r, g, b, a, u1, v0, 1, P);
|
|
3443
|
+
i = this.writeVertex(i, cx, cy, r, g, b, a, u1, v1, 1, P);
|
|
3444
|
+
this.writeVertex(i, dx, dy, r, g, b, a, u0, v1, 1, P);
|
|
3445
|
+
this.pushQuadIndices();
|
|
3446
|
+
}
|
|
3447
|
+
/**
|
|
3448
|
+
* Append one rect filled by a gradient: the corners of `(x, y, w, h)` mapped
|
|
3449
|
+
* through `m`, sampling the ramp atlas at `slot`.
|
|
3450
|
+
*
|
|
3451
|
+
* `uv` gives each channel of `a_uv` as an affine function of the coordinates
|
|
3452
|
+
* the corners arrive in, which is what lets a gradient ride the vertices at
|
|
3453
|
+
* all: a linear one's ramp position is affine in position outright, and a
|
|
3454
|
+
* radial or conic one's gradient-space *coordinate* is, even though the ramp
|
|
3455
|
+
* position it yields is not. Either way the rasterizer's interpolation across
|
|
3456
|
+
* a triangle is exact. `mode` says which of the two the fragment shader is
|
|
3457
|
+
* looking at, and `post` carries the atlas row for the modes that read it —
|
|
3458
|
+
* see `shaders/batchFill.ts`.
|
|
3459
|
+
*
|
|
3460
|
+
* Values outside 0..1 are the sampler's business; the atlas clamps to the
|
|
3461
|
+
* edge texel, which is what the gradient shader's own `clamp` did.
|
|
3462
|
+
*/
|
|
3463
|
+
pushGradientRect(x, y, w, h, m, uv, post, slot, mode, r, g, b, a) {
|
|
3464
|
+
this.reserve(4, 6);
|
|
3465
|
+
let i = this.nVerts * FLOATS_PER_VERTEX;
|
|
3466
|
+
const ma = m[0], mb = m[1], mc = m[3], md = m[4], mtx = m[6], mty = m[7];
|
|
3467
|
+
const x1 = x + w;
|
|
3468
|
+
const y1 = y + h;
|
|
3469
|
+
const P = packSlot(slot, mode);
|
|
3470
|
+
const corner = (cx, cy) => {
|
|
3471
|
+
const at = i;
|
|
3472
|
+
i = this.writeVertex(
|
|
3473
|
+
at,
|
|
3474
|
+
ma * cx + mc * cy + mtx,
|
|
3475
|
+
mb * cx + md * cy + mty,
|
|
3476
|
+
r,
|
|
3477
|
+
g,
|
|
3478
|
+
b,
|
|
3479
|
+
a,
|
|
3480
|
+
uv.ux * cx + uv.uy * cy + uv.u0,
|
|
3481
|
+
uv.vx * cx + uv.vy * cy + uv.v0,
|
|
3482
|
+
post,
|
|
3483
|
+
P
|
|
3484
|
+
);
|
|
3485
|
+
return i;
|
|
3486
|
+
};
|
|
3487
|
+
corner(x, y);
|
|
3488
|
+
corner(x1, y);
|
|
3489
|
+
corner(x1, y1);
|
|
3490
|
+
corner(x, y1);
|
|
3491
|
+
this.pushQuadIndices();
|
|
3492
|
+
}
|
|
3493
|
+
/** `pushMesh` for a mesh filled by a gradient — see `pushGradientRect` for
|
|
3494
|
+
* what `uv`, `post` and `mode` carry. */
|
|
3495
|
+
pushGradientMesh(mesh, m, uv, post, slot, mode, r, g, b, a) {
|
|
3496
|
+
const src = mesh.vertices;
|
|
3497
|
+
const srcIdx = mesh.indices;
|
|
3498
|
+
const n = src.length >> 1;
|
|
3499
|
+
this.reserve(n, srcIdx.length);
|
|
3500
|
+
this.pureRects = false;
|
|
3501
|
+
const v = this.verts;
|
|
3502
|
+
let i = this.nVerts * FLOATS_PER_VERTEX;
|
|
3503
|
+
const ma = m[0], mb = m[1], mc = m[3], md = m[4], mtx = m[6], mty = m[7];
|
|
3504
|
+
const P = packSlot(slot, mode);
|
|
3505
|
+
for (let k = 0; k < n; k++) {
|
|
3506
|
+
const x = src[k * 2];
|
|
3507
|
+
const y = src[k * 2 + 1];
|
|
3508
|
+
v[i++] = ma * x + mc * y + mtx;
|
|
3509
|
+
v[i++] = mb * x + md * y + mty;
|
|
3510
|
+
v[i++] = r;
|
|
3511
|
+
v[i++] = g;
|
|
3512
|
+
v[i++] = b;
|
|
3513
|
+
v[i++] = a;
|
|
3514
|
+
v[i++] = uv.ux * x + uv.uy * y + uv.u0;
|
|
3515
|
+
v[i++] = uv.vx * x + uv.vy * y + uv.v0;
|
|
3516
|
+
v[i++] = post;
|
|
3517
|
+
v[i++] = P;
|
|
3518
|
+
}
|
|
3168
3519
|
const base = this.nVerts;
|
|
3520
|
+
const out = this.idx;
|
|
3169
3521
|
let j = this.nIdx;
|
|
3170
|
-
|
|
3171
|
-
this.
|
|
3172
|
-
this.
|
|
3173
|
-
this.idx[j++] = base;
|
|
3174
|
-
this.idx[j++] = base + 2;
|
|
3175
|
-
this.idx[j++] = base + 3;
|
|
3176
|
-
this.nVerts += 4;
|
|
3177
|
-
this.nIdx += 6;
|
|
3522
|
+
for (let k = 0; k < srcIdx.length; k++) out[j++] = base + srcIdx[k];
|
|
3523
|
+
this.nVerts += n;
|
|
3524
|
+
this.nIdx += srcIdx.length;
|
|
3178
3525
|
}
|
|
3179
3526
|
/**
|
|
3180
3527
|
* Append a tessellated mesh through `m`, all vertices carrying `rgba`. The
|
|
@@ -3199,6 +3546,10 @@ var SolidBatch = class {
|
|
|
3199
3546
|
v[i++] = g;
|
|
3200
3547
|
v[i++] = b;
|
|
3201
3548
|
v[i++] = a;
|
|
3549
|
+
v[i++] = WHITE_U;
|
|
3550
|
+
v[i++] = WHITE_V;
|
|
3551
|
+
v[i++] = 1;
|
|
3552
|
+
v[i++] = PLAIN_WHITE;
|
|
3202
3553
|
}
|
|
3203
3554
|
const base = this.nVerts;
|
|
3204
3555
|
const out = this.idx;
|
|
@@ -3211,14 +3562,20 @@ var SolidBatch = class {
|
|
|
3211
3562
|
* Returns the index count for the caller's `drawElements`. */
|
|
3212
3563
|
uploadAndBind() {
|
|
3213
3564
|
const gl = this.gl;
|
|
3214
|
-
const
|
|
3565
|
+
const tier = BATCH_TIERS.findIndex(
|
|
3566
|
+
(t) => this.nVerts <= t.vertices && this.nIdx <= t.indices
|
|
3567
|
+
);
|
|
3568
|
+
const set = tier < 0 ? this.nextLargeSlot() : this.nextRingSlot(tier);
|
|
3215
3569
|
gl.bindVertexArray(set.vao);
|
|
3216
3570
|
gl.bindBuffer(gl.ARRAY_BUFFER, set.vbo);
|
|
3217
3571
|
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verts, 0, this.nVerts * FLOATS_PER_VERTEX);
|
|
3218
|
-
|
|
3219
|
-
if (rects < 0 || rects !== set.indexRects) {
|
|
3572
|
+
if (!this.pureRects) {
|
|
3220
3573
|
gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, this.idx, 0, this.nIdx);
|
|
3221
|
-
set.
|
|
3574
|
+
set.canonicalQuads = 0;
|
|
3575
|
+
} else if (set.canonicalQuads < this.nVerts >> 2) {
|
|
3576
|
+
const quads = Math.min(set.vertexCapacity >> 2, Math.floor(set.indexCapacity / 6));
|
|
3577
|
+
gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, quadIndices(quads));
|
|
3578
|
+
set.canonicalQuads = quads;
|
|
3222
3579
|
}
|
|
3223
3580
|
return this.nIdx;
|
|
3224
3581
|
}
|
|
@@ -3228,12 +3585,39 @@ var SolidBatch = class {
|
|
|
3228
3585
|
this.pureRects = true;
|
|
3229
3586
|
}
|
|
3230
3587
|
dispose() {
|
|
3231
|
-
for (const set of [...this.
|
|
3588
|
+
for (const set of [...this.rings.flat(), ...this.largeRing]) {
|
|
3232
3589
|
if (set) this.deleteSet(set);
|
|
3233
3590
|
}
|
|
3234
|
-
this.ring.fill(void 0);
|
|
3591
|
+
for (const ring of this.rings) ring.fill(void 0);
|
|
3235
3592
|
this.largeRing.fill(void 0);
|
|
3236
3593
|
}
|
|
3594
|
+
writeVertex(i, x, y, r, g, b, a, u, v, post, packed) {
|
|
3595
|
+
const out = this.verts;
|
|
3596
|
+
out[i] = x;
|
|
3597
|
+
out[i + 1] = y;
|
|
3598
|
+
out[i + 2] = r;
|
|
3599
|
+
out[i + 3] = g;
|
|
3600
|
+
out[i + 4] = b;
|
|
3601
|
+
out[i + 5] = a;
|
|
3602
|
+
out[i + 6] = u;
|
|
3603
|
+
out[i + 7] = v;
|
|
3604
|
+
out[i + 8] = post;
|
|
3605
|
+
out[i + 9] = packed;
|
|
3606
|
+
return i + FLOATS_PER_VERTEX;
|
|
3607
|
+
}
|
|
3608
|
+
/** Two triangles over the four corners just written. */
|
|
3609
|
+
pushQuadIndices() {
|
|
3610
|
+
const base = this.nVerts;
|
|
3611
|
+
let j = this.nIdx;
|
|
3612
|
+
this.idx[j++] = base;
|
|
3613
|
+
this.idx[j++] = base + 1;
|
|
3614
|
+
this.idx[j++] = base + 2;
|
|
3615
|
+
this.idx[j++] = base;
|
|
3616
|
+
this.idx[j++] = base + 2;
|
|
3617
|
+
this.idx[j++] = base + 3;
|
|
3618
|
+
this.nVerts += 4;
|
|
3619
|
+
this.nIdx += 6;
|
|
3620
|
+
}
|
|
3237
3621
|
/** Grow the CPU arrays so `vertices` / `indices` more fit. */
|
|
3238
3622
|
reserve(vertices, indices) {
|
|
3239
3623
|
const needVerts = (this.nVerts + vertices) * FLOATS_PER_VERTEX;
|
|
@@ -3249,13 +3633,14 @@ var SolidBatch = class {
|
|
|
3249
3633
|
this.idx = grown;
|
|
3250
3634
|
}
|
|
3251
3635
|
}
|
|
3252
|
-
nextRingSlot() {
|
|
3253
|
-
const
|
|
3254
|
-
|
|
3255
|
-
|
|
3636
|
+
nextRingSlot(tier) {
|
|
3637
|
+
const ring = this.rings[tier];
|
|
3638
|
+
const slot = this.nextInRing[tier];
|
|
3639
|
+
this.nextInRing[tier] = (slot + 1) % ring.length;
|
|
3640
|
+
const existing = ring[slot];
|
|
3256
3641
|
if (existing) return existing;
|
|
3257
|
-
const set = this.createSet(
|
|
3258
|
-
|
|
3642
|
+
const set = this.createSet(BATCH_TIERS[tier].vertices, BATCH_TIERS[tier].indices);
|
|
3643
|
+
ring[slot] = set;
|
|
3259
3644
|
return set;
|
|
3260
3645
|
}
|
|
3261
3646
|
nextLargeSlot() {
|
|
@@ -3266,7 +3651,7 @@ var SolidBatch = class {
|
|
|
3266
3651
|
if (!set) {
|
|
3267
3652
|
set = this.createSet(
|
|
3268
3653
|
doubledTo(SOLID_RING_SLOT_VERTICES, this.nVerts),
|
|
3269
|
-
doubledTo(
|
|
3654
|
+
doubledTo(BATCH_TIERS[BATCH_TIERS.length - 1].indices, this.nIdx)
|
|
3270
3655
|
);
|
|
3271
3656
|
this.largeRing[slot] = set;
|
|
3272
3657
|
return set;
|
|
@@ -3282,7 +3667,7 @@ var SolidBatch = class {
|
|
|
3282
3667
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, set.ibo);
|
|
3283
3668
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, set.indexCapacity * 4, gl.DYNAMIC_DRAW);
|
|
3284
3669
|
gl.bindVertexArray(null);
|
|
3285
|
-
set.
|
|
3670
|
+
set.canonicalQuads = 0;
|
|
3286
3671
|
}
|
|
3287
3672
|
return set;
|
|
3288
3673
|
}
|
|
@@ -3291,7 +3676,7 @@ var SolidBatch = class {
|
|
|
3291
3676
|
const vao = gl.createVertexArray();
|
|
3292
3677
|
const vbo = gl.createBuffer();
|
|
3293
3678
|
const ibo = gl.createBuffer();
|
|
3294
|
-
if (!vao || !vbo || !ibo) throw new Error("
|
|
3679
|
+
if (!vao || !vbo || !ibo) throw new Error("DrawBatch: failed to create GL objects");
|
|
3295
3680
|
const stride = FLOATS_PER_VERTEX * 4;
|
|
3296
3681
|
gl.bindVertexArray(vao);
|
|
3297
3682
|
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
@@ -3300,10 +3685,16 @@ var SolidBatch = class {
|
|
|
3300
3685
|
gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, stride, 0);
|
|
3301
3686
|
gl.enableVertexAttribArray(this.aColor);
|
|
3302
3687
|
gl.vertexAttribPointer(this.aColor, 4, gl.FLOAT, false, stride, 8);
|
|
3688
|
+
gl.enableVertexAttribArray(this.aUv);
|
|
3689
|
+
gl.vertexAttribPointer(this.aUv, 2, gl.FLOAT, false, stride, 24);
|
|
3690
|
+
gl.enableVertexAttribArray(this.aPost);
|
|
3691
|
+
gl.vertexAttribPointer(this.aPost, 1, gl.FLOAT, false, stride, 32);
|
|
3692
|
+
gl.enableVertexAttribArray(this.aSlot);
|
|
3693
|
+
gl.vertexAttribPointer(this.aSlot, 1, gl.FLOAT, false, stride, 36);
|
|
3303
3694
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
3304
3695
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices * 4, gl.DYNAMIC_DRAW);
|
|
3305
3696
|
gl.bindVertexArray(null);
|
|
3306
|
-
return { vao, vbo, ibo, vertexCapacity: vertices, indexCapacity: indices,
|
|
3697
|
+
return { vao, vbo, ibo, vertexCapacity: vertices, indexCapacity: indices, canonicalQuads: 0 };
|
|
3307
3698
|
}
|
|
3308
3699
|
deleteSet(set) {
|
|
3309
3700
|
const gl = this.gl;
|
|
@@ -3313,222 +3704,18 @@ var SolidBatch = class {
|
|
|
3313
3704
|
}
|
|
3314
3705
|
};
|
|
3315
3706
|
|
|
3316
|
-
// src/renderer/
|
|
3317
|
-
var
|
|
3318
|
-
|
|
3319
|
-
|
|
3320
|
-
var TIERS = [
|
|
3321
|
-
{ quads: 1, slots: 64 },
|
|
3322
|
-
{ quads: 16, slots: 64 },
|
|
3323
|
-
{ quads: 256, slots: 16 }
|
|
3324
|
-
];
|
|
3325
|
-
TIERS[0].slots;
|
|
3326
|
-
var IMAGE_LARGE_RING_SIZE = 4;
|
|
3327
|
-
function doubledTo2(from, need) {
|
|
3328
|
-
let capacity = from;
|
|
3329
|
-
while (capacity < need) capacity *= 2;
|
|
3330
|
-
return capacity;
|
|
3707
|
+
// src/renderer/shaders/registerProgram.ts
|
|
3708
|
+
var registry = /* @__PURE__ */ new Map();
|
|
3709
|
+
function getProgramSource(id) {
|
|
3710
|
+
return registry.get(id) ?? null;
|
|
3331
3711
|
}
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3335
|
-
|
|
3336
|
-
const j = q * 6;
|
|
3337
|
-
out[j] = b;
|
|
3338
|
-
out[j + 1] = b + 1;
|
|
3339
|
-
out[j + 2] = b + 2;
|
|
3340
|
-
out[j + 3] = b;
|
|
3341
|
-
out[j + 4] = b + 2;
|
|
3342
|
-
out[j + 5] = b + 3;
|
|
3712
|
+
var isDev = () => typeof process !== "undefined" ? process.env.NODE_ENV !== "production" : true;
|
|
3713
|
+
function registerProgram(id, vert, frag) {
|
|
3714
|
+
if (registry.has(id) && !isDev()) {
|
|
3715
|
+
throw new Error(`weasel registerProgram: duplicate program id "${id}". In production, re-registration is not allowed. Pass a unique id or call in dev mode.`);
|
|
3343
3716
|
}
|
|
3344
|
-
|
|
3345
|
-
}
|
|
3346
|
-
var ImageBatch = class {
|
|
3347
|
-
gl;
|
|
3348
|
-
aPos;
|
|
3349
|
-
aUv;
|
|
3350
|
-
aOpacity;
|
|
3351
|
-
/** One ring per tier, cycled per flush. Slots are created on first use, so a
|
|
3352
|
-
* renderer that flushes rarely allocates as few as it flushes. */
|
|
3353
|
-
rings = TIERS.map((t) => new Array(t.slots).fill(void 0));
|
|
3354
|
-
nextInRing = TIERS.map(() => 0);
|
|
3355
|
-
/** For flushes past the largest tier; these sets grow to fit. */
|
|
3356
|
-
largeRing = new Array(IMAGE_LARGE_RING_SIZE).fill(void 0);
|
|
3357
|
-
nextLarge = 0;
|
|
3358
|
-
verts = new Float32Array(INITIAL_QUADS * 4 * FLOATS_PER_VERTEX2);
|
|
3359
|
-
nQuads = 0;
|
|
3360
|
-
constructor(gl, prog) {
|
|
3361
|
-
const aPos = prog.attribute("a_position");
|
|
3362
|
-
const aUv = prog.attribute("a_uv");
|
|
3363
|
-
const aOpacity = prog.attribute("a_opacity");
|
|
3364
|
-
if (aPos === void 0 || aUv === void 0 || aOpacity === void 0) {
|
|
3365
|
-
throw new Error(
|
|
3366
|
-
"ImageBatch: vertex-opacity program is missing a_position / a_uv / a_opacity"
|
|
3367
|
-
);
|
|
3368
|
-
}
|
|
3369
|
-
this.gl = gl;
|
|
3370
|
-
this.aPos = aPos;
|
|
3371
|
-
this.aUv = aUv;
|
|
3372
|
-
this.aOpacity = aOpacity;
|
|
3373
|
-
}
|
|
3374
|
-
/** Indices staged — what a caller passes to `drawElements`. */
|
|
3375
|
-
get length() {
|
|
3376
|
-
return this.nQuads * 6;
|
|
3377
|
-
}
|
|
3378
|
-
get quads() {
|
|
3379
|
-
return this.nQuads;
|
|
3380
|
-
}
|
|
3381
|
-
/** Whether staging one more quad would put the run past the per-flush cap. */
|
|
3382
|
-
wouldOverflow() {
|
|
3383
|
-
return (this.nQuads + 1) * 4 > MAX_IMAGE_VERTICES_PER_BATCH;
|
|
3384
|
-
}
|
|
3385
|
-
/**
|
|
3386
|
-
* Append one image quad: the destination rect `(x, y, w, h)` mapped through
|
|
3387
|
-
* `m`, sampling `(u0, v0)`-`(u1, v1)`, every corner carrying `opacity`.
|
|
3388
|
-
*
|
|
3389
|
-
* An affine maps a rect to a parallelogram, so two triangles still cover it
|
|
3390
|
-
* and the batch draws at `u_model` identity. Corners wind top-left,
|
|
3391
|
-
* top-right, bottom-right, bottom-left, with UVs following — the flips a
|
|
3392
|
-
* command asks for are already in the `u`/`v` the caller passes.
|
|
3393
|
-
*/
|
|
3394
|
-
pushQuad(x, y, w, h, m, u0, v0, u1, v1, opacity) {
|
|
3395
|
-
this.reserve();
|
|
3396
|
-
const v = this.verts;
|
|
3397
|
-
let i = this.nQuads * 4 * FLOATS_PER_VERTEX2;
|
|
3398
|
-
const ma = m[0], mb = m[1], mc = m[3], md = m[4], mtx = m[6], mty = m[7];
|
|
3399
|
-
const x1 = x + w;
|
|
3400
|
-
const y1 = y + h;
|
|
3401
|
-
const ax = ma * x + mc * y + mtx, ay = mb * x + md * y + mty;
|
|
3402
|
-
const bx = ma * x1 + mc * y + mtx, by = mb * x1 + md * y + mty;
|
|
3403
|
-
const cx = ma * x1 + mc * y1 + mtx, cy = mb * x1 + md * y1 + mty;
|
|
3404
|
-
const dx = ma * x + mc * y1 + mtx, dy = mb * x + md * y1 + mty;
|
|
3405
|
-
v[i++] = ax;
|
|
3406
|
-
v[i++] = ay;
|
|
3407
|
-
v[i++] = u0;
|
|
3408
|
-
v[i++] = v0;
|
|
3409
|
-
v[i++] = opacity;
|
|
3410
|
-
v[i++] = bx;
|
|
3411
|
-
v[i++] = by;
|
|
3412
|
-
v[i++] = u1;
|
|
3413
|
-
v[i++] = v0;
|
|
3414
|
-
v[i++] = opacity;
|
|
3415
|
-
v[i++] = cx;
|
|
3416
|
-
v[i++] = cy;
|
|
3417
|
-
v[i++] = u1;
|
|
3418
|
-
v[i++] = v1;
|
|
3419
|
-
v[i++] = opacity;
|
|
3420
|
-
v[i++] = dx;
|
|
3421
|
-
v[i++] = dy;
|
|
3422
|
-
v[i++] = u0;
|
|
3423
|
-
v[i++] = v1;
|
|
3424
|
-
v[i++] = opacity;
|
|
3425
|
-
this.nQuads += 1;
|
|
3426
|
-
}
|
|
3427
|
-
/** Upload the staged geometry into the next set of buffers and bind its VAO.
|
|
3428
|
-
* Returns the index count for the caller's `drawElements`. */
|
|
3429
|
-
uploadAndBind() {
|
|
3430
|
-
const gl = this.gl;
|
|
3431
|
-
const tier = TIERS.findIndex((t) => this.nQuads <= t.quads);
|
|
3432
|
-
const set = tier < 0 ? this.nextLargeSlot() : this.nextRingSlot(tier);
|
|
3433
|
-
gl.bindVertexArray(set.vao);
|
|
3434
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, set.vbo);
|
|
3435
|
-
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verts, 0, this.nQuads * 4 * FLOATS_PER_VERTEX2);
|
|
3436
|
-
return this.nQuads * 6;
|
|
3437
|
-
}
|
|
3438
|
-
reset() {
|
|
3439
|
-
this.nQuads = 0;
|
|
3440
|
-
}
|
|
3441
|
-
dispose() {
|
|
3442
|
-
for (const set of [...this.rings.flat(), ...this.largeRing]) {
|
|
3443
|
-
if (set) this.deleteSet(set);
|
|
3444
|
-
}
|
|
3445
|
-
for (const ring of this.rings) ring.fill(void 0);
|
|
3446
|
-
this.largeRing.fill(void 0);
|
|
3447
|
-
}
|
|
3448
|
-
/** Grow the CPU arrays so one more quad fits. */
|
|
3449
|
-
reserve() {
|
|
3450
|
-
const need = (this.nQuads + 1) * 4 * FLOATS_PER_VERTEX2;
|
|
3451
|
-
if (need <= this.verts.length) return;
|
|
3452
|
-
const grown = new Float32Array(doubledTo2(this.verts.length, need));
|
|
3453
|
-
grown.set(this.verts);
|
|
3454
|
-
this.verts = grown;
|
|
3455
|
-
}
|
|
3456
|
-
nextRingSlot(tier) {
|
|
3457
|
-
const ring = this.rings[tier];
|
|
3458
|
-
const slot = this.nextInRing[tier];
|
|
3459
|
-
this.nextInRing[tier] = (slot + 1) % ring.length;
|
|
3460
|
-
const existing = ring[slot];
|
|
3461
|
-
if (existing) return existing;
|
|
3462
|
-
const set = this.createSet(TIERS[tier].quads);
|
|
3463
|
-
ring[slot] = set;
|
|
3464
|
-
return set;
|
|
3465
|
-
}
|
|
3466
|
-
nextLargeSlot() {
|
|
3467
|
-
const gl = this.gl;
|
|
3468
|
-
const slot = this.nextLarge;
|
|
3469
|
-
this.nextLarge = (slot + 1) % IMAGE_LARGE_RING_SIZE;
|
|
3470
|
-
let set = this.largeRing[slot];
|
|
3471
|
-
if (!set) {
|
|
3472
|
-
set = this.createSet(doubledTo2(TIERS[TIERS.length - 1].quads, this.nQuads));
|
|
3473
|
-
this.largeRing[slot] = set;
|
|
3474
|
-
return set;
|
|
3475
|
-
}
|
|
3476
|
-
if (this.nQuads > set.quadCapacity) {
|
|
3477
|
-
set.quadCapacity = doubledTo2(set.quadCapacity, this.nQuads);
|
|
3478
|
-
gl.bindVertexArray(set.vao);
|
|
3479
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, set.vbo);
|
|
3480
|
-
gl.bufferData(
|
|
3481
|
-
gl.ARRAY_BUFFER,
|
|
3482
|
-
set.quadCapacity * 4 * FLOATS_PER_VERTEX2 * 4,
|
|
3483
|
-
gl.DYNAMIC_DRAW
|
|
3484
|
-
);
|
|
3485
|
-
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, set.ibo);
|
|
3486
|
-
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, quadIndices(set.quadCapacity), gl.STATIC_DRAW);
|
|
3487
|
-
gl.bindVertexArray(null);
|
|
3488
|
-
}
|
|
3489
|
-
return set;
|
|
3490
|
-
}
|
|
3491
|
-
createSet(quads) {
|
|
3492
|
-
const gl = this.gl;
|
|
3493
|
-
const vao = gl.createVertexArray();
|
|
3494
|
-
const vbo = gl.createBuffer();
|
|
3495
|
-
const ibo = gl.createBuffer();
|
|
3496
|
-
if (!vao || !vbo || !ibo) throw new Error("ImageBatch: failed to create GL objects");
|
|
3497
|
-
const stride = FLOATS_PER_VERTEX2 * 4;
|
|
3498
|
-
gl.bindVertexArray(vao);
|
|
3499
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
3500
|
-
gl.bufferData(gl.ARRAY_BUFFER, quads * 4 * stride, gl.DYNAMIC_DRAW);
|
|
3501
|
-
gl.enableVertexAttribArray(this.aPos);
|
|
3502
|
-
gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, stride, 0);
|
|
3503
|
-
gl.enableVertexAttribArray(this.aUv);
|
|
3504
|
-
gl.vertexAttribPointer(this.aUv, 2, gl.FLOAT, false, stride, 8);
|
|
3505
|
-
gl.enableVertexAttribArray(this.aOpacity);
|
|
3506
|
-
gl.vertexAttribPointer(this.aOpacity, 1, gl.FLOAT, false, stride, 16);
|
|
3507
|
-
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
3508
|
-
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, quadIndices(quads), gl.STATIC_DRAW);
|
|
3509
|
-
gl.bindVertexArray(null);
|
|
3510
|
-
return { vao, vbo, ibo, quadCapacity: quads };
|
|
3511
|
-
}
|
|
3512
|
-
deleteSet(set) {
|
|
3513
|
-
const gl = this.gl;
|
|
3514
|
-
gl.deleteBuffer(set.vbo);
|
|
3515
|
-
gl.deleteBuffer(set.ibo);
|
|
3516
|
-
gl.deleteVertexArray(set.vao);
|
|
3517
|
-
}
|
|
3518
|
-
};
|
|
3519
|
-
|
|
3520
|
-
// src/renderer/shaders/registerProgram.ts
|
|
3521
|
-
var registry = /* @__PURE__ */ new Map();
|
|
3522
|
-
function getProgramSource(id) {
|
|
3523
|
-
return registry.get(id) ?? null;
|
|
3524
|
-
}
|
|
3525
|
-
var isDev = () => typeof process !== "undefined" ? process.env.NODE_ENV !== "production" : true;
|
|
3526
|
-
function registerProgram(id, vert, frag) {
|
|
3527
|
-
if (registry.has(id) && !isDev()) {
|
|
3528
|
-
throw new Error(`weasel registerProgram: duplicate program id "${id}". In production, re-registration is not allowed. Pass a unique id or call in dev mode.`);
|
|
3529
|
-
}
|
|
3530
|
-
registry.set(id, { vert, frag });
|
|
3531
|
-
return { id };
|
|
3717
|
+
registry.set(id, { vert, frag });
|
|
3718
|
+
return { id };
|
|
3532
3719
|
}
|
|
3533
3720
|
|
|
3534
3721
|
// src/renderer/effects/effectPrelude.ts
|
|
@@ -3668,14 +3855,13 @@ function dispatch(ctx, cmd) {
|
|
|
3668
3855
|
case "path":
|
|
3669
3856
|
return drawPath(ctx, cmd);
|
|
3670
3857
|
case "text":
|
|
3671
|
-
flushBatches(ctx);
|
|
3672
3858
|
return drawText(ctx, cmd);
|
|
3673
3859
|
case "image":
|
|
3674
3860
|
return drawImage(ctx, cmd);
|
|
3675
3861
|
case "sprites":
|
|
3676
3862
|
return drawSprites(ctx, cmd);
|
|
3677
3863
|
case "shader":
|
|
3678
|
-
|
|
3864
|
+
flushBatch(ctx);
|
|
3679
3865
|
return drawShader(ctx, cmd);
|
|
3680
3866
|
}
|
|
3681
3867
|
}
|
|
@@ -3792,7 +3978,7 @@ function drawShader(ctx, cmd) {
|
|
|
3792
3978
|
}
|
|
3793
3979
|
function drawGroupWithEffects(ctx, cmd, targets, width, height) {
|
|
3794
3980
|
const gl = ctx.gl;
|
|
3795
|
-
|
|
3981
|
+
flushBatch(ctx);
|
|
3796
3982
|
const parentTarget = ctx.renderTarget ?? null;
|
|
3797
3983
|
const parentClipDepth = ctx.clipDepth;
|
|
3798
3984
|
const scissorWasOn = gl.isEnabled(gl.SCISSOR_TEST);
|
|
@@ -3806,7 +3992,7 @@ function drawGroupWithEffects(ctx, cmd, targets, width, height) {
|
|
|
3806
3992
|
gl.stencilMask(255);
|
|
3807
3993
|
gl.clear(gl.COLOR_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
|
|
3808
3994
|
for (const child of cmd.children) dispatch(ctx, child);
|
|
3809
|
-
|
|
3995
|
+
flushBatch(ctx);
|
|
3810
3996
|
gl.disable(gl.BLEND);
|
|
3811
3997
|
for (const effect of cmd.effects) {
|
|
3812
3998
|
const program = ctx.ensureProgram?.(effect.program.id) ?? null;
|
|
@@ -3934,12 +4120,14 @@ function drawPathFill(ctx, cmd) {
|
|
|
3934
4120
|
const isSolid = fill.fill === void 0 || fill.fill === "solid";
|
|
3935
4121
|
const hasVColors = !!(cmd.vertexColors && cmd.vertexColors.length > 0);
|
|
3936
4122
|
const solid2 = fill;
|
|
3937
|
-
|
|
3938
|
-
|
|
4123
|
+
const paint = batchPaint(ctx, fill, hasVColors);
|
|
4124
|
+
if (paint !== void 0 && cmd.path.kind === "rect") {
|
|
4125
|
+
if (paint.kind === "ramp") pushRampRect(ctx, cmd.path, paint);
|
|
4126
|
+
else pushRect(ctx, cmd.path, paint);
|
|
3939
4127
|
return;
|
|
3940
4128
|
}
|
|
3941
4129
|
const mesh = fillMesh(ctx, cmd.path);
|
|
3942
|
-
if (
|
|
4130
|
+
if (tryStageFill(ctx, mesh, paint)) return;
|
|
3943
4131
|
const handle = meshHandle(ctx, mesh);
|
|
3944
4132
|
if (isSolid && hasVColors) {
|
|
3945
4133
|
drawPathFillVColor(ctx, cmd, solid2, handle);
|
|
@@ -3949,43 +4137,120 @@ function drawPathFill(ctx, cmd) {
|
|
|
3949
4137
|
drawPathFillByKind(ctx, fill, handle);
|
|
3950
4138
|
}
|
|
3951
4139
|
}
|
|
4140
|
+
var SAMPLER_UNITS = new Int32Array(
|
|
4141
|
+
Array.from({ length: BATCH_TEXTURE_SLOTS }, (_, i) => i)
|
|
4142
|
+
);
|
|
3952
4143
|
function isIdentityColorMatrix(cm) {
|
|
3953
4144
|
return cm === IDENTITY_COLOR_MATRIX || sameValues(IDENTITY_COLOR_MATRIX, cm);
|
|
3954
4145
|
}
|
|
3955
|
-
function stagedStateIsLive(ctx, staged) {
|
|
4146
|
+
function stagedStateIsLive(ctx, staged, image, sampling, synthBold = 0) {
|
|
3956
4147
|
if (staged.clipDepth !== ctx.clipDepth) return false;
|
|
4148
|
+
if (staged.synthBold !== synthBold) return false;
|
|
3957
4149
|
if (!staged.foldsAlpha && staged.alpha !== ctx.state.alpha) return false;
|
|
4150
|
+
if (image !== void 0 && slotForBitmap(staged, image, sampling) < 0) return false;
|
|
3958
4151
|
const colorMatrix = ctx.state.colorMatrix;
|
|
3959
4152
|
return staged.colorMatrix === colorMatrix || sameValues(staged.colorMatrix, colorMatrix);
|
|
3960
4153
|
}
|
|
4154
|
+
function slotForBitmap(staged, image, sampling) {
|
|
4155
|
+
for (let i = 0; i < staged.textures.length; i++) {
|
|
4156
|
+
const entry = staged.textures[i];
|
|
4157
|
+
if (entry.kind !== "bitmap" || entry.image !== image) continue;
|
|
4158
|
+
return entry.sampling === sampling ? i + 1 : -1;
|
|
4159
|
+
}
|
|
4160
|
+
return nextFreeSlot(staged);
|
|
4161
|
+
}
|
|
4162
|
+
function slotForRamps(staged) {
|
|
4163
|
+
for (let i = 0; i < staged.textures.length; i++) {
|
|
4164
|
+
if (staged.textures[i].kind === "ramps") return i + 1;
|
|
4165
|
+
}
|
|
4166
|
+
return nextFreeSlot(staged);
|
|
4167
|
+
}
|
|
4168
|
+
function slotForAtlas(staged, id) {
|
|
4169
|
+
for (let i = 0; i < staged.textures.length; i++) {
|
|
4170
|
+
const entry = staged.textures[i];
|
|
4171
|
+
if (entry.kind === "atlas" && entry.id === id) return i + 1;
|
|
4172
|
+
}
|
|
4173
|
+
return nextFreeSlot(staged);
|
|
4174
|
+
}
|
|
4175
|
+
function nextFreeSlot(staged) {
|
|
4176
|
+
return staged.textures.length + 1 < BATCH_TEXTURE_SLOTS ? staged.textures.length + 1 : -1;
|
|
4177
|
+
}
|
|
3961
4178
|
var MAX_BATCHED_MESH_VERTICES = 256;
|
|
3962
4179
|
function canBatchMesh(mesh) {
|
|
3963
4180
|
return !mesh.requiresStencil && mesh.vertices.length >> 1 <= MAX_BATCHED_MESH_VERTICES;
|
|
3964
4181
|
}
|
|
3965
4182
|
function stageSolid(ctx, vertices) {
|
|
3966
|
-
|
|
3967
|
-
if (ctx.
|
|
3968
|
-
|
|
3969
|
-
|
|
4183
|
+
if (ctx.batchState !== void 0 && !stagedStateIsLive(ctx, ctx.batchState)) flushBatch(ctx);
|
|
4184
|
+
if (ctx.drawBatch.wouldOverflow(vertices)) flushBatch(ctx);
|
|
4185
|
+
return openRun(ctx);
|
|
4186
|
+
}
|
|
4187
|
+
function openRun(ctx) {
|
|
4188
|
+
if (ctx.batchState === void 0) {
|
|
3970
4189
|
const colorMatrix = ctx.state.colorMatrix;
|
|
3971
4190
|
const foldsAlpha = isIdentityColorMatrix(colorMatrix);
|
|
3972
|
-
ctx.
|
|
4191
|
+
ctx.batchState = {
|
|
3973
4192
|
alpha: foldsAlpha ? 1 : ctx.state.alpha,
|
|
3974
4193
|
colorMatrix,
|
|
3975
4194
|
clipDepth: ctx.clipDepth,
|
|
3976
|
-
|
|
4195
|
+
synthBold: 0,
|
|
4196
|
+
foldsAlpha,
|
|
4197
|
+
textures: []
|
|
3977
4198
|
};
|
|
3978
4199
|
}
|
|
3979
|
-
return ctx.
|
|
4200
|
+
return ctx.batchState;
|
|
4201
|
+
}
|
|
4202
|
+
function stageImage(ctx, image, sampling) {
|
|
4203
|
+
if (ctx.batchState !== void 0 && !stagedStateIsLive(ctx, ctx.batchState, image, sampling)) {
|
|
4204
|
+
flushBatch(ctx);
|
|
4205
|
+
}
|
|
4206
|
+
if (ctx.drawBatch.wouldOverflow(4)) flushBatch(ctx);
|
|
4207
|
+
const staged = openRun(ctx);
|
|
4208
|
+
let slot = slotForBitmap(staged, image, sampling);
|
|
4209
|
+
if (slot > staged.textures.length) {
|
|
4210
|
+
staged.textures.push({ kind: "bitmap", image, sampling });
|
|
4211
|
+
slot = staged.textures.length;
|
|
4212
|
+
}
|
|
4213
|
+
return { staged, slot };
|
|
4214
|
+
}
|
|
4215
|
+
function stageGlyphs(ctx, atlasId, synthBold) {
|
|
4216
|
+
if (ctx.batchState !== void 0 && (!stagedStateIsLive(ctx, ctx.batchState, void 0, void 0, synthBold) || slotForAtlas(ctx.batchState, atlasId) < 0)) {
|
|
4217
|
+
flushBatch(ctx);
|
|
4218
|
+
}
|
|
4219
|
+
if (ctx.drawBatch.wouldOverflow(4)) flushBatch(ctx);
|
|
4220
|
+
const staged = openRun(ctx);
|
|
4221
|
+
staged.synthBold = synthBold;
|
|
4222
|
+
let slot = slotForAtlas(staged, atlasId);
|
|
4223
|
+
if (slot > staged.textures.length) {
|
|
4224
|
+
staged.textures.push({ kind: "atlas", id: atlasId });
|
|
4225
|
+
slot = staged.textures.length;
|
|
4226
|
+
}
|
|
4227
|
+
return { staged, slot };
|
|
4228
|
+
}
|
|
4229
|
+
function stageRamps(ctx, stops, vertices) {
|
|
4230
|
+
if (ctx.gradRamps.wouldReshape(stops)) flushBatch(ctx);
|
|
4231
|
+
if (ctx.batchState !== void 0 && (!stagedStateIsLive(ctx, ctx.batchState) || slotForRamps(ctx.batchState) < 0)) {
|
|
4232
|
+
flushBatch(ctx);
|
|
4233
|
+
}
|
|
4234
|
+
if (ctx.drawBatch.wouldOverflow(vertices)) flushBatch(ctx);
|
|
4235
|
+
const staged = openRun(ctx);
|
|
4236
|
+
let slot = slotForRamps(staged);
|
|
4237
|
+
if (slot > staged.textures.length) {
|
|
4238
|
+
staged.textures.push({ kind: "ramps" });
|
|
4239
|
+
slot = staged.textures.length;
|
|
4240
|
+
}
|
|
4241
|
+
return { staged, slot, rowV: ctx.gradRamps.rowV(ctx.gradRamps.upload(stops)) };
|
|
4242
|
+
}
|
|
4243
|
+
function stagedAlpha(ctx, staged, opacity) {
|
|
4244
|
+
return (opacity ?? 1) * (staged.foldsAlpha ? ctx.state.alpha : 1);
|
|
3980
4245
|
}
|
|
3981
4246
|
function stagedColor(ctx, staged, paint) {
|
|
3982
4247
|
const [r, g, b, a] = resolveColor(paint.color);
|
|
3983
|
-
return [r, g, b, a * (
|
|
4248
|
+
return [r, g, b, a * stagedAlpha(ctx, staged, paint.opacity)];
|
|
3984
4249
|
}
|
|
3985
4250
|
function pushRect(ctx, rect, fill) {
|
|
3986
4251
|
const staged = stageSolid(ctx, 4);
|
|
3987
4252
|
const [r, g, b, a] = stagedColor(ctx, staged, fill);
|
|
3988
|
-
ctx.
|
|
4253
|
+
ctx.drawBatch.pushRect(
|
|
3989
4254
|
rect.x,
|
|
3990
4255
|
rect.y,
|
|
3991
4256
|
rect.width,
|
|
@@ -4000,83 +4265,162 @@ function pushRect(ctx, rect, fill) {
|
|
|
4000
4265
|
function pushMesh(ctx, mesh, paint) {
|
|
4001
4266
|
const staged = stageSolid(ctx, mesh.vertices.length >> 1);
|
|
4002
4267
|
const [r, g, b, a] = stagedColor(ctx, staged, paint);
|
|
4003
|
-
ctx.
|
|
4268
|
+
ctx.drawBatch.pushMesh(mesh, ctx.state.transform, r, g, b, a);
|
|
4269
|
+
}
|
|
4270
|
+
function batchPaint(ctx, fill, hasVColors) {
|
|
4271
|
+
if (hasVColors) return void 0;
|
|
4272
|
+
const kind = fill.fill ?? "solid";
|
|
4273
|
+
if (kind === "solid") {
|
|
4274
|
+
const solid2 = fill;
|
|
4275
|
+
return { kind: "solid", color: solid2.color, opacity: solid2.opacity };
|
|
4276
|
+
}
|
|
4277
|
+
if (kind === "linear-gradient") {
|
|
4278
|
+
const grad = fill;
|
|
4279
|
+
return ramp(grad, PAINT_MODE_PLAIN, linearRampUV(ctx, grad));
|
|
4280
|
+
}
|
|
4281
|
+
if (kind === "radial-gradient") {
|
|
4282
|
+
const grad = fill;
|
|
4283
|
+
return ramp(grad, PAINT_MODE_RADIAL, radialRampUV(ctx, grad));
|
|
4284
|
+
}
|
|
4285
|
+
if (kind === "conic-gradient") {
|
|
4286
|
+
const grad = fill;
|
|
4287
|
+
return ramp(grad, PAINT_MODE_CONIC, conicRampUV(ctx, grad));
|
|
4288
|
+
}
|
|
4289
|
+
return void 0;
|
|
4004
4290
|
}
|
|
4005
|
-
function
|
|
4291
|
+
function ramp(fill, mode, uv) {
|
|
4292
|
+
return { kind: "ramp", stops: fill.stops, opacity: fill.opacity, mode, uv };
|
|
4293
|
+
}
|
|
4294
|
+
function gradientMap(ctx, units) {
|
|
4295
|
+
return mat3.multiply(gradientSpaceInverse(ctx, units), ctx.state.transform);
|
|
4296
|
+
}
|
|
4297
|
+
function linearRampUV(ctx, fill) {
|
|
4298
|
+
const g = gradientMap(ctx, fill.units);
|
|
4299
|
+
const dx = fill.to.x - fill.from.x;
|
|
4300
|
+
const dy = fill.to.y - fill.from.y;
|
|
4301
|
+
const len = Math.hypot(dx, dy) || 1;
|
|
4302
|
+
const k = 1 / (len * len);
|
|
4303
|
+
return {
|
|
4304
|
+
ux: (g[0] * dx + g[1] * dy) * k,
|
|
4305
|
+
uy: (g[3] * dx + g[4] * dy) * k,
|
|
4306
|
+
u0: ((g[6] - fill.from.x) * dx + (g[7] - fill.from.y) * dy) * k,
|
|
4307
|
+
vx: 0,
|
|
4308
|
+
vy: 0,
|
|
4309
|
+
v0: 0
|
|
4310
|
+
};
|
|
4311
|
+
}
|
|
4312
|
+
function radialRampUV(ctx, fill) {
|
|
4313
|
+
const g = gradientMap(ctx, fill.units);
|
|
4314
|
+
const k = 1 / Math.max(fill.radius, 1e-4);
|
|
4315
|
+
return {
|
|
4316
|
+
ux: g[0] * k,
|
|
4317
|
+
uy: g[3] * k,
|
|
4318
|
+
u0: (g[6] - fill.center.x) * k,
|
|
4319
|
+
vx: g[1] * k,
|
|
4320
|
+
vy: g[4] * k,
|
|
4321
|
+
v0: (g[7] - fill.center.y) * k
|
|
4322
|
+
};
|
|
4323
|
+
}
|
|
4324
|
+
function conicRampUV(ctx, fill) {
|
|
4325
|
+
const g = gradientMap(ctx, fill.units);
|
|
4326
|
+
const cos = Math.cos(fill.angle);
|
|
4327
|
+
const sin = Math.sin(fill.angle);
|
|
4328
|
+
const dx0 = g[6] - fill.center.x;
|
|
4329
|
+
const dy0 = g[7] - fill.center.y;
|
|
4330
|
+
return {
|
|
4331
|
+
ux: cos * g[0] + sin * g[1],
|
|
4332
|
+
uy: cos * g[3] + sin * g[4],
|
|
4333
|
+
u0: cos * dx0 + sin * dy0,
|
|
4334
|
+
vx: cos * g[1] - sin * g[0],
|
|
4335
|
+
vy: cos * g[4] - sin * g[3],
|
|
4336
|
+
v0: cos * dy0 - sin * dx0
|
|
4337
|
+
};
|
|
4338
|
+
}
|
|
4339
|
+
function rampVertices(paint, rowV) {
|
|
4340
|
+
return paint.mode === PAINT_MODE_PLAIN ? { uv: { ...paint.uv, v0: rowV }, post: 1 } : { uv: paint.uv, post: rowV };
|
|
4341
|
+
}
|
|
4342
|
+
function pushRampRect(ctx, rect, paint) {
|
|
4343
|
+
const { staged, slot, rowV } = stageRamps(ctx, paint.stops, 4);
|
|
4344
|
+
const { uv, post } = rampVertices(paint, rowV);
|
|
4345
|
+
ctx.drawBatch.pushGradientRect(
|
|
4346
|
+
rect.x,
|
|
4347
|
+
rect.y,
|
|
4348
|
+
rect.width,
|
|
4349
|
+
rect.height,
|
|
4350
|
+
ctx.state.transform,
|
|
4351
|
+
uv,
|
|
4352
|
+
post,
|
|
4353
|
+
slot,
|
|
4354
|
+
paint.mode,
|
|
4355
|
+
1,
|
|
4356
|
+
1,
|
|
4357
|
+
1,
|
|
4358
|
+
stagedAlpha(ctx, staged, paint.opacity)
|
|
4359
|
+
);
|
|
4360
|
+
}
|
|
4361
|
+
function pushRampMesh(ctx, mesh, paint) {
|
|
4362
|
+
const { staged, slot, rowV } = stageRamps(ctx, paint.stops, mesh.vertices.length >> 1);
|
|
4363
|
+
const { uv, post } = rampVertices(paint, rowV);
|
|
4364
|
+
ctx.drawBatch.pushGradientMesh(
|
|
4365
|
+
mesh,
|
|
4366
|
+
ctx.state.transform,
|
|
4367
|
+
uv,
|
|
4368
|
+
post,
|
|
4369
|
+
slot,
|
|
4370
|
+
paint.mode,
|
|
4371
|
+
1,
|
|
4372
|
+
1,
|
|
4373
|
+
1,
|
|
4374
|
+
stagedAlpha(ctx, staged, paint.opacity)
|
|
4375
|
+
);
|
|
4376
|
+
}
|
|
4377
|
+
function tryStageFill(ctx, mesh, paint) {
|
|
4006
4378
|
if (paint !== void 0 && canBatchMesh(mesh)) {
|
|
4007
|
-
|
|
4379
|
+
if (paint.kind === "ramp") pushRampMesh(ctx, mesh, paint);
|
|
4380
|
+
else pushMesh(ctx, mesh, paint);
|
|
4008
4381
|
return true;
|
|
4009
4382
|
}
|
|
4010
|
-
|
|
4383
|
+
flushBatch(ctx);
|
|
4011
4384
|
return false;
|
|
4012
4385
|
}
|
|
4013
|
-
function
|
|
4014
|
-
const batch = ctx.
|
|
4015
|
-
const staged = ctx.
|
|
4386
|
+
function flushBatch(ctx) {
|
|
4387
|
+
const batch = ctx.drawBatch;
|
|
4388
|
+
const staged = ctx.batchState;
|
|
4016
4389
|
if (batch.length === 0 || staged === void 0) return;
|
|
4017
4390
|
const gl = ctx.gl;
|
|
4018
|
-
const prog = ctx.
|
|
4391
|
+
const prog = ctx.batchFill;
|
|
4019
4392
|
gl.useProgram(prog.handle);
|
|
4020
4393
|
const indexCount = batch.uploadAndBind();
|
|
4021
4394
|
setProjAndModel(ctx, prog, BATCH_MODEL);
|
|
4022
4395
|
setColorUniform(ctx, prog, 1, 1, 1, 1);
|
|
4023
4396
|
setAlphaUniform(ctx, prog, staged.alpha);
|
|
4397
|
+
gl.uniform1f(prog.uniform("u_synthBold"), staged.synthBold);
|
|
4024
4398
|
setColorMatrixUniforms(ctx, prog, staged.colorMatrix);
|
|
4025
|
-
|
|
4026
|
-
gl.
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
}
|
|
4043
|
-
if (ctx.imageBatch.wouldOverflow()) flushImages(ctx);
|
|
4044
|
-
if (ctx.imageState === void 0) {
|
|
4045
|
-
ctx.imageState = {
|
|
4046
|
-
image,
|
|
4047
|
-
sampling,
|
|
4048
|
-
colorMatrix: ctx.state.colorMatrix,
|
|
4049
|
-
clipDepth: ctx.clipDepth
|
|
4050
|
-
};
|
|
4399
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
4400
|
+
gl.bindTexture(gl.TEXTURE_2D, ctx.whiteTexture);
|
|
4401
|
+
for (let i = 0; i < staged.textures.length; i++) {
|
|
4402
|
+
const entry = staged.textures[i];
|
|
4403
|
+
if (entry.kind === "atlas") {
|
|
4404
|
+
ctx.textureCache.bind(entry.id, i + 1);
|
|
4405
|
+
continue;
|
|
4406
|
+
}
|
|
4407
|
+
if (entry.kind === "ramps") {
|
|
4408
|
+
ctx.gradRamps.bind(i + 1);
|
|
4409
|
+
continue;
|
|
4410
|
+
}
|
|
4411
|
+
ctx.imageCache.bind(entry.image, i + 1);
|
|
4412
|
+
ctx.imageCache.setMagFilter(
|
|
4413
|
+
entry.image,
|
|
4414
|
+
entry.sampling === "nearest" ? gl.NEAREST : gl.LINEAR
|
|
4415
|
+
);
|
|
4051
4416
|
}
|
|
4052
|
-
|
|
4053
|
-
function flushImages(ctx) {
|
|
4054
|
-
const batch = ctx.imageBatch;
|
|
4055
|
-
const staged = ctx.imageState;
|
|
4056
|
-
if (batch.length === 0 || staged === void 0) return;
|
|
4057
|
-
const gl = ctx.gl;
|
|
4058
|
-
const prog = ctx.imageFillVOpacity;
|
|
4059
|
-
gl.useProgram(prog.handle);
|
|
4060
|
-
const indexCount = batch.uploadAndBind();
|
|
4061
|
-
setProjAndModel(ctx, prog, BATCH_MODEL);
|
|
4062
|
-
setAlphaUniform(ctx, prog, 1);
|
|
4063
|
-
setColorMatrixUniforms(ctx, prog, staged.colorMatrix);
|
|
4064
|
-
ctx.imageCache.bind(staged.image, 0);
|
|
4065
|
-
gl.texParameteri(
|
|
4066
|
-
gl.TEXTURE_2D,
|
|
4067
|
-
gl.TEXTURE_MAG_FILTER,
|
|
4068
|
-
staged.sampling === "nearest" ? gl.NEAREST : gl.LINEAR
|
|
4069
|
-
);
|
|
4070
|
-
gl.uniform1i(prog.uniform("u_sampler"), 0);
|
|
4417
|
+
gl.uniform1iv(prog.uniform("u_samplers"), SAMPLER_UNITS);
|
|
4071
4418
|
applyClipTest(ctx, staged.clipDepth);
|
|
4072
4419
|
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_INT, 0);
|
|
4420
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
4073
4421
|
gl.bindVertexArray(null);
|
|
4074
4422
|
batch.reset();
|
|
4075
|
-
ctx.
|
|
4076
|
-
}
|
|
4077
|
-
function flushBatches(ctx) {
|
|
4078
|
-
flushSolids(ctx);
|
|
4079
|
-
flushImages(ctx);
|
|
4423
|
+
ctx.batchState = void 0;
|
|
4080
4424
|
}
|
|
4081
4425
|
function expandAnchorColors(perAnchor, handle) {
|
|
4082
4426
|
const aA = handle.anchorA;
|
|
@@ -4161,8 +4505,9 @@ function paintBindContext(ctx) {
|
|
|
4161
4505
|
setProjAndModel: (prog) => setProjAndModel(ctx, prog),
|
|
4162
4506
|
spaceInverse: (units) => gradientSpaceInverse(ctx, units),
|
|
4163
4507
|
bindRamp: (stops, unit2) => {
|
|
4164
|
-
const
|
|
4165
|
-
ctx.
|
|
4508
|
+
const row = ctx.gradRamps.upload(stops);
|
|
4509
|
+
ctx.gradRamps.bind(unit2);
|
|
4510
|
+
return ctx.gradRamps.rowV(row);
|
|
4166
4511
|
}
|
|
4167
4512
|
};
|
|
4168
4513
|
BIND_CONTEXTS.set(ctx, made);
|
|
@@ -4222,12 +4567,14 @@ function gradientSpaceInverse(ctx, units) {
|
|
|
4222
4567
|
}
|
|
4223
4568
|
function bindPathFillGradient(ctx, fill) {
|
|
4224
4569
|
const gl = ctx.gl;
|
|
4225
|
-
const
|
|
4570
|
+
const row = ctx.gradRamps.upload(fill.stops);
|
|
4226
4571
|
gl.useProgram(ctx.gradFill.handle);
|
|
4227
4572
|
setProjAndModel(ctx, ctx.gradFill);
|
|
4228
4573
|
gl.uniformMatrix3fv(ctx.gradFill.uniform("u_worldInv"), false, gradientSpaceInverse(ctx, fill.units));
|
|
4229
|
-
ctx
|
|
4574
|
+
setColorMatrixUniforms(ctx, ctx.gradFill);
|
|
4575
|
+
ctx.gradRamps.bind(0);
|
|
4230
4576
|
gl.uniform1i(ctx.gradFill.uniform("u_ramp"), 0);
|
|
4577
|
+
gl.uniform1f(ctx.gradFill.uniform("u_rampV"), ctx.gradRamps.rowV(row));
|
|
4231
4578
|
setAlphaUniform(ctx, ctx.gradFill, ctx.state.alpha);
|
|
4232
4579
|
gl.uniform1f(ctx.gradFill.uniform("u_opacity"), fill.opacity ?? 1);
|
|
4233
4580
|
if (fill.fill === "linear-gradient") {
|
|
@@ -4281,7 +4628,7 @@ function rasterizePathToStencil(ctx, path) {
|
|
|
4281
4628
|
gl.bindVertexArray(null);
|
|
4282
4629
|
}
|
|
4283
4630
|
function pushClip(ctx, path, newDepth) {
|
|
4284
|
-
|
|
4631
|
+
flushBatch(ctx);
|
|
4285
4632
|
const gl = ctx.gl;
|
|
4286
4633
|
const ancestors = ancestorMask(newDepth - 1);
|
|
4287
4634
|
const newBit = 1 << newDepth;
|
|
@@ -4296,7 +4643,7 @@ function pushClip(ctx, path, newDepth) {
|
|
|
4296
4643
|
gl.stencilMask(255);
|
|
4297
4644
|
}
|
|
4298
4645
|
function popClip(ctx, path, oldDepth) {
|
|
4299
|
-
|
|
4646
|
+
flushBatch(ctx);
|
|
4300
4647
|
const gl = ctx.gl;
|
|
4301
4648
|
gl.enable(gl.STENCIL_TEST);
|
|
4302
4649
|
const oldBit = 1 << oldDepth + 1;
|
|
@@ -4343,7 +4690,7 @@ function drawPathStroke(ctx, rawCmd) {
|
|
|
4343
4690
|
const stroke = cmd.stroke;
|
|
4344
4691
|
const align = stroke.align ?? "center";
|
|
4345
4692
|
if (cmd.path.kind === "polygon" && align !== "center") {
|
|
4346
|
-
|
|
4693
|
+
flushBatch(ctx);
|
|
4347
4694
|
drawPathStrokeStenciled(ctx, cmd, align);
|
|
4348
4695
|
return;
|
|
4349
4696
|
}
|
|
@@ -4357,7 +4704,7 @@ function drawPathStrokeUnclipped(ctx, cmd) {
|
|
|
4357
4704
|
const mesh = strokeMesh(cmd.path, stroke, ctx.flattenTolerance);
|
|
4358
4705
|
if (mesh.indices.length === 0) return;
|
|
4359
4706
|
const hasVColors = !!(stroke.vertexColors && stroke.vertexColors.length > 0);
|
|
4360
|
-
if (
|
|
4707
|
+
if (tryStageFill(ctx, mesh, batchPaint(ctx, paint, hasVColors))) return;
|
|
4361
4708
|
const handle = hasVColors ? ctx.meshCache.uploadTransient(mesh) : ctx.meshCache.uploadRecurring(mesh);
|
|
4362
4709
|
if (!isSolid && !hasVColors) {
|
|
4363
4710
|
drawPathFillByKind(ctx, paint, handle);
|
|
@@ -4492,28 +4839,9 @@ function drawText(ctx, cmd) {
|
|
|
4492
4839
|
if (laid.groups.length === 0 && laid.decorations.length === 0) return;
|
|
4493
4840
|
const dx = cmd.x;
|
|
4494
4841
|
const dy = cmd.y + verticalAlignOffset(cmd.verticalAlign, cmd.height, laid.bounds.height);
|
|
4495
|
-
const gl = ctx.gl;
|
|
4496
|
-
applyClipTest(ctx);
|
|
4497
|
-
const preparedPrograms = /* @__PURE__ */ new Set();
|
|
4498
|
-
let currentProg = null;
|
|
4499
4842
|
for (const group of laid.groups) {
|
|
4500
|
-
if (group.source === "outline")
|
|
4501
|
-
|
|
4502
|
-
currentProg = null;
|
|
4503
|
-
continue;
|
|
4504
|
-
}
|
|
4505
|
-
const prog = group.source === "canvas" ? ctx.textSdfR8 : ctx.textSdf;
|
|
4506
|
-
if (prog !== currentProg) {
|
|
4507
|
-
gl.useProgram(prog.handle);
|
|
4508
|
-
currentProg = prog;
|
|
4509
|
-
}
|
|
4510
|
-
if (!preparedPrograms.has(prog)) {
|
|
4511
|
-
preparedPrograms.add(prog);
|
|
4512
|
-
setProjAndModel(ctx, prog);
|
|
4513
|
-
setColorMatrixUniforms(ctx, prog);
|
|
4514
|
-
setAlphaUniform(ctx, prog, ctx.state.alpha);
|
|
4515
|
-
}
|
|
4516
|
-
drawTextGroup(ctx, group, prog, dx, dy);
|
|
4843
|
+
if (group.source === "outline") drawTextOutlineGroup(ctx, group, dx, dy);
|
|
4844
|
+
else drawTextGroup(ctx, group, dx, dy);
|
|
4517
4845
|
}
|
|
4518
4846
|
drawTextDecorations(ctx, laid.decorations, dx, dy);
|
|
4519
4847
|
}
|
|
@@ -4522,14 +4850,16 @@ function drawTextOutlineGroup(ctx, group, dx, dy) {
|
|
|
4522
4850
|
const fill = group.fill;
|
|
4523
4851
|
if (fill !== null) {
|
|
4524
4852
|
const mesh = outlineGroupMesh(group, dx, dy);
|
|
4525
|
-
if (mesh)
|
|
4853
|
+
if (mesh) drawOutlineMesh(ctx, fill, mesh);
|
|
4526
4854
|
}
|
|
4527
4855
|
const strokePaint = group.stroke?.paint;
|
|
4528
4856
|
if (!strokePaint) return;
|
|
4529
4857
|
const ribbon = outlineGroupStrokeMesh(group, dx, dy, mat3.meanScaleOf(ctx.state.transform));
|
|
4530
|
-
if (ribbon)
|
|
4531
|
-
|
|
4532
|
-
|
|
4858
|
+
if (ribbon) drawOutlineMesh(ctx, strokePaint, ribbon);
|
|
4859
|
+
}
|
|
4860
|
+
function drawOutlineMesh(ctx, fill, mesh) {
|
|
4861
|
+
if (tryStageFill(ctx, mesh, batchPaint(ctx, fill, false))) return;
|
|
4862
|
+
drawPathFillByKind(ctx, fill, ctx.meshCache.uploadTransient(mesh));
|
|
4533
4863
|
}
|
|
4534
4864
|
function outlineGroupMesh(group, dx, dy) {
|
|
4535
4865
|
return mergeGlyphMeshes(group, dx, dy, (glyph) => outlineMesh(glyph.key, glyph.d));
|
|
@@ -4573,208 +4903,69 @@ function mergeGlyphMeshes(group, dx, dy, meshFor) {
|
|
|
4573
4903
|
return { vertices, indices };
|
|
4574
4904
|
}
|
|
4575
4905
|
function drawTextDecorations(ctx, decorations, dx, dy) {
|
|
4576
|
-
if (decorations.length === 0) return;
|
|
4577
|
-
const batches = /* @__PURE__ */ new Map();
|
|
4578
4906
|
for (const d of decorations) {
|
|
4579
|
-
const
|
|
4580
|
-
const
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
setColorMatrixUniforms(ctx, prog);
|
|
4593
|
-
applyClipTest(ctx);
|
|
4594
|
-
for (const { rgba, rects } of batches.values()) {
|
|
4595
|
-
const floats = rects.length * 4 * 2;
|
|
4596
|
-
if (TEXT_RULE_VERTICES.length < floats) TEXT_RULE_VERTICES = new Float32Array(grownTo(floats));
|
|
4597
|
-
const vertices = TEXT_RULE_VERTICES;
|
|
4598
|
-
let vi = 0;
|
|
4599
|
-
for (const d of rects) {
|
|
4600
|
-
const dx0 = d.x0 + dx, dx1 = d.x1 + dx;
|
|
4601
|
-
const dy0 = d.y0 + dy, dy1 = d.y1 + dy;
|
|
4602
|
-
vertices[vi++] = dx0;
|
|
4603
|
-
vertices[vi++] = dy0;
|
|
4604
|
-
vertices[vi++] = dx1;
|
|
4605
|
-
vertices[vi++] = dy0;
|
|
4606
|
-
vertices[vi++] = dx0;
|
|
4607
|
-
vertices[vi++] = dy1;
|
|
4608
|
-
vertices[vi++] = dx1;
|
|
4609
|
-
vertices[vi++] = dy1;
|
|
4610
|
-
}
|
|
4611
|
-
const ring = textQuadRing(gl, prog, TEXT_RULE_STRIDE, (loc) => {
|
|
4612
|
-
const aPos = loc("a_position");
|
|
4613
|
-
if (aPos !== void 0) {
|
|
4614
|
-
gl.enableVertexAttribArray(aPos);
|
|
4615
|
-
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, TEXT_RULE_STRIDE, 0);
|
|
4616
|
-
}
|
|
4617
|
-
});
|
|
4618
|
-
ensureQuadIndices(gl, ring, rects.length);
|
|
4619
|
-
bindTextQuadSlot(gl, ring, vertices.subarray(0, floats));
|
|
4620
|
-
setColorUniform(ctx, prog, rgba[0], rgba[1], rgba[2], rgba[3]);
|
|
4621
|
-
setAlphaUniform(ctx, prog, ctx.state.alpha);
|
|
4622
|
-
gl.drawElements(gl.TRIANGLES, rects.length * 6, gl.UNSIGNED_INT, 0);
|
|
4623
|
-
gl.bindVertexArray(null);
|
|
4907
|
+
const [r, g, b, a] = "color" in d.fill ? resolveColor(d.fill.color) : [0, 0, 0, 1];
|
|
4908
|
+
const staged = stageSolid(ctx, 4);
|
|
4909
|
+
ctx.drawBatch.pushRect(
|
|
4910
|
+
d.x0 + dx,
|
|
4911
|
+
d.y0 + dy,
|
|
4912
|
+
d.x1 - d.x0,
|
|
4913
|
+
d.y1 - d.y0,
|
|
4914
|
+
ctx.state.transform,
|
|
4915
|
+
r,
|
|
4916
|
+
g,
|
|
4917
|
+
b,
|
|
4918
|
+
a * (staged.foldsAlpha ? ctx.state.alpha : 1)
|
|
4919
|
+
);
|
|
4624
4920
|
}
|
|
4625
4921
|
}
|
|
4626
|
-
|
|
4922
|
+
var SYNTH_BOLD_AMOUNT = 0.08;
|
|
4923
|
+
function drawTextGroup(ctx, group, dx, dy) {
|
|
4627
4924
|
if (group.source === "canvas") {
|
|
4628
4925
|
if (!syncDynamicPageTexture(ctx.textureCache, group.page)) return;
|
|
4629
4926
|
} else {
|
|
4630
4927
|
if (!ensureFontTexture(group.family, group.weight, group.style, ctx.textureCache)) return;
|
|
4631
4928
|
}
|
|
4632
4929
|
if (group.quads.length === 0) return;
|
|
4633
|
-
const
|
|
4634
|
-
const
|
|
4635
|
-
|
|
4636
|
-
const
|
|
4637
|
-
|
|
4930
|
+
const atlasId = group.source === "canvas" ? dynamicPageTextureId(group.page) : textureCacheKey(group.family, group.weight, group.style);
|
|
4931
|
+
const mode = group.source === "canvas" ? GLYPH_MODE_R8 : GLYPH_MODE_MSDF;
|
|
4932
|
+
const bold = group.synthetic.bold ? SYNTH_BOLD_AMOUNT : 0;
|
|
4933
|
+
const tanItalic = group.synthetic.italic ? Math.tan(SYNTHETIC_ITALIC_RADIANS) : 0;
|
|
4934
|
+
const color = group.fill !== null && "color" in group.fill ? resolveColor(group.fill.color) : [0, 0, 0, 1];
|
|
4935
|
+
const batch = ctx.drawBatch;
|
|
4936
|
+
const m = ctx.state.transform;
|
|
4937
|
+
let { staged, slot } = stageGlyphs(ctx, atlasId, bold);
|
|
4938
|
+
let alpha = color[3] * (staged.foldsAlpha ? ctx.state.alpha : 1);
|
|
4638
4939
|
for (const q of group.quads) {
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
const aUv = loc("a_uv");
|
|
4665
|
-
const aBase = loc("a_baselineY");
|
|
4666
|
-
if (aPos !== void 0) {
|
|
4667
|
-
gl.enableVertexAttribArray(aPos);
|
|
4668
|
-
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, TEXT_GROUP_STRIDE, 0);
|
|
4669
|
-
}
|
|
4670
|
-
if (aUv !== void 0) {
|
|
4671
|
-
gl.enableVertexAttribArray(aUv);
|
|
4672
|
-
gl.vertexAttribPointer(aUv, 2, gl.FLOAT, false, TEXT_GROUP_STRIDE, 8);
|
|
4673
|
-
}
|
|
4674
|
-
if (aBase !== void 0) {
|
|
4675
|
-
gl.enableVertexAttribArray(aBase);
|
|
4676
|
-
gl.vertexAttribPointer(aBase, 1, gl.FLOAT, false, TEXT_GROUP_STRIDE, 16);
|
|
4677
|
-
}
|
|
4678
|
-
});
|
|
4679
|
-
ensureQuadIndices(gl, ring, group.quads.length);
|
|
4680
|
-
bindTextQuadSlot(gl, ring, vertices.subarray(0, floats));
|
|
4681
|
-
let r = 0, g = 0, b = 0, a = 1;
|
|
4682
|
-
if (group.fill !== null && "color" in group.fill) {
|
|
4683
|
-
[r, g, b, a] = resolveColor(group.fill.color);
|
|
4684
|
-
}
|
|
4685
|
-
setColorUniform(ctx, prog, r, g, b, a);
|
|
4686
|
-
const synthBoldAmount = group.synthetic.bold ? 0.08 : 0;
|
|
4687
|
-
const uSynthBold = prog.uniform("u_synthBold");
|
|
4688
|
-
if (uSynthBold !== void 0) gl.uniform1f(uSynthBold, synthBoldAmount);
|
|
4689
|
-
const synthItalicAmount = group.synthetic.italic ? SYNTHETIC_ITALIC_RADIANS : 0;
|
|
4690
|
-
const uSynthItalic = prog.uniform("u_synthItalic");
|
|
4691
|
-
if (uSynthItalic !== void 0) gl.uniform1f(uSynthItalic, synthItalicAmount);
|
|
4692
|
-
const texId = group.source === "canvas" ? dynamicPageTextureId(group.page) : textureCacheKey(group.family, group.weight, group.style);
|
|
4693
|
-
ctx.textureCache.bind(texId, 0);
|
|
4694
|
-
gl.uniform1i(prog.uniform("u_atlas"), 0);
|
|
4695
|
-
gl.drawElements(gl.TRIANGLES, group.quads.length * 6, gl.UNSIGNED_INT, 0);
|
|
4696
|
-
gl.bindVertexArray(null);
|
|
4697
|
-
}
|
|
4698
|
-
var TEXT_QUAD_RING_SIZE = 64;
|
|
4699
|
-
var TEXT_QUAD_RINGS = /* @__PURE__ */ new WeakMap();
|
|
4700
|
-
function grownTo(need) {
|
|
4701
|
-
let n = 256;
|
|
4702
|
-
while (n < need) n *= 2;
|
|
4703
|
-
return n;
|
|
4704
|
-
}
|
|
4705
|
-
function textQuadRing(gl, prog, stride, configureAttribs) {
|
|
4706
|
-
const existing = TEXT_QUAD_RINGS.get(prog);
|
|
4707
|
-
if (existing) return existing;
|
|
4708
|
-
const ibo = gl.createBuffer();
|
|
4709
|
-
if (!ibo) throw new Error("textQuadRing: createBuffer (IBO) returned null");
|
|
4710
|
-
const slots = [];
|
|
4711
|
-
for (let i = 0; i < TEXT_QUAD_RING_SIZE; i++) {
|
|
4712
|
-
const vao = gl.createVertexArray();
|
|
4713
|
-
const vbo = gl.createBuffer();
|
|
4714
|
-
if (!vao) throw new Error("textQuadRing: createVertexArray returned null");
|
|
4715
|
-
if (!vbo) throw new Error("textQuadRing: createBuffer returned null");
|
|
4716
|
-
const bytes = grownTo(64 * 4 * stride);
|
|
4717
|
-
gl.bindVertexArray(vao);
|
|
4718
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
4719
|
-
gl.bufferData(gl.ARRAY_BUFFER, bytes, gl.DYNAMIC_DRAW);
|
|
4720
|
-
configureAttribs((name) => prog.attribute(name));
|
|
4721
|
-
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
4722
|
-
gl.bindVertexArray(null);
|
|
4723
|
-
slots.push({ vao, vbo, bytes });
|
|
4724
|
-
}
|
|
4725
|
-
const ring = { slots, ibo, quads: 0, next: 0 };
|
|
4726
|
-
TEXT_QUAD_RINGS.set(prog, ring);
|
|
4727
|
-
return ring;
|
|
4728
|
-
}
|
|
4729
|
-
var TEXT_QUAD_INDICES = new Uint32Array(0);
|
|
4730
|
-
var TEXT_GROUP_STRIDE = 20;
|
|
4731
|
-
var TEXT_RULE_STRIDE = 8;
|
|
4732
|
-
var TEXT_GROUP_VERTICES = new Float32Array(0);
|
|
4733
|
-
var TEXT_RULE_VERTICES = new Float32Array(0);
|
|
4734
|
-
function ensureQuadIndices(gl, ring, quads) {
|
|
4735
|
-
if (quads <= ring.quads) return;
|
|
4736
|
-
const grown = grownTo(quads);
|
|
4737
|
-
if (TEXT_QUAD_INDICES.length < grown * 6) TEXT_QUAD_INDICES = new Uint32Array(grown * 6);
|
|
4738
|
-
const idx = TEXT_QUAD_INDICES;
|
|
4739
|
-
let ii = ring.quads * 6;
|
|
4740
|
-
for (let q = ring.quads; q < grown; q++) {
|
|
4741
|
-
const base = q * 4;
|
|
4742
|
-
idx[ii++] = base;
|
|
4743
|
-
idx[ii++] = base + 1;
|
|
4744
|
-
idx[ii++] = base + 2;
|
|
4745
|
-
idx[ii++] = base + 1;
|
|
4746
|
-
idx[ii++] = base + 3;
|
|
4747
|
-
idx[ii++] = base + 2;
|
|
4748
|
-
}
|
|
4749
|
-
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ring.ibo);
|
|
4750
|
-
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, idx.subarray(0, grown * 6), gl.STATIC_DRAW);
|
|
4751
|
-
ring.quads = grown;
|
|
4752
|
-
}
|
|
4753
|
-
function bindTextQuadSlot(gl, ring, vertices) {
|
|
4754
|
-
const slot = ring.slots[ring.next];
|
|
4755
|
-
ring.next = (ring.next + 1) % TEXT_QUAD_RING_SIZE;
|
|
4756
|
-
gl.bindVertexArray(slot.vao);
|
|
4757
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, slot.vbo);
|
|
4758
|
-
const bytes = vertices.byteLength;
|
|
4759
|
-
if (bytes > slot.bytes) {
|
|
4760
|
-
slot.bytes = grownTo(bytes);
|
|
4761
|
-
gl.bufferData(gl.ARRAY_BUFFER, slot.bytes, gl.DYNAMIC_DRAW);
|
|
4762
|
-
}
|
|
4763
|
-
gl.bufferSubData(gl.ARRAY_BUFFER, 0, vertices);
|
|
4764
|
-
}
|
|
4765
|
-
function disposeTextQuads(gl, prog) {
|
|
4766
|
-
const ring = TEXT_QUAD_RINGS.get(prog);
|
|
4767
|
-
if (!ring) return;
|
|
4768
|
-
for (const slot of ring.slots) {
|
|
4769
|
-
gl.deleteVertexArray(slot.vao);
|
|
4770
|
-
gl.deleteBuffer(slot.vbo);
|
|
4771
|
-
}
|
|
4772
|
-
gl.deleteBuffer(ring.ibo);
|
|
4773
|
-
TEXT_QUAD_RINGS.delete(prog);
|
|
4940
|
+
if (batch.wouldOverflow(4)) {
|
|
4941
|
+
flushBatch(ctx);
|
|
4942
|
+
({ staged, slot } = stageGlyphs(ctx, atlasId, bold));
|
|
4943
|
+
alpha = color[3] * (staged.foldsAlpha ? ctx.state.alpha : 1);
|
|
4944
|
+
}
|
|
4945
|
+
batch.pushGlyph(
|
|
4946
|
+
q.x0 + dx,
|
|
4947
|
+
q.y0 + dy,
|
|
4948
|
+
q.x1 + dx,
|
|
4949
|
+
q.y1 + dy,
|
|
4950
|
+
q.baselineY + dy,
|
|
4951
|
+
tanItalic,
|
|
4952
|
+
m,
|
|
4953
|
+
q.u0,
|
|
4954
|
+
q.v0,
|
|
4955
|
+
q.u1,
|
|
4956
|
+
q.v1,
|
|
4957
|
+
color[0],
|
|
4958
|
+
color[1],
|
|
4959
|
+
color[2],
|
|
4960
|
+
alpha,
|
|
4961
|
+
slot,
|
|
4962
|
+
mode
|
|
4963
|
+
);
|
|
4964
|
+
}
|
|
4774
4965
|
}
|
|
4775
4966
|
function drawImage(ctx, cmd) {
|
|
4776
4967
|
ctx.imageCache.upload(cmd.image, cmd.image);
|
|
4777
|
-
stageImage(ctx, cmd.image, cmd.sampling ?? "linear");
|
|
4968
|
+
const { staged, slot } = stageImage(ctx, cmd.image, cmd.sampling ?? "linear");
|
|
4778
4969
|
const src = cmd.source;
|
|
4779
4970
|
let u0 = 0, v0 = 0, u1 = 1, v1 = 1;
|
|
4780
4971
|
if (src) {
|
|
@@ -4794,7 +4985,7 @@ function drawImage(ctx, cmd) {
|
|
|
4794
4985
|
v0 = v1;
|
|
4795
4986
|
v1 = t;
|
|
4796
4987
|
}
|
|
4797
|
-
ctx.
|
|
4988
|
+
ctx.drawBatch.pushQuad(
|
|
4798
4989
|
cmd.x,
|
|
4799
4990
|
cmd.y,
|
|
4800
4991
|
cmd.w,
|
|
@@ -4804,7 +4995,11 @@ function drawImage(ctx, cmd) {
|
|
|
4804
4995
|
v0,
|
|
4805
4996
|
u1,
|
|
4806
4997
|
v1,
|
|
4807
|
-
|
|
4998
|
+
// Group alpha rides the vertices only where it rode the solid colors too:
|
|
4999
|
+
// with a real color matrix in the run it is `u_alpha`, and folding it here
|
|
5000
|
+
// as well would apply it twice.
|
|
5001
|
+
(cmd.opacity ?? 1) * (staged.foldsAlpha ? ctx.state.alpha : 1),
|
|
5002
|
+
slot
|
|
4808
5003
|
);
|
|
4809
5004
|
}
|
|
4810
5005
|
function drawSprites(ctx, cmd) {
|
|
@@ -4813,16 +5008,17 @@ function drawSprites(ctx, cmd) {
|
|
|
4813
5008
|
if (count === 0) return;
|
|
4814
5009
|
ctx.imageCache.upload(cmd.image, cmd.image);
|
|
4815
5010
|
const sampling = cmd.sampling ?? "linear";
|
|
4816
|
-
stageImage(ctx, cmd.image, sampling);
|
|
4817
|
-
const batch = ctx.
|
|
5011
|
+
let { staged, slot } = stageImage(ctx, cmd.image, sampling);
|
|
5012
|
+
const batch = ctx.drawBatch;
|
|
4818
5013
|
const m = ctx.state.transform;
|
|
4819
|
-
|
|
5014
|
+
let groupAlpha = staged.foldsAlpha ? ctx.state.alpha : 1;
|
|
4820
5015
|
const tw = cmd.image.width;
|
|
4821
5016
|
const th = cmd.image.height;
|
|
4822
5017
|
for (let s = 0, i = 0; s < count; s++, i += SPRITE_STRIDE) {
|
|
4823
|
-
if (batch.wouldOverflow()) {
|
|
4824
|
-
|
|
4825
|
-
stageImage(ctx, cmd.image, sampling);
|
|
5018
|
+
if (batch.wouldOverflow(4)) {
|
|
5019
|
+
flushBatch(ctx);
|
|
5020
|
+
({ staged, slot } = stageImage(ctx, cmd.image, sampling));
|
|
5021
|
+
groupAlpha = staged.foldsAlpha ? ctx.state.alpha : 1;
|
|
4826
5022
|
}
|
|
4827
5023
|
const sx = data[i + 4], sy = data[i + 5], sw = data[i + 6], sh = data[i + 7];
|
|
4828
5024
|
batch.pushQuad(
|
|
@@ -4835,7 +5031,8 @@ function drawSprites(ctx, cmd) {
|
|
|
4835
5031
|
sy / th,
|
|
4836
5032
|
(sx + sw) / tw,
|
|
4837
5033
|
(sy + sh) / th,
|
|
4838
|
-
data[i + 8] * groupAlpha
|
|
5034
|
+
data[i + 8] * groupAlpha,
|
|
5035
|
+
slot
|
|
4839
5036
|
);
|
|
4840
5037
|
}
|
|
4841
5038
|
}
|
|
@@ -4997,21 +5194,21 @@ var WeaselRenderer = class {
|
|
|
4997
5194
|
gl;
|
|
4998
5195
|
pathFill;
|
|
4999
5196
|
pathFillVColor;
|
|
5000
|
-
textSdf;
|
|
5001
|
-
textSdfR8;
|
|
5002
5197
|
imageFill;
|
|
5003
|
-
|
|
5198
|
+
batchFill;
|
|
5004
5199
|
gradFill;
|
|
5005
5200
|
patternFill;
|
|
5006
5201
|
meshCache;
|
|
5007
5202
|
textureCache;
|
|
5008
5203
|
imageCache;
|
|
5009
|
-
|
|
5204
|
+
gradRamps;
|
|
5010
5205
|
programRegistry = /* @__PURE__ */ new Map();
|
|
5011
5206
|
quadVbo = null;
|
|
5012
5207
|
quadIbo = null;
|
|
5013
|
-
|
|
5014
|
-
|
|
5208
|
+
drawBatch;
|
|
5209
|
+
/** 1x1 white, so a batch flush sampling no image still samples something —
|
|
5210
|
+
* see `shaders/batchFill.ts`. */
|
|
5211
|
+
whiteTexture = null;
|
|
5015
5212
|
groupState = new GroupState();
|
|
5016
5213
|
widthCss;
|
|
5017
5214
|
heightCss;
|
|
@@ -5071,22 +5268,12 @@ var WeaselRenderer = class {
|
|
|
5071
5268
|
this.pathFillVColor = new ShaderProgram(this.gl, VCOLOR_VERT_SRC, VCOLOR_FRAG_SRC);
|
|
5072
5269
|
this.pathFillVColor.lookupUniforms(PATH_FILL_UNIFORMS);
|
|
5073
5270
|
this.pathFillVColor.lookupAttributes(PATH_FILL_VCOLOR_ATTRIBUTES);
|
|
5074
|
-
this.textSdf = new ShaderProgram(this.gl, TEXT_VERT_SRC, TEXT_FRAG_SRC);
|
|
5075
|
-
this.textSdf.lookupUniforms(TEXT_SDF_UNIFORMS);
|
|
5076
|
-
this.textSdf.lookupAttributes(TEXT_SDF_ATTRIBUTES);
|
|
5077
|
-
this.textSdfR8 = new ShaderProgram(this.gl, TEXT_VERT_SRC, TEXT_FRAG_R8_SRC);
|
|
5078
|
-
this.textSdfR8.lookupUniforms(TEXT_SDF_UNIFORMS);
|
|
5079
|
-
this.textSdfR8.lookupAttributes(TEXT_SDF_ATTRIBUTES);
|
|
5080
5271
|
this.imageFill = new ShaderProgram(this.gl, IMAGE_VERT_SRC, IMAGE_FRAG_SRC);
|
|
5081
5272
|
this.imageFill.lookupUniforms(IMAGE_FILL_UNIFORMS);
|
|
5082
5273
|
this.imageFill.lookupAttributes(IMAGE_FILL_ATTRIBUTES);
|
|
5083
|
-
this.
|
|
5084
|
-
|
|
5085
|
-
|
|
5086
|
-
IMAGE_VOPACITY_FRAG_SRC
|
|
5087
|
-
);
|
|
5088
|
-
this.imageFillVOpacity.lookupUniforms(IMAGE_VOPACITY_UNIFORMS);
|
|
5089
|
-
this.imageFillVOpacity.lookupAttributes(IMAGE_VOPACITY_ATTRIBUTES);
|
|
5274
|
+
this.batchFill = new ShaderProgram(this.gl, BATCH_VERT_SRC, BATCH_FRAG_SRC);
|
|
5275
|
+
this.batchFill.lookupUniforms(BATCH_FILL_UNIFORMS);
|
|
5276
|
+
this.batchFill.lookupAttributes(BATCH_FILL_ATTRIBUTES);
|
|
5090
5277
|
this.gradFill = new ShaderProgram(this.gl, GRAD_VERT_SRC, GRAD_FRAG_SRC);
|
|
5091
5278
|
this.gradFill.lookupUniforms(GRAD_FILL_UNIFORMS);
|
|
5092
5279
|
this.gradFill.lookupAttributes(GRAD_FILL_ATTRIBUTES);
|
|
@@ -5098,10 +5285,10 @@ var WeaselRenderer = class {
|
|
|
5098
5285
|
this.meshCache = new GLMeshCache(this.gl, aPos);
|
|
5099
5286
|
this.textureCache = new GLTextureCache(this.gl);
|
|
5100
5287
|
this.imageCache = new GLImageCache(this.gl, this.imageMinification);
|
|
5101
|
-
this.
|
|
5288
|
+
this.gradRamps = new GradientRampAtlas(this.gl);
|
|
5102
5289
|
this.uploadQuadGeometry();
|
|
5103
|
-
this.
|
|
5104
|
-
this.
|
|
5290
|
+
this.drawBatch = new DrawBatch(this.gl, this.batchFill);
|
|
5291
|
+
this.whiteTexture = createWhiteTexture(this.gl);
|
|
5105
5292
|
}
|
|
5106
5293
|
uploadQuadGeometry() {
|
|
5107
5294
|
const gl = this.gl;
|
|
@@ -5217,22 +5404,12 @@ var WeaselRenderer = class {
|
|
|
5217
5404
|
this.pathFillVColor = new ShaderProgram(this.gl, VCOLOR_VERT_SRC, VCOLOR_FRAG_SRC);
|
|
5218
5405
|
this.pathFillVColor.lookupUniforms(PATH_FILL_UNIFORMS);
|
|
5219
5406
|
this.pathFillVColor.lookupAttributes(PATH_FILL_VCOLOR_ATTRIBUTES);
|
|
5220
|
-
this.textSdf = new ShaderProgram(this.gl, TEXT_VERT_SRC, TEXT_FRAG_SRC);
|
|
5221
|
-
this.textSdf.lookupUniforms(TEXT_SDF_UNIFORMS);
|
|
5222
|
-
this.textSdf.lookupAttributes(TEXT_SDF_ATTRIBUTES);
|
|
5223
|
-
this.textSdfR8 = new ShaderProgram(this.gl, TEXT_VERT_SRC, TEXT_FRAG_R8_SRC);
|
|
5224
|
-
this.textSdfR8.lookupUniforms(TEXT_SDF_UNIFORMS);
|
|
5225
|
-
this.textSdfR8.lookupAttributes(TEXT_SDF_ATTRIBUTES);
|
|
5226
5407
|
this.imageFill = new ShaderProgram(this.gl, IMAGE_VERT_SRC, IMAGE_FRAG_SRC);
|
|
5227
5408
|
this.imageFill.lookupUniforms(IMAGE_FILL_UNIFORMS);
|
|
5228
5409
|
this.imageFill.lookupAttributes(IMAGE_FILL_ATTRIBUTES);
|
|
5229
|
-
this.
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
IMAGE_VOPACITY_FRAG_SRC
|
|
5233
|
-
);
|
|
5234
|
-
this.imageFillVOpacity.lookupUniforms(IMAGE_VOPACITY_UNIFORMS);
|
|
5235
|
-
this.imageFillVOpacity.lookupAttributes(IMAGE_VOPACITY_ATTRIBUTES);
|
|
5410
|
+
this.batchFill = new ShaderProgram(this.gl, BATCH_VERT_SRC, BATCH_FRAG_SRC);
|
|
5411
|
+
this.batchFill.lookupUniforms(BATCH_FILL_UNIFORMS);
|
|
5412
|
+
this.batchFill.lookupAttributes(BATCH_FILL_ATTRIBUTES);
|
|
5236
5413
|
this.gradFill = new ShaderProgram(this.gl, GRAD_VERT_SRC, GRAD_FRAG_SRC);
|
|
5237
5414
|
this.gradFill.lookupUniforms(GRAD_FILL_UNIFORMS);
|
|
5238
5415
|
this.gradFill.lookupAttributes(GRAD_FILL_ATTRIBUTES);
|
|
@@ -5244,11 +5421,11 @@ var WeaselRenderer = class {
|
|
|
5244
5421
|
this.meshCache = new GLMeshCache(this.gl, aPos);
|
|
5245
5422
|
this.textureCache = new GLTextureCache(this.gl);
|
|
5246
5423
|
this.imageCache = new GLImageCache(this.gl, this.imageMinification);
|
|
5247
|
-
this.
|
|
5424
|
+
this.gradRamps = new GradientRampAtlas(this.gl);
|
|
5248
5425
|
markAllFontsNotUploaded();
|
|
5249
5426
|
this.uploadQuadGeometry();
|
|
5250
|
-
this.
|
|
5251
|
-
this.
|
|
5427
|
+
this.drawBatch = new DrawBatch(this.gl, this.batchFill);
|
|
5428
|
+
this.whiteTexture = createWhiteTexture(this.gl);
|
|
5252
5429
|
for (const id of this.programRegistry.keys()) {
|
|
5253
5430
|
const src = getProgramSource(id);
|
|
5254
5431
|
if (!src) continue;
|
|
@@ -5269,7 +5446,7 @@ var WeaselRenderer = class {
|
|
|
5269
5446
|
* Scope: built-in shader programs, any consumer-registered programs, the
|
|
5270
5447
|
* shared quad/rect geometry, any in-flight transient meshes, and the
|
|
5271
5448
|
* enumerable Map-keyed caches (`GLTextureCache` atlas/image textures,
|
|
5272
|
-
* `
|
|
5449
|
+
* `GradientRampAtlas`'s ramp texture) ARE freed.
|
|
5273
5450
|
*
|
|
5274
5451
|
* NOT freed: `GLImageCache` (bitmap/pattern textures) and `GLMeshCache`'s
|
|
5275
5452
|
* persistent per-Path mesh cache are keyed by `WeakMap`, not enumerable,
|
|
@@ -5297,7 +5474,7 @@ var WeaselRenderer = class {
|
|
|
5297
5474
|
}
|
|
5298
5475
|
this.meshCache.freeTransient();
|
|
5299
5476
|
this.meshCache.drainPendingDeletes();
|
|
5300
|
-
for (const prog of [this.pathFill, this.pathFillVColor, this.
|
|
5477
|
+
for (const prog of [this.pathFill, this.pathFillVColor, this.imageFill, this.batchFill, this.gradFill, this.patternFill]) {
|
|
5301
5478
|
gl.deleteProgram(prog.handle);
|
|
5302
5479
|
}
|
|
5303
5480
|
for (const prog of this.programRegistry.values()) {
|
|
@@ -5305,12 +5482,12 @@ var WeaselRenderer = class {
|
|
|
5305
5482
|
}
|
|
5306
5483
|
this.programRegistry.clear();
|
|
5307
5484
|
this.textureCache.free();
|
|
5308
|
-
this.
|
|
5485
|
+
this.gradRamps.free();
|
|
5309
5486
|
if (this.quadVbo) gl.deleteBuffer(this.quadVbo);
|
|
5310
5487
|
if (this.quadIbo) gl.deleteBuffer(this.quadIbo);
|
|
5311
|
-
|
|
5312
|
-
this.
|
|
5313
|
-
this.
|
|
5488
|
+
this.drawBatch.dispose();
|
|
5489
|
+
if (this.whiteTexture) gl.deleteTexture(this.whiteTexture);
|
|
5490
|
+
this.whiteTexture = null;
|
|
5314
5491
|
this.effectTargets.releaseAll();
|
|
5315
5492
|
}
|
|
5316
5493
|
/**
|
|
@@ -5337,22 +5514,20 @@ var WeaselRenderer = class {
|
|
|
5337
5514
|
gl,
|
|
5338
5515
|
pathFill: this.pathFill,
|
|
5339
5516
|
pathFillVColor: this.pathFillVColor,
|
|
5340
|
-
textSdf: this.textSdf,
|
|
5341
|
-
textSdfR8: this.textSdfR8,
|
|
5342
5517
|
imageFill: this.imageFill,
|
|
5343
|
-
|
|
5518
|
+
batchFill: this.batchFill,
|
|
5344
5519
|
gradFill: this.gradFill,
|
|
5345
5520
|
patternFill: this.patternFill,
|
|
5346
5521
|
meshCache: this.meshCache,
|
|
5347
5522
|
textureCache: this.textureCache,
|
|
5348
5523
|
imageCache: this.imageCache,
|
|
5349
|
-
|
|
5524
|
+
gradRamps: this.gradRamps,
|
|
5350
5525
|
programRegistry: this.programRegistry,
|
|
5351
5526
|
ensureProgram: (id) => this.ensureProgram(id),
|
|
5352
5527
|
quadVbo: this.quadVbo,
|
|
5353
5528
|
quadIbo: this.quadIbo,
|
|
5354
|
-
|
|
5355
|
-
|
|
5529
|
+
drawBatch: this.drawBatch,
|
|
5530
|
+
whiteTexture: this.whiteTexture,
|
|
5356
5531
|
state: this.groupState,
|
|
5357
5532
|
widthCss: this.widthCss,
|
|
5358
5533
|
heightCss: this.heightCss,
|
|
@@ -5367,7 +5542,7 @@ var WeaselRenderer = class {
|
|
|
5367
5542
|
restoreTargetRect: () => this.applyTarget()
|
|
5368
5543
|
};
|
|
5369
5544
|
for (const cmd of commands) dispatch(ctx, cmd);
|
|
5370
|
-
|
|
5545
|
+
flushBatch(ctx);
|
|
5371
5546
|
this.meshCache.freeTransient();
|
|
5372
5547
|
}
|
|
5373
5548
|
resize(dims) {
|
|
@@ -5397,28 +5572,16 @@ var WeaselRenderer = class {
|
|
|
5397
5572
|
return this.pathFillVColor;
|
|
5398
5573
|
}
|
|
5399
5574
|
/** @internal */
|
|
5400
|
-
|
|
5401
|
-
return this.
|
|
5402
|
-
}
|
|
5403
|
-
/** @internal */
|
|
5404
|
-
_imageBatch() {
|
|
5405
|
-
return this.imageBatch;
|
|
5406
|
-
}
|
|
5407
|
-
/** @internal */
|
|
5408
|
-
_textSdf() {
|
|
5409
|
-
return this.textSdf;
|
|
5410
|
-
}
|
|
5411
|
-
/** @internal */
|
|
5412
|
-
_textSdfR8() {
|
|
5413
|
-
return this.textSdfR8;
|
|
5575
|
+
_drawBatch() {
|
|
5576
|
+
return this.drawBatch;
|
|
5414
5577
|
}
|
|
5415
5578
|
/** @internal */
|
|
5416
5579
|
_imageFill() {
|
|
5417
5580
|
return this.imageFill;
|
|
5418
5581
|
}
|
|
5419
5582
|
/** @internal */
|
|
5420
|
-
|
|
5421
|
-
return this.
|
|
5583
|
+
_batchFill() {
|
|
5584
|
+
return this.batchFill;
|
|
5422
5585
|
}
|
|
5423
5586
|
/** @internal */
|
|
5424
5587
|
_gradFill() {
|
|
@@ -5441,8 +5604,8 @@ var WeaselRenderer = class {
|
|
|
5441
5604
|
return this.imageCache;
|
|
5442
5605
|
}
|
|
5443
5606
|
/** @internal */
|
|
5444
|
-
|
|
5445
|
-
return this.
|
|
5607
|
+
_gradRamps() {
|
|
5608
|
+
return this.gradRamps;
|
|
5446
5609
|
}
|
|
5447
5610
|
/** @internal */
|
|
5448
5611
|
_groupState() {
|
|
@@ -5461,6 +5624,28 @@ var WeaselRenderer = class {
|
|
|
5461
5624
|
return this.dpr;
|
|
5462
5625
|
}
|
|
5463
5626
|
};
|
|
5627
|
+
function createWhiteTexture(gl) {
|
|
5628
|
+
const tex = gl.createTexture();
|
|
5629
|
+
if (!tex) return null;
|
|
5630
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
5631
|
+
gl.texImage2D(
|
|
5632
|
+
gl.TEXTURE_2D,
|
|
5633
|
+
0,
|
|
5634
|
+
gl.RGBA,
|
|
5635
|
+
1,
|
|
5636
|
+
1,
|
|
5637
|
+
0,
|
|
5638
|
+
gl.RGBA,
|
|
5639
|
+
gl.UNSIGNED_BYTE,
|
|
5640
|
+
new Uint8Array([255, 255, 255, 255])
|
|
5641
|
+
);
|
|
5642
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
5643
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
5644
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
5645
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
5646
|
+
gl.bindTexture(gl.TEXTURE_2D, null);
|
|
5647
|
+
return tex;
|
|
5648
|
+
}
|
|
5464
5649
|
|
|
5465
5650
|
// src/renderer/spriteSheet.ts
|
|
5466
5651
|
function frameRect(sheet, index) {
|
|
@@ -5940,6 +6125,109 @@ function createParallaxLayer(opts) {
|
|
|
5940
6125
|
}
|
|
5941
6126
|
};
|
|
5942
6127
|
}
|
|
6128
|
+
|
|
6129
|
+
// src/features/simulation/types.ts
|
|
6130
|
+
var DEFAULT_ALPHA_DECAY = 1 - Math.pow(1e-3, 1 / 300);
|
|
6131
|
+
var DEFAULT_ALPHA_MIN = 1e-3;
|
|
6132
|
+
var DEFAULT_VELOCITY_DECAY = 0.4;
|
|
6133
|
+
|
|
6134
|
+
// src/features/simulation/createSimulation.ts
|
|
6135
|
+
function createSimulation(opts) {
|
|
6136
|
+
let nodes = opts.nodes;
|
|
6137
|
+
let forces = opts.forces ?? [];
|
|
6138
|
+
let alpha = opts.alpha ?? 1;
|
|
6139
|
+
let alphaMin = opts.alphaMin ?? DEFAULT_ALPHA_MIN;
|
|
6140
|
+
let alphaDecay = opts.alphaDecay ?? DEFAULT_ALPHA_DECAY;
|
|
6141
|
+
let alphaTarget = opts.alphaTarget ?? 0;
|
|
6142
|
+
let velocityDecay = opts.velocityDecay ?? DEFAULT_VELOCITY_DECAY;
|
|
6143
|
+
const random = opts.random ?? Math.random;
|
|
6144
|
+
function prime(list) {
|
|
6145
|
+
list.forEach((n, i) => {
|
|
6146
|
+
n.index = i;
|
|
6147
|
+
if (n.vx == null) n.vx = 0;
|
|
6148
|
+
if (n.vy == null) n.vy = 0;
|
|
6149
|
+
});
|
|
6150
|
+
}
|
|
6151
|
+
prime(nodes);
|
|
6152
|
+
for (const f of forces) f.initialize?.(nodes, random);
|
|
6153
|
+
function step() {
|
|
6154
|
+
alpha += (alphaTarget - alpha) * alphaDecay;
|
|
6155
|
+
for (const f of forces) f(alpha);
|
|
6156
|
+
const friction = 1 - velocityDecay;
|
|
6157
|
+
for (const n of nodes) {
|
|
6158
|
+
if (n.fx == null) {
|
|
6159
|
+
n.vx = (n.vx ?? 0) * friction;
|
|
6160
|
+
if (!Number.isFinite(n.vx)) n.vx = 0;
|
|
6161
|
+
n.x += n.vx;
|
|
6162
|
+
if (!Number.isFinite(n.x)) n.x = 0;
|
|
6163
|
+
} else {
|
|
6164
|
+
n.x = n.fx;
|
|
6165
|
+
n.vx = 0;
|
|
6166
|
+
}
|
|
6167
|
+
if (n.fy == null) {
|
|
6168
|
+
n.vy = (n.vy ?? 0) * friction;
|
|
6169
|
+
if (!Number.isFinite(n.vy)) n.vy = 0;
|
|
6170
|
+
n.y += n.vy;
|
|
6171
|
+
if (!Number.isFinite(n.y)) n.y = 0;
|
|
6172
|
+
} else {
|
|
6173
|
+
n.y = n.fy;
|
|
6174
|
+
n.vy = 0;
|
|
6175
|
+
}
|
|
6176
|
+
}
|
|
6177
|
+
}
|
|
6178
|
+
const core = {
|
|
6179
|
+
get nodes() {
|
|
6180
|
+
return nodes;
|
|
6181
|
+
},
|
|
6182
|
+
setNodes(next) {
|
|
6183
|
+
nodes = next;
|
|
6184
|
+
prime(nodes);
|
|
6185
|
+
for (const f of forces) f.initialize?.(nodes, random);
|
|
6186
|
+
return core;
|
|
6187
|
+
},
|
|
6188
|
+
setForces(next) {
|
|
6189
|
+
const old = forces;
|
|
6190
|
+
forces = next;
|
|
6191
|
+
for (const f of next) {
|
|
6192
|
+
if (!old.includes(f)) f.initialize?.(nodes, random);
|
|
6193
|
+
}
|
|
6194
|
+
return core;
|
|
6195
|
+
},
|
|
6196
|
+
alpha(value) {
|
|
6197
|
+
if (value === void 0) return alpha;
|
|
6198
|
+
alpha = value;
|
|
6199
|
+
return core;
|
|
6200
|
+
},
|
|
6201
|
+
alphaTarget(value) {
|
|
6202
|
+
if (value === void 0) return alphaTarget;
|
|
6203
|
+
alphaTarget = value;
|
|
6204
|
+
return core;
|
|
6205
|
+
},
|
|
6206
|
+
alphaDecay(value) {
|
|
6207
|
+
if (value === void 0) return alphaDecay;
|
|
6208
|
+
alphaDecay = value;
|
|
6209
|
+
return core;
|
|
6210
|
+
},
|
|
6211
|
+
alphaMin(value) {
|
|
6212
|
+
if (value === void 0) return alphaMin;
|
|
6213
|
+
alphaMin = value;
|
|
6214
|
+
return core;
|
|
6215
|
+
},
|
|
6216
|
+
velocityDecay(value) {
|
|
6217
|
+
if (value === void 0) return velocityDecay;
|
|
6218
|
+
velocityDecay = value;
|
|
6219
|
+
return core;
|
|
6220
|
+
},
|
|
6221
|
+
tick(iterations = 1) {
|
|
6222
|
+
for (let i = 0; i < iterations; i++) step();
|
|
6223
|
+
return core;
|
|
6224
|
+
},
|
|
6225
|
+
isSettled() {
|
|
6226
|
+
return alpha < alphaMin && alphaTarget === 0;
|
|
6227
|
+
}
|
|
6228
|
+
};
|
|
6229
|
+
return core;
|
|
6230
|
+
}
|
|
5943
6231
|
var documentHidden = () => typeof document !== "undefined" && document.hidden;
|
|
5944
6232
|
var resolveTarget = (target) => typeof target === "function" ? target() : target?.current ?? null;
|
|
5945
6233
|
function useVisibleRaf(frame, options = {}) {
|
|
@@ -6034,75 +6322,32 @@ function useVisibleRaf(frame, options = {}) {
|
|
|
6034
6322
|
return useMemo(() => ({ request, cancel, isVisible }), [request, cancel, isVisible]);
|
|
6035
6323
|
}
|
|
6036
6324
|
|
|
6037
|
-
// src/features/simulation/types.ts
|
|
6038
|
-
var DEFAULT_ALPHA_DECAY = 1 - Math.pow(1e-3, 1 / 300);
|
|
6039
|
-
var DEFAULT_ALPHA_MIN = 1e-3;
|
|
6040
|
-
var DEFAULT_VELOCITY_DECAY = 0.4;
|
|
6041
|
-
|
|
6042
6325
|
// src/features/simulation/useSimulation.ts
|
|
6043
6326
|
function useSimulation(opts) {
|
|
6044
6327
|
const optsRef = useRef(opts);
|
|
6045
6328
|
optsRef.current = opts;
|
|
6046
|
-
const
|
|
6047
|
-
|
|
6048
|
-
const
|
|
6049
|
-
const alphaMinRef = useRef(opts.alphaMin ?? DEFAULT_ALPHA_MIN);
|
|
6050
|
-
const alphaDecayRef = useRef(opts.alphaDecay ?? DEFAULT_ALPHA_DECAY);
|
|
6051
|
-
const alphaTargetRef = useRef(opts.alphaTarget ?? 0);
|
|
6052
|
-
const velocityDecayRef = useRef(opts.velocityDecay ?? DEFAULT_VELOCITY_DECAY);
|
|
6329
|
+
const coreRef = useRef(null);
|
|
6330
|
+
coreRef.current ??= createSimulation(opts);
|
|
6331
|
+
const core = coreRef.current;
|
|
6053
6332
|
const endedRef = useRef(false);
|
|
6054
6333
|
const mountedRef = useRef(true);
|
|
6055
|
-
const clockRef = useRef(null);
|
|
6056
|
-
if (clockRef.current === null) {
|
|
6057
|
-
clockRef.current = {
|
|
6058
|
-
requestFrame: opts.requestFrame ?? ((cb) => requestAnimationFrame(cb)),
|
|
6059
|
-
cancelFrame: opts.cancelFrame ?? ((h) => cancelAnimationFrame(h))
|
|
6060
|
-
};
|
|
6061
|
-
}
|
|
6062
6334
|
const frameLoop = useVisibleRaf(
|
|
6063
6335
|
() => {
|
|
6064
6336
|
rafTick();
|
|
6065
6337
|
},
|
|
6066
6338
|
{
|
|
6067
|
-
requestFrame:
|
|
6068
|
-
cancelFrame:
|
|
6339
|
+
requestFrame: opts.requestFrame,
|
|
6340
|
+
cancelFrame: opts.cancelFrame
|
|
6069
6341
|
}
|
|
6070
6342
|
);
|
|
6071
|
-
const tickOnce = () => {
|
|
6072
|
-
alphaRef.current += (alphaTargetRef.current - alphaRef.current) * alphaDecayRef.current;
|
|
6073
|
-
const forces = forcesRef.current;
|
|
6074
|
-
for (const f of forces) f(alphaRef.current);
|
|
6075
|
-
const friction = 1 - velocityDecayRef.current;
|
|
6076
|
-
const nodes = nodesRef.current;
|
|
6077
|
-
for (const n of nodes) {
|
|
6078
|
-
if (n.fx == null) {
|
|
6079
|
-
n.vx = (n.vx ?? 0) * friction;
|
|
6080
|
-
if (!Number.isFinite(n.vx)) n.vx = 0;
|
|
6081
|
-
n.x += n.vx;
|
|
6082
|
-
if (!Number.isFinite(n.x)) n.x = 0;
|
|
6083
|
-
} else {
|
|
6084
|
-
n.x = n.fx;
|
|
6085
|
-
n.vx = 0;
|
|
6086
|
-
}
|
|
6087
|
-
if (n.fy == null) {
|
|
6088
|
-
n.vy = (n.vy ?? 0) * friction;
|
|
6089
|
-
if (!Number.isFinite(n.vy)) n.vy = 0;
|
|
6090
|
-
n.y += n.vy;
|
|
6091
|
-
if (!Number.isFinite(n.y)) n.y = 0;
|
|
6092
|
-
} else {
|
|
6093
|
-
n.y = n.fy;
|
|
6094
|
-
n.vy = 0;
|
|
6095
|
-
}
|
|
6096
|
-
}
|
|
6097
|
-
};
|
|
6098
6343
|
const stopRaf = () => {
|
|
6099
6344
|
frameLoop.cancel();
|
|
6100
6345
|
};
|
|
6101
6346
|
const rafTick = () => {
|
|
6102
6347
|
if (!mountedRef.current) return;
|
|
6103
|
-
|
|
6104
|
-
optsRef.current.onTick?.(
|
|
6105
|
-
if (
|
|
6348
|
+
core.tick();
|
|
6349
|
+
optsRef.current.onTick?.(core.nodes);
|
|
6350
|
+
if (core.alpha() < core.alphaMin()) {
|
|
6106
6351
|
stopRaf();
|
|
6107
6352
|
if (!endedRef.current) {
|
|
6108
6353
|
endedRef.current = true;
|
|
@@ -6116,17 +6361,9 @@ function useSimulation(opts) {
|
|
|
6116
6361
|
if (!mountedRef.current) return;
|
|
6117
6362
|
frameLoop.request();
|
|
6118
6363
|
};
|
|
6119
|
-
const
|
|
6120
|
-
if (!
|
|
6121
|
-
|
|
6122
|
-
nodesRef.current.forEach((n, i) => {
|
|
6123
|
-
n.index = i;
|
|
6124
|
-
if (n.vx == null) n.vx = 0;
|
|
6125
|
-
if (n.vy == null) n.vy = 0;
|
|
6126
|
-
});
|
|
6127
|
-
for (const f of forcesRef.current) {
|
|
6128
|
-
f.initialize?.(nodesRef.current, Math.random);
|
|
6129
|
-
}
|
|
6364
|
+
const startedRef = useRef(false);
|
|
6365
|
+
if (!startedRef.current) {
|
|
6366
|
+
startedRef.current = true;
|
|
6130
6367
|
startRaf();
|
|
6131
6368
|
}
|
|
6132
6369
|
useEffect(() => {
|
|
@@ -6139,80 +6376,195 @@ function useSimulation(opts) {
|
|
|
6139
6376
|
const handle = useMemo(() => {
|
|
6140
6377
|
const h = {
|
|
6141
6378
|
get nodes() {
|
|
6142
|
-
return
|
|
6379
|
+
return core.nodes;
|
|
6143
6380
|
},
|
|
6144
6381
|
setNodes(newNodes) {
|
|
6145
|
-
|
|
6146
|
-
newNodes.forEach((n, i) => {
|
|
6147
|
-
n.index = i;
|
|
6148
|
-
if (n.vx == null) n.vx = 0;
|
|
6149
|
-
if (n.vy == null) n.vy = 0;
|
|
6150
|
-
});
|
|
6151
|
-
for (const f of forcesRef.current) {
|
|
6152
|
-
f.initialize?.(newNodes, Math.random);
|
|
6153
|
-
}
|
|
6382
|
+
core.setNodes(newNodes);
|
|
6154
6383
|
return h;
|
|
6155
6384
|
},
|
|
6156
6385
|
setForces(newForces) {
|
|
6157
|
-
|
|
6158
|
-
forcesRef.current = newForces;
|
|
6159
|
-
for (const f of newForces) {
|
|
6160
|
-
if (!old.includes(f)) {
|
|
6161
|
-
f.initialize?.(nodesRef.current, Math.random);
|
|
6162
|
-
}
|
|
6163
|
-
}
|
|
6386
|
+
core.setForces(newForces);
|
|
6164
6387
|
return h;
|
|
6165
6388
|
},
|
|
6166
6389
|
alpha(value) {
|
|
6167
|
-
if (value === void 0) return
|
|
6168
|
-
|
|
6169
|
-
if (value >=
|
|
6390
|
+
if (value === void 0) return core.alpha();
|
|
6391
|
+
core.alpha(value);
|
|
6392
|
+
if (value >= core.alphaMin()) endedRef.current = false;
|
|
6170
6393
|
return h;
|
|
6171
6394
|
},
|
|
6172
6395
|
alphaTarget(value) {
|
|
6173
|
-
if (value === void 0) return
|
|
6174
|
-
|
|
6396
|
+
if (value === void 0) return core.alphaTarget();
|
|
6397
|
+
core.alphaTarget(value);
|
|
6175
6398
|
if (value > 0) endedRef.current = false;
|
|
6176
6399
|
return h;
|
|
6177
6400
|
},
|
|
6178
6401
|
alphaDecay(value) {
|
|
6179
|
-
if (value === void 0) return
|
|
6180
|
-
|
|
6402
|
+
if (value === void 0) return core.alphaDecay();
|
|
6403
|
+
core.alphaDecay(value);
|
|
6181
6404
|
return h;
|
|
6182
6405
|
},
|
|
6183
6406
|
alphaMin(value) {
|
|
6184
|
-
if (value === void 0) return
|
|
6185
|
-
|
|
6407
|
+
if (value === void 0) return core.alphaMin();
|
|
6408
|
+
core.alphaMin(value);
|
|
6186
6409
|
return h;
|
|
6187
6410
|
},
|
|
6188
6411
|
velocityDecay(value) {
|
|
6189
|
-
if (value === void 0) return
|
|
6190
|
-
|
|
6412
|
+
if (value === void 0) return core.velocityDecay();
|
|
6413
|
+
core.velocityDecay(value);
|
|
6191
6414
|
return h;
|
|
6192
6415
|
},
|
|
6193
6416
|
restart() {
|
|
6194
|
-
if (
|
|
6195
|
-
|
|
6417
|
+
if (core.alpha() < core.alphaMin()) core.alpha(1);
|
|
6418
|
+
endedRef.current = false;
|
|
6419
|
+
startRaf();
|
|
6420
|
+
return h;
|
|
6421
|
+
},
|
|
6422
|
+
stop() {
|
|
6423
|
+
stopRaf();
|
|
6424
|
+
return h;
|
|
6425
|
+
},
|
|
6426
|
+
tick(iterations = 1) {
|
|
6427
|
+
core.tick(iterations);
|
|
6428
|
+
return h;
|
|
6429
|
+
},
|
|
6430
|
+
isSettled() {
|
|
6431
|
+
return core.isSettled();
|
|
6432
|
+
}
|
|
6433
|
+
};
|
|
6434
|
+
return h;
|
|
6435
|
+
}, []);
|
|
6436
|
+
return handle;
|
|
6437
|
+
}
|
|
6438
|
+
|
|
6439
|
+
// src/interactions/actions/previewOverrides.ts
|
|
6440
|
+
function syncPreviewOverrides(state) {
|
|
6441
|
+
const { overrides } = state.scene;
|
|
6442
|
+
for (const [id, pose] of state.previews) {
|
|
6443
|
+
const existing = state.overrideEntries.get(id);
|
|
6444
|
+
if (existing) {
|
|
6445
|
+
existing.pose = pose;
|
|
6446
|
+
continue;
|
|
6447
|
+
}
|
|
6448
|
+
const entry = { pose };
|
|
6449
|
+
state.overrideEntries.set(id, entry);
|
|
6450
|
+
overrides.set(id, entry);
|
|
6451
|
+
}
|
|
6452
|
+
for (const id of state.overrideEntries.keys()) {
|
|
6453
|
+
if (state.previews.has(id)) continue;
|
|
6454
|
+
state.overrideEntries.delete(id);
|
|
6455
|
+
overrides.clear(id);
|
|
6456
|
+
}
|
|
6457
|
+
overrides.commit();
|
|
6458
|
+
}
|
|
6459
|
+
function dropPreviewOverrides(state) {
|
|
6460
|
+
if (state.overrideEntries.size === 0) return;
|
|
6461
|
+
for (const id of state.overrideEntries.keys()) state.scene.overrides.clear(id);
|
|
6462
|
+
state.overrideEntries.clear();
|
|
6463
|
+
state.scene.overrides.commit();
|
|
6464
|
+
}
|
|
6465
|
+
|
|
6466
|
+
// src/features/poseRun/usePoseRun.ts
|
|
6467
|
+
var EMPTY = /* @__PURE__ */ new Map();
|
|
6468
|
+
function usePoseRun(opts) {
|
|
6469
|
+
const optsRef = useRef(opts);
|
|
6470
|
+
optsRef.current = opts;
|
|
6471
|
+
const state = useRef({
|
|
6472
|
+
previews: /* @__PURE__ */ new Map(),
|
|
6473
|
+
overrideEntries: /* @__PURE__ */ new Map()
|
|
6474
|
+
});
|
|
6475
|
+
const running = useRef(false);
|
|
6476
|
+
const frame = useRef(0);
|
|
6477
|
+
const mounted = useRef(true);
|
|
6478
|
+
const loop = useVisibleRaf(() => {
|
|
6479
|
+
tick();
|
|
6480
|
+
}, {
|
|
6481
|
+
requestFrame: opts.requestFrame,
|
|
6482
|
+
cancelFrame: opts.cancelFrame
|
|
6483
|
+
});
|
|
6484
|
+
const syncState = () => ({
|
|
6485
|
+
scene: optsRef.current.scene,
|
|
6486
|
+
previews: state.current.previews,
|
|
6487
|
+
overrideEntries: state.current.overrideEntries
|
|
6488
|
+
});
|
|
6489
|
+
const pinnedNow = () => {
|
|
6490
|
+
const { overrides } = optsRef.current.scene;
|
|
6491
|
+
let pinned;
|
|
6492
|
+
for (const id of overrides.ids()) {
|
|
6493
|
+
const entry = overrides.get(id);
|
|
6494
|
+
if (entry === void 0 || entry === state.current.overrideEntries.get(id)) continue;
|
|
6495
|
+
if (entry.pose === void 0) continue;
|
|
6496
|
+
(pinned ??= /* @__PURE__ */ new Map()).set(id, entry.pose);
|
|
6497
|
+
}
|
|
6498
|
+
return pinned ?? EMPTY;
|
|
6499
|
+
};
|
|
6500
|
+
const commit = () => {
|
|
6501
|
+
const { previews } = state.current;
|
|
6502
|
+
const scene = optsRef.current.scene;
|
|
6503
|
+
let moved = 0;
|
|
6504
|
+
if (previews.size > 0) {
|
|
6505
|
+
scene.batch(optsRef.current.label ?? "Layout", () => {
|
|
6506
|
+
for (const [id, pose] of previews) {
|
|
6507
|
+
if (scene.get(id) === void 0) continue;
|
|
6508
|
+
scene.setPose(id, pose);
|
|
6509
|
+
moved++;
|
|
6196
6510
|
}
|
|
6197
|
-
|
|
6198
|
-
|
|
6199
|
-
|
|
6200
|
-
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6511
|
+
});
|
|
6512
|
+
}
|
|
6513
|
+
dropPreviewOverrides(syncState());
|
|
6514
|
+
previews.clear();
|
|
6515
|
+
optsRef.current.onCommit?.(moved);
|
|
6516
|
+
};
|
|
6517
|
+
const halt = () => {
|
|
6518
|
+
running.current = false;
|
|
6519
|
+
loop.cancel();
|
|
6520
|
+
};
|
|
6521
|
+
const tick = () => {
|
|
6522
|
+
if (!mounted.current || !running.current) return;
|
|
6523
|
+
const pinned = pinnedNow();
|
|
6524
|
+
const { poses, done } = optsRef.current.step({ pinned, frame: frame.current });
|
|
6525
|
+
frame.current++;
|
|
6526
|
+
state.current.previews.clear();
|
|
6527
|
+
for (const [id, pose] of poses) {
|
|
6528
|
+
if (pinned.has(id)) continue;
|
|
6529
|
+
state.current.previews.set(id, pose);
|
|
6530
|
+
}
|
|
6531
|
+
syncPreviewOverrides(syncState());
|
|
6532
|
+
if (done) {
|
|
6533
|
+
halt();
|
|
6534
|
+
commit();
|
|
6535
|
+
return;
|
|
6536
|
+
}
|
|
6537
|
+
loop.request();
|
|
6538
|
+
};
|
|
6539
|
+
useEffect(() => {
|
|
6540
|
+
mounted.current = true;
|
|
6541
|
+
return () => {
|
|
6542
|
+
mounted.current = false;
|
|
6543
|
+
loop.cancel();
|
|
6544
|
+
dropPreviewOverrides(syncState());
|
|
6545
|
+
state.current.previews.clear();
|
|
6212
6546
|
};
|
|
6213
|
-
|
|
6214
|
-
|
|
6215
|
-
|
|
6547
|
+
}, [loop]);
|
|
6548
|
+
return useMemo(() => ({
|
|
6549
|
+
start() {
|
|
6550
|
+
if (running.current || !mounted.current) return;
|
|
6551
|
+
running.current = true;
|
|
6552
|
+
frame.current = 0;
|
|
6553
|
+
loop.request();
|
|
6554
|
+
},
|
|
6555
|
+
stop() {
|
|
6556
|
+
if (!running.current) return;
|
|
6557
|
+
halt();
|
|
6558
|
+
commit();
|
|
6559
|
+
},
|
|
6560
|
+
cancel() {
|
|
6561
|
+
halt();
|
|
6562
|
+
dropPreviewOverrides(syncState());
|
|
6563
|
+
state.current.previews.clear();
|
|
6564
|
+
},
|
|
6565
|
+
isRunning: () => running.current
|
|
6566
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
6567
|
+
}), [loop]);
|
|
6216
6568
|
}
|
|
6217
6569
|
|
|
6218
6570
|
// src/core/device/profile.ts
|
|
@@ -7162,31 +7514,158 @@ function resolveParams(params) {
|
|
|
7162
7514
|
return typeof params === "function" ? params() : params;
|
|
7163
7515
|
}
|
|
7164
7516
|
|
|
7165
|
-
// src/
|
|
7166
|
-
|
|
7167
|
-
|
|
7168
|
-
|
|
7169
|
-
|
|
7170
|
-
|
|
7171
|
-
|
|
7172
|
-
|
|
7517
|
+
// src/core/scene/dependents.ts
|
|
7518
|
+
var NONE = Object.freeze([]);
|
|
7519
|
+
function dependencyIdsOf(node, childrenOf) {
|
|
7520
|
+
const deps = node.dependsOn;
|
|
7521
|
+
if (deps === void 0) return NONE;
|
|
7522
|
+
return deps === "children" ? childrenOf(node.id) : deps;
|
|
7523
|
+
}
|
|
7524
|
+
function createDependentsIndex() {
|
|
7525
|
+
const forward = /* @__PURE__ */ new Map();
|
|
7526
|
+
const reverse = /* @__PURE__ */ new Map();
|
|
7527
|
+
function detachOwnDeps(id) {
|
|
7528
|
+
const old = reverse.get(id);
|
|
7529
|
+
if (old === void 0) return;
|
|
7530
|
+
for (const dep of old) {
|
|
7531
|
+
const set = forward.get(dep);
|
|
7532
|
+
if (set === void 0) continue;
|
|
7533
|
+
set.delete(id);
|
|
7534
|
+
if (set.size === 0) forward.delete(dep);
|
|
7173
7535
|
}
|
|
7174
|
-
|
|
7175
|
-
state.overrideEntries.set(id, entry);
|
|
7176
|
-
overrides.set(id, entry);
|
|
7536
|
+
reverse.delete(id);
|
|
7177
7537
|
}
|
|
7178
|
-
|
|
7179
|
-
|
|
7180
|
-
|
|
7181
|
-
|
|
7538
|
+
return {
|
|
7539
|
+
add(id, deps) {
|
|
7540
|
+
detachOwnDeps(id);
|
|
7541
|
+
if (deps.length === 0) return;
|
|
7542
|
+
reverse.set(id, [...deps]);
|
|
7543
|
+
for (const dep of deps) {
|
|
7544
|
+
let set = forward.get(dep);
|
|
7545
|
+
if (set === void 0) {
|
|
7546
|
+
set = /* @__PURE__ */ new Set();
|
|
7547
|
+
forward.set(dep, set);
|
|
7548
|
+
}
|
|
7549
|
+
set.add(id);
|
|
7550
|
+
}
|
|
7551
|
+
},
|
|
7552
|
+
remove(id) {
|
|
7553
|
+
detachOwnDeps(id);
|
|
7554
|
+
},
|
|
7555
|
+
clear() {
|
|
7556
|
+
forward.clear();
|
|
7557
|
+
reverse.clear();
|
|
7558
|
+
},
|
|
7559
|
+
isEmpty() {
|
|
7560
|
+
return forward.size === 0;
|
|
7561
|
+
},
|
|
7562
|
+
dependentsOf(id) {
|
|
7563
|
+
const set = forward.get(id);
|
|
7564
|
+
return set === void 0 ? NONE : [...set];
|
|
7565
|
+
},
|
|
7566
|
+
transitiveDependentsOf(id) {
|
|
7567
|
+
const direct = forward.get(id);
|
|
7568
|
+
if (direct === void 0) return NONE;
|
|
7569
|
+
const out = /* @__PURE__ */ new Set();
|
|
7570
|
+
const stack = [...direct];
|
|
7571
|
+
while (stack.length > 0) {
|
|
7572
|
+
const next = stack.pop();
|
|
7573
|
+
if (out.has(next)) continue;
|
|
7574
|
+
out.add(next);
|
|
7575
|
+
for (const d of forward.get(next) ?? []) stack.push(d);
|
|
7576
|
+
}
|
|
7577
|
+
return out;
|
|
7578
|
+
}
|
|
7579
|
+
};
|
|
7580
|
+
}
|
|
7581
|
+
function sameDependsOn(a, b) {
|
|
7582
|
+
if (a === b) return true;
|
|
7583
|
+
if (a === void 0 || b === void 0) return false;
|
|
7584
|
+
if (a === "children" || b === "children") return false;
|
|
7585
|
+
if (a.length !== b.length) return false;
|
|
7586
|
+
for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
|
|
7587
|
+
return true;
|
|
7588
|
+
}
|
|
7589
|
+
|
|
7590
|
+
// src/core/scene/derivedPath.ts
|
|
7591
|
+
var SLOT = "kit:derivedPath";
|
|
7592
|
+
var resolving = /* @__PURE__ */ new Set();
|
|
7593
|
+
var cycleHits = 0;
|
|
7594
|
+
function resolveDerivedPath(node, depOf2, childrenOf) {
|
|
7595
|
+
const derivePath = node.derivePath;
|
|
7596
|
+
if (derivePath === void 0) return null;
|
|
7597
|
+
const ids = dependencyIdsOf(node, childrenOf);
|
|
7598
|
+
if (ids.length === 0) return null;
|
|
7599
|
+
if (resolving.has(node.id)) {
|
|
7600
|
+
cycleHits++;
|
|
7601
|
+
return null;
|
|
7602
|
+
}
|
|
7603
|
+
resolving.add(node.id);
|
|
7604
|
+
const hitsBefore = cycleHits;
|
|
7605
|
+
try {
|
|
7606
|
+
const value = nodeMemo(
|
|
7607
|
+
node,
|
|
7608
|
+
SLOT,
|
|
7609
|
+
node.pose,
|
|
7610
|
+
() => derivePath(node, ids.map((id) => depOf2(id)))
|
|
7611
|
+
);
|
|
7612
|
+
if (cycleHits !== hitsBefore) dropPoseKeyedMemoSlots(node);
|
|
7613
|
+
return value;
|
|
7614
|
+
} finally {
|
|
7615
|
+
resolving.delete(node.id);
|
|
7182
7616
|
}
|
|
7183
|
-
overrides.commit();
|
|
7184
7617
|
}
|
|
7185
|
-
|
|
7186
|
-
|
|
7187
|
-
|
|
7188
|
-
|
|
7189
|
-
|
|
7618
|
+
|
|
7619
|
+
// src/core/scene/effectivePose.ts
|
|
7620
|
+
var SLOT2 = "kit:derivedPose";
|
|
7621
|
+
var resolving2 = /* @__PURE__ */ new Set();
|
|
7622
|
+
var cycleHits2 = 0;
|
|
7623
|
+
function derivedPose(source, node) {
|
|
7624
|
+
const derive = node.derivePose;
|
|
7625
|
+
if (derive === void 0) return null;
|
|
7626
|
+
const ids = dependencyIdsOf(node, source.childrenOf);
|
|
7627
|
+
if (ids.length === 0) return null;
|
|
7628
|
+
if (resolving2.has(node.id)) {
|
|
7629
|
+
cycleHits2++;
|
|
7630
|
+
return null;
|
|
7631
|
+
}
|
|
7632
|
+
resolving2.add(node.id);
|
|
7633
|
+
const hitsBefore = cycleHits2;
|
|
7634
|
+
try {
|
|
7635
|
+
const value = nodeMemo(
|
|
7636
|
+
node,
|
|
7637
|
+
SLOT2,
|
|
7638
|
+
node.pose,
|
|
7639
|
+
() => derive(node, ids.map((id) => derivedDepOf(source, id)))
|
|
7640
|
+
);
|
|
7641
|
+
if (cycleHits2 !== hitsBefore) dropPoseKeyedMemoSlots(node);
|
|
7642
|
+
return value;
|
|
7643
|
+
} finally {
|
|
7644
|
+
resolving2.delete(node.id);
|
|
7645
|
+
}
|
|
7646
|
+
}
|
|
7647
|
+
function derivedDepOf(source, id) {
|
|
7648
|
+
const node = source.get(id);
|
|
7649
|
+
if (node === void 0) return void 0;
|
|
7650
|
+
return {
|
|
7651
|
+
node,
|
|
7652
|
+
pose: effectivePose(source, node),
|
|
7653
|
+
get path() {
|
|
7654
|
+
return resolveDerivedPath(
|
|
7655
|
+
node,
|
|
7656
|
+
(depId) => derivedDepOf(source, depId),
|
|
7657
|
+
(depId) => source.childrenOf(depId)
|
|
7658
|
+
);
|
|
7659
|
+
}
|
|
7660
|
+
};
|
|
7661
|
+
}
|
|
7662
|
+
function documentPose(source, node) {
|
|
7663
|
+
return derivedPose(source, node) ?? node.pose;
|
|
7664
|
+
}
|
|
7665
|
+
function effectivePose(source, node) {
|
|
7666
|
+
const override = source.overrides.get(node.id)?.pose;
|
|
7667
|
+
if (override !== void 0) return override;
|
|
7668
|
+
return derivedPose(source, node) ?? node.pose;
|
|
7190
7669
|
}
|
|
7191
7670
|
|
|
7192
7671
|
// src/core/scene/types.ts
|
|
@@ -7218,6 +7697,86 @@ function geometryDataOp(projection, node, m, label) {
|
|
|
7218
7697
|
return createSetDataOp({ id: node.id, from: node.data, to: next, label, coalesceKey: `setData:${node.id}` });
|
|
7219
7698
|
}
|
|
7220
7699
|
|
|
7700
|
+
// src/core/scene/nodeFnFields.ts
|
|
7701
|
+
var NODE_FN_FIELDS = [
|
|
7702
|
+
{
|
|
7703
|
+
field: "clipFromPose",
|
|
7704
|
+
opKey: "clipKey",
|
|
7705
|
+
jsonKey: "clipFromPoseKey",
|
|
7706
|
+
containersOnly: true,
|
|
7707
|
+
lost: "clip"
|
|
7708
|
+
},
|
|
7709
|
+
{
|
|
7710
|
+
field: "derivePath",
|
|
7711
|
+
opKey: "derivePathKey",
|
|
7712
|
+
jsonKey: "derivePathKey",
|
|
7713
|
+
containersOnly: false,
|
|
7714
|
+
lost: "derived path"
|
|
7715
|
+
},
|
|
7716
|
+
{
|
|
7717
|
+
field: "derivePose",
|
|
7718
|
+
opKey: "derivePoseKey",
|
|
7719
|
+
jsonKey: "derivePoseKey",
|
|
7720
|
+
containersOnly: false,
|
|
7721
|
+
lost: "derived pose"
|
|
7722
|
+
}
|
|
7723
|
+
];
|
|
7724
|
+
function createNodeFnFields(registry2) {
|
|
7725
|
+
return NODE_FN_FIELDS.map((spec) => {
|
|
7726
|
+
const table = registry2[spec.field];
|
|
7727
|
+
const reverse = /* @__PURE__ */ new Map();
|
|
7728
|
+
if (table) for (const [key, fn] of Object.entries(table)) reverse.set(fn, key);
|
|
7729
|
+
const pending = /* @__PURE__ */ new Map();
|
|
7730
|
+
const applies = (node) => !spec.containersOnly || node.kind === "container";
|
|
7731
|
+
return {
|
|
7732
|
+
spec,
|
|
7733
|
+
keyOf: (fn) => reverse.get(fn),
|
|
7734
|
+
fnOf: (key) => table?.[key],
|
|
7735
|
+
read: (node) => applies(node) ? node[spec.field] : void 0,
|
|
7736
|
+
write: (node, fn) => {
|
|
7737
|
+
if (applies(node)) node[spec.field] = fn;
|
|
7738
|
+
},
|
|
7739
|
+
pending
|
|
7740
|
+
};
|
|
7741
|
+
});
|
|
7742
|
+
}
|
|
7743
|
+
function restoreFn(field, node, key, site, warn) {
|
|
7744
|
+
const fn = field.fnOf(key);
|
|
7745
|
+
if (fn === void 0) {
|
|
7746
|
+
warn(
|
|
7747
|
+
"scene",
|
|
7748
|
+
`${site}: ${field.spec.opKey} "${key}" not in this scene's registry \u2014 node "${node.id}" restored without its ${field.spec.lost}. Register a function with this key in the registry option to restore it.`
|
|
7749
|
+
);
|
|
7750
|
+
return;
|
|
7751
|
+
}
|
|
7752
|
+
field.write(node, fn);
|
|
7753
|
+
field.pending.set(node.id, fn);
|
|
7754
|
+
}
|
|
7755
|
+
function fnKeysOf(fields, node, which, onUnregistered) {
|
|
7756
|
+
const out = {};
|
|
7757
|
+
for (const field of fields) {
|
|
7758
|
+
const fn = field.read(node);
|
|
7759
|
+
if (fn === void 0) continue;
|
|
7760
|
+
const key = field.keyOf(fn);
|
|
7761
|
+
if (key === void 0) {
|
|
7762
|
+
onUnregistered?.(field);
|
|
7763
|
+
continue;
|
|
7764
|
+
}
|
|
7765
|
+
out[field.spec[which]] = key;
|
|
7766
|
+
}
|
|
7767
|
+
return out;
|
|
7768
|
+
}
|
|
7769
|
+
function fnFieldsOfNode(node) {
|
|
7770
|
+
const src = node;
|
|
7771
|
+
const out = {};
|
|
7772
|
+
for (const spec of NODE_FN_FIELDS) {
|
|
7773
|
+
if (spec.containersOnly && node.kind !== "container") continue;
|
|
7774
|
+
const fn = src[spec.field];
|
|
7775
|
+
if (fn !== void 0) out[spec.field] = fn;
|
|
7776
|
+
}
|
|
7777
|
+
return out;
|
|
7778
|
+
}
|
|
7779
|
+
|
|
7221
7780
|
// src/interactions/actions/move/gestureAdapter.ts
|
|
7222
7781
|
function moveGestureAdapter(scene) {
|
|
7223
7782
|
return {
|
|
@@ -7225,7 +7784,7 @@ function moveGestureAdapter(scene) {
|
|
|
7225
7784
|
getNodes: () => {
|
|
7226
7785
|
return [...scene.renderOrderNodes()];
|
|
7227
7786
|
},
|
|
7228
|
-
getPose: (id) => scene.get(asNodeId(id))
|
|
7787
|
+
getPose: (id) => documentPose(scene, scene.get(asNodeId(id))),
|
|
7229
7788
|
getParent: (id) => scene.get(asNodeId(id))?.parent ?? null,
|
|
7230
7789
|
setPose: (id, pose) => scene.setPose(asNodeId(id), pose),
|
|
7231
7790
|
setParent: (id, parentId) => scene.move(asNodeId(id), parentId === null ? null : asNodeId(parentId)),
|
|
@@ -7240,8 +7799,7 @@ function moveGestureAdapter(scene) {
|
|
|
7240
7799
|
...index !== void 0 ? { index } : {},
|
|
7241
7800
|
...node.parent !== null ? { parent: node.parent } : {},
|
|
7242
7801
|
...node.dependsOn !== void 0 ? { dependsOn: node.dependsOn } : {},
|
|
7243
|
-
...node
|
|
7244
|
-
...node.kind === "container" && node.clipFromPose !== void 0 ? { clipFromPose: node.clipFromPose } : {}
|
|
7802
|
+
...fnFieldsOfNode(node)
|
|
7245
7803
|
}),
|
|
7246
7804
|
getChildren: (parentId) => parentId === null ? [...scene.roots] : [...scene.childrenOf(asNodeId(parentId))],
|
|
7247
7805
|
setChildOrder: (parentId, ids) => {
|
|
@@ -7489,7 +8047,7 @@ function unreleasedIds(scratch, released) {
|
|
|
7489
8047
|
}
|
|
7490
8048
|
function scenePoseAdapter(scene) {
|
|
7491
8049
|
return {
|
|
7492
|
-
getPose: (id) => scene.get(id)
|
|
8050
|
+
getPose: (id) => documentPose(scene, scene.get(id)),
|
|
7493
8051
|
getParent: (id) => scene.get(id)?.parent ?? null
|
|
7494
8052
|
};
|
|
7495
8053
|
}
|
|
@@ -7902,7 +8460,7 @@ function defaultCommitAdapter(scene) {
|
|
|
7902
8460
|
getNodes: () => {
|
|
7903
8461
|
return [...scene.renderOrderNodes()];
|
|
7904
8462
|
},
|
|
7905
|
-
getPose: (id) => scene.get(asNodeId(id))
|
|
8463
|
+
getPose: (id) => documentPose(scene, scene.get(asNodeId(id))),
|
|
7906
8464
|
getSelection: () => [...scene.getSelection()],
|
|
7907
8465
|
setSelection: (ids) => scene.setSelection(ids.map(asNodeId)),
|
|
7908
8466
|
getParent: (id) => scene.get(asNodeId(id))?.parent ?? null,
|
|
@@ -7936,12 +8494,8 @@ function defaultCommitAdapter(scene) {
|
|
|
7936
8494
|
// source removal) re-inserts at the recorded z-order slot instead
|
|
7937
8495
|
// of appending at the end.
|
|
7938
8496
|
...index !== void 0 ? { index } : {},
|
|
7939
|
-
// The function-valued fields travel with the node, or undo of a delete
|
|
7940
|
-
// brings an edge back as a static path that never follows its endpoints
|
|
7941
|
-
// again, and a clipped container back with nothing clipped.
|
|
7942
8497
|
...node.dependsOn !== void 0 ? { dependsOn: node.dependsOn } : {},
|
|
7943
|
-
...node
|
|
7944
|
-
...node.kind === "container" && node.clipFromPose !== void 0 ? { clipFromPose: node.clipFromPose } : {}
|
|
8498
|
+
...fnFieldsOfNode(node)
|
|
7945
8499
|
})
|
|
7946
8500
|
};
|
|
7947
8501
|
}
|
|
@@ -10272,6 +10826,26 @@ var duplicateAction = {
|
|
|
10272
10826
|
enabled: requiresSelection
|
|
10273
10827
|
};
|
|
10274
10828
|
|
|
10829
|
+
// src/core/scene/kitRegistry.ts
|
|
10830
|
+
var UNION_OF_CHILDREN = "kit:unionOfChildren";
|
|
10831
|
+
function unionOfChildren(_node, deps) {
|
|
10832
|
+
const poses = [];
|
|
10833
|
+
for (const d of deps) {
|
|
10834
|
+
if (d !== void 0) poses.push(d.pose);
|
|
10835
|
+
}
|
|
10836
|
+
if (poses.length === 0) return null;
|
|
10837
|
+
return unionAABB(poses);
|
|
10838
|
+
}
|
|
10839
|
+
function withKitRegistry(registry2) {
|
|
10840
|
+
return {
|
|
10841
|
+
...registry2,
|
|
10842
|
+
derivePose: {
|
|
10843
|
+
[UNION_OF_CHILDREN]: unionOfChildren,
|
|
10844
|
+
...registry2.derivePose
|
|
10845
|
+
}
|
|
10846
|
+
};
|
|
10847
|
+
}
|
|
10848
|
+
|
|
10275
10849
|
// src/interactions/actions/defaults/group.ts
|
|
10276
10850
|
var containerIdCounter = 0;
|
|
10277
10851
|
function freshContainerId() {
|
|
@@ -10309,7 +10883,9 @@ var groupAction = {
|
|
|
10309
10883
|
layer,
|
|
10310
10884
|
pose,
|
|
10311
10885
|
data: {},
|
|
10312
|
-
parent: parent ?? null
|
|
10886
|
+
parent: parent ?? null,
|
|
10887
|
+
dependsOn: "children",
|
|
10888
|
+
derivePose: unionOfChildren
|
|
10313
10889
|
},
|
|
10314
10890
|
label: "Group"
|
|
10315
10891
|
})
|
|
@@ -12727,7 +13303,7 @@ function useStandardActions(opts) {
|
|
|
12727
13303
|
}, [reg, depReg, excludeKey]);
|
|
12728
13304
|
}
|
|
12729
13305
|
var IDENTITY_EXPAND2 = (ids) => ids;
|
|
12730
|
-
var
|
|
13306
|
+
var EMPTY2 = Object.freeze([]);
|
|
12731
13307
|
function useResizePolicy(options) {
|
|
12732
13308
|
const optsRef = useRef(options);
|
|
12733
13309
|
optsRef.current = options;
|
|
@@ -12735,7 +13311,7 @@ function useResizePolicy(options) {
|
|
|
12735
13311
|
const o = optsRef.current;
|
|
12736
13312
|
return {
|
|
12737
13313
|
constraints: o.constraints ?? DEFAULT_RESIZE_BEHAVIORS,
|
|
12738
|
-
pointSnap: o.pointSnap ??
|
|
13314
|
+
pointSnap: o.pointSnap ?? EMPTY2,
|
|
12739
13315
|
expandIds: o.expandIds ?? IDENTITY_EXPAND2,
|
|
12740
13316
|
projection: o.projection ?? AUTO_POSE_DESCRIPTOR
|
|
12741
13317
|
};
|
|
@@ -17348,7 +17924,7 @@ var TEXT_PAINTER = {
|
|
|
17348
17924
|
const p = pose;
|
|
17349
17925
|
const y = p.y;
|
|
17350
17926
|
const paint = { fill: d.fill, stroke: resolveNodeStroke(d.stroke) ?? void 0 };
|
|
17351
|
-
return d.runs && d.runs.length > 0 ? [textCommandFromRuns(p.x, y, d.runs, d.style, void 0, p.height,
|
|
17927
|
+
return d.runs && d.runs.length > 0 ? [textCommandFromRuns(p.x, y, d.runs, d.style, void 0, p.height, d.verticalAlign, paint)] : [textCommand(p.x, y, d.text, d.style, void 0, p.height, d.verticalAlign, paint)];
|
|
17352
17928
|
}),
|
|
17353
17929
|
// The pose is a *wrap box*, not a bounding box — "Away" in a 300-unit box
|
|
17354
17930
|
// leaves most of it empty, and a pose-rect silhouette claims all of it. The
|
|
@@ -17372,7 +17948,11 @@ var TEXT_PAINTER = {
|
|
|
17372
17948
|
height: p.height,
|
|
17373
17949
|
text: d.text,
|
|
17374
17950
|
runs: d.runs,
|
|
17375
|
-
style: d.style
|
|
17951
|
+
style: d.style,
|
|
17952
|
+
// `textLineBoxes` applies the same shift `drawText` does, so picking
|
|
17953
|
+
// follows a centered or bottom-aligned block down its box instead of
|
|
17954
|
+
// staying where a top-aligned one would have drawn.
|
|
17955
|
+
verticalAlign: d.verticalAlign
|
|
17376
17956
|
},
|
|
17377
17957
|
{ maxWidth: Infinity }
|
|
17378
17958
|
);
|
|
@@ -17607,12 +18187,15 @@ var DERIVED_PAINTER = {
|
|
|
17607
18187
|
const declared = resolveNodeFill(d?.fill, strokeSpec === null ? DEFAULT_SHAPE_FILL : null);
|
|
17608
18188
|
const fill = declared && resolveFillPattern(fillInPoseFrame(declared, box));
|
|
17609
18189
|
const stroke = strokeSpec && strokeInPoseFrame(strokeSpec, box);
|
|
17610
|
-
|
|
18190
|
+
const cmd = {
|
|
17611
18191
|
kind: "path",
|
|
17612
18192
|
path,
|
|
17613
18193
|
...fill ? { fill } : {},
|
|
17614
18194
|
...stroke ? { stroke } : {}
|
|
17615
|
-
}
|
|
18195
|
+
};
|
|
18196
|
+
if (!stroke) return [cmd];
|
|
18197
|
+
const width = resolveStrokeWidth(stroke.width ?? 1, 1);
|
|
18198
|
+
return [cmd, ...markerDrawCommands(path, stroke, width, void 0)];
|
|
17616
18199
|
},
|
|
17617
18200
|
// The derived path *is* the silhouette, and it is already absolute — the
|
|
17618
18201
|
// pose is a placeholder, so nothing here can be recovered from it. Without
|
|
@@ -17656,95 +18239,27 @@ function registerBuiltInShapePainters() {
|
|
|
17656
18239
|
registerNodeShape(PATH_PAINTER);
|
|
17657
18240
|
registerNodeShape(SHAPE_PAINTER);
|
|
17658
18241
|
registerNodeShape(IMAGE_PAINTER);
|
|
17659
|
-
registerNodeShape(RECT_FALLBACK_PAINTER);
|
|
17660
|
-
}
|
|
17661
|
-
registerBuiltInShapePainters();
|
|
17662
|
-
|
|
17663
|
-
// src/core/scene/poseOverrides.ts
|
|
17664
|
-
function createPoseOverrides(getNode, onInvalidate) {
|
|
17665
|
-
const entries = /* @__PURE__ */ new Map();
|
|
17666
|
-
const listeners = /* @__PURE__ */ new Set();
|
|
17667
|
-
let generation2 = 0;
|
|
17668
|
-
function invalidate(id) {
|
|
17669
|
-
const node = getNode(id);
|
|
17670
|
-
if (node) dropPoseKeyedMemoSlots(node);
|
|
17671
|
-
onInvalidate?.(id);
|
|
17672
|
-
}
|
|
17673
|
-
function published() {
|
|
17674
|
-
generation2++;
|
|
17675
|
-
for (const listener of listeners) listener();
|
|
17676
|
-
}
|
|
17677
|
-
return {
|
|
17678
|
-
set(id, entry) {
|
|
17679
|
-
entries.set(id, entry);
|
|
17680
|
-
invalidate(id);
|
|
17681
|
-
published();
|
|
17682
|
-
},
|
|
17683
|
-
get(id) {
|
|
17684
|
-
return entries.get(id);
|
|
17685
|
-
},
|
|
17686
|
-
has(id) {
|
|
17687
|
-
return entries.has(id);
|
|
17688
|
-
},
|
|
17689
|
-
ids() {
|
|
17690
|
-
return [...entries.keys()];
|
|
17691
|
-
},
|
|
17692
|
-
clear(id) {
|
|
17693
|
-
if (!entries.delete(id)) return;
|
|
17694
|
-
invalidate(id);
|
|
17695
|
-
published();
|
|
17696
|
-
},
|
|
17697
|
-
clearAll() {
|
|
17698
|
-
if (entries.size === 0) return;
|
|
17699
|
-
for (const id of entries.keys()) invalidate(id);
|
|
17700
|
-
entries.clear();
|
|
17701
|
-
published();
|
|
17702
|
-
},
|
|
17703
|
-
commit() {
|
|
17704
|
-
for (const id of entries.keys()) invalidate(id);
|
|
17705
|
-
published();
|
|
17706
|
-
},
|
|
17707
|
-
subscribe(fn) {
|
|
17708
|
-
listeners.add(fn);
|
|
17709
|
-
return () => {
|
|
17710
|
-
listeners.delete(fn);
|
|
17711
|
-
};
|
|
17712
|
-
},
|
|
17713
|
-
getGeneration() {
|
|
17714
|
-
return generation2;
|
|
17715
|
-
}
|
|
17716
|
-
};
|
|
17717
|
-
}
|
|
17718
|
-
function effectivePose(overrides, node) {
|
|
17719
|
-
return overrides.get(node.id)?.pose ?? node.pose;
|
|
17720
|
-
}
|
|
17721
|
-
|
|
17722
|
-
// src/canvas/derivedPath.ts
|
|
17723
|
-
var SLOT = "kit:derivedPath";
|
|
17724
|
-
function resolveDerivedPath(node, poseOf) {
|
|
17725
|
-
const deps = node.dependsOn;
|
|
17726
|
-
const derivePath = node.derivePath;
|
|
17727
|
-
if (deps === void 0 || deps.length === 0 || derivePath === void 0) return null;
|
|
17728
|
-
return nodeMemo(
|
|
17729
|
-
node,
|
|
17730
|
-
SLOT,
|
|
17731
|
-
node.pose,
|
|
17732
|
-
() => derivePath(node, deps.map((id) => poseOf(id)))
|
|
17733
|
-
);
|
|
18242
|
+
registerNodeShape(RECT_FALLBACK_PAINTER);
|
|
17734
18243
|
}
|
|
17735
|
-
|
|
17736
|
-
|
|
17737
|
-
|
|
17738
|
-
|
|
17739
|
-
|
|
17740
|
-
};
|
|
18244
|
+
registerBuiltInShapePainters();
|
|
18245
|
+
|
|
18246
|
+
// src/canvas/derivedPath.ts
|
|
18247
|
+
function sceneDepLookup(scene) {
|
|
18248
|
+
return (id) => derivedDepOf(scene, id);
|
|
17741
18249
|
}
|
|
17742
18250
|
function withDerivedPaths(scene, drawOne) {
|
|
17743
|
-
const
|
|
18251
|
+
const depOf2 = sceneDepLookup(scene);
|
|
18252
|
+
const childrenOf = (id) => scene.childrenOf(id);
|
|
17744
18253
|
return (node, pose, view, ctx) => {
|
|
17745
|
-
|
|
17746
|
-
|
|
17747
|
-
|
|
18254
|
+
if (node.dependsOn === void 0) return drawOne(node, pose, view, ctx);
|
|
18255
|
+
return drawOne(node, pose, view, {
|
|
18256
|
+
...ctx,
|
|
18257
|
+
derivedPath: resolveDerivedPath(
|
|
18258
|
+
node,
|
|
18259
|
+
depOf2,
|
|
18260
|
+
childrenOf
|
|
18261
|
+
)
|
|
18262
|
+
});
|
|
17748
18263
|
};
|
|
17749
18264
|
}
|
|
17750
18265
|
|
|
@@ -17776,6 +18291,7 @@ function pickWalk(src, q) {
|
|
|
17776
18291
|
};
|
|
17777
18292
|
for (const node of src.order()) {
|
|
17778
18293
|
if (!includeContainers && node.kind === "container") continue;
|
|
18294
|
+
if (node.pickable === false) continue;
|
|
17779
18295
|
if (node.layer !== void 0 && src.layerIsPainted?.(node.layer) === false) continue;
|
|
17780
18296
|
if (src.alphaOf !== void 0 && src.alphaOf(node.id) <= 0) continue;
|
|
17781
18297
|
const pose = src.poseOf(node);
|
|
@@ -17813,14 +18329,23 @@ function scenePickSource(scene, opts = {}) {
|
|
|
17813
18329
|
}
|
|
17814
18330
|
}
|
|
17815
18331
|
const readAlpha = alphaOf ?? (enumerable ? faded ? (id) => faded.has(id) ? 0 : 1 : void 0 : (id) => scene.overrides.get(asNodeId(id))?.alpha ?? 1);
|
|
17816
|
-
const poseOf = getPose ? (node) => getPose(node.id) : (node) => effectivePose(scene
|
|
18332
|
+
const poseOf = getPose ? (node) => getPose(node.id) : (node) => effectivePose(scene, node);
|
|
18333
|
+
const childrenOf = (id) => scene.childrenOf(id);
|
|
18334
|
+
const depOf2 = (id) => {
|
|
18335
|
+
const dep = scene.get(id);
|
|
18336
|
+
if (dep === void 0) return void 0;
|
|
18337
|
+
return {
|
|
18338
|
+
node: dep,
|
|
18339
|
+
pose: poseOf(dep),
|
|
18340
|
+
get path() {
|
|
18341
|
+
return resolveDerivedPath(dep, depOf2, childrenOf);
|
|
18342
|
+
}
|
|
18343
|
+
};
|
|
18344
|
+
};
|
|
17817
18345
|
const derivedPathOf = (node) => {
|
|
17818
18346
|
const n = node;
|
|
17819
|
-
if (n.dependsOn === void 0
|
|
17820
|
-
return resolveDerivedPath(n,
|
|
17821
|
-
const dep = scene.get(id);
|
|
17822
|
-
return dep === void 0 ? void 0 : poseOf(dep);
|
|
17823
|
-
});
|
|
18347
|
+
if (n.dependsOn === void 0) return null;
|
|
18348
|
+
return resolveDerivedPath(n, depOf2, childrenOf);
|
|
17824
18349
|
};
|
|
17825
18350
|
return {
|
|
17826
18351
|
order: () => scene.renderOrderNodes(),
|
|
@@ -19938,8 +20463,8 @@ function useFrameLoop(paint, options = {}) {
|
|
|
19938
20463
|
}, []);
|
|
19939
20464
|
return { requestRedraw, subscribeFrame };
|
|
19940
20465
|
}
|
|
19941
|
-
var
|
|
19942
|
-
var EMPTY_SNAPSHOT = () =>
|
|
20466
|
+
var EMPTY3 = [];
|
|
20467
|
+
var EMPTY_SNAPSHOT = () => EMPTY3;
|
|
19943
20468
|
var NEVER_CHANGES = () => () => {
|
|
19944
20469
|
};
|
|
19945
20470
|
function useSelection(opts = {}) {
|
|
@@ -21724,71 +22249,67 @@ function composeAlphaFor(scene, alphaFor) {
|
|
|
21724
22249
|
return alphaFor ? (id) => alphaFor(id) * overrideAlphaFor(id) : overrideAlphaFor;
|
|
21725
22250
|
}
|
|
21726
22251
|
function wireSceneSlotToScene(slot, scene, alphaFor) {
|
|
21727
|
-
const
|
|
22252
|
+
const depOf2 = sceneDepLookup(scene);
|
|
21728
22253
|
return {
|
|
21729
22254
|
...slot,
|
|
21730
22255
|
drawOne: withDerivedPaths(scene, slot.drawOne),
|
|
21731
|
-
derivedPathOf: (node) => resolveDerivedPath(node,
|
|
22256
|
+
derivedPathOf: (node) => resolveDerivedPath(node, depOf2, (id) => scene.childrenOf(id)),
|
|
21732
22257
|
alphaFor: composeAlphaFor(scene, alphaFor)
|
|
21733
22258
|
};
|
|
21734
22259
|
}
|
|
21735
22260
|
|
|
21736
|
-
// src/core/scene/
|
|
21737
|
-
|
|
21738
|
-
|
|
21739
|
-
const
|
|
21740
|
-
|
|
21741
|
-
function
|
|
21742
|
-
const
|
|
21743
|
-
if (
|
|
21744
|
-
|
|
21745
|
-
|
|
21746
|
-
|
|
21747
|
-
|
|
21748
|
-
|
|
21749
|
-
}
|
|
21750
|
-
reverse.delete(id);
|
|
22261
|
+
// src/core/scene/poseOverrides.ts
|
|
22262
|
+
function createPoseOverrides(getNode, onInvalidate) {
|
|
22263
|
+
const entries = /* @__PURE__ */ new Map();
|
|
22264
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
22265
|
+
let generation2 = 0;
|
|
22266
|
+
function invalidate(id) {
|
|
22267
|
+
const node = getNode(id);
|
|
22268
|
+
if (node) dropPoseKeyedMemoSlots(node);
|
|
22269
|
+
onInvalidate?.(id);
|
|
22270
|
+
}
|
|
22271
|
+
function published() {
|
|
22272
|
+
generation2++;
|
|
22273
|
+
for (const listener of listeners) listener();
|
|
21751
22274
|
}
|
|
21752
22275
|
return {
|
|
21753
|
-
|
|
21754
|
-
|
|
21755
|
-
|
|
21756
|
-
|
|
21757
|
-
for (const dep of deps) {
|
|
21758
|
-
let set = forward.get(dep);
|
|
21759
|
-
if (set === void 0) {
|
|
21760
|
-
set = /* @__PURE__ */ new Set();
|
|
21761
|
-
forward.set(dep, set);
|
|
21762
|
-
}
|
|
21763
|
-
set.add(id);
|
|
21764
|
-
}
|
|
22276
|
+
set(id, entry) {
|
|
22277
|
+
entries.set(id, entry);
|
|
22278
|
+
invalidate(id);
|
|
22279
|
+
published();
|
|
21765
22280
|
},
|
|
21766
|
-
|
|
21767
|
-
|
|
22281
|
+
get(id) {
|
|
22282
|
+
return entries.get(id);
|
|
21768
22283
|
},
|
|
21769
|
-
|
|
21770
|
-
|
|
21771
|
-
reverse.clear();
|
|
22284
|
+
has(id) {
|
|
22285
|
+
return entries.has(id);
|
|
21772
22286
|
},
|
|
21773
|
-
|
|
21774
|
-
return
|
|
22287
|
+
ids() {
|
|
22288
|
+
return [...entries.keys()];
|
|
21775
22289
|
},
|
|
21776
|
-
|
|
21777
|
-
|
|
21778
|
-
|
|
22290
|
+
clear(id) {
|
|
22291
|
+
if (!entries.delete(id)) return;
|
|
22292
|
+
invalidate(id);
|
|
22293
|
+
published();
|
|
21779
22294
|
},
|
|
21780
|
-
|
|
21781
|
-
|
|
21782
|
-
|
|
21783
|
-
|
|
21784
|
-
|
|
21785
|
-
|
|
21786
|
-
|
|
21787
|
-
|
|
21788
|
-
|
|
21789
|
-
|
|
21790
|
-
|
|
21791
|
-
|
|
22295
|
+
clearAll() {
|
|
22296
|
+
if (entries.size === 0) return;
|
|
22297
|
+
for (const id of entries.keys()) invalidate(id);
|
|
22298
|
+
entries.clear();
|
|
22299
|
+
published();
|
|
22300
|
+
},
|
|
22301
|
+
commit() {
|
|
22302
|
+
for (const id of entries.keys()) invalidate(id);
|
|
22303
|
+
published();
|
|
22304
|
+
},
|
|
22305
|
+
subscribe(fn) {
|
|
22306
|
+
listeners.add(fn);
|
|
22307
|
+
return () => {
|
|
22308
|
+
listeners.delete(fn);
|
|
22309
|
+
};
|
|
22310
|
+
},
|
|
22311
|
+
getGeneration() {
|
|
22312
|
+
return generation2;
|
|
21792
22313
|
}
|
|
21793
22314
|
};
|
|
21794
22315
|
}
|
|
@@ -21814,23 +22335,13 @@ function createScene(options) {
|
|
|
21814
22335
|
layers: [],
|
|
21815
22336
|
layerIndex: /* @__PURE__ */ new Map()
|
|
21816
22337
|
};
|
|
21817
|
-
const registry2 = options.registry ?? {};
|
|
21818
|
-
const
|
|
21819
|
-
|
|
21820
|
-
for (const [key, fn] of Object.entries(registry2.clipFromPose)) {
|
|
21821
|
-
reverseClipFromPose.set(fn, key);
|
|
21822
|
-
}
|
|
21823
|
-
}
|
|
21824
|
-
const reverseDerivePath = /* @__PURE__ */ new Map();
|
|
21825
|
-
if (registry2.derivePath) {
|
|
21826
|
-
for (const [key, fn] of Object.entries(registry2.derivePath)) {
|
|
21827
|
-
reverseDerivePath.set(fn, key);
|
|
21828
|
-
}
|
|
21829
|
-
}
|
|
21830
|
-
const pendingClipPatches = /* @__PURE__ */ new Map();
|
|
21831
|
-
const pendingDerivePathPatches = /* @__PURE__ */ new Map();
|
|
22338
|
+
const registry2 = withKitRegistry(options.registry ?? {});
|
|
22339
|
+
const fnFields = createNodeFnFields(registry2);
|
|
22340
|
+
const fnField = (name) => fnFields.find((f) => f.spec.field === name);
|
|
21832
22341
|
const dependents = createDependentsIndex();
|
|
22342
|
+
const childDerived = /* @__PURE__ */ new Set();
|
|
21833
22343
|
function invalidateDependents(id) {
|
|
22344
|
+
invalidateChildDerivedFrom(state.nodes.get(id)?.parent ?? null);
|
|
21834
22345
|
if (dependents.isEmpty()) return;
|
|
21835
22346
|
const subtree = [id];
|
|
21836
22347
|
descendants(id, subtree);
|
|
@@ -21841,6 +22352,35 @@ function createScene(options) {
|
|
|
21841
22352
|
}
|
|
21842
22353
|
}
|
|
21843
22354
|
}
|
|
22355
|
+
function invalidateChildDerivedFrom(start) {
|
|
22356
|
+
if (childDerived.size === 0) return;
|
|
22357
|
+
let cursor = start;
|
|
22358
|
+
while (cursor !== null) {
|
|
22359
|
+
const node = state.nodes.get(cursor);
|
|
22360
|
+
if (node === void 0) return;
|
|
22361
|
+
if (childDerived.has(cursor)) {
|
|
22362
|
+
dropPoseKeyedMemoSlots(node);
|
|
22363
|
+
for (const dep of dependents.transitiveDependentsOf(cursor)) {
|
|
22364
|
+
const d = state.nodes.get(dep);
|
|
22365
|
+
if (d !== void 0) dropPoseKeyedMemoSlots(d);
|
|
22366
|
+
}
|
|
22367
|
+
}
|
|
22368
|
+
cursor = node.parent;
|
|
22369
|
+
}
|
|
22370
|
+
}
|
|
22371
|
+
function trackChildDerived(id, dependsOn) {
|
|
22372
|
+
if (dependsOn === "children") childDerived.add(id);
|
|
22373
|
+
else childDerived.delete(id);
|
|
22374
|
+
}
|
|
22375
|
+
function retarget(id, dependsOn) {
|
|
22376
|
+
const node = requireNode(id);
|
|
22377
|
+
if (dependsOn === void 0) delete node.dependsOn;
|
|
22378
|
+
else node.dependsOn = dependsOn;
|
|
22379
|
+
dependents.add(id, dependsOn === void 0 || dependsOn === "children" ? [] : dependsOn);
|
|
22380
|
+
trackChildDerived(id, dependsOn);
|
|
22381
|
+
dropPoseKeyedMemoSlots(requireNode(id));
|
|
22382
|
+
invalidateDependents(id);
|
|
22383
|
+
}
|
|
21844
22384
|
for (let i = 0; i < options.systemLayers.length; i++) {
|
|
21845
22385
|
const spec = options.systemLayers[i];
|
|
21846
22386
|
if (state.layerIndex.has(spec.id)) {
|
|
@@ -21927,13 +22467,12 @@ function createScene(options) {
|
|
|
21927
22467
|
for (const listener of listeners) listener();
|
|
21928
22468
|
}
|
|
21929
22469
|
function pruneCacheForDroppedOps(ops) {
|
|
21930
|
-
if (
|
|
22470
|
+
if (fnFields.every((f) => f.pending.size === 0)) return;
|
|
21931
22471
|
for (const op of ops) {
|
|
21932
22472
|
if (op.name !== "kit:add") continue;
|
|
21933
22473
|
const id = op.args?.id;
|
|
21934
22474
|
if (id && !state.nodes.has(id)) {
|
|
21935
|
-
|
|
21936
|
-
pendingDerivePathPatches.delete(id);
|
|
22475
|
+
for (const field of fnFields) field.pending.delete(id);
|
|
21937
22476
|
}
|
|
21938
22477
|
}
|
|
21939
22478
|
}
|
|
@@ -22014,39 +22553,25 @@ function createScene(options) {
|
|
|
22014
22553
|
}
|
|
22015
22554
|
return { ids, removing };
|
|
22016
22555
|
}
|
|
22017
|
-
function
|
|
22018
|
-
|
|
22019
|
-
|
|
22020
|
-
|
|
22021
|
-
|
|
22022
|
-
|
|
22556
|
+
function patchNodeFunctions(spec, id, { cacheForRedo }) {
|
|
22557
|
+
const node = state.nodes.get(id);
|
|
22558
|
+
if (node === void 0) return;
|
|
22559
|
+
for (const field of fnFields) {
|
|
22560
|
+
const fn = spec[field.spec.field];
|
|
22561
|
+
if (fn === void 0) continue;
|
|
22562
|
+
if (field.spec.containersOnly && spec.kind !== "container") continue;
|
|
22563
|
+
field.write(node, fn);
|
|
22564
|
+
if (cacheForRedo) field.pending.set(id, fn);
|
|
22023
22565
|
}
|
|
22024
22566
|
}
|
|
22025
|
-
function patchDerivePath(spec, id, { cacheForRedo }) {
|
|
22026
|
-
if (spec.derivePath === void 0) return;
|
|
22027
|
-
state.nodes.get(id).derivePath = spec.derivePath;
|
|
22028
|
-
if (cacheForRedo) pendingDerivePathPatches.set(id, spec.derivePath);
|
|
22029
|
-
}
|
|
22030
22567
|
function restoreNodeFunctions(node, keys) {
|
|
22031
22568
|
if (!keys) return;
|
|
22032
|
-
|
|
22033
|
-
|
|
22034
|
-
if (
|
|
22035
|
-
|
|
22036
|
-
|
|
22037
|
-
|
|
22038
|
-
dwarn("scene", `kit:remove: derivePathKey "${keys.derivePathKey}" not in this scene's registry \u2014 node "${node.id}" restored without derived geometry. Register a function with this key in the registry option to restore it.`);
|
|
22039
|
-
}
|
|
22040
|
-
}
|
|
22041
|
-
if (node.kind !== "container" || keys.clipKey === void 0) return;
|
|
22042
|
-
const container = node;
|
|
22043
|
-
if (container.clipFromPose !== void 0) return;
|
|
22044
|
-
const clip = registry2.clipFromPose?.[keys.clipKey];
|
|
22045
|
-
if (clip) {
|
|
22046
|
-
container.clipFromPose = clip;
|
|
22047
|
-
pendingClipPatches.set(node.id, clip);
|
|
22048
|
-
} else {
|
|
22049
|
-
dwarn("scene", `kit:remove: clipKey "${keys.clipKey}" not in this scene's registry \u2014 container "${node.id}" restored without clip. Register a function with this key in the registry option to restore the clip.`);
|
|
22569
|
+
const target = node;
|
|
22570
|
+
for (const field of fnFields) {
|
|
22571
|
+
if (field.read(target) !== void 0) continue;
|
|
22572
|
+
const key = keys[field.spec.opKey];
|
|
22573
|
+
if (key === void 0) continue;
|
|
22574
|
+
restoreFn(field, target, key, "kit:remove", dwarn);
|
|
22050
22575
|
}
|
|
22051
22576
|
}
|
|
22052
22577
|
function registerKitOp(kind, handler) {
|
|
@@ -22060,33 +22585,19 @@ function createScene(options) {
|
|
|
22060
22585
|
const node = p.kind === "container" ? { kind: "container", id: p.id, layer: p.layer, pose: p.pose, data: p.data, parent: p.parent, children: [] } : { kind: "leaf", id: p.id, layer: p.layer, pose: p.pose, data: p.data, parent: p.parent };
|
|
22061
22586
|
state.nodes.set(p.id, node);
|
|
22062
22587
|
attach(p.id, p.parent, p.index);
|
|
22063
|
-
if (p.kind === "container") {
|
|
22064
|
-
const cached = pendingClipPatches.get(p.id);
|
|
22065
|
-
if (cached) {
|
|
22066
|
-
node.clipFromPose = cached;
|
|
22067
|
-
} else if (p.clipKey !== void 0) {
|
|
22068
|
-
const fn = registry2.clipFromPose?.[p.clipKey];
|
|
22069
|
-
if (fn) {
|
|
22070
|
-
node.clipFromPose = fn;
|
|
22071
|
-
pendingClipPatches.set(p.id, fn);
|
|
22072
|
-
} else {
|
|
22073
|
-
dwarn("scene", `kit:add: clipKey "${p.clipKey}" not in this scene's registry \u2014 container "${p.id}" restored without clip. Register a function with this key in the registry option to restore the clip.`);
|
|
22074
|
-
}
|
|
22075
|
-
}
|
|
22076
|
-
}
|
|
22077
22588
|
if (p.dependsOn !== void 0) node.dependsOn = p.dependsOn;
|
|
22078
|
-
|
|
22079
|
-
|
|
22080
|
-
|
|
22081
|
-
|
|
22082
|
-
|
|
22083
|
-
const
|
|
22084
|
-
if (
|
|
22085
|
-
|
|
22086
|
-
|
|
22087
|
-
} else {
|
|
22088
|
-
dwarn("scene", `kit:add: derivePathKey "${p.derivePathKey}" not in this scene's registry \u2014 node "${p.id}" restored without derived geometry. Register a function with this key in the registry option to restore it.`);
|
|
22589
|
+
if (p.pickable !== void 0) node.pickable = p.pickable;
|
|
22590
|
+
dependents.add(p.id, p.dependsOn === "children" ? [] : p.dependsOn ?? []);
|
|
22591
|
+
trackChildDerived(p.id, p.dependsOn);
|
|
22592
|
+
const target = node;
|
|
22593
|
+
for (const field of fnFields) {
|
|
22594
|
+
const cached = field.pending.get(p.id);
|
|
22595
|
+
if (cached !== void 0) {
|
|
22596
|
+
field.write(target, cached);
|
|
22597
|
+
continue;
|
|
22089
22598
|
}
|
|
22599
|
+
const key = p[field.spec.opKey];
|
|
22600
|
+
if (key !== void 0) restoreFn(field, target, key, "kit:add", dwarn);
|
|
22090
22601
|
}
|
|
22091
22602
|
invalidateDependents(p.id);
|
|
22092
22603
|
},
|
|
@@ -22094,6 +22605,8 @@ function createScene(options) {
|
|
|
22094
22605
|
detach(p.id);
|
|
22095
22606
|
state.nodes.delete(p.id);
|
|
22096
22607
|
dependents.remove(p.id);
|
|
22608
|
+
childDerived.delete(p.id);
|
|
22609
|
+
invalidateChildDerivedFrom(p.parent);
|
|
22097
22610
|
invalidateDependents(p.id);
|
|
22098
22611
|
}
|
|
22099
22612
|
});
|
|
@@ -22103,7 +22616,9 @@ function createScene(options) {
|
|
|
22103
22616
|
for (const n of p.nodes) {
|
|
22104
22617
|
state.nodes.delete(n.id);
|
|
22105
22618
|
dependents.remove(n.id);
|
|
22619
|
+
childDerived.delete(n.id);
|
|
22106
22620
|
}
|
|
22621
|
+
for (const d of p.detached) invalidateChildDerivedFrom(d.parent);
|
|
22107
22622
|
},
|
|
22108
22623
|
revert: (p) => {
|
|
22109
22624
|
const keys = new Map((p.fnKeys ?? []).map((k) => [k.id, k]));
|
|
@@ -22111,9 +22626,11 @@ function createScene(options) {
|
|
|
22111
22626
|
const clone = n.kind === "container" ? { ...n, children: [...n.children] } : { ...n };
|
|
22112
22627
|
restoreNodeFunctions(clone, keys.get(n.id));
|
|
22113
22628
|
state.nodes.set(n.id, clone);
|
|
22114
|
-
dependents.add(n.id, clone.dependsOn ?? []);
|
|
22629
|
+
dependents.add(n.id, clone.dependsOn === "children" ? [] : clone.dependsOn ?? []);
|
|
22630
|
+
trackChildDerived(n.id, clone.dependsOn);
|
|
22115
22631
|
}
|
|
22116
22632
|
for (const d of p.detached) attach(d.id, d.parent, d.index);
|
|
22633
|
+
for (const d of p.detached) invalidateChildDerivedFrom(d.parent);
|
|
22117
22634
|
}
|
|
22118
22635
|
});
|
|
22119
22636
|
registerKitOp("kit:setPose", {
|
|
@@ -22129,9 +22646,11 @@ function createScene(options) {
|
|
|
22129
22646
|
registerKitOp("kit:setData", {
|
|
22130
22647
|
apply: (p) => {
|
|
22131
22648
|
requireNode(p.id).data = p.to;
|
|
22649
|
+
invalidateDependents(p.id);
|
|
22132
22650
|
},
|
|
22133
22651
|
revert: (p) => {
|
|
22134
22652
|
requireNode(p.id).data = p.from;
|
|
22653
|
+
invalidateDependents(p.id);
|
|
22135
22654
|
}
|
|
22136
22655
|
});
|
|
22137
22656
|
registerKitOp("kit:setLayer", {
|
|
@@ -22139,21 +22658,33 @@ function createScene(options) {
|
|
|
22139
22658
|
requireLayerIndex(p.to);
|
|
22140
22659
|
requireNode(p.id).layer = p.to;
|
|
22141
22660
|
invalidateOrder();
|
|
22661
|
+
invalidateDependents(p.id);
|
|
22142
22662
|
},
|
|
22143
22663
|
revert: (p) => {
|
|
22144
22664
|
requireNode(p.id).layer = p.from;
|
|
22145
22665
|
invalidateOrder();
|
|
22666
|
+
invalidateDependents(p.id);
|
|
22667
|
+
}
|
|
22668
|
+
});
|
|
22669
|
+
registerKitOp("kit:setDependsOn", {
|
|
22670
|
+
apply: (p) => {
|
|
22671
|
+
retarget(p.id, p.to);
|
|
22672
|
+
},
|
|
22673
|
+
revert: (p) => {
|
|
22674
|
+
retarget(p.id, p.from);
|
|
22146
22675
|
}
|
|
22147
22676
|
});
|
|
22148
22677
|
registerKitOp("kit:move", {
|
|
22149
22678
|
apply: (p) => {
|
|
22150
22679
|
detach(p.id);
|
|
22151
22680
|
attach(p.id, p.toParent, p.toIndex);
|
|
22681
|
+
invalidateChildDerivedFrom(p.fromParent);
|
|
22152
22682
|
invalidateDependents(p.id);
|
|
22153
22683
|
},
|
|
22154
22684
|
revert: (p) => {
|
|
22155
22685
|
detach(p.id);
|
|
22156
22686
|
attach(p.id, p.fromParent, p.fromIndex);
|
|
22687
|
+
invalidateChildDerivedFrom(p.toParent);
|
|
22157
22688
|
invalidateDependents(p.id);
|
|
22158
22689
|
}
|
|
22159
22690
|
});
|
|
@@ -22426,8 +22957,6 @@ function createScene(options) {
|
|
|
22426
22957
|
}
|
|
22427
22958
|
const sibs = siblingsOf(parent);
|
|
22428
22959
|
const index = spec.index ?? sibs.length;
|
|
22429
|
-
const clipKey = spec.kind === "container" && spec.clipFromPose !== void 0 ? reverseClipFromPose.get(spec.clipFromPose) : void 0;
|
|
22430
|
-
const derivePathKey = spec.derivePath !== void 0 ? reverseDerivePath.get(spec.derivePath) : void 0;
|
|
22431
22960
|
executeAndLog("kit:add", {
|
|
22432
22961
|
id,
|
|
22433
22962
|
kind: spec.kind,
|
|
@@ -22436,12 +22965,11 @@ function createScene(options) {
|
|
|
22436
22965
|
data: spec.data,
|
|
22437
22966
|
parent,
|
|
22438
22967
|
index,
|
|
22439
|
-
...clipKey !== void 0 ? { clipKey } : {},
|
|
22440
22968
|
...spec.dependsOn !== void 0 ? { dependsOn: spec.dependsOn } : {},
|
|
22441
|
-
...
|
|
22969
|
+
...spec.pickable !== void 0 ? { pickable: spec.pickable } : {},
|
|
22970
|
+
...fnKeysOf(fnFields, { ...spec, id, kind: spec.kind }, "opKey")
|
|
22442
22971
|
}, `add ${spec.kind}`);
|
|
22443
|
-
|
|
22444
|
-
patchDerivePath(spec, id, { cacheForRedo: true });
|
|
22972
|
+
patchNodeFunctions(spec, id, { cacheForRedo: true });
|
|
22445
22973
|
return id;
|
|
22446
22974
|
},
|
|
22447
22975
|
remove(id) {
|
|
@@ -22460,13 +22988,8 @@ function createScene(options) {
|
|
|
22460
22988
|
const detached = snapshot.filter((n) => n.parent === null || !removing.has(n.parent)).map((n) => ({ id: n.id, parent: n.parent, index: siblingsOf(n.parent).indexOf(n.id) })).sort((l, r) => l.index - r.index);
|
|
22461
22989
|
for (const nid of ids) overrides.clear(nid);
|
|
22462
22990
|
const fnKeys = snapshot.flatMap((n) => {
|
|
22463
|
-
const
|
|
22464
|
-
|
|
22465
|
-
return derivePathKey === void 0 && clipKey === void 0 ? [] : [{
|
|
22466
|
-
id: n.id,
|
|
22467
|
-
...derivePathKey !== void 0 ? { derivePathKey } : {},
|
|
22468
|
-
...clipKey !== void 0 ? { clipKey } : {}
|
|
22469
|
-
}];
|
|
22991
|
+
const keys = fnKeysOf(fnFields, n, "opKey");
|
|
22992
|
+
return Object.keys(keys).length === 0 ? [] : [{ id: n.id, ...keys }];
|
|
22470
22993
|
});
|
|
22471
22994
|
const payload = {
|
|
22472
22995
|
nodes: snapshot,
|
|
@@ -22516,6 +23039,15 @@ function createScene(options) {
|
|
|
22516
23039
|
});
|
|
22517
23040
|
}
|
|
22518
23041
|
},
|
|
23042
|
+
setDependsOn(id, dependsOn) {
|
|
23043
|
+
const node = requireNode(id);
|
|
23044
|
+
if (sameDependsOn(node.dependsOn, dependsOn)) return;
|
|
23045
|
+
executeAndLog(
|
|
23046
|
+
"kit:setDependsOn",
|
|
23047
|
+
{ id, from: node.dependsOn, to: dependsOn },
|
|
23048
|
+
"setDependsOn"
|
|
23049
|
+
);
|
|
23050
|
+
},
|
|
22519
23051
|
move(id, parent, index) {
|
|
22520
23052
|
const node = requireNode(id);
|
|
22521
23053
|
if (parent !== null) {
|
|
@@ -22744,25 +23276,17 @@ function createScene(options) {
|
|
|
22744
23276
|
data: n.data
|
|
22745
23277
|
};
|
|
22746
23278
|
if (n.parent != null) out.parent = n.parent;
|
|
22747
|
-
if (n.
|
|
22748
|
-
|
|
22749
|
-
|
|
22750
|
-
|
|
22751
|
-
|
|
22752
|
-
|
|
22753
|
-
}
|
|
22754
|
-
out.clipFromPoseKey = key;
|
|
22755
|
-
}
|
|
22756
|
-
if (n.dependsOn && n.dependsOn.length > 0) out.dependsOn = n.dependsOn;
|
|
22757
|
-
if (n.derivePath) {
|
|
22758
|
-
const key = reverseDerivePath.get(n.derivePath);
|
|
22759
|
-
if (!key) {
|
|
23279
|
+
if (n.dependsOn === "children") out.dependsOn = "children";
|
|
23280
|
+
else if (n.dependsOn && n.dependsOn.length > 0) out.dependsOn = n.dependsOn;
|
|
23281
|
+
if (n.pickable === false) out.pickable = false;
|
|
23282
|
+
Object.assign(
|
|
23283
|
+
out,
|
|
23284
|
+
fnKeysOf(fnFields, n, "jsonKey", (field) => {
|
|
22760
23285
|
throw new Error(
|
|
22761
|
-
`Scene.toJSON: node '${id}' has
|
|
23286
|
+
`Scene.toJSON: node '${id}' has ${field.spec.field} but no matching registry key. The function must be registered via createScene's registry option to round-trip.`
|
|
22762
23287
|
);
|
|
22763
|
-
}
|
|
22764
|
-
|
|
22765
|
-
}
|
|
23288
|
+
})
|
|
23289
|
+
);
|
|
22766
23290
|
nodes.push(out);
|
|
22767
23291
|
}
|
|
22768
23292
|
const systemLayers = state.layers.map((l) => {
|
|
@@ -22794,8 +23318,7 @@ function createScene(options) {
|
|
|
22794
23318
|
state.layerIndex.set(spec.id, i);
|
|
22795
23319
|
}
|
|
22796
23320
|
history.clear();
|
|
22797
|
-
|
|
22798
|
-
pendingDerivePathPatches.clear();
|
|
23321
|
+
for (const field of fnFields) field.pending.clear();
|
|
22799
23322
|
currentBatch = null;
|
|
22800
23323
|
batchDepth = 0;
|
|
22801
23324
|
batchDirty = false;
|
|
@@ -22833,18 +23356,19 @@ function createScene(options) {
|
|
|
22833
23356
|
data: spec.data,
|
|
22834
23357
|
parent,
|
|
22835
23358
|
index,
|
|
22836
|
-
...spec.dependsOn !== void 0 ? { dependsOn: spec.dependsOn } : {}
|
|
23359
|
+
...spec.dependsOn !== void 0 ? { dependsOn: spec.dependsOn } : {},
|
|
23360
|
+
...spec.pickable !== void 0 ? { pickable: spec.pickable } : {}
|
|
22837
23361
|
});
|
|
22838
|
-
|
|
22839
|
-
patchDerivePath(spec, id, { cacheForRedo: false });
|
|
23362
|
+
patchNodeFunctions(spec, id, { cacheForRedo: false });
|
|
22840
23363
|
}
|
|
22841
23364
|
}
|
|
22842
23365
|
if (options.initial) {
|
|
22843
23366
|
applyConstructionSpecs(options.initial);
|
|
22844
23367
|
notify2();
|
|
22845
23368
|
}
|
|
22846
|
-
scene.__clipCacheSize = () =>
|
|
22847
|
-
scene.__derivePathCacheSize = () =>
|
|
23369
|
+
scene.__clipCacheSize = () => fnField("clipFromPose").pending.size;
|
|
23370
|
+
scene.__derivePathCacheSize = () => fnField("derivePath").pending.size;
|
|
23371
|
+
scene.__derivePoseCacheSize = () => fnField("derivePose").pending.size;
|
|
22848
23372
|
return scene;
|
|
22849
23373
|
}
|
|
22850
23374
|
function specsFromSerialized(json, registry2) {
|
|
@@ -22860,24 +23384,21 @@ function specsFromSerialized(json, registry2) {
|
|
|
22860
23384
|
data: n.data
|
|
22861
23385
|
};
|
|
22862
23386
|
if (n.parent !== void 0) spec.parent = n.parent;
|
|
22863
|
-
if (n.
|
|
22864
|
-
|
|
22865
|
-
|
|
22866
|
-
|
|
22867
|
-
|
|
22868
|
-
|
|
22869
|
-
|
|
22870
|
-
|
|
22871
|
-
|
|
22872
|
-
if (n.dependsOn !== void 0) spec.dependsOn = n.dependsOn;
|
|
22873
|
-
if (n.derivePathKey !== void 0) {
|
|
22874
|
-
const fn = registry2.derivePath?.[n.derivePathKey];
|
|
23387
|
+
if (n.pickable !== void 0) spec.pickable = n.pickable;
|
|
23388
|
+
if (n.dependsOn !== void 0) {
|
|
23389
|
+
spec.dependsOn = n.dependsOn === "children" ? "children" : n.dependsOn;
|
|
23390
|
+
}
|
|
23391
|
+
const serialized = n;
|
|
23392
|
+
for (const field of NODE_FN_FIELDS) {
|
|
23393
|
+
const key = serialized[field.jsonKey];
|
|
23394
|
+
if (key === void 0) continue;
|
|
23395
|
+
const fn = registry2[field.field]?.[key];
|
|
22875
23396
|
if (!fn) {
|
|
22876
23397
|
throw new Error(
|
|
22877
|
-
`Scene: unknown
|
|
23398
|
+
`Scene: unknown ${field.field} key '${key}'. Register a function with this key in the registry option.`
|
|
22878
23399
|
);
|
|
22879
23400
|
}
|
|
22880
|
-
spec.
|
|
23401
|
+
spec[field.field] = fn;
|
|
22881
23402
|
}
|
|
22882
23403
|
return spec;
|
|
22883
23404
|
});
|
|
@@ -23864,7 +24385,7 @@ function sceneToAdapter(scene, options = {}) {
|
|
|
23864
24385
|
const nid = asNodeId(id);
|
|
23865
24386
|
const n = scene.get(nid);
|
|
23866
24387
|
if (!n) throw new Error(`sceneToAdapter: unknown node "${id}"`);
|
|
23867
|
-
return effectivePose(scene
|
|
24388
|
+
return effectivePose(scene, n);
|
|
23868
24389
|
},
|
|
23869
24390
|
getParent(id) {
|
|
23870
24391
|
const n = scene.get(asNodeId(id));
|
|
@@ -23949,11 +24470,10 @@ function sceneToAdapter(scene, options = {}) {
|
|
|
23949
24470
|
id: node.id,
|
|
23950
24471
|
...index !== void 0 ? { index } : {},
|
|
23951
24472
|
...node.parent !== null ? { parent: node.parent } : {},
|
|
23952
|
-
...node.kind === "container" && node.clipFromPose ? { clipFromPose: node.clipFromPose } : {},
|
|
23953
24473
|
// Derivation travels with the node, or undo of a delete brings an
|
|
23954
24474
|
// edge back as a static path that never follows its endpoints again.
|
|
23955
24475
|
...node.dependsOn !== void 0 ? { dependsOn: node.dependsOn } : {},
|
|
23956
|
-
...node
|
|
24476
|
+
...fnFieldsOfNode(node)
|
|
23957
24477
|
});
|
|
23958
24478
|
},
|
|
23959
24479
|
removeNode(id) {
|
|
@@ -24183,20 +24703,13 @@ function useSceneSelectTool(args) {
|
|
|
24183
24703
|
};
|
|
24184
24704
|
}, [scene, commitInsert, insertLayer, layouts, selection]);
|
|
24185
24705
|
const wiredMoveOptions = useMemo(() => {
|
|
24186
|
-
const
|
|
24187
|
-
const n = scene.get(asNodeId(id));
|
|
24188
|
-
return n ? n.pose : null;
|
|
24189
|
-
};
|
|
24190
|
-
const merged = {
|
|
24191
|
-
cascadeWorldPose: defaultCascade,
|
|
24192
|
-
...moveOptions ?? {}
|
|
24193
|
-
};
|
|
24706
|
+
const merged = { ...moveOptions ?? {} };
|
|
24194
24707
|
if (snap2) {
|
|
24195
24708
|
const existing = merged.behaviors ?? [];
|
|
24196
24709
|
merged.behaviors = [snap(snap2), ...existing];
|
|
24197
24710
|
}
|
|
24198
24711
|
return merged;
|
|
24199
|
-
}, [
|
|
24712
|
+
}, [moveOptions, snap2]);
|
|
24200
24713
|
const wiredHitBody = useMemo(() => {
|
|
24201
24714
|
return (wx, wy, camera) => {
|
|
24202
24715
|
if (pickEveryProp) {
|
|
@@ -24339,7 +24852,7 @@ function usePreviewGhostLayer(args) {
|
|
|
24339
24852
|
}
|
|
24340
24853
|
if (idSet.size === 0) return [];
|
|
24341
24854
|
const sc = sceneRef.current;
|
|
24342
|
-
const
|
|
24855
|
+
const depOf2 = sceneDepLookup(sc);
|
|
24343
24856
|
const previewPoseFor = (id) => previewPoseIn(sources, id);
|
|
24344
24857
|
const previewDataFor = (id) => previewDataIn(sources, id);
|
|
24345
24858
|
const buildSubtree = (id) => {
|
|
@@ -24362,7 +24875,7 @@ function usePreviewGhostLayer(args) {
|
|
|
24362
24875
|
const clip = findShapeSilhouette(
|
|
24363
24876
|
effNode,
|
|
24364
24877
|
effPose,
|
|
24365
|
-
{ derivedPath: resolveDerivedPath(effNode,
|
|
24878
|
+
{ derivedPath: resolveDerivedPath(effNode, depOf2, (nid) => sc.childrenOf(nid)) }
|
|
24366
24879
|
);
|
|
24367
24880
|
if (clip) group.clip = clip;
|
|
24368
24881
|
}
|
|
@@ -27396,12 +27909,12 @@ function sceneAsHierarchy(scene) {
|
|
|
27396
27909
|
const node = scene.get(parentId);
|
|
27397
27910
|
return node && node.kind === "container" ? node.children : [];
|
|
27398
27911
|
},
|
|
27399
|
-
getPose: (id) => scene
|
|
27912
|
+
getPose: (id) => effectivePose(scene, scene.get(id))
|
|
27400
27913
|
};
|
|
27401
27914
|
}
|
|
27402
27915
|
function buildSceneViewCommands(scene, view, drawOne, extraCommands, alphaFor) {
|
|
27403
27916
|
const derived = withDerivedPaths(scene, drawOne);
|
|
27404
|
-
const
|
|
27917
|
+
const depLookup = sceneDepLookup(scene);
|
|
27405
27918
|
const wrappedDrawOne = (node, pose, v) => {
|
|
27406
27919
|
const overrideAlpha = scene.overrides.get(node.id)?.alpha ?? 1;
|
|
27407
27920
|
return wrapNodeOutput(
|
|
@@ -27417,7 +27930,8 @@ function buildSceneViewCommands(scene, view, drawOne, extraCommands, alphaFor) {
|
|
|
27417
27930
|
void 0,
|
|
27418
27931
|
((node) => resolveDerivedPath(
|
|
27419
27932
|
node,
|
|
27420
|
-
|
|
27933
|
+
depLookup,
|
|
27934
|
+
(id) => scene.childrenOf(id)
|
|
27421
27935
|
))
|
|
27422
27936
|
);
|
|
27423
27937
|
if (extraCommands && extraCommands.length > 0) {
|
|
@@ -27511,6 +28025,44 @@ function SceneViewCanvasInner(props) {
|
|
|
27511
28025
|
);
|
|
27512
28026
|
}
|
|
27513
28027
|
var SceneViewCanvas = SceneViewCanvasInner;
|
|
28028
|
+
var NEVER_SUBSCRIBE = () => () => {
|
|
28029
|
+
};
|
|
28030
|
+
var DEFAULT_LAYER = "default";
|
|
28031
|
+
function isTrivialOptions(options) {
|
|
28032
|
+
return !!options && typeof options === "object" && "items" in options && !("systemLayers" in options);
|
|
28033
|
+
}
|
|
28034
|
+
function useScene(options) {
|
|
28035
|
+
const sceneRef = useRef(null);
|
|
28036
|
+
if (sceneRef.current === null) {
|
|
28037
|
+
if (isTrivialOptions(options)) {
|
|
28038
|
+
const scene2 = createScene({
|
|
28039
|
+
systemLayers: [{ id: DEFAULT_LAYER }],
|
|
28040
|
+
historyLimit: options.historyLimit,
|
|
28041
|
+
generateId: options.generateId,
|
|
28042
|
+
initial: options.items.map((item) => ({
|
|
28043
|
+
kind: "leaf",
|
|
28044
|
+
layer: DEFAULT_LAYER,
|
|
28045
|
+
pose: item,
|
|
28046
|
+
data: item,
|
|
28047
|
+
id: asNodeId(item.id)
|
|
28048
|
+
}))
|
|
28049
|
+
});
|
|
28050
|
+
sceneRef.current = scene2;
|
|
28051
|
+
} else {
|
|
28052
|
+
sceneRef.current = createScene(
|
|
28053
|
+
options
|
|
28054
|
+
);
|
|
28055
|
+
}
|
|
28056
|
+
}
|
|
28057
|
+
const scene = sceneRef.current;
|
|
28058
|
+
const subscribed = options?.subscribe !== false;
|
|
28059
|
+
useSyncExternalStore(
|
|
28060
|
+
subscribed ? scene.subscribe : NEVER_SUBSCRIBE,
|
|
28061
|
+
scene.getVersion,
|
|
28062
|
+
scene.getVersion
|
|
28063
|
+
);
|
|
28064
|
+
return scene;
|
|
28065
|
+
}
|
|
27514
28066
|
|
|
27515
28067
|
// src/canvas/minimapMath.ts
|
|
27516
28068
|
var DEFAULT_FIT_PADDING = 8;
|
|
@@ -27547,7 +28099,7 @@ function sceneLeafBounds(scene, poseBounds) {
|
|
|
27547
28099
|
let any = false;
|
|
27548
28100
|
for (const node of scene.nodes.values()) {
|
|
27549
28101
|
if (node.kind !== "leaf") continue;
|
|
27550
|
-
const b = poseBounds(node
|
|
28102
|
+
const b = poseBounds(documentPose(scene, node));
|
|
27551
28103
|
if (b.x < minX) minX = b.x;
|
|
27552
28104
|
if (b.y < minY) minY = b.y;
|
|
27553
28105
|
const right = b.x + b.width;
|
|
@@ -28920,9 +29472,10 @@ function useSceneTextEdit(scene, container, options = {}) {
|
|
|
28920
29472
|
return get ? get(node.data) : { fill: node.data.fill, stroke: node.data.stroke };
|
|
28921
29473
|
},
|
|
28922
29474
|
getScreenPose: (id) => {
|
|
28923
|
-
const
|
|
29475
|
+
const scene2 = sceneRef.current;
|
|
29476
|
+
const node = scene2.get(asNodeId(id));
|
|
28924
29477
|
if (!node) return null;
|
|
28925
|
-
const pose = node
|
|
29478
|
+
const pose = effectivePose(scene2, node);
|
|
28926
29479
|
const style = optsRef.current.getStyle ? optsRef.current.getStyle(node.data) : node.data.style;
|
|
28927
29480
|
const view = resolveView2(optsRef.current.view);
|
|
28928
29481
|
const zoom = view ? view.scale.x : 1;
|
|
@@ -28980,11 +29533,12 @@ function useSceneTextEdit(scene, container, options = {}) {
|
|
|
28980
29533
|
for (let i = order.length - 1; i >= 0; i--) {
|
|
28981
29534
|
const node = order[i];
|
|
28982
29535
|
const text = readText(node.data);
|
|
29536
|
+
const at = effectivePose(sceneRef.current, node);
|
|
28983
29537
|
const pose = {
|
|
28984
|
-
x:
|
|
28985
|
-
y:
|
|
28986
|
-
width:
|
|
28987
|
-
height:
|
|
29538
|
+
x: at.x,
|
|
29539
|
+
y: at.y,
|
|
29540
|
+
width: at.width,
|
|
29541
|
+
height: at.height,
|
|
28988
29542
|
text,
|
|
28989
29543
|
runs: readRuns(node.data),
|
|
28990
29544
|
style: readStyle(node.data)
|
|
@@ -29218,6 +29772,54 @@ function polygonPathDistance(path, px, py) {
|
|
|
29218
29772
|
}
|
|
29219
29773
|
return best === Infinity ? Infinity : Math.sqrt(best);
|
|
29220
29774
|
}
|
|
29775
|
+
|
|
29776
|
+
// src/features/paths/pathAt.ts
|
|
29777
|
+
function pointAlongPath(path, t, opts = {}) {
|
|
29778
|
+
const polylines = extractPolylines(
|
|
29779
|
+
path,
|
|
29780
|
+
opts.flattenTolerance === void 0 ? {} : { flattenTolerance: opts.flattenTolerance }
|
|
29781
|
+
);
|
|
29782
|
+
const segments = [];
|
|
29783
|
+
let total = 0;
|
|
29784
|
+
let first;
|
|
29785
|
+
for (const pl of polylines) {
|
|
29786
|
+
const count = pl.points.length / 2;
|
|
29787
|
+
if (count === 0) continue;
|
|
29788
|
+
first ??= { x: pl.points[0], y: pl.points[1] };
|
|
29789
|
+
const last2 = pl.closed ? count : count - 1;
|
|
29790
|
+
for (let i = 0; i < last2; i++) {
|
|
29791
|
+
const j = (i + 1) % count;
|
|
29792
|
+
const ax = pl.points[i * 2];
|
|
29793
|
+
const ay = pl.points[i * 2 + 1];
|
|
29794
|
+
const bx = pl.points[j * 2];
|
|
29795
|
+
const by = pl.points[j * 2 + 1];
|
|
29796
|
+
const len = Math.hypot(bx - ax, by - ay);
|
|
29797
|
+
if (len === 0) continue;
|
|
29798
|
+
segments.push({ ax, ay, bx, by, len });
|
|
29799
|
+
total += len;
|
|
29800
|
+
}
|
|
29801
|
+
}
|
|
29802
|
+
if (first === void 0) return null;
|
|
29803
|
+
if (segments.length === 0) return { point: first, tangent: { x: 1, y: 0 } };
|
|
29804
|
+
const target = Math.min(Math.max(t, 0), 1) * total;
|
|
29805
|
+
let walked = 0;
|
|
29806
|
+
for (const seg of segments) {
|
|
29807
|
+
if (walked + seg.len < target) {
|
|
29808
|
+
walked += seg.len;
|
|
29809
|
+
continue;
|
|
29810
|
+
}
|
|
29811
|
+
const u = (target - walked) / seg.len;
|
|
29812
|
+
return {
|
|
29813
|
+
point: { x: seg.ax + (seg.bx - seg.ax) * u, y: seg.ay + (seg.by - seg.ay) * u },
|
|
29814
|
+
tangent: { x: (seg.bx - seg.ax) / seg.len, y: (seg.by - seg.ay) / seg.len }
|
|
29815
|
+
};
|
|
29816
|
+
}
|
|
29817
|
+
const last = segments[segments.length - 1];
|
|
29818
|
+
return {
|
|
29819
|
+
point: { x: last.bx, y: last.by },
|
|
29820
|
+
tangent: { x: (last.bx - last.ax) / last.len, y: (last.by - last.ay) / last.len }
|
|
29821
|
+
};
|
|
29822
|
+
}
|
|
29221
29823
|
var PLACEHOLDER_FILL = { color: "#ffffff" };
|
|
29222
29824
|
var PLACEHOLDER_STROKE = { paint: { color: "#ffffff" }, width: 1 };
|
|
29223
29825
|
function resolveOverride(base, override, tMs) {
|
|
@@ -30149,44 +30751,6 @@ function useArrayAdapter(options) {
|
|
|
30149
30751
|
ref.current = items;
|
|
30150
30752
|
return arrayAdapter({ ref, ...rest });
|
|
30151
30753
|
}
|
|
30152
|
-
var NEVER_SUBSCRIBE = () => () => {
|
|
30153
|
-
};
|
|
30154
|
-
var DEFAULT_LAYER = "default";
|
|
30155
|
-
function isTrivialOptions(options) {
|
|
30156
|
-
return !!options && typeof options === "object" && "items" in options && !("systemLayers" in options);
|
|
30157
|
-
}
|
|
30158
|
-
function useScene(options) {
|
|
30159
|
-
const sceneRef = useRef(null);
|
|
30160
|
-
if (sceneRef.current === null) {
|
|
30161
|
-
if (isTrivialOptions(options)) {
|
|
30162
|
-
const scene2 = createScene({
|
|
30163
|
-
systemLayers: [{ id: DEFAULT_LAYER }],
|
|
30164
|
-
historyLimit: options.historyLimit,
|
|
30165
|
-
generateId: options.generateId,
|
|
30166
|
-
initial: options.items.map((item) => ({
|
|
30167
|
-
kind: "leaf",
|
|
30168
|
-
layer: DEFAULT_LAYER,
|
|
30169
|
-
pose: item,
|
|
30170
|
-
data: item,
|
|
30171
|
-
id: asNodeId(item.id)
|
|
30172
|
-
}))
|
|
30173
|
-
});
|
|
30174
|
-
sceneRef.current = scene2;
|
|
30175
|
-
} else {
|
|
30176
|
-
sceneRef.current = createScene(
|
|
30177
|
-
options
|
|
30178
|
-
);
|
|
30179
|
-
}
|
|
30180
|
-
}
|
|
30181
|
-
const scene = sceneRef.current;
|
|
30182
|
-
const subscribed = options?.subscribe !== false;
|
|
30183
|
-
useSyncExternalStore(
|
|
30184
|
-
subscribed ? scene.subscribe : NEVER_SUBSCRIBE,
|
|
30185
|
-
scene.getVersion,
|
|
30186
|
-
scene.getVersion
|
|
30187
|
-
);
|
|
30188
|
-
return scene;
|
|
30189
|
-
}
|
|
30190
30754
|
function useGuides(initial = []) {
|
|
30191
30755
|
const [guides, setGuides] = useState(initial);
|
|
30192
30756
|
const ref = useRef(initial);
|
|
@@ -31814,6 +32378,6 @@ function mergeContributions(...bundles) {
|
|
|
31814
32378
|
return out;
|
|
31815
32379
|
}
|
|
31816
32380
|
|
|
31817
|
-
export { ALWAYS, ANCHOR_HIT_BASE_PX, ActionsProviderIfRoot, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, ArrowIcon, BUILTIN_MARKERS, BUNDLE_TOOLS, COARSE_TARGET_SCALE, CURVE_REPS, CanvasView, ColorOverrideRegistry, CropIcon, CursorCoordsHud, DEFAULT_ALPHA_DECAY, DEFAULT_ALPHA_MIN, DEFAULT_DEBUG_STROKES, DEFAULT_DEBUG_THEME, DEFAULT_DEVICE_PROFILE, DEFAULT_FILL_COLOR, DEFAULT_HANDLE_SIZE2 as DEFAULT_HANDLE_SIZE, DEFAULT_MAX_ZOOM, DEFAULT_MIN_ZOOM, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_SHAPE_FILL, DEFAULT_STROKE_COLOR, DEFAULT_VELOCITY_DECAY, DepRegistryProviderIfRoot, DeviceProfileProvider, DivideIcon, EASINGS, EFFECT_KIT_UNIFORMS, EFFECT_VERT_SRC, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, GHOST_STROKE, HANDLE_BASE_PX, HandIcon, IDENTITY_COLOR_MATRIX, IDENTITY_JOINT, IDENTITY_POSE_COMPOSITION, ImageIcon, IntersectIcon, KIT_SHAPE_KINDS, KIT_STANDARD_ACTION_IDS, LassoIcon, LineIcon, MIXED, MOVE_ANCHORS, MinimapCanvas, NEVER, OUTLINE_MIN_SCREEN_PX, PAINTED_CURSOR_LAYER_ID, PATH_ANCHOR_CHROME_ID, PenIcon, PencilIcon, PickHud, PointerProviderIfRoot, PolygonIcon, RECT_ALIGN_PROJECTION, ROTATION_HANDLE_BASE_PX, RectIcon, SPRING_PRESETS, SPRITE_STRIDE, SceneCanvas, SceneViewCanvas, SelectIcon, SelectionContextProvider, SelectionContextProviderIfRoot, ShaderCompileError, StarIcon, SubtractIcon, TOOL_PREF_KINDS, TextIcon, UnionIcon, UnknownIcon, VERSION, VIEW_ANIMATION_KEY, WHEEL_ZOOM_STEP, WeaselProvider, WeaselRenderer, _resetMarkersForTests, _resetPaintKindsForTests, aabbCenter, actionIs, actionShortcuts, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyBooleanOp, applyStyleToRange, areaSelectAction, arrayAdapter, asNodeId, asPaint, axisAlignedBounds, bezierCubic, bezierQuadratic, blendPoses, blur, buildChromeCtx, buildGradientRamp, buildRuleCtx, buildSceneViewCommands, canBringForward, canHover, canSendBackward, capabilityAll, capabilityIn, capabilityIs, capabilityNot, caretIndexAt, cellAt, charOffsetToDomPosition, clampView, clearSelectionAction, clientToCanvas, clipboardCopyAction, clipboardCutAction, cloneAction, coarsePointer, composeAffordanceLayer, composePath, composeRectPose, composeSelectionPose, composeWorldPose, computeFitView, computeFitViewport, computeIndicatorCommand, computeWheelAction, cond, constrainTo45, containedThenNearest, countPathAnchors, createCellHighlightLayer, createChildrenLayer, createCornerResizeAffordance, createDebugOverlayLayer, createDebugSink, createDispatcher, createGridLayer, createGuidesLayer, createHistory2 as createHistory, createMoveToIndexOp, createNodeProperties, createNodeRouting, createPaintedCursorLayer, createPaintedCursorState, createParallaxLayer, createPathAnchorAffordances, createPathEditingOverlayLayer, createPathLayer, createPenPreviewLayer, createReorderOp, createRotationAffordance, createScene, createSelectionHandlesLayer, createSelectionOutlineLayer, createSelectionOverlayLayer, createSetDataOp, createSetLayerOp, createSetPathOp, createSetTextOp, createTextLayer, createVelocityTracker, createViewResolver, createViewportLayer, cubicBezierEasing, cycleVertexColors, decomposePath, decomposeRectPose, defaultCommitAdapter, defaultDrawOne, defaultLabelTextRenderer, defaultNodeProperties, defaultNodeRouting, defaultVisibilityRules, defineTool, defineViewportTool, deriveAlignmentGuides, deriveParallaxView, describeRule, domPositionToCharOffset, domToRuns, drawLayers, drawOneLayer, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorsAction, enterTextEditAction, enumerateAnchors, evaluate, fillInPoseFrame, fillToBoundsFrame, findNodeShape, findShapeInk, findShapeSilhouette, fitTextPose, fitToBounds, fitViewToBounds, fitZoom, focused, forEachCoalesced, frameRect, freeform, gateLayer, gesturing, getAlpha01, getImageBitmap, getMarker, getNodeShapes, getPaintKind, getStylusData, gradientForBounds, gradientGeometry, hexToRgba, hitAffordanceRegions, hitAnchor, hitRotationHandle, hostAnchorCss, hostAnchorRect, hovering, hoveringSelected, imageStatus, inferredNodeProperties, inferredNodeRouting, insertAction, interpolateView, isBuiltinToolPref, isEditableTarget, isGradientFill, isLayerPainted, isLayerVisible, isPatternSpec, keySpecShortcut, lassoSelectAction, lerpColorArray, lerpOklab, lerpOklch, linear, listMarkers, listPaintKinds, liveScope, makePinchZoomAction, makeViewportWheelPanAction, makeViewportZoomAction, markerDrawCommands, markerInset, markerKeyOf, markerSites, mat3, matchAlignment, matchesKeyBinding, meanScale, mergeAlphaFromPrev, mergeContributions, modeIn, modeIs, modeNot, modifierHeld, momentum, moveAction, multiActive, nearest, nearestWithin, nestedHitTester, never, nodeHasFlag, none, normalizeHex, not, nurbs, oklabToOklch, oklabToSrgbU8, oklchToOklab, openFilePicker, openPointerSession, or, paintAlpha, paintKindOf, paintWithAlpha, paintWithColor, parseColor, parseColorToRgba255, parseDebugFlags, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathDivide, pathExclude, pathFromD, pathInPoseFrame, pathInWorld, pathIntersect, pathIntersectsPolygon, pathIntersectsRect, pathOriginProjection, pathSubtract, pathToAnchors, pathUnion, pickTopMostHit, pinchZoomAction, planPixelRender, pointInRotatedRect, pointInTextPose, poseRotationOf, pressureToWidth, rainbowVertexColors, rebaseLocalPose, rectCorners, registerContentHandler, registerEffect, registerMarker, registerNodeShape, registerPaintKind, registerProgram, renderLabel, renderSceneToCanvas, renderSceneToPixels, resizeAction, resolveColor, resolveDeviceProfile, resolveEasing, resolveFillPattern, resolveMarkerSize, resolveParams, resolvePatternSpec, resolveSkeleton, resolveStrokeWidth, resolveVisibility, rgbaToHex, rotateAction, rotateAroundAABBCenter, rotatePathAround, rotatePoint, rotatedRectCorners, rotationDegreesUnit, rotationHandle, roundToCell, runsToDom, sampleGradientStops, sampleTrack, sceneFromJSON, sceneNodeClientRect, sceneSelectionStore, sceneToAdapter, scopeBindings, screenToWorld, selectFromLasso, selectionAtLeast, selectionEmpty, selectionIs, setFlagOverRange, shapeCoversPoint, sliceAction, snapPoint, solid, solidVertexColors, specificity, spiro, splitPathByLine, splitSubpaths, springPose, springVertexColors, srgbU8ToOklab, staggerVertexColors, startThresholdDrag, strokeInsets, strokeOf, strokeWith, styleAtRange, subscribeImageReady, tessellate, tessellateStroke, textCommand, textCommandFromRuns, tileGrid, toHex8, translatePoseViaDescriptor, translateRectPose, trimPolyline, tweenPose, tweenVertexColors, unionAABB, unionBounds, unionBoundsPath, useActiveToolContext, useAlign, useAnimator, useArrayAdapter, useAutoCenter, useBooleans, useBooleansAdapter, useCanvasFocus, useCanvasSize, useDecayLoop, useDeviceProfile, useDistribute, useDragGesture, useDragHandle, useDragRadial, useDragRect, useDropZone, useEllipseTool, useEyedropperTool, useGestureDispatcher, useGridCellHover, useGuides, useHandTool, useHandleDrag, useHostAnchor, useHoverTracking, useImageTool, useKeybindings, useLassoTool, useLineTool, useNodeOverlayFrame, useOptionalActiveToolContext, usePenTool, usePencilTool, usePinchGesture, usePointerStylus, usePolygonTool, usePublishSelection, useRectTool, useResizePolicy, useRotateTool, useScene, useSceneAdapter, useSceneTextEdit, useSelectTool, useSelection, useSelectionContext, useSimulation, useSliceDep, useStandardActions, useStarTool, useTextEdit, useTextTool, useTools, useVelocityTracker, useViewAnimation, useVisibleRaf, viewToMat3, viewToTransform, viewportDragPanAction, viewportWheelPanAction, viewportZoomAction, viewportsAt, vignette, visualBoundsViaDescriptor, wheelPan, wheelZoom, wheelZoomFactor, when, withAlpha01, withCoord, withGradientKind, worldEditToStorage, worldPoseLookup, worldToScreen, zoomAt, zoomAtLeast };
|
|
31818
|
-
//# sourceMappingURL=chunk-
|
|
31819
|
-
//# sourceMappingURL=chunk-
|
|
32381
|
+
export { ALWAYS, ANCHOR_HIT_BASE_PX, ActionsProviderIfRoot, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, ArrowIcon, BUILTIN_MARKERS, BUNDLE_TOOLS, COARSE_TARGET_SCALE, CURVE_REPS, CanvasView, ColorOverrideRegistry, CropIcon, CursorCoordsHud, DEFAULT_ALPHA_DECAY, DEFAULT_ALPHA_MIN, DEFAULT_DEBUG_STROKES, DEFAULT_DEBUG_THEME, DEFAULT_DEVICE_PROFILE, DEFAULT_FILL_COLOR, DEFAULT_HANDLE_SIZE2 as DEFAULT_HANDLE_SIZE, DEFAULT_MAX_ZOOM, DEFAULT_MIN_ZOOM, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_SHAPE_FILL, DEFAULT_STROKE_COLOR, DEFAULT_VELOCITY_DECAY, DepRegistryProviderIfRoot, DeviceProfileProvider, DivideIcon, EASINGS, EFFECT_KIT_UNIFORMS, EFFECT_VERT_SRC, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, GHOST_STROKE, HANDLE_BASE_PX, HandIcon, IDENTITY_COLOR_MATRIX, IDENTITY_JOINT, IDENTITY_POSE_COMPOSITION, ImageIcon, IntersectIcon, KIT_SHAPE_KINDS, KIT_STANDARD_ACTION_IDS, LassoIcon, LineIcon, MIXED, MOVE_ANCHORS, MinimapCanvas, NEVER, OUTLINE_MIN_SCREEN_PX, PAINTED_CURSOR_LAYER_ID, PATH_ANCHOR_CHROME_ID, PenIcon, PencilIcon, PickHud, PointerProviderIfRoot, PolygonIcon, RECT_ALIGN_PROJECTION, ROTATION_HANDLE_BASE_PX, RectIcon, SPRING_PRESETS, SPRITE_STRIDE, SceneCanvas, SceneViewCanvas, SelectIcon, SelectionContextProvider, SelectionContextProviderIfRoot, ShaderCompileError, StarIcon, SubtractIcon, TOOL_PREF_KINDS, TextIcon, UNION_OF_CHILDREN, UnionIcon, UnknownIcon, VERSION, VIEW_ANIMATION_KEY, WHEEL_ZOOM_STEP, WeaselProvider, WeaselRenderer, _resetMarkersForTests, _resetPaintKindsForTests, aabbCenter, actionIs, actionShortcuts, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyBooleanOp, applyStyleToRange, areaSelectAction, arrayAdapter, asNodeId, asPaint, axisAlignedBounds, bezierCubic, bezierQuadratic, blendPoses, blur, buildChromeCtx, buildGradientRamp, buildRuleCtx, buildSceneViewCommands, canBringForward, canHover, canSendBackward, capabilityAll, capabilityIn, capabilityIs, capabilityNot, caretIndexAt, cellAt, charOffsetToDomPosition, clampView, clearSelectionAction, clientToCanvas, clipboardCopyAction, clipboardCutAction, cloneAction, coarsePointer, composeAffordanceLayer, composePath, composeRectPose, composeSelectionPose, composeWorldPose, computeFitView, computeFitViewport, computeIndicatorCommand, computeWheelAction, cond, constrainTo45, containedThenNearest, countPathAnchors, createCellHighlightLayer, createChildrenLayer, createCornerResizeAffordance, createDebugOverlayLayer, createDebugSink, createDispatcher, createGridLayer, createGuidesLayer, createHistory2 as createHistory, createMoveToIndexOp, createNodeProperties, createNodeRouting, createPaintedCursorLayer, createPaintedCursorState, createParallaxLayer, createPathAnchorAffordances, createPathEditingOverlayLayer, createPathLayer, createPenPreviewLayer, createPoseOverrides, createReorderOp, createRotationAffordance, createScene, createSelectionHandlesLayer, createSelectionOutlineLayer, createSelectionOverlayLayer, createSetDataOp, createSetLayerOp, createSetPathOp, createSetTextOp, createSimulation, createTextLayer, createVelocityTracker, createViewResolver, createViewportLayer, cubicBezierEasing, cycleVertexColors, decomposePath, decomposeRectPose, defaultCommitAdapter, defaultDrawOne, defaultLabelTextRenderer, defaultNodeProperties, defaultNodeRouting, defaultVisibilityRules, defineTool, defineViewportTool, deriveAlignmentGuides, deriveParallaxView, derivedDepOf, derivedPose, describeRule, documentPose, domPositionToCharOffset, domToRuns, drawLayers, drawOneLayer, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorsAction, effectivePose, enterTextEditAction, enumerateAnchors, evaluate, fillInPoseFrame, fillToBoundsFrame, findNodeShape, findShapeInk, findShapeSilhouette, fitTextPose, fitToBounds, fitViewToBounds, fitZoom, focused, forEachCoalesced, frameRect, freeform, gateLayer, gesturing, getAlpha01, getImageBitmap, getMarker, getNodeShapes, getPaintKind, getStylusData, gradientForBounds, gradientGeometry, hexToRgba, hitAffordanceRegions, hitAnchor, hitRotationHandle, hostAnchorCss, hostAnchorRect, hovering, hoveringSelected, imageStatus, inferredNodeProperties, inferredNodeRouting, insertAction, interpolateView, isBuiltinToolPref, isEditableTarget, isGradientFill, isLayerPainted, isLayerVisible, isPatternSpec, keySpecShortcut, lassoSelectAction, lerpColorArray, lerpOklab, lerpOklch, linear, listMarkers, listPaintKinds, liveScope, makePinchZoomAction, makeViewportWheelPanAction, makeViewportZoomAction, markerDrawCommands, markerInset, markerKeyOf, markerSites, mat3, matchAlignment, matchesKeyBinding, meanScale, mergeAlphaFromPrev, mergeContributions, modeIn, modeIs, modeNot, modifierHeld, momentum, moveAction, multiActive, nearest, nearestWithin, nestedHitTester, never, nodeHasFlag, none, normalizeHex, not, nurbs, oklabToOklch, oklabToSrgbU8, oklchToOklab, openFilePicker, openPointerSession, or, paintAlpha, paintKindOf, paintWithAlpha, paintWithColor, parseColor, parseColorToRgba255, parseDebugFlags, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathDistanceToPoint, pathDivide, pathExclude, pathFromD, pathInPoseFrame, pathInWorld, pathIntersect, pathIntersectsPolygon, pathIntersectsRect, pathOriginProjection, pathSubtract, pathToAnchors, pathUnion, pickTopMostHit, pinchZoomAction, planPixelRender, pointAlongPath, pointInRotatedRect, pointInTextPose, poseRotationOf, pressureToWidth, rainbowVertexColors, rebaseLocalPose, rectCorners, registerContentHandler, registerEffect, registerMarker, registerNodeShape, registerPaintKind, registerProgram, renderLabel, renderSceneToCanvas, renderSceneToPixels, resizeAction, resolveColor, resolveDeviceProfile, resolveEasing, resolveFillPattern, resolveMarkerSize, resolveParams, resolvePatternSpec, resolveSkeleton, resolveStrokeWidth, resolveVisibility, rgbaToHex, rotateAction, rotateAroundAABBCenter, rotatePathAround, rotatePoint, rotatedRectCorners, rotationDegreesUnit, rotationHandle, roundToCell, runsToDom, sampleGradientStops, sampleTrack, sceneFromJSON, sceneNodeClientRect, sceneSelectionStore, sceneToAdapter, scopeBindings, screenToWorld, selectFromLasso, selectionAtLeast, selectionEmpty, selectionIs, setFlagOverRange, shapeCoversPoint, sliceAction, snapPoint, solid, solidVertexColors, specificity, spiro, splitPathByLine, splitSubpaths, springPose, springVertexColors, srgbU8ToOklab, staggerVertexColors, startThresholdDrag, strokeInsets, strokeOf, strokeWith, styleAtRange, subscribeImageReady, tessellate, tessellateStroke, textCommand, textCommandFromRuns, tileGrid, toHex8, translatePoseViaDescriptor, translateRectPose, trimPolyline, tweenPose, tweenVertexColors, unionAABB, unionBounds, unionBoundsPath, unionOfChildren, useActiveToolContext, useAlign, useAnimator, useArrayAdapter, useAutoCenter, useBooleans, useBooleansAdapter, useCanvasFocus, useCanvasSize, useDecayLoop, useDeviceProfile, useDistribute, useDragGesture, useDragHandle, useDragRadial, useDragRect, useDropZone, useEllipseTool, useEyedropperTool, useGestureDispatcher, useGridCellHover, useGuides, useHandTool, useHandleDrag, useHostAnchor, useHoverTracking, useImageTool, useKeybindings, useLassoTool, useLineTool, useNodeOverlayFrame, useOptionalActiveToolContext, usePenTool, usePencilTool, usePinchGesture, usePointerStylus, usePolygonTool, usePoseRun, usePublishSelection, useRectTool, useResizePolicy, useRotateTool, useScene, useSceneAdapter, useSceneTextEdit, useSelectTool, useSelection, useSelectionContext, useSimulation, useSliceDep, useStandardActions, useStarTool, useTextEdit, useTextTool, useTools, useVelocityTracker, useViewAnimation, useVisibleRaf, viewToMat3, viewToTransform, viewportDragPanAction, viewportWheelPanAction, viewportZoomAction, viewportsAt, vignette, visualBoundsViaDescriptor, wheelPan, wheelZoom, wheelZoomFactor, when, withAlpha01, withCoord, withGradientKind, worldEditToStorage, worldPoseLookup, worldToScreen, zoomAt, zoomAtLeast };
|
|
32382
|
+
//# sourceMappingURL=chunk-R3AWPTLZ.js.map
|
|
32383
|
+
//# sourceMappingURL=chunk-R3AWPTLZ.js.map
|