canvas-ultrafast 1.0.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/README.md +146 -0
- package/dist/canvas-ultrafast.es.js +963 -0
- package/dist/canvas-ultrafast.es.js.br +0 -0
- package/dist/canvas-ultrafast.es.js.gz +0 -0
- package/dist/canvas-ultrafast.es.js.zst +0 -0
- package/dist/canvas-ultrafast.umd.js +47 -0
- package/dist/canvas-ultrafast.umd.js.br +0 -0
- package/dist/canvas-ultrafast.umd.js.gz +0 -0
- package/dist/canvas-ultrafast.umd.js.zst +0 -0
- package/dist/index.d.ts +229 -0
- package/package.json +56 -0
|
@@ -0,0 +1,963 @@
|
|
|
1
|
+
class v {
|
|
2
|
+
d = [];
|
|
3
|
+
b = {};
|
|
4
|
+
a(t, ...e) {
|
|
5
|
+
this.d.push({ type: "method", name: t, args: e });
|
|
6
|
+
}
|
|
7
|
+
c(t, e) {
|
|
8
|
+
this.b[t] = e, this.d.push({ type: "property", name: t, value: e });
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Drain and return all buffered commands.
|
|
12
|
+
* No _ prefix: called cross-file from pipeline, must survive mangleProps.
|
|
13
|
+
*/
|
|
14
|
+
takeCommands() {
|
|
15
|
+
if (this.d.length === 0) return [];
|
|
16
|
+
const t = this.d;
|
|
17
|
+
return this.d = [], t;
|
|
18
|
+
}
|
|
19
|
+
// Canvas 2D API methods
|
|
20
|
+
// State
|
|
21
|
+
save() {
|
|
22
|
+
this.a("save");
|
|
23
|
+
}
|
|
24
|
+
restore() {
|
|
25
|
+
this.a("restore");
|
|
26
|
+
}
|
|
27
|
+
// Transform
|
|
28
|
+
scale(t, e) {
|
|
29
|
+
this.a("scale", t, e);
|
|
30
|
+
}
|
|
31
|
+
rotate(t) {
|
|
32
|
+
this.a("rotate", t);
|
|
33
|
+
}
|
|
34
|
+
translate(t, e) {
|
|
35
|
+
this.a("translate", t, e);
|
|
36
|
+
}
|
|
37
|
+
transform(t, e, s, i, r, a) {
|
|
38
|
+
this.a("transform", t, e, s, i, r, a);
|
|
39
|
+
}
|
|
40
|
+
setTransform(t, e, s, i, r, a) {
|
|
41
|
+
this.a("setTransform", t, e, s, i, r, a);
|
|
42
|
+
}
|
|
43
|
+
resetTransform() {
|
|
44
|
+
this.a("resetTransform");
|
|
45
|
+
}
|
|
46
|
+
// Rectangles
|
|
47
|
+
clearRect(t, e, s, i) {
|
|
48
|
+
this.a("clearRect", t, e, s, i);
|
|
49
|
+
}
|
|
50
|
+
fillRect(t, e, s, i) {
|
|
51
|
+
this.a("fillRect", t, e, s, i);
|
|
52
|
+
}
|
|
53
|
+
strokeRect(t, e, s, i) {
|
|
54
|
+
this.a("strokeRect", t, e, s, i);
|
|
55
|
+
}
|
|
56
|
+
// Text
|
|
57
|
+
fillText(t, e, s, i) {
|
|
58
|
+
this.a("fillText", ...i !== void 0 ? [t, e, s, i] : [t, e, s]);
|
|
59
|
+
}
|
|
60
|
+
strokeText(t, e, s, i) {
|
|
61
|
+
this.a("strokeText", ...i !== void 0 ? [t, e, s, i] : [t, e, s]);
|
|
62
|
+
}
|
|
63
|
+
// Line drawing
|
|
64
|
+
beginPath() {
|
|
65
|
+
this.a("beginPath");
|
|
66
|
+
}
|
|
67
|
+
closePath() {
|
|
68
|
+
this.a("closePath");
|
|
69
|
+
}
|
|
70
|
+
moveTo(t, e) {
|
|
71
|
+
this.a("moveTo", t, e);
|
|
72
|
+
}
|
|
73
|
+
lineTo(t, e) {
|
|
74
|
+
this.a("lineTo", t, e);
|
|
75
|
+
}
|
|
76
|
+
bezierCurveTo(t, e, s, i, r, a) {
|
|
77
|
+
this.a("bezierCurveTo", t, e, s, i, r, a);
|
|
78
|
+
}
|
|
79
|
+
quadraticCurveTo(t, e, s, i) {
|
|
80
|
+
this.a("quadraticCurveTo", t, e, s, i);
|
|
81
|
+
}
|
|
82
|
+
arc(t, e, s, i, r, a) {
|
|
83
|
+
this.a("arc", ...a !== void 0 ? [t, e, s, i, r, a] : [t, e, s, i, r]);
|
|
84
|
+
}
|
|
85
|
+
arcTo(t, e, s, i, r) {
|
|
86
|
+
this.a("arcTo", t, e, s, i, r);
|
|
87
|
+
}
|
|
88
|
+
ellipse(t, e, s, i, r, a, h, o) {
|
|
89
|
+
this.a("ellipse", ...o !== void 0 ? [t, e, s, i, r, a, h, o] : [t, e, s, i, r, a, h]);
|
|
90
|
+
}
|
|
91
|
+
rect(t, e, s, i) {
|
|
92
|
+
this.a("rect", t, e, s, i);
|
|
93
|
+
}
|
|
94
|
+
// Fill and stroke
|
|
95
|
+
fill() {
|
|
96
|
+
this.a("fill");
|
|
97
|
+
}
|
|
98
|
+
stroke() {
|
|
99
|
+
this.a("stroke");
|
|
100
|
+
}
|
|
101
|
+
clip() {
|
|
102
|
+
this.a("clip");
|
|
103
|
+
}
|
|
104
|
+
// Properties (setters)
|
|
105
|
+
set fillStyle(t) {
|
|
106
|
+
this.c("fillStyle", t);
|
|
107
|
+
}
|
|
108
|
+
set strokeStyle(t) {
|
|
109
|
+
this.c("strokeStyle", t);
|
|
110
|
+
}
|
|
111
|
+
set lineWidth(t) {
|
|
112
|
+
this.c("lineWidth", t);
|
|
113
|
+
}
|
|
114
|
+
set lineCap(t) {
|
|
115
|
+
this.c("lineCap", t);
|
|
116
|
+
}
|
|
117
|
+
set lineJoin(t) {
|
|
118
|
+
this.c("lineJoin", t);
|
|
119
|
+
}
|
|
120
|
+
set miterLimit(t) {
|
|
121
|
+
this.c("miterLimit", t);
|
|
122
|
+
}
|
|
123
|
+
set lineDashOffset(t) {
|
|
124
|
+
this.c("lineDashOffset", t);
|
|
125
|
+
}
|
|
126
|
+
set font(t) {
|
|
127
|
+
this.c("font", t);
|
|
128
|
+
}
|
|
129
|
+
set textAlign(t) {
|
|
130
|
+
this.c("textAlign", t);
|
|
131
|
+
}
|
|
132
|
+
set textBaseline(t) {
|
|
133
|
+
this.c("textBaseline", t);
|
|
134
|
+
}
|
|
135
|
+
set globalAlpha(t) {
|
|
136
|
+
this.c("globalAlpha", t);
|
|
137
|
+
}
|
|
138
|
+
set globalCompositeOperation(t) {
|
|
139
|
+
this.c("globalCompositeOperation", t);
|
|
140
|
+
}
|
|
141
|
+
set shadowBlur(t) {
|
|
142
|
+
this.c("shadowBlur", t);
|
|
143
|
+
}
|
|
144
|
+
set shadowColor(t) {
|
|
145
|
+
this.c("shadowColor", t);
|
|
146
|
+
}
|
|
147
|
+
set shadowOffsetX(t) {
|
|
148
|
+
this.c("shadowOffsetX", t);
|
|
149
|
+
}
|
|
150
|
+
set shadowOffsetY(t) {
|
|
151
|
+
this.c("shadowOffsetY", t);
|
|
152
|
+
}
|
|
153
|
+
// Property getters (return local cached values)
|
|
154
|
+
get fillStyle() {
|
|
155
|
+
return this.b.fillStyle ?? "#000";
|
|
156
|
+
}
|
|
157
|
+
get strokeStyle() {
|
|
158
|
+
return this.b.strokeStyle ?? "#000";
|
|
159
|
+
}
|
|
160
|
+
get lineWidth() {
|
|
161
|
+
return this.b.lineWidth ?? 1;
|
|
162
|
+
}
|
|
163
|
+
get lineCap() {
|
|
164
|
+
return this.b.lineCap ?? "butt";
|
|
165
|
+
}
|
|
166
|
+
get lineJoin() {
|
|
167
|
+
return this.b.lineJoin ?? "miter";
|
|
168
|
+
}
|
|
169
|
+
get miterLimit() {
|
|
170
|
+
return this.b.miterLimit ?? 10;
|
|
171
|
+
}
|
|
172
|
+
get lineDashOffset() {
|
|
173
|
+
return this.b.lineDashOffset ?? 0;
|
|
174
|
+
}
|
|
175
|
+
get font() {
|
|
176
|
+
return this.b.font ?? "10px sans-serif";
|
|
177
|
+
}
|
|
178
|
+
get textAlign() {
|
|
179
|
+
return this.b.textAlign ?? "start";
|
|
180
|
+
}
|
|
181
|
+
get textBaseline() {
|
|
182
|
+
return this.b.textBaseline ?? "alphabetic";
|
|
183
|
+
}
|
|
184
|
+
get globalAlpha() {
|
|
185
|
+
return this.b.globalAlpha ?? 1;
|
|
186
|
+
}
|
|
187
|
+
get globalCompositeOperation() {
|
|
188
|
+
return this.b.globalCompositeOperation ?? "source-over";
|
|
189
|
+
}
|
|
190
|
+
get shadowBlur() {
|
|
191
|
+
return this.b.shadowBlur ?? 0;
|
|
192
|
+
}
|
|
193
|
+
get shadowColor() {
|
|
194
|
+
return this.b.shadowColor ?? "rgba(0, 0, 0, 0)";
|
|
195
|
+
}
|
|
196
|
+
get shadowOffsetX() {
|
|
197
|
+
return this.b.shadowOffsetX ?? 0;
|
|
198
|
+
}
|
|
199
|
+
get shadowOffsetY() {
|
|
200
|
+
return this.b.shadowOffsetY ?? 0;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
class L {
|
|
204
|
+
c = [];
|
|
205
|
+
a;
|
|
206
|
+
b;
|
|
207
|
+
/**
|
|
208
|
+
* @param width Canvas width in pixels
|
|
209
|
+
* @param height Canvas height in pixels
|
|
210
|
+
*/
|
|
211
|
+
constructor(t, e) {
|
|
212
|
+
this.b = F(t, e), this.a = new Float32Array(this.b);
|
|
213
|
+
}
|
|
214
|
+
/** Push current matrix onto the stack. No _ prefix: cross-file. */
|
|
215
|
+
save() {
|
|
216
|
+
this.c.push(new Float32Array(this.a));
|
|
217
|
+
}
|
|
218
|
+
/** Pop and restore the top matrix. No _ prefix: cross-file. */
|
|
219
|
+
restore() {
|
|
220
|
+
this.c.length > 0 && (this.a = this.c.pop());
|
|
221
|
+
}
|
|
222
|
+
/** Translate the current matrix. No _ prefix: cross-file. */
|
|
223
|
+
translate(t, e) {
|
|
224
|
+
const s = this.a;
|
|
225
|
+
s[6] += s[0] * t + s[3] * e, s[7] += s[1] * t + s[4] * e;
|
|
226
|
+
}
|
|
227
|
+
/** Rotate the current matrix by angle (radians). No _ prefix: cross-file. */
|
|
228
|
+
rotate(t) {
|
|
229
|
+
const e = Math.cos(t), s = Math.sin(t), i = this.a, r = i[0], a = i[1], h = i[3], o = i[4];
|
|
230
|
+
i[0] = r * e + h * s, i[1] = a * e + o * s, i[3] = r * -s + h * e, i[4] = a * -s + o * e;
|
|
231
|
+
}
|
|
232
|
+
/** Scale the current matrix. No _ prefix: cross-file. */
|
|
233
|
+
scale(t, e) {
|
|
234
|
+
const s = this.a;
|
|
235
|
+
s[0] *= t, s[1] *= t, s[3] *= e, s[4] *= e;
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Multiply current matrix by an arbitrary 2D affine transform.
|
|
239
|
+
* Canvas 2D transform(a, b, c, d, e, f) matrix:
|
|
240
|
+
* a c e
|
|
241
|
+
* b d f
|
|
242
|
+
* 0 0 1
|
|
243
|
+
* No _ prefix: cross-file.
|
|
244
|
+
*/
|
|
245
|
+
transform(t, e, s, i, r, a) {
|
|
246
|
+
const h = this.a, o = h[0], c = h[1], l = h[3], f = h[4], b = h[6], u = h[7];
|
|
247
|
+
h[0] = o * t + l * e, h[1] = c * t + f * e, h[3] = o * s + l * i, h[4] = c * s + f * i, h[6] = o * r + l * a + b, h[7] = c * r + f * a + u;
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Reset to projection then apply the given affine transform.
|
|
251
|
+
* Canvas 2D setTransform(a, b, c, d, e, f).
|
|
252
|
+
* No _ prefix: cross-file.
|
|
253
|
+
*/
|
|
254
|
+
setTransform(t, e, s, i, r, a) {
|
|
255
|
+
this.a.set(this.b), this.transform(t, e, s, i, r, a);
|
|
256
|
+
}
|
|
257
|
+
/** Reset to the base orthographic projection. No _ prefix: cross-file. */
|
|
258
|
+
resetTransform() {
|
|
259
|
+
this.a.set(this.b);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Update canvas dimensions (e.g., on resize).
|
|
263
|
+
* Recomputes the projection and resets the current matrix.
|
|
264
|
+
* No _ prefix: cross-file.
|
|
265
|
+
*/
|
|
266
|
+
resize(t, e) {
|
|
267
|
+
this.b = F(t, e), this.a = new Float32Array(this.b), this.c = [];
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Returns the current 3×3 matrix for gl.uniformMatrix3fv.
|
|
271
|
+
* No _ prefix: cross-file.
|
|
272
|
+
*/
|
|
273
|
+
getMatrix() {
|
|
274
|
+
return this.a;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
function F(n, t) {
|
|
278
|
+
return new Float32Array([
|
|
279
|
+
2 / n,
|
|
280
|
+
0,
|
|
281
|
+
0,
|
|
282
|
+
// column 0
|
|
283
|
+
0,
|
|
284
|
+
-2 / t,
|
|
285
|
+
0,
|
|
286
|
+
// column 1
|
|
287
|
+
-1,
|
|
288
|
+
1,
|
|
289
|
+
1
|
|
290
|
+
// column 2
|
|
291
|
+
]);
|
|
292
|
+
}
|
|
293
|
+
const B = {
|
|
294
|
+
black: 255,
|
|
295
|
+
white: 4294967295,
|
|
296
|
+
red: 4278190335,
|
|
297
|
+
green: 8388863,
|
|
298
|
+
blue: 65535,
|
|
299
|
+
yellow: 4294902015,
|
|
300
|
+
cyan: 16777215,
|
|
301
|
+
magenta: 4278255615,
|
|
302
|
+
orange: 4289003775,
|
|
303
|
+
transparent: 0
|
|
304
|
+
}, x = /* @__PURE__ */ new Map();
|
|
305
|
+
function g(n) {
|
|
306
|
+
const t = x.get(n);
|
|
307
|
+
if (t) return t;
|
|
308
|
+
const e = U(n);
|
|
309
|
+
return x.set(n, e), e;
|
|
310
|
+
}
|
|
311
|
+
function U(n) {
|
|
312
|
+
const t = n.trim();
|
|
313
|
+
if (t.charCodeAt(0) === 35)
|
|
314
|
+
return k(t);
|
|
315
|
+
if (t.charCodeAt(0) === 114)
|
|
316
|
+
return y(t);
|
|
317
|
+
const e = B[t.toLowerCase()];
|
|
318
|
+
return e !== void 0 ? new Float32Array([
|
|
319
|
+
(e >>> 24 & 255) / 255,
|
|
320
|
+
(e >>> 16 & 255) / 255,
|
|
321
|
+
(e >>> 8 & 255) / 255,
|
|
322
|
+
(e & 255) / 255
|
|
323
|
+
]) : new Float32Array([0, 0, 0, 1]);
|
|
324
|
+
}
|
|
325
|
+
function k(n) {
|
|
326
|
+
const t = n.length;
|
|
327
|
+
if (t === 4) {
|
|
328
|
+
const e = parseInt(n[1], 16), s = parseInt(n[2], 16), i = parseInt(n[3], 16);
|
|
329
|
+
return new Float32Array([
|
|
330
|
+
e * 17 / 255,
|
|
331
|
+
s * 17 / 255,
|
|
332
|
+
i * 17 / 255,
|
|
333
|
+
1
|
|
334
|
+
]);
|
|
335
|
+
}
|
|
336
|
+
if (t === 7) {
|
|
337
|
+
const e = parseInt(n.slice(1, 3), 16), s = parseInt(n.slice(3, 5), 16), i = parseInt(n.slice(5, 7), 16);
|
|
338
|
+
return new Float32Array([e / 255, s / 255, i / 255, 1]);
|
|
339
|
+
}
|
|
340
|
+
if (t === 9) {
|
|
341
|
+
const e = parseInt(n.slice(1, 3), 16), s = parseInt(n.slice(3, 5), 16), i = parseInt(n.slice(5, 7), 16), r = parseInt(n.slice(7, 9), 16);
|
|
342
|
+
return new Float32Array([e / 255, s / 255, i / 255, r / 255]);
|
|
343
|
+
}
|
|
344
|
+
if (t === 5) {
|
|
345
|
+
const e = parseInt(n[1], 16), s = parseInt(n[2], 16), i = parseInt(n[3], 16), r = parseInt(n[4], 16);
|
|
346
|
+
return new Float32Array([
|
|
347
|
+
e * 17 / 255,
|
|
348
|
+
s * 17 / 255,
|
|
349
|
+
i * 17 / 255,
|
|
350
|
+
r * 17 / 255
|
|
351
|
+
]);
|
|
352
|
+
}
|
|
353
|
+
return new Float32Array([0, 0, 0, 1]);
|
|
354
|
+
}
|
|
355
|
+
function y(n) {
|
|
356
|
+
const t = n.indexOf("("), e = n.lastIndexOf(")");
|
|
357
|
+
if (t === -1 || e === -1) return new Float32Array([0, 0, 0, 1]);
|
|
358
|
+
const s = n.slice(t + 1, e).split(","), i = parseFloat(s[0]) / 255, r = parseFloat(s[1]) / 255, a = parseFloat(s[2]) / 255, h = s.length >= 4 ? parseFloat(s[3]) : 1;
|
|
359
|
+
return new Float32Array([i, r, a, h]);
|
|
360
|
+
}
|
|
361
|
+
const D = `
|
|
362
|
+
attribute vec2 a_position;
|
|
363
|
+
uniform mat3 u_matrix;
|
|
364
|
+
void main() {
|
|
365
|
+
vec3 pos = u_matrix * vec3(a_position, 1.0);
|
|
366
|
+
gl_Position = vec4(pos.xy, 0.0, 1.0);
|
|
367
|
+
}
|
|
368
|
+
`, I = `
|
|
369
|
+
precision mediump float;
|
|
370
|
+
uniform vec4 u_color;
|
|
371
|
+
void main() {
|
|
372
|
+
gl_FragColor = u_color;
|
|
373
|
+
}
|
|
374
|
+
`, M = `
|
|
375
|
+
attribute vec2 a_position;
|
|
376
|
+
attribute vec2 a_texCoord;
|
|
377
|
+
uniform mat3 u_matrix;
|
|
378
|
+
varying vec2 v_texCoord;
|
|
379
|
+
void main() {
|
|
380
|
+
vec3 pos = u_matrix * vec3(a_position, 1.0);
|
|
381
|
+
gl_Position = vec4(pos.xy, 0.0, 1.0);
|
|
382
|
+
v_texCoord = a_texCoord;
|
|
383
|
+
}
|
|
384
|
+
`, O = `
|
|
385
|
+
precision mediump float;
|
|
386
|
+
varying vec2 v_texCoord;
|
|
387
|
+
uniform sampler2D u_texture;
|
|
388
|
+
uniform vec4 u_color;
|
|
389
|
+
void main() {
|
|
390
|
+
vec4 texel = texture2D(u_texture, v_texCoord);
|
|
391
|
+
gl_FragColor = texel * u_color;
|
|
392
|
+
}
|
|
393
|
+
`, N = `
|
|
394
|
+
attribute vec2 a_position;
|
|
395
|
+
varying vec2 v_texCoord;
|
|
396
|
+
void main() {
|
|
397
|
+
v_texCoord = a_position;
|
|
398
|
+
gl_Position = vec4(a_position * 2.0 - 1.0, 0, 1);
|
|
399
|
+
}
|
|
400
|
+
`, X = `
|
|
401
|
+
precision mediump float;
|
|
402
|
+
varying vec2 v_texCoord;
|
|
403
|
+
uniform sampler2D u_texture;
|
|
404
|
+
void main() {
|
|
405
|
+
gl_FragColor = texture2D(u_texture, v_texCoord);
|
|
406
|
+
}
|
|
407
|
+
`;
|
|
408
|
+
class G {
|
|
409
|
+
c;
|
|
410
|
+
F;
|
|
411
|
+
A;
|
|
412
|
+
// Transform
|
|
413
|
+
a;
|
|
414
|
+
// State
|
|
415
|
+
i = new Float32Array([0, 0, 0, 1]);
|
|
416
|
+
d = new Float32Array([0, 0, 0, 1]);
|
|
417
|
+
f = 1;
|
|
418
|
+
e = 1;
|
|
419
|
+
g = "10px sans-serif";
|
|
420
|
+
j = "start";
|
|
421
|
+
k = "alphabetic";
|
|
422
|
+
o = "butt";
|
|
423
|
+
p = "miter";
|
|
424
|
+
G = [];
|
|
425
|
+
// Path state
|
|
426
|
+
t = [];
|
|
427
|
+
// flat: x0,y0,x1,y1,...
|
|
428
|
+
l = 0;
|
|
429
|
+
m = 0;
|
|
430
|
+
u = 0;
|
|
431
|
+
v = 0;
|
|
432
|
+
// WebGL resources
|
|
433
|
+
q;
|
|
434
|
+
B;
|
|
435
|
+
r;
|
|
436
|
+
C;
|
|
437
|
+
D;
|
|
438
|
+
s;
|
|
439
|
+
// Text rendering surface
|
|
440
|
+
b;
|
|
441
|
+
H;
|
|
442
|
+
// Temp arrays to avoid allocation in hot path
|
|
443
|
+
X = new Float32Array(4);
|
|
444
|
+
constructor(t, e, s) {
|
|
445
|
+
this.c = t, this.F = e, this.A = s, this.a = new L(e, s), this.q = this.I(
|
|
446
|
+
D,
|
|
447
|
+
I,
|
|
448
|
+
!1
|
|
449
|
+
), this.B = this.I(
|
|
450
|
+
M,
|
|
451
|
+
O,
|
|
452
|
+
!0
|
|
453
|
+
), this.r = t.createBuffer(), t.bindBuffer(t.ARRAY_BUFFER, this.r), t.bufferData(t.ARRAY_BUFFER, new Float32Array([
|
|
454
|
+
0,
|
|
455
|
+
0,
|
|
456
|
+
1,
|
|
457
|
+
0,
|
|
458
|
+
0,
|
|
459
|
+
1,
|
|
460
|
+
0,
|
|
461
|
+
1,
|
|
462
|
+
1,
|
|
463
|
+
0,
|
|
464
|
+
1,
|
|
465
|
+
1
|
|
466
|
+
]), t.STATIC_DRAW), this.C = t.createBuffer(), this.D = t.createBuffer(), this.s = t.createTexture(), t.bindTexture(t.TEXTURE_2D, this.s), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_MIN_FILTER, t.LINEAR), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_MAG_FILTER, t.LINEAR), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_WRAP_S, t.CLAMP_TO_EDGE), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_WRAP_T, t.CLAMP_TO_EDGE), this.b = new OffscreenCanvas(512, 128), this.H = this.b.getContext("2d"), t.enable(t.BLEND), t.blendFunc(t.SRC_ALPHA, t.ONE_MINUS_SRC_ALPHA);
|
|
467
|
+
}
|
|
468
|
+
/**
|
|
469
|
+
* Execute a batch of Canvas 2D commands as WebGL draw calls.
|
|
470
|
+
* No _ prefix: called cross-file from webgl-renderer.
|
|
471
|
+
*/
|
|
472
|
+
executeBatch(t) {
|
|
473
|
+
for (const e of t)
|
|
474
|
+
e.type === "property" ? this.L(e.name, e.value) : this.M(e.name, e.args);
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Update canvas dimensions on resize.
|
|
478
|
+
* No _ prefix: called cross-file.
|
|
479
|
+
*/
|
|
480
|
+
resize(t, e) {
|
|
481
|
+
this.F = t, this.A = e, this.a.resize(t, e);
|
|
482
|
+
}
|
|
483
|
+
/**
|
|
484
|
+
* Clean up WebGL resources.
|
|
485
|
+
* No _ prefix: called cross-file.
|
|
486
|
+
*/
|
|
487
|
+
destroy() {
|
|
488
|
+
const t = this.c;
|
|
489
|
+
t.deleteBuffer(this.r), t.deleteBuffer(this.C), t.deleteBuffer(this.D), t.deleteTexture(this.s), t.deleteProgram(this.q.n), t.deleteProgram(this.B.n);
|
|
490
|
+
}
|
|
491
|
+
// -------------------------------------------------------------------------
|
|
492
|
+
// Private: property handling
|
|
493
|
+
// -------------------------------------------------------------------------
|
|
494
|
+
L(t, e) {
|
|
495
|
+
switch (t) {
|
|
496
|
+
case "fillStyle":
|
|
497
|
+
this.i = g(e);
|
|
498
|
+
break;
|
|
499
|
+
case "strokeStyle":
|
|
500
|
+
this.d = g(e);
|
|
501
|
+
break;
|
|
502
|
+
case "lineWidth":
|
|
503
|
+
this.f = e;
|
|
504
|
+
break;
|
|
505
|
+
case "globalAlpha":
|
|
506
|
+
this.e = e;
|
|
507
|
+
break;
|
|
508
|
+
case "font":
|
|
509
|
+
this.g = e;
|
|
510
|
+
break;
|
|
511
|
+
case "textAlign":
|
|
512
|
+
this.j = e;
|
|
513
|
+
break;
|
|
514
|
+
case "textBaseline":
|
|
515
|
+
this.k = e;
|
|
516
|
+
break;
|
|
517
|
+
case "lineCap":
|
|
518
|
+
this.o = e;
|
|
519
|
+
break;
|
|
520
|
+
case "lineJoin":
|
|
521
|
+
this.p = e;
|
|
522
|
+
break;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
// -------------------------------------------------------------------------
|
|
526
|
+
// Private: method dispatch
|
|
527
|
+
// -------------------------------------------------------------------------
|
|
528
|
+
M(t, e) {
|
|
529
|
+
switch (t) {
|
|
530
|
+
// Rectangles
|
|
531
|
+
case "clearRect":
|
|
532
|
+
this.N(e[0], e[1], e[2], e[3]);
|
|
533
|
+
break;
|
|
534
|
+
case "fillRect":
|
|
535
|
+
this.O(e[0], e[1], e[2], e[3]);
|
|
536
|
+
break;
|
|
537
|
+
case "strokeRect":
|
|
538
|
+
this.P(e[0], e[1], e[2], e[3]);
|
|
539
|
+
break;
|
|
540
|
+
// Text
|
|
541
|
+
case "fillText":
|
|
542
|
+
this.Q(e[0], e[1], e[2]);
|
|
543
|
+
break;
|
|
544
|
+
case "strokeText":
|
|
545
|
+
this.R(e[0], e[1], e[2]);
|
|
546
|
+
break;
|
|
547
|
+
// Path
|
|
548
|
+
case "beginPath":
|
|
549
|
+
this.t = [];
|
|
550
|
+
break;
|
|
551
|
+
case "closePath":
|
|
552
|
+
(this.l !== this.u || this.m !== this.v) && (this.t.push(
|
|
553
|
+
this.l,
|
|
554
|
+
this.m,
|
|
555
|
+
this.u,
|
|
556
|
+
this.v
|
|
557
|
+
), this.l = this.u, this.m = this.v);
|
|
558
|
+
break;
|
|
559
|
+
case "moveTo":
|
|
560
|
+
this.l = this.u = e[0], this.m = this.v = e[1];
|
|
561
|
+
break;
|
|
562
|
+
case "lineTo": {
|
|
563
|
+
const s = e[0], i = e[1];
|
|
564
|
+
this.t.push(this.l, this.m, s, i), this.l = s, this.m = i;
|
|
565
|
+
break;
|
|
566
|
+
}
|
|
567
|
+
case "stroke":
|
|
568
|
+
this.S();
|
|
569
|
+
break;
|
|
570
|
+
case "fill":
|
|
571
|
+
break;
|
|
572
|
+
// State
|
|
573
|
+
case "save":
|
|
574
|
+
this.T();
|
|
575
|
+
break;
|
|
576
|
+
case "restore":
|
|
577
|
+
this.U();
|
|
578
|
+
break;
|
|
579
|
+
// Transforms
|
|
580
|
+
case "translate":
|
|
581
|
+
this.a.translate(e[0], e[1]);
|
|
582
|
+
break;
|
|
583
|
+
case "rotate":
|
|
584
|
+
this.a.rotate(e[0]);
|
|
585
|
+
break;
|
|
586
|
+
case "scale":
|
|
587
|
+
this.a.scale(e[0], e[1]);
|
|
588
|
+
break;
|
|
589
|
+
case "transform":
|
|
590
|
+
this.a.transform(
|
|
591
|
+
e[0],
|
|
592
|
+
e[1],
|
|
593
|
+
e[2],
|
|
594
|
+
e[3],
|
|
595
|
+
e[4],
|
|
596
|
+
e[5]
|
|
597
|
+
);
|
|
598
|
+
break;
|
|
599
|
+
case "setTransform":
|
|
600
|
+
this.a.setTransform(
|
|
601
|
+
e[0],
|
|
602
|
+
e[1],
|
|
603
|
+
e[2],
|
|
604
|
+
e[3],
|
|
605
|
+
e[4],
|
|
606
|
+
e[5]
|
|
607
|
+
);
|
|
608
|
+
break;
|
|
609
|
+
case "resetTransform":
|
|
610
|
+
this.a.resetTransform();
|
|
611
|
+
break;
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
// -------------------------------------------------------------------------
|
|
615
|
+
// Private: drawing operations
|
|
616
|
+
// -------------------------------------------------------------------------
|
|
617
|
+
N(t, e, s, i) {
|
|
618
|
+
const r = this.c;
|
|
619
|
+
r.enable(r.SCISSOR_TEST), r.scissor(t, this.A - e - i, s, i), r.clearColor(0, 0, 0, 0), r.clear(r.COLOR_BUFFER_BIT), r.disable(r.SCISSOR_TEST);
|
|
620
|
+
}
|
|
621
|
+
O(t, e, s, i) {
|
|
622
|
+
const r = this.c, a = this.q;
|
|
623
|
+
r.useProgram(a.n), this.a.save(), this.a.translate(t, e), this.a.scale(s, i), r.uniformMatrix3fv(a.w, !1, this.a.getMatrix()), this.x(a.y, this.i, this.e), this.a.restore(), r.bindBuffer(r.ARRAY_BUFFER, this.r), r.enableVertexAttribArray(a.h), r.vertexAttribPointer(a.h, 2, r.FLOAT, !1, 0, 0), r.drawArrays(r.TRIANGLES, 0, 6);
|
|
624
|
+
}
|
|
625
|
+
P(t, e, s, i) {
|
|
626
|
+
const r = this.f, a = r / 2;
|
|
627
|
+
this.z(t - a, e - a, s + r, r, this.d), this.z(t - a, e + i - a, s + r, r, this.d), this.z(t - a, e + a, r, i - r, this.d), this.z(t + s - a, e + a, r, i - r, this.d);
|
|
628
|
+
}
|
|
629
|
+
/** Internal: draw a filled rect with a specific color (used by strokeRect). */
|
|
630
|
+
z(t, e, s, i, r) {
|
|
631
|
+
const a = this.c, h = this.q;
|
|
632
|
+
a.useProgram(h.n), this.a.save(), this.a.translate(t, e), this.a.scale(s, i), a.uniformMatrix3fv(h.w, !1, this.a.getMatrix()), this.x(h.y, r, this.e), this.a.restore(), a.bindBuffer(a.ARRAY_BUFFER, this.r), a.enableVertexAttribArray(h.h), a.vertexAttribPointer(h.h, 2, a.FLOAT, !1, 0, 0), a.drawArrays(a.TRIANGLES, 0, 6);
|
|
633
|
+
}
|
|
634
|
+
S() {
|
|
635
|
+
const t = this.t;
|
|
636
|
+
if (t.length === 0) return;
|
|
637
|
+
const e = this.c, s = this.q, i = Math.max(this.f / 2, 0.5), r = t.length / 4, a = new Float32Array(r * 12);
|
|
638
|
+
for (let h = 0, o = 0; h < t.length; h += 4) {
|
|
639
|
+
const c = t[h], l = t[h + 1], f = t[h + 2], b = t[h + 3], u = f - c, m = b - l, E = Math.sqrt(u * u + m * m);
|
|
640
|
+
if (E < 1e-3) continue;
|
|
641
|
+
const d = -m / E * i, A = u / E * i, S = c + d, w = l + A, T = c - d, R = l - A, _ = f + d, p = b + A, C = f - d, P = b - A;
|
|
642
|
+
a[o++] = S, a[o++] = w, a[o++] = T, a[o++] = R, a[o++] = _, a[o++] = p, a[o++] = T, a[o++] = R, a[o++] = C, a[o++] = P, a[o++] = _, a[o++] = p;
|
|
643
|
+
}
|
|
644
|
+
e.bindBuffer(e.ARRAY_BUFFER, this.C), e.bufferData(e.ARRAY_BUFFER, a, e.DYNAMIC_DRAW), e.useProgram(s.n), e.uniformMatrix3fv(s.w, !1, this.a.getMatrix()), this.x(s.y, this.d, this.e), e.enableVertexAttribArray(s.h), e.vertexAttribPointer(s.h, 2, e.FLOAT, !1, 0, 0), e.drawArrays(e.TRIANGLES, 0, r * 6);
|
|
645
|
+
}
|
|
646
|
+
Q(t, e, s) {
|
|
647
|
+
this.J(t, e, s, "fill");
|
|
648
|
+
}
|
|
649
|
+
R(t, e, s) {
|
|
650
|
+
this.J(t, e, s, "stroke");
|
|
651
|
+
}
|
|
652
|
+
J(t, e, s, i) {
|
|
653
|
+
const r = this.c, a = this.H;
|
|
654
|
+
a.font = this.g, a.textAlign = "left", a.textBaseline = "top";
|
|
655
|
+
const h = a.measureText(t), o = Math.ceil(h.width) + 4, c = H(this.g), l = Math.ceil(c * 1.5) + 4;
|
|
656
|
+
if (o <= 0 || l <= 0) return;
|
|
657
|
+
(this.b.width < o || this.b.height < l) && (this.b.width = Math.max(this.b.width, o), this.b.height = Math.max(this.b.height, l), a.font = this.g, a.textAlign = "left", a.textBaseline = "top"), a.clearRect(0, 0, this.b.width, this.b.height), i === "fill" ? (a.fillStyle = "white", a.fillText(t, 2, 2)) : (a.strokeStyle = "white", a.lineWidth = this.f, a.strokeText(t, 2, 2)), r.bindTexture(r.TEXTURE_2D, this.s), r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 1), r.texImage2D(
|
|
658
|
+
r.TEXTURE_2D,
|
|
659
|
+
0,
|
|
660
|
+
r.RGBA,
|
|
661
|
+
r.RGBA,
|
|
662
|
+
r.UNSIGNED_BYTE,
|
|
663
|
+
this.b
|
|
664
|
+
), r.pixelStorei(r.UNPACK_PREMULTIPLY_ALPHA_WEBGL, 0);
|
|
665
|
+
const f = i === "fill" ? this.i : this.d;
|
|
666
|
+
let b = e - 2, u = s - 2;
|
|
667
|
+
switch (this.j) {
|
|
668
|
+
case "center":
|
|
669
|
+
b -= o / 2;
|
|
670
|
+
break;
|
|
671
|
+
case "right":
|
|
672
|
+
case "end":
|
|
673
|
+
b -= o;
|
|
674
|
+
break;
|
|
675
|
+
}
|
|
676
|
+
switch (this.k) {
|
|
677
|
+
case "top":
|
|
678
|
+
break;
|
|
679
|
+
case "middle":
|
|
680
|
+
u -= l / 2;
|
|
681
|
+
break;
|
|
682
|
+
case "alphabetic":
|
|
683
|
+
case "ideographic":
|
|
684
|
+
u -= c;
|
|
685
|
+
break;
|
|
686
|
+
case "bottom":
|
|
687
|
+
case "hanging":
|
|
688
|
+
u -= l;
|
|
689
|
+
break;
|
|
690
|
+
}
|
|
691
|
+
this.V(
|
|
692
|
+
b,
|
|
693
|
+
u,
|
|
694
|
+
o,
|
|
695
|
+
l,
|
|
696
|
+
o / this.b.width,
|
|
697
|
+
l / this.b.height,
|
|
698
|
+
f
|
|
699
|
+
);
|
|
700
|
+
}
|
|
701
|
+
V(t, e, s, i, r, a, h) {
|
|
702
|
+
const o = this.c, c = this.B, l = new Float32Array([
|
|
703
|
+
t,
|
|
704
|
+
e,
|
|
705
|
+
0,
|
|
706
|
+
0,
|
|
707
|
+
t + s,
|
|
708
|
+
e,
|
|
709
|
+
r,
|
|
710
|
+
0,
|
|
711
|
+
t,
|
|
712
|
+
e + i,
|
|
713
|
+
0,
|
|
714
|
+
a,
|
|
715
|
+
t,
|
|
716
|
+
e + i,
|
|
717
|
+
0,
|
|
718
|
+
a,
|
|
719
|
+
t + s,
|
|
720
|
+
e,
|
|
721
|
+
r,
|
|
722
|
+
0,
|
|
723
|
+
t + s,
|
|
724
|
+
e + i,
|
|
725
|
+
r,
|
|
726
|
+
a
|
|
727
|
+
]);
|
|
728
|
+
o.bindBuffer(o.ARRAY_BUFFER, this.D), o.bufferData(o.ARRAY_BUFFER, l, o.DYNAMIC_DRAW), o.useProgram(c.n), o.uniformMatrix3fv(c.w, !1, this.a.getMatrix()), this.x(c.y, h, this.e), o.blendFunc(o.ONE, o.ONE_MINUS_SRC_ALPHA);
|
|
729
|
+
const f = 16;
|
|
730
|
+
o.enableVertexAttribArray(c.h), o.vertexAttribPointer(c.h, 2, o.FLOAT, !1, f, 0), o.enableVertexAttribArray(c.E), o.vertexAttribPointer(c.E, 2, o.FLOAT, !1, f, 8), o.activeTexture(o.TEXTURE0), o.bindTexture(o.TEXTURE_2D, this.s), o.uniform1i(c.W, 0), o.drawArrays(o.TRIANGLES, 0, 6), o.blendFunc(o.SRC_ALPHA, o.ONE_MINUS_SRC_ALPHA), o.disableVertexAttribArray(c.E);
|
|
731
|
+
}
|
|
732
|
+
// -------------------------------------------------------------------------
|
|
733
|
+
// Private: state management
|
|
734
|
+
// -------------------------------------------------------------------------
|
|
735
|
+
T() {
|
|
736
|
+
this.a.save(), this.G.push({
|
|
737
|
+
i: new Float32Array(this.i),
|
|
738
|
+
d: new Float32Array(this.d),
|
|
739
|
+
f: this.f,
|
|
740
|
+
e: this.e,
|
|
741
|
+
g: this.g,
|
|
742
|
+
j: this.j,
|
|
743
|
+
k: this.k,
|
|
744
|
+
o: this.o,
|
|
745
|
+
p: this.p
|
|
746
|
+
});
|
|
747
|
+
}
|
|
748
|
+
U() {
|
|
749
|
+
this.a.restore();
|
|
750
|
+
const t = this.G.pop();
|
|
751
|
+
t && (this.i = t.i, this.d = t.d, this.f = t.f, this.e = t.e, this.g = t.g, this.j = t.j, this.k = t.k, this.o = t.o, this.p = t.p);
|
|
752
|
+
}
|
|
753
|
+
// -------------------------------------------------------------------------
|
|
754
|
+
// Private: WebGL helpers
|
|
755
|
+
// -------------------------------------------------------------------------
|
|
756
|
+
x(t, e, s) {
|
|
757
|
+
const i = e[3] * s;
|
|
758
|
+
this.c.uniform4f(t, e[0], e[1], e[2], i);
|
|
759
|
+
}
|
|
760
|
+
I(t, e, s) {
|
|
761
|
+
const i = this.c, r = this.K(i.VERTEX_SHADER, t), a = this.K(i.FRAGMENT_SHADER, e), h = i.createProgram();
|
|
762
|
+
if (i.attachShader(h, r), i.attachShader(h, a), i.linkProgram(h), !i.getProgramParameter(h, i.LINK_STATUS))
|
|
763
|
+
throw new Error("Shader link failed: " + i.getProgramInfoLog(h));
|
|
764
|
+
return i.deleteShader(r), i.deleteShader(a), {
|
|
765
|
+
n: h,
|
|
766
|
+
w: i.getUniformLocation(h, "u_matrix"),
|
|
767
|
+
y: i.getUniformLocation(h, "u_color"),
|
|
768
|
+
W: s ? i.getUniformLocation(h, "u_texture") : null,
|
|
769
|
+
h: i.getAttribLocation(h, "a_position"),
|
|
770
|
+
E: s ? i.getAttribLocation(h, "a_texCoord") : -1
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
K(t, e) {
|
|
774
|
+
const s = this.c, i = s.createShader(t);
|
|
775
|
+
if (s.shaderSource(i, e), s.compileShader(i), !s.getShaderParameter(i, s.COMPILE_STATUS)) {
|
|
776
|
+
const r = s.getShaderInfoLog(i);
|
|
777
|
+
throw s.deleteShader(i), new Error("Shader compile failed: " + r);
|
|
778
|
+
}
|
|
779
|
+
return i;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
function H(n) {
|
|
783
|
+
const t = n.match(/(\d+(?:\.\d+)?)\s*px/);
|
|
784
|
+
return t ? parseFloat(t[1]) : 10;
|
|
785
|
+
}
|
|
786
|
+
class W {
|
|
787
|
+
b;
|
|
788
|
+
a;
|
|
789
|
+
h;
|
|
790
|
+
i;
|
|
791
|
+
d = null;
|
|
792
|
+
// Triple buffer: three FBOs with color texture attachments
|
|
793
|
+
c;
|
|
794
|
+
j = 0;
|
|
795
|
+
e = 1;
|
|
796
|
+
w = 2;
|
|
797
|
+
o = !1;
|
|
798
|
+
// Display program
|
|
799
|
+
f;
|
|
800
|
+
// Fullscreen quad VBO
|
|
801
|
+
g;
|
|
802
|
+
k = -1;
|
|
803
|
+
constructor(t) {
|
|
804
|
+
this.a = t, this.i = new v();
|
|
805
|
+
const e = t.getContext("webgl2", {
|
|
806
|
+
alpha: !1,
|
|
807
|
+
antialias: !1,
|
|
808
|
+
desynchronized: !0,
|
|
809
|
+
preserveDrawingBuffer: !0,
|
|
810
|
+
powerPreference: "high-performance"
|
|
811
|
+
});
|
|
812
|
+
if (!e)
|
|
813
|
+
throw new Error("WebGL2 not supported");
|
|
814
|
+
this.b = e, e.pixelStorei(e.UNPACK_PREMULTIPLY_ALPHA_WEBGL, !1), this.s(), this.h = new G(e, t.width, t.height), this.f = this.t(
|
|
815
|
+
N,
|
|
816
|
+
X
|
|
817
|
+
), this.u(), this.v(), this.startDisplay();
|
|
818
|
+
}
|
|
819
|
+
// -------------------------------------------------------------------------
|
|
820
|
+
// Public API (no _ prefix: cross-file access safe from mangleProps)
|
|
821
|
+
// -------------------------------------------------------------------------
|
|
822
|
+
/** Get the CanvasAPI for recording draw commands. */
|
|
823
|
+
getCanvasAPI() {
|
|
824
|
+
return this.i;
|
|
825
|
+
}
|
|
826
|
+
/**
|
|
827
|
+
* Submit a batch of Canvas 2D commands to be rendered into the write FBO.
|
|
828
|
+
* After rendering, the write and ready FBOs are swapped so the display
|
|
829
|
+
* loop picks up the latest frame.
|
|
830
|
+
*/
|
|
831
|
+
submitBatch(t) {
|
|
832
|
+
if (t.length === 0) return;
|
|
833
|
+
const e = this.b;
|
|
834
|
+
e.bindFramebuffer(e.FRAMEBUFFER, this.c[this.j].l), e.viewport(0, 0, this.a.width, this.a.height), this.h.executeBatch(t);
|
|
835
|
+
const s = this.j;
|
|
836
|
+
this.j = this.e, this.e = s, this.o = !0;
|
|
837
|
+
}
|
|
838
|
+
/** Start the passthrough RAF display loop with auto-flush. */
|
|
839
|
+
startDisplay() {
|
|
840
|
+
this.d === null && this.p();
|
|
841
|
+
}
|
|
842
|
+
/** Stop the passthrough RAF display loop. Last frame persists (preserveDrawingBuffer). */
|
|
843
|
+
stopDisplay() {
|
|
844
|
+
this.d !== null && (cancelAnimationFrame(this.d), this.d = null);
|
|
845
|
+
}
|
|
846
|
+
/** Returns the display canvas element. */
|
|
847
|
+
getCanvas() {
|
|
848
|
+
return this.a;
|
|
849
|
+
}
|
|
850
|
+
/** Get canvas dimensions. */
|
|
851
|
+
getCanvasSize() {
|
|
852
|
+
return { width: this.a.width, height: this.a.height };
|
|
853
|
+
}
|
|
854
|
+
/** Capture the current displayed frame as an ImageBitmap. */
|
|
855
|
+
screenshot() {
|
|
856
|
+
return this.q(), createImageBitmap(this.a);
|
|
857
|
+
}
|
|
858
|
+
/** Clean up all WebGL resources. */
|
|
859
|
+
destroy() {
|
|
860
|
+
this.stopDisplay();
|
|
861
|
+
const t = this.b;
|
|
862
|
+
this.h.destroy();
|
|
863
|
+
for (const s of this.c)
|
|
864
|
+
t.deleteFramebuffer(s.l), t.deleteTexture(s.m);
|
|
865
|
+
t.deleteProgram(this.f), t.deleteBuffer(this.g);
|
|
866
|
+
const e = t.getExtension("WEBGL_lose_context");
|
|
867
|
+
e && e.loseContext();
|
|
868
|
+
}
|
|
869
|
+
// -------------------------------------------------------------------------
|
|
870
|
+
// Extension points (used by maalata CRT display)
|
|
871
|
+
// -------------------------------------------------------------------------
|
|
872
|
+
/** Returns the WebGL2 context for external rendering (e.g. CRT shader). */
|
|
873
|
+
getGL() {
|
|
874
|
+
return this.b;
|
|
875
|
+
}
|
|
876
|
+
/** Returns the ready FBO's texture — the latest fully rendered frame. */
|
|
877
|
+
getReadyTexture() {
|
|
878
|
+
return this.c[this.e].m;
|
|
879
|
+
}
|
|
880
|
+
// -------------------------------------------------------------------------
|
|
881
|
+
// Private: display loop
|
|
882
|
+
// -------------------------------------------------------------------------
|
|
883
|
+
p() {
|
|
884
|
+
this.d = requestAnimationFrame(() => this.p());
|
|
885
|
+
const t = this.i.takeCommands();
|
|
886
|
+
t.length && this.submitBatch(t), this.q();
|
|
887
|
+
}
|
|
888
|
+
/**
|
|
889
|
+
* Render the ready FBO to the display canvas via passthrough shader.
|
|
890
|
+
* Called at vsync rate by RAF, or once synchronously for screenshots.
|
|
891
|
+
*/
|
|
892
|
+
q() {
|
|
893
|
+
if (!this.o) return;
|
|
894
|
+
const t = this.b;
|
|
895
|
+
t.bindFramebuffer(t.FRAMEBUFFER, null), t.viewport(0, 0, this.a.width, this.a.height), t.activeTexture(t.TEXTURE0), t.bindTexture(t.TEXTURE_2D, this.c[this.e].m), t.useProgram(this.f), t.bindBuffer(t.ARRAY_BUFFER, this.g), t.enableVertexAttribArray(this.k), t.vertexAttribPointer(this.k, 2, t.FLOAT, !1, 0, 0), t.disable(t.BLEND), t.drawArrays(t.TRIANGLES, 0, 6), t.enable(t.BLEND);
|
|
896
|
+
}
|
|
897
|
+
// -------------------------------------------------------------------------
|
|
898
|
+
// Private: initialization
|
|
899
|
+
// -------------------------------------------------------------------------
|
|
900
|
+
s() {
|
|
901
|
+
this.c = [
|
|
902
|
+
this.n(),
|
|
903
|
+
this.n(),
|
|
904
|
+
this.n()
|
|
905
|
+
];
|
|
906
|
+
}
|
|
907
|
+
n() {
|
|
908
|
+
const t = this.b, e = this.a.width, s = this.a.height, i = t.createFramebuffer();
|
|
909
|
+
t.bindFramebuffer(t.FRAMEBUFFER, i);
|
|
910
|
+
const r = t.createTexture();
|
|
911
|
+
t.bindTexture(t.TEXTURE_2D, r), t.texStorage2D(t.TEXTURE_2D, 1, t.RGBA8, e, s), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_MIN_FILTER, t.LINEAR), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_MAG_FILTER, t.LINEAR), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_WRAP_S, t.CLAMP_TO_EDGE), t.texParameteri(t.TEXTURE_2D, t.TEXTURE_WRAP_T, t.CLAMP_TO_EDGE), t.framebufferTexture2D(t.FRAMEBUFFER, t.COLOR_ATTACHMENT0, t.TEXTURE_2D, r, 0);
|
|
912
|
+
const a = t.checkFramebufferStatus(t.FRAMEBUFFER);
|
|
913
|
+
if (a !== t.FRAMEBUFFER_COMPLETE)
|
|
914
|
+
throw new Error("Framebuffer incomplete: 0x" + a.toString(16));
|
|
915
|
+
return t.bindFramebuffer(t.FRAMEBUFFER, null), { l: i, m: r };
|
|
916
|
+
}
|
|
917
|
+
v() {
|
|
918
|
+
const t = this.b;
|
|
919
|
+
for (const e of this.c)
|
|
920
|
+
t.bindFramebuffer(t.FRAMEBUFFER, e.l), t.clearColor(0, 0, 0, 1), t.clear(t.COLOR_BUFFER_BIT);
|
|
921
|
+
t.bindFramebuffer(t.FRAMEBUFFER, null), t.clearColor(0, 0, 0, 1), t.clear(t.COLOR_BUFFER_BIT);
|
|
922
|
+
}
|
|
923
|
+
u() {
|
|
924
|
+
const t = this.b;
|
|
925
|
+
this.g = t.createBuffer(), t.bindBuffer(t.ARRAY_BUFFER, this.g), t.bufferData(t.ARRAY_BUFFER, new Float32Array([
|
|
926
|
+
0,
|
|
927
|
+
0,
|
|
928
|
+
1,
|
|
929
|
+
0,
|
|
930
|
+
0,
|
|
931
|
+
1,
|
|
932
|
+
0,
|
|
933
|
+
1,
|
|
934
|
+
1,
|
|
935
|
+
0,
|
|
936
|
+
1,
|
|
937
|
+
1
|
|
938
|
+
]), t.STATIC_DRAW), this.k = t.getAttribLocation(this.f, "a_position");
|
|
939
|
+
}
|
|
940
|
+
// -------------------------------------------------------------------------
|
|
941
|
+
// Private: shader helpers
|
|
942
|
+
// -------------------------------------------------------------------------
|
|
943
|
+
t(t, e) {
|
|
944
|
+
const s = this.b, i = this.r(s.VERTEX_SHADER, t), r = this.r(s.FRAGMENT_SHADER, e), a = s.createProgram();
|
|
945
|
+
if (s.attachShader(a, i), s.attachShader(a, r), s.linkProgram(a), !s.getProgramParameter(a, s.LINK_STATUS))
|
|
946
|
+
throw new Error("Shader link failed: " + s.getProgramInfoLog(a));
|
|
947
|
+
return s.deleteShader(i), s.deleteShader(r), a;
|
|
948
|
+
}
|
|
949
|
+
r(t, e) {
|
|
950
|
+
const s = this.b, i = s.createShader(t);
|
|
951
|
+
if (s.shaderSource(i, e), s.compileShader(i), !s.getShaderParameter(i, s.COMPILE_STATUS)) {
|
|
952
|
+
const r = s.getShaderInfoLog(i);
|
|
953
|
+
throw s.deleteShader(i), new Error("Shader compile failed: " + r);
|
|
954
|
+
}
|
|
955
|
+
return i;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
export {
|
|
959
|
+
v as CanvasAPI,
|
|
960
|
+
L as MatrixStack,
|
|
961
|
+
W as UltrafastRenderer,
|
|
962
|
+
g as parseColor
|
|
963
|
+
};
|