@oh-just-another/renderer-canvas 0.58.1 → 0.60.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/README.md +63 -15
  3. package/dist/.tsbuildinfo +1 -1
  4. package/dist/canvas-target.d.ts +6 -1
  5. package/dist/canvas-target.d.ts.map +1 -1
  6. package/dist/canvas-target.js +18 -5
  7. package/dist/canvas-target.js.map +1 -1
  8. package/dist/constants.d.ts +81 -0
  9. package/dist/constants.d.ts.map +1 -1
  10. package/dist/constants.js +81 -0
  11. package/dist/constants.js.map +1 -1
  12. package/dist/hi-dpi.d.ts +21 -13
  13. package/dist/hi-dpi.d.ts.map +1 -1
  14. package/dist/hi-dpi.js +28 -33
  15. package/dist/hi-dpi.js.map +1 -1
  16. package/dist/image-source.d.ts +11 -0
  17. package/dist/image-source.d.ts.map +1 -1
  18. package/dist/image-source.js +20 -0
  19. package/dist/image-source.js.map +1 -1
  20. package/dist/index.d.ts +3 -3
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +6 -12
  23. package/dist/index.js.map +1 -1
  24. package/dist/layered-canvas.d.ts +7 -1
  25. package/dist/layered-canvas.d.ts.map +1 -1
  26. package/dist/layered-canvas.js +6 -3
  27. package/dist/layered-canvas.js.map +1 -1
  28. package/dist/layered-surface.d.ts +16 -0
  29. package/dist/layered-surface.d.ts.map +1 -1
  30. package/dist/layered-surface.js +53 -15
  31. package/dist/layered-surface.js.map +1 -1
  32. package/dist/recording-target.d.ts +85 -25
  33. package/dist/recording-target.d.ts.map +1 -1
  34. package/dist/recording-target.js +250 -50
  35. package/dist/recording-target.js.map +1 -1
  36. package/dist/render-worker.js +16 -3
  37. package/dist/render-worker.js.map +1 -1
  38. package/dist/tile-compositor.d.ts +43 -1
  39. package/dist/tile-compositor.d.ts.map +1 -1
  40. package/dist/tile-compositor.js +48 -5
  41. package/dist/tile-compositor.js.map +1 -1
  42. package/dist/webgl-helpers.d.ts +7 -0
  43. package/dist/webgl-helpers.d.ts.map +1 -0
  44. package/dist/webgl-helpers.js +32 -0
  45. package/dist/webgl-helpers.js.map +1 -0
  46. package/dist/webgl2-curve.d.ts +11 -0
  47. package/dist/webgl2-curve.d.ts.map +1 -1
  48. package/dist/webgl2-curve.js +151 -68
  49. package/dist/webgl2-curve.js.map +1 -1
  50. package/dist/webgl2-ellipse.d.ts +0 -27
  51. package/dist/webgl2-ellipse.d.ts.map +1 -1
  52. package/dist/webgl2-ellipse.js +21 -47
  53. package/dist/webgl2-ellipse.js.map +1 -1
  54. package/dist/webgl2-msdf-text.d.ts +14 -0
  55. package/dist/webgl2-msdf-text.d.ts.map +1 -1
  56. package/dist/webgl2-msdf-text.js +84 -36
  57. package/dist/webgl2-msdf-text.js.map +1 -1
  58. package/dist/webgl2-rect-batch.d.ts +81 -0
  59. package/dist/webgl2-rect-batch.d.ts.map +1 -0
  60. package/dist/webgl2-rect-batch.js +201 -0
  61. package/dist/webgl2-rect-batch.js.map +1 -0
  62. package/dist/webgl2-stroke.d.ts +6 -30
  63. package/dist/webgl2-stroke.d.ts.map +1 -1
  64. package/dist/webgl2-stroke.js +17 -30
  65. package/dist/webgl2-stroke.js.map +1 -1
  66. package/dist/webgl2-target.d.ts +74 -8
  67. package/dist/webgl2-target.d.ts.map +1 -1
  68. package/dist/webgl2-target.js +356 -257
  69. package/dist/webgl2-target.js.map +1 -1
  70. package/package.json +10 -8
@@ -2,8 +2,26 @@ import { TILE_SIZE, } from "@oh-just-another/renderer-core";
2
2
  import { getElementsInLayer, getElementWorldBounds, getLayersInOrder, } from "@oh-just-another/scene";
3
3
  import { createOffscreenCanvas2DTarget } from "./offscreen.js";
4
4
  import { getElementRenderer } from "@oh-just-another/renderer-core";
