q5 2.21.5 → 2.22.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/q5.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * q5.js
3
- * @version 2.21
3
+ * @version 2.22
4
4
  * @author quinton-ashley, Tezumie, and LingDong-
5
5
  * @license LGPL-3.0
6
6
  * @class Q5
@@ -41,7 +41,8 @@ function Q5(scope, parent, renderer) {
41
41
 
42
42
  $.canvas = $.ctx = $.drawingContext = null;
43
43
  $.pixels = [];
44
- let looper = null;
44
+ let looper = null,
45
+ useRAF = true;
45
46
 
46
47
  $.frameCount = 0;
47
48
  $.deltaTime = 16;
@@ -83,13 +84,22 @@ function Q5(scope, parent, renderer) {
83
84
  $._didResize = false;
84
85
  }
85
86
 
86
- if ($._loop) looper = raf($._draw);
87
- else if ($.frameCount && !$._redraw) return;
87
+ if ($._loop) {
88
+ if (useRAF) looper = raf($._draw);
89
+ else {
90
+ let nextTS = ts + $._targetFrameDuration;
91
+ let frameDelay = nextTS - performance.now();
92
+ while (frameDelay < 0) frameDelay += $._targetFrameDuration;
93
+ log(frameDelay);
94
+ looper = setTimeout(() => $._draw(nextTS), frameDelay);
95
+ }
96
+ } else if ($.frameCount && !$._redraw) return;
88
97
 
89
- if (looper && $.frameCount) {
90
- let time_since_last = ts - $._lastFrameTime;
91
- if (time_since_last < $._targetFrameDuration - 4) return;
98
+ if ($.frameCount && useRAF) {
99
+ let timeSinceLast = ts - $._lastFrameTime;
100
+ if (timeSinceLast < $._targetFrameDuration - 4) return;
92
101
  }
102
+
93
103
  q.deltaTime = ts - $._lastFrameTime;
94
104
  $._frameRate = 1000 / $.deltaTime;
95
105
  q.frameCount++;
@@ -100,7 +110,6 @@ function Q5(scope, parent, renderer) {
100
110
  try {
101
111
  $.draw();
102
112
  } catch (e) {
103
- if (!Q5.disableFriendlyErrors && $._askAI) $._askAI(e);
104
113
  if (!Q5.errorTolerant) $.noLoop();
105
114
  throw e;
106
115
  }
@@ -117,6 +126,10 @@ function Q5(scope, parent, renderer) {
117
126
  };
118
127
  $.noLoop = () => {
119
128
  $._loop = false;
129
+ if (looper) {
130
+ if (useRAF) cancelAnimationFrame(looper);
131
+ else clearTimeout(looper);
132
+ }
120
133
  looper = null;
121
134
  };
122
135
  $.loop = () => {
@@ -140,6 +153,14 @@ function Q5(scope, parent, renderer) {
140
153
  if (hz) {
141
154
  $._targetFrameRate = hz;
142
155
  $._targetFrameDuration = 1000 / hz;
156
+
157
+ if ($._loop && $._setupDone && looper != null) {
158
+ if (useRAF) cancelAnimationFrame(looper);
159
+ else clearTimeout(looper);
160
+ looper = null;
161
+ }
162
+ useRAF = hz <= 60;
163
+ setTimeout(() => $._draw(), $._targetFrameDuration);
143
164
  }
144
165
  return $._frameRate;
145
166
  };
@@ -243,14 +264,7 @@ function Q5(scope, parent, renderer) {
243
264
  for (let k of userFns) {
244
265
  if (!t[k]) $[k] = () => {};
245
266
  else if ($._isGlobal) {
246
- $[k] = (event) => {
247
- try {
248
- return t[k](event);
249
- } catch (e) {
250
- if ($._askAI) $._askAI(e);
251
- throw e;
252
- }
253
- };
267
+ $[k] = (event) => t[k](event);
254
268
  }
255
269
  }
256
270
 
@@ -314,7 +328,7 @@ function createCanvas(w, h, opt) {
314
328
  }
315
329
  }
316
330
 
317
- Q5.version = Q5.VERSION = '2.21';
331
+ Q5.version = Q5.VERSION = '2.22';
318
332
 
319
333
  if (typeof document == 'object') {
320
334
  document.addEventListener('DOMContentLoaded', () => {
@@ -407,7 +421,6 @@ Q5.modules.canvas = ($, q) => {
407
421
  if ($._hooks) {
408
422
  for (let m of $._hooks.postCanvas) m();
409
423
  }
410
- if ($._beginRender) $._beginRender();
411
424
 
412
425
  if ($._addEventMethods) $._addEventMethods(c);
413
426
 
@@ -514,7 +527,7 @@ Q5.modules.canvas = ($, q) => {
514
527
  $.pixelDensity = (v) => {
515
528
  if (!v || v == $._pixelDensity) return $._pixelDensity;
516
529
  $._pixelDensity = v;
517
- $._setCanvasSize(c.w, c.h);
530
+ $._resizeCanvas(c.w, c.h);
518
531
  return v;
519
532
  };
520
533
 
@@ -688,6 +701,22 @@ Q5.renderers.c2d.canvas = ($, q) => {
688
701
 
689
702
  if ($._scope == 'image') return;
690
703
 
704
+ $.background = function (c) {
705
+ $.ctx.save();
706
+ $.ctx.resetTransform();
707
+ $.ctx.globalAlpha = 1;
708
+ if (c.canvas) $.image(c, 0, 0, $.canvas.width, $.canvas.height);
709
+ else {
710
+ if (Q5.Color && !c._q5Color) {
711
+ if (typeof c != 'string') c = $.color(...arguments);
712
+ else if ($._namedColors[c]) c = $.color(...$._namedColors[c]);
713
+ }
714
+ $.ctx.fillStyle = c.toString();
715
+ $.ctx.fillRect(0, 0, $.canvas.width, $.canvas.height);
716
+ }
717
+ $.ctx.restore();
718
+ };
719
+
691
720
  $._resizeCanvas = (w, h) => {
692
721
  let t = {};
693
722
  for (let prop in $.ctx) {
@@ -868,22 +897,6 @@ Q5.renderers.c2d.shapes = ($) => {
868
897
 
869
898
  // DRAWING
870
899
 
871
- $.background = function (c) {
872
- $.ctx.save();
873
- $.ctx.resetTransform();
874
- $.ctx.globalAlpha = 1;
875
- if (c.canvas) $.image(c, 0, 0, $.canvas.width, $.canvas.height);
876
- else {
877
- if (Q5.Color && !c._q5Color) {
878
- if (typeof c != 'string') c = $.color(...arguments);
879
- else if ($._namedColors[c]) c = $.color(...$._namedColors[c]);
880
- }
881
- $.ctx.fillStyle = c.toString();
882
- $.ctx.fillRect(0, 0, $.canvas.width, $.canvas.height);
883
- }
884
- $.ctx.restore();
885
- };
886
-
887
900
  $.line = (x0, y0, x1, y1) => {
888
901
  if ($._doStroke) {
889
902
  $._da && ((x0 *= $._da), (y0 *= $._da), (x1 *= $._da), (y1 *= $._da));
@@ -1217,8 +1230,8 @@ Q5.renderers.c2d.shapes = ($) => {
1217
1230
  $.erase = function (fillAlpha = 255, strokeAlpha = 255) {
1218
1231
  $.ctx.save();
1219
1232
  $.ctx.globalCompositeOperation = 'destination-out';
1220
- $.ctx.fillStyle = `rgba(0, 0, 0, ${fillAlpha / 255})`;
1221
- $.ctx.strokeStyle = `rgba(0, 0, 0, ${strokeAlpha / 255})`;
1233
+ $.ctx.fillStyle = `rgb(0 0 0 / ${fillAlpha / 255})`;
1234
+ $.ctx.strokeStyle = `rgb(0 0 0 / ${strokeAlpha / 255})`;
1222
1235
  };
1223
1236
 
1224
1237
  $.noErase = function () {
@@ -2095,21 +2108,29 @@ Q5.modules.ai = ($) => {
2095
2108
  };
2096
2109
  Q5.modules.color = ($, q) => {
2097
2110
  $.RGB = $.RGBA = $._colorMode = 'rgb';
2098
- $.SRGB = 'srgb';
2111
+ $.HSL = 'hsl';
2112
+ $.HSB = 'hsb';
2099
2113
  $.OKLCH = 'oklch';
2100
2114
 
2101
- $.colorMode = (mode, format) => {
2115
+ $.SRGB = 'srgb';
2116
+ $.DISPLAY_P3 = 'display-p3';
2117
+
2118
+ $.colorMode = (mode, format, gamut) => {
2102
2119
  $._colorMode = mode;
2103
- let srgb = $.canvas.colorSpace == 'srgb' || mode == 'srgb';
2120
+ let srgb = $.canvas.colorSpace == 'srgb' || gamut == 'srgb';
2104
2121
  format ??= srgb ? 'integer' : 'float';
2105
2122
  $._colorFormat = format == 'float' || format == 1 ? 1 : 255;
2106
2123
  if (mode == 'oklch') {
2107
2124
  q.Color = Q5.ColorOKLCH;
2125
+ } else if (mode == 'hsl') {
2126
+ q.Color = srgb ? Q5.ColorHSL : Q5.ColorHSL_P3;
2127
+ } else if (mode == 'hsb') {
2128
+ q.Color = srgb ? Q5.ColorHSB : Q5.ColorHSB_P3;
2108
2129
  } else {
2109
2130
  if ($._colorFormat == 255) {
2110
- q.Color = srgb ? Q5.ColorRGBA_8 : Q5.ColorRGBA_P3_8;
2131
+ q.Color = srgb ? Q5.ColorRGB_8 : Q5.ColorRGB_P3_8;
2111
2132
  } else {
2112
- q.Color = srgb ? Q5.ColorRGBA : Q5.ColorRGBA_P3;
2133
+ q.Color = srgb ? Q5.ColorRGB : Q5.ColorRGB_P3;
2113
2134
  }
2114
2135
  $._colorMode = 'rgb';
2115
2136
  }
@@ -2203,7 +2224,8 @@ Q5.modules.color = ($, q) => {
2203
2224
 
2204
2225
  $.lightness = (c) => {
2205
2226
  if (c.l) return c.l;
2206
- return ((0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) * 100) / 255;
2227
+ let l = (0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) * 100;
2228
+ return $._colorFormat == 255 ? l / 255 : l;
2207
2229
  };
2208
2230
  $.hue = (c) => {
2209
2231
  if (c.h) return c.h;
@@ -2248,6 +2270,12 @@ Q5.Color = class {
2248
2270
  constructor() {
2249
2271
  this._q5Color = true;
2250
2272
  }
2273
+ get alpha() {
2274
+ return this.a;
2275
+ }
2276
+ set alpha(v) {
2277
+ this.a = v;
2278
+ }
2251
2279
  };
2252
2280
 
2253
2281
  Q5.ColorOKLCH = class extends Q5.Color {
@@ -2289,15 +2317,9 @@ Q5.ColorOKLCH = class extends Q5.Color {
2289
2317
  set hue(v) {
2290
2318
  this.h = v;
2291
2319
  }
2292
- get alpha() {
2293
- return this.a;
2294
- }
2295
- set alpha(v) {
2296
- this.a = v;
2297
- }
2298
2320
  };
2299
2321
 
2300
- Q5.ColorRGBA = class extends Q5.Color {
2322
+ Q5.ColorRGB = class extends Q5.Color {
2301
2323
  constructor(r, g, b, a) {
2302
2324
  super();
2303
2325
  this.r = r;
@@ -2317,6 +2339,7 @@ Q5.ColorRGBA = class extends Q5.Color {
2317
2339
  toString() {
2318
2340
  return `color(srgb ${this.r} ${this.g} ${this.b} / ${this.a})`;
2319
2341
  }
2342
+
2320
2343
  get red() {
2321
2344
  return this.r;
2322
2345
  }
@@ -2335,22 +2358,16 @@ Q5.ColorRGBA = class extends Q5.Color {
2335
2358
  set blue(v) {
2336
2359
  this.b = v;
2337
2360
  }
2338
- get alpha() {
2339
- return this.a;
2340
- }
2341
- set alpha(v) {
2342
- this.a = v;
2343
- }
2344
2361
  };
2345
2362
 
2346
- Q5.ColorRGBA_P3 = class extends Q5.ColorRGBA {
2363
+ Q5.ColorRGB_P3 = class extends Q5.ColorRGB {
2347
2364
  toString() {
2348
2365
  return `color(display-p3 ${this.r} ${this.g} ${this.b} / ${this.a})`;
2349
2366
  }
2350
2367
  };
2351
2368
 
2352
- // legacy 8-bit (0-255) integer color format
2353
- Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
2369
+ // legacy 8-bit (0-255) integer color format, srgb color space
2370
+ Q5.ColorRGB_8 = class extends Q5.ColorRGB {
2354
2371
  constructor(r, g, b, a) {
2355
2372
  super(r, g, b, a ?? 255);
2356
2373
  }
@@ -2373,7 +2390,7 @@ Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
2373
2390
  };
2374
2391
 
2375
2392
  // p3 10-bit color in integer color format, for backwards compatibility
2376
- Q5.ColorRGBA_P3_8 = class extends Q5.ColorRGBA {
2393
+ Q5.ColorRGB_P3_8 = class extends Q5.ColorRGB_8 {
2377
2394
  constructor(r, g, b, a) {
2378
2395
  super(r, g, b, a ?? 255);
2379
2396
  this._edited = true;
@@ -2418,6 +2435,159 @@ Q5.ColorRGBA_P3_8 = class extends Q5.ColorRGBA {
2418
2435
  return this._css;
2419
2436
  }
2420
2437
  };
2438
+
2439
+ Q5.ColorHSL = class extends Q5.Color {
2440
+ constructor(h, s, l, a) {
2441
+ super();
2442
+ this.h = h;
2443
+ this.s = s;
2444
+ this.l = l;
2445
+ this.a = a ?? 1;
2446
+ }
2447
+ get levels() {
2448
+ return [this.h, this.s, this.l, this.a];
2449
+ }
2450
+ equals(c) {
2451
+ return c && this.h == c.h && this.s == c.s && this.l == c.l && this.a == c.a;
2452
+ }
2453
+ isSameColor(c) {
2454
+ return c && this.h == c.h && this.s == c.s && this.l == c.l;
2455
+ }
2456
+ toString() {
2457
+ return `hsl(${this.h} ${this.s} ${this.l} / ${this.a})`;
2458
+ }
2459
+
2460
+ get hue() {
2461
+ return this.h;
2462
+ }
2463
+ set hue(v) {
2464
+ this.h = v;
2465
+ }
2466
+ get saturation() {
2467
+ return this.s;
2468
+ }
2469
+ set saturation(v) {
2470
+ this.s = v;
2471
+ }
2472
+ get lightness() {
2473
+ return this.l;
2474
+ }
2475
+ set lightness(v) {
2476
+ this.l = v;
2477
+ }
2478
+ };
2479
+
2480
+ Q5.ColorHSL_P3 = class extends Q5.ColorHSL {
2481
+ toString() {
2482
+ let o = Q5.HSLtoRGB(this.h, this.s, this.l);
2483
+ return `color(display-p3 ${o.join(' ')} / ${this.a})`;
2484
+ }
2485
+ };
2486
+
2487
+ Q5.ColorHSB = class extends Q5.ColorHSL {
2488
+ constructor(h, s, b, a) {
2489
+ super(h, s, b, a);
2490
+ delete this.l;
2491
+ this.b = b;
2492
+ }
2493
+ get levels() {
2494
+ return [this.h, this.s, this.b, this.a];
2495
+ }
2496
+ equals(c) {
2497
+ return c && this.h == c.h && this.s == c.s && this.b == c.b && this.a == c.a;
2498
+ }
2499
+ isSameColor(c) {
2500
+ return c && this.h == c.h && this.s == c.s && this.b == c.b;
2501
+ }
2502
+ toString() {
2503
+ let o = Q5.HSBtoHSL(this.h, this.s, this.b);
2504
+ return `hsl(${o.join(' ')} / ${this.a})`;
2505
+ }
2506
+
2507
+ get v() {
2508
+ return this.b;
2509
+ }
2510
+ set v(v) {
2511
+ this.b = v;
2512
+ }
2513
+ get brightness() {
2514
+ return this.b;
2515
+ }
2516
+ set brightness(v) {
2517
+ this.b = v;
2518
+ }
2519
+ get value() {
2520
+ return this.b;
2521
+ }
2522
+ set value(v) {
2523
+ this.b = v;
2524
+ }
2525
+ };
2526
+
2527
+ Q5.ColorHSB_P3 = class extends Q5.ColorHSB {
2528
+ toString() {
2529
+ let o = Q5.HSLtoRGB(...Q5.HSBtoHSL(this.h, this.s, this.b));
2530
+ return `color(display-p3 ${o.join(' ')} / ${this.a})`;
2531
+ }
2532
+ };
2533
+
2534
+ Q5.HSLtoRGB = (h, s, l) => {
2535
+ l /= 100;
2536
+ let m = (s / 100) * Math.min(l, 1 - l);
2537
+ let f = (n, k = (n + h / 30) % 12) => l - m * Math.max(Math.min(k - 3, 9 - k, 1), -1);
2538
+ return [f(0), f(8), f(4)];
2539
+ };
2540
+
2541
+ Q5.HSBtoHSL = (h, s, v, l = v * (1 - s / 200)) => [h, !l || l == 100 ? 0 : ((v - l) / Math.min(l, 100 - l)) * 100, l];
2542
+
2543
+ {
2544
+ const multiplyMatrices = (A, B) => [
2545
+ A[0] * B[0] + A[1] * B[1] + A[2] * B[2],
2546
+ A[3] * B[0] + A[4] * B[1] + A[5] * B[2],
2547
+ A[6] * B[0] + A[7] * B[1] + A[8] * B[2]
2548
+ ];
2549
+
2550
+ const oklch2oklab = (l, c, h) => [
2551
+ l,
2552
+ isNaN(h) ? 0 : c * Math.cos((h * Math.PI) / 180),
2553
+ isNaN(h) ? 0 : c * Math.sin((h * Math.PI) / 180)
2554
+ ];
2555
+
2556
+ const srgbLinear2rgb = (rgb) =>
2557
+ rgb.map((c) =>
2558
+ Math.max(
2559
+ 0,
2560
+ Math.min(1, Math.abs(c) > 0.0031308 ? (c < 0 ? -1 : 1) * (1.055 * Math.abs(c) ** (1 / 2.4) - 0.055) : 12.92 * c)
2561
+ )
2562
+ );
2563
+
2564
+ const oklab2xyz = (lab) => {
2565
+ const LMSg = multiplyMatrices(
2566
+ [
2567
+ 1, 0.3963377773761749, 0.2158037573099136, 1, -0.1055613458156586, -0.0638541728258133, 1, -0.0894841775298119,
2568
+ -1.2914855480194092
2569
+ ],
2570
+ lab
2571
+ );
2572
+ return multiplyMatrices(
2573
+ [
2574
+ 1.2268798758459243, -0.5578149944602171, 0.2813910456659647, -0.0405757452148008, 1.112286803280317,
2575
+ -0.0717110580655164, -0.0763729366746601, -0.4214933324022432, 1.5869240198367816
2576
+ ],
2577
+ LMSg.map((val) => val ** 3)
2578
+ );
2579
+ };
2580
+ const xyz2rgbLinear = (xyz) =>
2581
+ multiplyMatrices(
2582
+ [
2583
+ 3.2409699419045226, -1.537383177570094, -0.4986107602930034, -0.9692436362808796, 1.8759675015077202,
2584
+ 0.04155505740717559, 0.05563007969699366, -0.20397695888897652, 1.0569715142428786
2585
+ ],
2586
+ xyz
2587
+ );
2588
+
2589
+ Q5.OKLCHtoRGB = (l, c, h) => srgbLinear2rgb(xyz2rgbLinear(oklab2xyz(oklch2oklab(l, c, h))));
2590
+ }
2421
2591
  Q5.modules.display = ($) => {
2422
2592
  if (!$.canvas || $._scope == 'graphics') return;
2423
2593
 
@@ -4556,9 +4726,11 @@ struct Q5 {
4556
4726
  $._pipelineConfigs = [];
4557
4727
  $._pipelines = [];
4558
4728
  $._buffers = [];
4729
+ $._prevFramePL = 0;
4559
4730
  $._framePL = 0;
4560
4731
 
4561
4732
  // local variables used for slightly better performance
4733
+
4562
4734
  // stores pipeline shifts and vertex counts/image indices
4563
4735
  let drawStack = ($.drawStack = []);
4564
4736
 
@@ -4595,7 +4767,7 @@ struct Q5 {
4595
4767
  $.bindGroupLayouts = [mainLayout];
4596
4768
 
4597
4769
  let uniformBuffer = Q5.device.createBuffer({
4598
- size: 64, // Size of four floats
4770
+ size: 64,
4599
4771
  usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
4600
4772
  });
4601
4773
 
@@ -4695,7 +4867,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
4695
4867
  fragment: {
4696
4868
  module: frameShader,
4697
4869
  entryPoint: 'fragMain',
4698
- targets: [{ format, blend: $.blendConfigs.normal }]
4870
+ targets: [{ format }]
4699
4871
  },
4700
4872
  primitive: { topology: 'triangle-strip' },
4701
4873
  multisample: { count: 4 }
@@ -4723,27 +4895,23 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
4723
4895
  createMainView();
4724
4896
  };
4725
4897
 
4726
- $.pixelDensity = (v) => {
4727
- if (!v || v == $._pixelDensity) return $._pixelDensity;
4728
- $._pixelDensity = v;
4729
- $._setCanvasSize(c.w, c.h);
4730
- createMainView();
4731
- return v;
4732
- };
4733
-
4734
- // current color index, used to associate a vertex with a color
4735
4898
  let addColor = (r, g, b, a = 1) => {
4736
- if (typeof r == 'string') r = $.color(r);
4737
- else if (b == undefined) {
4899
+ if (typeof r == 'string' || $._colorMode != 'rgb') {
4900
+ r = $.color(r, g, b, a);
4901
+ } else if (b == undefined) {
4738
4902
  // grayscale mode `fill(1, 0.5)`
4739
4903
  a = g ?? 1;
4740
4904
  g = b = r;
4741
4905
  }
4742
4906
  if (r._q5Color) {
4743
- a = r.a;
4744
- b = r.b;
4745
- g = r.g;
4746
- r = r.r;
4907
+ let c = r;
4908
+ if (c.r) ({ r, g, b, a } = c);
4909
+ else {
4910
+ if (c.c) c = Q5.OKLCHtoRGB(c.l, c.c, c.h);
4911
+ else if (c.l) c = Q5.HSLtoRGB(c.h, c.s, c.l);
4912
+ else c = Q5.HSLtoRGB(...Q5.HSBtoHSL(c.h, c.s, c.b));
4913
+ [r, g, b, a] = c;
4914
+ }
4747
4915
  }
4748
4916
 
4749
4917
  let cs = colorStack,
@@ -4776,7 +4944,6 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
4776
4944
  $._tint = colorIndex;
4777
4945
  };
4778
4946
  $.opacity = (a) => ($._globalAlpha = a);
4779
-
4780
4947
  $.noFill = () => ($._doFill = false);
4781
4948
  $.noStroke = () => ($._doStroke = false);
4782
4949
  $.noTint = () => ($._tint = 1);
@@ -4784,6 +4951,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
4784
4951
  $._strokeWeight = 1;
4785
4952
  $._hsw = 0.5;
4786
4953
  $._scaledSW = 1;
4954
+
4787
4955
  $.strokeWeight = (v) => {
4788
4956
  v = Math.abs(v);
4789
4957
  $._strokeWeight = v;
@@ -4934,7 +5102,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
4934
5102
  $._matrixDirty = true;
4935
5103
  };
4936
5104
 
4937
- // function to save the current matrix state if dirty
5105
+ // saves the current matrix state
4938
5106
  $._saveMatrix = () => {
4939
5107
  transforms.set(matrix, matrices.length * MATRIX_SIZE);
4940
5108
  $._matrixIndex = matrices.length;
@@ -5066,13 +5234,28 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5066
5234
  };
5067
5235
 
5068
5236
  let shouldClear;
5237
+
5069
5238
  $.clear = () => {
5070
5239
  shouldClear = true;
5071
5240
  };
5072
5241
 
5073
- $._beginRender = () => {
5074
- if (encoder) return;
5242
+ $.background = (r, g, b, a) => {
5243
+ $.push();
5244
+ $.resetMatrix();
5245
+ if (r.canvas) {
5246
+ let img = r;
5247
+ $._imageMode = 'corner';
5248
+ $.image(img, -c.hw, -c.hh, c.w, c.h);
5249
+ } else {
5250
+ $._rectMode = 'corner';
5251
+ $.fill(r, g, b, a);
5252
+ $._doStroke = false;
5253
+ $.rect(-c.hw, -c.hh, c.w, c.h);
5254
+ }
5255
+ $.pop();
5256
+ };
5075
5257
 
5258
+ $._beginRender = () => {
5076
5259
  // swap the frame textures
5077
5260
  const temp = frameA;
5078
5261
  frameA = frameB;
@@ -5103,7 +5286,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5103
5286
  });
5104
5287
 
5105
5288
  if (!shouldClear) {
5106
- pass.setPipeline($._pipelines[0]);
5289
+ pass.setPipeline($._pipelines[$._prevFramePL]);
5107
5290
  pass.setBindGroup(0, frameBindGroup);
5108
5291
  pass.draw(4);
5109
5292
  }
@@ -5120,6 +5303,8 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5120
5303
  new Float32Array(transformBuffer.getMappedRange()).set(transforms.slice(0, matrices.length * MATRIX_SIZE));
5121
5304
  transformBuffer.unmap();
5122
5305
 
5306
+ $._buffers.push(transformBuffer);
5307
+
5123
5308
  let colorsBuffer = Q5.device.createBuffer({
5124
5309
  size: colorStackIndex * 4,
5125
5310
  usage: GPUBufferUsage.STORAGE,
@@ -5129,6 +5314,8 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5129
5314
  new Float32Array(colorsBuffer.getMappedRange()).set(colorStack.slice(0, colorStackIndex));
5130
5315
  colorsBuffer.unmap();
5131
5316
 
5317
+ $._buffers.push(colorsBuffer);
5318
+
5132
5319
  $._uniforms = [
5133
5320
  $.width,
5134
5321
  $.height,
@@ -5189,7 +5376,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5189
5376
  pass.setBindGroup(1, $._textureBindGroups[v]);
5190
5377
  pass.draw(4, 1, imageVertOffset);
5191
5378
  imageVertOffset += 4;
5192
- } else if (curPipelineIndex == 1 || curPipelineIndex >= 1000) {
5379
+ } else {
5193
5380
  // draw a shape
5194
5381
  // v is the number of vertices
5195
5382
  pass.draw(v, 1, drawVertOffset);
@@ -5198,7 +5385,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5198
5385
  }
5199
5386
  };
5200
5387
 
5201
- $._finishRender = () => {
5388
+ $._finishRender = async () => {
5202
5389
  pass.end();
5203
5390
 
5204
5391
  pass = encoder.beginRenderPass({
@@ -5228,6 +5415,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5228
5415
  pass.end();
5229
5416
 
5230
5417
  Q5.device.queue.submit([encoder.finish()]);
5418
+ $._pass = pass = encoder = null;
5231
5419
 
5232
5420
  // destroy buffers
5233
5421
  Q5.device.queue.onSubmittedWorkDone().then(() => {
@@ -5235,8 +5423,6 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5235
5423
  $._buffers = [];
5236
5424
  });
5237
5425
 
5238
- $._pass = pass = encoder = null;
5239
-
5240
5426
  // clear the stacks for the next frame
5241
5427
  drawStack.splice(0, drawStack.length);
5242
5428
  colorIndex = 1;
@@ -5886,22 +6072,6 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5886
6072
  $.endShape(true);
5887
6073
  };
5888
6074
 
5889
- $.background = (r, g, b, a) => {
5890
- $.push();
5891
- $.resetMatrix();
5892
- if (r.canvas) {
5893
- let img = r;
5894
- $._imageMode = 'corner';
5895
- $.image(img, -c.hw, -c.hh, c.w, c.h);
5896
- } else {
5897
- $._rectMode = 'corner';
5898
- $.fill(r, g, b, a);
5899
- $._doStroke = false;
5900
- $.rect(-c.hw, -c.hh, c.w, c.h);
5901
- }
5902
- $.pop();
5903
- };
5904
-
5905
6075
  $._hooks.preRender.push(() => {
5906
6076
  $._pass.setPipeline($._pipelines[1]);
5907
6077
 
@@ -7049,6 +7219,7 @@ Q5.renderers.webgpu.shaders = ($) => {
7049
7219
 
7050
7220
  let pl = plCounters[type];
7051
7221
  $._pipelines[pl] = Q5.device.createRenderPipeline(config);
7222
+ $._pipelines[pl].shader = shader;
7052
7223
  shader.pipelineIndex = pl;
7053
7224
 
7054
7225
  plCounters[type]++;
@@ -7063,15 +7234,17 @@ Q5.renderers.webgpu.shaders = ($) => {
7063
7234
  $.createTextShader = (code) => $._createShader(code, 'text');
7064
7235
 
7065
7236
  $.shader = (shader) => {
7066
- $['_' + shader.type + 'PL'] = shader.pipelineIndex;
7237
+ if (shader.applyBeforeDraw) $._prevFramePL = shader.pipelineIndex;
7238
+ else $['_' + shader.type + 'PL'] = shader.pipelineIndex;
7067
7239
  };
7068
7240
 
7069
7241
  $.resetShader = (type = 'shapes') => {
7242
+ if (type == 'frame') $._prevFramePL = 0;
7070
7243
  $['_' + type + 'PL'] = pipelineTypes.indexOf(type);
7071
7244
  };
7072
7245
 
7073
7246
  $.resetShaders = () => {
7074
- $._framePL = 0;
7247
+ $._prevFramePL = $._framePL = 0;
7075
7248
  $._shapesPL = 1;
7076
7249
  $._imagePL = 2;
7077
7250
  $._videoPL = 3;