@oh-just-another/renderer-canvas 0.57.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 (81) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/LICENSE +21 -0
  3. package/README.md +36 -0
  4. package/dist/.tsbuildinfo +1 -0
  5. package/dist/canvas-target.d.ts +83 -0
  6. package/dist/canvas-target.d.ts.map +1 -0
  7. package/dist/canvas-target.js +208 -0
  8. package/dist/canvas-target.js.map +1 -0
  9. package/dist/canvas-text-shaper.d.ts +11 -0
  10. package/dist/canvas-text-shaper.d.ts.map +1 -0
  11. package/dist/canvas-text-shaper.js +56 -0
  12. package/dist/canvas-text-shaper.js.map +1 -0
  13. package/dist/constants.d.ts +52 -0
  14. package/dist/constants.d.ts.map +1 -0
  15. package/dist/constants.js +52 -0
  16. package/dist/constants.js.map +1 -0
  17. package/dist/hi-dpi.d.ts +26 -0
  18. package/dist/hi-dpi.d.ts.map +1 -0
  19. package/dist/hi-dpi.js +62 -0
  20. package/dist/hi-dpi.js.map +1 -0
  21. package/dist/image-source.d.ts +3 -0
  22. package/dist/image-source.d.ts.map +1 -0
  23. package/dist/image-source.js +65 -0
  24. package/dist/image-source.js.map +1 -0
  25. package/dist/index.d.ts +15 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +24 -0
  28. package/dist/index.js.map +1 -0
  29. package/dist/layered-canvas.d.ts +46 -0
  30. package/dist/layered-canvas.d.ts.map +1 -0
  31. package/dist/layered-canvas.js +95 -0
  32. package/dist/layered-canvas.js.map +1 -0
  33. package/dist/layered-surface.d.ts +75 -0
  34. package/dist/layered-surface.d.ts.map +1 -0
  35. package/dist/layered-surface.js +262 -0
  36. package/dist/layered-surface.js.map +1 -0
  37. package/dist/offscreen.d.ts +30 -0
  38. package/dist/offscreen.d.ts.map +1 -0
  39. package/dist/offscreen.js +50 -0
  40. package/dist/offscreen.js.map +1 -0
  41. package/dist/recording-target.d.ts +203 -0
  42. package/dist/recording-target.d.ts.map +1 -0
  43. package/dist/recording-target.js +260 -0
  44. package/dist/recording-target.js.map +1 -0
  45. package/dist/render-worker.d.ts +2 -0
  46. package/dist/render-worker.d.ts.map +1 -0
  47. package/dist/render-worker.js +112 -0
  48. package/dist/render-worker.js.map +1 -0
  49. package/dist/tile-compositor.d.ts +44 -0
  50. package/dist/tile-compositor.d.ts.map +1 -0
  51. package/dist/tile-compositor.js +110 -0
  52. package/dist/tile-compositor.js.map +1 -0
  53. package/dist/webgl2-color.d.ts +13 -0
  54. package/dist/webgl2-color.d.ts.map +1 -0
  55. package/dist/webgl2-color.js +26 -0
  56. package/dist/webgl2-color.js.map +1 -0
  57. package/dist/webgl2-curve.d.ts +46 -0
  58. package/dist/webgl2-curve.d.ts.map +1 -0
  59. package/dist/webgl2-curve.js +162 -0
  60. package/dist/webgl2-curve.js.map +1 -0
  61. package/dist/webgl2-ellipse.d.ts +52 -0
  62. package/dist/webgl2-ellipse.d.ts.map +1 -0
  63. package/dist/webgl2-ellipse.js +171 -0
  64. package/dist/webgl2-ellipse.js.map +1 -0
  65. package/dist/webgl2-msdf-text.d.ts +84 -0
  66. package/dist/webgl2-msdf-text.d.ts.map +1 -0
  67. package/dist/webgl2-msdf-text.js +306 -0
  68. package/dist/webgl2-msdf-text.js.map +1 -0
  69. package/dist/webgl2-stroke.d.ts +52 -0
  70. package/dist/webgl2-stroke.d.ts.map +1 -0
  71. package/dist/webgl2-stroke.js +318 -0
  72. package/dist/webgl2-stroke.js.map +1 -0
  73. package/dist/webgl2-target.d.ts +311 -0
  74. package/dist/webgl2-target.d.ts.map +1 -0
  75. package/dist/webgl2-target.js +1368 -0
  76. package/dist/webgl2-target.js.map +1 -0
  77. package/dist/webgpu-detect.d.ts +30 -0
  78. package/dist/webgpu-detect.d.ts.map +1 -0
  79. package/dist/webgpu-detect.js +74 -0
  80. package/dist/webgpu-detect.js.map +1 -0
  81. package/package.json +67 -0
