q5 2.13.1 → 2.13.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -18,7 +18,6 @@ Q5.renderers.webgpu.canvas = ($, q) => {
18
18
 
19
19
  let pass,
20
20
  mainView,
21
- colorsLayout,
22
21
  colorIndex = 1,
23
22
  colorStackIndex = 8;
24
23
 
@@ -30,7 +29,6 @@ Q5.renderers.webgpu.canvas = ($, q) => {
30
29
  let drawStack = ($.drawStack = []);
31
30
 
32
31
  // colors used for each draw call
33
-
34
32
  let colorStack = ($.colorStack = new Float32Array(1e6));
35
33
 
36
34
  // prettier-ignore
@@ -39,43 +37,28 @@ Q5.renderers.webgpu.canvas = ($, q) => {
39
37
  1, 1, 1, 1 // white
40
38
  ]);
41
39
 
42
- $._transformLayout = Q5.device.createBindGroupLayout({
43
- label: 'transformLayout',
40
+ let mainLayout = Q5.device.createBindGroupLayout({
41
+ label: 'mainLayout',
44
42
  entries: [
45
43
  {
46
44
  binding: 0,
47
45
  visibility: GPUShaderStage.VERTEX,
48
- buffer: {
49
- type: 'uniform',
50
- hasDynamicOffset: false
51
- }
46
+ buffer: { type: 'uniform' }
52
47
  },
53
48
  {
54
49
  binding: 1,
55
50
  visibility: GPUShaderStage.VERTEX,
56
- buffer: {
57
- type: 'read-only-storage',
58
- hasDynamicOffset: false
59
- }
60
- }
61
- ]
62
- });
63
-
64
- colorsLayout = Q5.device.createBindGroupLayout({
65
- label: 'colorsLayout',
66
- entries: [
51
+ buffer: { type: 'read-only-storage' }
52
+ },
67
53
  {
68
- binding: 0,
54
+ binding: 2,
69
55
  visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
70
- buffer: {
71
- type: 'read-only-storage',
72
- hasDynamicOffset: false
73
- }
56
+ buffer: { type: 'read-only-storage' }
74
57
  }
75
58
  ]
76
59
  });
77
60
 
78
- $.bindGroupLayouts = [$._transformLayout, colorsLayout];
61
+ $.bindGroupLayouts = [mainLayout];
79
62
 
80
63
  let uniformBuffer = Q5.device.createBuffer({
81
64
  size: 8, // Size of two floats
@@ -105,7 +88,6 @@ Q5.renderers.webgpu.canvas = ($, q) => {
105
88
  Q5.device.queue.writeBuffer(uniformBuffer, 0, new Float32Array([$.canvas.hw, $.canvas.hh]));
106
89
 
107
90
  createMainView();
108
-
109
91
  return c;
110
92
  };
111
93
 
@@ -149,7 +131,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
149
131
  };
150
132
 
151
133
  $._stroke = 0;
152
- $._fill = $._tint = 1;
134
+ $._fill = $._tint = $._globalAlpha = 1;
153
135
  $._doFill = $._doStroke = true;
154
136
 
155
137
  $.fill = (r, g, b, a) => {
@@ -166,6 +148,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
166
148
  addColor(r, g, b, a);
167
149
  $._tint = colorIndex;
168
150
  };
151
+ $.opacity = (a) => ($._globalAlpha = a);
169
152
 
170
153
  $.noFill = () => ($._doFill = false);
171
154
  $.noStroke = () => ($._doStroke = false);
@@ -179,6 +162,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
179
162
  transforms = new Float32Array(MAX_TRANSFORMS * MATRIX_SIZE),
180
163
  matrices = [],
181
164
  matricesIndexStack = [];
165
+
182
166
  let matrix;
183
167
 
184
168
  // tracks if the matrix has been modified
@@ -214,12 +198,10 @@ Q5.renderers.webgpu.canvas = ($, q) => {
214
198
  if (!a) return;
215
199
  if ($._angleMode) a *= $._DEGTORAD;
216
200
 
217
- let cosR = Math.cos(a);
218
- let sinR = Math.sin(a);
219
-
220
- let m = matrix;
221
-
222
- let m0 = m[0],
201
+ let cosR = Math.cos(a),
202
+ sinR = Math.sin(a),
203
+ m = matrix,
204
+ m0 = m[0],
223
205
  m1 = m[1],
224
206
  m4 = m[4],
225
207
  m5 = m[5];
@@ -266,15 +248,15 @@ Q5.renderers.webgpu.canvas = ($, q) => {
266
248
  if (!ang) return;
267
249
  if ($._angleMode) ang *= $._DEGTORAD;
268
250
 
269
- let tanAng = Math.tan(ang);
270
-
271
- let m0 = matrix[0],
272
- m1 = matrix[1],
273
- m4 = matrix[4],
274
- m5 = matrix[5];
251
+ let tanAng = Math.tan(ang),
252
+ m = matrix,
253
+ m0 = m[0],
254
+ m1 = m[1],
255
+ m4 = m[4],
256
+ m5 = m[5];
275
257
 
276
- matrix[0] = m0 + m4 * tanAng;
277
- matrix[1] = m1 + m5 * tanAng;
258
+ m[0] = m0 + m4 * tanAng;
259
+ m[1] = m1 + m5 * tanAng;
278
260
 
279
261
  $._matrixDirty = true;
280
262
  };
@@ -283,15 +265,15 @@ Q5.renderers.webgpu.canvas = ($, q) => {
283
265
  if (!ang) return;
284
266
  if ($._angleMode) ang *= $._DEGTORAD;
285
267
 
286
- let tanAng = Math.tan(ang);
287
-
288
- let m0 = matrix[0],
289
- m1 = matrix[1],
290
- m4 = matrix[4],
291
- m5 = matrix[5];
268
+ let tanAng = Math.tan(ang),
269
+ m = matrix,
270
+ m0 = m[0],
271
+ m1 = m[1],
272
+ m4 = m[4],
273
+ m5 = m[5];
292
274
 
293
- matrix[4] = m4 + m0 * tanAng;
294
- matrix[5] = m5 + m1 * tanAng;
275
+ m[4] = m4 + m0 * tanAng;
276
+ m[5] = m5 + m1 * tanAng;
295
277
 
296
278
  $._matrixDirty = true;
297
279
  };
@@ -459,26 +441,14 @@ Q5.renderers.webgpu.canvas = ($, q) => {
459
441
  };
460
442
 
461
443
  $._render = () => {
462
- if (matrices.length > 1 || !$._transformBindGroup) {
463
- let transformBuffer = Q5.device.createBuffer({
464
- size: matrices.length * MATRIX_SIZE * 4, // 4 bytes per float
465
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
466
- mappedAtCreation: true
467
- });
468
-
469
- new Float32Array(transformBuffer.getMappedRange()).set(transforms.slice(0, matrices.length * MATRIX_SIZE));
470
- transformBuffer.unmap();
471
-
472
- $._transformBindGroup = Q5.device.createBindGroup({
473
- layout: $._transformLayout,
474
- entries: [
475
- { binding: 0, resource: { buffer: uniformBuffer } },
476
- { binding: 1, resource: { buffer: transformBuffer } }
477
- ]
478
- });
479
- }
444
+ let transformBuffer = Q5.device.createBuffer({
445
+ size: matrices.length * MATRIX_SIZE * 4, // 4 bytes per float
446
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
447
+ mappedAtCreation: true
448
+ });
480
449
 
481
- pass.setBindGroup(0, $._transformBindGroup);
450
+ new Float32Array(transformBuffer.getMappedRange()).set(transforms.slice(0, matrices.length * MATRIX_SIZE));
451
+ transformBuffer.unmap();
482
452
 
483
453
  let colorsBuffer = Q5.device.createBuffer({
484
454
  size: colorStackIndex * 4,
@@ -489,20 +459,23 @@ Q5.renderers.webgpu.canvas = ($, q) => {
489
459
  new Float32Array(colorsBuffer.getMappedRange()).set(colorStack.slice(0, colorStackIndex));
490
460
  colorsBuffer.unmap();
491
461
 
492
- $._colorsBindGroup = Q5.device.createBindGroup({
493
- layout: colorsLayout,
494
- entries: [{ binding: 0, resource: { buffer: colorsBuffer } }]
462
+ mainBindGroup = Q5.device.createBindGroup({
463
+ layout: mainLayout,
464
+ entries: [
465
+ { binding: 0, resource: { buffer: uniformBuffer } },
466
+ { binding: 1, resource: { buffer: transformBuffer } },
467
+ { binding: 2, resource: { buffer: colorsBuffer } }
468
+ ]
495
469
  });
496
470
 
497
- pass.setBindGroup(1, $._colorsBindGroup);
471
+ pass.setBindGroup(0, mainBindGroup);
498
472
 
499
473
  for (let m of $._hooks.preRender) m();
500
474
 
501
475
  let drawVertOffset = 0,
502
476
  imageVertOffset = 0,
503
477
  textCharOffset = 0,
504
- curPipelineIndex = -1,
505
- curTextureIndex = -1;
478
+ curPipelineIndex = -1;
506
479
 
507
480
  for (let i = 0; i < drawStack.length; i += 2) {
508
481
  let v = drawStack[i + 1];
@@ -518,20 +491,16 @@ Q5.renderers.webgpu.canvas = ($, q) => {
518
491
  pass.draw(v, 1, drawVertOffset);
519
492
  drawVertOffset += v;
520
493
  } else if (curPipelineIndex == 1) {
521
- // let vertCount = drawStack[i + 2];
522
494
  // draw images
523
- if (curTextureIndex != v) {
524
- // v is the texture index
525
- pass.setBindGroup(2, $._textureBindGroups[v]);
526
- }
495
+ // v is the texture index
496
+ pass.setBindGroup(1, $._textureBindGroups[v]);
527
497
  pass.draw(4, 1, imageVertOffset);
528
498
  imageVertOffset += 4;
529
- // i++;
530
499
  } else if (curPipelineIndex == 2) {
531
500
  // draw text
532
501
  let o = drawStack[i + 2];
533
- pass.setBindGroup(2, $._fonts[o].bindGroup);
534
- pass.setBindGroup(3, $._textBindGroup);
502
+ pass.setBindGroup(1, $._fonts[o].bindGroup);
503
+ pass.setBindGroup(2, $._textBindGroup);
535
504
 
536
505
  // v is the number of characters in the text
537
506
  pass.draw(4, v, 0, textCharOffset);
@@ -4,46 +4,40 @@ Q5.renderers.webgpu.drawing = ($, q) => {
4
4
  vertexStack = new Float32Array(1e7),
5
5
  vertIndex = 0;
6
6
 
7
- let vertexShader = Q5.device.createShaderModule({
8
- label: 'drawingVertexShader',
7
+ let drawingShader = Q5.device.createShaderModule({
8
+ label: 'drawingShader',
9
9
  code: `
10
- struct VertexInput {
10
+ struct Uniforms {
11
+ halfWidth: f32,
12
+ halfHeight: f32
13
+ }
14
+ struct VertexParams {
11
15
  @location(0) pos: vec2f,
12
16
  @location(1) colorIndex: f32,
13
17
  @location(2) matrixIndex: f32
14
18
  }
15
- struct VertexOutput {
19
+ struct FragmentParams {
16
20
  @builtin(position) position: vec4f,
17
21
  @location(0) color: vec4f
18
22
  }
19
- struct Uniforms {
20
- halfWidth: f32,
21
- halfHeight: f32
22
- }
23
23
 
24
24
  @group(0) @binding(0) var<uniform> uniforms: Uniforms;
25
25
  @group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;
26
-
27
- @group(1) @binding(0) var<storage> colors : array<vec4f>;
26
+ @group(0) @binding(2) var<storage> colors : array<vec4f>;
28
27
 
29
28
  @vertex
30
- fn vertexMain(input: VertexInput) -> VertexOutput {
31
- var vert = vec4f(input.pos, 0.0, 1.0);
32
- vert = transforms[i32(input.matrixIndex)] * vert;
29
+ fn vertexMain(v: VertexParams) -> FragmentParams {
30
+ var vert = vec4f(v.pos, 0.0, 1.0);
31
+ vert = transforms[i32(v.matrixIndex)] * vert;
33
32
  vert.x /= uniforms.halfWidth;
34
33
  vert.y /= uniforms.halfHeight;
35
34
 
36
- var output: VertexOutput;
37
- output.position = vert;
38
- output.color = colors[i32(input.colorIndex)];
39
- return output;
35
+ var f: FragmentParams;
36
+ f.position = vert;
37
+ f.color = colors[i32(v.colorIndex)];
38
+ return f;
40
39
  }
41
- `
42
- });
43
40
 
44
- let fragmentShader = Q5.device.createShaderModule({
45
- label: 'drawingFragmentShader',
46
- code: `
47
41
  @fragment
48
42
  fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
49
43
  return color;
@@ -52,7 +46,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
52
46
  });
53
47
 
54
48
  let vertexBufferLayout = {
55
- arrayStride: 16, // 2 coordinates + 1 color index + 1 transform index * 4 bytes each
49
+ arrayStride: 16, // 4 floats * 4 bytes
56
50
  attributes: [
57
51
  { format: 'float32x2', offset: 0, shaderLocation: 0 }, // position
58
52
  { format: 'float32', offset: 8, shaderLocation: 1 }, // colorIndex
@@ -69,19 +63,17 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
69
63
  label: 'drawingPipeline',
70
64
  layout: pipelineLayout,
71
65
  vertex: {
72
- module: vertexShader,
66
+ module: drawingShader,
73
67
  entryPoint: 'vertexMain',
74
68
  buffers: [vertexBufferLayout]
75
69
  },
76
70
  fragment: {
77
- module: fragmentShader,
71
+ module: drawingShader,
78
72
  entryPoint: 'fragmentMain',
79
73
  targets: [{ format: 'bgra8unorm', blend: $.blendConfigs.normal }]
80
74
  },
81
75
  primitive: { topology: 'triangle-strip', stripIndexFormat: 'uint32' },
82
- multisample: {
83
- count: 4
84
- }
76
+ multisample: { count: 4 }
85
77
  };
86
78
 
87
79
  $._pipelines[0] = Q5.device.createRenderPipeline($._pipelineConfigs[0]);
@@ -1,61 +1,64 @@
1
1
  Q5.renderers.webgpu.image = ($, q) => {
2
- $._textureBindGroups = [];
3
2
  let vertexStack = new Float32Array(1e7),
4
3
  vertIndex = 0;
5
4
 
6
5
  let imageShader = Q5.device.createShaderModule({
7
6
  label: 'imageShader',
8
7
  code: `
9
- struct VertexInput {
8
+ struct Uniforms {
9
+ halfWidth: f32,
10
+ halfHeight: f32
11
+ }
12
+ struct VertexParams {
10
13
  @location(0) pos: vec2f,
11
14
  @location(1) texCoord: vec2f,
12
15
  @location(2) tintIndex: f32,
13
- @location(3) matrixIndex: f32
16
+ @location(3) matrixIndex: f32,
17
+ @location(4) globalAlpha: f32
14
18
  }
15
- struct VertexOutput {
19
+ struct FragmentParams {
16
20
  @builtin(position) position: vec4f,
17
21
  @location(0) texCoord: vec2f,
18
- @location(1) tintIndex: f32
19
- }
20
- struct Uniforms {
21
- halfWidth: f32,
22
- halfHeight: f32
22
+ @location(1) tintIndex: f32,
23
+ @location(2) globalAlpha: f32
23
24
  }
24
25
 
25
26
  @group(0) @binding(0) var<uniform> uniforms: Uniforms;
26
27
  @group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;
28
+ @group(0) @binding(2) var<storage> colors : array<vec4f>;
27
29
 
28
- @group(1) @binding(0) var<storage> colors : array<vec4f>;
29
-
30
- @group(2) @binding(0) var samp: sampler;
31
- @group(2) @binding(1) var texture: texture_2d<f32>;
30
+ @group(1) @binding(0) var samp: sampler;
31
+ @group(1) @binding(1) var texture: texture_2d<f32>;
32
32
 
33
33
  @vertex
34
- fn vertexMain(input: VertexInput) -> VertexOutput {
35
- var vert = vec4f(input.pos, 0.0, 1.0);
36
- vert = transforms[i32(input.matrixIndex)] * vert;
34
+ fn vertexMain(v: VertexParams) -> FragmentParams {
35
+ var vert = vec4f(v.pos, 0.0, 1.0);
36
+ vert = transforms[i32(v.matrixIndex)] * vert;
37
37
  vert.x /= uniforms.halfWidth;
38
38
  vert.y /= uniforms.halfHeight;
39
39
 
40
- var output: VertexOutput;
41
- output.position = vert;
42
- output.texCoord = input.texCoord;
43
- output.tintIndex = input.tintIndex;
44
- return output;
40
+ var f: FragmentParams;
41
+ f.position = vert;
42
+ f.texCoord = v.texCoord;
43
+ f.tintIndex = v.tintIndex;
44
+ f.globalAlpha = v.globalAlpha;
45
+ return f;
45
46
  }
46
47
 
47
48
  @fragment
48
- fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @location(0) vec4f {
49
- let texColor = textureSample(texture, samp, texCoord);
50
- let tintColor = colors[i32(tintIndex)];
49
+ fn fragmentMain(f: FragmentParams) -> @location(0) vec4f {
50
+ let texColor = textureSample(texture, samp, f.texCoord);
51
+ let tintColor = colors[i32(f.tintIndex)];
51
52
 
52
53
  // Mix original and tinted colors using tint alpha as blend factor
53
- let tinted = vec4f(texColor.rgb * tintColor.rgb, texColor.a);
54
+ let tinted = vec4f(texColor.rgb * tintColor.rgb, texColor.a * f.globalAlpha);
54
55
  return mix(texColor, tinted, tintColor.a);
55
56
  }
56
57
  `
57
58
  });
58
59
 
60
+ $._textureBindGroups = [];
61
+
59
62
  let textureLayout = Q5.device.createBindGroupLayout({
60
63
  label: 'textureLayout',
61
64
  entries: [
@@ -73,12 +76,13 @@ fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @l
73
76
  });
74
77
 
75
78
  const vertexBufferLayout = {
76
- arrayStride: 24,
79
+ arrayStride: 28,
77
80
  attributes: [
78
81
  { shaderLocation: 0, offset: 0, format: 'float32x2' },
79
82
  { shaderLocation: 1, offset: 8, format: 'float32x2' },
80
83
  { shaderLocation: 2, offset: 16, format: 'float32' }, // tintIndex
81
- { shaderLocation: 3, offset: 20, format: 'float32' } // matrixIndex
84
+ { shaderLocation: 3, offset: 20, format: 'float32' }, // matrixIndex
85
+ { shaderLocation: 4, offset: 24, format: 'float32' } // globalAlpha
82
86
  ]
83
87
  };
84
88
 
@@ -114,14 +118,11 @@ fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @l
114
118
  minFilter: filter
115
119
  });
116
120
  };
117
- makeSampler('linear');
118
121
 
119
- $.smooth = () => {
120
- makeSampler('linear');
121
- };
122
- $.noSmooth = () => {
123
- makeSampler('nearest');
124
- };
122
+ $.smooth = () => makeSampler('linear');
123
+ $.noSmooth = () => makeSampler('nearest');
124
+
125
+ $.smooth();
125
126
 
126
127
  let MAX_TEXTURES = 12000;
127
128
 
@@ -184,7 +185,7 @@ fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @l
184
185
 
185
186
  $.imageMode = (x) => ($._imageMode = x);
186
187
 
187
- const addVert = (x, y, u, v, ci, ti) => {
188
+ const addVert = (x, y, u, v, ci, ti, ga) => {
188
189
  let s = vertexStack,
189
190
  i = vertIndex;
190
191
  s[i++] = x;
@@ -193,6 +194,7 @@ fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @l
193
194
  s[i++] = v;
194
195
  s[i++] = ci;
195
196
  s[i++] = ti;
197
+ s[i++] = ga;
196
198
  vertIndex = i;
197
199
  };
198
200
 
@@ -203,16 +205,15 @@ fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @l
203
205
 
204
206
  if ($._matrixDirty) $._saveMatrix();
205
207
 
206
- let ti = $._matrixIndex,
207
- w = img.width,
208
- h = img.height;
208
+ let w = img.width,
209
+ h = img.height,
210
+ pd = g._pixelDensity || 1;
209
211
 
210
212
  dw ??= g.defaultWidth;
211
213
  dh ??= g.defaultHeight;
212
214
  sw ??= w;
213
215
  sh ??= h;
214
216
 
215
- let pd = g._pixelDensity || 1;
216
217
  dw *= pd;
217
218
  dh *= pd;
218
219
 
@@ -221,14 +222,15 @@ fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @l
221
222
  let u0 = sx / w,
222
223
  v0 = sy / h,
223
224
  u1 = (sx + sw) / w,
224
- v1 = (sy + sh) / h;
225
-
226
- let ci = $._tint;
225
+ v1 = (sy + sh) / h,
226
+ ti = $._matrixIndex,
227
+ ci = $._tint,
228
+ ga = $._globalAlpha;
227
229
 
228
- addVert(l, t, u0, v0, ci, ti);
229
- addVert(r, t, u1, v0, ci, ti);
230
- addVert(l, b, u0, v1, ci, ti);
231
- addVert(r, b, u1, v1, ci, ti);
230
+ addVert(l, t, u0, v0, ci, ti, ga);
231
+ addVert(r, t, u1, v0, ci, ti, ga);
232
+ addVert(l, b, u0, v1, ci, ti, ga);
233
+ addVert(r, b, u1, v1, ci, ti, ga);
232
234
 
233
235
  $.drawStack.push(1, img.textureIndex);
234
236
  };
@@ -240,7 +242,7 @@ fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @l
240
242
  $.pass.setPipeline($._pipelines[1]);
241
243
 
242
244
  let vertexBuffer = Q5.device.createBuffer({
243
- size: vertIndex * 4,
245
+ size: vertIndex * 5,
244
246
  usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
245
247
  mappedAtCreation: true
246
248
  });