@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.
- package/CHANGELOG.md +18 -0
- package/LICENSE +21 -0
- package/README.md +36 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/canvas-target.d.ts +83 -0
- package/dist/canvas-target.d.ts.map +1 -0
- package/dist/canvas-target.js +208 -0
- package/dist/canvas-target.js.map +1 -0
- package/dist/canvas-text-shaper.d.ts +11 -0
- package/dist/canvas-text-shaper.d.ts.map +1 -0
- package/dist/canvas-text-shaper.js +56 -0
- package/dist/canvas-text-shaper.js.map +1 -0
- package/dist/constants.d.ts +52 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +52 -0
- package/dist/constants.js.map +1 -0
- package/dist/hi-dpi.d.ts +26 -0
- package/dist/hi-dpi.d.ts.map +1 -0
- package/dist/hi-dpi.js +62 -0
- package/dist/hi-dpi.js.map +1 -0
- package/dist/image-source.d.ts +3 -0
- package/dist/image-source.d.ts.map +1 -0
- package/dist/image-source.js +65 -0
- package/dist/image-source.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/layered-canvas.d.ts +46 -0
- package/dist/layered-canvas.d.ts.map +1 -0
- package/dist/layered-canvas.js +95 -0
- package/dist/layered-canvas.js.map +1 -0
- package/dist/layered-surface.d.ts +75 -0
- package/dist/layered-surface.d.ts.map +1 -0
- package/dist/layered-surface.js +262 -0
- package/dist/layered-surface.js.map +1 -0
- package/dist/offscreen.d.ts +30 -0
- package/dist/offscreen.d.ts.map +1 -0
- package/dist/offscreen.js +50 -0
- package/dist/offscreen.js.map +1 -0
- package/dist/recording-target.d.ts +203 -0
- package/dist/recording-target.d.ts.map +1 -0
- package/dist/recording-target.js +260 -0
- package/dist/recording-target.js.map +1 -0
- package/dist/render-worker.d.ts +2 -0
- package/dist/render-worker.d.ts.map +1 -0
- package/dist/render-worker.js +112 -0
- package/dist/render-worker.js.map +1 -0
- package/dist/tile-compositor.d.ts +44 -0
- package/dist/tile-compositor.d.ts.map +1 -0
- package/dist/tile-compositor.js +110 -0
- package/dist/tile-compositor.js.map +1 -0
- package/dist/webgl2-color.d.ts +13 -0
- package/dist/webgl2-color.d.ts.map +1 -0
- package/dist/webgl2-color.js +26 -0
- package/dist/webgl2-color.js.map +1 -0
- package/dist/webgl2-curve.d.ts +46 -0
- package/dist/webgl2-curve.d.ts.map +1 -0
- package/dist/webgl2-curve.js +162 -0
- package/dist/webgl2-curve.js.map +1 -0
- package/dist/webgl2-ellipse.d.ts +52 -0
- package/dist/webgl2-ellipse.d.ts.map +1 -0
- package/dist/webgl2-ellipse.js +171 -0
- package/dist/webgl2-ellipse.js.map +1 -0
- package/dist/webgl2-msdf-text.d.ts +84 -0
- package/dist/webgl2-msdf-text.d.ts.map +1 -0
- package/dist/webgl2-msdf-text.js +306 -0
- package/dist/webgl2-msdf-text.js.map +1 -0
- package/dist/webgl2-stroke.d.ts +52 -0
- package/dist/webgl2-stroke.d.ts.map +1 -0
- package/dist/webgl2-stroke.js +318 -0
- package/dist/webgl2-stroke.js.map +1 -0
- package/dist/webgl2-target.d.ts +311 -0
- package/dist/webgl2-target.d.ts.map +1 -0
- package/dist/webgl2-target.js +1368 -0
- package/dist/webgl2-target.js.map +1 -0
- package/dist/webgpu-detect.d.ts +30 -0
- package/dist/webgpu-detect.d.ts.map +1 -0
- package/dist/webgpu-detect.js +74 -0
- package/dist/webgpu-detect.js.map +1 -0
- package/package.json +67 -0
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `drawImage` is NOT serialisable through this command stream — image
|
|
3
|
+
* sources (HTMLImageElement, ImageBitmap, HTMLCanvasElement) either
|
|
4
|
+
* can't cross the postMessage boundary cleanly or require expensive
|
|
5
|
+
* transfers. The recording target silently skips `drawImage` calls and
|
|
6
|
+
* counts them in `skippedImageDraws` so the host UI can warn (or fall
|
|
7
|
+
* back to main-thread compositing for image-heavy scenes).
|
|
8
|
+
*
|
|
9
|
+
* `measureText` returns a synchronous heuristic — the worker has the
|
|
10
|
+
* authoritative measurement, but routing per-call is too chatty. Hosts
|
|
11
|
+
* that care about pixel-perfect text in offscreen mode should
|
|
12
|
+
* pre-measure on a sidecar text shaper.
|
|
13
|
+
*/
|
|
14
|
+
export class RecordingTarget {
|
|
15
|
+
commands = [];
|
|
16
|
+
_width;
|
|
17
|
+
_height;
|
|
18
|
+
/** Counter so hosts can warn when images are silently skipped. */
|
|
19
|
+
skippedImageDraws = 0;
|
|
20
|
+
constructor(width, height) {
|
|
21
|
+
this._width = width;
|
|
22
|
+
this._height = height;
|
|
23
|
+
}
|
|
24
|
+
get size() {
|
|
25
|
+
return { width: this._width, height: this._height };
|
|
26
|
+
}
|
|
27
|
+
resize(width, height) {
|
|
28
|
+
this._width = width;
|
|
29
|
+
this._height = height;
|
|
30
|
+
this.commands.push({ k: "resize", w: width, h: height });
|
|
31
|
+
}
|
|
32
|
+
/** Pop the buffered commands and clear the internal log. */
|
|
33
|
+
flush() {
|
|
34
|
+
const out = this.commands;
|
|
35
|
+
this.commands = [];
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
/** Snapshot of the buffered commands without clearing. */
|
|
39
|
+
peek() {
|
|
40
|
+
return this.commands;
|
|
41
|
+
}
|
|
42
|
+
setFill(color) {
|
|
43
|
+
this.commands.push({ k: "setFill", color });
|
|
44
|
+
}
|
|
45
|
+
setStroke(color) {
|
|
46
|
+
this.commands.push({ k: "setStroke", color });
|
|
47
|
+
}
|
|
48
|
+
setStrokeWidth(w) {
|
|
49
|
+
this.commands.push({ k: "setStrokeWidth", w });
|
|
50
|
+
}
|
|
51
|
+
setOpacity(a) {
|
|
52
|
+
this.commands.push({ k: "setOpacity", a });
|
|
53
|
+
}
|
|
54
|
+
setLineCap(cap) {
|
|
55
|
+
this.commands.push({ k: "setLineCap", cap });
|
|
56
|
+
}
|
|
57
|
+
setLineJoin(join) {
|
|
58
|
+
this.commands.push({ k: "setLineJoin", join });
|
|
59
|
+
}
|
|
60
|
+
setDashArray(dash) {
|
|
61
|
+
this.commands.push({ k: "setDashArray", dash });
|
|
62
|
+
}
|
|
63
|
+
setFont(family, size, options) {
|
|
64
|
+
this.commands.push({ k: "setFont", family, size, ...(options ? { options } : {}) });
|
|
65
|
+
}
|
|
66
|
+
setTextAlign(align) {
|
|
67
|
+
this.commands.push({ k: "setTextAlign", align });
|
|
68
|
+
}
|
|
69
|
+
setTextBaseline(baseline) {
|
|
70
|
+
this.commands.push({ k: "setTextBaseline", baseline });
|
|
71
|
+
}
|
|
72
|
+
save() {
|
|
73
|
+
this.commands.push({ k: "save" });
|
|
74
|
+
}
|
|
75
|
+
restore() {
|
|
76
|
+
this.commands.push({ k: "restore" });
|
|
77
|
+
}
|
|
78
|
+
translate(x, y) {
|
|
79
|
+
this.commands.push({ k: "translate", x, y });
|
|
80
|
+
}
|
|
81
|
+
rotate(r) {
|
|
82
|
+
this.commands.push({ k: "rotate", r });
|
|
83
|
+
}
|
|
84
|
+
scale(sx, sy) {
|
|
85
|
+
this.commands.push({ k: "scale", sx, sy });
|
|
86
|
+
}
|
|
87
|
+
setTransform(t) {
|
|
88
|
+
this.commands.push({ k: "setTransform", t });
|
|
89
|
+
}
|
|
90
|
+
resetTransform() {
|
|
91
|
+
this.commands.push({ k: "resetTransform" });
|
|
92
|
+
}
|
|
93
|
+
beginPath() {
|
|
94
|
+
this.commands.push({ k: "beginPath" });
|
|
95
|
+
}
|
|
96
|
+
closePath() {
|
|
97
|
+
this.commands.push({ k: "closePath" });
|
|
98
|
+
}
|
|
99
|
+
moveTo(x, y) {
|
|
100
|
+
this.commands.push({ k: "moveTo", x, y });
|
|
101
|
+
}
|
|
102
|
+
lineTo(x, y) {
|
|
103
|
+
this.commands.push({ k: "lineTo", x, y });
|
|
104
|
+
}
|
|
105
|
+
quadraticCurveTo(cx, cy, x, y) {
|
|
106
|
+
this.commands.push({ k: "quadraticCurveTo", cx, cy, x, y });
|
|
107
|
+
}
|
|
108
|
+
bezierCurveTo(c1x, c1y, c2x, c2y, x, y) {
|
|
109
|
+
this.commands.push({ k: "bezierCurveTo", c1x, c1y, c2x, c2y, x, y });
|
|
110
|
+
}
|
|
111
|
+
rect(x, y, w, h) {
|
|
112
|
+
this.commands.push({ k: "rect", x, y, w, h });
|
|
113
|
+
}
|
|
114
|
+
ellipse(cx, cy, rx, ry) {
|
|
115
|
+
this.commands.push({ k: "ellipse", cx, cy, rx, ry });
|
|
116
|
+
}
|
|
117
|
+
fill(rule) {
|
|
118
|
+
this.commands.push(rule !== undefined ? { k: "fill", rule } : { k: "fill" });
|
|
119
|
+
}
|
|
120
|
+
stroke() {
|
|
121
|
+
this.commands.push({ k: "stroke" });
|
|
122
|
+
}
|
|
123
|
+
fillText(text, x, y, maxWidth) {
|
|
124
|
+
this.commands.push(maxWidth !== undefined
|
|
125
|
+
? { k: "fillText", text, x, y, maxWidth }
|
|
126
|
+
: { k: "fillText", text, x, y });
|
|
127
|
+
}
|
|
128
|
+
measureText(text) {
|
|
129
|
+
// Heuristic — same factor as @text-wasm's fallback so layout stays
|
|
130
|
+
// roughly proportional. The Editor's text rendering path re-measures
|
|
131
|
+
// on the real Canvas2D in the main thread when it needs precise
|
|
132
|
+
// widths (label wrapping, hit-test).
|
|
133
|
+
return { width: text.length * 8 };
|
|
134
|
+
}
|
|
135
|
+
drawImage(_image, _dx, _dy, _dw, _dh) {
|
|
136
|
+
this.skippedImageDraws++;
|
|
137
|
+
}
|
|
138
|
+
clear(bounds) {
|
|
139
|
+
this.commands.push(bounds !== undefined ? { k: "clear", bounds } : { k: "clear" });
|
|
140
|
+
}
|
|
141
|
+
markDirty(bounds) {
|
|
142
|
+
this.commands.push({ k: "markDirty", bounds });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Replay a previously-flushed command buffer onto a real RenderTarget.
|
|
147
|
+
* Used by the worker entry point to apply commands shipped from the
|
|
148
|
+
* main thread.
|
|
149
|
+
*/
|
|
150
|
+
export const replayCommands = (target, commands) => {
|
|
151
|
+
for (const cmd of commands) {
|
|
152
|
+
switch (cmd.k) {
|
|
153
|
+
case "setFill":
|
|
154
|
+
target.setFill(cmd.color);
|
|
155
|
+
break;
|
|
156
|
+
case "setStroke":
|
|
157
|
+
target.setStroke(cmd.color);
|
|
158
|
+
break;
|
|
159
|
+
case "setStrokeWidth":
|
|
160
|
+
target.setStrokeWidth(cmd.w);
|
|
161
|
+
break;
|
|
162
|
+
case "setOpacity":
|
|
163
|
+
target.setOpacity(cmd.a);
|
|
164
|
+
break;
|
|
165
|
+
case "setLineCap":
|
|
166
|
+
target.setLineCap(cmd.cap);
|
|
167
|
+
break;
|
|
168
|
+
case "setLineJoin":
|
|
169
|
+
target.setLineJoin(cmd.join);
|
|
170
|
+
break;
|
|
171
|
+
case "setDashArray":
|
|
172
|
+
target.setDashArray(cmd.dash);
|
|
173
|
+
break;
|
|
174
|
+
case "setFont":
|
|
175
|
+
target.setFont(cmd.family, cmd.size, cmd.options);
|
|
176
|
+
break;
|
|
177
|
+
case "setTextAlign":
|
|
178
|
+
target.setTextAlign(cmd.align);
|
|
179
|
+
break;
|
|
180
|
+
case "setTextBaseline":
|
|
181
|
+
target.setTextBaseline(cmd.baseline);
|
|
182
|
+
break;
|
|
183
|
+
case "save":
|
|
184
|
+
target.save();
|
|
185
|
+
break;
|
|
186
|
+
case "restore":
|
|
187
|
+
target.restore();
|
|
188
|
+
break;
|
|
189
|
+
case "translate":
|
|
190
|
+
target.translate(cmd.x, cmd.y);
|
|
191
|
+
break;
|
|
192
|
+
case "rotate":
|
|
193
|
+
target.rotate(cmd.r);
|
|
194
|
+
break;
|
|
195
|
+
case "scale":
|
|
196
|
+
target.scale(cmd.sx, cmd.sy);
|
|
197
|
+
break;
|
|
198
|
+
case "setTransform":
|
|
199
|
+
target.setTransform(cmd.t);
|
|
200
|
+
break;
|
|
201
|
+
case "resetTransform":
|
|
202
|
+
target.resetTransform();
|
|
203
|
+
break;
|
|
204
|
+
case "beginPath":
|
|
205
|
+
target.beginPath();
|
|
206
|
+
break;
|
|
207
|
+
case "closePath":
|
|
208
|
+
target.closePath();
|
|
209
|
+
break;
|
|
210
|
+
case "moveTo":
|
|
211
|
+
target.moveTo(cmd.x, cmd.y);
|
|
212
|
+
break;
|
|
213
|
+
case "lineTo":
|
|
214
|
+
target.lineTo(cmd.x, cmd.y);
|
|
215
|
+
break;
|
|
216
|
+
case "quadraticCurveTo":
|
|
217
|
+
target.quadraticCurveTo(cmd.cx, cmd.cy, cmd.x, cmd.y);
|
|
218
|
+
break;
|
|
219
|
+
case "bezierCurveTo":
|
|
220
|
+
target.bezierCurveTo(cmd.c1x, cmd.c1y, cmd.c2x, cmd.c2y, cmd.x, cmd.y);
|
|
221
|
+
break;
|
|
222
|
+
case "rect":
|
|
223
|
+
target.rect(cmd.x, cmd.y, cmd.w, cmd.h);
|
|
224
|
+
break;
|
|
225
|
+
case "ellipse":
|
|
226
|
+
target.ellipse(cmd.cx, cmd.cy, cmd.rx, cmd.ry);
|
|
227
|
+
break;
|
|
228
|
+
case "fill":
|
|
229
|
+
if (cmd.rule !== undefined)
|
|
230
|
+
target.fill(cmd.rule);
|
|
231
|
+
else
|
|
232
|
+
target.fill();
|
|
233
|
+
break;
|
|
234
|
+
case "stroke":
|
|
235
|
+
target.stroke();
|
|
236
|
+
break;
|
|
237
|
+
case "fillText":
|
|
238
|
+
if (cmd.maxWidth !== undefined)
|
|
239
|
+
target.fillText(cmd.text, cmd.x, cmd.y, cmd.maxWidth);
|
|
240
|
+
else
|
|
241
|
+
target.fillText(cmd.text, cmd.x, cmd.y);
|
|
242
|
+
break;
|
|
243
|
+
case "clear":
|
|
244
|
+
if (cmd.bounds !== undefined)
|
|
245
|
+
target.clear(cmd.bounds);
|
|
246
|
+
else
|
|
247
|
+
target.clear();
|
|
248
|
+
break;
|
|
249
|
+
case "markDirty":
|
|
250
|
+
target.markDirty?.(cmd.bounds);
|
|
251
|
+
break;
|
|
252
|
+
case "resize":
|
|
253
|
+
// No-op for replay — the worker owns the canvas size and
|
|
254
|
+
// resizes via its own `resize` message, not via the command
|
|
255
|
+
// stream.
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
//# sourceMappingURL=recording-target.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"recording-target.js","sourceRoot":"","sources":["../src/recording-target.ts"],"names":[],"mappings":"AAiFA;;;;;;;;;;;;GAYG;AACH,MAAM,OAAO,eAAe;IAClB,QAAQ,GAAoB,EAAE,CAAC;IAC/B,MAAM,CAAS;IACf,OAAO,CAAS;IACxB,kEAAkE;IAClE,iBAAiB,GAAG,CAAC,CAAC;IAEtB,YAAY,KAAa,EAAE,MAAc;QACvC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IAED,IAAI,IAAI;QACN,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;IACtD,CAAC;IAED,MAAM,CAAC,KAAa,EAAE,MAAc;QAClC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3D,CAAC;IAED,4DAA4D;IAC5D,KAAK;QACH,MAAM,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,EAAE,CAAC;QACnB,OAAO,GAAG,CAAC;IACb,CAAC;IAED,0DAA0D;IAC1D,IAAI;QACF,OAAO,IAAI,CAAC,QAAQ,CAAC;IACvB,CAAC;IAED,OAAO,CAAC,KAAmB;QACzB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;IAC9C,CAAC;IACD,SAAS,CAAC,KAAmB;QAC3B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,CAAC;IAChD,CAAC;IACD,cAAc,CAAC,CAAS;QACtB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,EAAE,CAAC,CAAC;IACjD,CAAC;IACD,UAAU,CAAC,CAAS;QAClB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,YAAY,EAAE,CAAC,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,UAAU,CAAC,GAAY;QACrB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC;IAC/C,CAAC;IACD,WAAW,CAAC,IAAc;QACxB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;IACD,YAAY,CAAC,IAA8B;QACzC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,cAAc,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,CACL,MAAc,EACd,IAAY,EACZ,OAAqE;QAErE,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACtF,CAAC;IACD,YAAY,CAAC,KAAgB;QAC3B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAC;IACnD,CAAC;IACD,eAAe,CAAC,QAAsB;QACpC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,IAAI;QACF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IACpC,CAAC;IACD,OAAO;QACL,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC;IACvC,CAAC;IAED,SAAS,CAAC,CAAS,EAAE,CAAS;QAC5B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC;IACD,MAAM,CAAC,CAAS;QACd,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC;IACD,KAAK,CAAC,EAAU,EAAE,EAAU;QAC1B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IAC7C,CAAC;IACD,YAAY,CAAC,CAAY;QACvB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC;IACD,cAAc;QACZ,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,gBAAgB,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,SAAS;QACP,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC;IACzC,CAAC;IACD,SAAS;QACP,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC;IACzC,CAAC;IACD,MAAM,CAAC,CAAS,EAAE,CAAS;QACzB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,MAAM,CAAC,CAAS,EAAE,CAAS;QACzB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC5C,CAAC;IACD,gBAAgB,CAAC,EAAU,EAAE,EAAU,EAAE,CAAS,EAAE,CAAS;QAC3D,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,kBAAkB,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,aAAa,CAAC,GAAW,EAAE,GAAW,EAAE,GAAW,EAAE,GAAW,EAAE,CAAS,EAAE,CAAS;QACpF,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,eAAe,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACvE,CAAC;IACD,IAAI,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS,EAAE,CAAS;QAC7C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,CAAC,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU;QACpD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;IACvD,CAAC;IAED,IAAI,CAAC,IAAe;QAClB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/E,CAAC;IACD,MAAM;QACJ,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtC,CAAC;IAED,QAAQ,CAAC,IAAY,EAAE,CAAS,EAAE,CAAS,EAAE,QAAiB;QAC5D,IAAI,CAAC,QAAQ,CAAC,IAAI,CAChB,QAAQ,KAAK,SAAS;YACpB,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,QAAQ,EAAE;YACzC,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAClC,CAAC;IACJ,CAAC;IACD,WAAW,CAAC,IAAY;QACtB,mEAAmE;QACnE,qEAAqE;QACrE,gEAAgE;QAChE,qCAAqC;QACrC,OAAO,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;IACpC,CAAC;IAED,SAAS,CAAC,MAAe,EAAE,GAAW,EAAE,GAAW,EAAE,GAAW,EAAE,GAAW;QAC3E,IAAI,CAAC,iBAAiB,EAAE,CAAC;IAC3B,CAAC;IAED,KAAK,CAAC,MAAe;QACnB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC;IACrF,CAAC;IAED,SAAS,CAAC,MAAc;QACtB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,CAAC;IACjD,CAAC;CACF;AAED;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,MAAoB,EACpB,QAAkC,EAC5B,EAAE;IACR,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,QAAQ,GAAG,CAAC,CAAC,EAAE,CAAC;YACd,KAAK,SAAS;gBACZ,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC1B,MAAM;YACR,KAAK,WAAW;gBACd,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC5B,MAAM;YACR,KAAK,gBAAgB;gBACnB,MAAM,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC7B,MAAM;YACR,KAAK,YAAY;gBACf,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACzB,MAAM;YACR,KAAK,YAAY;gBACf,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;gBAC3B,MAAM;YACR,KAAK,aAAa;gBAChB,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC7B,MAAM;YACR,KAAK,cAAc;gBACjB,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAC9B,MAAM;YACR,KAAK,SAAS;gBACZ,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;gBAClD,MAAM;YACR,KAAK,cAAc;gBACjB,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBAC/B,MAAM;YACR,KAAK,iBAAiB;gBACpB,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gBACrC,MAAM;YACR,KAAK,MAAM;gBACT,MAAM,CAAC,IAAI,EAAE,CAAC;gBACd,MAAM;YACR,KAAK,SAAS;gBACZ,MAAM,CAAC,OAAO,EAAE,CAAC;gBACjB,MAAM;YACR,KAAK,WAAW;gBACd,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC/B,MAAM;YACR,KAAK,QAAQ;gBACX,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBACrB,MAAM;YACR,KAAK,OAAO;gBACV,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC7B,MAAM;YACR,KAAK,cAAc;gBACjB,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC3B,MAAM;YACR,KAAK,gBAAgB;gBACnB,MAAM,CAAC,cAAc,EAAE,CAAC;gBACxB,MAAM;YACR,KAAK,WAAW;gBACd,MAAM,CAAC,SAAS,EAAE,CAAC;gBACnB,MAAM;YACR,KAAK,WAAW;gBACd,MAAM,CAAC,SAAS,EAAE,CAAC;gBACnB,MAAM;YACR,KAAK,QAAQ;gBACX,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC5B,MAAM;YACR,KAAK,QAAQ;gBACX,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC5B,MAAM;YACR,KAAK,kBAAkB;gBACrB,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;gBACtD,MAAM;YACR,KAAK,eAAe;gBAClB,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;gBACvE,MAAM;YACR,KAAK,MAAM;gBACT,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;gBACxC,MAAM;YACR,KAAK,SAAS;gBACZ,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC/C,MAAM;YACR,KAAK,MAAM;gBACT,IAAI,GAAG,CAAC,IAAI,KAAK,SAAS;oBAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;;oBAC7C,MAAM,CAAC,IAAI,EAAE,CAAC;gBACnB,MAAM;YACR,KAAK,QAAQ;gBACX,MAAM,CAAC,MAAM,EAAE,CAAC;gBAChB,MAAM;YACR,KAAK,UAAU;gBACb,IAAI,GAAG,CAAC,QAAQ,KAAK,SAAS;oBAAE,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,QAAQ,CAAC,CAAC;;oBACjF,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC;gBAC7C,MAAM;YACR,KAAK,OAAO;gBACV,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS;oBAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;;oBAClD,MAAM,CAAC,KAAK,EAAE,CAAC;gBACpB,MAAM;YACR,KAAK,WAAW;gBACd,MAAM,CAAC,SAAS,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBAC/B,MAAM;YACR,KAAK,QAAQ;gBACX,yDAAyD;gBACzD,4DAA4D;gBAC5D,UAAU;gBACV,MAAM;QACV,CAAC;IACH,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-worker.d.ts","sourceRoot":"","sources":["../src/render-worker.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/// <reference lib="webworker" />
|
|
2
|
+
import { installBuiltinRenderers, renderScene } from "@oh-just-another/renderer-core";
|
|
3
|
+
import { Canvas2DTarget } from "./canvas-target.js";
|
|
4
|
+
import { replayCommands } from "./recording-target.js";
|
|
5
|
+
const state = { canvas: null, target: null, dpr: 1 };
|
|
6
|
+
let renderersInstalled = false;
|
|
7
|
+
const ensureRenderers = () => {
|
|
8
|
+
if (renderersInstalled)
|
|
9
|
+
return;
|
|
10
|
+
installBuiltinRenderers();
|
|
11
|
+
renderersInstalled = true;
|
|
12
|
+
};
|
|
13
|
+
const post = (msg, transfer) => {
|
|
14
|
+
if (transfer && transfer.length > 0) {
|
|
15
|
+
self.postMessage(msg, transfer);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
self.postMessage(msg);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
const init = (canvas, width, height, dpr) => {
|
|
22
|
+
state.canvas = canvas;
|
|
23
|
+
state.dpr = dpr;
|
|
24
|
+
// Resize the bitmap to dpr-scaled pixels — the host's CSS size is
|
|
25
|
+
// (width, height); render into the bigger buffer and let the
|
|
26
|
+
// composite step downsample as needed.
|
|
27
|
+
canvas.width = Math.max(1, Math.round(width * dpr));
|
|
28
|
+
canvas.height = Math.max(1, Math.round(height * dpr));
|
|
29
|
+
const ctx = canvas.getContext("2d");
|
|
30
|
+
if (!ctx)
|
|
31
|
+
throw new Error("OffscreenCanvas 2D context unavailable");
|
|
32
|
+
ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
33
|
+
state.target = new Canvas2DTarget(ctx, width, height, dpr);
|
|
34
|
+
post({ type: "ready" });
|
|
35
|
+
};
|
|
36
|
+
const resize = (width, height) => {
|
|
37
|
+
if (!state.canvas || !state.target)
|
|
38
|
+
return;
|
|
39
|
+
state.canvas.width = Math.max(1, Math.round(width * state.dpr));
|
|
40
|
+
state.canvas.height = Math.max(1, Math.round(height * state.dpr));
|
|
41
|
+
const ctx = state.canvas.getContext("2d");
|
|
42
|
+
if (!ctx)
|
|
43
|
+
return;
|
|
44
|
+
ctx.setTransform(state.dpr, 0, 0, state.dpr, 0, 0);
|
|
45
|
+
state.target.resize(width, height, state.dpr);
|
|
46
|
+
};
|
|
47
|
+
const snapshot = (scene) => {
|
|
48
|
+
if (!state.canvas || !state.target) {
|
|
49
|
+
post({ type: "error", message: "Worker not initialised" });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
ensureRenderers();
|
|
53
|
+
const ctx = state.canvas.getContext("2d");
|
|
54
|
+
if (ctx === null) {
|
|
55
|
+
post({ type: "error", message: "Worker not initialised" });
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
ctx.save();
|
|
59
|
+
ctx.setTransform(state.dpr, 0, 0, state.dpr, 0, 0);
|
|
60
|
+
ctx.clearRect(0, 0, state.target.size.width, state.target.size.height);
|
|
61
|
+
renderScene(scene, state.target);
|
|
62
|
+
ctx.restore();
|
|
63
|
+
const bitmap = state.canvas.transferToImageBitmap();
|
|
64
|
+
post({ type: "frame-done", bitmap }, [bitmap]);
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Replay a serialised RecordingTarget command stream onto the owned
|
|
68
|
+
* OffscreenCanvas. Used by the LayeredSurface "offscreen" backend: the
|
|
69
|
+
* main thread captures every RenderTarget call into a buffer and ships
|
|
70
|
+
* it here per frame; the worker replays.
|
|
71
|
+
*/
|
|
72
|
+
const replay = (commands) => {
|
|
73
|
+
if (!state.target) {
|
|
74
|
+
post({ type: "error", message: "Worker not initialised" });
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
replayCommands(state.target, commands);
|
|
78
|
+
};
|
|
79
|
+
self.addEventListener("message", (ev) => {
|
|
80
|
+
const msg = ev.data;
|
|
81
|
+
try {
|
|
82
|
+
switch (msg.type) {
|
|
83
|
+
case "init":
|
|
84
|
+
init(msg.canvas, msg.width, msg.height, msg.dpr);
|
|
85
|
+
break;
|
|
86
|
+
case "resize":
|
|
87
|
+
resize(msg.width, msg.height);
|
|
88
|
+
break;
|
|
89
|
+
case "snapshot":
|
|
90
|
+
// A dpr update only takes effect on the next resize; snapshot
|
|
91
|
+
// honours whatever transform init established.
|
|
92
|
+
snapshot(msg.scene);
|
|
93
|
+
break;
|
|
94
|
+
case "replay":
|
|
95
|
+
replay(msg.commands);
|
|
96
|
+
break;
|
|
97
|
+
case "frame":
|
|
98
|
+
// Patch-stream frames are not implemented; the protocol is
|
|
99
|
+
// reserved. Reply with an error so callers don't hang on the
|
|
100
|
+
// awaited response.
|
|
101
|
+
post({ type: "error", message: "patch-stream frames not implemented" });
|
|
102
|
+
break;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
post({
|
|
107
|
+
type: "error",
|
|
108
|
+
message: err instanceof Error ? err.message : String(err),
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
//# sourceMappingURL=render-worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render-worker.js","sourceRoot":"","sources":["../src/render-worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { type TileCache } from "@oh-just-another/renderer-core";
|
|
2
|
+
import type { Bounds, ElementId } from "@oh-just-another/types";
|
|
3
|
+
import { type Scene } from "@oh-just-another/scene";
|
|
4
|
+
import type { Canvas2DTarget } from "./canvas-target.js";
|
|
5
|
+
/**
|
|
6
|
+
* Main-thread Canvas2D tile compositor.
|
|
7
|
+
*
|
|
8
|
+
* Splits the visible viewport into a fixed-size world-space grid
|
|
9
|
+
* (`TILE_SIZE` per side; default 2048 world units). Each tile is
|
|
10
|
+
* rasterised once into its own OffscreenCanvas, stored in a
|
|
11
|
+
* `TileCache`, and composited onto the main canvas via `drawImage`.
|
|
12
|
+
* Pure pan re-composites from cache; zoom changes the bucket and may
|
|
13
|
+
* invalidate.
|
|
14
|
+
*
|
|
15
|
+
* Designed for very large scenes where the per-frame `renderScene`
|
|
16
|
+
* walks every visible shape — composite of N cached bitmaps is far
|
|
17
|
+
* cheaper than re-rasterising N shapes.
|
|
18
|
+
*/
|
|
19
|
+
export interface ChangedElementRecord {
|
|
20
|
+
/** World bbox of the shape in the previous frame, or null if it was just added. */
|
|
21
|
+
readonly before: Bounds | null;
|
|
22
|
+
/** World bbox of the shape in the current frame, or null if it was just removed. */
|
|
23
|
+
readonly after: Bounds | null;
|
|
24
|
+
}
|
|
25
|
+
export interface RenderViaTilesOptions {
|
|
26
|
+
/** World-space rect currently visible. Tiles outside are skipped. */
|
|
27
|
+
readonly viewport: Bounds;
|
|
28
|
+
/** Persistent tile cache — same instance across frames. */
|
|
29
|
+
readonly cache: TileCache<OffscreenCanvas>;
|
|
30
|
+
/**
|
|
31
|
+
* Element ids whose scene-reference changed since the previous frame,
|
|
32
|
+
* each with the before/after world bbox. The compositor routes
|
|
33
|
+
* invalidation by case:
|
|
34
|
+
* • removed (after null) → invalidateForElement (id present in
|
|
35
|
+
* reverse index)
|
|
36
|
+
* • added (before null) → invalidateRect (no id yet)
|
|
37
|
+
* • mutated/moved (both) → both rects
|
|
38
|
+
*/
|
|
39
|
+
readonly changedElements?: ReadonlyMap<ElementId, ChangedElementRecord>;
|
|
40
|
+
/** Current zoom (used to pick the cache bucket). */
|
|
41
|
+
readonly zoomBucket: number;
|
|
42
|
+
}
|
|
43
|
+
export declare const renderViaTiles: (scene: Scene, mainTarget: Canvas2DTarget, options: RenderViaTilesOptions) => void;
|
|
44
|
+
//# sourceMappingURL=tile-compositor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tile-compositor.d.ts","sourceRoot":"","sources":["../src/tile-compositor.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,SAAS,EAGf,MAAM,gCAAgC,CAAC;AACxC,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAIL,KAAK,KAAK,EAEX,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAGzD;;;;;;;;;;;;;GAaG;AAEH,MAAM,WAAW,oBAAoB;IACnC,mFAAmF;IACnF,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,oFAAoF;IACpF,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,qBAAqB;IACpC,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,eAAe,CAAC,CAAC;IAC3C;;;;;;;;OAQG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,WAAW,CAAC,SAAS,EAAE,oBAAoB,CAAC,CAAC;IACxE,oDAAoD;IACpD,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;CAC7B;AAED,eAAO,MAAM,cAAc,GACzB,OAAO,KAAK,EACZ,YAAY,cAAc,EAC1B,SAAS,qBAAqB,KAC7B,IA0CF,CAAC"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { TILE_SIZE, } from "@oh-just-another/renderer-core";
|
|
2
|
+
import { getElementsInLayer, getElementWorldBounds, getLayersInOrder, } from "@oh-just-another/scene";
|
|
3
|
+
import { createOffscreenCanvas2DTarget } from "./offscreen.js";
|
|
4
|
+
import { getElementRenderer } from "@oh-just-another/renderer-core";
|
|
5
|
+
export const renderViaTiles = (scene, mainTarget, options) => {
|
|
6
|
+
const { viewport, cache, changedElements, zoomBucket } = options;
|
|
7
|
+
// 1) Invalidate cached tiles per patch (covers add / remove / move).
|
|
8
|
+
if (changedElements) {
|
|
9
|
+
for (const [id, record] of changedElements) {
|
|
10
|
+
cache.invalidateForPatch({
|
|
11
|
+
...(record.after === null ? { removedElementId: id } : {}),
|
|
12
|
+
...(record.before ? { beforeBounds: record.before } : {}),
|
|
13
|
+
...(record.after ? { afterBounds: record.after } : {}),
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// 2) Visible tile range.
|
|
18
|
+
const colMin = Math.floor(viewport.x / TILE_SIZE);
|
|
19
|
+
const rowMin = Math.floor(viewport.y / TILE_SIZE);
|
|
20
|
+
const colMax = Math.floor((viewport.x + viewport.width) / TILE_SIZE);
|
|
21
|
+
const rowMax = Math.floor((viewport.y + viewport.height) / TILE_SIZE);
|
|
22
|
+
// 3) For each visible tile, hit cache or render fresh.
|
|
23
|
+
for (let row = rowMin; row <= rowMax; row++) {
|
|
24
|
+
for (let col = colMin; col <= colMax; col++) {
|
|
25
|
+
const key = { col, row, zoom: zoomBucket };
|
|
26
|
+
let entry = cache.get(key);
|
|
27
|
+
if (!entry) {
|
|
28
|
+
const fresh = rasteriseTile(scene, col, row, zoomBucket);
|
|
29
|
+
if (!fresh)
|
|
30
|
+
continue;
|
|
31
|
+
cache.set(fresh);
|
|
32
|
+
entry = fresh;
|
|
33
|
+
}
|
|
34
|
+
// Composite — draw the cached bitmap at its world position. The
|
|
35
|
+
// main target's transform already maps world→screen.
|
|
36
|
+
mainTarget.drawImage(entry.bitmap, entry.bounds.x, entry.bounds.y, entry.bounds.width, entry.bounds.height);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Render a single tile's worth of shapes into a fresh OffscreenCanvas
|
|
42
|
+
* sized at `TILE_SIZE * zoomBucket` device pixels per side. Returns
|
|
43
|
+
* `null` when the tile contains no shapes.
|
|
44
|
+
*/
|
|
45
|
+
const rasteriseTile = (scene, col, row, zoomBucket) => {
|
|
46
|
+
if (typeof OffscreenCanvas === "undefined")
|
|
47
|
+
return null;
|
|
48
|
+
const worldX = col * TILE_SIZE;
|
|
49
|
+
const worldY = row * TILE_SIZE;
|
|
50
|
+
const worldBounds = {
|
|
51
|
+
x: worldX,
|
|
52
|
+
y: worldY,
|
|
53
|
+
width: TILE_SIZE,
|
|
54
|
+
height: TILE_SIZE,
|
|
55
|
+
};
|
|
56
|
+
const shapes = elementsIntersectingTile(scene, worldBounds);
|
|
57
|
+
if (shapes.length === 0)
|
|
58
|
+
return null;
|
|
59
|
+
// Bitmap size — `TILE_SIZE * zoomBucket` device pixels so the tile
|
|
60
|
+
// stays crisp at this bucket. Higher buckets allocate more memory;
|
|
61
|
+
// cache eviction keeps total bounded.
|
|
62
|
+
const bitmapSize = Math.max(1, Math.round(TILE_SIZE * zoomBucket));
|
|
63
|
+
const { canvas, target } = createOffscreenCanvas2DTarget(bitmapSize, bitmapSize);
|
|
64
|
+
// World → tile-local + zoom scaling.
|
|
65
|
+
target.save();
|
|
66
|
+
target.scale(zoomBucket, zoomBucket);
|
|
67
|
+
target.translate(-worldX, -worldY);
|
|
68
|
+
for (const shape of shapes) {
|
|
69
|
+
const renderer = getElementRenderer(shape.type);
|
|
70
|
+
if (!renderer)
|
|
71
|
+
continue;
|
|
72
|
+
target.save();
|
|
73
|
+
target.translate(shape.position.x, shape.position.y);
|
|
74
|
+
if (shape.rotation !== 0)
|
|
75
|
+
target.rotate(shape.rotation);
|
|
76
|
+
if (shape.scale.x !== 1 || shape.scale.y !== 1) {
|
|
77
|
+
target.scale(shape.scale.x, shape.scale.y);
|
|
78
|
+
}
|
|
79
|
+
renderer(shape, target, { zoom: zoomBucket });
|
|
80
|
+
target.restore();
|
|
81
|
+
}
|
|
82
|
+
target.restore();
|
|
83
|
+
// 4 bytes per pixel (RGBA) — byte accounting for LRU.
|
|
84
|
+
const bytes = bitmapSize * bitmapSize * 4;
|
|
85
|
+
return {
|
|
86
|
+
key: { col, row, zoom: zoomBucket },
|
|
87
|
+
bitmap: canvas,
|
|
88
|
+
bounds: worldBounds,
|
|
89
|
+
bytes,
|
|
90
|
+
elements: shapes.map((s) => s.id),
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
const elementsIntersectingTile = (scene, tileBounds) => {
|
|
94
|
+
const out = [];
|
|
95
|
+
for (const layer of getLayersInOrder(scene)) {
|
|
96
|
+
if (!layer.visible)
|
|
97
|
+
continue;
|
|
98
|
+
for (const shape of getElementsInLayer(scene, layer.id)) {
|
|
99
|
+
const b = getElementWorldBounds(shape);
|
|
100
|
+
if (intersects(b, tileBounds))
|
|
101
|
+
out.push(shape);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return out;
|
|
105
|
+
};
|
|
106
|
+
const intersects = (a, b) => a.x < b.x + b.width &&
|
|
107
|
+
a.x + a.width > b.x &&
|
|
108
|
+
a.y < b.y + b.height &&
|
|
109
|
+
a.y + a.height > b.y;
|
|
110
|
+
//# sourceMappingURL=tile-compositor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tile-compositor.js","sourceRoot":"","sources":["../src/tile-compositor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Color } from "@oh-just-another/types";
|
|
2
|
+
/**
|
|
3
|
+
* Parse a CSS color into normalised RGBA `[r, g, b, a]` where every
|
|
4
|
+
* component is in `[0, 1]`. Delegates to `@math/color` so the WebGL2
|
|
5
|
+
* backend understands the same syntaxes as Canvas2D — short hex
|
|
6
|
+
* (`#bbb`), `rgb()`/`rgba()`, named colors (`white`, `transparent`),
|
|
7
|
+
* and `#rrggbbaa` with explicit alpha.
|
|
8
|
+
*
|
|
9
|
+
* Anything unparseable falls back to opaque black plus a dev-time
|
|
10
|
+
* warning.
|
|
11
|
+
*/
|
|
12
|
+
export declare const parseWebGL2Color: (color: Color | null) => [number, number, number, number];
|
|
13
|
+
//# sourceMappingURL=webgl2-color.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webgl2-color.d.ts","sourceRoot":"","sources":["../src/webgl2-color.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,wBAAwB,CAAC;AAGpD;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,GAAI,OAAO,KAAK,GAAG,IAAI,KAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAYrF,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { color as colorParser } from "@oh-just-another/math";
|
|
2
|
+
/**
|
|
3
|
+
* Parse a CSS color into normalised RGBA `[r, g, b, a]` where every
|
|
4
|
+
* component is in `[0, 1]`. Delegates to `@math/color` so the WebGL2
|
|
5
|
+
* backend understands the same syntaxes as Canvas2D — short hex
|
|
6
|
+
* (`#bbb`), `rgb()`/`rgba()`, named colors (`white`, `transparent`),
|
|
7
|
+
* and `#rrggbbaa` with explicit alpha.
|
|
8
|
+
*
|
|
9
|
+
* Anything unparseable falls back to opaque black plus a dev-time
|
|
10
|
+
* warning.
|
|
11
|
+
*/
|
|
12
|
+
export const parseWebGL2Color = (color) => {
|
|
13
|
+
if (color === null)
|
|
14
|
+
return [0, 0, 0, 0];
|
|
15
|
+
try {
|
|
16
|
+
const { r, g, b, a } = colorParser.parse(color);
|
|
17
|
+
return [r / 255, g / 255, b / 255, a];
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
if (typeof console !== "undefined") {
|
|
21
|
+
console.warn(`[WebGL2Target] cannot parse color '${color}', falling back to black`);
|
|
22
|
+
}
|
|
23
|
+
return [0, 0, 0, 1];
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
//# sourceMappingURL=webgl2-color.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webgl2-color.js","sourceRoot":"","sources":["../src/webgl2-color.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,IAAI,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAE7D;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,KAAmB,EAAoC,EAAE;IACxF,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAChD,OAAO,CAAC,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,CAAC,CAAC;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,OAAO,OAAO,KAAK,WAAW,EAAE,CAAC;YAEnC,OAAO,CAAC,IAAI,CAAC,sCAAsC,KAAK,0BAA0B,CAAC,CAAC;QACtF,CAAC;QACD,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACtB,CAAC;AACH,CAAC,CAAC"}
|