@@ -0,0 +1,46 @@
1
+ import { type Point } from "@oh-just-another/curve-mesh";
2
+ import type { Transform } from "@oh-just-another/types";
3
+ /**
4
+ * Loop-Blinn curve rendering for WebGL2Target. Owns the dedicated
5
+ * shader program (vertex (x, y, u, v, w) → fragment `(u² - v) * w`
6
+ * inside / outside test) and the buffer plumbing.
7
+ *
8
+ * Curves stay vector-perfect at any zoom (no facets at high zoom, no
9
+ * over-tessellated triangle counts at 1×), and packing all curve
10
+ * triangles into one buffer means one draw per `fill()` regardless of
11
+ * curve count.
12
+ *
13
+ * A curve triangle covers the convex hull of the three control points,
14
+ * and the fragment test discards the side that lies outside the
15
+ * parabola. So a curve that bulges outward from the polygon needs its
16
+ * triangle added on top of the polygon fill; a curve bulging inward
17
+ * needs the triangle subtracted. The sign field `w` in each vertex's UV
18
+ * encodes which side to keep.
19
+ */
20
+ export interface CurveSegment {
21
+ readonly kind: "q" | "c";
22
+ readonly points: readonly Point[];
23
+ }
24
+ export declare class LoopBlinnCurvePipeline {
25
+ private readonly gl;
26
+ private readonly program;
27
+ private readonly vbo;
28
+ private readonly uvBuf;
29
+ private readonly uTransform;
30
+ private readonly uColor;
31
+ private readonly uOpacity;
32
+ private readonly aPos;
33
+ private readonly aUVW;
34
+ constructor(gl: WebGL2RenderingContext);
35
+ /**
36
+ * Triangulate every segment in `curves`, batch the triangles into one
37
+ * draw, and emit them through the Loop-Blinn fragment test. No-op when
38
+ * `curves` is empty.
39
+ */
40
+ draw(curves: readonly CurveSegment[], color: readonly [number, number, number], opacity: number, transform: Transform, surfaceSize: {
41
+ width: number;
42
+ height: number;
43
+ }): void;
44
+ dispose(): void;
45
+ }
46
+ //# sourceMappingURL=webgl2-curve.d.ts.map
@@ -0,0 +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,CAAuB;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuB;IAChD,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"}
@@ -0,0 +1,162 @@
1
+ import { cubicToTriangles, packCurveTriangles, quadraticToTriangle, } from "@oh-just-another/curve-mesh";
2
+ export class LoopBlinnCurvePipeline {
3
+ gl;
4
+ program;
5
+ vbo;
6
+ uvBuf;
7
+ uTransform;
8
+ uColor;
9
+ uOpacity;
10
+ aPos;
11
+ aUVW;
12
+ constructor(gl) {
13
+ 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);
17
+ this.vbo = glReq(gl.createBuffer());
18
+ this.uvBuf = glReq(gl.createBuffer());
19
+ this.aPos = gl.getAttribLocation(this.program, "aPos");
20
+ this.aUVW = gl.getAttribLocation(this.program, "aUVW");
21
+ this.uTransform = glReq(gl.getUniformLocation(this.program, "uTransform"));
22
+ this.uColor = glReq(gl.getUniformLocation(this.program, "uColor"));
23
+ this.uOpacity = glReq(gl.getUniformLocation(this.program, "uOpacity"));
24
+ }
25
+ /**
26
+ * Triangulate every segment in `curves`, batch the triangles into one
27
+ * draw, and emit them through the Loop-Blinn fragment test. No-op when
28
+ * `curves` is empty.
29
+ */
30
+ draw(curves, color, opacity, transform, surfaceSize) {
31
+ if (curves.length === 0 || opacity <= 0)
32
+ 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)
52
+ return;
53
+ const { positions, uvs } = packCurveTriangles(triangles);
54
+ const gl = this.gl;
55
+ gl.useProgram(this.program);
56
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
57
+ gl.bufferData(gl.ARRAY_BUFFER, positions, gl.DYNAMIC_DRAW);
58
+ gl.enableVertexAttribArray(this.aPos);
59
+ gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, 0, 0);
60
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.uvBuf);
61
+ gl.bufferData(gl.ARRAY_BUFFER, uvs, gl.DYNAMIC_DRAW);
62
+ gl.enableVertexAttribArray(this.aUVW);
63
+ gl.vertexAttribPointer(this.aUVW, 3, gl.FLOAT, false, 0, 0);
64
+ gl.uniformMatrix3fv(this.uTransform, false, affineToClipMat3(transform, surfaceSize.width, surfaceSize.height));
65
+ gl.uniform3f(this.uColor, color[0], color[1], color[2]);
66
+ gl.uniform1f(this.uOpacity, opacity);
67
+ gl.drawArrays(gl.TRIANGLES, 0, positions.length / 2);
68
+ }
69
+ dispose() {
70
+ this.gl.deleteBuffer(this.vbo);
71
+ this.gl.deleteBuffer(this.uvBuf);
72
+ this.gl.deleteProgram(this.program);
73
+ }
74
+ }
75
+ const affineToClipMat3 = (t, w, h) => {
76
+ const sx = 2 / w;
77
+ const sy = -2 / h;
78
+ return new Float32Array([
79
+ t.a * sx, t.b * sy, 0,
80
+ t.c * sx, t.d * sy, 0,
81
+ t.e * sx - 1, t.f * sy + 1, 1,
82
+ ]);
83
+ };
84
+ /**
85
+ * Vertex shader passes through the Loop-Blinn (u, v, w) coordinates as
86
+ * a varying; the fragment shader runs the inside / outside test.
87
+ */
88
+ const VERTEX_SRC = `#version 300 es
89
+ in vec2 aPos;
90
+ in vec3 aUVW;
91
+ uniform mat3 uTransform;
92
+ out vec3 vUVW;
93
+ void main() {
94
+ vec3 p = uTransform * vec3(aPos, 1.0);
95
+ gl_Position = vec4(p.xy, 0.0, 1.0);
96
+ vUVW = aUVW;
97
+ }`;
98
+ /**
99
+ * Loop-Blinn implicit Bezier test:
100
+ * procedural = u² - v
101
+ * discard if `procedural * w > 0` — `w` encodes which side of the
102
+ * parabola is the "filled" region. `fwidth(procedural)` gives the
103
+ * screen-pixel derivative used to feather the edge for AA.
104
+ */
105
+ const FRAGMENT_SRC = `#version 300 es
106
+ precision mediump float;
107
+ uniform vec3 uColor;
108
+ uniform float uOpacity;
109
+ in vec3 vUVW;
110
+ out vec4 fragColor;
111
+
112
+ void main() {
113
+ float u = vUVW.x;
114
+ float v = vUVW.y;
115
+ float w = vUVW.z;
116
+ float p = u * u - v;
117
+ float dp = fwidth(p);
118
+ // Signed distance to the curve in procedural units; multiplied by w
119
+ // so the "outside" side discards regardless of curve orientation.
120
+ // smoothstep antialiases the edge over one screen pixel of
121
+ // procedural-space.
122
+ float coverage = smoothstep(dp, -dp, p * w);
123
+ if (coverage <= 0.0) discard;
124
+ // Premultiplied output to match the context's premultipliedAlpha
125
+ // contract + blendFunc(ONE, 1-SRC_ALPHA).
126
+ float a = coverage * uOpacity;
127
+ fragColor = vec4(uColor * a, a);
128
+ }`;
129
+ /**
130
+ * Asserts a WebGL resource handle is non-null. `gl.createBuffer` /
131
+ * `getUniformLocation` / `createShader` are typed non-null but return
132
+ * `null` on context loss; this surfaces that as a throw.
133
+ */
134
+ const glReq = (v) => {
135
+ if (v === null)
136
+ throw new Error("packages/renderer-canvas: WebGL resource creation failed");
137
+ return v;
138
+ };
139
+ const compile = (gl, type, src) => {
140
+ const sh = glReq(gl.createShader(type));
141
+ gl.shaderSource(sh, src);
142
+ gl.compileShader(sh);
143
+ if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
144
+ const log = gl.getShaderInfoLog(sh);
145
+ gl.deleteShader(sh);
146
+ throw new Error(`Loop-Blinn shader compile failed: ${log}`);
147
+ }
148
+ return sh;
149
+ };
150
+ const link = (gl, vert, frag) => {
151
+ const program = gl.createProgram();
152
+ gl.attachShader(program, vert);
153
+ gl.attachShader(program, frag);
154
+ gl.linkProgram(program);
155
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
156
+ const log = gl.getProgramInfoLog(program);
157
+ gl.deleteProgram(program);
158
+ throw new Error(`Loop-Blinn program link failed: ${log}`);
159
+ }
160
+ return program;
161
+ };
162
+ //# sourceMappingURL=webgl2-curve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webgl2-curve.js","sourceRoot":"","sources":["../src/webgl2-curve.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
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
+ export declare class EllipsePipeline {
30
+ private readonly gl;
31
+ private readonly program;
32
+ private readonly vbo;
33
+ private readonly aPos;
34
+ private readonly aLocal;
35
+ private readonly uTransform;
36
+ private readonly uColor;
37
+ private readonly uOpacity;
38
+ constructor(gl: WebGL2RenderingContext);
39
+ /**
40
+ * Draw a filled ellipse. `cx, cy` — centre in caller's coordinate
41
+ * system. `rx, ry` — radii. The caller's affine `transform` combines
42
+ * with the unit-square → bbox mapping into a single uniform matrix.
43
+ *
44
+ * Degenerate cases (`rx ≤ 0`, `ry ≤ 0`, `opacity ≤ 0`) early-return.
45
+ */
46
+ draw(cx: number, cy: number, rx: number, ry: number, color: readonly [number, number, number], opacity: number, transform: Transform, surfaceSize: {
47
+ width: number;
48
+ height: number;
49
+ }): void;
50
+ dispose(): void;
51
+ }
52
+ //# sourceMappingURL=webgl2-ellipse.d.ts.map
@@ -0,0 +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,CAAuB;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuB;gBAEnB,EAAE,EAAE,sBAAsB;IAwBvD;;;;;;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;IAmCP,OAAO,IAAI,IAAI;CAIhB"}
@@ -0,0 +1,171 @@
1
+ /**
2
+ * Fragment-shader SDF ellipse pipeline for `WebGL2Target`. Renders an
3
+ * ellipse as a single textured quad (4 vertices, 2 triangles)
4
+ * regardless of radius — the fragment shader does an inside/outside
5
+ * test against the unit circle in normalised local coordinates.
6
+ *
7
+ * Vertex layout (static, interleaved):
8
+ * aPos aLocal
9
+ * 0,0 -1,-1
10
+ * 1,0 1,-1
11
+ * 0,1 -1, 1
12
+ * 1,1 1, 1
13
+ *
14
+ * `uTransform` maps `aPos` (unit square [0,1]²) through:
15
+ * 1. scale to ellipse bbox (2*rx, 2*ry)
16
+ * 2. translate to (cx-rx, cy-ry)
17
+ * 3. apply caller's world→screen affine
18
+ * 4. pixel→clip-space (NDC)
19
+ *
20
+ * The fragment shader gets `vLocal` interpolated across the quad:
21
+ * inside the ellipse → dot(vLocal, vLocal) < 1
22
+ * on the boundary → dot(vLocal, vLocal) = 1
23
+ * outside → dot(vLocal, vLocal) > 1
24
+ *
25
+ * `smoothstep(1+fwidth, 1-fwidth, r²)` gives sub-pixel AA at the
26
+ * boundary independent of zoom.
27
+ */
28
+ export class EllipsePipeline {
29
+ gl;
30
+ program;
31
+ vbo;
32
+ aPos;
33
+ aLocal;
34
+ uTransform;
35
+ uColor;
36
+ uOpacity;
37
+ constructor(gl) {
38
+ 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);
42
+ this.aPos = gl.getAttribLocation(this.program, "aPos");
43
+ this.aLocal = gl.getAttribLocation(this.program, "aLocal");
44
+ this.uTransform = glReq(gl.getUniformLocation(this.program, "uTransform"));
45
+ this.uColor = glReq(gl.getUniformLocation(this.program, "uColor"));
46
+ this.uOpacity = glReq(gl.getUniformLocation(this.program, "uOpacity"));
47
+ // Static interleaved buffer — never re-uploaded.
48
+ this.vbo = glReq(gl.createBuffer());
49
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
50
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
51
+ 0, 0, -1, -1,
52
+ 1, 0, 1, -1,
53
+ 0, 1, -1, 1,
54
+ 1, 1, 1, 1,
55
+ ]), gl.STATIC_DRAW);
56
+ }
57
+ /**
58
+ * Draw a filled ellipse. `cx, cy` — centre in caller's coordinate
59
+ * system. `rx, ry` — radii. The caller's affine `transform` combines
60
+ * with the unit-square → bbox mapping into a single uniform matrix.
61
+ *
62
+ * Degenerate cases (`rx ≤ 0`, `ry ≤ 0`, `opacity ≤ 0`) early-return.
63
+ */
64
+ draw(cx, cy, rx, ry, color, opacity, transform, surfaceSize) {
65
+ if (opacity <= 0 || rx <= 0 || ry <= 0)
66
+ return;
67
+ const gl = this.gl;
68
+ gl.useProgram(this.program);
69
+ gl.bindBuffer(gl.ARRAY_BUFFER, this.vbo);
70
+ gl.enableVertexAttribArray(this.aPos);
71
+ gl.vertexAttribPointer(this.aPos, 2, gl.FLOAT, false, 16, 0);
72
+ gl.enableVertexAttribArray(this.aLocal);
73
+ gl.vertexAttribPointer(this.aLocal, 2, gl.FLOAT, false, 16, 8);
74
+ const w = 2 * rx;
75
+ const h = 2 * ry;
76
+ const left = cx - rx;
77
+ const top = cy - ry;
78
+ const sx = 2 / surfaceSize.width;
79
+ const sy = -2 / surfaceSize.height;
80
+ // Combined matrix: (aPos.x, aPos.y) ∈ [0,1]² → clip-space NDC.
81
+ // Steps folded into one column-major mat3:
82
+ // scaleSq = (aPos.x * w, aPos.y * h)
83
+ // inWorld = transform · (scaleSq + (left, top))
84
+ // inClip = pixel→clip(inWorld)
85
+ const t = transform;
86
+ const mat = new Float32Array([
87
+ t.a * w * sx, t.b * w * sy, 0,
88
+ t.c * h * sx, t.d * h * sy, 0,
89
+ (t.a * left + t.c * top + t.e) * sx - 1,
90
+ (t.b * left + t.d * top + t.f) * sy + 1,
91
+ 1,
92
+ ]);
93
+ gl.uniformMatrix3fv(this.uTransform, false, mat);
94
+ gl.uniform3f(this.uColor, color[0], color[1], color[2]);
95
+ gl.uniform1f(this.uOpacity, opacity);
96
+ gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
97
+ }
98
+ dispose() {
99
+ this.gl.deleteBuffer(this.vbo);
100
+ this.gl.deleteProgram(this.program);
101
+ }
102
+ }
103
+ const VERTEX_SRC = `#version 300 es
104
+ in vec2 aPos;
105
+ in vec2 aLocal;
106
+ uniform mat3 uTransform;
107
+ out vec2 vLocal;
108
+ void main() {
109
+ vec3 p = uTransform * vec3(aPos, 1.0);
110
+ gl_Position = vec4(p.xy, 0.0, 1.0);
111
+ vLocal = aLocal;
112
+ }`;
113
+ /**
114
+ * SDF circle test in normalised local space (-1..1 over ellipse bbox).
115
+ * r² = dot(vLocal, vLocal) — squared distance from centre.
116
+ * Inside circle: r² < 1. Outside: r² > 1. Boundary: r² = 1.
117
+ *
118
+ * `fwidth(r²)` gives the screen-space rate of change of r²; it sets the
119
+ * smoothstep width so the boundary stays a 1-screen-pixel band
120
+ * regardless of zoom.
121
+ *
122
+ * Output premultiplied (rgb·a, a) to match the context's
123
+ * `premultipliedAlpha: true` + `blendFunc(ONE, 1 - SRC_ALPHA)`.
124
+ */
125
+ const FRAGMENT_SRC = `#version 300 es
126
+ precision mediump float;
127
+ uniform vec3 uColor;
128
+ uniform float uOpacity;
129
+ in vec2 vLocal;
130
+ out vec4 fragColor;
131
+ void main() {
132
+ float r2 = dot(vLocal, vLocal);
133
+ float dr = fwidth(r2);
134
+ float coverage = smoothstep(1.0 + dr, 1.0 - dr, r2);
135
+ if (coverage <= 0.0) discard;
136
+ float a = coverage * uOpacity;
137
+ fragColor = vec4(uColor * a, a);
138
+ }`;
139
+ /**
140
+ * Asserts a WebGL resource handle is non-null. Creation APIs are typed
141
+ * non-null but return `null` on context loss; surface that as a throw.
142
+ */
143
+ const glReq = (v) => {
144
+ if (v === null)
145
+ throw new Error("packages/renderer-canvas: WebGL resource creation failed");
146
+ return v;
147
+ };
148
+ const compile = (gl, type, src) => {
149
+ const sh = glReq(gl.createShader(type));
150
+ gl.shaderSource(sh, src);
151
+ gl.compileShader(sh);
152
+ if (!gl.getShaderParameter(sh, gl.COMPILE_STATUS)) {
153
+ const log = gl.getShaderInfoLog(sh);
154
+ gl.deleteShader(sh);
155
+ throw new Error(`Ellipse shader compile failed: ${log}`);
156
+ }
157
+ return sh;
158
+ };
159
+ const link = (gl, vert, frag) => {
160
+ const program = gl.createProgram();
161
+ gl.attachShader(program, vert);
162
+ gl.attachShader(program, frag);
163
+ gl.linkProgram(program);
164
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
165
+ const log = gl.getProgramInfoLog(program);
166
+ gl.deleteProgram(program);
167
+ throw new Error(`Ellipse program link failed: ${log}`);
168
+ }
169
+ return program;
170
+ };
171
+ //# sourceMappingURL=webgl2-ellipse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webgl2-ellipse.js","sourceRoot":"","sources":["../src/webgl2-ellipse.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,84 @@
1
+ import type { AtlasGlyph, GlyphAtlas } from "@oh-just-another/glyph-atlas";
2
+ import type { Transform } from "@oh-just-another/types";
3
+ /**
4
+ * MSDF text-rendering glue for WebGL2Target. Owns the dedicated shader
5
+ * program (vertex quad + median3 + smoothstep AA fragment), a reusable
6
+ * VBO, and the per-frame batching logic.
7
+ *
8
+ * The MSDF pipeline has its own shader, uniforms and vertex layout that
9
+ * share nothing with the solid / stroke / image programs, so it lives
10
+ * in its own module and is independently testable.
11
+ *
12
+ * One instance per WebGL2 context. `dispose()` releases the program and
13
+ * VBO.
14
+ */
15
+ export interface Msdf2DTextStyle {
16
+ /** Premultiplied alpha 0..1. */
17
+ readonly opacity: number;
18
+ /** Fill colour as normalised RGB (0..1 per channel). */
19
+ readonly color: readonly [number, number, number];
20
+ /** Current world→screen affine. */
21
+ readonly transform: Transform;
22
+ }
23
+ export declare class MsdfTextPipeline {
24
+ private readonly gl;
25
+ private readonly program;
26
+ private readonly vbo;
27
+ private readonly uTransform;
28
+ private readonly uColor;
29
+ private readonly uOpacity;
30
+ private readonly uAtlasSize;
31
+ private readonly uPxRange;
32
+ private readonly uAtlas;
33
+ private readonly aPos;
34
+ private readonly aUV;
35
+ constructor(gl: WebGL2RenderingContext);
36
+ /**
37
+ * Build per-glyph quads for `text` starting at the cursor position
38
+ * `(x, y)` in world coordinates (top-left baseline convention —
39
+ * caller adjusts for textAlign / textBaseline upstream).
40
+ *
41
+ * Returns the screen-width of the rendered string in world units so
42
+ * callers can chain text or compute hit-test boxes. Returns 0 if the
43
+ * atlas couldn't bake one of the glyphs (atlas full) — the partial
44
+ * draw still lands.
45
+ */
46
+ drawText(text: string, x: number, y: number, fontSize: number, atlas: GlyphAtlas, style: Msdf2DTextStyle, surfaceSize: {
47
+ width: number;
48
+ height: number;
49
+ },
50
+ /**
51
+ * Horizontal alignment factor: 0 = left (cursor at `x`), 0.5 =
52
+ * centre, 1 = right. Applied as a single world-space x shift after
53
+ * measuring the run, so there's no separate width-measuring walk
54
+ * over the atlas.
55
+ */
56
+ alignFactor?: number,
57
+ /** Embedded font id (0=sans, 1=serif, 2=mono); selects atlas glyphs. */
58
+ fontId?: number): number;
59
+ dispose(): void;
60
+ }
61
+ /**
62
+ * Pure-math helper: compute the screen-space rect + atlas UV rect for
63
+ * one glyph. Exported so tests can verify the geometry without booting
64
+ * a real WebGL2 context.
65
+ *
66
+ * Returns `{ left, top, right, bottom, u0, v0, u1, v1 }` in screen
67
+ * pixels / normalised UVs. Caller packs the six vertices into a vertex
68
+ * buffer.
69
+ */
70
+ export declare const glyphQuadGeometry: (g: AtlasGlyph, cursorX: number, cursorY: number, fontSize: number, atlas: {
71
+ atlasSize: number;
72
+ tileSize: number;
73
+ range: number;
74
+ }) => {
75
+ left: number;
76
+ top: number;
77
+ right: number;
78
+ bottom: number;
79
+ u0: number;
80
+ v0: number;
81
+ u1: number;
82
+ v1: number;
83
+ };
84
+ //# sourceMappingURL=webgl2-msdf-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webgl2-msdf-text.d.ts","sourceRoot":"","sources":["../src/webgl2-msdf-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,eAAe;IAC9B,gCAAgC;IAChC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAClD,mCAAmC;IACnC,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;CAC/B;AAED,qBAAa,gBAAgB;IAYf,OAAO,CAAC,QAAQ,CAAC,EAAE;IAX/B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IACvC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuB;IAChD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAuB;IAClD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAuB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;IAC9C,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;gBAEA,EAAE,EAAE,sBAAsB;IAevD;;;;;;;;;OASG;IACH,QAAQ,CACN,IAAI,EAAE,MAAM,EACZ,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,UAAU,EACjB,KAAK,EAAE,eAAe,EACtB,WAAW,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE;IAC9C;;;;;OAKG;IACH,WAAW,SAAI;IACf,wEAAwE;IACxE,MAAM,SAAI,GACT,MAAM;IAmET,OAAO,IAAI,IAAI;CAIhB;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,GAC5B,GAAG,UAAU,EACb,SAAS,MAAM,EACf,SAAS,MAAM,EACf,UAAU,MAAM,EAChB,OAAO;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,KAC5D;IACD,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,MAAM,CAAC;CA2CZ,CAAC"}