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