@vectojs/core 1.38.1 → 1.39.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -135
- package/dist/{chunk-QVTCKWDO.mjs → chunk-7PYD5UDX.mjs} +93 -43
- package/dist/{chunk-LWEMD34D.mjs → chunk-AISSDI6U.mjs} +132 -33
- package/dist/{chunk-ZYYP2M5D.js → chunk-BKXERWAD.js} +181 -82
- package/dist/{chunk-SRXU3ZXK.js → chunk-POPXUPKR.js} +141 -91
- package/dist/index.js +772 -401
- package/dist/index.mjs +459 -88
- package/dist/renderer/CanvasRenderer.d.ts +6 -0
- package/dist/renderer/SVGRenderer.d.ts +17 -2
- package/dist/renderer/WebGPUParticleSystemManager.d.ts +2 -0
- package/dist/renderer.js +2 -2
- package/dist/renderer.mjs +1 -1
- package/dist/text/MSDFTextEntity.d.ts +0 -1
- package/dist/text.js +2 -2
- package/dist/text.mjs +1 -1
- package/dist/tree/Entity.d.ts +8 -2
- package/dist/tree/Scene.d.ts +123 -0
- package/dist/tree/scene/A11yProjectionManager.d.ts +12 -0
- package/dist/tree/scene/HitTester.d.ts +14 -2
- package/dist/tree/scene/WasmBackendFacade.d.ts +17 -0
- package/dist/tree/scene/keyboard.d.ts +56 -0
- package/dist/wasm/backend.d.ts +7 -7
- package/dist/wasm/vectojs_core.wasm +0 -0
- package/package.json +8 -8
|
@@ -65,7 +65,8 @@ function emptyDrawCounters() {
|
|
|
65
65
|
}
|
|
66
66
|
var TWO_PI = Math.PI * 2;
|
|
67
67
|
function getDevicePixelRatio() {
|
|
68
|
-
|
|
68
|
+
const raw = typeof window !== "undefined" ? window.devicePixelRatio : 1;
|
|
69
|
+
return Number.isFinite(raw) && raw > 0 ? raw : 1;
|
|
69
70
|
}
|
|
70
71
|
var CanvasRenderer = (_class = class _CanvasRenderer {
|
|
71
72
|
|
|
@@ -109,17 +110,28 @@ var CanvasRenderer = (_class = class _CanvasRenderer {
|
|
|
109
110
|
__init7() {this.batchCount = 0}
|
|
110
111
|
__init8() {this._cachedFont = ""}
|
|
111
112
|
__init9() {this._cachedFill = ""}
|
|
113
|
+
// Stroke-side counterparts of the fill/font caches, read by stroke()'s
|
|
114
|
+
// style-elision branch. Reset wherever the context state can change behind
|
|
115
|
+
// our back: restore(), resize(), contextrestored, dispose().
|
|
116
|
+
__init10() {this._cachedStroke = ""}
|
|
117
|
+
__init11() {this._cachedLineWidth = -1}
|
|
118
|
+
__init12() {this._cachedLineCap = ""}
|
|
119
|
+
__init13() {this._cachedLineJoin = ""}
|
|
120
|
+
// Context-loss listeners, held for removal in dispose() so a canvas that
|
|
121
|
+
// outlives the renderer cannot retain it through these closures.
|
|
122
|
+
|
|
123
|
+
|
|
112
124
|
/** Backend discriminator; see {@link IRenderer.kind}. */
|
|
113
|
-
|
|
125
|
+
__init14() {this.kind = "canvas2d"}
|
|
114
126
|
/**
|
|
115
127
|
* Draw counters, allocated only once counting is enabled.
|
|
116
128
|
*
|
|
117
129
|
* Null when off, so the guard on every op is a single null test and an inactive
|
|
118
130
|
* renderer carries no counter object at all.
|
|
119
131
|
*/
|
|
120
|
-
|
|
132
|
+
__init15() {this.counters = null}
|
|
121
133
|
/** Accumulated primitive area, kept separately so the ratio is derived on read. */
|
|
122
|
-
|
|
134
|
+
__init16() {this.drawnArea = 0}
|
|
123
135
|
/**
|
|
124
136
|
* @param canvas - The target canvas. Its backing store is resized to the
|
|
125
137
|
* logical size × devicePixelRatio.
|
|
@@ -129,7 +141,7 @@ var CanvasRenderer = (_class = class _CanvasRenderer {
|
|
|
129
141
|
* set) so the canvas's own dimensions aren't clobbered by the window's.
|
|
130
142
|
* @param maxDPR - See {@link maxDPR}.
|
|
131
143
|
*/
|
|
132
|
-
constructor(canvas, size, maxDPR) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);_class.prototype.__init5.call(this);_class.prototype.__init6.call(this);_class.prototype.__init7.call(this);_class.prototype.__init8.call(this);_class.prototype.__init9.call(this);_class.prototype.__init10.call(this);_class.prototype.__init11.call(this);_class.prototype.__init12.call(this);
|
|
144
|
+
constructor(canvas, size, maxDPR) {;_class.prototype.__init.call(this);_class.prototype.__init2.call(this);_class.prototype.__init3.call(this);_class.prototype.__init4.call(this);_class.prototype.__init5.call(this);_class.prototype.__init6.call(this);_class.prototype.__init7.call(this);_class.prototype.__init8.call(this);_class.prototype.__init9.call(this);_class.prototype.__init10.call(this);_class.prototype.__init11.call(this);_class.prototype.__init12.call(this);_class.prototype.__init13.call(this);_class.prototype.__init14.call(this);_class.prototype.__init15.call(this);_class.prototype.__init16.call(this);
|
|
133
145
|
this.maxDPR = maxDPR;
|
|
134
146
|
const dpr = this.effectiveDPR();
|
|
135
147
|
this.appliedDPR = dpr;
|
|
@@ -162,11 +174,11 @@ var CanvasRenderer = (_class = class _CanvasRenderer {
|
|
|
162
174
|
*/
|
|
163
175
|
setupContextLossRecovery() {
|
|
164
176
|
if (typeof this.canvas.addEventListener !== "function") return;
|
|
165
|
-
this.
|
|
177
|
+
this._onContextLost = (e) => {
|
|
166
178
|
e.preventDefault();
|
|
167
179
|
this.contextLost = true;
|
|
168
|
-
}
|
|
169
|
-
this.
|
|
180
|
+
};
|
|
181
|
+
this._onContextRestored = () => {
|
|
170
182
|
const ctx = this.canvas.getContext("2d");
|
|
171
183
|
if (!ctx) return;
|
|
172
184
|
this.ctx = ctx;
|
|
@@ -176,11 +188,17 @@ var CanvasRenderer = (_class = class _CanvasRenderer {
|
|
|
176
188
|
ctx.scale(restoredDPR, restoredDPR);
|
|
177
189
|
this._cachedFont = "";
|
|
178
190
|
this._cachedFill = "";
|
|
191
|
+
this._cachedStroke = "";
|
|
192
|
+
this._cachedLineWidth = -1;
|
|
193
|
+
this._cachedLineCap = "";
|
|
194
|
+
this._cachedLineJoin = "";
|
|
179
195
|
this.batchActive = false;
|
|
180
196
|
this.batchCount = 0;
|
|
181
197
|
this.contextLost = false;
|
|
182
198
|
_optionalChain([this, 'access', _8 => _8.contextRestoredCb, 'optionalCall', _9 => _9()]);
|
|
183
|
-
}
|
|
199
|
+
};
|
|
200
|
+
this.canvas.addEventListener("contextlost", this._onContextLost);
|
|
201
|
+
this.canvas.addEventListener("contextrestored", this._onContextRestored);
|
|
184
202
|
}
|
|
185
203
|
/**
|
|
186
204
|
* Expose the underlying `CanvasRenderingContext2D` for operations not
|
|
@@ -194,7 +212,9 @@ var CanvasRenderer = (_class = class _CanvasRenderer {
|
|
|
194
212
|
/** Real `devicePixelRatio`, clamped to {@link maxDPR} when set. */
|
|
195
213
|
effectiveDPR() {
|
|
196
214
|
const real = getDevicePixelRatio();
|
|
197
|
-
|
|
215
|
+
if (this.maxDPR === void 0) return real;
|
|
216
|
+
if (!Number.isFinite(this.maxDPR) || this.maxDPR <= 0) return real;
|
|
217
|
+
return Math.min(real, this.maxDPR);
|
|
198
218
|
}
|
|
199
219
|
/**
|
|
200
220
|
* @inheritdoc
|
|
@@ -225,16 +245,26 @@ var CanvasRenderer = (_class = class _CanvasRenderer {
|
|
|
225
245
|
*/
|
|
226
246
|
resize(width, height) {
|
|
227
247
|
const dpr = this.effectiveDPR();
|
|
248
|
+
const safeWidth = Number.isFinite(width) && width >= 0 ? width : this.width;
|
|
249
|
+
const safeHeight = Number.isFinite(height) && height >= 0 ? height : this.height;
|
|
250
|
+
const backingW = Number.isFinite(safeWidth * dpr) ? Math.max(1, Math.round(safeWidth * dpr)) : 1;
|
|
251
|
+
const backingH = Number.isFinite(safeHeight * dpr) ? Math.max(1, Math.round(safeHeight * dpr)) : 1;
|
|
228
252
|
this.appliedDPR = dpr;
|
|
229
|
-
this.width =
|
|
230
|
-
this.height =
|
|
231
|
-
this.ctx.canvas.width =
|
|
232
|
-
this.ctx.canvas.height =
|
|
233
|
-
this.ctx.canvas.style
|
|
234
|
-
|
|
253
|
+
this.width = safeWidth;
|
|
254
|
+
this.height = safeHeight;
|
|
255
|
+
this.ctx.canvas.width = backingW;
|
|
256
|
+
this.ctx.canvas.height = backingH;
|
|
257
|
+
if (this.ctx.canvas.style) {
|
|
258
|
+
this.ctx.canvas.style.width = `${safeWidth}px`;
|
|
259
|
+
this.ctx.canvas.style.height = `${safeHeight}px`;
|
|
260
|
+
}
|
|
235
261
|
this.ctx.scale(dpr, dpr);
|
|
236
262
|
this._cachedFont = "";
|
|
237
263
|
this._cachedFill = "";
|
|
264
|
+
this._cachedStroke = "";
|
|
265
|
+
this._cachedLineWidth = -1;
|
|
266
|
+
this._cachedLineCap = "";
|
|
267
|
+
this._cachedLineJoin = "";
|
|
238
268
|
this.batchActive = false;
|
|
239
269
|
this.batchCount = 0;
|
|
240
270
|
}
|
|
@@ -288,6 +318,10 @@ var CanvasRenderer = (_class = class _CanvasRenderer {
|
|
|
288
318
|
this.ctx.restore();
|
|
289
319
|
this._cachedFont = "";
|
|
290
320
|
this._cachedFill = "";
|
|
321
|
+
this._cachedStroke = "";
|
|
322
|
+
this._cachedLineWidth = -1;
|
|
323
|
+
this._cachedLineCap = "";
|
|
324
|
+
this._cachedLineJoin = "";
|
|
291
325
|
}
|
|
292
326
|
/** @inheritdoc */
|
|
293
327
|
translate(x, y) {
|
|
@@ -412,10 +446,17 @@ var CanvasRenderer = (_class = class _CanvasRenderer {
|
|
|
412
446
|
stroke(color, lineWidth = 1) {
|
|
413
447
|
this.flush();
|
|
414
448
|
if (this.counters) this.counters.strokes++;
|
|
415
|
-
this.
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
449
|
+
if (this._cachedStroke !== color || this._cachedLineWidth !== lineWidth || this._cachedLineCap !== "round" || this._cachedLineJoin !== "round") {
|
|
450
|
+
if (this.counters) this.counters.stateSwitches++;
|
|
451
|
+
this.ctx.strokeStyle = color;
|
|
452
|
+
this.ctx.lineWidth = lineWidth;
|
|
453
|
+
this.ctx.lineCap = "round";
|
|
454
|
+
this.ctx.lineJoin = "round";
|
|
455
|
+
this._cachedStroke = color;
|
|
456
|
+
this._cachedLineWidth = lineWidth;
|
|
457
|
+
this._cachedLineCap = "round";
|
|
458
|
+
this._cachedLineJoin = "round";
|
|
459
|
+
}
|
|
419
460
|
this.ctx.stroke();
|
|
420
461
|
}
|
|
421
462
|
/** @inheritdoc */
|
|
@@ -454,6 +495,17 @@ var CanvasRenderer = (_class = class _CanvasRenderer {
|
|
|
454
495
|
this.batchActive = false;
|
|
455
496
|
this._cachedFont = "";
|
|
456
497
|
this._cachedFill = "";
|
|
498
|
+
this._cachedStroke = "";
|
|
499
|
+
this._cachedLineWidth = -1;
|
|
500
|
+
this._cachedLineCap = "";
|
|
501
|
+
this._cachedLineJoin = "";
|
|
502
|
+
if (typeof this.canvas.removeEventListener === "function") {
|
|
503
|
+
if (this._onContextLost) this.canvas.removeEventListener("contextlost", this._onContextLost);
|
|
504
|
+
if (this._onContextRestored)
|
|
505
|
+
this.canvas.removeEventListener("contextrestored", this._onContextRestored);
|
|
506
|
+
}
|
|
507
|
+
this._onContextLost = void 0;
|
|
508
|
+
this._onContextRestored = void 0;
|
|
457
509
|
}
|
|
458
510
|
}, _class.__initStatic(), _class);
|
|
459
511
|
|
|
@@ -476,9 +528,13 @@ function hasSafeSchemeOrIsRelative(url) {
|
|
|
476
528
|
return SAFE_SCHEMES.has(`${candidate.toLowerCase()}:`);
|
|
477
529
|
}
|
|
478
530
|
var CHAR_REF = /&(?:#\d+|#x[\da-f]+|colon|tab|newline);/i;
|
|
531
|
+
var MAX_CODE_POINT = 1114111;
|
|
532
|
+
function decodeCodePoint(value) {
|
|
533
|
+
return value <= MAX_CODE_POINT ? String.fromCodePoint(value) : "\uFFFD";
|
|
534
|
+
}
|
|
479
535
|
function decodeCharacterReferences(value) {
|
|
480
536
|
if (value.indexOf("&") < 0 || !CHAR_REF.test(value)) return value;
|
|
481
|
-
return value.replace(/&#x([\da-f]+);/gi, (_, hex) =>
|
|
537
|
+
return value.replace(/&#x([\da-f]+);/gi, (_, hex) => decodeCodePoint(parseInt(hex, 16))).replace(/&#(\d+);/g, (_, dec) => decodeCodePoint(parseInt(dec, 10))).replace(/:/gi, ":").replace(/&tab;/gi, " ").replace(/&newline;/gi, "\n");
|
|
482
538
|
}
|
|
483
539
|
function sanitizeUrl(href) {
|
|
484
540
|
if (typeof href !== "string") return "";
|
|
@@ -545,44 +601,47 @@ function fontFamilyFromShorthand(font, sizeToken) {
|
|
|
545
601
|
}
|
|
546
602
|
var SVGRenderer = (_class2 = class {
|
|
547
603
|
/** Backend discriminator; see {@link IRenderer.kind}. */
|
|
548
|
-
|
|
604
|
+
__init17() {this.kind = "svg"}
|
|
549
605
|
|
|
550
606
|
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
607
|
+
__init18() {this.buffer = []}
|
|
608
|
+
__init19() {this.defsBuffer = []}
|
|
609
|
+
__init20() {this.currentPath = []}
|
|
554
610
|
// Inline matrix states (3x3 representation)
|
|
555
611
|
// [a, b, c, d, e, f] corresponding to:
|
|
556
612
|
// | a c e |
|
|
557
613
|
// | b d f |
|
|
558
614
|
// | 0 0 1 |
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
615
|
+
__init21() {this.mStack = []}
|
|
616
|
+
__init22() {this.ma = 1}
|
|
617
|
+
__init23() {this.mb = 0}
|
|
618
|
+
__init24() {this.mc = 0}
|
|
619
|
+
__init25() {this.md = 1}
|
|
620
|
+
__init26() {this.me = 0}
|
|
621
|
+
__init27() {this.mf = 0}
|
|
566
622
|
// Alpha stack
|
|
567
|
-
|
|
568
|
-
|
|
623
|
+
__init28() {this.alphaStack = []}
|
|
624
|
+
__init29() {this.globalAlpha = 1}
|
|
569
625
|
// Clipping stack
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
626
|
+
__init30() {this.clipDepthStack = []}
|
|
627
|
+
__init31() {this.clipDepth = 0}
|
|
628
|
+
__init32() {this.clipCounter = 0}
|
|
573
629
|
// uniquely identifies clipPaths
|
|
574
630
|
// Batch circles states (local coordinates)
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
631
|
+
__init33() {this.batchCircles = []}
|
|
632
|
+
__init34() {this.batchMatrix = [1, 0, 0, 1, 0, 0]}
|
|
633
|
+
__init35() {this.batchColor = ""}
|
|
634
|
+
__init36() {this.batchAlpha = 1}
|
|
635
|
+
__init37() {this.batchActive = false}
|
|
580
636
|
// Cache for generated gradient defs
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
637
|
+
__init38() {this.gradientCounter = 0}
|
|
638
|
+
__init39() {this.gradientCache = /* @__PURE__ */ new Map()}
|
|
639
|
+
/** Root font size used to resolve `em`/`rem` font sizes (default 16px). */
|
|
640
|
+
|
|
641
|
+
constructor(width, height, options) {;_class2.prototype.__init17.call(this);_class2.prototype.__init18.call(this);_class2.prototype.__init19.call(this);_class2.prototype.__init20.call(this);_class2.prototype.__init21.call(this);_class2.prototype.__init22.call(this);_class2.prototype.__init23.call(this);_class2.prototype.__init24.call(this);_class2.prototype.__init25.call(this);_class2.prototype.__init26.call(this);_class2.prototype.__init27.call(this);_class2.prototype.__init28.call(this);_class2.prototype.__init29.call(this);_class2.prototype.__init30.call(this);_class2.prototype.__init31.call(this);_class2.prototype.__init32.call(this);_class2.prototype.__init33.call(this);_class2.prototype.__init34.call(this);_class2.prototype.__init35.call(this);_class2.prototype.__init36.call(this);_class2.prototype.__init37.call(this);_class2.prototype.__init38.call(this);_class2.prototype.__init39.call(this);
|
|
584
642
|
this.width = width;
|
|
585
643
|
this.height = height;
|
|
644
|
+
this.rootFontSize = _nullishCoalesce(_optionalChain([options, 'optionalAccess', _10 => _10.rootFontSize]), () => ( 16));
|
|
586
645
|
installRendererDevTraps(this, "SVGRenderer");
|
|
587
646
|
}
|
|
588
647
|
clear() {
|
|
@@ -770,12 +829,22 @@ var SVGRenderer = (_class2 = class {
|
|
|
770
829
|
`<path d="${dStr}" transform="${transformStr}" fill="none" stroke="${strokeVal}" stroke-width="${lineWidth}" stroke-opacity="${this.globalAlpha}" />`
|
|
771
830
|
);
|
|
772
831
|
}
|
|
832
|
+
/**
|
|
833
|
+
* Emit a `<text>` element for a text run.
|
|
834
|
+
*
|
|
835
|
+
* Font-size unit handling: `px` sizes pass through; `em` and `rem` are both
|
|
836
|
+
* scaled against the renderer's `rootFontSize` (constructor option, default
|
|
837
|
+
* 16 — matching the browser default, not necessarily the host page's root,
|
|
838
|
+
* so pass `{ rootFontSize }` when exporting against a non-default root).
|
|
839
|
+
* A percentage size (`'100% Inter'`) has no absolute meaning in this
|
|
840
|
+
* context and silently falls back to the default 16px font size.
|
|
841
|
+
*/
|
|
773
842
|
fillText(text, x, y, font, color) {
|
|
774
843
|
this.flush();
|
|
775
844
|
const sizeToken = parseFontSizeToken(font);
|
|
776
845
|
let fontSize = sizeToken ? sizeToken.value : 16;
|
|
777
|
-
if (sizeToken && sizeToken.unit
|
|
778
|
-
fontSize = fontSize *
|
|
846
|
+
if (sizeToken && (sizeToken.unit === "em" || sizeToken.unit === "rem")) {
|
|
847
|
+
fontSize = fontSize * this.rootFontSize;
|
|
779
848
|
}
|
|
780
849
|
const lowerFont = font.toLowerCase();
|
|
781
850
|
const fontStyle = lowerFont.includes("italic") ? "italic" : lowerFont.includes("oblique") ? "oblique" : "normal";
|
|
@@ -805,8 +874,8 @@ var SVGRenderer = (_class2 = class {
|
|
|
805
874
|
}
|
|
806
875
|
drawImage(source, dx, dy, dw, dh) {
|
|
807
876
|
this.flush();
|
|
808
|
-
const fromCanvas2 = typeof _optionalChain([source, 'optionalAccess',
|
|
809
|
-
const rawHref = fromCanvas2 ? source.toDataURL() : _optionalChain([source, 'optionalAccess',
|
|
877
|
+
const fromCanvas2 = typeof _optionalChain([source, 'optionalAccess', _11 => _11.toDataURL]) === "function";
|
|
878
|
+
const rawHref = fromCanvas2 ? source.toDataURL() : _optionalChain([source, 'optionalAccess', _12 => _12.src]) || "";
|
|
810
879
|
const href = fromCanvas2 && this.isSafeRasterDataUrl(rawHref) ? rawHref : sanitizeUrl(String(rawHref));
|
|
811
880
|
const transformStr = `matrix(${this.ma},${this.mb},${this.mc},${this.md},${this.me},${this.mf})`;
|
|
812
881
|
if (href) {
|
|
@@ -957,11 +1026,11 @@ var SVGRenderer = (_class2 = class {
|
|
|
957
1026
|
}
|
|
958
1027
|
/**
|
|
959
1028
|
* SVGRenderer accumulates strings in memory; nothing external is allocated.
|
|
960
|
-
* Drop the buffers for GC and become idempotent.
|
|
1029
|
+
* Drop the buffers for GC and become idempotent. `clear()` already empties
|
|
1030
|
+
* the gradient cache, so no second clear is needed here.
|
|
961
1031
|
*/
|
|
962
1032
|
dispose() {
|
|
963
1033
|
this.clear();
|
|
964
|
-
this.gradientCache.clear();
|
|
965
1034
|
}
|
|
966
1035
|
}, _class2);
|
|
967
1036
|
|
|
@@ -1333,13 +1402,22 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1333
1402
|
premultipliedAlpha: false
|
|
1334
1403
|
});
|
|
1335
1404
|
if (!gl) return null;
|
|
1336
|
-
const
|
|
1337
|
-
const
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1405
|
+
const programs = [];
|
|
1406
|
+
const linkTracked = (vsSrc, fsSrc) => {
|
|
1407
|
+
const program = link(gl, vsSrc, fsSrc);
|
|
1408
|
+
if (program) programs.push(program);
|
|
1409
|
+
return program;
|
|
1410
|
+
};
|
|
1411
|
+
const pointProgram = linkTracked(POINT_VERT, POINT_FRAG);
|
|
1412
|
+
const rectProgram = linkTracked(RECT_VERT, RECT_FRAG);
|
|
1413
|
+
const spriteProgram = linkTracked(SPRITE_VERT, SPRITE_FRAG);
|
|
1414
|
+
const msdfProgram = linkTracked(SPRITE_VERT, MSDF_FRAG);
|
|
1415
|
+
const circleQuadProgram = linkTracked(SPRITE_VERT, CIRCLE_QUAD_FRAG);
|
|
1416
|
+
if (!pointProgram || !rectProgram || !spriteProgram || !msdfProgram || !circleQuadProgram) {
|
|
1417
|
+
for (const program of programs) gl.deleteProgram(program);
|
|
1418
|
+
_optionalChain([gl, 'access', _13 => _13.getExtension, 'call', _14 => _14("WEBGL_lose_context"), 'optionalAccess', _15 => _15.loseContext, 'call', _16 => _16()]);
|
|
1342
1419
|
return null;
|
|
1420
|
+
}
|
|
1343
1421
|
gl.enable(gl.BLEND);
|
|
1344
1422
|
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
|
|
1345
1423
|
const pAPos = gl.getAttribLocation(pointProgram, "a_pos");
|
|
@@ -1519,6 +1597,7 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1519
1597
|
ensureQuadIndices(spriteCount);
|
|
1520
1598
|
gl.drawElements(gl.TRIANGLES, spriteCount * INDICES_PER_QUAD, gl.UNSIGNED_INT, 0);
|
|
1521
1599
|
frameDrawCalls++;
|
|
1600
|
+
gl.bindVertexArray(null);
|
|
1522
1601
|
spriteCount = 0;
|
|
1523
1602
|
};
|
|
1524
1603
|
const drawGlyphs = () => {
|
|
@@ -1797,6 +1876,7 @@ function createWebGLPointRenderer(canvas) {
|
|
|
1797
1876
|
}
|
|
1798
1877
|
|
|
1799
1878
|
// src/renderer/WebGPUParticleSystemManager.ts
|
|
1879
|
+
var recordComputePassScratch = new Float32Array(20);
|
|
1800
1880
|
var COMPUTE_SHADER = `
|
|
1801
1881
|
struct Particle {
|
|
1802
1882
|
position: vec2<f32>,
|
|
@@ -1971,16 +2051,22 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
|
|
|
1971
2051
|
`;
|
|
1972
2052
|
var WebGPUParticleSystemManager = (_class3 = class {
|
|
1973
2053
|
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
2054
|
+
__init40() {this.computePipeline = null}
|
|
2055
|
+
__init41() {this.renderPipeline = null}
|
|
2056
|
+
// Held so destroy() can release them — modules were previously unreachable
|
|
2057
|
+
// after initPipelines and lived until context loss (#684).
|
|
2058
|
+
__init42() {this.computeModule = null}
|
|
2059
|
+
__init43() {this.renderModule = null}
|
|
2060
|
+
__init44() {this.computeBindGroupLayout = null}
|
|
2061
|
+
__init45() {this.renderBindGroupLayout = null}
|
|
2062
|
+
constructor(device) {;_class3.prototype.__init40.call(this);_class3.prototype.__init41.call(this);_class3.prototype.__init42.call(this);_class3.prototype.__init43.call(this);_class3.prototype.__init44.call(this);_class3.prototype.__init45.call(this);
|
|
1979
2063
|
this.device = device;
|
|
1980
2064
|
}
|
|
1981
2065
|
initPipelines(format) {
|
|
1982
|
-
|
|
1983
|
-
|
|
2066
|
+
this.computeModule = this.device.createShaderModule({ code: COMPUTE_SHADER });
|
|
2067
|
+
this.renderModule = this.device.createShaderModule({ code: RENDER_SHADER });
|
|
2068
|
+
const computeModule = this.computeModule;
|
|
2069
|
+
const renderModule = this.renderModule;
|
|
1984
2070
|
this.computeBindGroupLayout = this.device.createBindGroupLayout({
|
|
1985
2071
|
entries: [
|
|
1986
2072
|
{
|
|
@@ -2039,6 +2125,8 @@ var WebGPUParticleSystemManager = (_class3 = class {
|
|
|
2039
2125
|
});
|
|
2040
2126
|
}
|
|
2041
2127
|
setupEntityResources(entity) {
|
|
2128
|
+
releaseGpuObject(entity.gpuStorageBuffer);
|
|
2129
|
+
releaseGpuObject(entity.gpuUniformBuffer);
|
|
2042
2130
|
const storageSize = entity.maxParticles * 32;
|
|
2043
2131
|
entity.gpuStorageBuffer = this.device.createBuffer({
|
|
2044
2132
|
size: storageSize,
|
|
@@ -2065,7 +2153,7 @@ var WebGPUParticleSystemManager = (_class3 = class {
|
|
|
2065
2153
|
}
|
|
2066
2154
|
recordComputePass(pass, entity, dt, mouseX, mouseY, width, height) {
|
|
2067
2155
|
if (!this.computePipeline || !entity.computeBindGroup) return;
|
|
2068
|
-
const uniformArray =
|
|
2156
|
+
const uniformArray = recordComputePassScratch;
|
|
2069
2157
|
const color = parseColorToRGBA(entity.baseColor);
|
|
2070
2158
|
let opacity = 1;
|
|
2071
2159
|
for (let current = entity; current; current = current.parent) {
|
|
@@ -2109,34 +2197,45 @@ var WebGPUParticleSystemManager = (_class3 = class {
|
|
|
2109
2197
|
pass.draw(6, entity.maxParticles);
|
|
2110
2198
|
}
|
|
2111
2199
|
destroy() {
|
|
2200
|
+
releaseGpuObject(this.computePipeline);
|
|
2201
|
+
releaseGpuObject(this.renderPipeline);
|
|
2202
|
+
releaseGpuObject(this.computeModule);
|
|
2203
|
+
releaseGpuObject(this.renderModule);
|
|
2112
2204
|
this.computePipeline = null;
|
|
2113
2205
|
this.renderPipeline = null;
|
|
2206
|
+
this.computeModule = null;
|
|
2207
|
+
this.renderModule = null;
|
|
2114
2208
|
this.computeBindGroupLayout = null;
|
|
2115
2209
|
this.renderBindGroupLayout = null;
|
|
2116
2210
|
}
|
|
2117
2211
|
}, _class3);
|
|
2212
|
+
function releaseGpuObject(obj) {
|
|
2213
|
+
if (obj && typeof obj.destroy === "function") {
|
|
2214
|
+
obj.destroy();
|
|
2215
|
+
}
|
|
2216
|
+
}
|
|
2118
2217
|
|
|
2119
2218
|
// src/renderer/GlyphRasterAtlas.ts
|
|
2120
2219
|
var HARD_MAX_SIZE = 8192;
|
|
2121
2220
|
var PAD = 2;
|
|
2122
2221
|
var GlyphRasterAtlas = (_class4 = class {
|
|
2123
|
-
|
|
2222
|
+
__init46() {this.slots = /* @__PURE__ */ new Map()}
|
|
2124
2223
|
|
|
2125
2224
|
|
|
2126
|
-
|
|
2127
|
-
|
|
2225
|
+
__init47() {this.canvas = null}
|
|
2226
|
+
__init48() {this.ctx = null}
|
|
2128
2227
|
/**
|
|
2129
2228
|
* Shelf packing: glyphs land left-to-right on a row, then a new row starts.
|
|
2130
2229
|
* A monospace grid produces near-uniform widths, so shelves waste very little
|
|
2131
2230
|
* and cost one comparison per insert — a real 2D packer would buy nothing here.
|
|
2132
2231
|
*/
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
constructor(options = {}) {;_class4.prototype.
|
|
2232
|
+
__init49() {this.penX = PAD}
|
|
2233
|
+
__init50() {this.penY = PAD}
|
|
2234
|
+
__init51() {this.rowHeight = 0}
|
|
2235
|
+
__init52() {this._hits = 0}
|
|
2236
|
+
__init53() {this._misses = 0}
|
|
2237
|
+
__init54() {this._resets = 0}
|
|
2238
|
+
constructor(options = {}) {;_class4.prototype.__init46.call(this);_class4.prototype.__init47.call(this);_class4.prototype.__init48.call(this);_class4.prototype.__init49.call(this);_class4.prototype.__init50.call(this);_class4.prototype.__init51.call(this);_class4.prototype.__init52.call(this);_class4.prototype.__init53.call(this);_class4.prototype.__init54.call(this);
|
|
2140
2239
|
this.dpr = Math.max(1, _nullishCoalesce(options.dpr, () => ( 1)));
|
|
2141
2240
|
this.maxSize = Math.min(HARD_MAX_SIZE, Math.max(256, _nullishCoalesce(options.maxSize, () => ( 2048))));
|
|
2142
2241
|
}
|
|
@@ -2195,7 +2294,7 @@ var GlyphRasterAtlas = (_class4 = class {
|
|
|
2195
2294
|
* (headless, unrasterizable, or too large to pack).
|
|
2196
2295
|
*/
|
|
2197
2296
|
get(font, color, glyph) {
|
|
2198
|
-
const key = font
|
|
2297
|
+
const key = `${font.length}\0${font}${color.length}\0${color}${glyph.length}\0${glyph}`;
|
|
2199
2298
|
const existing = this.slots.get(key);
|
|
2200
2299
|
if (existing !== void 0) {
|
|
2201
2300
|
if (existing) this._hits++;
|
|
@@ -2318,13 +2417,13 @@ var GlyphRasterAtlas = (_class4 = class {
|
|
|
2318
2417
|
|
|
2319
2418
|
// src/renderer/TextRasterCache.ts
|
|
2320
2419
|
var TextRasterCache = (_class5 = class {
|
|
2321
|
-
|
|
2420
|
+
__init55() {this.cache = /* @__PURE__ */ new Map()}
|
|
2322
2421
|
|
|
2323
2422
|
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
constructor(options = {}) {;_class5.prototype.
|
|
2423
|
+
__init56() {this.scratchCtx = null}
|
|
2424
|
+
__init57() {this._hits = 0}
|
|
2425
|
+
__init58() {this._misses = 0}
|
|
2426
|
+
constructor(options = {}) {;_class5.prototype.__init55.call(this);_class5.prototype.__init56.call(this);_class5.prototype.__init57.call(this);_class5.prototype.__init58.call(this);
|
|
2328
2427
|
this.maxEntries = Math.max(1, _nullishCoalesce(options.maxEntries, () => ( 4096)));
|
|
2329
2428
|
this.dpr = Math.max(1, _nullishCoalesce(options.dpr, () => ( 1)));
|
|
2330
2429
|
}
|
|
@@ -2349,7 +2448,7 @@ var TextRasterCache = (_class5 = class {
|
|
|
2349
2448
|
* fall back to {@link IRenderer.fillText}).
|
|
2350
2449
|
*/
|
|
2351
2450
|
get(font, color, text) {
|
|
2352
|
-
const key = font
|
|
2451
|
+
const key = `${font.length}\0${font}${color.length}\0${color}${text.length}\0${text}`;
|
|
2353
2452
|
const hit = this.cache.get(key);
|
|
2354
2453
|
if (hit) {
|
|
2355
2454
|
this._hits++;
|