q5 2.27.9 → 2.28.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.
Files changed (5) hide show
  1. package/deno.json +1 -1
  2. package/package.json +2 -2
  3. package/q5.d.ts +27 -7
  4. package/q5.js +520 -454
  5. package/q5.min.js +2 -2
package/q5.js CHANGED
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * q5.js
3
- * @version 2.27
3
+ * @version 2.28
4
4
  * @author quinton-ashley
5
5
  * @contributors evanalulu, Tezumie, ormaq, Dukemz, LingDong-
6
6
  * @license LGPL-3.0
@@ -264,6 +264,7 @@ function Q5(scope, parent, renderer) {
264
264
  $._isTouchAware = t.touchStarted || t.touchMoved || t.touchEnded;
265
265
 
266
266
  let userFns = [
267
+ 'preload',
267
268
  'setup',
268
269
  'postProcess',
269
270
  'mouseMoved',
@@ -284,18 +285,16 @@ function Q5(scope, parent, renderer) {
284
285
  // shim if undefined
285
286
  for (let name of userFns) $[name] ??= () => {};
286
287
 
287
- function wrapWithFES(fn) {
288
- if (!t[fn]) $[fn] = () => {};
289
- else if ($._isGlobal) {
290
- $[fn] = (event) => {
291
- try {
292
- return t[fn](event);
293
- } catch (e) {
294
- if ($._fes) $._fes(e);
295
- throw e;
296
- }
297
- };
298
- }
288
+ function wrapWithFES(name) {
289
+ const fn = t[name] || $[name];
290
+ $[name] = (event) => {
291
+ try {
292
+ return fn(event);
293
+ } catch (e) {
294
+ if ($._fes) $._fes(e);
295
+ throw e;
296
+ }
297
+ };
299
298
  }
300
299
 
301
300
  async function start() {
@@ -384,7 +383,7 @@ function createCanvas(w, h, opt) {
384
383
  }
385
384
  }
386
385
 
387
- Q5.version = Q5.VERSION = '2.27';
386
+ Q5.version = Q5.VERSION = '2.28';
388
387
 
389
388
  if (typeof document == 'object') {
390
389
  document.addEventListener('DOMContentLoaded', () => {
@@ -615,45 +614,6 @@ Q5.modules.canvas = ($, q) => {
615
614
  } else $._da = 0;
616
615
  };
617
616
 
618
- $._styleNames = [
619
- '_fill',
620
- '_stroke',
621
- '_strokeWeight',
622
- '_doStroke',
623
- '_doFill',
624
- '_strokeSet',
625
- '_fillSet',
626
- '_shadow',
627
- '_doShadow',
628
- '_shadowOffsetX',
629
- '_shadowOffsetY',
630
- '_shadowBlur',
631
- '_tint',
632
- '_colorMode',
633
- '_colorFormat',
634
- 'Color',
635
- '_imageMode',
636
- '_rectMode',
637
- '_ellipseMode',
638
- '_textSize',
639
- '_textAlign',
640
- '_textBaseline'
641
- ];
642
- $._styles = [];
643
-
644
- $.pushStyles = () => {
645
- let styles = {};
646
- for (let s of $._styleNames) styles[s] = $[s];
647
- $._styles.push(styles);
648
- };
649
- $.popStyles = () => {
650
- let styles = $._styles.pop();
651
- for (let s of $._styleNames) $[s] = styles[s];
652
-
653
- if ($._webgpu) $.colorMode($._colorMode, $._colorFormat);
654
- else q.Color = styles.Color;
655
- };
656
-
657
617
  if (window && $._scope != 'graphics') {
658
618
  window.addEventListener('resize', () => {
659
619
  $._didResize = true;
@@ -919,13 +879,45 @@ Q5.renderers.c2d.canvas = ($, q) => {
919
879
  }
920
880
  };
921
881
 
922
- $.pushMatrix = () => $.ctx.save();
923
- $.popMatrix = () => $.ctx.restore();
882
+ $._styleNames = [
883
+ '_fill',
884
+ '_stroke',
885
+ '_strokeWeight',
886
+ '_doFill',
887
+ '_doStroke',
888
+ '_fillSet',
889
+ '_strokeSet',
890
+ '_shadow',
891
+ '_doShadow',
892
+ '_shadowOffsetX',
893
+ '_shadowOffsetY',
894
+ '_shadowBlur',
895
+ '_tint',
896
+ '_textSize',
897
+ '_textAlign',
898
+ '_textBaseline',
899
+ '_imageMode',
900
+ '_rectMode',
901
+ '_ellipseMode',
902
+ '_colorMode',
903
+ '_colorFormat',
904
+ 'Color'
905
+ ];
906
+ $._styles = [];
924
907
 
925
- let _popStyles = $.popStyles;
908
+ $.pushStyles = () => {
909
+ let styles = {};
910
+ for (let s of $._styleNames) styles[s] = $[s];
911
+ $._styles.push(styles);
912
+ };
913
+
914
+ function popStyles() {
915
+ let styles = $._styles.pop();
916
+ for (let s of $._styleNames) $[s] = styles[s];
917
+ }
926
918
 
927
919
  $.popStyles = () => {
928
- _popStyles();
920
+ popStyles();
929
921
 
930
922
  $.ctx.fillStyle = $._fill;
931
923
  $.ctx.strokeStyle = $._stroke;
@@ -936,13 +928,16 @@ Q5.renderers.c2d.canvas = ($, q) => {
936
928
  $.ctx.shadowBlur = $._doShadow ? $._shadowBlur : 0;
937
929
  };
938
930
 
931
+ $.pushMatrix = () => $.ctx.save();
932
+ $.popMatrix = () => $.ctx.restore();
933
+
939
934
  $.push = () => {
940
935
  $.ctx.save();
941
936
  $.pushStyles();
942
937
  };
943
938
  $.pop = () => {
944
939
  $.ctx.restore();
945
- _popStyles();
940
+ popStyles();
946
941
  };
947
942
  };
948
943
  Q5.renderers.c2d.shapes = ($) => {
@@ -3259,10 +3254,10 @@ Q5.modules.input = ($, q) => {
3259
3254
  };
3260
3255
 
3261
3256
  $._onmouseup = (e) => {
3257
+ q.mouseIsPressed = false;
3262
3258
  if (pressAmt > 0) pressAmt--;
3263
3259
  else return;
3264
3260
  $._updateMouse(e);
3265
- q.mouseIsPressed = false;
3266
3261
  $.mouseReleased(e);
3267
3262
  };
3268
3263
 
@@ -3367,10 +3362,11 @@ Q5.modules.input = ($, q) => {
3367
3362
  l('keyup', (e) => $._onkeyup(e), false);
3368
3363
 
3369
3364
  let pointer = window.PointerEvent ? 'pointer' : 'mouse';
3370
-
3371
3365
  l(pointer + 'move', (e) => $._onmousemove(e), false);
3372
-
3373
3366
  l('touchmove', (e) => $._ontouchmove(e));
3367
+ l(pointer + 'up', (e) => $._onmouseup(e));
3368
+ l('touchend', (e) => $._ontouchend(e));
3369
+ l('touchcancel', (e) => $._ontouchend(e));
3374
3370
 
3375
3371
  if (!c) l('wheel', (e) => $._onwheel(e));
3376
3372
  // making the window level event listener for wheel events
@@ -3381,14 +3377,9 @@ Q5.modules.input = ($, q) => {
3381
3377
  if (!$._isGlobal && c) l = c.addEventListener.bind(c);
3382
3378
 
3383
3379
  l(pointer + 'down', (e) => $._onmousedown(e));
3384
- l(pointer + 'up', (e) => $._onmouseup(e));
3385
-
3380
+ l('touchstart', (e) => $._ontouchstart(e));
3386
3381
  l('click', (e) => $._onclick(e));
3387
3382
  l('dblclick', (e) => $._ondblclick(e));
3388
-
3389
- l('touchstart', (e) => $._ontouchstart(e));
3390
- l('touchend', (e) => $._ontouchend(e));
3391
- l('touchcancel', (e) => $._ontouchend(e));
3392
3383
  }
3393
3384
  };
3394
3385
  Q5.modules.math = ($, q) => {
@@ -4905,11 +4896,6 @@ struct Q5 {
4905
4896
  $._g = $.createGraphics(1, 1, 'c2d');
4906
4897
  if ($._g.colorMode) $._g.colorMode($.RGB, 1);
4907
4898
 
4908
- $._hooks = {
4909
- prerender: [],
4910
- postrender: []
4911
- };
4912
-
4913
4899
  let encoder,
4914
4900
  pass,
4915
4901
  mainView,
@@ -4919,21 +4905,26 @@ struct Q5 {
4919
4905
  frameSampler,
4920
4906
  frameBindGroup,
4921
4907
  colorIndex = 1,
4922
- colorStackIndex = 8;
4908
+ colorStackIndex = 8,
4909
+ prevFramePL = 0,
4910
+ framePL = 0;
4923
4911
 
4924
4912
  $._pipelineConfigs = [];
4925
4913
  $._pipelines = [];
4926
4914
  $._buffers = [];
4927
- $._prevFramePL = 0;
4928
- $._framePL = 0;
4915
+
4916
+ $._hooks = {
4917
+ prerender: [],
4918
+ postrender: []
4919
+ };
4929
4920
 
4930
4921
  // local variables used for slightly better performance
4931
4922
 
4932
4923
  // stores pipeline shifts and vertex counts/image indices
4933
- let drawStack = ($._drawStack = []);
4924
+ let drawStack = [];
4934
4925
 
4935
4926
  // colors used for each draw call
4936
- let colorStack = ($._colorStack = new Float32Array(1e6));
4927
+ let colorStack = new Float32Array(1e6);
4937
4928
 
4938
4929
  // prettier-ignore
4939
4930
  colorStack.set([
@@ -5097,29 +5088,38 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5097
5088
  // since these values are checked so often in `addColor`,
5098
5089
  // they're stored in local variables for better performance
5099
5090
  let usingRGB = true,
5100
- colorFormat = 1;
5091
+ _colorMode = 'rgb',
5092
+ _colorFormat = 1;
5101
5093
 
5102
5094
  if ($.colorMode) {
5103
- let cm = $.colorMode;
5095
+ let colorMode = $.colorMode;
5104
5096
  $.colorMode = function () {
5105
- cm(...arguments);
5106
- usingRGB = $._colorMode == 'rgb';
5107
- colorFormat = $._colorFormat;
5097
+ colorMode(...arguments);
5098
+ _colorMode = $._colorMode;
5099
+ usingRGB = _colorMode == 'rgb';
5100
+ _colorFormat = $._colorFormat;
5108
5101
  };
5109
5102
  }
5110
5103
 
5111
- let addColor = (r, g, b, a) => {
5112
- if (typeof r === 'string' || usingRGB === false) {
5113
- r = $.color(r, g, b, a);
5104
+ const addColor = (r, g, b, a) => {
5105
+ let isColor = r._q5Color;
5106
+
5107
+ if (usingRGB === false || (g === undefined && !isColor && typeof r !== 'number')) {
5108
+ if (usingRGB === false || typeof r == 'string' || !Array.isArray(r)) {
5109
+ r = $.color(r, g, b, a);
5110
+ } else {
5111
+ [r, g, b, a] = r;
5112
+ }
5114
5113
  } else if (b === undefined) {
5115
5114
  // grayscale mode `fill(1, 0.5)`
5116
- a = g ?? colorFormat;
5115
+ a = g ?? _colorFormat;
5117
5116
  g = b = r;
5118
5117
  }
5119
- a ??= colorFormat;
5120
- if (r._q5Color) {
5118
+ a ??= _colorFormat;
5119
+
5120
+ if (isColor === true) {
5121
5121
  let c = r;
5122
- if (c.r != undefined) ({ r, g, b, a } = c);
5122
+ if (usingRGB) ({ r, g, b, a } = c);
5123
5123
  else {
5124
5124
  a = c.a;
5125
5125
  if (c.c != undefined) c = Q5.OKLCHtoRGB(c.l, c.c, c.h);
@@ -5129,7 +5129,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5129
5129
  }
5130
5130
  }
5131
5131
 
5132
- if (colorFormat === 255) {
5132
+ if (_colorFormat === 255) {
5133
5133
  r /= 255;
5134
5134
  g /= 255;
5135
5135
  b /= 255;
@@ -5147,38 +5147,42 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5147
5147
  colorIndex++;
5148
5148
  };
5149
5149
 
5150
- $._stroke = 0;
5151
- $._fill = $._tint = $._globalAlpha = 1;
5152
- $._doFill = $._doStroke = true;
5150
+ let doFill = true,
5151
+ doStroke = true,
5152
+ fillSet = false,
5153
+ strokeSet = false,
5154
+ strokeIdx = 0,
5155
+ fillIdx = 1,
5156
+ tintIdx = 1,
5157
+ globalAlpha = 1,
5158
+ sw = 1, // stroke weight
5159
+ hsw = 0.5, // half the stroke weight
5160
+ scaledSW = 1;
5153
5161
 
5154
5162
  $.fill = (r, g, b, a) => {
5155
5163
  addColor(r, g, b, a);
5156
- $._doFill = $._fillSet = true;
5157
- $._fill = colorIndex;
5164
+ doFill = fillSet = true;
5165
+ fillIdx = colorIndex;
5158
5166
  };
5159
5167
  $.stroke = (r, g, b, a) => {
5160
5168
  addColor(r, g, b, a);
5161
- $._doStroke = $._strokeSet = true;
5162
- $._stroke = colorIndex;
5169
+ doStroke = strokeSet = true;
5170
+ strokeIdx = colorIndex;
5163
5171
  };
5164
5172
  $.tint = (r, g, b, a) => {
5165
5173
  addColor(r, g, b, a);
5166
- $._tint = colorIndex;
5174
+ tintIdx = colorIndex;
5167
5175
  };
5168
- $.opacity = (a) => ($._globalAlpha = a);
5169
- $.noFill = () => ($._doFill = false);
5170
- $.noStroke = () => ($._doStroke = false);
5171
- $.noTint = () => ($._tint = 1);
5172
-
5173
- $._strokeWeight = 1;
5174
- $._hsw = 0.5;
5175
- $._scaledSW = 1;
5176
+ $.opacity = (a) => (globalAlpha = a);
5177
+ $.noFill = () => (doFill = false);
5178
+ $.noStroke = () => (doStroke = false);
5179
+ $.noTint = () => (tintIdx = 1);
5176
5180
 
5177
5181
  $.strokeWeight = (v) => {
5178
5182
  v = Math.abs(v);
5179
- $._strokeWeight = v;
5180
- $._scaledSW = v * $._scale;
5181
- $._hsw = v / 2;
5183
+ sw = v;
5184
+ scaledSW = v * _scale;
5185
+ hsw = v / 2;
5182
5186
  };
5183
5187
 
5184
5188
  const MAX_TRANSFORMS = $._graphics ? 1000 : 1e7,
@@ -5187,10 +5191,9 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5187
5191
 
5188
5192
  let matrix,
5189
5193
  matrices = [],
5190
- matricesIndexStack = [];
5191
-
5192
- // tracks if the matrix has been modified
5193
- $._matrixDirty = false;
5194
+ matricesIdxStack = [],
5195
+ matrixIdx = 0,
5196
+ matrixDirty = false; // tracks if the matrix has been modified
5194
5197
 
5195
5198
  // initialize with a 4x4 identity matrix
5196
5199
  // prettier-ignore
@@ -5205,7 +5208,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5205
5208
 
5206
5209
  $.resetMatrix = () => {
5207
5210
  matrix = matrices[0].slice();
5208
- $._matrixIndex = 0;
5211
+ matrixIdx = 0;
5209
5212
  };
5210
5213
  $.resetMatrix();
5211
5214
 
@@ -5216,7 +5219,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5216
5219
  m[12] += x * m[0];
5217
5220
  m[13] -= y * m[5];
5218
5221
  m[14] += z * m[10];
5219
- $._matrixDirty = true;
5222
+ matrixDirty = true;
5220
5223
  };
5221
5224
 
5222
5225
  $.rotate = $.rotateZ = (a) => {
@@ -5245,16 +5248,16 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5245
5248
  m[5] = m5 * cosR - m4 * sinR;
5246
5249
  }
5247
5250
 
5248
- $._matrixDirty = true;
5251
+ matrixDirty = true;
5249
5252
  };
5250
5253
 
5251
- $._scale = 1;
5254
+ let _scale = 1;
5252
5255
 
5253
5256
  $.scale = (x = 1, y, z = 1) => {
5254
5257
  y ??= x;
5255
5258
 
5256
- $._scale = Math.max(Math.abs(x), Math.abs(y));
5257
- $._scaledSW = $._strokeWeight * $._scale;
5259
+ _scale = Math.max(Math.abs(x), Math.abs(y));
5260
+ scaledSW = sw * _scale;
5258
5261
 
5259
5262
  let m = matrix;
5260
5263
 
@@ -5271,7 +5274,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5271
5274
  m[10] *= z;
5272
5275
  m[11] *= z;
5273
5276
 
5274
- $._matrixDirty = true;
5277
+ matrixDirty = true;
5275
5278
  };
5276
5279
 
5277
5280
  $.shearX = (ang) => {
@@ -5288,7 +5291,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5288
5291
  m[0] = m0 + m4 * tanAng;
5289
5292
  m[1] = m1 + m5 * tanAng;
5290
5293
 
5291
- $._matrixDirty = true;
5294
+ matrixDirty = true;
5292
5295
  };
5293
5296
 
5294
5297
  $.shearY = (ang) => {
@@ -5305,7 +5308,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5305
5308
  m[4] = m4 + m0 * tanAng;
5306
5309
  m[5] = m5 + m1 * tanAng;
5307
5310
 
5308
- $._matrixDirty = true;
5311
+ matrixDirty = true;
5309
5312
  };
5310
5313
 
5311
5314
  $.applyMatrix = (...args) => {
@@ -5322,38 +5325,93 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5322
5325
 
5323
5326
  // overwrite the current transformation matrix
5324
5327
  matrix = m.slice();
5325
- $._matrixDirty = true;
5328
+ matrixDirty = true;
5326
5329
  };
5327
5330
 
5328
5331
  // saves the current matrix state
5329
- $._saveMatrix = () => {
5332
+ const saveMatrix = () => {
5330
5333
  transforms.set(matrix, matrices.length * MATRIX_SIZE);
5331
- $._matrixIndex = matrices.length;
5334
+ matrixIdx = matrices.length;
5332
5335
  matrices.push(matrix.slice());
5333
- $._matrixDirty = false;
5336
+ matrixDirty = false;
5334
5337
  };
5335
5338
 
5336
5339
  // push the current matrix index onto the stack
5337
5340
  $.pushMatrix = () => {
5338
- if ($._matrixDirty) $._saveMatrix();
5339
- matricesIndexStack.push($._matrixIndex);
5341
+ if (matrixDirty) saveMatrix();
5342
+ matricesIdxStack.push(matrixIdx);
5340
5343
  };
5341
5344
 
5342
5345
  $.popMatrix = () => {
5343
- if (!matricesIndexStack.length) {
5346
+ if (!matricesIdxStack.length) {
5344
5347
  return console.warn('Matrix index stack is empty!');
5345
5348
  }
5346
5349
  // pop the last matrix index and set it as the current matrix index
5347
- let idx = matricesIndexStack.pop();
5350
+ let idx = matricesIdxStack.pop();
5348
5351
  matrix = matrices[idx].slice();
5349
- $._matrixIndex = idx;
5350
- $._matrixDirty = false;
5352
+ matrixIdx = idx;
5353
+ matrixDirty = false;
5351
5354
  };
5352
5355
 
5353
- let _pushStyles = $.pushStyles;
5356
+ let styles = [];
5357
+
5354
5358
  $.pushStyles = () => {
5355
- _pushStyles();
5356
- $.strokeWeight($._strokeWeight);
5359
+ styles.push([
5360
+ fillIdx,
5361
+ strokeIdx,
5362
+ sw,
5363
+ hsw,
5364
+ scaledSW,
5365
+ doFill,
5366
+ doStroke,
5367
+ fillSet,
5368
+ strokeSet,
5369
+ tintIdx,
5370
+ _textSize,
5371
+ _textAlign,
5372
+ _textBaseline,
5373
+ _imageMode,
5374
+ _rectMode,
5375
+ _ellipseMode,
5376
+ usingRGB,
5377
+ _colorMode,
5378
+ _colorFormat,
5379
+ Color
5380
+ ]);
5381
+ };
5382
+
5383
+ $.popStyles = () => {
5384
+ let s = styles.pop();
5385
+
5386
+ // array destructuring to local variables is way better
5387
+ // for performance than copying from one object to another
5388
+ [
5389
+ fillIdx,
5390
+ strokeIdx,
5391
+ sw,
5392
+ hsw,
5393
+ scaledSW,
5394
+ doFill,
5395
+ doStroke,
5396
+ fillSet,
5397
+ strokeSet,
5398
+ tintIdx,
5399
+ _textSize,
5400
+ _textAlign,
5401
+ _textBaseline,
5402
+ _imageMode,
5403
+ _rectMode,
5404
+ _ellipseMode,
5405
+ usingRGB,
5406
+ _colorMode,
5407
+ _colorFormat
5408
+ ] = s;
5409
+
5410
+ // since these values are used outside of q5-webgpu
5411
+ // they need to be stored on the instance
5412
+ $._colorFormat = _colorFormat;
5413
+ $._colorMode = _colorMode;
5414
+ $.Color = s.at(-1);
5357
5415
  };
5358
5416
 
5359
5417
  $.push = () => {
@@ -5366,7 +5424,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5366
5424
  $.popStyles();
5367
5425
  };
5368
5426
 
5369
- $._calcBox = (x, y, w, h, mode) => {
5427
+ const calcBox = (x, y, w, h, mode) => {
5370
5428
  // left, right, top, bottom
5371
5429
  let l, r, t, b;
5372
5430
  if (!mode || mode == 'corner') {
@@ -5426,7 +5484,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5426
5484
  replace: [1, 0, 0, 1, 0, 0]
5427
5485
  };
5428
5486
 
5429
- $._blendModeNames = Object.keys(blendModes);
5487
+ let blendModeNames = Object.keys(blendModes);
5430
5488
 
5431
5489
  $.blendConfigs = {};
5432
5490
 
@@ -5445,12 +5503,12 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5445
5503
  };
5446
5504
  }
5447
5505
 
5448
- $._blendMode = 'source-over';
5506
+ let _blendMode = 'source-over';
5449
5507
 
5450
5508
  $.blendMode = (mode) => {
5451
- if (mode == $._blendMode) return;
5452
- $._blendMode = mode;
5453
- let i = $._blendModeNames.indexOf(mode);
5509
+ if (mode == _blendMode) return;
5510
+ _blendMode = mode;
5511
+ let i = blendModeNames.indexOf(mode);
5454
5512
  if (i == -1) {
5455
5513
  console.error(`Blend mode "${mode}" not supported in q5.js WebGPU.`);
5456
5514
  return;
@@ -5465,19 +5523,17 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5465
5523
  };
5466
5524
 
5467
5525
  $.background = (r, g, b, a) => {
5468
- $.push();
5469
- $.resetMatrix();
5470
5526
  if (r.canvas) {
5527
+ $.push();
5528
+ $.resetMatrix();
5471
5529
  let img = r;
5472
- $._imageMode = 'corner';
5530
+ _imageMode = 'corner';
5473
5531
  $.image(img, -c.hw, -c.hh, c.w, c.h);
5532
+ $.pop();
5474
5533
  } else {
5475
- $._rectMode = 'corner';
5476
- $.fill(r, g, b, a);
5477
- $._doStroke = false;
5478
- $.rect(-c.hw, -c.hh, c.w, c.h);
5534
+ addColor(r, g, b, a);
5535
+ addRect(-c.hw, c.hh, c.hw, c.hh, c.hw, -c.hh, -c.hw, -c.hh, colorIndex, 0);
5479
5536
  }
5480
- $.pop();
5481
5537
  };
5482
5538
 
5483
5539
  $._beginRender = () => {
@@ -5511,7 +5567,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5511
5567
  });
5512
5568
 
5513
5569
  if (!shouldClear) {
5514
- pass.setPipeline($._pipelines[$._prevFramePL]);
5570
+ pass.setPipeline($._pipelines[prevFramePL]);
5515
5571
  pass.setBindGroup(0, frameBindGroup);
5516
5572
  pass.draw(4);
5517
5573
  }
@@ -5583,7 +5639,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5583
5639
  if (drawStack[i] != curPipelineIndex) {
5584
5640
  if (drawStack[i] == 0) {
5585
5641
  // change blend mode
5586
- let mode = $._blendModeNames[v];
5642
+ let mode = blendModeNames[v];
5587
5643
  for (let i = 1; i < $._pipelines.length; i++) {
5588
5644
  $._pipelineConfigs[i].fragment.targets[0].blend = $.blendConfigs[mode];
5589
5645
  $._pipelines[i] = Q5.device.createRenderPipeline($._pipelineConfigs[i]);
@@ -5644,7 +5700,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5644
5700
  ]
5645
5701
  });
5646
5702
 
5647
- pass.setPipeline($._pipelines[$._framePL]);
5703
+ pass.setPipeline($._pipelines[framePL]);
5648
5704
  pass.setBindGroup(0, frameBindGroup);
5649
5705
  pass.draw(4);
5650
5706
  pass.end();
@@ -5657,7 +5713,7 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5657
5713
  colorIndex = 1;
5658
5714
  colorStackIndex = 8;
5659
5715
  matrices = [matrices[0]];
5660
- matricesIndexStack = [];
5716
+ matricesIdxStack = [];
5661
5717
 
5662
5718
  $._texture = frameA;
5663
5719
 
@@ -5669,40 +5725,10 @@ fn fragMain(f: FragParams ) -> @location(0) vec4f {
5669
5725
  $._buffers = [];
5670
5726
  });
5671
5727
  };
5672
- };
5673
5728
 
5674
- Q5.initWebGPU = async () => {
5675
- if (!navigator.gpu) {
5676
- console.warn('q5 WebGPU not supported on this browser! Use Google Chrome or Edge.');
5677
- return false;
5678
- }
5679
- if (!Q5.requestedGPU) {
5680
- let adapter = await navigator.gpu.requestAdapter();
5681
- if (!adapter) {
5682
- console.warn('q5 WebGPU could not start! No appropriate GPUAdapter found, vulkan may need to be enabled.');
5683
- return false;
5684
- }
5685
- Q5.device = await adapter.requestDevice();
5729
+ /* SHAPES */
5686
5730
 
5687
- Q5.device.lost.then((e) => {
5688
- console.error('WebGPU crashed!');
5689
- console.error(e);
5690
- });
5691
- }
5692
- return true;
5693
- };
5694
-
5695
- Q5.WebGPU = async function (scope, parent) {
5696
- if (!scope || scope == 'global') Q5._hasGlobal = true;
5697
- if (!(await Q5.initWebGPU())) {
5698
- return new Q5(scope, parent, 'webgpu-fallback');
5699
- }
5700
- return new Q5(scope, parent, 'webgpu');
5701
- };
5702
-
5703
- Q5.webgpu = Q5.WebGPU;
5704
- Q5.renderers.webgpu.shapes = ($) => {
5705
- $._shapesPL = 1;
5731
+ let shapesPL = 1;
5706
5732
 
5707
5733
  $._shapesShaderCode =
5708
5734
  $._baseShaderCode +
@@ -5751,14 +5777,12 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5751
5777
  code: $._shapesShaderCode
5752
5778
  });
5753
5779
 
5754
- let c = $.canvas,
5755
- drawStack = $._drawStack,
5756
- vertexStack = new Float32Array($._graphics ? 1000 : 1e7),
5757
- vertIndex = 0;
5780
+ let shapesVertStack = new Float32Array($._graphics ? 1000 : 1e7),
5781
+ shapesVertIdx = 0;
5758
5782
  const TAU = Math.PI * 2;
5759
5783
  const HALF_PI = Math.PI / 2;
5760
5784
 
5761
- let vertexBufferLayout = {
5785
+ let shapesVertBuffLayout = {
5762
5786
  arrayStride: 16, // 4 floats * 4 bytes
5763
5787
  attributes: [
5764
5788
  { format: 'float32x2', offset: 0, shaderLocation: 0 }, // position
@@ -5778,7 +5802,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5778
5802
  vertex: {
5779
5803
  module: shapesShader,
5780
5804
  entryPoint: 'vertexMain',
5781
- buffers: [vertexBufferLayout]
5805
+ buffers: [shapesVertBuffLayout]
5782
5806
  },
5783
5807
  fragment: {
5784
5808
  module: shapesShader,
@@ -5792,18 +5816,18 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5792
5816
  $._pipelines[1] = Q5.device.createRenderPipeline($._pipelineConfigs[1]);
5793
5817
 
5794
5818
  const addVert = (x, y, ci, ti) => {
5795
- let v = vertexStack,
5796
- i = vertIndex;
5819
+ let v = shapesVertStack,
5820
+ i = shapesVertIdx;
5797
5821
  v[i++] = x;
5798
5822
  v[i++] = y;
5799
5823
  v[i++] = ci;
5800
5824
  v[i++] = ti;
5801
- vertIndex = i;
5825
+ shapesVertIdx = i;
5802
5826
  };
5803
5827
 
5804
5828
  const addRect = (x1, y1, x2, y2, x3, y3, x4, y4, ci, ti) => {
5805
- let v = vertexStack,
5806
- i = vertIndex;
5829
+ let v = shapesVertStack,
5830
+ i = shapesVertIdx;
5807
5831
 
5808
5832
  v[i++] = x1;
5809
5833
  v[i++] = y1;
@@ -5825,8 +5849,8 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5825
5849
  v[i++] = ci;
5826
5850
  v[i++] = ti;
5827
5851
 
5828
- vertIndex = i;
5829
- drawStack.push($._shapesPL, 4);
5852
+ shapesVertIdx = i;
5853
+ drawStack.push(shapesPL, 4);
5830
5854
  };
5831
5855
 
5832
5856
  const addArc = (x, y, a, b, startAngle, endAngle, n, ci, ti) => {
@@ -5834,8 +5858,8 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5834
5858
  let angleIncrement = angleRange / n;
5835
5859
  let t = startAngle;
5836
5860
 
5837
- let v = vertexStack,
5838
- i = vertIndex;
5861
+ let v = shapesVertStack,
5862
+ i = shapesVertIdx;
5839
5863
 
5840
5864
  for (let j = 0; j <= n; j++) {
5841
5865
  // add center vertex
@@ -5857,8 +5881,8 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5857
5881
  t += angleIncrement;
5858
5882
  }
5859
5883
 
5860
- vertIndex = i;
5861
- drawStack.push($._shapesPL, (n + 1) * 2);
5884
+ shapesVertIdx = i;
5885
+ drawStack.push(shapesPL, (n + 1) * 2);
5862
5886
  };
5863
5887
 
5864
5888
  const addArcStroke = (x, y, outerA, outerB, innerA, innerB, startAngle, endAngle, n, ci, ti) => {
@@ -5866,8 +5890,8 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5866
5890
  let angleIncrement = angleRange / n;
5867
5891
  let t = startAngle;
5868
5892
 
5869
- let v = vertexStack,
5870
- i = vertIndex;
5893
+ let v = shapesVertStack,
5894
+ i = shapesVertIdx;
5871
5895
 
5872
5896
  for (let j = 0; j <= n; j++) {
5873
5897
  // Outer vertex
@@ -5892,45 +5916,46 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5892
5916
  t += angleIncrement;
5893
5917
  }
5894
5918
 
5895
- vertIndex = i;
5896
- drawStack.push($._shapesPL, (n + 1) * 2);
5919
+ shapesVertIdx = i;
5920
+ drawStack.push(shapesPL, (n + 1) * 2);
5897
5921
  };
5898
5922
 
5899
- $.rectMode = (x) => ($._rectMode = x);
5923
+ let _rectMode = 'corner';
5924
+
5925
+ $.rectMode = (x) => (_rectMode = x);
5900
5926
 
5901
5927
  $.rect = (x, y, w, h, rr = 0) => {
5902
5928
  h ??= w;
5903
- let [l, r, t, b] = $._calcBox(x, y, w, h, $._rectMode);
5929
+ let [l, r, t, b] = calcBox(x, y, w, h, _rectMode);
5904
5930
  let ci, ti;
5905
- if ($._matrixDirty) $._saveMatrix();
5906
- ti = $._matrixIndex;
5931
+ if (matrixDirty) saveMatrix();
5932
+ ti = matrixIdx;
5907
5933
 
5908
5934
  if (!rr) {
5909
- if ($._doFill) {
5910
- ci = $._fill;
5935
+ if (doFill) {
5936
+ ci = fillIdx;
5911
5937
  addRect(l, t, r, t, r, b, l, b, ci, ti);
5912
5938
  }
5913
5939
 
5914
- if ($._doStroke) {
5915
- ci = $._stroke;
5916
- let sw = $._strokeWeight / 2;
5940
+ if (doStroke) {
5941
+ ci = strokeIdx;
5917
5942
 
5918
5943
  // Calculate stroke positions
5919
- let lsw = l - sw,
5920
- rsw = r + sw,
5921
- tsw = t + sw,
5922
- bsw = b - sw,
5923
- lpsw = l + sw,
5924
- rpsw = r - sw,
5925
- tpsw = t - sw,
5926
- bpsw = b + sw;
5944
+ let lsw = l - hsw,
5945
+ rsw = r + hsw,
5946
+ tsw = t + hsw,
5947
+ bsw = b - hsw,
5948
+ lpsw = l + hsw,
5949
+ rpsw = r - hsw,
5950
+ tpsw = t - hsw,
5951
+ bpsw = b + hsw;
5927
5952
 
5928
5953
  addRect(lsw, tpsw, rsw, tpsw, rsw, tsw, lsw, tsw, ci, ti); // Top
5929
5954
  addRect(lsw, bsw, rsw, bsw, rsw, bpsw, lsw, bpsw, ci, ti); // Bottom
5930
5955
 
5931
5956
  // Adjust side strokes to avoid overlapping corners
5932
- tsw = t - sw;
5933
- bsw = b + sw;
5957
+ tsw = t - hsw;
5958
+ bsw = b + hsw;
5934
5959
 
5935
5960
  addRect(lsw, tsw, lpsw, tsw, lpsw, bsw, lsw, bsw, ci, ti); // Left
5936
5961
  addRect(rpsw, tsw, rsw, tsw, rsw, bsw, rpsw, bsw, ci, ti); // Right
@@ -5946,15 +5971,15 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5946
5971
  // Clamp radius
5947
5972
  rr = Math.min(rr, Math.min(w, h) / 2);
5948
5973
 
5949
- let n = getArcSegments(rr * $._scale);
5974
+ let n = getArcSegments(rr * _scale);
5950
5975
 
5951
5976
  let trr = t + rr,
5952
5977
  brr = b - rr,
5953
5978
  lrr = l - rr,
5954
5979
  rrr = r + rr;
5955
5980
 
5956
- if ($._doFill) {
5957
- ci = $._fill;
5981
+ if (doFill) {
5982
+ ci = fillIdx;
5958
5983
  // Corner arcs
5959
5984
  addArc(r, b, rr, rr, 0, HALF_PI, n, ci, ti);
5960
5985
  addArc(l, b, rr, rr, Math.PI, HALF_PI, n, ci, ti);
@@ -5966,9 +5991,8 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5966
5991
  addRect(rrr, t, r, t, r, b, rrr, b, ci, ti); // Right
5967
5992
  }
5968
5993
 
5969
- if ($._doStroke) {
5970
- ci = $._stroke;
5971
- let hsw = $._hsw;
5994
+ if (doStroke) {
5995
+ ci = strokeIdx;
5972
5996
 
5973
5997
  let outerA = rr + hsw,
5974
5998
  outerB = rr + hsw,
@@ -6001,9 +6025,9 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6001
6025
 
6002
6026
  $.plane = (x, y, w, h) => {
6003
6027
  h ??= w;
6004
- let [l, r, t, b] = $._calcBox(x, y, w, h, 'center');
6005
- if ($._matrixDirty) $._saveMatrix();
6006
- addRect(l, t, r, t, r, b, l, b, $._fill, $._matrixIndex);
6028
+ let [l, r, t, b] = calcBox(x, y, w, h, 'center');
6029
+ if (matrixDirty) saveMatrix();
6030
+ addRect(l, t, r, t, r, b, l, b, fillIdx, matrixIdx);
6007
6031
  };
6008
6032
 
6009
6033
  // prettier-ignore
@@ -6037,24 +6061,24 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6037
6061
  d < 2400 ? 90 :
6038
6062
  100;
6039
6063
 
6040
- $._ellipseMode = Q5.CENTER;
6041
- $.ellipseMode = (x) => ($._ellipseMode = x);
6064
+ let _ellipseMode = 'center';
6065
+
6066
+ $.ellipseMode = (x) => (_ellipseMode = x);
6042
6067
 
6043
6068
  $.ellipse = (x, y, w, h) => {
6044
- let n = getArcSegments(Math.max(Math.abs(w), Math.abs(h)) * $._scale);
6069
+ let n = getArcSegments(Math.max(Math.abs(w), Math.abs(h)) * _scale);
6045
6070
  let a = w / 2;
6046
6071
  let b = w == h ? a : h / 2;
6047
6072
 
6048
- if ($._matrixDirty) $._saveMatrix();
6049
- let ti = $._matrixIndex;
6073
+ if (matrixDirty) saveMatrix();
6074
+ let ti = matrixIdx;
6050
6075
 
6051
- if ($._doFill) {
6052
- addArc(x, -y, a, b, 0, TAU, n, $._fill, ti);
6076
+ if (doFill) {
6077
+ addArc(x, -y, a, b, 0, TAU, n, fillIdx, ti);
6053
6078
  }
6054
- if ($._doStroke) {
6055
- let sw = $._strokeWeight / 2;
6079
+ if (doStroke) {
6056
6080
  // Draw the stroke as a ring using triangle strips
6057
- addArcStroke(x, -y, a + sw, b + sw, a - sw, b - sw, 0, TAU, n, $._stroke, ti);
6081
+ addArcStroke(x, -y, a + hsw, b + hsw, a - hsw, b - hsw, 0, TAU, n, strokeIdx, ti);
6058
6082
  }
6059
6083
  };
6060
6084
 
@@ -6079,74 +6103,72 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6079
6103
 
6080
6104
  // Calculate position based on ellipseMode
6081
6105
  let a, b;
6082
- if ($._ellipseMode == $.CENTER) {
6106
+ if (_ellipseMode == $.CENTER) {
6083
6107
  a = w / 2;
6084
6108
  b = h / 2;
6085
- } else if ($._ellipseMode == $.RADIUS) {
6109
+ } else if (_ellipseMode == $.RADIUS) {
6086
6110
  a = w;
6087
6111
  b = h;
6088
- } else if ($._ellipseMode == $.CORNER) {
6112
+ } else if (_ellipseMode == $.CORNER) {
6089
6113
  x += w / 2;
6090
6114
  y += h / 2;
6091
6115
  a = w / 2;
6092
6116
  b = h / 2;
6093
- } else if ($._ellipseMode == $.CORNERS) {
6117
+ } else if (_ellipseMode == $.CORNERS) {
6094
6118
  x = (x + w) / 2;
6095
6119
  y = (y + h) / 2;
6096
6120
  a = (w - x) / 2;
6097
6121
  b = (h - y) / 2;
6098
6122
  }
6099
6123
 
6100
- if ($._matrixDirty) $._saveMatrix();
6101
- let ti = $._matrixIndex;
6102
- let n = getArcSegments(Math.max(Math.abs(w), Math.abs(h)) * $._scale);
6124
+ if (matrixDirty) saveMatrix();
6125
+ let ti = matrixIdx;
6126
+ let n = getArcSegments(Math.max(Math.abs(w), Math.abs(h)) * _scale);
6103
6127
 
6104
6128
  // Draw fill
6105
- if ($._doFill) {
6106
- addArc(x, -y, a, b, start, stop, n, $._fill, ti);
6129
+ if (doFill) {
6130
+ addArc(x, -y, a, b, start, stop, n, fillIdx, ti);
6107
6131
  }
6108
6132
 
6109
6133
  // Draw stroke
6110
- if ($._doStroke) {
6111
- let hsw = $._hsw;
6112
- addArcStroke(x, -y, a + hsw, b + hsw, a - hsw, b - hsw, start, stop, n, $._stroke, ti);
6113
- if ($._strokeCap == 'round') {
6114
- addArc(x + a * Math.cos(start), -y - b * Math.sin(start), hsw, hsw, 0, TAU, n, $._stroke, ti);
6115
- addArc(x + a * Math.cos(stop), -y - b * Math.sin(stop), hsw, hsw, 0, TAU, n, $._stroke, ti);
6134
+ if (doStroke) {
6135
+ addArcStroke(x, -y, a + hsw, b + hsw, a - hsw, b - hsw, start, stop, n, strokeIdx, ti);
6136
+ if (_strokeCap == 'round') {
6137
+ addArc(x + a * Math.cos(start), -y - b * Math.sin(start), hsw, hsw, 0, TAU, n, strokeIdx, ti);
6138
+ addArc(x + a * Math.cos(stop), -y - b * Math.sin(stop), hsw, hsw, 0, TAU, n, strokeIdx, ti);
6116
6139
  }
6117
6140
  }
6118
6141
  };
6119
6142
 
6120
6143
  $.point = (x, y) => {
6121
- if ($._matrixDirty) $._saveMatrix();
6122
- let ti = $._matrixIndex,
6123
- ci = $._stroke,
6124
- sw = $._strokeWeight;
6144
+ if (matrixDirty) saveMatrix();
6145
+ let ti = matrixIdx,
6146
+ ci = strokeIdx;
6125
6147
 
6126
- if ($._scaledSW < 2) {
6127
- let [l, r, t, b] = $._calcBox(x, y, sw, sw, 'corner');
6148
+ if (scaledSW < 2) {
6149
+ let [l, r, t, b] = calcBox(x, y, sw, sw, 'corner');
6128
6150
  addRect(l, t, r, t, r, b, l, b, ci, ti);
6129
6151
  } else {
6130
- let n = getArcSegments($._scaledSW);
6152
+ let n = getArcSegments(scaledSW);
6131
6153
  sw /= 2;
6132
6154
  addArc(x, -y, sw, sw, 0, TAU, n, ci, ti);
6133
6155
  }
6134
6156
  };
6135
6157
 
6136
- $._strokeCap = $._strokeJoin = 'round';
6137
- $.strokeCap = (x) => ($._strokeCap = x);
6138
- $.strokeJoin = (x) => ($._strokeJoin = x);
6158
+ let _strokeCap = 'round',
6159
+ _strokeJoin = 'round';
6160
+
6161
+ $.strokeCap = (x) => (_strokeCap = x);
6162
+ $.strokeJoin = (x) => (_strokeJoin = x);
6139
6163
  $.lineMode = () => {
6140
- $._strokeCap = 'square';
6141
- $._strokeJoin = 'none';
6164
+ _strokeCap = 'square';
6165
+ _strokeJoin = 'none';
6142
6166
  };
6143
6167
 
6144
6168
  $.line = (x1, y1, x2, y2) => {
6145
- if ($._matrixDirty) $._saveMatrix();
6146
- let ti = $._matrixIndex,
6147
- ci = $._stroke,
6148
- sw = $._strokeWeight,
6149
- hsw = $._hsw;
6169
+ if (matrixDirty) saveMatrix();
6170
+ let ti = matrixIdx,
6171
+ ci = strokeIdx;
6150
6172
 
6151
6173
  // calculate the direction vector and length
6152
6174
  let dx = x2 - x1,
@@ -6159,8 +6181,8 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6159
6181
 
6160
6182
  addRect(x1 + px, -y1 - py, x1 - px, -y1 + py, x2 - px, -y2 + py, x2 + px, -y2 - py, ci, ti);
6161
6183
 
6162
- if ($._scaledSW > 2 && $._strokeCap != 'square') {
6163
- let n = getArcSegments($._scaledSW);
6184
+ if (scaledSW > 2 && _strokeCap != 'square') {
6185
+ let n = getArcSegments(scaledSW);
6164
6186
  addArc(x1, -y1, hsw, hsw, 0, TAU, n, ci, ti);
6165
6187
  addArc(x2, -y2, hsw, hsw, 0, TAU, n, ci, ti);
6166
6188
  }
@@ -6183,19 +6205,19 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6183
6205
  };
6184
6206
 
6185
6207
  $.vertex = (x, y) => {
6186
- if ($._matrixDirty) $._saveMatrix();
6187
- sv.push(x, -y, $._fill, $._matrixIndex);
6208
+ if (matrixDirty) saveMatrix();
6209
+ sv.push(x, -y, fillIdx, matrixIdx);
6188
6210
  shapeVertCount++;
6189
6211
  };
6190
6212
 
6191
6213
  $.curveVertex = (x, y) => {
6192
- if ($._matrixDirty) $._saveMatrix();
6214
+ if (matrixDirty) saveMatrix();
6193
6215
  curveVertices.push({ x: x, y: -y });
6194
6216
  };
6195
6217
 
6196
6218
  $.bezierVertex = function (cx1, cy1, cx2, cy2, x, y) {
6197
6219
  if (shapeVertCount === 0) throw new Error('Shape needs a vertex()');
6198
- if ($._matrixDirty) $._saveMatrix();
6220
+ if (matrixDirty) saveMatrix();
6199
6221
 
6200
6222
  // Get the last vertex as the starting point (P₀)
6201
6223
  let prevIndex = (shapeVertCount - 1) * 4;
@@ -6231,7 +6253,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6231
6253
  vy = mt3 * startY + 3 * mt2 * t * -cy1 + 3 * mt * t2 * -cy2 + t3 * -y;
6232
6254
  }
6233
6255
 
6234
- sv.push(vx, vy, $._fill, $._matrixIndex);
6256
+ sv.push(vx, vy, fillIdx, matrixIdx);
6235
6257
  shapeVertCount++;
6236
6258
  }
6237
6259
  };
@@ -6278,7 +6300,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6278
6300
  (2 * p0.y - 5 * p1.y + 4 * p2.y - p3.y) * t2 +
6279
6301
  (-p0.y + 3 * p1.y - 3 * p2.y + p3.y) * t3);
6280
6302
 
6281
- sv.push(x, y, $._fill, $._matrixIndex);
6303
+ sv.push(x, y, fillIdx, matrixIdx);
6282
6304
  shapeVertCount++;
6283
6305
  }
6284
6306
  }
@@ -6304,14 +6326,14 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6304
6326
  }
6305
6327
  }
6306
6328
 
6307
- if ($._doFill) {
6329
+ if (doFill) {
6308
6330
  if (shapeVertCount == 5) {
6309
6331
  // for quads, draw two triangles
6310
6332
  addVert(sv[0], sv[1], sv[2], sv[3]); // v0
6311
6333
  addVert(sv[4], sv[5], sv[6], sv[7]); // v1
6312
6334
  addVert(sv[12], sv[13], sv[14], sv[15]); // v3
6313
6335
  addVert(sv[8], sv[9], sv[10], sv[11]); // v2
6314
- drawStack.push($._shapesPL, 4);
6336
+ drawStack.push(shapesPL, 4);
6315
6337
  } else {
6316
6338
  // triangulate the shape
6317
6339
  for (let i = 1; i < shapeVertCount - 1; i++) {
@@ -6323,29 +6345,28 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6323
6345
  addVert(sv[v1], sv[v1 + 1], sv[v1 + 2], sv[v1 + 3]);
6324
6346
  addVert(sv[v2], sv[v2 + 1], sv[v2 + 2], sv[v2 + 3]);
6325
6347
  }
6326
- drawStack.push($._shapesPL, (shapeVertCount - 2) * 3);
6348
+ drawStack.push(shapesPL, (shapeVertCount - 2) * 3);
6327
6349
  }
6328
6350
  }
6329
6351
 
6330
- if ($._doStroke) {
6331
- let hsw = $._hsw,
6332
- n = getArcSegments($._scaledSW),
6333
- ti = $._matrixIndex,
6334
- ogStrokeCap = $._strokeCap;
6335
- $._strokeCap = 'square';
6352
+ if (doStroke) {
6353
+ let n = getArcSegments(scaledSW),
6354
+ ti = matrixIdx,
6355
+ ogStrokeCap = _strokeCap;
6356
+ _strokeCap = 'square';
6336
6357
  // draw lines between vertices
6337
6358
  for (let i = 0; i < shapeVertCount - 1; i++) {
6338
6359
  let v1 = i * 4;
6339
6360
  let v2 = (i + 1) * 4;
6340
6361
  $.line(sv[v1], -sv[v1 + 1], sv[v2], -sv[v2 + 1]);
6341
6362
 
6342
- addArc(sv[v1], sv[v1 + 1], hsw, hsw, 0, TAU, n, $._stroke, ti);
6363
+ addArc(sv[v1], sv[v1 + 1], hsw, hsw, 0, TAU, n, strokeIdx, ti);
6343
6364
  }
6344
6365
  let v1 = (shapeVertCount - 1) * 4;
6345
6366
  let v2 = 0;
6346
6367
  if (close) $.line(sv[v1], -sv[v1 + 1], sv[v2], -sv[v2 + 1]);
6347
- addArc(sv[v1], sv[v1 + 1], hsw, hsw, 0, TAU, n, $._stroke, ti);
6348
- $._strokeCap = ogStrokeCap;
6368
+ addArc(sv[v1], sv[v1 + 1], hsw, hsw, 0, TAU, n, strokeIdx, ti);
6369
+ _strokeCap = ogStrokeCap;
6349
6370
  }
6350
6371
 
6351
6372
  // reset for the next shape
@@ -6390,87 +6411,88 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6390
6411
  $._hooks.prerender.push(() => {
6391
6412
  $._pass.setPipeline($._pipelines[1]);
6392
6413
 
6393
- let vertexBuffer = Q5.device.createBuffer({
6394
- size: vertIndex * 4,
6414
+ let shapesVertBuff = Q5.device.createBuffer({
6415
+ size: shapesVertIdx * 4,
6395
6416
  usage: GPUBufferUsage.VERTEX,
6396
6417
  mappedAtCreation: true
6397
6418
  });
6398
6419
 
6399
- new Float32Array(vertexBuffer.getMappedRange()).set(vertexStack.slice(0, vertIndex));
6400
- vertexBuffer.unmap();
6420
+ new Float32Array(shapesVertBuff.getMappedRange()).set(shapesVertStack.slice(0, shapesVertIdx));
6421
+ shapesVertBuff.unmap();
6401
6422
 
6402
- $._pass.setVertexBuffer(0, vertexBuffer);
6423
+ $._pass.setVertexBuffer(0, shapesVertBuff);
6403
6424
 
6404
- $._buffers.push(vertexBuffer);
6425
+ $._buffers.push(shapesVertBuff);
6405
6426
  });
6406
6427
 
6407
6428
  $._hooks.postrender.push(() => {
6408
- vertIndex = 0;
6429
+ shapesVertIdx = 0;
6409
6430
  });
6410
- };
6411
- Q5.renderers.webgpu.image = ($, q) => {
6412
- $._imagePL = 2;
6413
- $._videoPL = 3;
6431
+
6432
+ /* IMAGE */
6433
+
6434
+ let imagePL = 2,
6435
+ videoPL = 3;
6414
6436
 
6415
6437
  $._imageShaderCode =
6416
6438
  $._baseShaderCode +
6417
6439
  /* wgsl */ `
6418
- struct VertexParams {
6419
- @builtin(vertex_index) vertexIndex : u32,
6420
- @location(0) pos: vec2f,
6421
- @location(1) texCoord: vec2f,
6422
- @location(2) tintIndex: f32,
6423
- @location(3) matrixIndex: f32,
6424
- @location(4) imageAlpha: f32
6425
- }
6426
- struct FragParams {
6427
- @builtin(position) position: vec4f,
6428
- @location(0) texCoord: vec2f,
6429
- @location(1) tintColor: vec4f,
6430
- @location(2) imageAlpha: f32
6431
- }
6432
-
6433
- @group(0) @binding(0) var<uniform> q: Q5;
6434
- @group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;
6435
- @group(0) @binding(2) var<storage> colors : array<vec4f>;
6436
-
6437
- @group(1) @binding(0) var samp: sampler;
6438
- @group(1) @binding(1) var tex: texture_2d<f32>;
6439
-
6440
- fn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {
6441
- var vert = vec4f(pos, 0f, 1f);
6442
- vert = transforms[i32(matrixIndex)] * vert;
6443
- vert.x /= q.halfWidth;
6444
- vert.y /= q.halfHeight;
6445
- return vert;
6446
- }
6447
-
6448
- fn applyTint(texColor: vec4f, tintColor: vec4f) -> vec4f {
6449
- // apply the tint color to the sampled texture color at full strength
6450
- let tinted = vec4f(texColor.rgb * tintColor.rgb, texColor.a);
6451
- // mix in the tint using the tint alpha as the blend strength
6452
- return mix(texColor, tinted, tintColor.a);
6453
- }
6454
-
6455
- @vertex
6456
- fn vertexMain(v: VertexParams) -> FragParams {
6457
- var vert = transformVertex(v.pos, v.matrixIndex);
6458
-
6459
- var f: FragParams;
6460
- f.position = vert;
6461
- f.texCoord = v.texCoord;
6462
- f.tintColor = colors[i32(v.tintIndex)];
6463
- f.imageAlpha = v.imageAlpha;
6464
- return f;
6465
- }
6466
-
6467
- @fragment
6468
- fn fragMain(f: FragParams) -> @location(0) vec4f {
6469
- var texColor = textureSample(tex, samp, f.texCoord);
6470
- texColor.a *= f.imageAlpha;
6471
- return applyTint(texColor, f.tintColor);
6472
- }
6473
- `;
6440
+ struct VertexParams {
6441
+ @builtin(vertex_index) vertexIndex : u32,
6442
+ @location(0) pos: vec2f,
6443
+ @location(1) texCoord: vec2f,
6444
+ @location(2) tintIndex: f32,
6445
+ @location(3) matrixIndex: f32,
6446
+ @location(4) imageAlpha: f32
6447
+ }
6448
+ struct FragParams {
6449
+ @builtin(position) position: vec4f,
6450
+ @location(0) texCoord: vec2f,
6451
+ @location(1) tintColor: vec4f,
6452
+ @location(2) imageAlpha: f32
6453
+ }
6454
+
6455
+ @group(0) @binding(0) var<uniform> q: Q5;
6456
+ @group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;
6457
+ @group(0) @binding(2) var<storage> colors : array<vec4f>;
6458
+
6459
+ @group(1) @binding(0) var samp: sampler;
6460
+ @group(1) @binding(1) var tex: texture_2d<f32>;
6461
+
6462
+ fn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {
6463
+ var vert = vec4f(pos, 0f, 1f);
6464
+ vert = transforms[i32(matrixIndex)] * vert;
6465
+ vert.x /= q.halfWidth;
6466
+ vert.y /= q.halfHeight;
6467
+ return vert;
6468
+ }
6469
+
6470
+ fn applyTint(texColor: vec4f, tintColor: vec4f) -> vec4f {
6471
+ // apply the tint color to the sampled texture color at full strength
6472
+ let tinted = vec4f(texColor.rgb * tintColor.rgb, texColor.a);
6473
+ // mix in the tint using the tint alpha as the blend strength
6474
+ return mix(texColor, tinted, tintColor.a);
6475
+ }
6476
+
6477
+ @vertex
6478
+ fn vertexMain(v: VertexParams) -> FragParams {
6479
+ var vert = transformVertex(v.pos, v.matrixIndex);
6480
+
6481
+ var f: FragParams;
6482
+ f.position = vert;
6483
+ f.texCoord = v.texCoord;
6484
+ f.tintColor = colors[i32(v.tintIndex)];
6485
+ f.imageAlpha = v.imageAlpha;
6486
+ return f;
6487
+ }
6488
+
6489
+ @fragment
6490
+ fn fragMain(f: FragParams) -> @location(0) vec4f {
6491
+ var texColor = textureSample(tex, samp, f.texCoord);
6492
+ texColor.a *= f.imageAlpha;
6493
+ return applyTint(texColor, f.tintColor);
6494
+ }
6495
+ `;
6474
6496
 
6475
6497
  let imageShader = Q5.device.createShaderModule({
6476
6498
  label: 'imageShader',
@@ -6486,10 +6508,10 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6486
6508
  code: $._videoShaderCode
6487
6509
  });
6488
6510
 
6489
- let vertexStack = new Float32Array($._graphics ? 1000 : 1e7),
6490
- vertIndex = 0;
6511
+ let imgVertStack = new Float32Array($._graphics ? 1000 : 1e7),
6512
+ imgVertIdx = 0;
6491
6513
 
6492
- let vertexBufferLayout = {
6514
+ let imgVertBuffLayout = {
6493
6515
  arrayStride: 28,
6494
6516
  attributes: [
6495
6517
  { shaderLocation: 0, offset: 0, format: 'float32x2' },
@@ -6548,7 +6570,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6548
6570
  vertex: {
6549
6571
  module: imageShader,
6550
6572
  entryPoint: 'vertexMain',
6551
- buffers: [{ arrayStride: 0, attributes: [] }, vertexBufferLayout]
6573
+ buffers: [{ arrayStride: 0, attributes: [] }, imgVertBuffLayout]
6552
6574
  },
6553
6575
  fragment: {
6554
6576
  module: imageShader,
@@ -6567,7 +6589,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6567
6589
  vertex: {
6568
6590
  module: videoShader,
6569
6591
  entryPoint: 'vertexMain',
6570
- buffers: [{ arrayStride: 0, attributes: [] }, vertexBufferLayout]
6592
+ buffers: [{ arrayStride: 0, attributes: [] }, imgVertBuffLayout]
6571
6593
  },
6572
6594
  fragment: {
6573
6595
  module: videoShader,
@@ -6747,11 +6769,13 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6747
6769
  return g;
6748
6770
  };
6749
6771
 
6750
- $.imageMode = (x) => ($._imageMode = x);
6772
+ let _imageMode = 'corner';
6751
6773
 
6752
- const addVert = (x, y, u, v, ci, ti, ia) => {
6753
- let s = vertexStack,
6754
- i = vertIndex;
6774
+ $.imageMode = (x) => (_imageMode = x);
6775
+
6776
+ const addImgVert = (x, y, u, v, ci, ti, ia) => {
6777
+ let s = imgVertStack,
6778
+ i = imgVertIdx;
6755
6779
  s[i++] = x;
6756
6780
  s[i++] = y;
6757
6781
  s[i++] = u;
@@ -6759,7 +6783,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6759
6783
  s[i++] = ci;
6760
6784
  s[i++] = ti;
6761
6785
  s[i++] = ia;
6762
- vertIndex = i;
6786
+ imgVertIdx = i;
6763
6787
  };
6764
6788
 
6765
6789
  $.image = (img, dx = 0, dy = 0, dw, dh, sx = 0, sy = 0, sw, sh) => {
@@ -6770,7 +6794,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6770
6794
  if (img.flipped) $.scale(-1, 1);
6771
6795
  }
6772
6796
 
6773
- if ($._matrixDirty) $._saveMatrix();
6797
+ if (matrixDirty) saveMatrix();
6774
6798
 
6775
6799
  let cnv = img.canvas || img,
6776
6800
  w = cnv.width,
@@ -6800,23 +6824,23 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6800
6824
  sx *= pd;
6801
6825
  sy *= pd;
6802
6826
 
6803
- let [l, r, t, b] = $._calcBox(dx, dy, dw, dh, $._imageMode);
6827
+ let [l, r, t, b] = calcBox(dx, dy, dw, dh, _imageMode);
6804
6828
 
6805
6829
  let u0 = sx / w,
6806
6830
  v0 = sy / h,
6807
6831
  u1 = (sx + sw) / w,
6808
6832
  v1 = (sy + sh) / h,
6809
- ti = $._matrixIndex,
6810
- ci = $._tint,
6811
- ia = $._globalAlpha;
6833
+ ti = matrixIdx,
6834
+ ci = tintIdx,
6835
+ ia = globalAlpha;
6812
6836
 
6813
- addVert(l, t, u0, v0, ci, ti, ia);
6814
- addVert(r, t, u1, v0, ci, ti, ia);
6815
- addVert(l, b, u0, v1, ci, ti, ia);
6816
- addVert(r, b, u1, v1, ci, ti, ia);
6837
+ addImgVert(l, t, u0, v0, ci, ti, ia);
6838
+ addImgVert(r, t, u1, v0, ci, ti, ia);
6839
+ addImgVert(l, b, u0, v1, ci, ti, ia);
6840
+ addImgVert(r, b, u1, v1, ci, ti, ia);
6817
6841
 
6818
6842
  if (!isVideo) {
6819
- $._drawStack.push($._imagePL, img._texture.index);
6843
+ drawStack.push(imagePL, img._texture.index);
6820
6844
 
6821
6845
  if (makeFrame) {
6822
6846
  img.resetMatrix();
@@ -6839,55 +6863,47 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6839
6863
  })
6840
6864
  );
6841
6865
 
6842
- $._drawStack.push($._videoPL, $._textureBindGroups.length - 1);
6866
+ drawStack.push(videoPL, $._textureBindGroups.length - 1);
6843
6867
 
6844
6868
  if (img.flipped) $.scale(-1, 1);
6845
6869
  }
6846
6870
  };
6847
6871
 
6848
6872
  $._hooks.prerender.push(() => {
6849
- if (!vertIndex) return;
6873
+ if (!imgVertIdx) return;
6850
6874
 
6851
6875
  // Switch to image pipeline
6852
6876
  $._pass.setPipeline($._pipelines[2]);
6853
6877
 
6854
- let vertexBuffer = Q5.device.createBuffer({
6855
- size: vertIndex * 5,
6878
+ let imgVertBuff = Q5.device.createBuffer({
6879
+ size: imgVertIdx * 5,
6856
6880
  usage: GPUBufferUsage.VERTEX,
6857
6881
  mappedAtCreation: true
6858
6882
  });
6859
6883
 
6860
- new Float32Array(vertexBuffer.getMappedRange()).set(vertexStack.slice(0, vertIndex));
6861
- vertexBuffer.unmap();
6884
+ new Float32Array(imgVertBuff.getMappedRange()).set(imgVertStack.slice(0, imgVertIdx));
6885
+ imgVertBuff.unmap();
6862
6886
 
6863
- $._pass.setVertexBuffer(1, vertexBuffer);
6887
+ $._pass.setVertexBuffer(1, imgVertBuff);
6864
6888
 
6865
- $._buffers.push(vertexBuffer);
6889
+ $._buffers.push(imgVertBuff);
6866
6890
 
6867
6891
  if (vidFrames) {
6868
6892
  // Switch to video pipeline
6869
6893
  $._pass.setPipeline($._pipelines[3]);
6870
- $._pass.setVertexBuffer(1, vertexBuffer);
6894
+ $._pass.setVertexBuffer(1, imgVertBuff);
6871
6895
  }
6872
6896
  });
6873
6897
 
6874
6898
  $._hooks.postrender.push(() => {
6875
- vertIndex = 0;
6899
+ imgVertIdx = 0;
6876
6900
  $._textureBindGroups.splice(tIdx, vidFrames);
6877
6901
  vidFrames = 0;
6878
6902
  });
6879
- };
6880
6903
 
6881
- Q5.THRESHOLD = 1;
6882
- Q5.GRAY = 2;
6883
- Q5.OPAQUE = 3;
6884
- Q5.INVERT = 4;
6885
- Q5.POSTERIZE = 5;
6886
- Q5.DILATE = 6;
6887
- Q5.ERODE = 7;
6888
- Q5.BLUR = 8;
6889
- Q5.renderers.webgpu.text = ($, q) => {
6890
- $._textPL = 4;
6904
+ /* TEXT */
6905
+
6906
+ let textPL = 4;
6891
6907
 
6892
6908
  $._textShaderCode =
6893
6909
  $._baseShaderCode +
@@ -7223,10 +7239,10 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
7223
7239
  return $.loadFont(url, cb);
7224
7240
  };
7225
7241
 
7226
- $._textSize = 18;
7227
- $._textAlign = 'left';
7228
- $._textBaseline = 'alphabetic';
7229
- let leadingSet = false,
7242
+ let _textSize = 18,
7243
+ _textAlign = 'left',
7244
+ _textBaseline = 'alphabetic',
7245
+ leadingSet = false,
7230
7246
  leading = 22.5,
7231
7247
  leadDiff = 4.5,
7232
7248
  leadPercent = 1.25;
@@ -7240,8 +7256,8 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
7240
7256
  };
7241
7257
 
7242
7258
  $.textSize = (size) => {
7243
- if (size == undefined) return $._textSize;
7244
- $._textSize = size;
7259
+ if (size == undefined) return _textSize;
7260
+ _textSize = size;
7245
7261
  if (!leadingSet) {
7246
7262
  leading = size * leadPercent;
7247
7263
  leadDiff = leading - size;
@@ -7264,7 +7280,7 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
7264
7280
  };
7265
7281
 
7266
7282
  // ranges from 0.35 (black) to 0.65 (thin)
7267
- $._textEdge = 0.5;
7283
+ let textEdge = 0.5;
7268
7284
 
7269
7285
  $.textWeight = (weight) => {
7270
7286
  if (!weight) return $._textWeight;
@@ -7272,19 +7288,19 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
7272
7288
  weight = weights[weight.toLowerCase().replace(/[ _-]/g, '')];
7273
7289
  if (!weight) throw new Error(`Invalid font weight: ${weight}`);
7274
7290
  }
7275
- $._textEdge = 0.6875 - weight * 0.000375;
7291
+ textEdge = 0.6875 - weight * 0.000375;
7276
7292
  };
7277
7293
 
7278
7294
  $.textLeading = (lineHeight) => {
7279
7295
  $._font.lineHeight = leading = lineHeight;
7280
- leadDiff = leading - $._textSize;
7281
- leadPercent = leading / $._textSize;
7296
+ leadDiff = leading - _textSize;
7297
+ leadPercent = leading / _textSize;
7282
7298
  leadingSet = true;
7283
7299
  };
7284
7300
 
7285
7301
  $.textAlign = (horiz, vert) => {
7286
- $._textAlign = horiz;
7287
- if (vert) $._textBaseline = vert;
7302
+ _textAlign = horiz;
7303
+ if (vert) _textBaseline = vert;
7288
7304
  };
7289
7305
 
7290
7306
  let charStack = [],
@@ -7383,8 +7399,8 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
7383
7399
 
7384
7400
  let charsData = [];
7385
7401
 
7386
- let ta = $._textAlign,
7387
- tb = $._textBaseline,
7402
+ let ta = _textAlign,
7403
+ tb = _textBaseline,
7388
7404
  textIndex = textStack.length,
7389
7405
  o = 0, // offset
7390
7406
  measurements;
@@ -7398,8 +7414,8 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
7398
7414
  o += 4;
7399
7415
  });
7400
7416
 
7401
- if (tb == 'alphabetic') y -= $._textSize;
7402
- else if (tb == 'center') y -= $._textSize * 0.5;
7417
+ if (tb == 'alphabetic') y -= _textSize;
7418
+ else if (tb == 'center') y -= _textSize * 0.5;
7403
7419
  else if (tb == 'bottom') y -= leading;
7404
7420
  } else {
7405
7421
  // measure the text to get the line widths before setting
@@ -7407,7 +7423,7 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
7407
7423
  measurements = measureText($._font, str);
7408
7424
 
7409
7425
  let offsetY = 0;
7410
- if (tb == 'alphabetic') y -= $._textSize;
7426
+ if (tb == 'alphabetic') y -= _textSize;
7411
7427
  else if (tb == 'center') offsetY = measurements.height * 0.5;
7412
7428
  else if (tb == 'bottom') offsetY = measurements.height;
7413
7429
 
@@ -7429,19 +7445,19 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
7429
7445
 
7430
7446
  let txt = [];
7431
7447
 
7432
- if ($._matrixDirty) $._saveMatrix();
7448
+ if (matrixDirty) saveMatrix();
7433
7449
 
7434
7450
  txt[0] = x;
7435
7451
  txt[1] = -y;
7436
- txt[2] = $._textSize / 42;
7437
- txt[3] = $._matrixIndex;
7438
- txt[4] = $._doFill && $._fillSet ? $._fill : 0;
7439
- txt[5] = $._stroke;
7440
- txt[6] = $._doStroke && $._strokeSet ? $._strokeWeight : 0;
7441
- txt[7] = $._textEdge;
7452
+ txt[2] = _textSize / 42;
7453
+ txt[3] = matrixIdx;
7454
+ txt[4] = doFill && fillSet ? fillIdx : 0;
7455
+ txt[5] = strokeIdx;
7456
+ txt[6] = doStroke && strokeSet ? sw : 0;
7457
+ txt[7] = textEdge;
7442
7458
 
7443
7459
  textStack.push(txt);
7444
- $._drawStack.push($._textPL, measurements.printedCharCount, $._font.index);
7460
+ drawStack.push(textPL, measurements.printedCharCount, $._font.index);
7445
7461
  };
7446
7462
 
7447
7463
  $.textWidth = (str) => {
@@ -7450,15 +7466,15 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
7450
7466
  };
7451
7467
 
7452
7468
  $.createTextImage = (str, w, h) => {
7453
- $._g.textSize($._textSize);
7469
+ $._g.textSize(_textSize);
7454
7470
 
7455
- if ($._doFill && $._fillSet) {
7456
- let fi = $._fill * 4;
7457
- $._g.fill($._colorStack.slice(fi, fi + 4));
7471
+ if (doFill && fillSet) {
7472
+ let fi = fillIdx * 4;
7473
+ $._g.fill(colorStack.slice(fi, fi + 4));
7458
7474
  }
7459
- if ($._doStroke && $._strokeSet) {
7460
- let si = $._stroke * 4;
7461
- $._g.stroke($._colorStack.slice(si, si + 4));
7475
+ if (doStroke && strokeSet) {
7476
+ let si = strokeIdx * 4;
7477
+ $._g.stroke(colorStack.slice(si, si + 4));
7462
7478
  }
7463
7479
 
7464
7480
  let g = $._g.createTextImage(str, w, h);
@@ -7469,21 +7485,21 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
7469
7485
  $.textImage = (img, x, y) => {
7470
7486
  if (typeof img == 'string') img = $.createTextImage(img);
7471
7487
 
7472
- let og = $._imageMode;
7473
- $._imageMode = 'corner';
7488
+ let og = _imageMode;
7489
+ _imageMode = 'corner';
7474
7490
 
7475
- let ta = $._textAlign;
7491
+ let ta = _textAlign;
7476
7492
  if (ta == 'center') x -= img.canvas.hw;
7477
7493
  else if (ta == 'right') x -= img.width;
7478
7494
 
7479
- let bl = $._textBaseline;
7495
+ let bl = _textBaseline;
7480
7496
  if (bl == 'alphabetic') y -= img._leading;
7481
7497
  else if (bl == 'center') y -= img._middle;
7482
7498
  else if (bl == 'bottom') y -= img._bottom;
7483
7499
  else if (bl == 'top') y -= img._top;
7484
7500
 
7485
7501
  $.image(img, x, y);
7486
- $._imageMode = og;
7502
+ _imageMode = og;
7487
7503
  };
7488
7504
 
7489
7505
  $._hooks.prerender.push(() => {
@@ -7538,8 +7554,9 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
7538
7554
  charStack = [];
7539
7555
  textStack = [];
7540
7556
  });
7541
- };
7542
- Q5.renderers.webgpu.shaders = ($) => {
7557
+
7558
+ /* SHADERS */
7559
+
7543
7560
  let pipelineTypes = ['frame', 'shapes', 'image', 'video', 'text'];
7544
7561
 
7545
7562
  let plCounters = {
@@ -7597,20 +7614,69 @@ Q5.renderers.webgpu.shaders = ($) => {
7597
7614
  $.createTextShader = (code) => $._createShader(code, 'text');
7598
7615
 
7599
7616
  $.shader = (shader) => {
7600
- if (shader.applyBeforeDraw) $._prevFramePL = shader.pipelineIndex;
7601
- else $['_' + shader.type + 'PL'] = shader.pipelineIndex;
7602
- };
7617
+ let type = shader.type;
7618
+ let idx = shader.pipelineIndex;
7603
7619
 
7604
- $.resetShader = (type = 'shapes') => {
7605
- if (type == 'frame') $._prevFramePL = 0;
7606
- $['_' + type + 'PL'] = pipelineTypes.indexOf(type);
7620
+ if (type == 'frame') {
7621
+ if (shader.applyBeforeDraw) prevFramePL = idx;
7622
+ else framePL = idx;
7623
+ } else if (type == 'shapes') shapesPL = idx;
7624
+ else if (type == 'image') imagePL = idx;
7625
+ else if (type == 'video') videoPL = idx;
7626
+ else if (type == 'text') textPL = idx;
7607
7627
  };
7608
7628
 
7629
+ $.resetShader = $.resetShapesShader = () => (shapesPL = 1);
7630
+ $.resetFrameShader = () => (prevFramePL = framePL = 0);
7631
+ $.resetImageShader = () => (imagePL = 2);
7632
+ $.resetVideoShader = () => (videoPL = 3);
7633
+ $.resetTextShader = () => (textPL = 4);
7634
+
7609
7635
  $.resetShaders = () => {
7610
- $._prevFramePL = $._framePL = 0;
7611
- $._shapesPL = 1;
7612
- $._imagePL = 2;
7613
- $._videoPL = 3;
7614
- $._textPL = 4;
7636
+ prevFramePL = framePL = 0;
7637
+ shapesPL = 1;
7638
+ imagePL = 2;
7639
+ videoPL = 3;
7640
+ textPL = 4;
7615
7641
  };
7616
7642
  };
7643
+
7644
+ Q5.THRESHOLD = 1;
7645
+ Q5.GRAY = 2;
7646
+ Q5.OPAQUE = 3;
7647
+ Q5.INVERT = 4;
7648
+ Q5.POSTERIZE = 5;
7649
+ Q5.DILATE = 6;
7650
+ Q5.ERODE = 7;
7651
+ Q5.BLUR = 8;
7652
+
7653
+ Q5.initWebGPU = async () => {
7654
+ if (!navigator.gpu) {
7655
+ console.warn('q5 WebGPU not supported on this browser! Use Google Chrome or Edge.');
7656
+ return false;
7657
+ }
7658
+ if (!Q5.requestedGPU) {
7659
+ let adapter = await navigator.gpu.requestAdapter();
7660
+ if (!adapter) {
7661
+ console.warn('q5 WebGPU could not start! No appropriate GPUAdapter found, vulkan may need to be enabled.');
7662
+ return false;
7663
+ }
7664
+ Q5.device = await adapter.requestDevice();
7665
+
7666
+ Q5.device.lost.then((e) => {
7667
+ console.error('WebGPU crashed!');
7668
+ console.error(e);
7669
+ });
7670
+ }
7671
+ return true;
7672
+ };
7673
+
7674
+ Q5.WebGPU = async function (scope, parent) {
7675
+ if (!scope || scope == 'global') Q5._hasGlobal = true;
7676
+ if (!(await Q5.initWebGPU())) {
7677
+ return new Q5(scope, parent, 'webgpu-fallback');
7678
+ }
7679
+ return new Q5(scope, parent, 'webgpu');
7680
+ };
7681
+
7682
+ Q5.webgpu = Q5.WebGPU;