@weasel-js/core 1.0.0 → 1.0.1
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 +335 -0
- package/dist/{chunk-D2C6K6FO.js → chunk-FVNWK7U3.js} +613 -219
- package/dist/chunk-FVNWK7U3.js.map +1 -0
- package/dist/clipboard.d.ts +1 -1
- package/dist/{index-ChM3ZJ2v.d.ts → index-DPI8DV0A.d.ts} +1 -1
- package/dist/index.d.ts +41 -13
- package/dist/index.js +1 -1
- package/dist/renderer.d.ts +52 -8
- package/dist/renderer.js +1 -1
- package/dist/routing.d.ts +2 -2
- package/dist/{types-DUpI7Apc.d.ts → types-Kh_osAq9.d.ts} +8 -1
- package/package.json +6 -6
- package/dist/chunk-D2C6K6FO.js.map +0 -1
|
@@ -13,13 +13,13 @@ import earcut from 'earcut';
|
|
|
13
13
|
import { applyToPoint, rotateAboutPoint, boxToBox, pointInPolygon, segmentsCross } from '@weasel-js/geom';
|
|
14
14
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
15
15
|
import polygonClipping from 'polygon-clipping';
|
|
16
|
-
import { matchSpec, mimeMatchesGlob } from '@weasel-js/gestures';
|
|
16
|
+
import { matchSpec, parseTargetSpec, mimeMatchesGlob } from '@weasel-js/gestures';
|
|
17
17
|
import { NORMAL, IMPLICIT_TAGS } from '@weasel-js/modes';
|
|
18
18
|
import { createHistory } from '@weasel-js/history';
|
|
19
19
|
export * from '@weasel-js/history';
|
|
20
20
|
|
|
21
21
|
// src/version.ts
|
|
22
|
-
var VERSION = "1.0.
|
|
22
|
+
var VERSION = "1.0.1" ;
|
|
23
23
|
|
|
24
24
|
// src/features/grid/roundToCell.ts
|
|
25
25
|
function roundToCell(value, cellSize) {
|
|
@@ -2224,7 +2224,7 @@ function warnMissingGlyphOnce(family, cp) {
|
|
|
2224
2224
|
`weasel layoutRuns: no glyph for U+${cp.toString(16).toUpperCase().padStart(4, "0")} (${JSON.stringify(ch)}) in "${family}", and the dynamic tier could not rasterize it \u2014 skipping the character. Bake it into the atlas, or call registerCanvasFont("${family}") to serve missing codepoints from installed fonts.`
|
|
2225
2225
|
);
|
|
2226
2226
|
}
|
|
2227
|
-
function layoutRuns(runs, opts
|
|
2227
|
+
function layoutRuns(runs, opts) {
|
|
2228
2228
|
const ctx = { groups: /* @__PURE__ */ new Map() };
|
|
2229
2229
|
const entries = [];
|
|
2230
2230
|
let prevCp;
|
|
@@ -2394,7 +2394,7 @@ function layoutRuns(runs, opts, origin) {
|
|
|
2394
2394
|
}
|
|
2395
2395
|
}
|
|
2396
2396
|
const lineBoxes = [];
|
|
2397
|
-
let penY =
|
|
2397
|
+
let penY = 0;
|
|
2398
2398
|
let maxLineWidth = 0;
|
|
2399
2399
|
const finiteWidth = Number.isFinite(opts.maxWidth) ? opts.maxWidth : 0;
|
|
2400
2400
|
for (const line of lines) {
|
|
@@ -2406,7 +2406,7 @@ function layoutRuns(runs, opts, origin) {
|
|
|
2406
2406
|
const slack = finiteWidth - line.width;
|
|
2407
2407
|
return opts.align === "center" ? slack / 2 : slack;
|
|
2408
2408
|
})();
|
|
2409
|
-
const lineX0 =
|
|
2409
|
+
const lineX0 = alignShift;
|
|
2410
2410
|
const baselineSource = line.entries[0] ?? line.blank;
|
|
2411
2411
|
const lineBaselineY = baselineSource ? penY + baselineSource.font.common.base * (baselineSource.fontSize / baselineSource.font.info.size) : penY;
|
|
2412
2412
|
let penX = lineX0;
|
|
@@ -2480,7 +2480,7 @@ function layoutRuns(runs, opts, origin) {
|
|
|
2480
2480
|
groups: [...ctx.groups.values()],
|
|
2481
2481
|
decorations,
|
|
2482
2482
|
lines: lineBoxes,
|
|
2483
|
-
bounds: { width: maxLineWidth, height: penY
|
|
2483
|
+
bounds: { width: maxLineWidth, height: penY }
|
|
2484
2484
|
};
|
|
2485
2485
|
}
|
|
2486
2486
|
var LAYOUT_CACHE_VARIANT_LIMIT = 8;
|
|
@@ -2493,10 +2493,10 @@ function outlineBucket(runs, min) {
|
|
|
2493
2493
|
for (const size of sizes) if (size >= min) n++;
|
|
2494
2494
|
return n;
|
|
2495
2495
|
}
|
|
2496
|
-
function variantKey(runs, opts
|
|
2497
|
-
return `${opts.maxWidth}|${opts.lineHeight}|${opts.align}|${outlineBucket(runs, opts.outlineMinSize)}
|
|
2496
|
+
function variantKey(runs, opts) {
|
|
2497
|
+
return `${opts.maxWidth}|${opts.lineHeight}|${opts.align}|${outlineBucket(runs, opts.outlineMinSize)}`;
|
|
2498
2498
|
}
|
|
2499
|
-
function cachedLayoutRuns(runs, opts
|
|
2499
|
+
function cachedLayoutRuns(runs, opts) {
|
|
2500
2500
|
const fonts = glyphGeneration();
|
|
2501
2501
|
let entry = cache2.get(runs);
|
|
2502
2502
|
if (entry === void 0) {
|
|
@@ -2506,10 +2506,10 @@ function cachedLayoutRuns(runs, opts, origin) {
|
|
|
2506
2506
|
entry.generation = fonts;
|
|
2507
2507
|
entry.byVariant.clear();
|
|
2508
2508
|
}
|
|
2509
|
-
const key = variantKey(runs, opts
|
|
2509
|
+
const key = variantKey(runs, opts);
|
|
2510
2510
|
const hit = entry.byVariant.get(key);
|
|
2511
2511
|
if (hit !== void 0) return hit;
|
|
2512
|
-
const laid = layoutRuns(runs, opts
|
|
2512
|
+
const laid = layoutRuns(runs, opts);
|
|
2513
2513
|
if (entry.byVariant.size >= LAYOUT_CACHE_VARIANT_LIMIT) entry.byVariant.clear();
|
|
2514
2514
|
entry.byVariant.set(key, laid);
|
|
2515
2515
|
return laid;
|
|
@@ -2827,26 +2827,267 @@ function outlineStrokeMesh(glyphKey, d, emWidth, stroke) {
|
|
|
2827
2827
|
return mesh.indices.length === 0 ? null : mesh;
|
|
2828
2828
|
}
|
|
2829
2829
|
|
|
2830
|
+
// src/renderer/solidBatch.ts
|
|
2831
|
+
var MAX_VERTICES_PER_BATCH = 32768;
|
|
2832
|
+
var FLOATS_PER_VERTEX = 6;
|
|
2833
|
+
var INITIAL_VERTICES = 256;
|
|
2834
|
+
var INITIAL_INDICES = 384;
|
|
2835
|
+
var SolidBatch = class {
|
|
2836
|
+
gl;
|
|
2837
|
+
vao;
|
|
2838
|
+
vbo;
|
|
2839
|
+
ibo;
|
|
2840
|
+
verts = new Float32Array(INITIAL_VERTICES * FLOATS_PER_VERTEX);
|
|
2841
|
+
idx = new Uint32Array(INITIAL_INDICES);
|
|
2842
|
+
nVerts = 0;
|
|
2843
|
+
nIdx = 0;
|
|
2844
|
+
/** What the GPU buffers are currently sized for. */
|
|
2845
|
+
vboVerts = 0;
|
|
2846
|
+
iboIdx = 0;
|
|
2847
|
+
constructor(gl, prog) {
|
|
2848
|
+
const aPos = prog.attribute("a_position");
|
|
2849
|
+
const aColor = prog.attribute("a_vertexColor");
|
|
2850
|
+
if (aPos === void 0 || aColor === void 0) {
|
|
2851
|
+
throw new Error("SolidBatch: vertex-color program is missing a_position / a_vertexColor");
|
|
2852
|
+
}
|
|
2853
|
+
const vao = gl.createVertexArray();
|
|
2854
|
+
const vbo = gl.createBuffer();
|
|
2855
|
+
const ibo = gl.createBuffer();
|
|
2856
|
+
if (!vao || !vbo || !ibo) throw new Error("SolidBatch: failed to create GL objects");
|
|
2857
|
+
this.gl = gl;
|
|
2858
|
+
this.vao = vao;
|
|
2859
|
+
this.vbo = vbo;
|
|
2860
|
+
this.ibo = ibo;
|
|
2861
|
+
const stride = FLOATS_PER_VERTEX * 4;
|
|
2862
|
+
gl.bindVertexArray(vao);
|
|
2863
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
2864
|
+
gl.enableVertexAttribArray(aPos);
|
|
2865
|
+
gl.vertexAttribPointer(aPos, 2, gl.FLOAT, false, stride, 0);
|
|
2866
|
+
gl.enableVertexAttribArray(aColor);
|
|
2867
|
+
gl.vertexAttribPointer(aColor, 4, gl.FLOAT, false, stride, 8);
|
|
2868
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibo);
|
|
2869
|
+
gl.bindVertexArray(null);
|
|
2870
|
+
this.growGpu(INITIAL_VERTICES, INITIAL_INDICES);
|
|
2871
|
+
}
|
|
2872
|
+
get length() {
|
|
2873
|
+
return this.nIdx;
|
|
2874
|
+
}
|
|
2875
|
+
/** Whether staging `vertices` more would put the run past the per-flush cap. */
|
|
2876
|
+
wouldOverflow(vertices) {
|
|
2877
|
+
return this.nVerts + vertices > MAX_VERTICES_PER_BATCH;
|
|
2878
|
+
}
|
|
2879
|
+
/**
|
|
2880
|
+
* Append one rect's four corners through `m`, all carrying `rgba` (straight
|
|
2881
|
+
* alpha). An affine maps a rect to a parallelogram, so two triangles still
|
|
2882
|
+
* cover it and the batch draws at `u_model` identity.
|
|
2883
|
+
*/
|
|
2884
|
+
pushRect(x, y, w, h, m, r, g, b, a) {
|
|
2885
|
+
this.reserve(4, 6);
|
|
2886
|
+
const v = this.verts;
|
|
2887
|
+
let i = this.nVerts * FLOATS_PER_VERTEX;
|
|
2888
|
+
const ma = m[0], mb = m[1], mc = m[3], md = m[4], mtx = m[6], mty = m[7];
|
|
2889
|
+
const x1 = x + w;
|
|
2890
|
+
const y1 = y + h;
|
|
2891
|
+
const ax = ma * x + mc * y + mtx, ay = mb * x + md * y + mty;
|
|
2892
|
+
const bx = ma * x1 + mc * y + mtx, by = mb * x1 + md * y + mty;
|
|
2893
|
+
const cx = ma * x1 + mc * y1 + mtx, cy = mb * x1 + md * y1 + mty;
|
|
2894
|
+
const dx = ma * x + mc * y1 + mtx, dy = mb * x + md * y1 + mty;
|
|
2895
|
+
v[i++] = ax;
|
|
2896
|
+
v[i++] = ay;
|
|
2897
|
+
v[i++] = r;
|
|
2898
|
+
v[i++] = g;
|
|
2899
|
+
v[i++] = b;
|
|
2900
|
+
v[i++] = a;
|
|
2901
|
+
v[i++] = bx;
|
|
2902
|
+
v[i++] = by;
|
|
2903
|
+
v[i++] = r;
|
|
2904
|
+
v[i++] = g;
|
|
2905
|
+
v[i++] = b;
|
|
2906
|
+
v[i++] = a;
|
|
2907
|
+
v[i++] = cx;
|
|
2908
|
+
v[i++] = cy;
|
|
2909
|
+
v[i++] = r;
|
|
2910
|
+
v[i++] = g;
|
|
2911
|
+
v[i++] = b;
|
|
2912
|
+
v[i++] = a;
|
|
2913
|
+
v[i++] = dx;
|
|
2914
|
+
v[i++] = dy;
|
|
2915
|
+
v[i++] = r;
|
|
2916
|
+
v[i++] = g;
|
|
2917
|
+
v[i++] = b;
|
|
2918
|
+
v[i++] = a;
|
|
2919
|
+
const base = this.nVerts;
|
|
2920
|
+
let j = this.nIdx;
|
|
2921
|
+
this.idx[j++] = base;
|
|
2922
|
+
this.idx[j++] = base + 1;
|
|
2923
|
+
this.idx[j++] = base + 2;
|
|
2924
|
+
this.idx[j++] = base;
|
|
2925
|
+
this.idx[j++] = base + 2;
|
|
2926
|
+
this.idx[j++] = base + 3;
|
|
2927
|
+
this.nVerts += 4;
|
|
2928
|
+
this.nIdx += 6;
|
|
2929
|
+
}
|
|
2930
|
+
/**
|
|
2931
|
+
* Append a tessellated mesh through `m`, all vertices carrying `rgba`. The
|
|
2932
|
+
* mesh's own indices are rebased onto the staged vertices, which is why the
|
|
2933
|
+
* index buffer is uploaded per flush rather than written once.
|
|
2934
|
+
*/
|
|
2935
|
+
pushMesh(mesh, m, r, g, b, a) {
|
|
2936
|
+
const src = mesh.vertices;
|
|
2937
|
+
const srcIdx = mesh.indices;
|
|
2938
|
+
const n = src.length >> 1;
|
|
2939
|
+
this.reserve(n, srcIdx.length);
|
|
2940
|
+
const v = this.verts;
|
|
2941
|
+
let i = this.nVerts * FLOATS_PER_VERTEX;
|
|
2942
|
+
const ma = m[0], mb = m[1], mc = m[3], md = m[4], mtx = m[6], mty = m[7];
|
|
2943
|
+
for (let k = 0; k < n; k++) {
|
|
2944
|
+
const x = src[k * 2];
|
|
2945
|
+
const y = src[k * 2 + 1];
|
|
2946
|
+
v[i++] = ma * x + mc * y + mtx;
|
|
2947
|
+
v[i++] = mb * x + md * y + mty;
|
|
2948
|
+
v[i++] = r;
|
|
2949
|
+
v[i++] = g;
|
|
2950
|
+
v[i++] = b;
|
|
2951
|
+
v[i++] = a;
|
|
2952
|
+
}
|
|
2953
|
+
const base = this.nVerts;
|
|
2954
|
+
const out = this.idx;
|
|
2955
|
+
let j = this.nIdx;
|
|
2956
|
+
for (let k = 0; k < srcIdx.length; k++) out[j++] = base + srcIdx[k];
|
|
2957
|
+
this.nVerts += n;
|
|
2958
|
+
this.nIdx += srcIdx.length;
|
|
2959
|
+
}
|
|
2960
|
+
/** Upload the staged geometry and bind the batch VAO. Returns the index
|
|
2961
|
+
* count for the caller's `drawElements`. */
|
|
2962
|
+
uploadAndBind() {
|
|
2963
|
+
const gl = this.gl;
|
|
2964
|
+
if (this.nVerts > this.vboVerts || this.nIdx > this.iboIdx) {
|
|
2965
|
+
this.growGpu(this.nVerts, this.nIdx);
|
|
2966
|
+
}
|
|
2967
|
+
gl.bindVertexArray(this.vao);
|
|
2968
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
|
|
2969
|
+
gl.bufferSubData(gl.ARRAY_BUFFER, 0, this.verts, 0, this.nVerts * FLOATS_PER_VERTEX);
|
|
2970
|
+
gl.bufferSubData(gl.ELEMENT_ARRAY_BUFFER, 0, this.idx, 0, this.nIdx);
|
|
2971
|
+
return this.nIdx;
|
|
2972
|
+
}
|
|
2973
|
+
reset() {
|
|
2974
|
+
this.nVerts = 0;
|
|
2975
|
+
this.nIdx = 0;
|
|
2976
|
+
}
|
|
2977
|
+
dispose() {
|
|
2978
|
+
const gl = this.gl;
|
|
2979
|
+
gl.deleteBuffer(this.vbo);
|
|
2980
|
+
gl.deleteBuffer(this.ibo);
|
|
2981
|
+
gl.deleteVertexArray(this.vao);
|
|
2982
|
+
}
|
|
2983
|
+
/** Grow the CPU arrays so `vertices` / `indices` more fit. */
|
|
2984
|
+
reserve(vertices, indices) {
|
|
2985
|
+
const needVerts = (this.nVerts + vertices) * FLOATS_PER_VERTEX;
|
|
2986
|
+
if (needVerts > this.verts.length) {
|
|
2987
|
+
let len = this.verts.length;
|
|
2988
|
+
while (len < needVerts) len *= 2;
|
|
2989
|
+
const grown = new Float32Array(len);
|
|
2990
|
+
grown.set(this.verts);
|
|
2991
|
+
this.verts = grown;
|
|
2992
|
+
}
|
|
2993
|
+
const needIdx = this.nIdx + indices;
|
|
2994
|
+
if (needIdx > this.idx.length) {
|
|
2995
|
+
let len = this.idx.length;
|
|
2996
|
+
while (len < needIdx) len *= 2;
|
|
2997
|
+
const grown = new Uint32Array(len);
|
|
2998
|
+
grown.set(this.idx);
|
|
2999
|
+
this.idx = grown;
|
|
3000
|
+
}
|
|
3001
|
+
}
|
|
3002
|
+
/** Size both GPU buffers for at least what is staged, doubling to amortize. */
|
|
3003
|
+
growGpu(vertices, indices) {
|
|
3004
|
+
const gl = this.gl;
|
|
3005
|
+
if (vertices > this.vboVerts) {
|
|
3006
|
+
let capacity = Math.max(this.vboVerts, INITIAL_VERTICES);
|
|
3007
|
+
while (capacity < vertices) capacity *= 2;
|
|
3008
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
|
|
3009
|
+
gl.bufferData(gl.ARRAY_BUFFER, capacity * FLOATS_PER_VERTEX * 4, gl.DYNAMIC_DRAW);
|
|
3010
|
+
this.vboVerts = capacity;
|
|
3011
|
+
}
|
|
3012
|
+
if (indices > this.iboIdx) {
|
|
3013
|
+
let capacity = Math.max(this.iboIdx, INITIAL_INDICES);
|
|
3014
|
+
while (capacity < indices) capacity *= 2;
|
|
3015
|
+
gl.bindVertexArray(this.vao);
|
|
3016
|
+
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.ibo);
|
|
3017
|
+
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, capacity * 4, gl.DYNAMIC_DRAW);
|
|
3018
|
+
gl.bindVertexArray(null);
|
|
3019
|
+
this.iboIdx = capacity;
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
};
|
|
3023
|
+
|
|
2830
3024
|
// src/renderer/draw.ts
|
|
2831
|
-
|
|
3025
|
+
var FRAME_UPLOADS = /* @__PURE__ */ new WeakMap();
|
|
3026
|
+
var FRAME_PROJ = /* @__PURE__ */ new WeakMap();
|
|
3027
|
+
function uploadedFor(ctx, prog) {
|
|
3028
|
+
let byProgram = FRAME_UPLOADS.get(ctx);
|
|
3029
|
+
if (!byProgram) {
|
|
3030
|
+
byProgram = /* @__PURE__ */ new WeakMap();
|
|
3031
|
+
FRAME_UPLOADS.set(ctx, byProgram);
|
|
3032
|
+
}
|
|
3033
|
+
let uploaded = byProgram.get(prog);
|
|
3034
|
+
if (!uploaded) {
|
|
3035
|
+
uploaded = {};
|
|
3036
|
+
byProgram.set(prog, uploaded);
|
|
3037
|
+
}
|
|
3038
|
+
return uploaded;
|
|
3039
|
+
}
|
|
3040
|
+
function sameValues(prev, next) {
|
|
3041
|
+
if (prev === void 0 || prev.length !== next.length) return false;
|
|
3042
|
+
for (let i = 0; i < prev.length; i++) if (prev[i] !== next[i]) return false;
|
|
3043
|
+
return true;
|
|
3044
|
+
}
|
|
3045
|
+
var BATCH_MODEL = mat3.identity();
|
|
3046
|
+
function projFor(ctx) {
|
|
3047
|
+
let proj = FRAME_PROJ.get(ctx);
|
|
3048
|
+
if (!proj) {
|
|
3049
|
+
proj = mat3.screenToClip(ctx.widthCss, ctx.heightCss);
|
|
3050
|
+
FRAME_PROJ.set(ctx, proj);
|
|
3051
|
+
}
|
|
3052
|
+
return proj;
|
|
3053
|
+
}
|
|
3054
|
+
var COLOR_MATRIX_SCRATCH = new Float32Array(16);
|
|
3055
|
+
function setColorMatrixUniforms(ctx, prog, cm = ctx.state.colorMatrix) {
|
|
2832
3056
|
const gl = ctx.gl;
|
|
2833
|
-
const
|
|
2834
|
-
const
|
|
2835
|
-
|
|
2836
|
-
for (let
|
|
2837
|
-
|
|
3057
|
+
const uploaded = uploadedFor(ctx, prog);
|
|
3058
|
+
const mLoc = prog.uniform("u_colorMatrix");
|
|
3059
|
+
if (mLoc !== void 0) {
|
|
3060
|
+
for (let row = 0; row < 4; row++) {
|
|
3061
|
+
for (let col = 0; col < 4; col++) {
|
|
3062
|
+
COLOR_MATRIX_SCRATCH[col * 4 + row] = cm[row * 5 + col];
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
if (!sameValues(uploaded.colorMatrix, COLOR_MATRIX_SCRATCH)) {
|
|
3066
|
+
gl.uniformMatrix4fv(mLoc, false, COLOR_MATRIX_SCRATCH);
|
|
3067
|
+
uploaded.colorMatrix = Float32Array.from(COLOR_MATRIX_SCRATCH);
|
|
2838
3068
|
}
|
|
2839
3069
|
}
|
|
2840
|
-
const mLoc = prog.uniform("u_colorMatrix");
|
|
2841
3070
|
const bLoc = prog.uniform("u_colorBias");
|
|
2842
|
-
if (
|
|
2843
|
-
|
|
3071
|
+
if (bLoc !== void 0) {
|
|
3072
|
+
const bias = [cm[4], cm[9], cm[14], cm[19]];
|
|
3073
|
+
if (!sameValues(uploaded.colorBias, bias)) {
|
|
3074
|
+
gl.uniform4f(bLoc, bias[0], bias[1], bias[2], bias[3]);
|
|
3075
|
+
uploaded.colorBias = Float32Array.from(bias);
|
|
3076
|
+
}
|
|
3077
|
+
}
|
|
2844
3078
|
}
|
|
2845
|
-
function
|
|
3079
|
+
function fillMesh(ctx, path) {
|
|
2846
3080
|
if (ctx.flattenTolerance !== void 0) {
|
|
2847
|
-
return
|
|
3081
|
+
return tessellate(path, { flattenTolerance: ctx.flattenTolerance });
|
|
2848
3082
|
}
|
|
2849
|
-
return
|
|
3083
|
+
return getMesh(path);
|
|
3084
|
+
}
|
|
3085
|
+
function meshHandle(ctx, mesh) {
|
|
3086
|
+
if (ctx.flattenTolerance !== void 0) return ctx.meshCache.uploadTransient(mesh);
|
|
3087
|
+
return ctx.meshCache.handleFor(mesh);
|
|
3088
|
+
}
|
|
3089
|
+
function fillMeshHandle(ctx, path) {
|
|
3090
|
+
return meshHandle(ctx, fillMesh(ctx, path));
|
|
2850
3091
|
}
|
|
2851
3092
|
function dispatch(ctx, cmd) {
|
|
2852
3093
|
switch (cmd.kind) {
|
|
@@ -2855,10 +3096,13 @@ function dispatch(ctx, cmd) {
|
|
|
2855
3096
|
case "path":
|
|
2856
3097
|
return drawPath(ctx, cmd);
|
|
2857
3098
|
case "text":
|
|
3099
|
+
flushSolids(ctx);
|
|
2858
3100
|
return drawText(ctx, cmd);
|
|
2859
3101
|
case "image":
|
|
3102
|
+
flushSolids(ctx);
|
|
2860
3103
|
return drawImage(ctx, cmd);
|
|
2861
3104
|
case "shader":
|
|
3105
|
+
flushSolids(ctx);
|
|
2862
3106
|
return drawShader(ctx, cmd);
|
|
2863
3107
|
}
|
|
2864
3108
|
}
|
|
@@ -2987,11 +3231,13 @@ function drawGroup(ctx, cmd) {
|
|
|
2987
3231
|
"weasel: clip nesting depth exceeded (max 7). You can't nest more than 7 levels of clipped containers in a single draw tree. Flatten the hierarchy or compose poses outside the scene graph."
|
|
2988
3232
|
);
|
|
2989
3233
|
}
|
|
3234
|
+
flushSolids(ctx);
|
|
2990
3235
|
pushClip(ctx, cmd.clip, newDepth);
|
|
2991
3236
|
ctx.clipDepth = newDepth;
|
|
2992
3237
|
}
|
|
2993
3238
|
for (const child of cmd.children) dispatch(ctx, child);
|
|
2994
3239
|
if (cmd.clip) {
|
|
3240
|
+
flushSolids(ctx);
|
|
2995
3241
|
popClip(ctx, cmd.clip, ctx.clipDepth - 1);
|
|
2996
3242
|
ctx.clipDepth -= 1;
|
|
2997
3243
|
}
|
|
@@ -3000,38 +3246,98 @@ function drawGroup(ctx, cmd) {
|
|
|
3000
3246
|
function drawPath(ctx, cmd) {
|
|
3001
3247
|
if (!cmd.fill && !cmd.stroke) return;
|
|
3002
3248
|
if (cmd.fill) {
|
|
3003
|
-
const
|
|
3004
|
-
|
|
3005
|
-
|
|
3249
|
+
const batchablePaint = (cmd.fill.fill === void 0 || cmd.fill.fill === "solid") && (!cmd.vertexColors || cmd.vertexColors.length === 0);
|
|
3250
|
+
const solid = cmd.fill;
|
|
3251
|
+
if (batchablePaint && cmd.path.kind === "rect") {
|
|
3252
|
+
pushRect(ctx, cmd.path, solid);
|
|
3006
3253
|
} else {
|
|
3007
|
-
const
|
|
3008
|
-
if (
|
|
3009
|
-
|
|
3010
|
-
} else if (handle.requiresStencil) {
|
|
3011
|
-
drawPathFillStencil(ctx, cmd.fill, handle);
|
|
3254
|
+
const mesh = fillMesh(ctx, cmd.path);
|
|
3255
|
+
if (batchablePaint && canBatchMesh(mesh)) {
|
|
3256
|
+
pushMesh(ctx, mesh, solid);
|
|
3012
3257
|
} else {
|
|
3013
|
-
|
|
3258
|
+
flushSolids(ctx);
|
|
3259
|
+
const handle = meshHandle(ctx, mesh);
|
|
3260
|
+
if (cmd.vertexColors && cmd.vertexColors.length > 0 && (cmd.fill.fill === void 0 || cmd.fill.fill === "solid")) {
|
|
3261
|
+
drawPathFillVColor(ctx, cmd, solid, handle);
|
|
3262
|
+
} else if (handle.requiresStencil) {
|
|
3263
|
+
drawPathFillStencil(ctx, cmd.fill, handle);
|
|
3264
|
+
} else {
|
|
3265
|
+
drawPathFillByKind(ctx, cmd.fill, handle);
|
|
3266
|
+
}
|
|
3014
3267
|
}
|
|
3015
3268
|
}
|
|
3016
3269
|
}
|
|
3017
|
-
if (cmd.stroke)
|
|
3018
|
-
|
|
3270
|
+
if (cmd.stroke) drawPathStroke(ctx, cmd);
|
|
3271
|
+
}
|
|
3272
|
+
function isIdentityColorMatrix(cm) {
|
|
3273
|
+
return cm === IDENTITY_COLOR_MATRIX || sameValues(IDENTITY_COLOR_MATRIX, cm);
|
|
3274
|
+
}
|
|
3275
|
+
function stagedStateIsLive(ctx, staged) {
|
|
3276
|
+
if (staged.clipDepth !== ctx.clipDepth) return false;
|
|
3277
|
+
if (!staged.foldsAlpha && staged.alpha !== ctx.state.alpha) return false;
|
|
3278
|
+
const colorMatrix = ctx.state.colorMatrix;
|
|
3279
|
+
return staged.colorMatrix === colorMatrix || sameValues(staged.colorMatrix, colorMatrix);
|
|
3280
|
+
}
|
|
3281
|
+
var MAX_BATCHED_MESH_VERTICES = 256;
|
|
3282
|
+
function canBatchMesh(mesh) {
|
|
3283
|
+
return !mesh.requiresStencil && mesh.vertices.length >> 1 <= MAX_BATCHED_MESH_VERTICES;
|
|
3284
|
+
}
|
|
3285
|
+
function stageSolid(ctx, vertices) {
|
|
3286
|
+
if (ctx.solidState !== void 0 && !stagedStateIsLive(ctx, ctx.solidState)) flushSolids(ctx);
|
|
3287
|
+
if (ctx.solidBatch.wouldOverflow(vertices)) flushSolids(ctx);
|
|
3288
|
+
if (ctx.solidState === void 0) {
|
|
3289
|
+
const colorMatrix = ctx.state.colorMatrix;
|
|
3290
|
+
const foldsAlpha = isIdentityColorMatrix(colorMatrix);
|
|
3291
|
+
ctx.solidState = {
|
|
3292
|
+
alpha: foldsAlpha ? 1 : ctx.state.alpha,
|
|
3293
|
+
colorMatrix,
|
|
3294
|
+
clipDepth: ctx.clipDepth,
|
|
3295
|
+
foldsAlpha
|
|
3296
|
+
};
|
|
3019
3297
|
}
|
|
3298
|
+
return ctx.solidState;
|
|
3299
|
+
}
|
|
3300
|
+
function stagedColor(ctx, staged, paint) {
|
|
3301
|
+
const [r, g, b, a] = resolveColor(paint.color);
|
|
3302
|
+
return [r, g, b, a * (paint.opacity ?? 1) * (staged.foldsAlpha ? ctx.state.alpha : 1)];
|
|
3303
|
+
}
|
|
3304
|
+
function pushRect(ctx, rect, fill) {
|
|
3305
|
+
const staged = stageSolid(ctx, 4);
|
|
3306
|
+
const [r, g, b, a] = stagedColor(ctx, staged, fill);
|
|
3307
|
+
ctx.solidBatch.pushRect(
|
|
3308
|
+
rect.x,
|
|
3309
|
+
rect.y,
|
|
3310
|
+
rect.width,
|
|
3311
|
+
rect.height,
|
|
3312
|
+
ctx.state.transform,
|
|
3313
|
+
r,
|
|
3314
|
+
g,
|
|
3315
|
+
b,
|
|
3316
|
+
a
|
|
3317
|
+
);
|
|
3318
|
+
}
|
|
3319
|
+
function pushMesh(ctx, mesh, paint) {
|
|
3320
|
+
const staged = stageSolid(ctx, mesh.vertices.length >> 1);
|
|
3321
|
+
const [r, g, b, a] = stagedColor(ctx, staged, paint);
|
|
3322
|
+
ctx.solidBatch.pushMesh(mesh, ctx.state.transform, r, g, b, a);
|
|
3020
3323
|
}
|
|
3021
|
-
function
|
|
3324
|
+
function flushSolids(ctx) {
|
|
3325
|
+
const batch = ctx.solidBatch;
|
|
3326
|
+
const staged = ctx.solidState;
|
|
3327
|
+
if (batch.length === 0 || staged === void 0) return;
|
|
3022
3328
|
const gl = ctx.gl;
|
|
3023
|
-
const
|
|
3024
|
-
|
|
3025
|
-
|
|
3026
|
-
|
|
3027
|
-
gl.
|
|
3028
|
-
gl.
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
applyClipTest(ctx);
|
|
3033
|
-
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_INT, 0);
|
|
3329
|
+
const prog = ctx.pathFillVColor;
|
|
3330
|
+
gl.useProgram(prog.handle);
|
|
3331
|
+
const indexCount = batch.uploadAndBind();
|
|
3332
|
+
setProjAndModel(ctx, prog, BATCH_MODEL);
|
|
3333
|
+
gl.uniform4f(prog.uniform("u_color"), 1, 1, 1, 1);
|
|
3334
|
+
gl.uniform1f(prog.uniform("u_alpha"), staged.alpha);
|
|
3335
|
+
setColorMatrixUniforms(ctx, prog, staged.colorMatrix);
|
|
3336
|
+
applyClipTest(ctx, staged.clipDepth);
|
|
3337
|
+
gl.drawElements(gl.TRIANGLES, indexCount, gl.UNSIGNED_INT, 0);
|
|
3034
3338
|
gl.bindVertexArray(null);
|
|
3339
|
+
batch.reset();
|
|
3340
|
+
ctx.solidState = void 0;
|
|
3035
3341
|
}
|
|
3036
3342
|
function expandAnchorColors(perAnchor, handle) {
|
|
3037
3343
|
const aA = handle.anchorA;
|
|
@@ -3076,11 +3382,18 @@ function drawPathFillVColor(ctx, cmd, fill, handle) {
|
|
|
3076
3382
|
gl.bindVertexArray(null);
|
|
3077
3383
|
gl.deleteBuffer(colorVbo);
|
|
3078
3384
|
}
|
|
3079
|
-
function setProjAndModel(ctx, prog) {
|
|
3385
|
+
function setProjAndModel(ctx, prog, model = ctx.state.transform) {
|
|
3080
3386
|
const gl = ctx.gl;
|
|
3081
|
-
const
|
|
3082
|
-
|
|
3083
|
-
|
|
3387
|
+
const uploaded = uploadedFor(ctx, prog);
|
|
3388
|
+
const proj = projFor(ctx);
|
|
3389
|
+
if (!sameValues(uploaded.proj, proj)) {
|
|
3390
|
+
gl.uniformMatrix3fv(prog.uniform("u_proj"), false, proj);
|
|
3391
|
+
uploaded.proj = Float32Array.from(proj);
|
|
3392
|
+
}
|
|
3393
|
+
if (!sameValues(uploaded.model, model)) {
|
|
3394
|
+
gl.uniformMatrix3fv(prog.uniform("u_model"), false, model);
|
|
3395
|
+
uploaded.model = Float32Array.from(model);
|
|
3396
|
+
}
|
|
3084
3397
|
}
|
|
3085
3398
|
function setSolidPaintUniforms(ctx, prog, color, opacity) {
|
|
3086
3399
|
const gl = ctx.gl;
|
|
@@ -3187,9 +3500,8 @@ function drawPathFillGradient(ctx, fill, handle) {
|
|
|
3187
3500
|
gl.drawElements(gl.TRIANGLES, handle.indexCount, gl.UNSIGNED_INT, 0);
|
|
3188
3501
|
gl.bindVertexArray(null);
|
|
3189
3502
|
}
|
|
3190
|
-
function applyClipTest(ctx) {
|
|
3503
|
+
function applyClipTest(ctx, depth = ctx.clipDepth) {
|
|
3191
3504
|
const gl = ctx.gl;
|
|
3192
|
-
const depth = ctx.clipDepth;
|
|
3193
3505
|
if (depth === 0) {
|
|
3194
3506
|
gl.disable(gl.STENCIL_TEST);
|
|
3195
3507
|
return;
|
|
@@ -3273,6 +3585,7 @@ function drawPathStroke(ctx, cmd) {
|
|
|
3273
3585
|
}
|
|
3274
3586
|
const align = stroke.align ?? "center";
|
|
3275
3587
|
if (cmd.path.kind === "polygon" && align !== "center") {
|
|
3588
|
+
flushSolids(ctx);
|
|
3276
3589
|
drawPathStrokeStenciled(ctx, cmd, align);
|
|
3277
3590
|
return;
|
|
3278
3591
|
}
|
|
@@ -3283,6 +3596,12 @@ function drawPathStrokeUnclipped(ctx, cmd) {
|
|
|
3283
3596
|
const solid = stroke.paint;
|
|
3284
3597
|
const mesh = tessellateStroke(cmd.path, stroke, { flattenTolerance: ctx.flattenTolerance });
|
|
3285
3598
|
if (mesh.indices.length === 0) return;
|
|
3599
|
+
const hasVColors = !!(stroke.vertexColors && stroke.vertexColors.length > 0);
|
|
3600
|
+
if (!hasVColors && canBatchMesh(mesh)) {
|
|
3601
|
+
pushMesh(ctx, mesh, solid);
|
|
3602
|
+
return;
|
|
3603
|
+
}
|
|
3604
|
+
flushSolids(ctx);
|
|
3286
3605
|
const handle = ctx.meshCache.uploadTransient(mesh);
|
|
3287
3606
|
const gl = ctx.gl;
|
|
3288
3607
|
if (stroke.vertexColors && stroke.vertexColors.length > 0) {
|
|
@@ -3380,20 +3699,17 @@ function drawText(ctx, cmd) {
|
|
|
3380
3699
|
const maxWidth = cmd.maxWidth ?? Infinity;
|
|
3381
3700
|
const minScreen = ctx.textOutlineMinScreenSize ?? OUTLINE_MIN_SCREEN_PX;
|
|
3382
3701
|
const outlineMinSize = Number.isFinite(minScreen) ? minScreen / modelScale(ctx.state.transform) : void 0;
|
|
3383
|
-
const laid = cachedLayoutRuns(
|
|
3384
|
-
cmd.runs,
|
|
3385
|
-
{ maxWidth, lineHeight, align, outlineMinSize },
|
|
3386
|
-
{ x: cmd.x, y: cmd.y }
|
|
3387
|
-
);
|
|
3702
|
+
const laid = cachedLayoutRuns(cmd.runs, { maxWidth, lineHeight, align, outlineMinSize });
|
|
3388
3703
|
if (laid.groups.length === 0 && laid.decorations.length === 0) return;
|
|
3389
|
-
const
|
|
3704
|
+
const dx = cmd.x;
|
|
3705
|
+
const dy = cmd.y + verticalAlignOffset(cmd.verticalAlign, cmd.height, laid.bounds.height);
|
|
3390
3706
|
const gl = ctx.gl;
|
|
3391
3707
|
applyClipTest(ctx);
|
|
3392
3708
|
const preparedPrograms = /* @__PURE__ */ new Set();
|
|
3393
3709
|
let currentProg = null;
|
|
3394
3710
|
for (const group of laid.groups) {
|
|
3395
3711
|
if (group.source === "outline") {
|
|
3396
|
-
drawTextOutlineGroup(ctx, group, dy);
|
|
3712
|
+
drawTextOutlineGroup(ctx, group, dx, dy);
|
|
3397
3713
|
currentProg = null;
|
|
3398
3714
|
continue;
|
|
3399
3715
|
}
|
|
@@ -3408,31 +3724,31 @@ function drawText(ctx, cmd) {
|
|
|
3408
3724
|
setColorMatrixUniforms(ctx, prog);
|
|
3409
3725
|
gl.uniform1f(prog.uniform("u_alpha"), ctx.state.alpha);
|
|
3410
3726
|
}
|
|
3411
|
-
drawTextGroup(ctx, group, prog, dy);
|
|
3727
|
+
drawTextGroup(ctx, group, prog, dx, dy);
|
|
3412
3728
|
}
|
|
3413
|
-
drawTextDecorations(ctx, laid.decorations, dy);
|
|
3729
|
+
drawTextDecorations(ctx, laid.decorations, dx, dy);
|
|
3414
3730
|
}
|
|
3415
3731
|
var SYNTHETIC_ITALIC_RADIANS = 0.2094;
|
|
3416
|
-
function drawTextOutlineGroup(ctx, group, dy) {
|
|
3417
|
-
const mesh = outlineGroupMesh(group, dy);
|
|
3732
|
+
function drawTextOutlineGroup(ctx, group, dx, dy) {
|
|
3733
|
+
const mesh = outlineGroupMesh(group, dx, dy);
|
|
3418
3734
|
if (mesh) drawPathFillByKind(ctx, group.fill, ctx.meshCache.uploadTransient(mesh));
|
|
3419
3735
|
if (!group.stroke) return;
|
|
3420
|
-
const strokeMesh = outlineGroupStrokeMesh(group, dy);
|
|
3736
|
+
const strokeMesh = outlineGroupStrokeMesh(group, dx, dy);
|
|
3421
3737
|
if (strokeMesh) {
|
|
3422
3738
|
drawPathFillByKind(ctx, group.stroke.paint, ctx.meshCache.uploadTransient(strokeMesh));
|
|
3423
3739
|
}
|
|
3424
3740
|
}
|
|
3425
|
-
function outlineGroupMesh(group, dy) {
|
|
3426
|
-
return mergeGlyphMeshes(group, dy, (glyph) => outlineMesh(glyph.key, glyph.d));
|
|
3741
|
+
function outlineGroupMesh(group, dx, dy) {
|
|
3742
|
+
return mergeGlyphMeshes(group, dx, dy, (glyph) => outlineMesh(glyph.key, glyph.d));
|
|
3427
3743
|
}
|
|
3428
|
-
function outlineGroupStrokeMesh(group, dy) {
|
|
3744
|
+
function outlineGroupStrokeMesh(group, dx, dy) {
|
|
3429
3745
|
const stroke = group.stroke;
|
|
3430
3746
|
if (!stroke) return null;
|
|
3431
3747
|
const width = stroke.width ?? 1;
|
|
3432
3748
|
if (!(width > 0)) return null;
|
|
3433
|
-
return mergeGlyphMeshes(group, dy, (glyph) => glyph.scale > 0 ? outlineStrokeMesh(glyph.key, glyph.d, quantizeEmWidth(width / glyph.scale), stroke) : null);
|
|
3749
|
+
return mergeGlyphMeshes(group, dx, dy, (glyph) => glyph.scale > 0 ? outlineStrokeMesh(glyph.key, glyph.d, quantizeEmWidth(width / glyph.scale), stroke) : null);
|
|
3434
3750
|
}
|
|
3435
|
-
function mergeGlyphMeshes(group, dy, meshFor) {
|
|
3751
|
+
function mergeGlyphMeshes(group, dx, dy, meshFor) {
|
|
3436
3752
|
const parts = [];
|
|
3437
3753
|
let vertexFloats = 0;
|
|
3438
3754
|
let indexCount = 0;
|
|
@@ -3455,7 +3771,7 @@ function mergeGlyphMeshes(group, dy, meshFor) {
|
|
|
3455
3771
|
for (let k = 0; k < mesh.vertices.length; k += 2) {
|
|
3456
3772
|
const ex = mesh.vertices[k];
|
|
3457
3773
|
const ey = mesh.vertices[k + 1];
|
|
3458
|
-
vertices[vi++] = x + (ex - ey * shear) * scale2;
|
|
3774
|
+
vertices[vi++] = x + dx + (ex - ey * shear) * scale2;
|
|
3459
3775
|
vertices[vi++] = baselineY + dy + ey * scale2;
|
|
3460
3776
|
}
|
|
3461
3777
|
for (let k = 0; k < mesh.indices.length; k++) indices[ii++] = base + mesh.indices[k];
|
|
@@ -3463,7 +3779,7 @@ function mergeGlyphMeshes(group, dy, meshFor) {
|
|
|
3463
3779
|
}
|
|
3464
3780
|
return { vertices, indices };
|
|
3465
3781
|
}
|
|
3466
|
-
function drawTextDecorations(ctx, decorations, dy) {
|
|
3782
|
+
function drawTextDecorations(ctx, decorations, dx, dy) {
|
|
3467
3783
|
if (decorations.length === 0) return;
|
|
3468
3784
|
const batches = /* @__PURE__ */ new Map();
|
|
3469
3785
|
for (const d of decorations) {
|
|
@@ -3486,14 +3802,15 @@ function drawTextDecorations(ctx, decorations, dy) {
|
|
|
3486
3802
|
const vertices = new Float32Array(rects.length * 4 * 2);
|
|
3487
3803
|
let vi = 0;
|
|
3488
3804
|
for (const d of rects) {
|
|
3805
|
+
const dx0 = d.x0 + dx, dx1 = d.x1 + dx;
|
|
3489
3806
|
const dy0 = d.y0 + dy, dy1 = d.y1 + dy;
|
|
3490
|
-
vertices[vi++] =
|
|
3807
|
+
vertices[vi++] = dx0;
|
|
3491
3808
|
vertices[vi++] = dy0;
|
|
3492
|
-
vertices[vi++] =
|
|
3809
|
+
vertices[vi++] = dx1;
|
|
3493
3810
|
vertices[vi++] = dy0;
|
|
3494
|
-
vertices[vi++] =
|
|
3811
|
+
vertices[vi++] = dx0;
|
|
3495
3812
|
vertices[vi++] = dy1;
|
|
3496
|
-
vertices[vi++] =
|
|
3813
|
+
vertices[vi++] = dx1;
|
|
3497
3814
|
vertices[vi++] = dy1;
|
|
3498
3815
|
}
|
|
3499
3816
|
const indices = new Uint32Array(rects.length * 6);
|
|
@@ -3532,7 +3849,7 @@ function drawTextDecorations(ctx, decorations, dy) {
|
|
|
3532
3849
|
gl.deleteBuffer(ibo);
|
|
3533
3850
|
}
|
|
3534
3851
|
}
|
|
3535
|
-
function drawTextGroup(ctx, group, prog, dy) {
|
|
3852
|
+
function drawTextGroup(ctx, group, prog, dx, dy) {
|
|
3536
3853
|
if (group.source === "canvas") {
|
|
3537
3854
|
if (!syncDynamicPageTexture(ctx.textureCache, group.page)) return;
|
|
3538
3855
|
} else {
|
|
@@ -3543,23 +3860,24 @@ function drawTextGroup(ctx, group, prog, dy) {
|
|
|
3543
3860
|
const vertices = new Float32Array(group.quads.length * 4 * 5);
|
|
3544
3861
|
let vi = 0;
|
|
3545
3862
|
for (const q of group.quads) {
|
|
3863
|
+
const x0 = q.x0 + dx, x1 = q.x1 + dx;
|
|
3546
3864
|
const y0 = q.y0 + dy, y1 = q.y1 + dy, by = q.baselineY + dy;
|
|
3547
|
-
vertices[vi++] =
|
|
3865
|
+
vertices[vi++] = x0;
|
|
3548
3866
|
vertices[vi++] = y0;
|
|
3549
3867
|
vertices[vi++] = q.u0;
|
|
3550
3868
|
vertices[vi++] = q.v0;
|
|
3551
3869
|
vertices[vi++] = by;
|
|
3552
|
-
vertices[vi++] =
|
|
3870
|
+
vertices[vi++] = x1;
|
|
3553
3871
|
vertices[vi++] = y0;
|
|
3554
3872
|
vertices[vi++] = q.u1;
|
|
3555
3873
|
vertices[vi++] = q.v0;
|
|
3556
3874
|
vertices[vi++] = by;
|
|
3557
|
-
vertices[vi++] =
|
|
3875
|
+
vertices[vi++] = x0;
|
|
3558
3876
|
vertices[vi++] = y1;
|
|
3559
3877
|
vertices[vi++] = q.u0;
|
|
3560
3878
|
vertices[vi++] = q.v1;
|
|
3561
3879
|
vertices[vi++] = by;
|
|
3562
|
-
vertices[vi++] =
|
|
3880
|
+
vertices[vi++] = x1;
|
|
3563
3881
|
vertices[vi++] = y1;
|
|
3564
3882
|
vertices[vi++] = q.u1;
|
|
3565
3883
|
vertices[vi++] = q.v1;
|
|
@@ -3786,10 +4104,7 @@ var WeaselRenderer = class {
|
|
|
3786
4104
|
programRegistry = /* @__PURE__ */ new Map();
|
|
3787
4105
|
quadVbo = null;
|
|
3788
4106
|
quadIbo = null;
|
|
3789
|
-
|
|
3790
|
-
rectVao = null;
|
|
3791
|
-
rectVbo = null;
|
|
3792
|
-
rectIbo = null;
|
|
4107
|
+
solidBatch;
|
|
3793
4108
|
groupState = new GroupState();
|
|
3794
4109
|
widthCss;
|
|
3795
4110
|
heightCss;
|
|
@@ -3864,31 +4179,7 @@ var WeaselRenderer = class {
|
|
|
3864
4179
|
this.imageCache = new GLImageCache(this.gl, this.imageMinification);
|
|
3865
4180
|
this.gradRampCache = new GradientRampCache(this.gl);
|
|
3866
4181
|
this.uploadQuadGeometry();
|
|
3867
|
-
this.
|
|
3868
|
-
}
|
|
3869
|
-
/** Allocate the shared rect VAO + dynamic VBO (4 verts × 2 floats) + static
|
|
3870
|
-
* IBO (6 indices). drawRectFast bufferSubData's the 4 corner coords each
|
|
3871
|
-
* draw, avoiding per-rect buffer allocation in animated demos. */
|
|
3872
|
-
uploadRectGeometry(aPositionLoc) {
|
|
3873
|
-
const gl = this.gl;
|
|
3874
|
-
this.rectVao = gl.createVertexArray();
|
|
3875
|
-
this.rectVbo = gl.createBuffer();
|
|
3876
|
-
this.rectIbo = gl.createBuffer();
|
|
3877
|
-
if (!this.rectVao || !this.rectVbo || !this.rectIbo) {
|
|
3878
|
-
throw new Error("WeaselRenderer: failed to create rect-fast geometry");
|
|
3879
|
-
}
|
|
3880
|
-
gl.bindVertexArray(this.rectVao);
|
|
3881
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, this.rectVbo);
|
|
3882
|
-
gl.bufferData(gl.ARRAY_BUFFER, 8 * 4, gl.DYNAMIC_DRAW);
|
|
3883
|
-
gl.enableVertexAttribArray(aPositionLoc);
|
|
3884
|
-
gl.vertexAttribPointer(aPositionLoc, 2, gl.FLOAT, false, 0, 0);
|
|
3885
|
-
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.rectIbo);
|
|
3886
|
-
gl.bufferData(
|
|
3887
|
-
gl.ELEMENT_ARRAY_BUFFER,
|
|
3888
|
-
new Uint32Array([0, 1, 2, 0, 2, 3]),
|
|
3889
|
-
gl.STATIC_DRAW
|
|
3890
|
-
);
|
|
3891
|
-
gl.bindVertexArray(null);
|
|
4182
|
+
this.solidBatch = new SolidBatch(this.gl, this.pathFillVColor);
|
|
3892
4183
|
}
|
|
3893
4184
|
uploadQuadGeometry() {
|
|
3894
4185
|
const gl = this.gl;
|
|
@@ -3976,7 +4267,7 @@ var WeaselRenderer = class {
|
|
|
3976
4267
|
this.gradRampCache = new GradientRampCache(this.gl);
|
|
3977
4268
|
markAllFontsNotUploaded();
|
|
3978
4269
|
this.uploadQuadGeometry();
|
|
3979
|
-
this.
|
|
4270
|
+
this.solidBatch = new SolidBatch(this.gl, this.pathFillVColor);
|
|
3980
4271
|
for (const id of this.programRegistry.keys()) {
|
|
3981
4272
|
const src = getProgramSource(id);
|
|
3982
4273
|
if (!src) continue;
|
|
@@ -4036,9 +4327,7 @@ var WeaselRenderer = class {
|
|
|
4036
4327
|
this.gradRampCache.free();
|
|
4037
4328
|
if (this.quadVbo) gl.deleteBuffer(this.quadVbo);
|
|
4038
4329
|
if (this.quadIbo) gl.deleteBuffer(this.quadIbo);
|
|
4039
|
-
|
|
4040
|
-
if (this.rectIbo) gl.deleteBuffer(this.rectIbo);
|
|
4041
|
-
if (this.rectVao) gl.deleteVertexArray(this.rectVao);
|
|
4330
|
+
this.solidBatch.dispose();
|
|
4042
4331
|
}
|
|
4043
4332
|
/**
|
|
4044
4333
|
* Draw one frame.
|
|
@@ -4071,8 +4360,7 @@ var WeaselRenderer = class {
|
|
|
4071
4360
|
programRegistry: this.programRegistry,
|
|
4072
4361
|
quadVbo: this.quadVbo,
|
|
4073
4362
|
quadIbo: this.quadIbo,
|
|
4074
|
-
|
|
4075
|
-
rectVbo: this.rectVbo,
|
|
4363
|
+
solidBatch: this.solidBatch,
|
|
4076
4364
|
state: this.groupState,
|
|
4077
4365
|
widthCss: this.widthCss,
|
|
4078
4366
|
heightCss: this.heightCss,
|
|
@@ -4082,6 +4370,7 @@ var WeaselRenderer = class {
|
|
|
4082
4370
|
viewMatrix
|
|
4083
4371
|
};
|
|
4084
4372
|
for (const cmd of commands) dispatch(ctx, cmd);
|
|
4373
|
+
flushSolids(ctx);
|
|
4085
4374
|
this.meshCache.freeTransient();
|
|
4086
4375
|
}
|
|
4087
4376
|
resize(dims) {
|
|
@@ -4111,6 +4400,10 @@ var WeaselRenderer = class {
|
|
|
4111
4400
|
return this.pathFillVColor;
|
|
4112
4401
|
}
|
|
4113
4402
|
/** @internal */
|
|
4403
|
+
_solidBatch() {
|
|
4404
|
+
return this.solidBatch;
|
|
4405
|
+
}
|
|
4406
|
+
/** @internal */
|
|
4114
4407
|
_textSdf() {
|
|
4115
4408
|
return this.textSdf;
|
|
4116
4409
|
}
|
|
@@ -5380,12 +5673,7 @@ function moveGestureAdapter(scene) {
|
|
|
5380
5673
|
return {
|
|
5381
5674
|
getNode: (id) => scene.get(asNodeId(id)),
|
|
5382
5675
|
getNodes: () => {
|
|
5383
|
-
|
|
5384
|
-
for (const id of scene.renderOrder()) {
|
|
5385
|
-
const n = scene.get(id);
|
|
5386
|
-
if (n) out.push(n);
|
|
5387
|
-
}
|
|
5388
|
-
return out;
|
|
5676
|
+
return [...scene.renderOrderNodes()];
|
|
5389
5677
|
},
|
|
5390
5678
|
getPose: (id) => scene.get(asNodeId(id)).pose,
|
|
5391
5679
|
getParent: (id) => scene.get(asNodeId(id))?.parent ?? null,
|
|
@@ -6001,12 +6289,7 @@ function defaultCommitAdapter(scene) {
|
|
|
6001
6289
|
return {
|
|
6002
6290
|
getNode: (id) => scene.get(asNodeId(id)),
|
|
6003
6291
|
getNodes: () => {
|
|
6004
|
-
|
|
6005
|
-
for (const id of scene.renderOrder()) {
|
|
6006
|
-
const n = scene.get(id);
|
|
6007
|
-
if (n) out.push(n);
|
|
6008
|
-
}
|
|
6009
|
-
return out;
|
|
6292
|
+
return [...scene.renderOrderNodes()];
|
|
6010
6293
|
},
|
|
6011
6294
|
getPose: (id) => scene.get(asNodeId(id)).pose,
|
|
6012
6295
|
getParent: (id) => scene.get(asNodeId(id))?.parent ?? null,
|
|
@@ -10706,18 +10989,39 @@ function modsCount(mods) {
|
|
|
10706
10989
|
}
|
|
10707
10990
|
function targetRank(target) {
|
|
10708
10991
|
if (target === void 0) return 0;
|
|
10709
|
-
|
|
10710
|
-
if (
|
|
10711
|
-
|
|
10712
|
-
|
|
10992
|
+
const form = parseTargetSpec(target);
|
|
10993
|
+
if (form === null) return 1;
|
|
10994
|
+
switch (form.form) {
|
|
10995
|
+
case "kind":
|
|
10996
|
+
return form.requireSelected ? 3 : 2;
|
|
10997
|
+
case "affordance":
|
|
10998
|
+
return 2;
|
|
10999
|
+
case "body":
|
|
11000
|
+
return 1;
|
|
11001
|
+
case "predicate":
|
|
11002
|
+
return 1;
|
|
11003
|
+
default: {
|
|
11004
|
+
return 1;
|
|
11005
|
+
}
|
|
11006
|
+
}
|
|
10713
11007
|
}
|
|
10714
11008
|
function targetConsultsAffordance(specTarget) {
|
|
10715
11009
|
if (specTarget === void 0) return false;
|
|
10716
|
-
|
|
10717
|
-
|
|
10718
|
-
|
|
11010
|
+
const form = parseTargetSpec(specTarget);
|
|
11011
|
+
if (form === null) return false;
|
|
11012
|
+
switch (form.form) {
|
|
11013
|
+
case "predicate":
|
|
11014
|
+
return form.kindOf.readsAffordance !== false;
|
|
11015
|
+
case "affordance":
|
|
11016
|
+
return true;
|
|
11017
|
+
case "body":
|
|
11018
|
+
return false;
|
|
11019
|
+
case "kind":
|
|
11020
|
+
return false;
|
|
11021
|
+
default: {
|
|
11022
|
+
return false;
|
|
11023
|
+
}
|
|
10719
11024
|
}
|
|
10720
|
-
return typeof specTarget === "string" && specTarget.startsWith("affordance:");
|
|
10721
11025
|
}
|
|
10722
11026
|
function specTargetOf(spec) {
|
|
10723
11027
|
return "target" in spec ? spec.target : void 0;
|
|
@@ -10760,7 +11064,7 @@ function reportDeadClaim(owner, warn) {
|
|
|
10760
11064
|
);
|
|
10761
11065
|
}
|
|
10762
11066
|
function specificity(spec) {
|
|
10763
|
-
const t = targetRank(
|
|
11067
|
+
const t = targetRank(specTargetOf(spec));
|
|
10764
11068
|
const mods = "mods" in spec ? spec.mods : void 0;
|
|
10765
11069
|
const m = modsCount(mods);
|
|
10766
11070
|
const p = "phase" in spec && spec.phase !== void 0 ? 1 : 0;
|
|
@@ -13633,21 +13937,18 @@ function textLineBoxes(pose, opts = {}) {
|
|
|
13633
13937
|
const style = resolveTextStyle(pose.style);
|
|
13634
13938
|
const source = pose.runs && pose.runs.length > 0 ? pose.runs : pose.text;
|
|
13635
13939
|
const runs = resolveRuns(toRuns(source), style);
|
|
13636
|
-
const laid = layoutRuns(
|
|
13637
|
-
|
|
13638
|
-
|
|
13639
|
-
|
|
13640
|
-
|
|
13641
|
-
|
|
13642
|
-
|
|
13643
|
-
{ x: pose.x, y: pose.y }
|
|
13644
|
-
);
|
|
13645
|
-
const dy = verticalAlignOffset(pose.verticalAlign, pose.height, laid.bounds.height);
|
|
13940
|
+
const laid = layoutRuns(runs, {
|
|
13941
|
+
maxWidth: opts.maxWidth ?? pose.width,
|
|
13942
|
+
lineHeight: style.lineHeight,
|
|
13943
|
+
align: style.align
|
|
13944
|
+
});
|
|
13945
|
+
const dx = pose.x;
|
|
13946
|
+
const dy = pose.y + verticalAlignOffset(pose.verticalAlign, pose.height, laid.bounds.height);
|
|
13646
13947
|
const out = [];
|
|
13647
13948
|
for (const line of laid.lines) {
|
|
13648
13949
|
if (!opts.includeEmpty && line.x1 <= line.x0) continue;
|
|
13649
13950
|
out.push({
|
|
13650
|
-
x: line.x0 - padding,
|
|
13951
|
+
x: line.x0 + dx - padding,
|
|
13651
13952
|
y: line.y0 + dy - padding,
|
|
13652
13953
|
width: line.x1 - line.x0 + padding * 2,
|
|
13653
13954
|
height: line.y1 - line.y0 + padding * 2
|
|
@@ -16630,6 +16931,15 @@ function wrapWithPoseRotation(cmds, pose) {
|
|
|
16630
16931
|
children: cmds
|
|
16631
16932
|
}];
|
|
16632
16933
|
}
|
|
16934
|
+
|
|
16935
|
+
// src/canvas/wrapNodeOutput.ts
|
|
16936
|
+
function wrapNodeOutput(cmds, pose, alpha) {
|
|
16937
|
+
const rotated = wrapWithPoseRotation(cmds, pose);
|
|
16938
|
+
if (alpha !== 1 && rotated.length > 0) {
|
|
16939
|
+
return [{ kind: "group", alpha, children: rotated }];
|
|
16940
|
+
}
|
|
16941
|
+
return rotated;
|
|
16942
|
+
}
|
|
16633
16943
|
function CursorCoordsHud({ canvasRef, viewRef, offset }) {
|
|
16634
16944
|
const [state, setState] = useState({
|
|
16635
16945
|
client: { x: 0, y: 0 },
|
|
@@ -16881,12 +17191,7 @@ function buildSceneLayer(cfg, adapter, debugSink, boundsOfFn, hideIds, slot) {
|
|
|
16881
17191
|
const oy = pose.y ?? (b ? b.y : 0);
|
|
16882
17192
|
debugSink.recordOrigin(obj.id, { x: ox, y: oy });
|
|
16883
17193
|
}
|
|
16884
|
-
|
|
16885
|
-
const alpha = cfg.alphaFor ? cfg.alphaFor(obj.id) : 1;
|
|
16886
|
-
if (alpha !== 1 && rotated.length > 0) {
|
|
16887
|
-
return [{ kind: "group", alpha, children: rotated }];
|
|
16888
|
-
}
|
|
16889
|
-
return rotated;
|
|
17194
|
+
return wrapNodeOutput(cmds, pose, cfg.alphaFor ? cfg.alphaFor(obj.id) : 1);
|
|
16890
17195
|
};
|
|
16891
17196
|
const hierarchicalAdapter = cfg.toPose ? {
|
|
16892
17197
|
...a,
|
|
@@ -16910,13 +17215,8 @@ function buildSceneLayer(cfg, adapter, debugSink, boundsOfFn, hideIds, slot) {
|
|
|
16910
17215
|
const pose = toPose(obj);
|
|
16911
17216
|
if (drawOne) {
|
|
16912
17217
|
const cmds = drawOne(obj, pose, view);
|
|
16913
|
-
const
|
|
16914
|
-
const
|
|
16915
|
-
if (alpha !== 1 && rotated.length > 0) {
|
|
16916
|
-
children.push({ kind: "group", alpha, children: rotated });
|
|
16917
|
-
} else {
|
|
16918
|
-
for (const cmd of rotated) children.push(cmd);
|
|
16919
|
-
}
|
|
17218
|
+
const wrapped = wrapNodeOutput(cmds, pose, cfg.alphaFor ? cfg.alphaFor(obj.id) : 1);
|
|
17219
|
+
for (const cmd of wrapped) children.push(cmd);
|
|
16920
17220
|
}
|
|
16921
17221
|
if (debugSink) {
|
|
16922
17222
|
const b = boundsOfFn ? boundsOfFn(obj.id) : null;
|
|
@@ -17630,6 +17930,7 @@ function createScene(options) {
|
|
|
17630
17930
|
return i;
|
|
17631
17931
|
}
|
|
17632
17932
|
function rebuildLayerIndex() {
|
|
17933
|
+
invalidateOrder();
|
|
17633
17934
|
state.layerIndex.clear();
|
|
17634
17935
|
for (let i = 0; i < state.layers.length; i++) {
|
|
17635
17936
|
state.layerIndex.set(state.layers[i].id, i);
|
|
@@ -17655,6 +17956,7 @@ function createScene(options) {
|
|
|
17655
17956
|
const idx = sibs.indexOf(id);
|
|
17656
17957
|
if (idx < 0) throw new Error(`Scene: node "${id}" not found in its parent's children`);
|
|
17657
17958
|
sibs.splice(idx, 1);
|
|
17959
|
+
invalidateOrder();
|
|
17658
17960
|
return { parent: node.parent, index: idx };
|
|
17659
17961
|
}
|
|
17660
17962
|
function attach(id, parent, index) {
|
|
@@ -17663,6 +17965,7 @@ function createScene(options) {
|
|
|
17663
17965
|
sibs.splice(i, 0, id);
|
|
17664
17966
|
const node = requireNode(id);
|
|
17665
17967
|
node.parent = parent;
|
|
17968
|
+
invalidateOrder();
|
|
17666
17969
|
}
|
|
17667
17970
|
function descendants(id, out) {
|
|
17668
17971
|
const n = state.nodes.get(id);
|
|
@@ -17742,9 +18045,11 @@ function createScene(options) {
|
|
|
17742
18045
|
apply: (p) => {
|
|
17743
18046
|
requireLayerIndex(p.to);
|
|
17744
18047
|
requireNode(p.id).layer = p.to;
|
|
18048
|
+
invalidateOrder();
|
|
17745
18049
|
},
|
|
17746
18050
|
revert: (p) => {
|
|
17747
18051
|
requireNode(p.id).layer = p.from;
|
|
18052
|
+
invalidateOrder();
|
|
17748
18053
|
}
|
|
17749
18054
|
});
|
|
17750
18055
|
registerKitOp("kit:move", {
|
|
@@ -17883,21 +18188,98 @@ function createScene(options) {
|
|
|
17883
18188
|
registered.set(k, h);
|
|
17884
18189
|
}
|
|
17885
18190
|
}
|
|
17886
|
-
function
|
|
17887
|
-
|
|
17888
|
-
|
|
17889
|
-
|
|
17890
|
-
|
|
17891
|
-
|
|
17892
|
-
|
|
17893
|
-
|
|
17894
|
-
|
|
17895
|
-
|
|
17896
|
-
|
|
17897
|
-
|
|
18191
|
+
function renderOrderInternal() {
|
|
18192
|
+
return state.layers.length === 1 ? renderOrderFlat() : renderOrderBucketed();
|
|
18193
|
+
}
|
|
18194
|
+
function renderOrderNodesInternal() {
|
|
18195
|
+
return state.layers.length === 1 ? renderOrderNodesFlat() : renderOrderNodesBucketed();
|
|
18196
|
+
}
|
|
18197
|
+
let structureGeneration = 0;
|
|
18198
|
+
let orderCache = { gen: 0 };
|
|
18199
|
+
function invalidateOrder() {
|
|
18200
|
+
structureGeneration++;
|
|
18201
|
+
}
|
|
18202
|
+
function currentOrderCache() {
|
|
18203
|
+
if (orderCache.gen !== structureGeneration) {
|
|
18204
|
+
orderCache = { gen: structureGeneration };
|
|
18205
|
+
}
|
|
18206
|
+
return orderCache;
|
|
18207
|
+
}
|
|
18208
|
+
function renderOrderFlat() {
|
|
18209
|
+
const only = state.layers[0].id;
|
|
18210
|
+
const out = [];
|
|
18211
|
+
const stack = [...state.roots].reverse();
|
|
18212
|
+
while (stack.length > 0) {
|
|
18213
|
+
const id = stack.pop();
|
|
18214
|
+
const node = state.nodes.get(id);
|
|
18215
|
+
if (!node) continue;
|
|
18216
|
+
if (node.layer === only) out.push(id);
|
|
18217
|
+
if (node.kind === "container") {
|
|
18218
|
+
for (let i = node.children.length - 1; i >= 0; i--) {
|
|
18219
|
+
stack.push(node.children[i]);
|
|
17898
18220
|
}
|
|
17899
18221
|
}
|
|
17900
18222
|
}
|
|
18223
|
+
return out;
|
|
18224
|
+
}
|
|
18225
|
+
function renderOrderNodesFlat() {
|
|
18226
|
+
const only = state.layers[0].id;
|
|
18227
|
+
const out = [];
|
|
18228
|
+
const stack = [...state.roots].reverse();
|
|
18229
|
+
while (stack.length > 0) {
|
|
18230
|
+
const id = stack.pop();
|
|
18231
|
+
const node = state.nodes.get(id);
|
|
18232
|
+
if (!node) continue;
|
|
18233
|
+
if (node.layer === only) out.push(node);
|
|
18234
|
+
if (node.kind === "container") {
|
|
18235
|
+
for (let i = node.children.length - 1; i >= 0; i--) {
|
|
18236
|
+
stack.push(node.children[i]);
|
|
18237
|
+
}
|
|
18238
|
+
}
|
|
18239
|
+
}
|
|
18240
|
+
return out;
|
|
18241
|
+
}
|
|
18242
|
+
function renderOrderBucketed() {
|
|
18243
|
+
const buckets = state.layers.map(() => []);
|
|
18244
|
+
const stack = [...state.roots].reverse();
|
|
18245
|
+
while (stack.length > 0) {
|
|
18246
|
+
const id = stack.pop();
|
|
18247
|
+
const node = state.nodes.get(id);
|
|
18248
|
+
if (!node) continue;
|
|
18249
|
+
const bucket = buckets[state.layerIndex.get(node.layer) ?? -1];
|
|
18250
|
+
if (bucket) bucket.push(id);
|
|
18251
|
+
if (node.kind === "container") {
|
|
18252
|
+
for (let i = node.children.length - 1; i >= 0; i--) {
|
|
18253
|
+
stack.push(node.children[i]);
|
|
18254
|
+
}
|
|
18255
|
+
}
|
|
18256
|
+
}
|
|
18257
|
+
const out = [];
|
|
18258
|
+
for (const bucket of buckets) {
|
|
18259
|
+
for (const id of bucket) out.push(id);
|
|
18260
|
+
}
|
|
18261
|
+
return out;
|
|
18262
|
+
}
|
|
18263
|
+
function renderOrderNodesBucketed() {
|
|
18264
|
+
const buckets = state.layers.map(() => []);
|
|
18265
|
+
const stack = [...state.roots].reverse();
|
|
18266
|
+
while (stack.length > 0) {
|
|
18267
|
+
const id = stack.pop();
|
|
18268
|
+
const node = state.nodes.get(id);
|
|
18269
|
+
if (!node) continue;
|
|
18270
|
+
const bucket = buckets[state.layerIndex.get(node.layer) ?? -1];
|
|
18271
|
+
if (bucket) bucket.push(node);
|
|
18272
|
+
if (node.kind === "container") {
|
|
18273
|
+
for (let i = node.children.length - 1; i >= 0; i--) {
|
|
18274
|
+
stack.push(node.children[i]);
|
|
18275
|
+
}
|
|
18276
|
+
}
|
|
18277
|
+
}
|
|
18278
|
+
const out = [];
|
|
18279
|
+
for (const bucket of buckets) {
|
|
18280
|
+
for (const node of bucket) out.push(node);
|
|
18281
|
+
}
|
|
18282
|
+
return out;
|
|
17901
18283
|
}
|
|
17902
18284
|
const scene = {
|
|
17903
18285
|
get nodes() {
|
|
@@ -17926,7 +18308,12 @@ function createScene(options) {
|
|
|
17926
18308
|
return out;
|
|
17927
18309
|
},
|
|
17928
18310
|
renderOrder() {
|
|
17929
|
-
|
|
18311
|
+
const c = currentOrderCache();
|
|
18312
|
+
return c.ids ??= renderOrderInternal();
|
|
18313
|
+
},
|
|
18314
|
+
renderOrderNodes() {
|
|
18315
|
+
const c = currentOrderCache();
|
|
18316
|
+
return c.nodes ??= renderOrderNodesInternal();
|
|
17930
18317
|
},
|
|
17931
18318
|
add(spec) {
|
|
17932
18319
|
const id = spec.id ?? generateId();
|
|
@@ -18234,9 +18621,8 @@ function createScene(options) {
|
|
|
18234
18621
|
},
|
|
18235
18622
|
toJSON() {
|
|
18236
18623
|
const nodes = [];
|
|
18237
|
-
for (const
|
|
18238
|
-
const
|
|
18239
|
-
if (!n) continue;
|
|
18624
|
+
for (const n of renderOrderNodesInternal()) {
|
|
18625
|
+
const id = n.id;
|
|
18240
18626
|
const out = {
|
|
18241
18627
|
id,
|
|
18242
18628
|
kind: n.kind,
|
|
@@ -18270,6 +18656,7 @@ function createScene(options) {
|
|
|
18270
18656
|
state.roots.length = 0;
|
|
18271
18657
|
state.layers.length = 0;
|
|
18272
18658
|
state.layerIndex.clear();
|
|
18659
|
+
invalidateOrder();
|
|
18273
18660
|
for (let i = 0; i < json.systemLayers.length; i++) {
|
|
18274
18661
|
const spec = json.systemLayers[i];
|
|
18275
18662
|
if (state.layerIndex.has(spec.id)) {
|
|
@@ -18567,9 +18954,8 @@ function sceneToAdapter(scene, options = {}) {
|
|
|
18567
18954
|
getNodes() {
|
|
18568
18955
|
const visible = visibleLayers();
|
|
18569
18956
|
const out = [];
|
|
18570
|
-
for (const
|
|
18571
|
-
|
|
18572
|
-
if (n && visible.has(n.layer)) out.push(n);
|
|
18957
|
+
for (const n of scene.renderOrderNodes()) {
|
|
18958
|
+
if (visible.has(n.layer)) out.push(n);
|
|
18573
18959
|
}
|
|
18574
18960
|
return out;
|
|
18575
18961
|
},
|
|
@@ -18909,9 +19295,7 @@ function useSceneSelectTool(args) {
|
|
|
18909
19295
|
// path descriptor for a tighter test.
|
|
18910
19296
|
hitTestArea: (rect) => {
|
|
18911
19297
|
const hits = [];
|
|
18912
|
-
for (const
|
|
18913
|
-
const n = scene.get(nid);
|
|
18914
|
-
if (!n) continue;
|
|
19298
|
+
for (const n of scene.renderOrderNodes()) {
|
|
18915
19299
|
if (isPathLike(n.pose) && pathPoseDescriptor.intersectsRect) {
|
|
18916
19300
|
if (pathPoseDescriptor.intersectsRect(n.pose, rect)) hits.push(n.id);
|
|
18917
19301
|
continue;
|
|
@@ -18949,9 +19333,8 @@ function useSceneSelectTool(args) {
|
|
|
18949
19333
|
}
|
|
18950
19334
|
const tolerance = pickTolerancePx / meanScale(getView?.()?.scale ?? { x: 1, y: 1 });
|
|
18951
19335
|
const out = [];
|
|
18952
|
-
for (const
|
|
18953
|
-
|
|
18954
|
-
if (!n || !poseContainsRotated(n.pose, wx, wy, tolerance)) continue;
|
|
19336
|
+
for (const n of scene.renderOrderNodes()) {
|
|
19337
|
+
if (!poseContainsRotated(n.pose, wx, wy, tolerance)) continue;
|
|
18955
19338
|
if (shapePicking && !shapeCoversPoint(n, n.pose, wx, wy, { tolerance })) continue;
|
|
18956
19339
|
out.push(n.id);
|
|
18957
19340
|
}
|
|
@@ -20095,23 +20478,25 @@ function hitTestAreaPolygon(scene, area, areaBounds) {
|
|
|
20095
20478
|
const ab = areaBounds ?? boundsOf(area);
|
|
20096
20479
|
if (!ab) return [];
|
|
20097
20480
|
const hits = [];
|
|
20098
|
-
|
|
20099
|
-
|
|
20100
|
-
|
|
20481
|
+
const order = scene.renderOrderNodes();
|
|
20482
|
+
for (let i = 0; i < order.length; i++) {
|
|
20483
|
+
const node = order[i];
|
|
20484
|
+
if (node.kind === "container") continue;
|
|
20101
20485
|
const pose = node.pose;
|
|
20102
|
-
const
|
|
20486
|
+
const silhouette = pose !== null && typeof pose === "object" && pose.kind === "polygon";
|
|
20487
|
+
const b = silhouette ? nodeMemo(node, "aabb", pose, () => aabbOfPose(pose)) : aabbOfPose(pose);
|
|
20103
20488
|
if (!Number.isFinite(b.x) || !Number.isFinite(b.y) || !Number.isFinite(b.width) || !Number.isFinite(b.height)) {
|
|
20104
20489
|
continue;
|
|
20105
20490
|
}
|
|
20106
20491
|
if (b.x >= ab.x + ab.width || b.x + b.width <= ab.x || b.y >= ab.y + ab.height || b.y + b.height <= ab.y) {
|
|
20107
20492
|
continue;
|
|
20108
20493
|
}
|
|
20109
|
-
if (!
|
|
20110
|
-
hits.push(id);
|
|
20494
|
+
if (!silhouette) {
|
|
20495
|
+
hits.push(node.id);
|
|
20111
20496
|
continue;
|
|
20112
20497
|
}
|
|
20113
20498
|
if (silhouetteOverlapsArea(pose.coords, area)) {
|
|
20114
|
-
hits.push(id);
|
|
20499
|
+
hits.push(node.id);
|
|
20115
20500
|
}
|
|
20116
20501
|
}
|
|
20117
20502
|
return hits;
|
|
@@ -22345,14 +22730,25 @@ var inferredNodeProperties = inferredNodeRouting.map((e) => ({
|
|
|
22345
22730
|
|
|
22346
22731
|
// src/canvas/sceneViewRender.ts
|
|
22347
22732
|
var RENDERER_CACHE = /* @__PURE__ */ new WeakMap();
|
|
22348
|
-
function
|
|
22349
|
-
|
|
22350
|
-
|
|
22351
|
-
|
|
22352
|
-
|
|
22353
|
-
|
|
22354
|
-
|
|
22355
|
-
|
|
22733
|
+
function sceneAsHierarchy(scene) {
|
|
22734
|
+
return {
|
|
22735
|
+
getLayers: () => scene.layers.map((l) => ({ id: l.id, visible: l.visible })),
|
|
22736
|
+
getNode: (id) => scene.get(id),
|
|
22737
|
+
getChildren: (parentId) => {
|
|
22738
|
+
if (parentId === null) return scene.roots;
|
|
22739
|
+
const node = scene.get(parentId);
|
|
22740
|
+
return node && node.kind === "container" ? node.children : [];
|
|
22741
|
+
},
|
|
22742
|
+
getPose: (id) => scene.get(id).pose
|
|
22743
|
+
};
|
|
22744
|
+
}
|
|
22745
|
+
function buildSceneViewCommands(scene, view, drawOne, extraCommands, alphaFor) {
|
|
22746
|
+
const wrappedDrawOne = (node, pose, v) => wrapNodeOutput(drawOne(node, pose, v), pose, alphaFor ? alphaFor(node.id) : 1);
|
|
22747
|
+
const children = buildSceneTree(
|
|
22748
|
+
sceneAsHierarchy(scene),
|
|
22749
|
+
wrappedDrawOne,
|
|
22750
|
+
view
|
|
22751
|
+
);
|
|
22356
22752
|
if (extraCommands && extraCommands.length > 0) {
|
|
22357
22753
|
for (const cmd of extraCommands) children.push(cmd);
|
|
22358
22754
|
}
|
|
@@ -22363,7 +22759,7 @@ function buildSceneViewCommands(scene, view, drawOne, extraCommands) {
|
|
|
22363
22759
|
}];
|
|
22364
22760
|
}
|
|
22365
22761
|
function renderSceneToCanvas(args) {
|
|
22366
|
-
const { canvas, scene, view, width, height, drawOne, extraCommands } = args;
|
|
22762
|
+
const { canvas, scene, view, width, height, drawOne, extraCommands, alphaFor } = args;
|
|
22367
22763
|
const dpr = args.dpr ?? (typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1);
|
|
22368
22764
|
let entry = RENDERER_CACHE.get(canvas);
|
|
22369
22765
|
if (!entry) {
|
|
@@ -22391,11 +22787,11 @@ function renderSceneToCanvas(args) {
|
|
|
22391
22787
|
entry.height = height;
|
|
22392
22788
|
entry.dpr = dpr;
|
|
22393
22789
|
}
|
|
22394
|
-
const commands = buildSceneViewCommands(scene, view, drawOne, extraCommands);
|
|
22790
|
+
const commands = buildSceneViewCommands(scene, view, drawOne, extraCommands, alphaFor);
|
|
22395
22791
|
entry.renderer.render(commands, viewToMat3(view));
|
|
22396
22792
|
}
|
|
22397
22793
|
function SceneViewCanvasInner(props) {
|
|
22398
|
-
const { scene, view, width, height, drawOne, extraCommands, className, canvasRef } = props;
|
|
22794
|
+
const { scene, view, width, height, drawOne, extraCommands, alphaFor, className, canvasRef } = props;
|
|
22399
22795
|
useSyncExternalStore(scene.subscribe, scene.getVersion, scene.getVersion);
|
|
22400
22796
|
const localRef = useRef(null);
|
|
22401
22797
|
const setCanvasRef = (el) => {
|
|
@@ -22416,7 +22812,8 @@ function SceneViewCanvasInner(props) {
|
|
|
22416
22812
|
width,
|
|
22417
22813
|
height,
|
|
22418
22814
|
drawOne,
|
|
22419
|
-
extraCommands
|
|
22815
|
+
extraCommands,
|
|
22816
|
+
alphaFor
|
|
22420
22817
|
});
|
|
22421
22818
|
});
|
|
22422
22819
|
return /* @__PURE__ */ jsx(
|
|
@@ -22515,6 +22912,7 @@ function MinimapCanvasInner(props) {
|
|
|
22515
22912
|
width,
|
|
22516
22913
|
height,
|
|
22517
22914
|
drawOne,
|
|
22915
|
+
alphaFor,
|
|
22518
22916
|
fit = "scene",
|
|
22519
22917
|
poseBounds,
|
|
22520
22918
|
indicatorStyle,
|
|
@@ -22626,6 +23024,7 @@ function MinimapCanvasInner(props) {
|
|
|
22626
23024
|
height,
|
|
22627
23025
|
drawOne,
|
|
22628
23026
|
extraCommands,
|
|
23027
|
+
alphaFor,
|
|
22629
23028
|
className,
|
|
22630
23029
|
canvasRef: setCanvasRef
|
|
22631
23030
|
}
|
|
@@ -22667,7 +23066,7 @@ function planPixelRender(args) {
|
|
|
22667
23066
|
fill: { fill: "solid", color: args.background }
|
|
22668
23067
|
});
|
|
22669
23068
|
}
|
|
22670
|
-
commands.push(...buildSceneViewCommands(args.scene, view, drawOne));
|
|
23069
|
+
commands.push(...buildSceneViewCommands(args.scene, view, drawOne, void 0, args.alphaFor));
|
|
22671
23070
|
return { width, height, view, commands };
|
|
22672
23071
|
}
|
|
22673
23072
|
function defaultCreateCanvas(width, height) {
|
|
@@ -23019,15 +23418,11 @@ function measureText(ctx, text, maxWidth, style) {
|
|
|
23019
23418
|
function measureTextBounds(text, style, opts) {
|
|
23020
23419
|
const resolved = resolveTextStyle(style);
|
|
23021
23420
|
const runs = resolveRuns([{ text }], resolved);
|
|
23022
|
-
const { bounds } = layoutRuns(
|
|
23023
|
-
|
|
23024
|
-
|
|
23025
|
-
|
|
23026
|
-
|
|
23027
|
-
align: resolved.align
|
|
23028
|
-
},
|
|
23029
|
-
{ x: 0, y: 0 }
|
|
23030
|
-
);
|
|
23421
|
+
const { bounds } = layoutRuns(runs, {
|
|
23422
|
+
maxWidth: opts?.maxWidth ?? Infinity,
|
|
23423
|
+
lineHeight: opts?.lineHeight ?? resolved.lineHeight,
|
|
23424
|
+
align: resolved.align
|
|
23425
|
+
});
|
|
23031
23426
|
return bounds;
|
|
23032
23427
|
}
|
|
23033
23428
|
|
|
@@ -23940,10 +24335,9 @@ function useSceneTextEdit(scene, container, options = {}) {
|
|
|
23940
24335
|
const cy = view ? canvasY / view.scale.y + view.y : canvasY;
|
|
23941
24336
|
const readText = (data) => optsRef.current.getText ? optsRef.current.getText(data) : data.text ?? "";
|
|
23942
24337
|
const readStyle = (data) => optsRef.current.getStyle ? optsRef.current.getStyle(data) : data.style;
|
|
23943
|
-
const order =
|
|
24338
|
+
const order = sceneRef.current.renderOrderNodes();
|
|
23944
24339
|
for (let i = order.length - 1; i >= 0; i--) {
|
|
23945
|
-
const node =
|
|
23946
|
-
if (!node) continue;
|
|
24340
|
+
const node = order[i];
|
|
23947
24341
|
const text = readText(node.data);
|
|
23948
24342
|
const pose = {
|
|
23949
24343
|
x: node.pose.x,
|
|
@@ -27639,5 +28033,5 @@ function mergeContributions(...bundles) {
|
|
|
27639
28033
|
}
|
|
27640
28034
|
|
|
27641
28035
|
export { ALWAYS, ANCHOR_HIT_BASE_PX, ActionsProviderIfRoot, ActiveToolContextProvider, ActiveToolContextProviderIfRoot, BUNDLE_TOOLS, COARSE_TARGET_SCALE, CURVE_REPS, ColorOverrideRegistry, CropIcon, CursorCoordsHud, DEFAULT_ALPHA_DECAY, DEFAULT_ALPHA_MIN, DEFAULT_DEBUG_THEME, DEFAULT_DEVICE_PROFILE, DEFAULT_FILL_COLOR, DEFAULT_HANDLE_SIZE2 as DEFAULT_HANDLE_SIZE, DEFAULT_PALETTE, DEFAULT_ROTATION_HANDLE_DISTANCE, DEFAULT_STROKE_COLOR, DEFAULT_TEXT_STYLE, DEFAULT_VELOCITY_DECAY, DepRegistryProviderIfRoot, DeviceProfileProvider, DivideIcon, EASINGS, EllipseIcon, ExcludeIcon, EyedropperIcon, FALLBACK_FIT_VIEW, GHOST_STROKE, HANDLE_BASE_PX, HandIcon, IDENTITY_COLOR_MATRIX, IDENTITY_POSE_COMPOSITION, IntersectIcon, KIT_SHAPE_KINDS, LassoIcon, LineIcon, MIXED, MOVE_ANCHORS, MinimapCanvas, NEVER, OUTLINE_MIN_SCREEN_PX, PATH_ANCHOR_CHROME_ID, PenIcon, PencilIcon, PickHud, PointerProviderIfRoot, PolygonIcon, RECT_ALIGN_PROJECTION, ROTATION_HANDLE_BASE_PX, RectIcon, SPRING_PRESETS, SceneCanvas, SceneViewCanvas, SelectIcon, SelectionContextProvider, SelectionContextProviderIfRoot, ShaderCompileError, StarIcon, SubtractIcon, TextIcon, UnionIcon, UnknownIcon, VERSION, WeaselProvider, WeaselRenderer, aabbCenter, actionIs, alignDeltaFor, alignInsertBehavior, alignMoveBehavior, alignResizeBehavior, alignedStrokeRect, always, and, animateLifecycle, animateOnSetPose, annulusSemiAxes, applyBooleanOp, applyHitExistingGate, applyStyleToRange, areaSelectAction, arrayAdapter, asNodeId, bezierCubic, bezierQuadratic, 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, computeFitView2 as computeFitView, computeIndicatorCommand, computeWheelAction, cond, constrainTo45, containedThenNearest, countPathAnchors, createCellHighlightLayer, createChildrenLayer, createCornerResizeAffordance, createDebugOverlayLayer, createDebugSink, createDispatcher, createGridLayer, createGuidesLayer, createHistory2 as createHistory, createMarkdownRenderer, createMoveToIndexOp, createNodeProperties, createNodeRouting, createParallaxLayer, createPathAnchorAffordances, createPathEditingOverlayLayer, createPathLayer, createPenPreviewLayer, createReorderOp, createRotationAffordance, createScene, createSelectionHandlesLayer, createSelectionOutlineLayer, createSelectionOverlayLayer, createSetDataOp, createSetLayerOp, createSetPathOp, createSetTextOp, createTextLayer, createViewportLayer, cycleVertexColors, decomposePath, decomposeRectPose, defaultCommitAdapter, defaultDrawOne, defaultLabelTextRenderer, defaultNodeProperties, defaultNodeRouting, defaultVisibilityRules, deriveAlignmentGuides, deriveParallaxView, describeRule, domPositionToCharOffset, domToRuns, drawLayers, 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, easeOutCubic2 as easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorsAction, enterTextEditAction, enumerateAnchors, evaluate, fillInPoseFrame, fillToBoundsFrame, findNodeShape, findShapeInk, findShapeSilhouette, fitTextPose, fitToBounds, fitViewToBounds, fitZoom, focused, fontString, forEachCoalesced, freeform, gateLayer, gesturing, getAlpha01, getImageBitmap, getNodeShapes, getStylusData, gradientForBounds, gradientGeometry, hexToRgba, hitAffordanceRegions, hitAnchor, hitRotationHandle, hovering, hoveringSelected, imageStatus, inferredNodeProperties, inferredNodeRouting, insertAction, isEditableTarget2 as isEditableTarget, isPatternSpec, lassoSelectAction, layoutMarkdown, lerpColorArray, lerpOklab, lerpOklch, linear, liveScope, makeViewportZoomAction, markdownToRuns, mat3, matchAlignment, matchesKeyBinding, meanScale, measureText, measureTextBounds, measuredWidth, mergeAlphaFromPrev, mergeContributions, modeIn, modeIs, modeNot, modifierHeld, momentum, moveAction, multiActive, nearest, nearestWithin, nestedHitTester, never, nodeHasFlag, none, normalizeHex, not, nurbs, oklabToOklch, oklabToSrgbU8, oklchToOklab, openFilePicker, or, 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, registerNodeShape, registerProgram, renderLabel, renderSceneToCanvas, renderSceneToPixels, resizeAction, resolveColor, resolveDeviceProfile, resolveFillPattern, resolvePatternSpec, resolveRuns, resolveTextStyle, resolveVisibility, rgbaToHex, rotateAction, rotateAroundAABBCenter, rotatePathAround, rotatePoint, rotatedRectCorners, rotationDegreesUnit, rotationHandle, roundToCell, runsToDom, runsToMarkdown, runsToPlainText, sampleGradientStops, sceneFromJSON, sceneNodeClientRect, sceneToAdapter, scopeBindings, screenToWorld, selectFromLasso, selectionAtLeast, selectionEmpty, selectionIs, setFlagOverRange, shapeCoversPoint, sliceAction, snapPoint, solidVertexColors, specificity, spiro, splitPathByLine, splitSubpaths, springPose, springVertexColors, srgbU8ToOklab, staggerVertexColors, startThresholdDrag, styleAtRange, subscribeImageReady, tessellate, tessellateStroke, textCommand, textLineBoxes, tileGrid, toHex8, toRuns, translatePoseViaDescriptor, translateRectPose, tweenPose, tweenVertexColors, 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, useHoverTracking, useImageTool, useKeybindings, useLassoTool, useLineTool, useOptionalActiveToolContext, usePenTool, usePencilTool, usePinchGesture, usePinchZoomTool, usePointerStylus, usePolygonTool, usePublishSelection, useRectTool, useResizePolicy, useRotateTool, useScene, useSceneAdapter, useSceneTextEdit, useSelectTool, useSelection, useSelectionContext, useSimulation, useSliceDep, useStandardActions, useStarTool, useTextEdit, useTextTool, useTools, useVelocityTracker, useViewAnimation, useViewTween, useZoom, verticalAlignOffset, viewToMat3, viewToTransform, viewportDragPanAction, viewportZoomAction, when, withAlpha01, withCoord, withGradientKind, worldEditToStorage, worldPoseLookup, worldToScreen, zoomAt, zoomAtLeast };
|
|
27642
|
-
//# sourceMappingURL=chunk-
|
|
27643
|
-
//# sourceMappingURL=chunk-
|
|
28036
|
+
//# sourceMappingURL=chunk-FVNWK7U3.js.map
|
|
28037
|
+
//# sourceMappingURL=chunk-FVNWK7U3.js.map
|