textmode.js 0.1.4-beta.1 → 0.1.4-beta.3
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/dist/textmode.esm.js +655 -357
- package/dist/textmode.esm.min.js +732 -434
- package/dist/textmode.umd.js +6 -6
- package/dist/textmode.umd.min.js +12 -12
- package/dist/types/Textmode.d.ts +14 -0
- package/dist/types/rendering/webgl/Framebuffer.d.ts +9 -0
- package/dist/types/rendering/webgl/Renderer.d.ts +9 -0
- package/dist/types/rendering/webgl/Shader.d.ts +9 -0
- package/dist/types/textmode/Canvas.d.ts +9 -0
- package/dist/types/textmode/ConversionPipeline.d.ts +9 -0
- package/dist/types/textmode/Grid.d.ts +9 -0
- package/dist/types/textmode/Textmodifier.d.ts +117 -0
- package/dist/types/textmode/converters/Converter.d.ts +9 -0
- package/dist/types/textmode/font/TextmodeFont.d.ts +9 -0
- package/package.json +2 -2
package/dist/textmode.esm.min.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
var se = Object.defineProperty;
|
|
2
|
-
var
|
|
3
|
-
var
|
|
2
|
+
var oe = (h, e, t) => e in h ? se(h, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : h[e] = t;
|
|
3
|
+
var a = (h, e, t) => oe(h, typeof e != "symbol" ? e + "" : e, t);
|
|
4
4
|
class F extends Error {
|
|
5
5
|
constructor(t, r, i = {}) {
|
|
6
6
|
const s = F.createFormattedMessage(t, i);
|
|
7
7
|
super(s);
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
a(this, "originalError");
|
|
9
|
+
a(this, "context");
|
|
10
10
|
this.name = "TextmodeError", this.originalError = r, this.context = i;
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
@@ -18,8 +18,8 @@ class F extends Error {
|
|
|
18
18
|
i += `
|
|
19
19
|
|
|
20
20
|
📋 Context:`;
|
|
21
|
-
for (const [s,
|
|
22
|
-
const n = F.formatValue(
|
|
21
|
+
for (const [s, o] of Object.entries(r)) {
|
|
22
|
+
const n = F.formatValue(o);
|
|
23
23
|
i += `
|
|
24
24
|
- ${s}: ${n}`;
|
|
25
25
|
}
|
|
@@ -41,15 +41,15 @@ class F extends Error {
|
|
|
41
41
|
return t.length === 0 ? "[]" : t.length <= 5 ? `[${t.map((r) => F.formatValue(r)).join(", ")}]` : `[${t.slice(0, 3).map((r) => F.formatValue(r)).join(", ")}, ... +${t.length - 3} more]`;
|
|
42
42
|
if (typeof t == "object") {
|
|
43
43
|
const r = Object.keys(t);
|
|
44
|
-
return r.length === 0 ? "{}" : r.length <= 3 ? `{ ${r.map((
|
|
44
|
+
return r.length === 0 ? "{}" : r.length <= 3 ? `{ ${r.map((o) => `${o}: ${F.formatValue(t[o])}`).join(", ")} }` : `{ ${r.slice(0, 2).map((s) => `${s}: ${F.formatValue(t[s])}`).join(", ")}, ... +${r.length - 2} more }`;
|
|
45
45
|
}
|
|
46
46
|
return String(t);
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
-
var ne = /* @__PURE__ */ ((
|
|
49
|
+
var ne = /* @__PURE__ */ ((h) => (h[h.SILENT = 0] = "SILENT", h[h.WARNING = 1] = "WARNING", h[h.ERROR = 2] = "ERROR", h[h.THROW = 3] = "THROW", h))(ne || {});
|
|
50
50
|
const E = class E {
|
|
51
51
|
constructor() {
|
|
52
|
-
|
|
52
|
+
a(this, "_options", {
|
|
53
53
|
globalLevel: 3
|
|
54
54
|
/* THROW */
|
|
55
55
|
});
|
|
@@ -103,19 +103,19 @@ const E = class E {
|
|
|
103
103
|
this._options.globalLevel = e;
|
|
104
104
|
}
|
|
105
105
|
};
|
|
106
|
-
|
|
107
|
-
let
|
|
108
|
-
const x =
|
|
109
|
-
class
|
|
106
|
+
a(E, "_instance", null);
|
|
107
|
+
let $ = E;
|
|
108
|
+
const x = $.getInstance();
|
|
109
|
+
class ae {
|
|
110
110
|
constructor(e, t, r = t, i = {}) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
111
|
+
a(this, "gl");
|
|
112
|
+
a(this, "_framebuffer");
|
|
113
|
+
a(this, "_texture");
|
|
114
|
+
a(this, "_width");
|
|
115
|
+
a(this, "_height");
|
|
116
|
+
a(this, "options");
|
|
117
|
+
a(this, "previousState", null);
|
|
118
|
+
a(this, "_pixels", null);
|
|
119
119
|
this.gl = e, this._width = t, this._height = r, this.options = {
|
|
120
120
|
filter: "nearest",
|
|
121
121
|
wrap: "clamp",
|
|
@@ -189,18 +189,32 @@ class oe {
|
|
|
189
189
|
get(e, t, r, i) {
|
|
190
190
|
const { gl: s } = this;
|
|
191
191
|
if (e === void 0 && t === void 0) {
|
|
192
|
-
const
|
|
193
|
-
return s.bindFramebuffer(s.FRAMEBUFFER, this._framebuffer), s.readPixels(0, 0, this._width, this._height, s.RGBA, s.UNSIGNED_BYTE,
|
|
192
|
+
const o = new Uint8Array(this._width * this._height * 4), n = s.getParameter(s.FRAMEBUFFER_BINDING);
|
|
193
|
+
return s.bindFramebuffer(s.FRAMEBUFFER, this._framebuffer), s.readPixels(0, 0, this._width, this._height, s.RGBA, s.UNSIGNED_BYTE, o), s.bindFramebuffer(s.FRAMEBUFFER, n), o;
|
|
194
194
|
} else if (r === void 0 && i === void 0) {
|
|
195
195
|
(e < 0 || t < 0 || e >= this._width || t >= this._height) && (console.warn("The x and y values passed to Framebuffer.get are outside of its range and will be clamped."), e = Math.max(0, Math.min(e, this._width - 1)), t = Math.max(0, Math.min(t, this._height - 1)));
|
|
196
|
-
const
|
|
197
|
-
return s.bindFramebuffer(s.FRAMEBUFFER, this._framebuffer), s.readPixels(e, t, 1, 1, s.RGBA, s.UNSIGNED_BYTE,
|
|
196
|
+
const o = new Uint8Array(4), n = s.getParameter(s.FRAMEBUFFER_BINDING);
|
|
197
|
+
return s.bindFramebuffer(s.FRAMEBUFFER, this._framebuffer), s.readPixels(e, t, 1, 1, s.RGBA, s.UNSIGNED_BYTE, o), s.bindFramebuffer(s.FRAMEBUFFER, n), [o[0], o[1], o[2], o[3]];
|
|
198
198
|
} else {
|
|
199
199
|
e = Math.max(0, Math.min(e, this._width - 1)), t = Math.max(0, Math.min(t, this._height - 1)), r = Math.max(1, Math.min(r, this._width - e)), i = Math.max(1, Math.min(i, this._height - t));
|
|
200
|
-
const
|
|
201
|
-
return s.bindFramebuffer(s.FRAMEBUFFER, this._framebuffer), s.readPixels(e, t, r, i, s.RGBA, s.UNSIGNED_BYTE,
|
|
200
|
+
const o = new Uint8Array(r * i * 4), n = s.getParameter(s.FRAMEBUFFER_BINDING);
|
|
201
|
+
return s.bindFramebuffer(s.FRAMEBUFFER, this._framebuffer), s.readPixels(e, t, r, i, s.RGBA, s.UNSIGNED_BYTE, o), s.bindFramebuffer(s.FRAMEBUFFER, n), o;
|
|
202
202
|
}
|
|
203
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* Dispose of WebGL resources used by this framebuffer.
|
|
206
|
+
* This method is idempotent and safe to call multiple times.
|
|
207
|
+
*/
|
|
208
|
+
dispose() {
|
|
209
|
+
const { gl: e } = this;
|
|
210
|
+
this._framebuffer && (e.deleteFramebuffer(this._framebuffer), this._framebuffer = null), this._texture && (e.deleteTexture(this._texture), this._texture = null), this._pixels = null;
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Check if this framebuffer has been disposed
|
|
214
|
+
*/
|
|
215
|
+
get isDisposed() {
|
|
216
|
+
return this._framebuffer === null || this._texture === null;
|
|
217
|
+
}
|
|
204
218
|
get framebuffer() {
|
|
205
219
|
return this._framebuffer;
|
|
206
220
|
}
|
|
@@ -219,29 +233,29 @@ class oe {
|
|
|
219
233
|
}
|
|
220
234
|
class Q {
|
|
221
235
|
constructor(e, t, r) {
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
236
|
+
a(this, "gl");
|
|
237
|
+
a(this, "x");
|
|
238
|
+
a(this, "y");
|
|
225
239
|
this.gl = e, this.x = t, this.y = r;
|
|
226
240
|
}
|
|
227
241
|
}
|
|
228
|
-
class
|
|
242
|
+
class A {
|
|
229
243
|
constructor(e, t, r, i, s) {
|
|
230
244
|
/** The WebGL rendering context */
|
|
231
|
-
|
|
245
|
+
a(this, "gl");
|
|
232
246
|
/** The vertex buffer containing position and texture coordinates */
|
|
233
|
-
|
|
247
|
+
a(this, "vertexBuffer");
|
|
234
248
|
/** The number of vertices in this geometry (always 6 for two triangles) */
|
|
235
|
-
|
|
249
|
+
a(this, "vertexCount", 6);
|
|
236
250
|
/** Bytes per vertex: depends on position format (vec2 vs vec3) */
|
|
237
|
-
|
|
251
|
+
a(this, "bytesPerVertex");
|
|
238
252
|
this.gl = e, this.bytesPerVertex = 16;
|
|
239
|
-
const
|
|
253
|
+
const o = e.getParameter(e.VIEWPORT), n = o[2], l = o[3], c = e.getParameter(e.FRAMEBUFFER_BINDING) !== null, u = t / n * 2 - 1, d = (t + i) / n * 2 - 1;
|
|
240
254
|
let f, g;
|
|
241
|
-
c ? (f = r /
|
|
242
|
-
let _,
|
|
243
|
-
|
|
244
|
-
const v = this.generateVertices(_,
|
|
255
|
+
c ? (f = r / l * 2 - 1, g = (r + s) / l * 2 - 1) : (f = 1 - r / l * 2, g = 1 - (r + s) / l * 2);
|
|
256
|
+
let p, _, b, C;
|
|
257
|
+
p = u, b = d, _ = f, C = g;
|
|
258
|
+
const v = this.generateVertices(p, _, b, C);
|
|
245
259
|
this.vertexBuffer = e.createBuffer(), e.bindBuffer(e.ARRAY_BUFFER, this.vertexBuffer), e.bufferData(e.ARRAY_BUFFER, v, e.STATIC_DRAW);
|
|
246
260
|
}
|
|
247
261
|
/**
|
|
@@ -292,18 +306,18 @@ class M {
|
|
|
292
306
|
this.gl.enableVertexAttribArray(t), this.gl.vertexAttribPointer(t, 2, this.gl.FLOAT, !1, this.bytesPerVertex, 0), this.gl.enableVertexAttribArray(r), this.gl.vertexAttribPointer(r, 2, this.gl.FLOAT, !1, this.bytesPerVertex, 8), this.gl.drawArrays(this.gl.TRIANGLES, 0, this.vertexCount), this.gl.disableVertexAttribArray(t), this.gl.disableVertexAttribArray(r);
|
|
293
307
|
}
|
|
294
308
|
}
|
|
295
|
-
class
|
|
296
|
-
constructor(t, r, i, s,
|
|
309
|
+
class he extends Q {
|
|
310
|
+
constructor(t, r, i, s, o) {
|
|
297
311
|
super(t, r, i);
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
this.width = s, this.height =
|
|
312
|
+
a(this, "width");
|
|
313
|
+
a(this, "height");
|
|
314
|
+
this.width = s, this.height = o;
|
|
301
315
|
}
|
|
302
316
|
/**
|
|
303
317
|
* Render the filled rectangle using the existing Rectangle geometry.
|
|
304
318
|
*/
|
|
305
319
|
renderFill() {
|
|
306
|
-
new
|
|
320
|
+
new A(this.gl, this.x, this.y, this.width, this.height).render();
|
|
307
321
|
}
|
|
308
322
|
/**
|
|
309
323
|
* Render the stroke rectangle as four separate Rectangle instances for each edge.
|
|
@@ -312,30 +326,30 @@ class le extends Q {
|
|
|
312
326
|
*/
|
|
313
327
|
renderStroke(t) {
|
|
314
328
|
if (t <= 0) return;
|
|
315
|
-
const r = new
|
|
316
|
-
r.render(), i.render(), s.render(),
|
|
329
|
+
const r = new A(this.gl, this.x, this.y, this.width, t), i = new A(this.gl, this.x + this.width - t, this.y, t, this.height), s = new A(this.gl, this.x, this.y + this.height - t, this.width, t), o = new A(this.gl, this.x, this.y, t, this.height);
|
|
330
|
+
r.render(), i.render(), s.render(), o.render();
|
|
317
331
|
}
|
|
318
332
|
}
|
|
319
|
-
class
|
|
320
|
-
constructor(e, t, r, i, s,
|
|
333
|
+
class le {
|
|
334
|
+
constructor(e, t, r, i, s, o) {
|
|
321
335
|
/** The WebGL rendering context */
|
|
322
|
-
|
|
336
|
+
a(this, "gl");
|
|
323
337
|
/** The vertex buffer containing position and texture coordinates */
|
|
324
|
-
|
|
338
|
+
a(this, "vertexBuffer");
|
|
325
339
|
/** The number of vertices in this geometry (always 6 for two triangles) */
|
|
326
|
-
|
|
340
|
+
a(this, "vertexCount", 6);
|
|
327
341
|
/** Bytes per vertex: vec2+vec2 = 16 bytes */
|
|
328
|
-
|
|
342
|
+
a(this, "bytesPerVertex");
|
|
329
343
|
this.gl = e, this.bytesPerVertex = 16;
|
|
330
|
-
const n = e.getParameter(e.VIEWPORT),
|
|
344
|
+
const n = e.getParameter(e.VIEWPORT), l = n[2], c = n[3], u = e.getParameter(e.FRAMEBUFFER_BINDING) !== null, d = i - t, f = s - r, g = Math.sqrt(d * d + f * f);
|
|
331
345
|
if (g === 0) {
|
|
332
346
|
const ie = this.generateVertices(0, 0, 0, 0);
|
|
333
347
|
this.vertexBuffer = e.createBuffer(), e.bindBuffer(e.ARRAY_BUFFER, this.vertexBuffer), e.bufferData(e.ARRAY_BUFFER, ie, e.STATIC_DRAW);
|
|
334
348
|
return;
|
|
335
349
|
}
|
|
336
|
-
const
|
|
350
|
+
const p = d / g, b = -(f / g), C = p, v = o / 2, w = t + b * v, D = r + C * v, R = t - b * v, y = r - C * v, P = i + b * v, M = s + C * v, Z = i - b * v, W = s - C * v, J = w / l * 2 - 1, K = R / l * 2 - 1, ee = P / l * 2 - 1, te = Z / l * 2 - 1;
|
|
337
351
|
let B, G, V, k;
|
|
338
|
-
u ? (B =
|
|
352
|
+
u ? (B = D / c * 2 - 1, G = y / c * 2 - 1, V = M / c * 2 - 1, k = W / c * 2 - 1) : (B = 1 - D / c * 2, G = 1 - y / c * 2, V = 1 - M / c * 2, k = 1 - W / c * 2);
|
|
339
353
|
const re = this.generateLineVertices(
|
|
340
354
|
J,
|
|
341
355
|
B,
|
|
@@ -391,7 +405,7 @@ class he {
|
|
|
391
405
|
* Uses the four corners calculated based on line direction and thickness
|
|
392
406
|
* @private
|
|
393
407
|
*/
|
|
394
|
-
generateLineVertices(e, t, r, i, s,
|
|
408
|
+
generateLineVertices(e, t, r, i, s, o, n, l) {
|
|
395
409
|
return new Float32Array([
|
|
396
410
|
e,
|
|
397
411
|
t,
|
|
@@ -404,7 +418,7 @@ class he {
|
|
|
404
418
|
1,
|
|
405
419
|
// corner2 (start - perpendicular)
|
|
406
420
|
s,
|
|
407
|
-
|
|
421
|
+
o,
|
|
408
422
|
1,
|
|
409
423
|
0,
|
|
410
424
|
// corner3 (end + perpendicular)
|
|
@@ -414,12 +428,12 @@ class he {
|
|
|
414
428
|
1,
|
|
415
429
|
// corner2 (start - perpendicular)
|
|
416
430
|
n,
|
|
417
|
-
|
|
431
|
+
l,
|
|
418
432
|
1,
|
|
419
433
|
1,
|
|
420
434
|
// corner4 (end - perpendicular)
|
|
421
435
|
s,
|
|
422
|
-
|
|
436
|
+
o,
|
|
423
437
|
1,
|
|
424
438
|
0
|
|
425
439
|
// corner3 (end + perpendicular)
|
|
@@ -436,11 +450,11 @@ class he {
|
|
|
436
450
|
}
|
|
437
451
|
}
|
|
438
452
|
class ce extends Q {
|
|
439
|
-
constructor(t, r, i, s,
|
|
453
|
+
constructor(t, r, i, s, o) {
|
|
440
454
|
super(t, r, i);
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
this.x2 = s, this.y2 =
|
|
455
|
+
a(this, "x2");
|
|
456
|
+
a(this, "y2");
|
|
457
|
+
this.x2 = s, this.y2 = o;
|
|
444
458
|
}
|
|
445
459
|
/**
|
|
446
460
|
* Lines don't support fill rendering - this method does nothing.
|
|
@@ -454,23 +468,23 @@ class ce extends Q {
|
|
|
454
468
|
*/
|
|
455
469
|
renderStroke(t) {
|
|
456
470
|
if (t <= 0) return;
|
|
457
|
-
new
|
|
471
|
+
new le(this.gl, this.x, this.y, this.x2, this.y2, t).render();
|
|
458
472
|
}
|
|
459
473
|
}
|
|
460
474
|
class T {
|
|
461
475
|
constructor(e, t, r) {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
476
|
+
a(this, "gl");
|
|
477
|
+
a(this, "program");
|
|
478
|
+
a(this, "uniformLocations", /* @__PURE__ */ new Map());
|
|
479
|
+
a(this, "attributeLocations", /* @__PURE__ */ new Map());
|
|
480
|
+
a(this, "textureUnitCounter", 0);
|
|
467
481
|
this.gl = e, this.program = this.createProgram(t, r), this.cacheLocations();
|
|
468
482
|
}
|
|
469
483
|
createProgram(e, t) {
|
|
470
484
|
const r = this.createShader(this.gl.VERTEX_SHADER, e), i = this.createShader(this.gl.FRAGMENT_SHADER, t), s = this.gl.createProgram();
|
|
471
485
|
if (this.gl.attachShader(s, r), this.gl.attachShader(s, i), this.gl.linkProgram(s), !this.gl.getProgramParameter(s, this.gl.LINK_STATUS)) {
|
|
472
|
-
const
|
|
473
|
-
throw new Error(`Shader program link error: ${
|
|
486
|
+
const o = this.gl.getProgramInfoLog(s);
|
|
487
|
+
throw new Error(`Shader program link error: ${o}`);
|
|
474
488
|
}
|
|
475
489
|
return this.gl.deleteShader(r), this.gl.deleteShader(i), s;
|
|
476
490
|
}
|
|
@@ -520,7 +534,7 @@ class T {
|
|
|
520
534
|
this.gl.uniform1i(r, t ? 1 : 0);
|
|
521
535
|
else if (Array.isArray(t))
|
|
522
536
|
if (i && (i.type === this.gl.INT_VEC2 || i.type === this.gl.INT_VEC3 || i.type === this.gl.INT_VEC4)) {
|
|
523
|
-
const s = t.map((
|
|
537
|
+
const s = t.map((o) => Math.floor(o));
|
|
524
538
|
switch (s.length) {
|
|
525
539
|
case 2:
|
|
526
540
|
this.gl.uniform2iv(r, s);
|
|
@@ -590,6 +604,19 @@ class T {
|
|
|
590
604
|
get glProgram() {
|
|
591
605
|
return this.program;
|
|
592
606
|
}
|
|
607
|
+
/**
|
|
608
|
+
* Dispose of WebGL resources used by this shader.
|
|
609
|
+
* This method is idempotent and safe to call multiple times.
|
|
610
|
+
*/
|
|
611
|
+
dispose() {
|
|
612
|
+
this.program && (this.gl.deleteProgram(this.program), this.program = null), this.uniformLocations.clear(), this.attributeLocations.clear(), this.textureUnitCounter = 0;
|
|
613
|
+
}
|
|
614
|
+
/**
|
|
615
|
+
* Check if this shader has been disposed
|
|
616
|
+
*/
|
|
617
|
+
get isDisposed() {
|
|
618
|
+
return this.program === null;
|
|
619
|
+
}
|
|
593
620
|
/**
|
|
594
621
|
* Reset texture unit counter (useful when starting a new frame)
|
|
595
622
|
*/
|
|
@@ -600,22 +627,22 @@ class T {
|
|
|
600
627
|
var S = "attribute vec2 a_position;attribute vec2 a_texCoord;varying vec2 v_uv;uniform float u_rotation;uniform vec2 u_center;uniform float u_aspectRatio;mat2 rotate2D(float angle){float s=sin(angle);float c=cos(angle);return mat2(c,-s,s,c);}void main(){v_uv=a_texCoord;vec2 pos=a_position;pos-=u_center;pos.x*=u_aspectRatio;pos=rotate2D(-u_rotation)*pos;pos.x/=u_aspectRatio;pos+=u_center;gl_Position=vec4(pos,0.0,1.0);}", ue = "precision lowp float;uniform sampler2D u_texture;varying vec2 v_uv;void main(){gl_FragColor=texture2D(u_texture,v_uv);}", de = "precision lowp float;uniform vec4 u_color;void main(){gl_FragColor=u_color;}";
|
|
601
628
|
class fe {
|
|
602
629
|
constructor(e) {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
630
|
+
a(this, "gl");
|
|
631
|
+
a(this, "imageShader");
|
|
632
|
+
a(this, "solidColorShader");
|
|
633
|
+
a(this, "currentShader", null);
|
|
607
634
|
// Fill state management - default: white fill enabled
|
|
608
|
-
|
|
609
|
-
|
|
635
|
+
a(this, "currentFillColor", [1, 1, 1, 1]);
|
|
636
|
+
a(this, "fillMode", !0);
|
|
610
637
|
// Stroke state management - default: black stroke enabled, weight 1
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
638
|
+
a(this, "currentStrokeColor", [0, 0, 0, 1]);
|
|
639
|
+
a(this, "currentStrokeWeight", 1);
|
|
640
|
+
a(this, "strokeMode", !0);
|
|
614
641
|
// Transformation state management
|
|
615
|
-
|
|
642
|
+
a(this, "currentRotation", 0);
|
|
616
643
|
// in degrees
|
|
617
644
|
// State stack for push/pop functionality
|
|
618
|
-
|
|
645
|
+
a(this, "stateStack", []);
|
|
619
646
|
this.gl = e, this.imageShader = new T(this.gl, S, ue), this.solidColorShader = new T(this.gl, S, de), this.gl.enable(this.gl.BLEND), this.gl.blendEquation(this.gl.FUNC_ADD), this.gl.blendFunc(this.gl.ONE, this.gl.ONE_MINUS_SRC_ALPHA);
|
|
620
647
|
}
|
|
621
648
|
/**
|
|
@@ -729,18 +756,18 @@ class fe {
|
|
|
729
756
|
* Draw a rectangle with the current fill and/or stroke settings
|
|
730
757
|
*/
|
|
731
758
|
rect(e, t, r, i) {
|
|
732
|
-
const s = new
|
|
759
|
+
const s = new he(this.gl, e, t, r, i);
|
|
733
760
|
if (this.currentShader !== null) {
|
|
734
761
|
if (this.currentRotation !== 0) {
|
|
735
|
-
const { centerX: d, centerY: f, radians: g, aspectRatio:
|
|
736
|
-
this.setUniform("u_rotation", g), this.setUniform("u_center", [d, f]), this.setUniform("u_aspectRatio",
|
|
762
|
+
const { centerX: d, centerY: f, radians: g, aspectRatio: p } = this.calculateRotationParams(e, t, r, i);
|
|
763
|
+
this.setUniform("u_rotation", g), this.setUniform("u_center", [d, f]), this.setUniform("u_aspectRatio", p);
|
|
737
764
|
} else
|
|
738
765
|
this.setUniform("u_rotation", 0), this.setUniform("u_center", [0, 0]), this.setUniform("u_aspectRatio", 1);
|
|
739
766
|
s.renderFill(), this.currentShader = null;
|
|
740
767
|
return;
|
|
741
768
|
}
|
|
742
|
-
const
|
|
743
|
-
this.fillMode && (this.shader(
|
|
769
|
+
const o = this.solidColorShader, { centerX: n, centerY: l, radians: c, aspectRatio: u } = this.calculateRotationParams(e, t, r, i);
|
|
770
|
+
this.fillMode && (this.shader(o), this.setUniform("u_color", this.currentFillColor), this.setUniform("u_rotation", c), this.setUniform("u_center", [n, l]), this.setUniform("u_aspectRatio", u), s.renderFill()), this.strokeMode && (this.shader(o), this.setUniform("u_color", this.currentStrokeColor), this.setUniform("u_rotation", c), this.setUniform("u_center", [n, l]), this.setUniform("u_aspectRatio", u), s.renderStroke(this.currentStrokeWeight)), this.currentShader = null;
|
|
744
771
|
}
|
|
745
772
|
/**
|
|
746
773
|
* Draw a line from (x1, y1) to (x2, y2) with the current stroke settings.
|
|
@@ -755,31 +782,31 @@ class fe {
|
|
|
755
782
|
const s = new ce(this.gl, e, t, r, i);
|
|
756
783
|
if (this.currentShader !== null) {
|
|
757
784
|
if (this.currentRotation !== 0) {
|
|
758
|
-
const
|
|
759
|
-
this.setUniform("u_rotation", R), this.setUniform("u_center", [w,
|
|
785
|
+
const _ = (e + r) / 2, b = (t + i) / 2, C = Math.abs(r - e), v = Math.abs(i - t), { centerX: w, centerY: D, radians: R, aspectRatio: y } = this.calculateRotationParams(_ - C / 2, b - v / 2, C, v);
|
|
786
|
+
this.setUniform("u_rotation", R), this.setUniform("u_center", [w, D]), this.setUniform("u_aspectRatio", y);
|
|
760
787
|
} else
|
|
761
788
|
this.setUniform("u_rotation", 0), this.setUniform("u_center", [0, 0]), this.setUniform("u_aspectRatio", 1);
|
|
762
789
|
s.renderStroke(this.currentStrokeWeight), this.currentShader = null;
|
|
763
790
|
return;
|
|
764
791
|
}
|
|
765
|
-
const
|
|
766
|
-
this.shader(
|
|
792
|
+
const o = this.solidColorShader, n = (e + r) / 2, l = (t + i) / 2, c = Math.abs(r - e), u = Math.abs(i - t), { centerX: d, centerY: f, radians: g, aspectRatio: p } = this.calculateRotationParams(n - c / 2, l - u / 2, c, u);
|
|
793
|
+
this.shader(o), this.setUniform("u_color", this.currentStrokeColor), this.setUniform("u_rotation", g), this.setUniform("u_center", [d, f]), this.setUniform("u_aspectRatio", p), s.renderStroke(this.currentStrokeWeight), this.currentShader = null;
|
|
767
794
|
}
|
|
768
795
|
/**
|
|
769
796
|
* Calculate rotation parameters for built-in shaders (NDC coordinates)
|
|
770
797
|
*/
|
|
771
798
|
calculateRotationParams(e, t, r, i) {
|
|
772
|
-
const s = this.gl.getParameter(this.gl.VIEWPORT),
|
|
799
|
+
const s = this.gl.getParameter(this.gl.VIEWPORT), o = s[2], n = s[3], l = o / n, c = this.gl.getParameter(this.gl.FRAMEBUFFER_BINDING) !== null, u = e + r / 2, d = t + i / 2, f = u / o * 2 - 1;
|
|
773
800
|
let g;
|
|
774
801
|
c ? g = d / n * 2 - 1 : g = 1 - d / n * 2;
|
|
775
|
-
const
|
|
776
|
-
return { centerX: f, centerY: g, radians:
|
|
802
|
+
const p = this.currentRotation * Math.PI / 180;
|
|
803
|
+
return { centerX: f, centerY: g, radians: p, aspectRatio: l };
|
|
777
804
|
}
|
|
778
805
|
/**
|
|
779
806
|
* Create a new framebuffer
|
|
780
807
|
*/
|
|
781
808
|
createFramebuffer(e, t, r = {}) {
|
|
782
|
-
return new
|
|
809
|
+
return new ae(this.gl, e, t, r);
|
|
783
810
|
}
|
|
784
811
|
/**
|
|
785
812
|
* Fill the current framebuffer with a solid color
|
|
@@ -805,23 +832,36 @@ class fe {
|
|
|
805
832
|
get context() {
|
|
806
833
|
return this.gl;
|
|
807
834
|
}
|
|
835
|
+
/**
|
|
836
|
+
* Dispose of all WebGL resources managed by this renderer.
|
|
837
|
+
* This method is idempotent and safe to call multiple times.
|
|
838
|
+
*/
|
|
839
|
+
dispose() {
|
|
840
|
+
this.imageShader && !this.imageShader.isDisposed && this.imageShader.dispose(), this.solidColorShader && !this.solidColorShader.isDisposed && this.solidColorShader.dispose(), this.imageShader = null, this.solidColorShader = null, this.currentShader = null, this.stateStack = [];
|
|
841
|
+
}
|
|
842
|
+
/**
|
|
843
|
+
* Check if this renderer has been disposed
|
|
844
|
+
*/
|
|
845
|
+
get isDisposed() {
|
|
846
|
+
return this.imageShader === null || this.solidColorShader === null;
|
|
847
|
+
}
|
|
808
848
|
/**
|
|
809
849
|
* Render a framebuffer at a specific position with optional scaling
|
|
810
850
|
*/
|
|
811
851
|
image(e, t, r, i, s) {
|
|
812
852
|
this.shader(this.imageShader), this.setUniform("u_texture", e.texture);
|
|
813
|
-
const { centerX:
|
|
853
|
+
const { centerX: o, centerY: n, radians: l, aspectRatio: c } = this.calculateRotationParams(
|
|
814
854
|
t,
|
|
815
855
|
r,
|
|
816
856
|
i ?? e.width,
|
|
817
857
|
s ?? e.height
|
|
818
858
|
);
|
|
819
|
-
this.setUniform("u_rotation",
|
|
859
|
+
this.setUniform("u_rotation", l), this.setUniform("u_center", [o, n]), this.setUniform("u_aspectRatio", c), this.rect(t, r, i ?? e.width, s ?? e.height);
|
|
820
860
|
}
|
|
821
861
|
}
|
|
822
862
|
var m = {};
|
|
823
|
-
m.parse = function(
|
|
824
|
-
var e = function(s,
|
|
863
|
+
m.parse = function(h) {
|
|
864
|
+
var e = function(s, o, n, l) {
|
|
825
865
|
var c = m.T, u = {
|
|
826
866
|
cmap: c.cmap,
|
|
827
867
|
head: c.head,
|
|
@@ -830,119 +870,119 @@ m.parse = function(l) {
|
|
|
830
870
|
hmtx: c.hmtx,
|
|
831
871
|
loca: c.loca,
|
|
832
872
|
glyf: c.glyf
|
|
833
|
-
}, d = { _data: s, _index:
|
|
873
|
+
}, d = { _data: s, _index: o, _offset: n };
|
|
834
874
|
for (var f in u) {
|
|
835
875
|
var g = m.findTable(s, f, n);
|
|
836
876
|
if (g) {
|
|
837
|
-
var
|
|
838
|
-
|
|
877
|
+
var p = g[0], _ = l[p];
|
|
878
|
+
_ == null && (_ = u[f].parseTab(s, p, g[1], d)), d[f] = l[p] = _;
|
|
839
879
|
}
|
|
840
880
|
}
|
|
841
881
|
return d;
|
|
842
|
-
}, t = new Uint8Array(
|
|
882
|
+
}, t = new Uint8Array(h), r = {}, i = e(t, 0, 0, r);
|
|
843
883
|
return [i];
|
|
844
884
|
};
|
|
845
|
-
m.findTable = function(
|
|
846
|
-
for (var r = m.B, i = r.readUshort(
|
|
847
|
-
var n = r.readASCII(
|
|
848
|
-
r.readUint(
|
|
849
|
-
var
|
|
850
|
-
if (n == e) return [
|
|
885
|
+
m.findTable = function(h, e, t) {
|
|
886
|
+
for (var r = m.B, i = r.readUshort(h, t + 4), s = t + 12, o = 0; o < i; o++) {
|
|
887
|
+
var n = r.readASCII(h, s, 4);
|
|
888
|
+
r.readUint(h, s + 4);
|
|
889
|
+
var l = r.readUint(h, s + 8), c = r.readUint(h, s + 12);
|
|
890
|
+
if (n == e) return [l, c];
|
|
851
891
|
s += 16;
|
|
852
892
|
}
|
|
853
893
|
return null;
|
|
854
894
|
};
|
|
855
895
|
m.T = {};
|
|
856
896
|
m.B = {
|
|
857
|
-
readShort: function(
|
|
897
|
+
readShort: function(h, e) {
|
|
858
898
|
var t = m.B.t.uint16;
|
|
859
|
-
return t[0] =
|
|
899
|
+
return t[0] = h[e] << 8 | h[e + 1], m.B.t.int16[0];
|
|
860
900
|
},
|
|
861
|
-
readUshort: function(
|
|
862
|
-
return
|
|
901
|
+
readUshort: function(h, e) {
|
|
902
|
+
return h[e] << 8 | h[e + 1];
|
|
863
903
|
},
|
|
864
|
-
readUshorts: function(
|
|
904
|
+
readUshorts: function(h, e, t) {
|
|
865
905
|
for (var r = [], i = 0; i < t; i++)
|
|
866
|
-
r.push(m.B.readUshort(
|
|
906
|
+
r.push(m.B.readUshort(h, e + i * 2));
|
|
867
907
|
return r;
|
|
868
908
|
},
|
|
869
|
-
readUint: function(
|
|
909
|
+
readUint: function(h, e) {
|
|
870
910
|
var t = m.B.t.uint8;
|
|
871
|
-
return t[3] =
|
|
911
|
+
return t[3] = h[e], t[2] = h[e + 1], t[1] = h[e + 2], t[0] = h[e + 3], m.B.t.uint32[0];
|
|
872
912
|
},
|
|
873
|
-
readASCII: function(
|
|
874
|
-
for (var r = "", i = 0; i < t; i++) r += String.fromCharCode(
|
|
913
|
+
readASCII: function(h, e, t) {
|
|
914
|
+
for (var r = "", i = 0; i < t; i++) r += String.fromCharCode(h[e + i]);
|
|
875
915
|
return r;
|
|
876
916
|
},
|
|
877
917
|
// Simplified typed array buffer - only what's needed
|
|
878
918
|
t: function() {
|
|
879
|
-
var
|
|
919
|
+
var h = new ArrayBuffer(8);
|
|
880
920
|
return {
|
|
881
|
-
uint8: new Uint8Array(
|
|
882
|
-
int16: new Int16Array(
|
|
883
|
-
uint16: new Uint16Array(
|
|
884
|
-
uint32: new Uint32Array(
|
|
921
|
+
uint8: new Uint8Array(h),
|
|
922
|
+
int16: new Int16Array(h),
|
|
923
|
+
uint16: new Uint16Array(h),
|
|
924
|
+
uint32: new Uint32Array(h)
|
|
885
925
|
};
|
|
886
926
|
}()
|
|
887
927
|
};
|
|
888
928
|
m.T.cmap = {
|
|
889
|
-
parseTab: function(
|
|
929
|
+
parseTab: function(h, e, t) {
|
|
890
930
|
var r = { tables: [], ids: {}, off: e };
|
|
891
|
-
|
|
892
|
-
var i = m.B, s = i.readUshort,
|
|
893
|
-
s(
|
|
894
|
-
var n = s(
|
|
931
|
+
h = new Uint8Array(h.buffer, e, t), e = 0;
|
|
932
|
+
var i = m.B, s = i.readUshort, o = m.T.cmap;
|
|
933
|
+
s(h, e), e += 2;
|
|
934
|
+
var n = s(h, e);
|
|
895
935
|
e += 2;
|
|
896
|
-
for (var
|
|
897
|
-
var u = s(
|
|
936
|
+
for (var l = [], c = 0; c < n; c++) {
|
|
937
|
+
var u = s(h, e);
|
|
898
938
|
e += 2;
|
|
899
|
-
var d = s(
|
|
939
|
+
var d = s(h, e);
|
|
900
940
|
e += 2;
|
|
901
|
-
var f = i.readUint(
|
|
941
|
+
var f = i.readUint(h, e);
|
|
902
942
|
e += 4;
|
|
903
|
-
var g = "p" + u + "e" + d,
|
|
904
|
-
if (
|
|
905
|
-
|
|
906
|
-
var
|
|
907
|
-
|
|
908
|
-
var
|
|
909
|
-
|
|
943
|
+
var g = "p" + u + "e" + d, p = l.indexOf(f);
|
|
944
|
+
if (p == -1) {
|
|
945
|
+
p = r.tables.length;
|
|
946
|
+
var _ = {};
|
|
947
|
+
l.push(f);
|
|
948
|
+
var b = _.format = s(h, f);
|
|
949
|
+
b == 4 ? _ = o.parse4(h, f, _) : b == 12 && (_ = o.parse12(h, f, _)), r.tables.push(_);
|
|
910
950
|
}
|
|
911
|
-
r.ids[g] != null && console.log("multiple tables for one platform+encoding: " + g), r.ids[g] =
|
|
951
|
+
r.ids[g] != null && console.log("multiple tables for one platform+encoding: " + g), r.ids[g] = p;
|
|
912
952
|
}
|
|
913
953
|
return r;
|
|
914
954
|
},
|
|
915
|
-
parse4: function(
|
|
916
|
-
var r = m.B, i = r.readUshort, s = r.readUshorts,
|
|
955
|
+
parse4: function(h, e, t) {
|
|
956
|
+
var r = m.B, i = r.readUshort, s = r.readUshorts, o = e;
|
|
917
957
|
e += 2;
|
|
918
|
-
var n = i(
|
|
919
|
-
e += 2, i(
|
|
920
|
-
var
|
|
958
|
+
var n = i(h, e);
|
|
959
|
+
e += 2, i(h, e), e += 2;
|
|
960
|
+
var l = i(h, e);
|
|
921
961
|
e += 2;
|
|
922
|
-
var c =
|
|
923
|
-
t.searchRange = i(
|
|
962
|
+
var c = l >>> 1;
|
|
963
|
+
t.searchRange = i(h, e), e += 2, t.entrySelector = i(h, e), e += 2, t.rangeShift = i(h, e), e += 2, t.endCount = s(h, e, c), e += c * 2, e += 2, t.startCount = s(h, e, c), e += c * 2, t.idDelta = [];
|
|
924
964
|
for (var u = 0; u < c; u++)
|
|
925
|
-
t.idDelta.push(r.readShort(
|
|
926
|
-
return t.idRangeOffset = s(
|
|
965
|
+
t.idDelta.push(r.readShort(h, e)), e += 2;
|
|
966
|
+
return t.idRangeOffset = s(h, e, c), e += c * 2, t.glyphIdArray = s(h, e, o + n - e >> 1), t;
|
|
927
967
|
},
|
|
928
|
-
parse12: function(
|
|
968
|
+
parse12: function(h, e, t) {
|
|
929
969
|
var r = m.B, i = r.readUint;
|
|
930
|
-
e += 4, i(
|
|
931
|
-
var s = i(
|
|
970
|
+
e += 4, i(h, e), e += 4, i(h, e), e += 4;
|
|
971
|
+
var s = i(h, e) * 3;
|
|
932
972
|
e += 4;
|
|
933
|
-
for (var
|
|
934
|
-
|
|
973
|
+
for (var o = t.groups = new Uint32Array(s), n = 0; n < s; n += 3)
|
|
974
|
+
o[n] = i(h, e + (n << 2)), o[n + 1] = i(h, e + (n << 2) + 4), o[n + 2] = i(h, e + (n << 2) + 8);
|
|
935
975
|
return t;
|
|
936
976
|
}
|
|
937
977
|
};
|
|
938
978
|
m.T.head = {
|
|
939
|
-
parseTab: function(
|
|
979
|
+
parseTab: function(h, e, t) {
|
|
940
980
|
var r = m.B, i = {};
|
|
941
|
-
return e += 18, i.unitsPerEm = r.readUshort(
|
|
981
|
+
return e += 18, i.unitsPerEm = r.readUshort(h, e), e += 2, e += 16, i.xMin = r.readShort(h, e), e += 2, i.yMin = r.readShort(h, e), e += 2, i.xMax = r.readShort(h, e), e += 2, i.yMax = r.readShort(h, e), e += 2, e += 6, i.indexToLocFormat = r.readShort(h, e), i;
|
|
942
982
|
}
|
|
943
983
|
};
|
|
944
984
|
m.T.hhea = {
|
|
945
|
-
parseTab: function(
|
|
985
|
+
parseTab: function(h, e, t) {
|
|
946
986
|
var r = m.B, i = {};
|
|
947
987
|
e += 4;
|
|
948
988
|
for (var s = [
|
|
@@ -962,79 +1002,79 @@ m.T.hhea = {
|
|
|
962
1002
|
"res3",
|
|
963
1003
|
"metricDataFormat",
|
|
964
1004
|
"numberOfHMetrics"
|
|
965
|
-
],
|
|
966
|
-
var n = s[
|
|
967
|
-
i[n] = h
|
|
1005
|
+
], o = 0; o < s.length; o++) {
|
|
1006
|
+
var n = s[o], l = n == "advanceWidthMax" || n == "numberOfHMetrics" ? r.readUshort : r.readShort;
|
|
1007
|
+
i[n] = l(h, e + o * 2);
|
|
968
1008
|
}
|
|
969
1009
|
return i;
|
|
970
1010
|
}
|
|
971
1011
|
};
|
|
972
1012
|
m.T.hmtx = {
|
|
973
|
-
parseTab: function(
|
|
974
|
-
for (var i = m.B, s = [],
|
|
975
|
-
c = i.readUshort(
|
|
1013
|
+
parseTab: function(h, e, t, r) {
|
|
1014
|
+
for (var i = m.B, s = [], o = [], n = r.maxp.numGlyphs, l = r.hhea.numberOfHMetrics, c = 0, u = 0, d = 0; d < l; )
|
|
1015
|
+
c = i.readUshort(h, e + (d << 2)), u = i.readShort(h, e + (d << 2) + 2), s.push(c), o.push(u), d++;
|
|
976
1016
|
for (; d < n; )
|
|
977
|
-
s.push(c),
|
|
978
|
-
return { aWidth: s, lsBearing:
|
|
1017
|
+
s.push(c), o.push(u), d++;
|
|
1018
|
+
return { aWidth: s, lsBearing: o };
|
|
979
1019
|
}
|
|
980
1020
|
};
|
|
981
1021
|
m.T.maxp = {
|
|
982
|
-
parseTab: function(
|
|
1022
|
+
parseTab: function(h, e, t) {
|
|
983
1023
|
var r = m.B, i = r.readUshort, s = {};
|
|
984
|
-
return r.readUint(
|
|
1024
|
+
return r.readUint(h, e), e += 4, s.numGlyphs = i(h, e), e += 2, s;
|
|
985
1025
|
}
|
|
986
1026
|
};
|
|
987
1027
|
m.T.loca = {
|
|
988
|
-
parseTab: function(
|
|
989
|
-
var i = m.B, s = [],
|
|
990
|
-
if (
|
|
991
|
-
if (
|
|
1028
|
+
parseTab: function(h, e, t, r) {
|
|
1029
|
+
var i = m.B, s = [], o = r.head.indexToLocFormat, n = r.maxp.numGlyphs + 1;
|
|
1030
|
+
if (o == 0) for (var l = 0; l < n; l++) s.push(i.readUshort(h, e + (l << 1)) << 1);
|
|
1031
|
+
if (o == 1) for (var l = 0; l < n; l++) s.push(i.readUint(h, e + (l << 2)));
|
|
992
1032
|
return s;
|
|
993
1033
|
}
|
|
994
1034
|
};
|
|
995
1035
|
m.T.glyf = {
|
|
996
|
-
parseTab: function(
|
|
997
|
-
for (var i = [], s = r.maxp.numGlyphs,
|
|
1036
|
+
parseTab: function(h, e, t, r) {
|
|
1037
|
+
for (var i = [], s = r.maxp.numGlyphs, o = 0; o < s; o++) i.push(null);
|
|
998
1038
|
return i;
|
|
999
1039
|
},
|
|
1000
|
-
_parseGlyf: function(
|
|
1001
|
-
var t = m.B, r =
|
|
1040
|
+
_parseGlyf: function(h, e) {
|
|
1041
|
+
var t = m.B, r = h._data, i = h.loca;
|
|
1002
1042
|
if (i[e] == i[e + 1]) return null;
|
|
1003
|
-
var s = m.findTable(r, "glyf",
|
|
1004
|
-
if (
|
|
1005
|
-
if (
|
|
1006
|
-
|
|
1007
|
-
for (var n = 0; n <
|
|
1008
|
-
|
|
1009
|
-
var
|
|
1010
|
-
if (s += 2, r.length - s <
|
|
1011
|
-
s +=
|
|
1012
|
-
var c =
|
|
1013
|
-
|
|
1043
|
+
var s = m.findTable(r, "glyf", h._offset)[0] + i[e], o = {};
|
|
1044
|
+
if (o.noc = t.readShort(r, s), s += 2, o.xMin = t.readShort(r, s), s += 2, o.yMin = t.readShort(r, s), s += 2, o.xMax = t.readShort(r, s), s += 2, o.yMax = t.readShort(r, s), s += 2, o.xMin >= o.xMax || o.yMin >= o.yMax) return null;
|
|
1045
|
+
if (o.noc > 0) {
|
|
1046
|
+
o.endPts = [];
|
|
1047
|
+
for (var n = 0; n < o.noc; n++)
|
|
1048
|
+
o.endPts.push(t.readUshort(r, s)), s += 2;
|
|
1049
|
+
var l = t.readUshort(r, s);
|
|
1050
|
+
if (s += 2, r.length - s < l) return null;
|
|
1051
|
+
s += l;
|
|
1052
|
+
var c = o.endPts[o.noc - 1] + 1;
|
|
1053
|
+
o.flags = [];
|
|
1014
1054
|
for (var n = 0; n < c; n++) {
|
|
1015
1055
|
var u = r[s];
|
|
1016
|
-
if (s++,
|
|
1056
|
+
if (s++, o.flags.push(u), u & 8) {
|
|
1017
1057
|
var d = r[s];
|
|
1018
1058
|
s++;
|
|
1019
1059
|
for (var f = 0; f < d; f++)
|
|
1020
|
-
|
|
1060
|
+
o.flags.push(u), n++;
|
|
1021
1061
|
}
|
|
1022
1062
|
}
|
|
1023
|
-
|
|
1063
|
+
o.xs = [];
|
|
1024
1064
|
for (var n = 0; n < c; n++) {
|
|
1025
|
-
var g = (
|
|
1026
|
-
g ? (
|
|
1065
|
+
var g = (o.flags[n] & 2) != 0, p = (o.flags[n] & 16) != 0;
|
|
1066
|
+
g ? (o.xs.push(p ? r[s] : -r[s]), s++) : p ? o.xs.push(0) : (o.xs.push(t.readShort(r, s)), s += 2);
|
|
1027
1067
|
}
|
|
1028
|
-
|
|
1068
|
+
o.ys = [];
|
|
1029
1069
|
for (var n = 0; n < c; n++) {
|
|
1030
|
-
var g = (
|
|
1031
|
-
g ? (
|
|
1070
|
+
var g = (o.flags[n] & 4) != 0, p = (o.flags[n] & 32) != 0;
|
|
1071
|
+
g ? (o.ys.push(p ? r[s] : -r[s]), s++) : p ? o.ys.push(0) : (o.ys.push(t.readShort(r, s)), s += 2);
|
|
1032
1072
|
}
|
|
1033
|
-
for (var
|
|
1034
|
-
|
|
1073
|
+
for (var _ = 0, b = 0, n = 0; n < c; n++)
|
|
1074
|
+
_ += o.xs[n], b += o.ys[n], o.xs[n] = _, o.ys[n] = b;
|
|
1035
1075
|
} else
|
|
1036
|
-
|
|
1037
|
-
return
|
|
1076
|
+
o.parts = [];
|
|
1077
|
+
return o;
|
|
1038
1078
|
}
|
|
1039
1079
|
};
|
|
1040
1080
|
typeof module < "u" && module.exports ? module.exports = m : typeof window < "u" && (window.Typr = m);
|
|
@@ -1069,10 +1109,10 @@ class me {
|
|
|
1069
1109
|
for (let r = 0; r < e.startCount.length; r++) {
|
|
1070
1110
|
const i = e.startCount[r], s = e.endCount[r];
|
|
1071
1111
|
if (!(i === 65535 && s === 65535)) {
|
|
1072
|
-
for (let
|
|
1073
|
-
if (this._calculateGlyphIndexFormat4(e,
|
|
1074
|
-
const
|
|
1075
|
-
t.push(
|
|
1112
|
+
for (let o = i; o <= s; o++)
|
|
1113
|
+
if (this._calculateGlyphIndexFormat4(e, o, r) > 0) {
|
|
1114
|
+
const l = String.fromCodePoint(o);
|
|
1115
|
+
t.push(l);
|
|
1076
1116
|
}
|
|
1077
1117
|
}
|
|
1078
1118
|
}
|
|
@@ -1088,9 +1128,9 @@ class me {
|
|
|
1088
1128
|
if (!e.groups)
|
|
1089
1129
|
return t;
|
|
1090
1130
|
for (let r = 0; r < e.groups.length; r += 3) {
|
|
1091
|
-
const i = e.groups[r], s = e.groups[r + 1],
|
|
1131
|
+
const i = e.groups[r], s = e.groups[r + 1], o = e.groups[r + 2];
|
|
1092
1132
|
for (let n = i; n <= s; n++)
|
|
1093
|
-
if (
|
|
1133
|
+
if (o + (n - i) > 0) {
|
|
1094
1134
|
const c = String.fromCodePoint(n);
|
|
1095
1135
|
t.push(c);
|
|
1096
1136
|
}
|
|
@@ -1141,9 +1181,9 @@ class ge {
|
|
|
1141
1181
|
* @param renderer The WebGL renderer instance
|
|
1142
1182
|
*/
|
|
1143
1183
|
constructor(e) {
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1184
|
+
a(this, "_textureCanvas");
|
|
1185
|
+
a(this, "_textureContext");
|
|
1186
|
+
a(this, "_renderer");
|
|
1147
1187
|
this._renderer = e, this._textureCanvas = document.createElement("canvas"), this._textureContext = this._textureCanvas.getContext("2d", { willReadFrequently: !0, alpha: !1 });
|
|
1148
1188
|
}
|
|
1149
1189
|
/**
|
|
@@ -1155,12 +1195,12 @@ class ge {
|
|
|
1155
1195
|
* @returns Object containing framebuffer, columns, and rows
|
|
1156
1196
|
*/
|
|
1157
1197
|
createTextureAtlas(e, t, r, i) {
|
|
1158
|
-
const s = e.length,
|
|
1159
|
-
this._setupCanvas(
|
|
1160
|
-
const u = this._renderer.createFramebuffer(
|
|
1198
|
+
const s = e.length, o = Math.ceil(Math.sqrt(s)), n = Math.ceil(s / o), l = t.width * o, c = t.height * n;
|
|
1199
|
+
this._setupCanvas(l, c, r, i), this._renderCharactersToCanvas(e, t, o, r), this._applyBlackWhiteThreshold();
|
|
1200
|
+
const u = this._renderer.createFramebuffer(l, c, { filter: "nearest" });
|
|
1161
1201
|
return u.update(this._textureCanvas), {
|
|
1162
1202
|
framebuffer: u,
|
|
1163
|
-
columns:
|
|
1203
|
+
columns: o,
|
|
1164
1204
|
rows: n
|
|
1165
1205
|
};
|
|
1166
1206
|
}
|
|
@@ -1185,7 +1225,7 @@ class ge {
|
|
|
1185
1225
|
*/
|
|
1186
1226
|
_renderCharactersToCanvas(e, t, r, i) {
|
|
1187
1227
|
for (let s = 0; s < e.length; s++) {
|
|
1188
|
-
const
|
|
1228
|
+
const o = s % r, n = Math.floor(s / r), l = o * t.width + t.width * 0.5, c = n * t.height + t.height * 0.5, u = Math.round(l - t.width * 0.5), d = Math.round(c - i * 0.5);
|
|
1189
1229
|
this._textureContext.fillText(e[s].character, u, d);
|
|
1190
1230
|
}
|
|
1191
1231
|
}
|
|
@@ -1198,19 +1238,19 @@ class ge {
|
|
|
1198
1238
|
_applyBlackWhiteThreshold(e = 128) {
|
|
1199
1239
|
const t = this._textureContext.getImageData(0, 0, this._textureCanvas.width, this._textureCanvas.height), r = t.data;
|
|
1200
1240
|
for (let i = 0; i < r.length; i += 4) {
|
|
1201
|
-
const s = 0.299 * r[i] + 0.587 * r[i + 1] + 0.114 * r[i + 2],
|
|
1241
|
+
const s = 0.299 * r[i] + 0.587 * r[i + 1] + 0.114 * r[i + 2], o = e + 32, n = s > o ? 255 : 0;
|
|
1202
1242
|
r[i] = n, r[i + 1] = n, r[i + 2] = n;
|
|
1203
1243
|
}
|
|
1204
1244
|
this._textureContext.putImageData(t, 0, 0);
|
|
1205
1245
|
}
|
|
1206
1246
|
}
|
|
1207
|
-
class
|
|
1247
|
+
class _e {
|
|
1208
1248
|
/**
|
|
1209
1249
|
* Creates a new MetricsCalculation instance.
|
|
1210
1250
|
*/
|
|
1211
1251
|
constructor() {
|
|
1212
|
-
|
|
1213
|
-
|
|
1252
|
+
a(this, "_tempCanvas");
|
|
1253
|
+
a(this, "_tempContext");
|
|
1214
1254
|
this._tempCanvas = document.createElement("canvas"), this._tempContext = this._tempCanvas.getContext("2d");
|
|
1215
1255
|
}
|
|
1216
1256
|
/**
|
|
@@ -1224,9 +1264,9 @@ class pe {
|
|
|
1224
1264
|
calculateMaxGlyphDimensions(e, t, r) {
|
|
1225
1265
|
this._tempContext.font = `${t}px ${r}`;
|
|
1226
1266
|
let i = 0, s = 0;
|
|
1227
|
-
for (const
|
|
1228
|
-
const n = this._tempContext.measureText(
|
|
1229
|
-
|
|
1267
|
+
for (const o of e) {
|
|
1268
|
+
const n = this._tempContext.measureText(o), l = n.width, c = n.actualBoundingBoxAscent + n.actualBoundingBoxDescent;
|
|
1269
|
+
l > 0 && (i = Math.max(i, l), s = Math.max(s, c));
|
|
1230
1270
|
}
|
|
1231
1271
|
return {
|
|
1232
1272
|
width: Math.ceil(i),
|
|
@@ -1234,7 +1274,7 @@ class pe {
|
|
|
1234
1274
|
};
|
|
1235
1275
|
}
|
|
1236
1276
|
}
|
|
1237
|
-
class
|
|
1277
|
+
class pe {
|
|
1238
1278
|
/**
|
|
1239
1279
|
* Creates TextmodeCharacter objects with unique color assignments.
|
|
1240
1280
|
* @param characters Array of character strings
|
|
@@ -1243,16 +1283,16 @@ class _e {
|
|
|
1243
1283
|
*/
|
|
1244
1284
|
createCharacterObjects(e, t) {
|
|
1245
1285
|
return e.map((r, i) => {
|
|
1246
|
-
const s = r.codePointAt(0) || 0,
|
|
1286
|
+
const s = r.codePointAt(0) || 0, o = this._generateCharacterColor(i);
|
|
1247
1287
|
let n = 0;
|
|
1248
1288
|
if (t.hmtx && t.hmtx.aWidth) {
|
|
1249
|
-
const
|
|
1250
|
-
|
|
1289
|
+
const l = this._getGlyphIndex(t, s);
|
|
1290
|
+
l > 0 && t.hmtx.aWidth[l] !== void 0 && (n = t.hmtx.aWidth[l]);
|
|
1251
1291
|
}
|
|
1252
1292
|
return {
|
|
1253
1293
|
character: r,
|
|
1254
1294
|
unicode: s,
|
|
1255
|
-
color:
|
|
1295
|
+
color: o,
|
|
1256
1296
|
advanceWidth: n
|
|
1257
1297
|
};
|
|
1258
1298
|
});
|
|
@@ -1274,9 +1314,9 @@ class _e {
|
|
|
1274
1314
|
if (i.idRangeOffset[s] === 0)
|
|
1275
1315
|
return t + i.idDelta[s] & 65535;
|
|
1276
1316
|
{
|
|
1277
|
-
const
|
|
1278
|
-
if (
|
|
1279
|
-
const n = i.glyphIdArray[
|
|
1317
|
+
const o = i.idRangeOffset[s] / 2 + (t - i.startCount[s]) - (i.startCount.length - s);
|
|
1318
|
+
if (o >= 0 && o < i.glyphIdArray.length) {
|
|
1319
|
+
const n = i.glyphIdArray[o];
|
|
1280
1320
|
if (n !== 0)
|
|
1281
1321
|
return n + i.idDelta[s] & 65535;
|
|
1282
1322
|
}
|
|
@@ -1332,21 +1372,21 @@ class xe {
|
|
|
1332
1372
|
* @ignore
|
|
1333
1373
|
*/
|
|
1334
1374
|
constructor(e, t = 16) {
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1375
|
+
a(this, "_font");
|
|
1376
|
+
a(this, "_characters", []);
|
|
1377
|
+
a(this, "_fontFramebuffer");
|
|
1378
|
+
a(this, "_fontSize", 16);
|
|
1379
|
+
a(this, "_textureColumns", 0);
|
|
1380
|
+
a(this, "_textureRows", 0);
|
|
1381
|
+
a(this, "_maxGlyphDimensions", { width: 0, height: 0 });
|
|
1382
|
+
a(this, "_fontFace");
|
|
1383
|
+
a(this, "_fontFamilyName", "UrsaFont");
|
|
1344
1384
|
// Component classes
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
this._fontSize = t, this._characterExtractor = new me(), this._textureAtlas = new ge(e), this._metricsCalculator = new
|
|
1385
|
+
a(this, "_characterExtractor");
|
|
1386
|
+
a(this, "_textureAtlas");
|
|
1387
|
+
a(this, "_metricsCalculator");
|
|
1388
|
+
a(this, "_characterColorMapper");
|
|
1389
|
+
this._fontSize = t, this._characterExtractor = new me(), this._textureAtlas = new ge(e), this._metricsCalculator = new _e(), this._characterColorMapper = new pe();
|
|
1350
1390
|
}
|
|
1351
1391
|
/**
|
|
1352
1392
|
* Initializes the font manager by loading the font and creating the texture atlas.
|
|
@@ -1484,6 +1524,19 @@ class xe {
|
|
|
1484
1524
|
get maxGlyphDimensions() {
|
|
1485
1525
|
return this._maxGlyphDimensions;
|
|
1486
1526
|
}
|
|
1527
|
+
/**
|
|
1528
|
+
* Dispose of all resources used by this font manager.
|
|
1529
|
+
* This method is idempotent and safe to call multiple times.
|
|
1530
|
+
*/
|
|
1531
|
+
dispose() {
|
|
1532
|
+
this._fontFramebuffer && !this._fontFramebuffer.isDisposed && this._fontFramebuffer.dispose(), this._fontFace && document.fonts.has(this._fontFace) && document.fonts.delete(this._fontFace), this._fontFramebuffer = null, this._fontFace = null, this._font = null, this._characters = [], this._maxGlyphDimensions = { width: 0, height: 0 }, this._textureColumns = 0, this._textureRows = 0;
|
|
1533
|
+
}
|
|
1534
|
+
/**
|
|
1535
|
+
* Check if this font manager has been disposed
|
|
1536
|
+
*/
|
|
1537
|
+
get isDisposed() {
|
|
1538
|
+
return this._fontFramebuffer === null || this._font === null;
|
|
1539
|
+
}
|
|
1487
1540
|
/** Returns the font size used for rendering. */
|
|
1488
1541
|
get fontSize() {
|
|
1489
1542
|
return this._fontSize;
|
|
@@ -1503,25 +1556,25 @@ class ve {
|
|
|
1503
1556
|
*/
|
|
1504
1557
|
constructor(e, t, r) {
|
|
1505
1558
|
/** The number of columns in the grid. */
|
|
1506
|
-
|
|
1559
|
+
a(this, "_cols");
|
|
1507
1560
|
/** The number of rows in the grid. */
|
|
1508
|
-
|
|
1561
|
+
a(this, "_rows");
|
|
1509
1562
|
/** The total width of the grid in pixels. */
|
|
1510
|
-
|
|
1563
|
+
a(this, "_width");
|
|
1511
1564
|
/** The total height of the grid in pixels. */
|
|
1512
|
-
|
|
1565
|
+
a(this, "_height");
|
|
1513
1566
|
/** The offset to the outer canvas on the x-axis when centering the grid. */
|
|
1514
|
-
|
|
1567
|
+
a(this, "_offsetX");
|
|
1515
1568
|
/** The offset to the outer canvas on the y-axis when centering the grid. */
|
|
1516
|
-
|
|
1569
|
+
a(this, "_offsetY");
|
|
1517
1570
|
/** Whether the grid dimensions are fixed, or responsive based on the canvas dimensions. */
|
|
1518
|
-
|
|
1571
|
+
a(this, "_fixedDimensions", !1);
|
|
1519
1572
|
/** The canvas element used to determine the grid dimensions. */
|
|
1520
|
-
|
|
1573
|
+
a(this, "_canvas");
|
|
1521
1574
|
/** The width of each cell in the grid. */
|
|
1522
|
-
|
|
1575
|
+
a(this, "_cellWidth");
|
|
1523
1576
|
/** The height of each cell in the grid. */
|
|
1524
|
-
|
|
1577
|
+
a(this, "_cellHeight");
|
|
1525
1578
|
this._canvas = e, this._cellWidth = t, this._cellHeight = r, this.reset();
|
|
1526
1579
|
}
|
|
1527
1580
|
/**
|
|
@@ -1598,6 +1651,19 @@ class ve {
|
|
|
1598
1651
|
get cellHeight() {
|
|
1599
1652
|
return this._cellHeight;
|
|
1600
1653
|
}
|
|
1654
|
+
/**
|
|
1655
|
+
* Dispose of this TextmodeGrid and clean up references.
|
|
1656
|
+
* This method is idempotent and safe to call multiple times.
|
|
1657
|
+
*/
|
|
1658
|
+
dispose() {
|
|
1659
|
+
this._canvas = null, this._cols = 0, this._rows = 0, this._width = 0, this._height = 0, this._offsetX = 0, this._offsetY = 0, this._cellWidth = 0, this._cellHeight = 0;
|
|
1660
|
+
}
|
|
1661
|
+
/**
|
|
1662
|
+
* Check if this TextmodeGrid has been disposed
|
|
1663
|
+
*/
|
|
1664
|
+
get isDisposed() {
|
|
1665
|
+
return this._canvas === null;
|
|
1666
|
+
}
|
|
1601
1667
|
/** Returns the number of columns in the grid. */
|
|
1602
1668
|
get cols() {
|
|
1603
1669
|
return this._cols;
|
|
@@ -1623,28 +1689,28 @@ class ve {
|
|
|
1623
1689
|
return this._offsetY;
|
|
1624
1690
|
}
|
|
1625
1691
|
}
|
|
1626
|
-
class
|
|
1692
|
+
class be {
|
|
1627
1693
|
constructor(e, t = !1, r = {}) {
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1694
|
+
a(this, "_canvas");
|
|
1695
|
+
a(this, "captureSource");
|
|
1696
|
+
a(this, "_isStandalone");
|
|
1631
1697
|
this.captureSource = e, this._isStandalone = t, this._canvas = this.createCanvas(r.width, r.height);
|
|
1632
1698
|
}
|
|
1633
1699
|
createCanvas(e, t) {
|
|
1634
1700
|
var i;
|
|
1635
1701
|
const r = document.createElement("canvas");
|
|
1636
|
-
if (r.className = "textmodeCanvas", this._isStandalone)
|
|
1702
|
+
if (r.className = "textmodeCanvas", r.style.imageRendering = "pixelated", this._isStandalone)
|
|
1637
1703
|
r.width = e || 800, r.height = t || 600, document.body.appendChild(r);
|
|
1638
1704
|
else {
|
|
1639
1705
|
const s = this.captureSource.getBoundingClientRect();
|
|
1640
|
-
let
|
|
1706
|
+
let o = Math.round(s.width), n = Math.round(s.height);
|
|
1641
1707
|
if (this.captureSource instanceof HTMLVideoElement) {
|
|
1642
1708
|
const u = this.captureSource;
|
|
1643
|
-
(
|
|
1709
|
+
(o === 0 || n === 0) && u.videoWidth > 0 && u.videoHeight > 0 && (o = u.videoWidth, n = u.videoHeight);
|
|
1644
1710
|
}
|
|
1645
|
-
r.width =
|
|
1646
|
-
const
|
|
1647
|
-
let c = parseInt(
|
|
1711
|
+
r.width = o, r.height = n, r.style.position = "absolute", r.style.pointerEvents = "none";
|
|
1712
|
+
const l = window.getComputedStyle(this.captureSource);
|
|
1713
|
+
let c = parseInt(l.zIndex || "0", 10);
|
|
1648
1714
|
isNaN(c) && (c = 0), r.style.zIndex = (c + 1).toString(), this.positionOverlayCanvas(r), (i = this.captureSource.parentNode) == null || i.insertBefore(r, this.captureSource.nextSibling);
|
|
1649
1715
|
}
|
|
1650
1716
|
return r;
|
|
@@ -1665,8 +1731,8 @@ class Ce {
|
|
|
1665
1731
|
const r = this.captureSource.getBoundingClientRect();
|
|
1666
1732
|
let i = Math.round(r.width), s = Math.round(r.height);
|
|
1667
1733
|
if (this.captureSource instanceof HTMLVideoElement) {
|
|
1668
|
-
const
|
|
1669
|
-
(i === 0 || s === 0) &&
|
|
1734
|
+
const o = this.captureSource;
|
|
1735
|
+
(i === 0 || s === 0) && o.videoWidth > 0 && o.videoHeight > 0 && (i = o.videoWidth, s = o.videoHeight);
|
|
1670
1736
|
}
|
|
1671
1737
|
this._canvas.width = i, this._canvas.height = s, this.positionOverlayCanvas(this._canvas);
|
|
1672
1738
|
}
|
|
@@ -1688,6 +1754,27 @@ class Ce {
|
|
|
1688
1754
|
throw new F("WebGL context could not be created. Ensure your browser supports WebGL.");
|
|
1689
1755
|
return t;
|
|
1690
1756
|
}
|
|
1757
|
+
/**
|
|
1758
|
+
* Dispose of this TextmodeCanvas and clean up all resources.
|
|
1759
|
+
* This method is idempotent and safe to call multiple times.
|
|
1760
|
+
*/
|
|
1761
|
+
dispose() {
|
|
1762
|
+
if (this._canvas) {
|
|
1763
|
+
const e = this._canvas.getContext("webgl") || this._canvas.getContext("webgl2");
|
|
1764
|
+
if (e) {
|
|
1765
|
+
const t = e.getExtension("WEBGL_lose_context");
|
|
1766
|
+
t && t.loseContext();
|
|
1767
|
+
}
|
|
1768
|
+
this._canvas.parentNode && this._canvas.parentNode.removeChild(this._canvas), this._canvas = null;
|
|
1769
|
+
}
|
|
1770
|
+
this.captureSource = null;
|
|
1771
|
+
}
|
|
1772
|
+
/**
|
|
1773
|
+
* Check if this TextmodeCanvas has been disposed
|
|
1774
|
+
*/
|
|
1775
|
+
get isDisposed() {
|
|
1776
|
+
return this._canvas === null;
|
|
1777
|
+
}
|
|
1691
1778
|
get canvas() {
|
|
1692
1779
|
return this._canvas;
|
|
1693
1780
|
}
|
|
@@ -1708,15 +1795,15 @@ class U {
|
|
|
1708
1795
|
* @ignore
|
|
1709
1796
|
*/
|
|
1710
1797
|
constructor(e, t, r, i = {}) {
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1798
|
+
a(this, "renderer");
|
|
1799
|
+
a(this, "fontManager");
|
|
1800
|
+
a(this, "grid");
|
|
1801
|
+
a(this, "_characterFramebuffer");
|
|
1802
|
+
a(this, "_primaryColorFramebuffer");
|
|
1803
|
+
a(this, "_secondaryColorFramebuffer");
|
|
1804
|
+
a(this, "_rotationFramebuffer");
|
|
1805
|
+
a(this, "_transformFramebuffer");
|
|
1806
|
+
a(this, "_options");
|
|
1720
1807
|
this.renderer = e, this.fontManager = t, this.grid = r, this._options = i, this._characterFramebuffer = this.renderer.createFramebuffer(this.grid.cols, this.grid.rows), this._primaryColorFramebuffer = this.renderer.createFramebuffer(this.grid.cols, this.grid.rows), this._secondaryColorFramebuffer = this.renderer.createFramebuffer(this.grid.cols, this.grid.rows), this._rotationFramebuffer = this.renderer.createFramebuffer(this.grid.cols, this.grid.rows), this._transformFramebuffer = this.renderer.createFramebuffer(this.grid.cols, this.grid.rows);
|
|
1721
1808
|
}
|
|
1722
1809
|
/**
|
|
@@ -1745,6 +1832,19 @@ class U {
|
|
|
1745
1832
|
disable() {
|
|
1746
1833
|
this.enabled(!1);
|
|
1747
1834
|
}
|
|
1835
|
+
/**
|
|
1836
|
+
* Dispose of all framebuffers used by this converter.
|
|
1837
|
+
* This method is idempotent and safe to call multiple times.
|
|
1838
|
+
*/
|
|
1839
|
+
dispose() {
|
|
1840
|
+
this._characterFramebuffer && !this._characterFramebuffer.isDisposed && this._characterFramebuffer.dispose(), this._primaryColorFramebuffer && !this._primaryColorFramebuffer.isDisposed && this._primaryColorFramebuffer.dispose(), this._secondaryColorFramebuffer && !this._secondaryColorFramebuffer.isDisposed && this._secondaryColorFramebuffer.dispose(), this._rotationFramebuffer && !this._rotationFramebuffer.isDisposed && this._rotationFramebuffer.dispose(), this._transformFramebuffer && !this._transformFramebuffer.isDisposed && this._transformFramebuffer.dispose(), this._characterFramebuffer = null, this._primaryColorFramebuffer = null, this._secondaryColorFramebuffer = null, this._rotationFramebuffer = null, this._transformFramebuffer = null;
|
|
1841
|
+
}
|
|
1842
|
+
/**
|
|
1843
|
+
* Check if this converter has been disposed
|
|
1844
|
+
*/
|
|
1845
|
+
get isDisposed() {
|
|
1846
|
+
return this._characterFramebuffer === null;
|
|
1847
|
+
}
|
|
1748
1848
|
/** Returns the framebuffer containing character data. */
|
|
1749
1849
|
get characterFramebuffer() {
|
|
1750
1850
|
return this._characterFramebuffer;
|
|
@@ -1770,7 +1870,7 @@ class U {
|
|
|
1770
1870
|
return this._options;
|
|
1771
1871
|
}
|
|
1772
1872
|
}
|
|
1773
|
-
class
|
|
1873
|
+
class Ce {
|
|
1774
1874
|
/**
|
|
1775
1875
|
* Create a new color palette instance.
|
|
1776
1876
|
* @param renderer The renderer instance.
|
|
@@ -1778,9 +1878,9 @@ class be {
|
|
|
1778
1878
|
*/
|
|
1779
1879
|
constructor(e, t) {
|
|
1780
1880
|
/** The framebuffer used to store the color palette. */
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1881
|
+
a(this, "_framebuffer");
|
|
1882
|
+
a(this, "_renderer");
|
|
1883
|
+
a(this, "_colors");
|
|
1784
1884
|
this._renderer = e, this._colors = t;
|
|
1785
1885
|
const r = Math.max(this._colors.length, 1);
|
|
1786
1886
|
this._framebuffer = this._renderer.createFramebuffer(r, 1), this._updateFramebuffer();
|
|
@@ -1794,8 +1894,8 @@ class be {
|
|
|
1794
1894
|
this._framebuffer.width !== e && this._framebuffer.resize(e, t);
|
|
1795
1895
|
const r = new Uint8Array(e * t * 4);
|
|
1796
1896
|
for (let i = 0; i < e; i++) {
|
|
1797
|
-
const s = i < this._colors.length ? this._colors[i] : [0, 0, 0],
|
|
1798
|
-
r[
|
|
1897
|
+
const s = i < this._colors.length ? this._colors[i] : [0, 0, 0], o = i * 4;
|
|
1898
|
+
r[o] = s[0], r[o + 1] = s[1], r[o + 2] = s[2], r[o + 3] = 255;
|
|
1799
1899
|
}
|
|
1800
1900
|
this._framebuffer.updatePixels(r, e, t);
|
|
1801
1901
|
}
|
|
@@ -1828,8 +1928,8 @@ class be {
|
|
|
1828
1928
|
class X extends U {
|
|
1829
1929
|
constructor(t, r, i, s = {}) {
|
|
1830
1930
|
super(t, r, i, s);
|
|
1831
|
-
|
|
1832
|
-
this.palette = new
|
|
1931
|
+
a(this, "palette");
|
|
1932
|
+
this.palette = new Ce(this.renderer, this.fontManager.getCharacterColors(" .:-=+*%@#"));
|
|
1833
1933
|
}
|
|
1834
1934
|
/**
|
|
1835
1935
|
* Sets the characters used for mapping.
|
|
@@ -1852,7 +1952,7 @@ class X extends U {
|
|
|
1852
1952
|
*/
|
|
1853
1953
|
characterColor(t, r = t, i = t, s = 255) {
|
|
1854
1954
|
x.validate(
|
|
1855
|
-
[t, r, i, s].every((
|
|
1955
|
+
[t, r, i, s].every((o) => o >= 0 && o <= 255),
|
|
1856
1956
|
"Character color values must be between 0 and 255",
|
|
1857
1957
|
{ method: "characterColor", providedValues: { r: t, g: r, b: i, a: s } }
|
|
1858
1958
|
) && (this._options.characterColor = [t, r, i, s]);
|
|
@@ -1880,7 +1980,7 @@ class X extends U {
|
|
|
1880
1980
|
*/
|
|
1881
1981
|
cellColor(t, r = t, i = t, s = 255) {
|
|
1882
1982
|
x.validate(
|
|
1883
|
-
[t, r, i, s].every((
|
|
1983
|
+
[t, r, i, s].every((o) => o >= 0 && o <= 255),
|
|
1884
1984
|
"Cell color values must be between 0 and 255",
|
|
1885
1985
|
{ method: "cellColor", providedValues: { r: t, g: r, b: i, a: s } }
|
|
1886
1986
|
) && (this._options.cellColor = [t, r, i, s]);
|
|
@@ -1982,12 +2082,12 @@ class L extends X {
|
|
|
1982
2082
|
*/
|
|
1983
2083
|
constructor(t, r, i) {
|
|
1984
2084
|
super(t, r, i, { ...Re });
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
2085
|
+
a(this, "sampleShader");
|
|
2086
|
+
a(this, "colorFillShader");
|
|
2087
|
+
a(this, "charMappingShader");
|
|
2088
|
+
a(this, "transformFillShader");
|
|
2089
|
+
a(this, "rotationFillShader");
|
|
2090
|
+
a(this, "sampleFramebuffer");
|
|
1991
2091
|
this.sampleShader = new T(t.context, S, Fe), this.colorFillShader = new T(t.context, S, we), this.transformFillShader = new T(t.context, S, ye), this.rotationFillShader = new T(t.context, S, Te), this.charMappingShader = new T(t.context, S, Se), this.sampleFramebuffer = this.renderer.createFramebuffer(this.grid.cols, this.grid.rows);
|
|
1992
2092
|
}
|
|
1993
2093
|
convert(t) {
|
|
@@ -2027,17 +2127,17 @@ class Ue {
|
|
|
2027
2127
|
* @ignore
|
|
2028
2128
|
*/
|
|
2029
2129
|
constructor(e, t, r) {
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2130
|
+
a(this, "renderer");
|
|
2131
|
+
a(this, "font");
|
|
2132
|
+
a(this, "grid");
|
|
2133
|
+
a(this, "converters");
|
|
2134
|
+
a(this, "_resultFramebuffer");
|
|
2135
|
+
a(this, "_asciiShader");
|
|
2136
|
+
a(this, "_characterFramebuffer");
|
|
2137
|
+
a(this, "_primaryColorFramebuffer");
|
|
2138
|
+
a(this, "_secondaryColorFramebuffer");
|
|
2139
|
+
a(this, "_rotationFramebuffer");
|
|
2140
|
+
a(this, "_transformFramebuffer");
|
|
2041
2141
|
this.renderer = e, this.font = t, this.grid = r, this._asciiShader = this.renderer.createShader(S, Ee), this.converters = [
|
|
2042
2142
|
{ name: "brightness", converter: new L(e, t, r) },
|
|
2043
2143
|
{ name: "custom", converter: new U(e, t, r) }
|
|
@@ -2056,8 +2156,8 @@ class Ue {
|
|
|
2056
2156
|
const t = (r, i) => {
|
|
2057
2157
|
r.begin(), this.renderer.clear();
|
|
2058
2158
|
for (const s of this.converters) {
|
|
2059
|
-
const
|
|
2060
|
-
|
|
2159
|
+
const o = s.converter;
|
|
2160
|
+
o.options.enabled && this.renderer.image(i(o), 0, 0);
|
|
2061
2161
|
}
|
|
2062
2162
|
r.end();
|
|
2063
2163
|
};
|
|
@@ -2167,6 +2267,21 @@ class Ue {
|
|
|
2167
2267
|
for (const e of this.converters)
|
|
2168
2268
|
e.converter.enable();
|
|
2169
2269
|
}
|
|
2270
|
+
/**
|
|
2271
|
+
* Dispose of all resources used by this conversion pipeline.
|
|
2272
|
+
* This method is idempotent and safe to call multiple times.
|
|
2273
|
+
*/
|
|
2274
|
+
dispose() {
|
|
2275
|
+
for (const e of this.converters)
|
|
2276
|
+
e.converter && !e.converter.isDisposed && e.converter.dispose();
|
|
2277
|
+
this._characterFramebuffer && !this._characterFramebuffer.isDisposed && this._characterFramebuffer.dispose(), this._primaryColorFramebuffer && !this._primaryColorFramebuffer.isDisposed && this._primaryColorFramebuffer.dispose(), this._secondaryColorFramebuffer && !this._secondaryColorFramebuffer.isDisposed && this._secondaryColorFramebuffer.dispose(), this._rotationFramebuffer && !this._rotationFramebuffer.isDisposed && this._rotationFramebuffer.dispose(), this._transformFramebuffer && !this._transformFramebuffer.isDisposed && this._transformFramebuffer.dispose(), this._resultFramebuffer && !this._resultFramebuffer.isDisposed && this._resultFramebuffer.dispose(), this._asciiShader && !this._asciiShader.isDisposed && this._asciiShader.dispose(), this.converters = [], this._characterFramebuffer = null, this._primaryColorFramebuffer = null, this._secondaryColorFramebuffer = null, this._rotationFramebuffer = null, this._transformFramebuffer = null, this._resultFramebuffer = null, this._asciiShader = null;
|
|
2278
|
+
}
|
|
2279
|
+
/**
|
|
2280
|
+
* Check if this conversion pipeline has been disposed
|
|
2281
|
+
*/
|
|
2282
|
+
get isDisposed() {
|
|
2283
|
+
return this._resultFramebuffer === null || this._asciiShader === null;
|
|
2284
|
+
}
|
|
2170
2285
|
/** Returns the character framebuffer containing the combined result of all converters. */
|
|
2171
2286
|
get characterFramebuffer() {
|
|
2172
2287
|
return this._characterFramebuffer;
|
|
@@ -2195,12 +2310,12 @@ class H {
|
|
|
2195
2310
|
* @returns Object containing all pixel data arrays
|
|
2196
2311
|
*/
|
|
2197
2312
|
extractFramebufferData(e) {
|
|
2198
|
-
const t = e.get("brightness"), r = t == null ? void 0 : t.characterFramebuffer, i = t == null ? void 0 : t.primaryColorFramebuffer, s = t == null ? void 0 : t.secondaryColorFramebuffer,
|
|
2199
|
-
return r == null || r.loadPixels(), i == null || i.loadPixels(), s == null || s.loadPixels(),
|
|
2313
|
+
const t = e.get("brightness"), r = t == null ? void 0 : t.characterFramebuffer, i = t == null ? void 0 : t.primaryColorFramebuffer, s = t == null ? void 0 : t.secondaryColorFramebuffer, o = t == null ? void 0 : t.transformFramebuffer, n = t == null ? void 0 : t.rotationFramebuffer;
|
|
2314
|
+
return r == null || r.loadPixels(), i == null || i.loadPixels(), s == null || s.loadPixels(), o == null || o.loadPixels(), n == null || n.loadPixels(), {
|
|
2200
2315
|
characterPixels: (r == null ? void 0 : r.pixels) || new Uint8Array(0),
|
|
2201
2316
|
primaryColorPixels: (i == null ? void 0 : i.pixels) || new Uint8Array(0),
|
|
2202
2317
|
secondaryColorPixels: (s == null ? void 0 : s.pixels) || new Uint8Array(0),
|
|
2203
|
-
transformPixels: (
|
|
2318
|
+
transformPixels: (o == null ? void 0 : o.pixels) || new Uint8Array(0),
|
|
2204
2319
|
rotationPixels: (n == null ? void 0 : n.pixels) || new Uint8Array(0)
|
|
2205
2320
|
};
|
|
2206
2321
|
}
|
|
@@ -2248,8 +2363,8 @@ class N {
|
|
|
2248
2363
|
*/
|
|
2249
2364
|
downloadFile(e, t, r) {
|
|
2250
2365
|
try {
|
|
2251
|
-
const i = this.createBlob(e, r), s = URL.createObjectURL(i),
|
|
2252
|
-
|
|
2366
|
+
const i = this.createBlob(e, r), s = URL.createObjectURL(i), o = document.createElement("a");
|
|
2367
|
+
o.href = s, o.download = t, o.style.display = "none", o.rel = "noopener", document.body.appendChild(o), o.click(), document.body.removeChild(o), URL.revokeObjectURL(s);
|
|
2253
2368
|
} catch (i) {
|
|
2254
2369
|
throw console.error("Failed to download file:", i), new Error(`File download failed: ${i instanceof Error ? i.message : "Unknown error"}`);
|
|
2255
2370
|
}
|
|
@@ -2287,7 +2402,7 @@ class N {
|
|
|
2287
2402
|
return `'textmode-export'-${this.generateTimestamp()}`;
|
|
2288
2403
|
}
|
|
2289
2404
|
}
|
|
2290
|
-
class
|
|
2405
|
+
class De extends H {
|
|
2291
2406
|
/**
|
|
2292
2407
|
* Extracts transform data from transform pixels
|
|
2293
2408
|
* @param transformPixels Transform framebuffer pixels
|
|
@@ -2296,10 +2411,10 @@ class Ae extends H {
|
|
|
2296
2411
|
* @returns Transform data object
|
|
2297
2412
|
*/
|
|
2298
2413
|
extractTransformData(e, t, r) {
|
|
2299
|
-
const i = e[r], s = e[r + 1],
|
|
2414
|
+
const i = e[r], s = e[r + 1], o = e[r + 2], n = i === 255, l = s === 255, c = o === 255, u = t[r], d = t[r + 1], f = u + d / 255, g = Math.round(f * 360 / 255 * 100) / 100;
|
|
2300
2415
|
return {
|
|
2301
2416
|
isInverted: n,
|
|
2302
|
-
flipHorizontal:
|
|
2417
|
+
flipHorizontal: l,
|
|
2303
2418
|
flipVertical: c,
|
|
2304
2419
|
rotation: g
|
|
2305
2420
|
};
|
|
@@ -2330,8 +2445,8 @@ class Ae extends H {
|
|
|
2330
2445
|
const r = [];
|
|
2331
2446
|
let i = 0;
|
|
2332
2447
|
for (let s = 0; s < t.rows; s++)
|
|
2333
|
-
for (let
|
|
2334
|
-
const n = i * 4,
|
|
2448
|
+
for (let o = 0; o < t.cols; o++) {
|
|
2449
|
+
const n = i * 4, l = this.getCharacterIndex(
|
|
2335
2450
|
e.characterPixels,
|
|
2336
2451
|
n
|
|
2337
2452
|
);
|
|
@@ -2345,9 +2460,9 @@ class Ae extends H {
|
|
|
2345
2460
|
const g = c;
|
|
2346
2461
|
c = u, u = g;
|
|
2347
2462
|
}
|
|
2348
|
-
const f = this.calculateCellPosition(
|
|
2463
|
+
const f = this.calculateCellPosition(o, s, t);
|
|
2349
2464
|
r.push({
|
|
2350
|
-
charIndex:
|
|
2465
|
+
charIndex: l,
|
|
2351
2466
|
primaryColor: c,
|
|
2352
2467
|
secondaryColor: u,
|
|
2353
2468
|
transform: d,
|
|
@@ -2357,7 +2472,7 @@ class Ae extends H {
|
|
|
2357
2472
|
return r;
|
|
2358
2473
|
}
|
|
2359
2474
|
}
|
|
2360
|
-
class
|
|
2475
|
+
class Ae {
|
|
2361
2476
|
/**
|
|
2362
2477
|
* Gets the glyph index for a given Unicode code point in a Typr.js font
|
|
2363
2478
|
* @param fontData The Typr.js font data
|
|
@@ -2374,9 +2489,9 @@ class Me {
|
|
|
2374
2489
|
if (i.idRangeOffset[s] === 0)
|
|
2375
2490
|
return t + i.idDelta[s] & 65535;
|
|
2376
2491
|
{
|
|
2377
|
-
const
|
|
2378
|
-
if (
|
|
2379
|
-
const n = i.glyphIdArray[
|
|
2492
|
+
const o = i.idRangeOffset[s] / 2 + (t - i.startCount[s]) - (i.startCount.length - s);
|
|
2493
|
+
if (o >= 0 && o < i.glyphIdArray.length) {
|
|
2494
|
+
const n = i.glyphIdArray[o];
|
|
2380
2495
|
if (n !== 0)
|
|
2381
2496
|
return n + i.idDelta[s] & 65535;
|
|
2382
2497
|
}
|
|
@@ -2407,15 +2522,15 @@ class Me {
|
|
|
2407
2522
|
createGlyphPath(e, t, r, i, s) {
|
|
2408
2523
|
if (!t || !t.xs || t.xs.length === 0)
|
|
2409
2524
|
return this.createEmptyPath();
|
|
2410
|
-
const
|
|
2525
|
+
const o = s / e.head.unitsPerEm;
|
|
2411
2526
|
return {
|
|
2412
2527
|
getBoundingBox: () => ({
|
|
2413
|
-
x1: r + t.xMin *
|
|
2414
|
-
y1: i + -t.yMax *
|
|
2415
|
-
x2: r + t.xMax *
|
|
2416
|
-
y2: i + -t.yMin *
|
|
2528
|
+
x1: r + t.xMin * o,
|
|
2529
|
+
y1: i + -t.yMax * o,
|
|
2530
|
+
x2: r + t.xMax * o,
|
|
2531
|
+
y2: i + -t.yMin * o
|
|
2417
2532
|
}),
|
|
2418
|
-
toSVG: () => this.glyphToSVGPath(t, r, i,
|
|
2533
|
+
toSVG: () => this.glyphToSVGPath(t, r, i, o)
|
|
2419
2534
|
};
|
|
2420
2535
|
}
|
|
2421
2536
|
/**
|
|
@@ -2428,29 +2543,29 @@ class Me {
|
|
|
2428
2543
|
*/
|
|
2429
2544
|
glyphToSVGPath(e, t, r, i) {
|
|
2430
2545
|
if (!e || !e.xs) return "";
|
|
2431
|
-
const { xs: s, ys:
|
|
2432
|
-
if (!s || !
|
|
2546
|
+
const { xs: s, ys: o, endPts: n, flags: l } = e;
|
|
2547
|
+
if (!s || !o || !n || !l) return "";
|
|
2433
2548
|
let c = "", u = 0;
|
|
2434
2549
|
for (let d = 0; d < n.length; d++) {
|
|
2435
2550
|
const f = n[d];
|
|
2436
2551
|
if (!(f < u)) {
|
|
2437
2552
|
if (f >= u) {
|
|
2438
|
-
const g = t + s[u] * i,
|
|
2439
|
-
c += `M${g.toFixed(2)},${
|
|
2440
|
-
let
|
|
2441
|
-
for (;
|
|
2442
|
-
if ((
|
|
2443
|
-
const
|
|
2444
|
-
c += `L${
|
|
2553
|
+
const g = t + s[u] * i, p = r - o[u] * i;
|
|
2554
|
+
c += `M${g.toFixed(2)},${p.toFixed(2)}`;
|
|
2555
|
+
let _ = u + 1;
|
|
2556
|
+
for (; _ <= f; )
|
|
2557
|
+
if ((l[_] & 1) !== 0) {
|
|
2558
|
+
const C = t + s[_] * i, v = r - o[_] * i;
|
|
2559
|
+
c += `L${C.toFixed(2)},${v.toFixed(2)}`, _++;
|
|
2445
2560
|
} else {
|
|
2446
|
-
const
|
|
2447
|
-
let w =
|
|
2448
|
-
if ((
|
|
2449
|
-
const R = t + s[w] * i, y = r -
|
|
2450
|
-
c += `Q${
|
|
2561
|
+
const C = t + s[_] * i, v = r - o[_] * i;
|
|
2562
|
+
let w = _ + 1 > f ? u : _ + 1;
|
|
2563
|
+
if ((l[w] & 1) !== 0) {
|
|
2564
|
+
const R = t + s[w] * i, y = r - o[w] * i;
|
|
2565
|
+
c += `Q${C.toFixed(2)},${v.toFixed(2)} ${R.toFixed(2)},${y.toFixed(2)}`, _ = w + 1;
|
|
2451
2566
|
} else {
|
|
2452
|
-
const R = t + s[w] * i, y = r -
|
|
2453
|
-
c += `Q${
|
|
2567
|
+
const R = t + s[w] * i, y = r - o[w] * i, P = (C + R) / 2, M = (v + y) / 2;
|
|
2568
|
+
c += `Q${C.toFixed(2)},${v.toFixed(2)} ${P.toFixed(2)},${M.toFixed(2)}`, _ = w;
|
|
2454
2569
|
}
|
|
2455
2570
|
}
|
|
2456
2571
|
c += "Z";
|
|
@@ -2471,18 +2586,18 @@ class Me {
|
|
|
2471
2586
|
*/
|
|
2472
2587
|
generateCharacterPath(e, t, r, i, s) {
|
|
2473
2588
|
try {
|
|
2474
|
-
const
|
|
2589
|
+
const o = e.codePointAt(0) || 0, n = this.getGlyphIndex(t, o);
|
|
2475
2590
|
if (n === 0)
|
|
2476
2591
|
return this.createEmptyPath();
|
|
2477
|
-
let
|
|
2592
|
+
let l = null;
|
|
2478
2593
|
try {
|
|
2479
|
-
t.glyf && t.glyf[n] !== null ?
|
|
2594
|
+
t.glyf && t.glyf[n] !== null ? l = t.glyf[n] : m && m.T && m.T.glyf && m.T.glyf._parseGlyf && (l = m.T.glyf._parseGlyf(t, n), t.glyf && l && (t.glyf[n] = l));
|
|
2480
2595
|
} catch (c) {
|
|
2481
2596
|
console.warn(`Failed to parse glyph ${n}:`, c);
|
|
2482
2597
|
}
|
|
2483
|
-
return
|
|
2484
|
-
} catch (
|
|
2485
|
-
return console.warn(`Failed to generate path for character "${e}":`,
|
|
2598
|
+
return l ? this.createGlyphPath(t, l, r, i, s) : this.createEmptyPath();
|
|
2599
|
+
} catch (o) {
|
|
2600
|
+
return console.warn(`Failed to generate path for character "${e}":`, o), this.createEmptyPath();
|
|
2486
2601
|
}
|
|
2487
2602
|
}
|
|
2488
2603
|
/**
|
|
@@ -2497,19 +2612,19 @@ class Me {
|
|
|
2497
2612
|
* @param advanceWidth Character advance width
|
|
2498
2613
|
* @returns SVG path data string or null if generation fails
|
|
2499
2614
|
*/
|
|
2500
|
-
generatePositionedCharacterPath(e, t, r, i, s,
|
|
2615
|
+
generatePositionedCharacterPath(e, t, r, i, s, o, n, l) {
|
|
2501
2616
|
try {
|
|
2502
|
-
const c = n / t.head.unitsPerEm, u =
|
|
2617
|
+
const c = n / t.head.unitsPerEm, u = l * c, d = r + (s - u) / 2, f = i + (o + n * 0.7) / 2;
|
|
2503
2618
|
return this.generateCharacterPath(e, t, d, f, n).toSVG() || null;
|
|
2504
2619
|
} catch (c) {
|
|
2505
2620
|
return console.warn(`Failed to generate positioned character path for "${e}":`, c), null;
|
|
2506
2621
|
}
|
|
2507
2622
|
}
|
|
2508
2623
|
}
|
|
2509
|
-
class
|
|
2624
|
+
class Me {
|
|
2510
2625
|
constructor() {
|
|
2511
|
-
|
|
2512
|
-
this.pathGenerator = new
|
|
2626
|
+
a(this, "pathGenerator");
|
|
2627
|
+
this.pathGenerator = new Ae();
|
|
2513
2628
|
}
|
|
2514
2629
|
/**
|
|
2515
2630
|
* Generates the SVG header with metadata
|
|
@@ -2561,12 +2676,12 @@ class De {
|
|
|
2561
2676
|
* @returns Transform attribute string or empty string
|
|
2562
2677
|
*/
|
|
2563
2678
|
generateTransformAttribute(e, t) {
|
|
2564
|
-
const { transform: r, position: i } = e, s = i.cellX + t.cellWidth / 2,
|
|
2679
|
+
const { transform: r, position: i } = e, s = i.cellX + t.cellWidth / 2, o = i.cellY + t.cellHeight / 2, n = [];
|
|
2565
2680
|
if (r.flipHorizontal || r.flipVertical) {
|
|
2566
|
-
const
|
|
2567
|
-
n.push(`translate(${s} ${
|
|
2681
|
+
const l = r.flipHorizontal ? -1 : 1, c = r.flipVertical ? -1 : 1;
|
|
2682
|
+
n.push(`translate(${s} ${o})`), n.push(`scale(${l} ${c})`), n.push(`translate(${-s} ${-o})`);
|
|
2568
2683
|
}
|
|
2569
|
-
return r.rotation && n.push(`rotate(${r.rotation} ${s} ${
|
|
2684
|
+
return r.rotation && n.push(`rotate(${r.rotation} ${s} ${o})`), n.length ? ` transform="${n.join(" ")}"` : "";
|
|
2570
2685
|
}
|
|
2571
2686
|
/**
|
|
2572
2687
|
* Generates background rectangle for a cell
|
|
@@ -2595,7 +2710,7 @@ class De {
|
|
|
2595
2710
|
const s = r.characters[e.charIndex];
|
|
2596
2711
|
if (!s)
|
|
2597
2712
|
return "";
|
|
2598
|
-
const
|
|
2713
|
+
const o = this.pathGenerator.generatePositionedCharacterPath(
|
|
2599
2714
|
s.character,
|
|
2600
2715
|
r.font,
|
|
2601
2716
|
e.position.cellX,
|
|
@@ -2605,12 +2720,12 @@ class De {
|
|
|
2605
2720
|
r.fontSize,
|
|
2606
2721
|
s.advanceWidth
|
|
2607
2722
|
);
|
|
2608
|
-
if (!
|
|
2723
|
+
if (!o)
|
|
2609
2724
|
return "";
|
|
2610
2725
|
const n = this.rgbaToColorString(e.primaryColor);
|
|
2611
2726
|
return i.drawMode === "stroke" ? `
|
|
2612
|
-
<path id="${`path-${e.charIndex}-${e.position.cellX}-${e.position.cellY}`.replace(/\./g, "-")}" d="${
|
|
2613
|
-
<path d="${
|
|
2727
|
+
<path id="${`path-${e.charIndex}-${e.position.cellX}-${e.position.cellY}`.replace(/\./g, "-")}" d="${o}" stroke="${n}" stroke-width="${i.strokeWidth}" fill="none" />` : `
|
|
2728
|
+
<path d="${o}" fill="${n}" />`;
|
|
2614
2729
|
}
|
|
2615
2730
|
/**
|
|
2616
2731
|
* Generates complete SVG content for a single cell
|
|
@@ -2623,9 +2738,9 @@ class De {
|
|
|
2623
2738
|
generateCellContent(e, t, r, i) {
|
|
2624
2739
|
let s = "";
|
|
2625
2740
|
s += this.generateCellBackground(e, t, i);
|
|
2626
|
-
const
|
|
2627
|
-
return n && (
|
|
2628
|
-
<g${
|
|
2741
|
+
const o = this.generateTransformAttribute(e, t), n = this.generateCharacterPath(e, t, r, i);
|
|
2742
|
+
return n && (o ? (s += `
|
|
2743
|
+
<g${o}>`, s += n, s += `
|
|
2629
2744
|
</g>`) : s += n), s;
|
|
2630
2745
|
}
|
|
2631
2746
|
/**
|
|
@@ -2640,8 +2755,8 @@ class De {
|
|
|
2640
2755
|
let s = this.generateSVGHeader(t);
|
|
2641
2756
|
s += this.generateBackground(t, i), s += `
|
|
2642
2757
|
<g id="ascii-cells">`;
|
|
2643
|
-
for (const
|
|
2644
|
-
s += this.generateCellContent(
|
|
2758
|
+
for (const o of e)
|
|
2759
|
+
s += this.generateCellContent(o, t, r, i);
|
|
2645
2760
|
return s += this.generateSVGFooter(), s;
|
|
2646
2761
|
}
|
|
2647
2762
|
/**
|
|
@@ -2686,10 +2801,10 @@ class Ie extends N {
|
|
|
2686
2801
|
}
|
|
2687
2802
|
class Y {
|
|
2688
2803
|
constructor() {
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
this.dataExtractor = new
|
|
2804
|
+
a(this, "dataExtractor");
|
|
2805
|
+
a(this, "contentGenerator");
|
|
2806
|
+
a(this, "fileHandler");
|
|
2807
|
+
this.dataExtractor = new De(), this.contentGenerator = new Me(), this.fileHandler = new Ie();
|
|
2693
2808
|
}
|
|
2694
2809
|
/**
|
|
2695
2810
|
* Applies default values to SVG export options
|
|
@@ -2714,13 +2829,13 @@ class Y {
|
|
|
2714
2829
|
const r = this.applyDefaultOptions(t), i = this.dataExtractor.extractFramebufferData(e.pipeline), s = this.dataExtractor.extractSVGCellData(
|
|
2715
2830
|
i,
|
|
2716
2831
|
e.grid
|
|
2717
|
-
),
|
|
2832
|
+
), o = this.contentGenerator.generateSVGContent(
|
|
2718
2833
|
s,
|
|
2719
2834
|
e.grid,
|
|
2720
2835
|
e.font,
|
|
2721
2836
|
r
|
|
2722
2837
|
);
|
|
2723
|
-
return this.contentGenerator.optimizeSVGContent(
|
|
2838
|
+
return this.contentGenerator.optimizeSVGContent(o);
|
|
2724
2839
|
}
|
|
2725
2840
|
/**
|
|
2726
2841
|
* Exports SVG content to a downloadable file
|
|
@@ -2748,15 +2863,15 @@ class Pe extends H {
|
|
|
2748
2863
|
extractCharacterGrid(e, t, r, i = " ") {
|
|
2749
2864
|
var n;
|
|
2750
2865
|
const s = [];
|
|
2751
|
-
let
|
|
2752
|
-
for (let
|
|
2866
|
+
let o = 0;
|
|
2867
|
+
for (let l = 0; l < t.rows; l++) {
|
|
2753
2868
|
const c = [];
|
|
2754
2869
|
for (let u = 0; u < t.cols; u++) {
|
|
2755
|
-
const d =
|
|
2870
|
+
const d = o * 4, f = this.getCharacterIndex(
|
|
2756
2871
|
e.characterPixels,
|
|
2757
2872
|
d
|
|
2758
2873
|
), g = ((n = r.characters[f]) == null ? void 0 : n.character) || i;
|
|
2759
|
-
c.push(g),
|
|
2874
|
+
c.push(g), o++;
|
|
2760
2875
|
}
|
|
2761
2876
|
s.push(c);
|
|
2762
2877
|
}
|
|
@@ -2773,8 +2888,8 @@ class Be {
|
|
|
2773
2888
|
generateTXTContent(e, t) {
|
|
2774
2889
|
const r = [];
|
|
2775
2890
|
for (const s of e) {
|
|
2776
|
-
let
|
|
2777
|
-
t.preserveTrailingSpaces || (
|
|
2891
|
+
let o = s.join("");
|
|
2892
|
+
t.preserveTrailingSpaces || (o = o.replace(/\s+$/, "")), r.push(o);
|
|
2778
2893
|
}
|
|
2779
2894
|
const i = t.lineEnding === "crlf" ? `\r
|
|
2780
2895
|
` : `
|
|
@@ -2808,9 +2923,9 @@ class Ge extends N {
|
|
|
2808
2923
|
}
|
|
2809
2924
|
class j {
|
|
2810
2925
|
constructor() {
|
|
2811
|
-
|
|
2812
|
-
|
|
2813
|
-
|
|
2926
|
+
a(this, "dataExtractor");
|
|
2927
|
+
a(this, "contentGenerator");
|
|
2928
|
+
a(this, "fileHandler");
|
|
2814
2929
|
this.dataExtractor = new Pe(), this.contentGenerator = new Be(), this.fileHandler = new Ge();
|
|
2815
2930
|
}
|
|
2816
2931
|
/**
|
|
@@ -2869,8 +2984,8 @@ class Ve extends H {
|
|
|
2869
2984
|
const i = e.canvas;
|
|
2870
2985
|
if (t === 1 && r === "transparent")
|
|
2871
2986
|
return i;
|
|
2872
|
-
const s = document.createElement("canvas"),
|
|
2873
|
-
return s.width = n, s.height =
|
|
2987
|
+
const s = document.createElement("canvas"), o = s.getContext("2d"), n = Math.round(i.width * t), l = Math.round(i.height * t);
|
|
2988
|
+
return s.width = n, s.height = l, r !== "transparent" && (o.fillStyle = r, o.fillRect(0, 0, n, l)), o.imageSmoothingEnabled = !1, o.drawImage(
|
|
2874
2989
|
i,
|
|
2875
2990
|
0,
|
|
2876
2991
|
0,
|
|
@@ -2879,7 +2994,7 @@ class Ve extends H {
|
|
|
2879
2994
|
0,
|
|
2880
2995
|
0,
|
|
2881
2996
|
n,
|
|
2882
|
-
|
|
2997
|
+
l
|
|
2883
2998
|
), s;
|
|
2884
2999
|
}
|
|
2885
3000
|
}
|
|
@@ -2902,10 +3017,10 @@ class ke {
|
|
|
2902
3017
|
*/
|
|
2903
3018
|
async generateImageBlob(e, t) {
|
|
2904
3019
|
return new Promise((r, i) => {
|
|
2905
|
-
const s = this.getMimeType(t.format),
|
|
3020
|
+
const s = this.getMimeType(t.format), o = (n) => {
|
|
2906
3021
|
n ? r(n) : i(new Error(`Failed to generate ${t.format.toUpperCase()} blob`));
|
|
2907
3022
|
};
|
|
2908
|
-
t.format === "png" ? e.toBlob(
|
|
3023
|
+
t.format === "png" ? e.toBlob(o, s) : e.toBlob(o, s, t.quality);
|
|
2909
3024
|
});
|
|
2910
3025
|
}
|
|
2911
3026
|
/**
|
|
@@ -2930,12 +3045,12 @@ const q = {
|
|
|
2930
3045
|
png: "image/png",
|
|
2931
3046
|
jpg: "image/jpeg",
|
|
2932
3047
|
webp: "image/webp"
|
|
2933
|
-
},
|
|
3048
|
+
}, z = {
|
|
2934
3049
|
png: ".png",
|
|
2935
3050
|
jpg: ".jpg",
|
|
2936
3051
|
webp: ".webp"
|
|
2937
3052
|
};
|
|
2938
|
-
class
|
|
3053
|
+
class ze extends N {
|
|
2939
3054
|
/**
|
|
2940
3055
|
* Saves image content as a downloadable file
|
|
2941
3056
|
* @param content The image content (data URL or blob)
|
|
@@ -2944,7 +3059,7 @@ class $e extends N {
|
|
|
2944
3059
|
*/
|
|
2945
3060
|
saveImage(e, t, r) {
|
|
2946
3061
|
try {
|
|
2947
|
-
const i =
|
|
3062
|
+
const i = z[r];
|
|
2948
3063
|
typeof e == "string" ? this.saveImageFromDataURL(e, this.sanitizeFilename(t) + i) : this.saveImageFromBlob(e, this.sanitizeFilename(t) + i);
|
|
2949
3064
|
} catch (i) {
|
|
2950
3065
|
throw console.error(`Failed to save ${r.toUpperCase()} image:`, i), new Error(`Image save failed: ${i instanceof Error ? i.message : "Unknown error"}`);
|
|
@@ -2979,7 +3094,7 @@ class $e extends N {
|
|
|
2979
3094
|
* @returns True if the format is supported for saving
|
|
2980
3095
|
*/
|
|
2981
3096
|
validateSaveSupport(e) {
|
|
2982
|
-
return e in q && e in
|
|
3097
|
+
return e in q && e in z;
|
|
2983
3098
|
}
|
|
2984
3099
|
/**
|
|
2985
3100
|
* Gets the MIME type for the specified image format
|
|
@@ -2995,15 +3110,15 @@ class $e extends N {
|
|
|
2995
3110
|
* @returns The file extension (including the dot)
|
|
2996
3111
|
*/
|
|
2997
3112
|
getFileExtension(e) {
|
|
2998
|
-
return
|
|
3113
|
+
return z[e];
|
|
2999
3114
|
}
|
|
3000
3115
|
}
|
|
3001
|
-
class
|
|
3116
|
+
class $e {
|
|
3002
3117
|
constructor() {
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
this.dataExtractor = new Ve(), this.contentGenerator = new ke(), this.fileHandler = new
|
|
3118
|
+
a(this, "dataExtractor");
|
|
3119
|
+
a(this, "contentGenerator");
|
|
3120
|
+
a(this, "fileHandler");
|
|
3121
|
+
this.dataExtractor = new Ve(), this.contentGenerator = new ke(), this.fileHandler = new ze();
|
|
3007
3122
|
}
|
|
3008
3123
|
/**
|
|
3009
3124
|
* Applies default values to image export options
|
|
@@ -3089,34 +3204,38 @@ class ze {
|
|
|
3089
3204
|
class I {
|
|
3090
3205
|
constructor(e = null, t = {}) {
|
|
3091
3206
|
/** The element to capture content from (optional for standalone mode) */
|
|
3092
|
-
|
|
3207
|
+
a(this, "captureSource");
|
|
3093
3208
|
/** Our WebGL overlay canvas manager */
|
|
3094
|
-
|
|
3209
|
+
a(this, "textmodeCanvas");
|
|
3095
3210
|
/** Core WebGL renderer */
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3211
|
+
a(this, "_renderer");
|
|
3212
|
+
a(this, "_canvasFramebuffer");
|
|
3213
|
+
a(this, "_font");
|
|
3214
|
+
a(this, "_grid");
|
|
3215
|
+
a(this, "resizeObserver");
|
|
3101
3216
|
// Auto-rendering properties
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3217
|
+
a(this, "_mode");
|
|
3218
|
+
a(this, "_frameRateLimit");
|
|
3219
|
+
a(this, "animationFrameId", null);
|
|
3220
|
+
a(this, "lastFrameTime", 0);
|
|
3221
|
+
a(this, "frameInterval");
|
|
3222
|
+
a(this, "_isLooping", !0);
|
|
3223
|
+
a(this, "_frameRate", 0);
|
|
3224
|
+
a(this, "lastRenderTime", 0);
|
|
3225
|
+
a(this, "_frameCount", 0);
|
|
3110
3226
|
// Frame rate measurement smoothing
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3227
|
+
a(this, "frameTimeHistory", []);
|
|
3228
|
+
a(this, "frameTimeHistorySize", 10);
|
|
3229
|
+
a(this, "_pipeline");
|
|
3114
3230
|
// Standalone canvas properties
|
|
3115
|
-
|
|
3116
|
-
|
|
3231
|
+
a(this, "_standalone", !1);
|
|
3232
|
+
a(this, "_drawCallback", () => {
|
|
3117
3233
|
});
|
|
3118
|
-
|
|
3234
|
+
a(this, "_resizedCallback", () => {
|
|
3119
3235
|
});
|
|
3236
|
+
// Destroy state
|
|
3237
|
+
a(this, "_isDestroyed", !1);
|
|
3238
|
+
a(this, "_windowResizeListener", null);
|
|
3120
3239
|
this.captureSource = e, this._standalone = e === null, this._mode = t.renderMode ?? "auto", this._frameRateLimit = t.frameRate ?? 60, this.frameInterval = 1e3 / this._frameRateLimit;
|
|
3121
3240
|
}
|
|
3122
3241
|
/**
|
|
@@ -3127,16 +3246,16 @@ class I {
|
|
|
3127
3246
|
*/
|
|
3128
3247
|
static async create(e = null, t = {}) {
|
|
3129
3248
|
const r = new I(e, t), i = r._standalone ? t : void 0;
|
|
3130
|
-
r.textmodeCanvas = new
|
|
3131
|
-
let s,
|
|
3132
|
-
r._standalone ? (s = t.width || 800,
|
|
3249
|
+
r.textmodeCanvas = new be(r.captureSource, r._standalone, i), r._renderer = new fe(r.textmodeCanvas.getWebGLContext());
|
|
3250
|
+
let s, o;
|
|
3251
|
+
r._standalone ? (s = t.width || 800, o = t.height || 600) : (s = r.textmodeCanvas.width || 800, o = r.textmodeCanvas.height || 600), r._canvasFramebuffer = r._renderer.createFramebuffer(s, o), r._font = new xe(r._renderer, t.fontSize ?? 16), await r._font.initialize(t.fontSource);
|
|
3133
3252
|
const n = r._font.maxGlyphDimensions;
|
|
3134
3253
|
return r._grid = new ve(r.textmodeCanvas.canvas, n.width, n.height), r._pipeline = new Ue(r._renderer, r._font, r._grid), r.setupEventListeners(), r.startAutoRendering(), r;
|
|
3135
3254
|
}
|
|
3136
3255
|
setupEventListeners() {
|
|
3137
|
-
|
|
3256
|
+
this._windowResizeListener = () => {
|
|
3138
3257
|
this._standalone ? this._resizedCallback() : this.resize();
|
|
3139
|
-
}), window.ResizeObserver && this.captureSource && !this._standalone && (this.resizeObserver = new ResizeObserver(() => {
|
|
3258
|
+
}, window.addEventListener("resize", this._windowResizeListener), window.ResizeObserver && this.captureSource && !this._standalone && (this.resizeObserver = new ResizeObserver(() => {
|
|
3140
3259
|
this.resize();
|
|
3141
3260
|
}), this.resizeObserver.observe(this.captureSource));
|
|
3142
3261
|
}
|
|
@@ -3288,7 +3407,7 @@ class I {
|
|
|
3288
3407
|
* ```
|
|
3289
3408
|
*/
|
|
3290
3409
|
async saveCanvas(e, t = "png", r = {}) {
|
|
3291
|
-
await new
|
|
3410
|
+
await new $e().saveImage(this.textmodeCanvas, {
|
|
3292
3411
|
...r,
|
|
3293
3412
|
filename: e,
|
|
3294
3413
|
format: t
|
|
@@ -3358,7 +3477,19 @@ class I {
|
|
|
3358
3477
|
* ```
|
|
3359
3478
|
*/
|
|
3360
3479
|
render() {
|
|
3361
|
-
|
|
3480
|
+
if (this._isDestroyed) {
|
|
3481
|
+
console.warn("Cannot render: Textmodifier instance has been destroyed");
|
|
3482
|
+
return;
|
|
3483
|
+
}
|
|
3484
|
+
if (this.measureFrameRate(), this._frameCount++, !this._canvasFramebuffer || !this._renderer || !this._pipeline) {
|
|
3485
|
+
console.warn("Cannot render: Required resources have been disposed");
|
|
3486
|
+
return;
|
|
3487
|
+
}
|
|
3488
|
+
if (this._standalone ? this._canvasFramebuffer && (this._canvasFramebuffer.begin(), this._drawCallback(), this._renderer && this._renderer.reset(), this._canvasFramebuffer && this._canvasFramebuffer.end()) : this.captureSource && this._canvasFramebuffer && this._canvasFramebuffer.update(this.captureSource), !this._pipeline || !this._renderer) {
|
|
3489
|
+
console.warn("Cannot complete render: Pipeline or renderer has been disposed");
|
|
3490
|
+
return;
|
|
3491
|
+
}
|
|
3492
|
+
this._pipeline.render(this._canvasFramebuffer), this._pipeline.hasEnabledConverters() ? this._renderer && this._pipeline.texture && this._grid && (this._renderer.background(0), this._renderer.image(this._pipeline.texture, this._grid.offsetX, this._grid.offsetY, this._pipeline.texture.width, this._pipeline.texture.height)) : this._renderer && this._canvasFramebuffer && this._grid && (this._renderer.clear(), this._renderer.image(this._canvasFramebuffer, this._grid.offsetX, this._grid.offsetY, this._canvasFramebuffer.width, this._canvasFramebuffer.height));
|
|
3362
3493
|
}
|
|
3363
3494
|
resize() {
|
|
3364
3495
|
this.textmodeCanvas.resize(), this._canvasFramebuffer.resize(this.textmodeCanvas.width, this.textmodeCanvas.height), this._grid.resize(), this._pipeline.resize(), this._renderer.resetViewport(), this._mode !== "manual" && this.render();
|
|
@@ -3367,11 +3498,17 @@ class I {
|
|
|
3367
3498
|
* Start automatic rendering
|
|
3368
3499
|
*/
|
|
3369
3500
|
startAutoRendering() {
|
|
3370
|
-
if (this._mode !== "auto") return;
|
|
3501
|
+
if (this._mode !== "auto" || this._isDestroyed || !this._isLooping) return;
|
|
3371
3502
|
this.lastFrameTime = performance.now();
|
|
3372
3503
|
const e = (t) => {
|
|
3504
|
+
if (this._isDestroyed)
|
|
3505
|
+
return;
|
|
3506
|
+
if (!this._isLooping) {
|
|
3507
|
+
this.animationFrameId = null;
|
|
3508
|
+
return;
|
|
3509
|
+
}
|
|
3373
3510
|
const r = t - this.lastFrameTime;
|
|
3374
|
-
r >= this.frameInterval && (this.render(), this.lastFrameTime = t - r % this.frameInterval), this.animationFrameId = requestAnimationFrame(e);
|
|
3511
|
+
r >= this.frameInterval && (this.render(), this.lastFrameTime = t - r % this.frameInterval), !this._isDestroyed && this._isLooping && (this.animationFrameId = requestAnimationFrame(e));
|
|
3375
3512
|
};
|
|
3376
3513
|
this.animationFrameId = requestAnimationFrame(e);
|
|
3377
3514
|
}
|
|
@@ -3380,6 +3517,7 @@ class I {
|
|
|
3380
3517
|
* Uses a rolling average for smoother frame rate reporting
|
|
3381
3518
|
*/
|
|
3382
3519
|
measureFrameRate() {
|
|
3520
|
+
if (this._isDestroyed) return;
|
|
3383
3521
|
const e = performance.now();
|
|
3384
3522
|
if (this.lastRenderTime > 0) {
|
|
3385
3523
|
const t = e - this.lastRenderTime;
|
|
@@ -3420,7 +3558,11 @@ class I {
|
|
|
3420
3558
|
* ```
|
|
3421
3559
|
*/
|
|
3422
3560
|
renderMode(e) {
|
|
3423
|
-
|
|
3561
|
+
if (this._isDestroyed) {
|
|
3562
|
+
console.warn("Cannot change render mode: Textmodifier instance has been destroyed");
|
|
3563
|
+
return;
|
|
3564
|
+
}
|
|
3565
|
+
this._mode !== e && (this.stopAutoRendering(), this._mode = e, e === "auto" && this._isLooping && this.startAutoRendering());
|
|
3424
3566
|
}
|
|
3425
3567
|
/**
|
|
3426
3568
|
* Set the maximum frame rate for auto rendering. If called without arguments, returns the current measured frame rate.
|
|
@@ -3441,7 +3583,105 @@ class I {
|
|
|
3441
3583
|
frameRate(e) {
|
|
3442
3584
|
if (e === void 0)
|
|
3443
3585
|
return this._frameRate;
|
|
3444
|
-
this._frameRateLimit = e, this.frameInterval = 1e3 / e, this._mode === "auto" && (this.stopAutoRendering(), this.startAutoRendering());
|
|
3586
|
+
this._frameRateLimit = e, this.frameInterval = 1e3 / e, this._mode === "auto" && this._isLooping && (this.stopAutoRendering(), this.startAutoRendering());
|
|
3587
|
+
}
|
|
3588
|
+
/**
|
|
3589
|
+
* Stop the automatic rendering loop while keeping the render mode as 'auto'.
|
|
3590
|
+
*
|
|
3591
|
+
* This method pauses the render loop without changing the render mode, allowing
|
|
3592
|
+
* it to be resumed later with {@link loop}. This is useful for temporarily pausing
|
|
3593
|
+
* animation while maintaining the ability to restart it.
|
|
3594
|
+
*
|
|
3595
|
+
* **Note:** This only affects rendering when in `'auto'` mode. In `'manual'` mode,
|
|
3596
|
+
* this method has no effect since rendering is already controlled manually.
|
|
3597
|
+
*
|
|
3598
|
+
* @example
|
|
3599
|
+
* ```javascript
|
|
3600
|
+
* // Create a textmodifier instance in auto mode
|
|
3601
|
+
* const textmodifier = await textmode.create(canvas);
|
|
3602
|
+
*
|
|
3603
|
+
* // The render loop is running automatically
|
|
3604
|
+
* console.log(textmodifier.isLooping()); // true
|
|
3605
|
+
*
|
|
3606
|
+
* // Stop the automatic rendering loop
|
|
3607
|
+
* textmodifier.noLoop();
|
|
3608
|
+
* console.log(textmodifier.isLooping()); // false
|
|
3609
|
+
*
|
|
3610
|
+
* // Resume the automatic rendering loop
|
|
3611
|
+
* textmodifier.loop();
|
|
3612
|
+
* console.log(textmodifier.isLooping()); // true
|
|
3613
|
+
* ```
|
|
3614
|
+
*/
|
|
3615
|
+
noLoop() {
|
|
3616
|
+
if (this._isDestroyed) {
|
|
3617
|
+
console.warn("Cannot stop loop: Textmodifier instance has been destroyed");
|
|
3618
|
+
return;
|
|
3619
|
+
}
|
|
3620
|
+
this._isLooping && (this._isLooping = !1, this.animationFrameId && (cancelAnimationFrame(this.animationFrameId), this.animationFrameId = null));
|
|
3621
|
+
}
|
|
3622
|
+
/**
|
|
3623
|
+
* Resume the automatic rendering loop if it was stopped by {@link noLoop}.
|
|
3624
|
+
*
|
|
3625
|
+
* This method restarts the render loop when in `'auto'` mode. If the render mode
|
|
3626
|
+
* is `'manual'`, the loop state will be set but automatic rendering will not start
|
|
3627
|
+
* until the mode is changed back to `'auto'`.
|
|
3628
|
+
*
|
|
3629
|
+
* @example
|
|
3630
|
+
* ```javascript
|
|
3631
|
+
* // Create a textmodifier instance
|
|
3632
|
+
* const textmodifier = await textmode.create(canvas);
|
|
3633
|
+
*
|
|
3634
|
+
* // Stop the loop
|
|
3635
|
+
* textmodifier.noLoop();
|
|
3636
|
+
*
|
|
3637
|
+
* // Resume the loop
|
|
3638
|
+
* textmodifier.loop();
|
|
3639
|
+
*
|
|
3640
|
+
* // You can also use this pattern for conditional animation
|
|
3641
|
+
* if (someCondition) {
|
|
3642
|
+
* textmodifier.loop();
|
|
3643
|
+
* } else {
|
|
3644
|
+
* textmodifier.noLoop();
|
|
3645
|
+
* }
|
|
3646
|
+
* ```
|
|
3647
|
+
*/
|
|
3648
|
+
loop() {
|
|
3649
|
+
if (this._isDestroyed) {
|
|
3650
|
+
console.warn("Cannot start loop: Textmodifier instance has been destroyed");
|
|
3651
|
+
return;
|
|
3652
|
+
}
|
|
3653
|
+
this._isLooping || (this._isLooping = !0, this._mode === "auto" && this.startAutoRendering());
|
|
3654
|
+
}
|
|
3655
|
+
/**
|
|
3656
|
+
* Check whether the textmodifier is currently running the automatic render loop.
|
|
3657
|
+
*
|
|
3658
|
+
* Returns `true` when both the render mode is `'auto'` AND the loop is active.
|
|
3659
|
+
* Returns `false` when in `'manual'` mode or when {@link noLoop} has been called.
|
|
3660
|
+
*
|
|
3661
|
+
* @returns True if the automatic render loop is currently active, false otherwise.
|
|
3662
|
+
*
|
|
3663
|
+
* @example
|
|
3664
|
+
* ```javascript
|
|
3665
|
+
* const textmodifier = await textmode.create(canvas);
|
|
3666
|
+
*
|
|
3667
|
+
* // Check loop status in different states
|
|
3668
|
+
* console.log(textmodifier.isLooping()); // true (auto mode, looping)
|
|
3669
|
+
*
|
|
3670
|
+
* textmodifier.noLoop();
|
|
3671
|
+
* console.log(textmodifier.isLooping()); // false (auto mode, not looping)
|
|
3672
|
+
*
|
|
3673
|
+
* textmodifier.renderMode('manual');
|
|
3674
|
+
* console.log(textmodifier.isLooping()); // false (manual mode)
|
|
3675
|
+
*
|
|
3676
|
+
* textmodifier.renderMode('auto');
|
|
3677
|
+
* console.log(textmodifier.isLooping()); // false (auto mode, but loop was stopped)
|
|
3678
|
+
*
|
|
3679
|
+
* textmodifier.loop();
|
|
3680
|
+
* console.log(textmodifier.isLooping()); // true (auto mode, looping)
|
|
3681
|
+
* ```
|
|
3682
|
+
*/
|
|
3683
|
+
isLooping() {
|
|
3684
|
+
return this._isDestroyed ? !1 : this._mode === "auto" && this._isLooping;
|
|
3445
3685
|
}
|
|
3446
3686
|
/**
|
|
3447
3687
|
* Set the font size used for rendering.
|
|
@@ -3973,33 +4213,77 @@ class I {
|
|
|
3973
4213
|
setUniform(e, t) {
|
|
3974
4214
|
this._renderer.setUniform(e, t);
|
|
3975
4215
|
}
|
|
4216
|
+
/**
|
|
4217
|
+
* Completely destroy this Textmodifier instance and free all associated resources.
|
|
4218
|
+
*
|
|
4219
|
+
* This method performs comprehensive cleanup of:
|
|
4220
|
+
* - WebGL resources (framebuffers, textures, shaders)
|
|
4221
|
+
* - Animation frames and timers
|
|
4222
|
+
* - Event listeners
|
|
4223
|
+
* - DOM elements
|
|
4224
|
+
* - Font resources
|
|
4225
|
+
*
|
|
4226
|
+
* After calling this method, the instance should not be used and will be eligible for garbage collection.
|
|
4227
|
+
* This method is idempotent and safe to call multiple times.
|
|
4228
|
+
*
|
|
4229
|
+
* @example
|
|
4230
|
+
* ```javascript
|
|
4231
|
+
* // Create a textmodifier instance
|
|
4232
|
+
* const textmodifier = await textmode.create(canvas);
|
|
4233
|
+
*
|
|
4234
|
+
* // Use it for rendering
|
|
4235
|
+
* textmodifier.render();
|
|
4236
|
+
*
|
|
4237
|
+
* // When done, completely clean up
|
|
4238
|
+
* textmodifier.destroy();
|
|
4239
|
+
*
|
|
4240
|
+
* // Instance is now safely disposed and ready for garbage collection
|
|
4241
|
+
* ```
|
|
4242
|
+
*/
|
|
4243
|
+
destroy() {
|
|
4244
|
+
this._isDestroyed || (this._isDestroyed = !0, this.stopAutoRendering(), this._windowResizeListener && (window.removeEventListener("resize", this._windowResizeListener), this._windowResizeListener = null), this.resizeObserver && (this.resizeObserver.disconnect(), this.resizeObserver = null), this._pipeline && !this._pipeline.isDisposed && this._pipeline.dispose(), this._font && !this._font.isDisposed && this._font.dispose(), this._grid && !this._grid.isDisposed && this._grid.dispose(), this._canvasFramebuffer && !this._canvasFramebuffer.isDisposed && this._canvasFramebuffer.dispose(), this._renderer && !this._renderer.isDisposed && this._renderer.dispose(), this.textmodeCanvas && !this.textmodeCanvas.isDisposed && this.textmodeCanvas.dispose(), this.captureSource = null, this.textmodeCanvas = null, this._renderer = null, this._canvasFramebuffer = null, this._font = null, this._grid = null, this._pipeline = null, this.resizeObserver = null, this._drawCallback = () => {
|
|
4245
|
+
}, this._resizedCallback = () => {
|
|
4246
|
+
}, this.animationFrameId = null, this.lastFrameTime = 0, this.lastRenderTime = 0, this._frameCount = 0, this._frameRate = 0, this.frameTimeHistory = [], this._isLooping = !1);
|
|
4247
|
+
}
|
|
3976
4248
|
/** Get the current grid object used for rendering. */
|
|
3977
4249
|
get grid() {
|
|
4250
|
+
if (this._isDestroyed)
|
|
4251
|
+
throw new Error("Cannot access grid: Textmodifier instance has been destroyed");
|
|
3978
4252
|
return this._grid;
|
|
3979
4253
|
}
|
|
3980
4254
|
/** Get the current font object used for rendering. */
|
|
3981
4255
|
get font() {
|
|
4256
|
+
if (this._isDestroyed)
|
|
4257
|
+
throw new Error("Cannot access font: Textmodifier instance has been destroyed");
|
|
3982
4258
|
return this._font;
|
|
3983
4259
|
}
|
|
3984
4260
|
/** Get the current rendering mode.*/
|
|
3985
4261
|
get mode() {
|
|
4262
|
+
if (this._isDestroyed)
|
|
4263
|
+
throw new Error("Cannot access mode: Textmodifier instance has been destroyed");
|
|
3986
4264
|
return this._mode;
|
|
3987
4265
|
}
|
|
3988
4266
|
/** Get the current textmode conversion pipeline. */
|
|
3989
4267
|
get pipeline() {
|
|
4268
|
+
if (this._isDestroyed)
|
|
4269
|
+
throw new Error("Cannot access pipeline: Textmodifier instance has been destroyed");
|
|
3990
4270
|
return this._pipeline;
|
|
3991
4271
|
}
|
|
3992
4272
|
/** Get the current frame count. */
|
|
3993
4273
|
get frameCount() {
|
|
3994
|
-
return this._frameCount;
|
|
4274
|
+
return this._isDestroyed ? 0 : this._frameCount;
|
|
3995
4275
|
}
|
|
3996
4276
|
/** Get the width of the canvas. */
|
|
3997
4277
|
get width() {
|
|
3998
|
-
return this.textmodeCanvas.width;
|
|
4278
|
+
return this._isDestroyed ? 0 : this.textmodeCanvas.width;
|
|
3999
4279
|
}
|
|
4000
4280
|
/** Get the height of the canvas. */
|
|
4001
4281
|
get height() {
|
|
4002
|
-
return this.textmodeCanvas.height;
|
|
4282
|
+
return this._isDestroyed ? 0 : this.textmodeCanvas.height;
|
|
4283
|
+
}
|
|
4284
|
+
/** Check if this Textmodifier instance has been destroyed. */
|
|
4285
|
+
get isDestroyed() {
|
|
4286
|
+
return this._isDestroyed;
|
|
4003
4287
|
}
|
|
4004
4288
|
}
|
|
4005
4289
|
class O {
|
|
@@ -4046,6 +4330,20 @@ class O {
|
|
|
4046
4330
|
* // Draw a rectangle with the fill color
|
|
4047
4331
|
* t.rect(x, y, 200, 150);
|
|
4048
4332
|
* });
|
|
4333
|
+
*
|
|
4334
|
+
* ////////
|
|
4335
|
+
*
|
|
4336
|
+
* // Resource management example
|
|
4337
|
+
* const textmodifier = await textmode.create(canvas);
|
|
4338
|
+
*
|
|
4339
|
+
* // Use the textmodifier...
|
|
4340
|
+
* textmodifier.render();
|
|
4341
|
+
*
|
|
4342
|
+
* // When done, completely clean up all resources
|
|
4343
|
+
* textmodifier.destroy();
|
|
4344
|
+
*
|
|
4345
|
+
* // The instance is now safely disposed and ready for garbage collection
|
|
4346
|
+
* console.log(textmodifier.isDestroyed); // true
|
|
4049
4347
|
* ```
|
|
4050
4348
|
*/
|
|
4051
4349
|
static async create(e, t = {}) {
|
|
@@ -4078,7 +4376,7 @@ class O {
|
|
|
4078
4376
|
* ```
|
|
4079
4377
|
*/
|
|
4080
4378
|
static get version() {
|
|
4081
|
-
return "0.1.4-beta.
|
|
4379
|
+
return "0.1.4-beta.2";
|
|
4082
4380
|
}
|
|
4083
4381
|
constructor() {
|
|
4084
4382
|
throw new Error("Textmode is a static class and cannot be instantiated.");
|
|
@@ -4088,7 +4386,7 @@ const He = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
|
4088
4386
|
__proto__: null
|
|
4089
4387
|
}, Symbol.toStringTag, { value: "Module" })), Ne = O.create, Oe = O.setErrorLevel, We = O.version;
|
|
4090
4388
|
export {
|
|
4091
|
-
|
|
4389
|
+
be as TextmodeCanvas,
|
|
4092
4390
|
Ue as TextmodeConversionPipeline,
|
|
4093
4391
|
ne as TextmodeErrorLevel,
|
|
4094
4392
|
xe as TextmodeFont,
|