5
+ /** @internal Exported for unit tests; not part of the package API. */
6
+ export const buildDrawOrderIndex = (scene) => {
7
+ const byId = new Map();
8
+ const order = new Map();
9
+ let rank = 0;
10
+ for (const layer of getLayersInOrder(scene)) {
11
+ if (!layer.visible)
12
+ continue;
13
+ for (const shape of getElementsInLayer(scene, layer.id)) {
14
+ byId.set(shape.id, shape);
15
+ order.set(shape.id, rank++);
16
+ }
17
+ }
18
+ return { byId, order };
19
+ };
5
20
  export const renderViaTiles = (scene, mainTarget, options) => {
6
- const { viewport, cache, changedElements, zoomBucket } = options;
21
+ const { viewport, cache, changedElements, zoomBucket, index } = options;
22
+ // Build the draw-order lookup once per frame when an index is supplied;
23
+ // each fresh tile reuses it instead of re-walking the scene.
24
+ const drawOrder = index ? buildDrawOrderIndex(scene) : null;
7
25
  // 1) Invalidate cached tiles per patch (covers add / remove / move).
8
26
  if (changedElements) {
9
27
  for (const [id, record] of changedElements) {
@@ -25,7 +43,7 @@ export const renderViaTiles = (scene, mainTarget, options) => {
25
43
  const key = { col, row, zoom: zoomBucket };
26
44
  let entry = cache.get(key);
27
45
  if (!entry) {
28
- const fresh = rasteriseTile(scene, col, row, zoomBucket);
46
+ const fresh = rasteriseTile(scene, col, row, zoomBucket, index, drawOrder);
29
47
  if (!fresh)
30
48
  continue;
31
49
  cache.set(fresh);
@@ -42,7 +60,7 @@ export const renderViaTiles = (scene, mainTarget, options) => {
42
60
  * sized at `TILE_SIZE * zoomBucket` device pixels per side. Returns
43
61
  * `null` when the tile contains no shapes.
44
62
  */
45
- const rasteriseTile = (scene, col, row, zoomBucket) => {
63
+ const rasteriseTile = (scene, col, row, zoomBucket, index, drawOrder) => {
46
64
  if (typeof OffscreenCanvas === "undefined")
47
65
  return null;
48
66
  const worldX = col * TILE_SIZE;
@@ -53,7 +71,9 @@ const rasteriseTile = (scene, col, row, zoomBucket) => {
53
71
  width: TILE_SIZE,
54
72
  height: TILE_SIZE,
55
73
  };
56
- const shapes = elementsIntersectingTile(scene, worldBounds);
74
+ const shapes = index && drawOrder
75
+ ? elementsIntersectingTileIndexed(index, drawOrder, worldBounds)
76
+ : elementsIntersectingTile(scene, worldBounds);
57
77
  if (shapes.length === 0)
58
78
  return null;
59
79
  // Bitmap size — `TILE_SIZE * zoomBucket` device pixels so the tile
@@ -90,7 +110,8 @@ const rasteriseTile = (scene, col, row, zoomBucket) => {
90
110
  elements: shapes.map((s) => s.id),
91
111
  };
92
112
  };
93
- const elementsIntersectingTile = (scene, tileBounds) => {
113
+ /** @internal Exported for unit tests; not part of the package API. */
114
+ export const elementsIntersectingTile = (scene, tileBounds) => {
94
115
  const out = [];
95
116
  for (const layer of getLayersInOrder(scene)) {
96
117
  if (!layer.visible)
@@ -103,5 +124,27 @@ const elementsIntersectingTile = (scene, tileBounds) => {
103
124
  }
104
125
  return out;
105
126
  };
127
+ /**
128
+ * Index-backed equivalent of {@link elementsIntersectingTile}. Queries the
129
+ * spatial index for candidate ids overlapping the tile, filters them
130
+ * against the precise world-AABB (same predicate the full scan uses), then
131
+ * restores global draw order via `drawOrder.order`. Returns the identical
132
+ * set and ordering as the full scan for a correctly-populated index — only
133
+ * the work is O(candidates) instead of O(shapes).
134
+ */
135
+ /** @internal Exported for unit tests; not part of the package API. */
136
+ export const elementsIntersectingTileIndexed = (index, drawOrder, tileBounds) => {
137
+ const hits = [];
138
+ for (const id of index.query(tileBounds)) {
139
+ const shape = drawOrder.byId.get(id);
140
+ if (!shape)
141
+ continue; // hidden layer or not in the current scene
142
+ if (!intersects(getElementWorldBounds(shape), tileBounds))
143
+ continue;
144
+ hits.push({ shape, order: drawOrder.order.get(id) ?? 0 });
145
+ }
146
+ hits.sort((a, b) => a.order - b.order);
147
+ return hits.map((h) => h.shape);
148
+ };
106
149
  const intersects = (a, b) => a.x < b.x + b.width && a.x + a.width > b.x && a.y < b.y + b.height && a.y + a.height > b.y;
107
150
  //# sourceMappingURL=tile-compositor.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tile-compositor.js","sourceRoot":"","sources":["../src/tile-compositor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tile-compositor.js","sourceRoot":"","sources":["../src/tile-compositor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /** Assert a WebGL resource was created (non-null), or throw. */
2
+ export declare const glReq: <T>(v: T | null) => T;
3
+ /** Compile a shader of `type` from `src`; `label` names the program in errors. */
4
+ export declare const compileShader: (gl: WebGL2RenderingContext, type: number, src: string, label: string) => WebGLShader;
5
+ /** Link a program from compiled shaders; `label` names the program in errors. */
6
+ export declare const linkProgram: (gl: WebGL2RenderingContext, vert: WebGLShader, frag: WebGLShader, label: string) => WebGLProgram;
7
+ //# sourceMappingURL=webgl-helpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webgl-helpers.d.ts","sourceRoot":"","sources":["../src/webgl-helpers.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,eAAO,MAAM,KAAK,GAAI,CAAC,EAAE,GAAG,CAAC,GAAG,IAAI,KAAG,CAGtC,CAAC;AAEF,kFAAkF;AAClF,eAAO,MAAM,aAAa,GACxB,IAAI,sBAAsB,EAC1B,MAAM,MAAM,EACZ,KAAK,MAAM,EACX,OAAO,MAAM,KACZ,WAUF,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,WAAW,GACtB,IAAI,sBAAsB,EAC1B,MAAM,WAAW,EACjB,MAAM,WAAW,EACjB,OAAO,MAAM,KACZ,YAWF,CAAC"}
@@ -0,0 +1,32 @@
1
+ /** Assert a WebGL resource was created (non-null), or throw. */
2
+ export const glReq = (v) => {
3
+ if (v === null)
4
+ throw new Error("packages/renderer-canvas: WebGL resource creation failed");
5
+ return v;
6
+ };
7
+ /** Compile a shader of `type` from `src`; `label` names the program in errors. */
8
+ export const compileShader = (gl, type, src, label) => {
9
+ const sh = glReq(gl.createShader(type));
10
+ gl.shaderSource(sh, src);
11
+ gl.compileShader(sh);
12
+ if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
13
+ const log = gl.getShaderInfoLog(sh);
14
+ gl.deleteShader(sh);
15
+ throw new Error(`${label} shader compile failed: ${log}`);
16
+ }
17
+ return sh;
18
+ };
19
+ /** Link a program from compiled shaders; `label` names the program in errors. */
20
+ export const linkProgram = (gl, vert, frag, label) => {
21
+ const program = glReq(gl.createProgram());
22
+ gl.attachShader(program, vert);
23
+ gl.attachShader(program, frag);
24
+ gl.linkProgram(program);
25
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
26
+ const log = gl.getProgramInfoLog(program);
27
+ gl.deleteProgram(program);
28
+ throw new Error(`${label} program link failed: ${log}`);
29
+ }
30
+ return program;
31
+ };
32
+ //# sourceMappingURL=webgl-helpers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webgl-helpers.js","sourceRoot":"","sources":["../src/webgl-helpers.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,MAAM,CAAC,MAAM,KAAK,GAAG,CAAI,CAAW,EAAK,EAAE;IACzC,IAAI,CAAC,KAAK,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,0DAA0D,CAAC,CAAC;IAC5F,OAAO,CAAC,CAAC;AACX,CAAC,CAAC;AAEF,kFAAkF;AAClF,MAAM,CAAC,MAAM,aAAa,GAAG,CAC3B,EAA0B,EAC1B,IAAY,EACZ,GAAW,EACX,KAAa,EACA,EAAE;IACf,MAAM,EAAE,GAAG,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC;IACxC,EAAE,CAAC,YAAY,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC;IACzB,EAAE,CAAC,aAAa,CAAC,EAAE,CAAC,CAAC;IACrB,IAAI,CAAC,EAAE,CAAC,kBAAkB,CAAC,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,EAAE,CAAC;QAClD,MAAM,GAAG,GAAG,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;QACpC,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;QACpB,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,2BAA2B,GAAG,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,EAAE,CAAC;AACZ,CAAC,CAAC;AAEF,iFAAiF;AACjF,MAAM,CAAC,MAAM,WAAW,GAAG,CACzB,EAA0B,EAC1B,IAAiB,EACjB,IAAiB,EACjB,KAAa,EACC,EAAE;IAChB,MAAM,OAAO,GAAG,KAAK,CAAC,EAAE,CAAC,aAAa,EAAE,CAAC,CAAC;IAC1C,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC/B,EAAE,CAAC,YAAY,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC/B,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,CAAC;IACxB,IAAI,CAAC,EAAE,CAAC,mBAAmB,CAAC,OAAO,EAAE,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC;QACrD,MAAM,GAAG,GAAG,EAAE,CAAC,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,EAAE,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,yBAAyB,GAAG,EAAE,CAAC,CAAC;IAC1D,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC,CAAC"}
@@ -43,4 +43,15 @@ export declare class LoopBlinnCurvePipeline {
43
43
  }): void;
44
44
  dispose(): void;
45
45
  }
46
+ /**
47
+ * Cached triangulation lookup. Returns per-entry packed buffers —
48
+ * valid until the entry is evicted, which can't happen before the
49
+ * caller's synchronous `bufferData` upload.
50
+ *
51
+ * Exported for tests only — not part of the package's public API.
52
+ */
53
+ export declare const triangulateCached: (curves: readonly CurveSegment[]) => {
54
+ positions: Float32Array;
55
+ uvs: Float32Array;
56
+ };
46
57
  //# sourceMappingURL=webgl2-curve.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"webgl2-curve.d.ts","sourceRoot":"","sources":["../src/webgl2-curve.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,KAAK,EACX,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;CACnC;AAED,qBAAa,sBAAsB;IAUrB,OAAO,CAAC,QAAQ,CAAC,EAAE;IAT/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8B;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8B;IACrD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;IACvD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAED,EAAE,EAAE,sBAAsB;IAavD;;;;OAIG;IACH,IAAI,CACF,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACxC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAC7C,IAAI;IAsCP,OAAO,IAAI,IAAI;CAKhB"}
1
+ {"version":3,"file":"webgl2-curve.d.ts","sourceRoot":"","sources":["../src/webgl2-curve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,KAAK,EAAE,MAAM,6BAA6B,CAAC;AAC7E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAIxD;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,GAAG,GAAG,GAAG,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,EAAE,CAAC;CACnC;AAED,qBAAa,sBAAsB;IAUrB,OAAO,CAAC,QAAQ,CAAC,EAAE;IAT/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAc;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8B;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8B;IACrD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;IACvD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;gBAED,EAAE,EAAE,sBAAsB;IAavD;;;;OAIG;IACH,IAAI,CACF,MAAM,EAAE,SAAS,YAAY,EAAE,EAC/B,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACxC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAC7C,IAAI;IAwBP,OAAO,IAAI,IAAI;CAKhB;AAyID;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,SAAS,YAAY,EAAE,KAC9B;IAAE,SAAS,EAAE,YAAY,CAAC;IAAC,GAAG,EAAE,YAAY,CAAA;CAoB9C,CAAC"}
@@ -1,4 +1,6 @@
1
- import { cubicToTriangles, packCurveTriangles, quadraticToTriangle, } from "@oh-just-another/curve-mesh";
1
+ import { CurveTriangleBatch } from "@oh-just-another/curve-mesh";
2
+ import { WEBGL2_CURVE_TRIANGULATION_CACHE_CAP } from "./constants.js";
3
+ import { compileShader, glReq, linkProgram } from "./webgl-helpers.js";
2
4
  export class LoopBlinnCurvePipeline {
3
5
  gl;
4
6
  program;
@@ -11,9 +13,9 @@ export class LoopBlinnCurvePipeline {
11
13
  aUVW;
12
14
  constructor(gl) {
13
15
  this.gl = gl;
14
- const vert = compile(gl, gl.VERTEX_SHADER, VERTEX_SRC);
15
- const frag = compile(gl, gl.FRAGMENT_SHADER, FRAGMENT_SRC);
16
- this.program = link(gl, vert, frag);
16
+ const vert = compileShader(gl, gl.VERTEX_SHADER, VERTEX_SRC, "Loop-Blinn");
17
+ const frag = compileShader(gl, gl.FRAGMENT_SHADER, FRAGMENT_SRC, "Loop-Blinn");
18
+ this.program = linkProgram(gl, vert, frag, "Loop-Blinn");
17
19
  this.vbo = glReq(gl.createBuffer());
18
20
  this.uvBuf = glReq(gl.createBuffer());
19
21
  this.aPos = gl.getAttribLocation(this.program, "aPos");
@@ -30,27 +32,9 @@ export class LoopBlinnCurvePipeline {
30
32
  draw(curves, color, opacity, transform, surfaceSize) {
31
33
  if (curves.length === 0 || opacity <= 0)
32
34
  return;
33
- const triangles = [];
34
- for (const seg of curves) {
35
- if (seg.kind === "q") {
36
- const [p0, p1, p2] = seg.points;
37
- if (!p0 || !p1 || !p2)
38
- continue;
39
- const tri = quadraticToTriangle(p0, p1, p2);
40
- if (tri)
41
- triangles.push(tri);
42
- }
43
- else {
44
- const [p0, p1, p2, p3] = seg.points;
45
- if (!p0 || !p1 || !p2 || !p3)
46
- continue;
47
- for (const tri of cubicToTriangles(p0, p1, p2, p3))
48
- triangles.push(tri);
49
- }
50
- }
51
- if (triangles.length === 0)
35
+ const { positions, uvs } = triangulateCached(curves);
36
+ if (positions.length === 0)
52
37
  return;
53
- const { positions, uvs } = packCurveTriangles(triangles);
54
38
  const gl = this.gl;
55
39
  gl.useProgram(this.program);
56
40
  gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
@@ -72,20 +56,152 @@ export class LoopBlinnCurvePipeline {
72
56
  this.gl.deleteProgram(this.program);
73
57
  }
74
58
  }
59
+ /**
60
+ * Module-level scratch for `affineToClipMat3` — same reuse pattern as
61
+ * the earcut / stroke / `applyMat` scratch buffers in webgl2-target.
62
+ * Consumed synchronously by `uniformMatrix3fv` (which copies the values
63
+ * into GL state), so one shared buffer avoids a Float32Array allocation
64
+ * per curve draw.
65
+ */
66
+ const scratchClipMat3 = new Float32Array(9);
75
67
  const affineToClipMat3 = (t, w, h) => {
76
68
  const sx = 2 / w;
77
69
  const sy = -2 / h;
78
- return new Float32Array([
79
- t.a * sx,
80
- t.b * sy,
81
- 0,
82
- t.c * sx,
83
- t.d * sy,
84
- 0,
85
- t.e * sx - 1,
86
- t.f * sy + 1,
87
- 1,
88
- ]);
70
+ scratchClipMat3[0] = t.a * sx;
71
+ scratchClipMat3[1] = t.b * sy;
72
+ scratchClipMat3[2] = 0;
73
+ scratchClipMat3[3] = t.c * sx;
74
+ scratchClipMat3[4] = t.d * sy;
75
+ scratchClipMat3[5] = 0;
76
+ scratchClipMat3[6] = t.e * sx - 1;
77
+ scratchClipMat3[7] = t.f * sy + 1;
78
+ scratchClipMat3[8] = 1;
79
+ return scratchClipMat3;
80
+ };
81
+ /**
82
+ * Content-keyed LRU cache of Loop-Blinn triangulations, shared by all
83
+ * `LoopBlinnCurvePipeline` instances (the data is GL-independent).
84
+ *
85
+ * Renderers emit paths in element-local coordinates and `draw()` gets
86
+ * the view transform separately (applied in the vertex shader), so:
87
+ * - identical geometry (every same-size rounded rect) shares one entry;
88
+ * - pan / zoom / drag never invalidate an entry;
89
+ * - no scale bucket is needed — triangulation is scale-independent
90
+ * (fixed cubic subdivision count, no screen-space adaptivity).
91
+ *
92
+ * The `curves` array is rebuilt by `WebGL2Target` on every
93
+ * `beginPath()`, so there is no stable object identity to key a WeakMap
94
+ * on; instead the key is the flat list of segment kinds +
95
+ * control-point coordinates, addressed by a 32-bit FNV-1a hash with a
96
+ * full float comparison on hit (hash collisions fall back to
97
+ * recompute + replace). `Map` insertion order gives LRU: hits re-insert
98
+ * at the tail, overflow evicts the head.
99
+ */
100
+ const curveMeshCache = new Map();
101
+ /** Scratch for building the flat key without per-draw allocation. */
102
+ let scratchKey = new Float64Array(64);
103
+ const ensureKeyCapacity = (n) => {
104
+ if (scratchKey.length >= n)
105
+ return;
106
+ let cap = scratchKey.length;
107
+ while (cap < n)
108
+ cap *= 2;
109
+ scratchKey = new Float64Array(cap);
110
+ };
111
+ /** Views over one float64 for hashing its bit pattern. */
112
+ const hashFloatBuf = new Float64Array(1);
113
+ const hashFloatBits = new Uint32Array(hashFloatBuf.buffer);
114
+ /** Shared zero-allocation triangulation sink (see `CurveTriangleBatch`). */
115
+ const sharedBatch = new CurveTriangleBatch();
116
+ /**
117
+ * Flatten `curves` into `scratchKey` (kind marker + control points per
118
+ * segment) and return the used length.
119
+ */
120
+ const buildKey = (curves) => {
121
+ // Worst case per segment: 1 kind marker + 4 points × 2 coords.
122
+ ensureKeyCapacity(curves.length * 9);
123
+ const key = scratchKey;
124
+ let off = 0;
125
+ for (const seg of curves) {
126
+ key[off++] = seg.kind === "q" ? 1 : 2;
127
+ for (const p of seg.points) {
128
+ key[off++] = p.x;
129
+ key[off++] = p.y;
130
+ }
131
+ }
132
+ return off;
133
+ };
134
+ /** FNV-1a over the bit patterns of `key[0..len)`. */
135
+ const hashKey = (key, len) => {
136
+ let h = 0x811c9dc5;
137
+ for (let i = 0; i < len; i++) {
138
+ hashFloatBuf[0] = key[i] ?? 0;
139
+ h = Math.imul(h ^ (hashFloatBits[0] ?? 0), 0x01000193);
140
+ h = Math.imul(h ^ (hashFloatBits[1] ?? 0), 0x01000193);
141
+ }
142
+ return h >>> 0;
143
+ };
144
+ const keysEqual = (a, b, len) => {
145
+ if (a.length !== len)
146
+ return false;
147
+ for (let i = 0; i < len; i++) {
148
+ if (a[i] !== b[i])
149
+ return false;
150
+ }
151
+ return true;
152
+ };
153
+ /** Triangulate `curves` through the shared batch into a fresh entry. */
154
+ const triangulate = (curves, keyLen) => {
155
+ sharedBatch.reset();
156
+ for (const seg of curves) {
157
+ if (seg.kind === "q") {
158
+ const [p0, p1, p2] = seg.points;
159
+ if (!p0 || !p1 || !p2)
160
+ continue;
161
+ sharedBatch.addQuadratic(p0, p1, p2);
162
+ }
163
+ else {
164
+ const [p0, p1, p2, p3] = seg.points;
165
+ if (!p0 || !p1 || !p2 || !p3)
166
+ continue;
167
+ sharedBatch.addCubic(p0, p1, p2, p3);
168
+ }
169
+ }
170
+ return {
171
+ key: scratchKey.slice(0, keyLen),
172
+ // Copy out of the shared batch — entries outlive the next batch use.
173
+ positions: new Float32Array(sharedBatch.positions),
174
+ uvs: new Float32Array(sharedBatch.uvs),
175
+ };
176
+ };
177
+ /**
178
+ * Cached triangulation lookup. Returns per-entry packed buffers —
179
+ * valid until the entry is evicted, which can't happen before the
180
+ * caller's synchronous `bufferData` upload.
181
+ *
182
+ * Exported for tests only — not part of the package's public API.
183
+ */
184
+ export const triangulateCached = (curves) => {
185
+ const keyLen = buildKey(curves);
186
+ const hash = hashKey(scratchKey, keyLen);
187
+ const cached = curveMeshCache.get(hash);
188
+ if (cached && keysEqual(cached.key, scratchKey, keyLen)) {
189
+ // Touch — re-insert at the tail so LRU eviction picks colder entries.
190
+ curveMeshCache.delete(hash);
191
+ curveMeshCache.set(hash, cached);
192
+ return cached;
193
+ }
194
+ // Miss or hash collision — recompute and (re)place the slot.
195
+ const entry = triangulate(curves, keyLen);
196
+ curveMeshCache.delete(hash);
197
+ curveMeshCache.set(hash, entry);
198
+ while (curveMeshCache.size > WEBGL2_CURVE_TRIANGULATION_CACHE_CAP) {
199
+ const oldest = curveMeshCache.keys().next().value;
200
+ if (oldest === undefined)
201
+ break;
202
+ curveMeshCache.delete(oldest);
203
+ }
204
+ return entry;
89
205
  };
90
206
  /**
91
207
  * Vertex shader passes through the Loop-Blinn (u, v, w) coordinates as
@@ -132,37 +248,4 @@ void main() {
132
248
  float a = coverage * uOpacity;
133
249
  fragColor = vec4(uColor * a, a);
134
250
  }`;
135
- /**
136
- * Asserts a WebGL resource handle is non-null. `gl.createBuffer` /
137
- * `getUniformLocation` / `createShader` are typed non-null but return
138
- * `null` on context loss; this surfaces that as a throw.
139
- */
140
- const glReq = (v) => {
141
- if (v === null)
142
- throw new Error("packages/renderer-canvas: WebGL resource creation failed");
143
- return v;
144
- };
145
- const compile = (gl, type, src) => {
146
- const sh = glReq(gl.createShader(type));
147
- gl.shaderSource(sh, src);
148
- gl.compileShader(sh);
149
- if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
150
- const log = gl.getShaderInfoLog(sh);
151
- gl.deleteShader(sh);
152
- throw new Error(`Loop-Blinn shader compile failed: ${log}`);
153
- }
154
- return sh;
155
- };
156
- const link = (gl, vert, frag) => {
157
- const program = gl.createProgram();
158
- gl.attachShader(program, vert);
159
- gl.attachShader(program, frag);
160
- gl.linkProgram(program);
161
- if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
162
- const log = gl.getProgramInfoLog(program);
163
- gl.deleteProgram(program);
164
- throw new Error(`Loop-Blinn program link failed: ${log}`);
165
- }
166
- return program;
167
- };
168
251
  //# sourceMappingURL=webgl2-curve.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"webgl2-curve.js","sourceRoot":"","sources":["../src/webgl2-curve.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"webgl2-curve.js","sourceRoot":"","sources":["../src/webgl2-curve.ts"],"names":[],"mappings":"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"}
@@ -1,31 +1,4 @@
1
1
  import type { Transform } from "@oh-just-another/types";
2
- /**
3
- * Fragment-shader SDF ellipse pipeline for `WebGL2Target`. Renders an
4
- * ellipse as a single textured quad (4 vertices, 2 triangles)
5
- * regardless of radius — the fragment shader does an inside/outside
6
- * test against the unit circle in normalised local coordinates.
7
- *
8
- * Vertex layout (static, interleaved):
9
- * aPos aLocal
10
- * 0,0 -1,-1
11
- * 1,0 1,-1
12
- * 0,1 -1, 1
13
- * 1,1 1, 1
14
- *
15
- * `uTransform` maps `aPos` (unit square [0,1]²) through:
16
- * 1. scale to ellipse bbox (2*rx, 2*ry)
17
- * 2. translate to (cx-rx, cy-ry)
18
- * 3. apply caller's world→screen affine
19
- * 4. pixel→clip-space (NDC)
20
- *
21
- * The fragment shader gets `vLocal` interpolated across the quad:
22
- * inside the ellipse → dot(vLocal, vLocal) < 1
23
- * on the boundary → dot(vLocal, vLocal) = 1
24
- * outside → dot(vLocal, vLocal) > 1
25
- *
26
- * `smoothstep(1+fwidth, 1-fwidth, r²)` gives sub-pixel AA at the
27
- * boundary independent of zoom.
28
- */
29
2
  export declare class EllipsePipeline {
30
3
  private readonly gl;
31
4
  private readonly program;
@@ -1 +1 @@
1
- {"version":3,"file":"webgl2-ellipse.d.ts","sourceRoot":"","sources":["../src/webgl2-ellipse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,qBAAa,eAAe;IASd,OAAO,CAAC,QAAQ,CAAC,EAAE;IAR/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8B;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8B;IACrD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;gBAE1B,EAAE,EAAE,sBAAsB;IAmBvD;;;;;;OAMG;IACH,IAAI,CACF,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACxC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAC7C,IAAI;IAuCP,OAAO,IAAI,IAAI;CAIhB"}
1
+ {"version":3,"file":"webgl2-ellipse.d.ts","sourceRoot":"","sources":["../src/webgl2-ellipse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAuCxD,qBAAa,eAAe;IASd,OAAO,CAAC,QAAQ,CAAC,EAAE;IAR/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAA8B;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA8B;IACrD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;gBAE1B,EAAE,EAAE,sBAAsB;IAmBvD;;;;;;OAMG;IACH,IAAI,CACF,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EACxC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,SAAS,EACpB,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAC7C,IAAI;IAqCP,OAAO,IAAI,IAAI;CAIhB"}
@@ -1,3 +1,4 @@
1
+ import { compileShader, glReq, linkProgram } from "./webgl-helpers.js";
1
2
  /**
2
3
  * Fragment-shader SDF ellipse pipeline for `WebGL2Target`. Renders an
3
4
  * ellipse as a single textured quad (4 vertices, 2 triangles)
@@ -25,6 +26,13 @@
25
26
  * `smoothstep(1+fwidth, 1-fwidth, r²)` gives sub-pixel AA at the
26
27
  * boundary independent of zoom.
27
28
  */
29
+ /**
30
+ * Module-level scratch mat3 — same reuse pattern as the earcut / stroke
31
+ * scratch buffers in webgl2-target/webgl2-stroke. `uniformMatrix3fv`
32
+ * copies the values into GL state synchronously, so one shared buffer
33
+ * avoids a Float32Array allocation per ellipse fill.
34
+ */
35
+ const scratchMat3 = new Float32Array(9);
28
36
  export class EllipsePipeline {
29
37
  gl;
30
38
  program;
@@ -36,9 +44,9 @@ export class EllipsePipeline {
36
44
  uOpacity;
37
45
  constructor(gl) {
38
46
  this.gl = gl;
39
- const vert = compile(gl, gl.VERTEX_SHADER, VERTEX_SRC);
40
- const frag = compile(gl, gl.FRAGMENT_SHADER, FRAGMENT_SRC);
41
- this.program = link(gl, vert, frag);
47
+ const vert = compileShader(gl, gl.VERTEX_SHADER, VERTEX_SRC, "Ellipse");
48
+ const frag = compileShader(gl, gl.FRAGMENT_SHADER, FRAGMENT_SRC, "Ellipse");
49
+ this.program = linkProgram(gl, vert, frag, "Ellipse");
42
50
  this.aPos = gl.getAttribLocation(this.program, "aPos");
43
51
  this.aLocal = gl.getAttribLocation(this.program, "aLocal");
44
52
  this.uTransform = gl.getUniformLocation(this.program, "uTransform");
@@ -78,18 +86,16 @@ export class EllipsePipeline {
78
86
  // inWorld = transform · (scaleSq + (left, top))
79
87
  // inClip = pixel→clip(inWorld)
80
88
  const t = transform;
81
- const mat = new Float32Array([
82
- t.a * w * sx,
83
- t.b * w * sy,
84
- 0,
85
- t.c * h * sx,
86
- t.d * h * sy,
87
- 0,
88
- (t.a * left + t.c * top + t.e) * sx - 1,
89
- (t.b * left + t.d * top + t.f) * sy + 1,
90
- 1,
91
- ]);
92
- gl.uniformMatrix3fv(this.uTransform, false, mat);
89
+ scratchMat3[0] = t.a * w * sx;
90
+ scratchMat3[1] = t.b * w * sy;
91
+ scratchMat3[2] = 0;
92
+ scratchMat3[3] = t.c * h * sx;
93
+ scratchMat3[4] = t.d * h * sy;
94
+ scratchMat3[5] = 0;
95
+ scratchMat3[6] = (t.a * left + t.c * top + t.e) * sx - 1;
96
+ scratchMat3[7] = (t.b * left + t.d * top + t.f) * sy + 1;
97
+ scratchMat3[8] = 1;
98
+ gl.uniformMatrix3fv(this.uTransform, false, scratchMat3);
93
99
  gl.uniform3f(this.uColor, color[0], color[1], color[2]);
94
100
  gl.uniform1f(this.uOpacity, opacity);
95
101
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
@@ -135,36 +141,4 @@ void main() {
135
141
  float a = coverage * uOpacity;
136
142
  fragColor = vec4(uColor * a, a);
137
143
  }`;
138
- /**
139
- * Asserts a WebGL resource handle is non-null. Creation APIs are typed
140
- * non-null but return `null` on context loss; surface that as a throw.
141
- */
142
- const glReq = (v) => {
143
- if (v === null)
144
- throw new Error("packages/renderer-canvas: WebGL resource creation failed");
145
- return v;
146
- };
147
- const compile = (gl, type, src) => {
148
- const sh = glReq(gl.createShader(type));
149
- gl.shaderSource(sh, src);
150
- gl.compileShader(sh);
151
- if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
152
- const log = gl.getShaderInfoLog(sh);
153
- gl.deleteShader(sh);
154
- throw new Error(`Ellipse shader compile failed: ${log}`);
155
- }
156
- return sh;
157
- };
158
- const link = (gl, vert, frag) => {
159
- const program = gl.createProgram();
160
- gl.attachShader(program, vert);
161
- gl.attachShader(program, frag);
162
- gl.linkProgram(program);
163
- if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
164
- const log = gl.getProgramInfoLog(program);
165
- gl.deleteProgram(program);
166
- throw new Error(`Ellipse program link failed: ${log}`);
167
- }
168
- return program;
169
- };
170
144
  //# sourceMappingURL=webgl2-ellipse.js.map