q5 2.13.1 → 2.13.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "q5",
3
- "version": "2.13.1",
3
+ "version": "2.13.2",
4
4
  "description": "A sequel to p5.js that's optimized for interactive art",
5
5
  "author": "quinton-ashley",
6
6
  "contributors": [
package/q5.js CHANGED
@@ -843,6 +843,7 @@ Q5.renderers.q2d.canvas = ($, q) => {
843
843
  if ($.ctx) {
844
844
  $.ctx.resetTransform();
845
845
  $.scale($._pixelDensity);
846
+ if ($._webgpuFallback) $.translate($.canvas.hw, $.canvas.hh);
846
847
  }
847
848
  };
848
849
 
@@ -3601,7 +3602,6 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3601
3602
 
3602
3603
  let pass,
3603
3604
  mainView,
3604
- colorsLayout,
3605
3605
  colorIndex = 1,
3606
3606
  colorStackIndex = 8;
3607
3607
 
@@ -3613,7 +3613,6 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3613
3613
  let drawStack = ($.drawStack = []);
3614
3614
 
3615
3615
  // colors used for each draw call
3616
-
3617
3616
  let colorStack = ($.colorStack = new Float32Array(1e6));
3618
3617
 
3619
3618
  // prettier-ignore
@@ -3622,43 +3621,28 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3622
3621
  1, 1, 1, 1 // white
3623
3622
  ]);
3624
3623
 
3625
- $._transformLayout = Q5.device.createBindGroupLayout({
3626
- label: 'transformLayout',
3624
+ let mainLayout = Q5.device.createBindGroupLayout({
3625
+ label: 'mainLayout',
3627
3626
  entries: [
3628
3627
  {
3629
3628
  binding: 0,
3630
3629
  visibility: GPUShaderStage.VERTEX,
3631
- buffer: {
3632
- type: 'uniform',
3633
- hasDynamicOffset: false
3634
- }
3630
+ buffer: { type: 'uniform' }
3635
3631
  },
3636
3632
  {
3637
3633
  binding: 1,
3638
3634
  visibility: GPUShaderStage.VERTEX,
3639
- buffer: {
3640
- type: 'read-only-storage',
3641
- hasDynamicOffset: false
3642
- }
3643
- }
3644
- ]
3645
- });
3646
-
3647
- colorsLayout = Q5.device.createBindGroupLayout({
3648
- label: 'colorsLayout',
3649
- entries: [
3635
+ buffer: { type: 'read-only-storage' }
3636
+ },
3650
3637
  {
3651
- binding: 0,
3638
+ binding: 2,
3652
3639
  visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
3653
- buffer: {
3654
- type: 'read-only-storage',
3655
- hasDynamicOffset: false
3656
- }
3640
+ buffer: { type: 'read-only-storage' }
3657
3641
  }
3658
3642
  ]
3659
3643
  });
3660
3644
 
3661
- $.bindGroupLayouts = [$._transformLayout, colorsLayout];
3645
+ $.bindGroupLayouts = [mainLayout];
3662
3646
 
3663
3647
  let uniformBuffer = Q5.device.createBuffer({
3664
3648
  size: 8, // Size of two floats
@@ -3688,7 +3672,6 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3688
3672
  Q5.device.queue.writeBuffer(uniformBuffer, 0, new Float32Array([$.canvas.hw, $.canvas.hh]));
3689
3673
 
3690
3674
  createMainView();
3691
-
3692
3675
  return c;
3693
3676
  };
3694
3677
 
@@ -3732,7 +3715,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3732
3715
  };
3733
3716
 
3734
3717
  $._stroke = 0;
3735
- $._fill = $._tint = 1;
3718
+ $._fill = $._tint = $._globalAlpha = 1;
3736
3719
  $._doFill = $._doStroke = true;
3737
3720
 
3738
3721
  $.fill = (r, g, b, a) => {
@@ -3749,6 +3732,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3749
3732
  addColor(r, g, b, a);
3750
3733
  $._tint = colorIndex;
3751
3734
  };
3735
+ $.opacity = (a) => ($._globalAlpha = a);
3752
3736
 
3753
3737
  $.noFill = () => ($._doFill = false);
3754
3738
  $.noStroke = () => ($._doStroke = false);
@@ -3762,6 +3746,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3762
3746
  transforms = new Float32Array(MAX_TRANSFORMS * MATRIX_SIZE),
3763
3747
  matrices = [],
3764
3748
  matricesIndexStack = [];
3749
+
3765
3750
  let matrix;
3766
3751
 
3767
3752
  // tracks if the matrix has been modified
@@ -3797,12 +3782,10 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3797
3782
  if (!a) return;
3798
3783
  if ($._angleMode) a *= $._DEGTORAD;
3799
3784
 
3800
- let cosR = Math.cos(a);
3801
- let sinR = Math.sin(a);
3802
-
3803
- let m = matrix;
3804
-
3805
- let m0 = m[0],
3785
+ let cosR = Math.cos(a),
3786
+ sinR = Math.sin(a),
3787
+ m = matrix,
3788
+ m0 = m[0],
3806
3789
  m1 = m[1],
3807
3790
  m4 = m[4],
3808
3791
  m5 = m[5];
@@ -3849,15 +3832,15 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3849
3832
  if (!ang) return;
3850
3833
  if ($._angleMode) ang *= $._DEGTORAD;
3851
3834
 
3852
- let tanAng = Math.tan(ang);
3853
-
3854
- let m0 = matrix[0],
3855
- m1 = matrix[1],
3856
- m4 = matrix[4],
3857
- m5 = matrix[5];
3835
+ let tanAng = Math.tan(ang),
3836
+ m = matrix,
3837
+ m0 = m[0],
3838
+ m1 = m[1],
3839
+ m4 = m[4],
3840
+ m5 = m[5];
3858
3841
 
3859
- matrix[0] = m0 + m4 * tanAng;
3860
- matrix[1] = m1 + m5 * tanAng;
3842
+ m[0] = m0 + m4 * tanAng;
3843
+ m[1] = m1 + m5 * tanAng;
3861
3844
 
3862
3845
  $._matrixDirty = true;
3863
3846
  };
@@ -3866,15 +3849,15 @@ Q5.renderers.webgpu.canvas = ($, q) => {
3866
3849
  if (!ang) return;
3867
3850
  if ($._angleMode) ang *= $._DEGTORAD;
3868
3851
 
3869
- let tanAng = Math.tan(ang);
3870
-
3871
- let m0 = matrix[0],
3872
- m1 = matrix[1],
3873
- m4 = matrix[4],
3874
- m5 = matrix[5];
3852
+ let tanAng = Math.tan(ang),
3853
+ m = matrix,
3854
+ m0 = m[0],
3855
+ m1 = m[1],
3856
+ m4 = m[4],
3857
+ m5 = m[5];
3875
3858
 
3876
- matrix[4] = m4 + m0 * tanAng;
3877
- matrix[5] = m5 + m1 * tanAng;
3859
+ m[4] = m4 + m0 * tanAng;
3860
+ m[5] = m5 + m1 * tanAng;
3878
3861
 
3879
3862
  $._matrixDirty = true;
3880
3863
  };
@@ -4042,26 +4025,14 @@ Q5.renderers.webgpu.canvas = ($, q) => {
4042
4025
  };
4043
4026
 
4044
4027
  $._render = () => {
4045
- if (matrices.length > 1 || !$._transformBindGroup) {
4046
- let transformBuffer = Q5.device.createBuffer({
4047
- size: matrices.length * MATRIX_SIZE * 4, // 4 bytes per float
4048
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
4049
- mappedAtCreation: true
4050
- });
4051
-
4052
- new Float32Array(transformBuffer.getMappedRange()).set(transforms.slice(0, matrices.length * MATRIX_SIZE));
4053
- transformBuffer.unmap();
4054
-
4055
- $._transformBindGroup = Q5.device.createBindGroup({
4056
- layout: $._transformLayout,
4057
- entries: [
4058
- { binding: 0, resource: { buffer: uniformBuffer } },
4059
- { binding: 1, resource: { buffer: transformBuffer } }
4060
- ]
4061
- });
4062
- }
4028
+ let transformBuffer = Q5.device.createBuffer({
4029
+ size: matrices.length * MATRIX_SIZE * 4, // 4 bytes per float
4030
+ usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
4031
+ mappedAtCreation: true
4032
+ });
4063
4033
 
4064
- pass.setBindGroup(0, $._transformBindGroup);
4034
+ new Float32Array(transformBuffer.getMappedRange()).set(transforms.slice(0, matrices.length * MATRIX_SIZE));
4035
+ transformBuffer.unmap();
4065
4036
 
4066
4037
  let colorsBuffer = Q5.device.createBuffer({
4067
4038
  size: colorStackIndex * 4,
@@ -4072,12 +4043,16 @@ Q5.renderers.webgpu.canvas = ($, q) => {
4072
4043
  new Float32Array(colorsBuffer.getMappedRange()).set(colorStack.slice(0, colorStackIndex));
4073
4044
  colorsBuffer.unmap();
4074
4045
 
4075
- $._colorsBindGroup = Q5.device.createBindGroup({
4076
- layout: colorsLayout,
4077
- entries: [{ binding: 0, resource: { buffer: colorsBuffer } }]
4046
+ mainBindGroup = Q5.device.createBindGroup({
4047
+ layout: mainLayout,
4048
+ entries: [
4049
+ { binding: 0, resource: { buffer: uniformBuffer } },
4050
+ { binding: 1, resource: { buffer: transformBuffer } },
4051
+ { binding: 2, resource: { buffer: colorsBuffer } }
4052
+ ]
4078
4053
  });
4079
4054
 
4080
- pass.setBindGroup(1, $._colorsBindGroup);
4055
+ pass.setBindGroup(0, mainBindGroup);
4081
4056
 
4082
4057
  for (let m of $._hooks.preRender) m();
4083
4058
 
@@ -4101,11 +4076,11 @@ Q5.renderers.webgpu.canvas = ($, q) => {
4101
4076
  pass.draw(v, 1, drawVertOffset);
4102
4077
  drawVertOffset += v;
4103
4078
  } else if (curPipelineIndex == 1) {
4104
- // let vertCount = drawStack[i + 2];
4079
+ // let instanceCount = drawStack[i + 2];
4105
4080
  // draw images
4106
4081
  if (curTextureIndex != v) {
4107
4082
  // v is the texture index
4108
- pass.setBindGroup(2, $._textureBindGroups[v]);
4083
+ pass.setBindGroup(1, $._textureBindGroups[v]);
4109
4084
  }
4110
4085
  pass.draw(4, 1, imageVertOffset);
4111
4086
  imageVertOffset += 4;
@@ -4113,8 +4088,8 @@ Q5.renderers.webgpu.canvas = ($, q) => {
4113
4088
  } else if (curPipelineIndex == 2) {
4114
4089
  // draw text
4115
4090
  let o = drawStack[i + 2];
4116
- pass.setBindGroup(2, $._fonts[o].bindGroup);
4117
- pass.setBindGroup(3, $._textBindGroup);
4091
+ pass.setBindGroup(1, $._fonts[o].bindGroup);
4092
+ pass.setBindGroup(2, $._textBindGroup);
4118
4093
 
4119
4094
  // v is the number of characters in the text
4120
4095
  pass.draw(4, v, 0, textCharOffset);
@@ -4173,46 +4148,40 @@ Q5.renderers.webgpu.drawing = ($, q) => {
4173
4148
  vertexStack = new Float32Array(1e7),
4174
4149
  vertIndex = 0;
4175
4150
 
4176
- let vertexShader = Q5.device.createShaderModule({
4177
- label: 'drawingVertexShader',
4151
+ let drawingShader = Q5.device.createShaderModule({
4152
+ label: 'drawingShader',
4178
4153
  code: `
4179
- struct VertexInput {
4154
+ struct Uniforms {
4155
+ halfWidth: f32,
4156
+ halfHeight: f32
4157
+ }
4158
+ struct VertexParams {
4180
4159
  @location(0) pos: vec2f,
4181
4160
  @location(1) colorIndex: f32,
4182
4161
  @location(2) matrixIndex: f32
4183
4162
  }
4184
- struct VertexOutput {
4163
+ struct FragmentParams {
4185
4164
  @builtin(position) position: vec4f,
4186
4165
  @location(0) color: vec4f
4187
4166
  }
4188
- struct Uniforms {
4189
- halfWidth: f32,
4190
- halfHeight: f32
4191
- }
4192
4167
 
4193
4168
  @group(0) @binding(0) var<uniform> uniforms: Uniforms;
4194
4169
  @group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;
4195
-
4196
- @group(1) @binding(0) var<storage> colors : array<vec4f>;
4170
+ @group(0) @binding(2) var<storage> colors : array<vec4f>;
4197
4171
 
4198
4172
  @vertex
4199
- fn vertexMain(input: VertexInput) -> VertexOutput {
4200
- var vert = vec4f(input.pos, 0.0, 1.0);
4201
- vert = transforms[i32(input.matrixIndex)] * vert;
4173
+ fn vertexMain(v: VertexParams) -> FragmentParams {
4174
+ var vert = vec4f(v.pos, 0.0, 1.0);
4175
+ vert = transforms[i32(v.matrixIndex)] * vert;
4202
4176
  vert.x /= uniforms.halfWidth;
4203
4177
  vert.y /= uniforms.halfHeight;
4204
4178
 
4205
- var output: VertexOutput;
4206
- output.position = vert;
4207
- output.color = colors[i32(input.colorIndex)];
4208
- return output;
4179
+ var f: FragmentParams;
4180
+ f.position = vert;
4181
+ f.color = colors[i32(v.colorIndex)];
4182
+ return f;
4209
4183
  }
4210
- `
4211
- });
4212
4184
 
4213
- let fragmentShader = Q5.device.createShaderModule({
4214
- label: 'drawingFragmentShader',
4215
- code: `
4216
4185
  @fragment
4217
4186
  fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
4218
4187
  return color;
@@ -4238,19 +4207,17 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
4238
4207
  label: 'drawingPipeline',
4239
4208
  layout: pipelineLayout,
4240
4209
  vertex: {
4241
- module: vertexShader,
4210
+ module: drawingShader,
4242
4211
  entryPoint: 'vertexMain',
4243
4212
  buffers: [vertexBufferLayout]
4244
4213
  },
4245
4214
  fragment: {
4246
- module: fragmentShader,
4215
+ module: drawingShader,
4247
4216
  entryPoint: 'fragmentMain',
4248
4217
  targets: [{ format: 'bgra8unorm', blend: $.blendConfigs.normal }]
4249
4218
  },
4250
4219
  primitive: { topology: 'triangle-strip', stripIndexFormat: 'uint32' },
4251
- multisample: {
4252
- count: 4
4253
- }
4220
+ multisample: { count: 4 }
4254
4221
  };
4255
4222
 
4256
4223
  $._pipelines[0] = Q5.device.createRenderPipeline($._pipelineConfigs[0]);
@@ -4686,63 +4653,66 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
4686
4653
  });
4687
4654
  };
4688
4655
  Q5.renderers.webgpu.image = ($, q) => {
4689
- $._textureBindGroups = [];
4690
4656
  let vertexStack = new Float32Array(1e7),
4691
4657
  vertIndex = 0;
4692
4658
 
4693
4659
  let imageShader = Q5.device.createShaderModule({
4694
4660
  label: 'imageShader',
4695
4661
  code: `
4696
- struct VertexInput {
4662
+ struct Uniforms {
4663
+ halfWidth: f32,
4664
+ halfHeight: f32
4665
+ }
4666
+ struct VertexParams {
4697
4667
  @location(0) pos: vec2f,
4698
4668
  @location(1) texCoord: vec2f,
4699
4669
  @location(2) tintIndex: f32,
4700
- @location(3) matrixIndex: f32
4670
+ @location(3) matrixIndex: f32,
4671
+ @location(4) globalAlpha: f32
4701
4672
  }
4702
- struct VertexOutput {
4673
+ struct FragmentParams {
4703
4674
  @builtin(position) position: vec4f,
4704
4675
  @location(0) texCoord: vec2f,
4705
- @location(1) tintIndex: f32
4706
- }
4707
- struct Uniforms {
4708
- halfWidth: f32,
4709
- halfHeight: f32
4676
+ @location(1) tintIndex: f32,
4677
+ @location(2) globalAlpha: f32
4710
4678
  }
4711
4679
 
4712
4680
  @group(0) @binding(0) var<uniform> uniforms: Uniforms;
4713
4681
  @group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;
4682
+ @group(0) @binding(2) var<storage> colors : array<vec4f>;
4714
4683
 
4715
- @group(1) @binding(0) var<storage> colors : array<vec4f>;
4716
-
4717
- @group(2) @binding(0) var samp: sampler;
4718
- @group(2) @binding(1) var texture: texture_2d<f32>;
4684
+ @group(1) @binding(0) var samp: sampler;
4685
+ @group(1) @binding(1) var texture: texture_2d<f32>;
4719
4686
 
4720
4687
  @vertex
4721
- fn vertexMain(input: VertexInput) -> VertexOutput {
4722
- var vert = vec4f(input.pos, 0.0, 1.0);
4723
- vert = transforms[i32(input.matrixIndex)] * vert;
4688
+ fn vertexMain(v: VertexParams) -> FragmentParams {
4689
+ var vert = vec4f(v.pos, 0.0, 1.0);
4690
+ vert = transforms[i32(v.matrixIndex)] * vert;
4724
4691
  vert.x /= uniforms.halfWidth;
4725
4692
  vert.y /= uniforms.halfHeight;
4726
4693
 
4727
- var output: VertexOutput;
4728
- output.position = vert;
4729
- output.texCoord = input.texCoord;
4730
- output.tintIndex = input.tintIndex;
4731
- return output;
4694
+ var f: FragmentParams;
4695
+ f.position = vert;
4696
+ f.texCoord = v.texCoord;
4697
+ f.tintIndex = v.tintIndex;
4698
+ f.globalAlpha = v.globalAlpha;
4699
+ return f;
4732
4700
  }
4733
4701
 
4734
4702
  @fragment
4735
- fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @location(0) vec4f {
4736
- let texColor = textureSample(texture, samp, texCoord);
4737
- let tintColor = colors[i32(tintIndex)];
4703
+ fn fragmentMain(f: FragmentParams) -> @location(0) vec4f {
4704
+ let texColor = textureSample(texture, samp, f.texCoord);
4705
+ let tintColor = colors[i32(f.tintIndex)];
4738
4706
 
4739
4707
  // Mix original and tinted colors using tint alpha as blend factor
4740
- let tinted = vec4f(texColor.rgb * tintColor.rgb, texColor.a);
4708
+ let tinted = vec4f(texColor.rgb * tintColor.rgb, texColor.a * f.globalAlpha);
4741
4709
  return mix(texColor, tinted, tintColor.a);
4742
4710
  }
4743
4711
  `
4744
4712
  });
4745
4713
 
4714
+ $._textureBindGroups = [];
4715
+
4746
4716
  let textureLayout = Q5.device.createBindGroupLayout({
4747
4717
  label: 'textureLayout',
4748
4718
  entries: [
@@ -4760,12 +4730,13 @@ fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @l
4760
4730
  });
4761
4731
 
4762
4732
  const vertexBufferLayout = {
4763
- arrayStride: 24,
4733
+ arrayStride: 28,
4764
4734
  attributes: [
4765
4735
  { shaderLocation: 0, offset: 0, format: 'float32x2' },
4766
4736
  { shaderLocation: 1, offset: 8, format: 'float32x2' },
4767
4737
  { shaderLocation: 2, offset: 16, format: 'float32' }, // tintIndex
4768
- { shaderLocation: 3, offset: 20, format: 'float32' } // matrixIndex
4738
+ { shaderLocation: 3, offset: 20, format: 'float32' }, // matrixIndex
4739
+ { shaderLocation: 4, offset: 24, format: 'float32' } // globalAlpha
4769
4740
  ]
4770
4741
  };
4771
4742
 
@@ -4871,7 +4842,7 @@ fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @l
4871
4842
 
4872
4843
  $.imageMode = (x) => ($._imageMode = x);
4873
4844
 
4874
- const addVert = (x, y, u, v, ci, ti) => {
4845
+ const addVert = (x, y, u, v, ci, ti, ga) => {
4875
4846
  let s = vertexStack,
4876
4847
  i = vertIndex;
4877
4848
  s[i++] = x;
@@ -4880,6 +4851,7 @@ fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @l
4880
4851
  s[i++] = v;
4881
4852
  s[i++] = ci;
4882
4853
  s[i++] = ti;
4854
+ s[i++] = ga;
4883
4855
  vertIndex = i;
4884
4856
  };
4885
4857
 
@@ -4890,16 +4862,15 @@ fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @l
4890
4862
 
4891
4863
  if ($._matrixDirty) $._saveMatrix();
4892
4864
 
4893
- let ti = $._matrixIndex,
4894
- w = img.width,
4895
- h = img.height;
4865
+ let w = img.width,
4866
+ h = img.height,
4867
+ pd = g._pixelDensity || 1;
4896
4868
 
4897
4869
  dw ??= g.defaultWidth;
4898
4870
  dh ??= g.defaultHeight;
4899
4871
  sw ??= w;
4900
4872
  sh ??= h;
4901
4873
 
4902
- let pd = g._pixelDensity || 1;
4903
4874
  dw *= pd;
4904
4875
  dh *= pd;
4905
4876
 
@@ -4908,14 +4879,15 @@ fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @l
4908
4879
  let u0 = sx / w,
4909
4880
  v0 = sy / h,
4910
4881
  u1 = (sx + sw) / w,
4911
- v1 = (sy + sh) / h;
4882
+ v1 = (sy + sh) / h,
4883
+ ti = $._matrixIndex,
4884
+ ci = $._tint,
4885
+ ga = $._globalAlpha;
4912
4886
 
4913
- let ci = $._tint;
4914
-
4915
- addVert(l, t, u0, v0, ci, ti);
4916
- addVert(r, t, u1, v0, ci, ti);
4917
- addVert(l, b, u0, v1, ci, ti);
4918
- addVert(r, b, u1, v1, ci, ti);
4887
+ addVert(l, t, u0, v0, ci, ti, ga);
4888
+ addVert(r, t, u1, v0, ci, ti, ga);
4889
+ addVert(l, b, u0, v1, ci, ti, ga);
4890
+ addVert(r, b, u1, v1, ci, ti, ga);
4919
4891
 
4920
4892
  $.drawStack.push(1, img.textureIndex);
4921
4893
  };
@@ -4927,7 +4899,7 @@ fn fragmentMain(@location(0) texCoord: vec2f, @location(1) tintIndex: f32) -> @l
4927
4899
  $.pass.setPipeline($._pipelines[1]);
4928
4900
 
4929
4901
  let vertexBuffer = Q5.device.createBuffer({
4930
- size: vertIndex * 4,
4902
+ size: vertIndex * 5,
4931
4903
  usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
4932
4904
  mappedAtCreation: true
4933
4905
  });
@@ -4955,14 +4927,15 @@ Q5.renderers.webgpu.text = ($, q) => {
4955
4927
  let textShader = Q5.device.createShaderModule({
4956
4928
  label: 'MSDF text shader',
4957
4929
  code: `
4958
- // Positions for simple quad geometry
4959
- const pos = array(vec2f(0, -1), vec2f(1, -1), vec2f(0, 0), vec2f(1, 0));
4960
-
4961
- struct VertexInput {
4930
+ struct Uniforms {
4931
+ halfWidth: f32,
4932
+ halfHeight: f32
4933
+ }
4934
+ struct VertexParams {
4962
4935
  @builtin(vertex_index) vertex : u32,
4963
4936
  @builtin(instance_index) instance : u32
4964
4937
  }
4965
- struct VertexOutput {
4938
+ struct FragmentParams {
4966
4939
  @builtin(position) position : vec4f,
4967
4940
  @location(0) texCoord : vec2f,
4968
4941
  @location(1) fillColor : vec4f
@@ -4980,43 +4953,40 @@ struct Text {
4980
4953
  fillIndex: f32,
4981
4954
  strokeIndex: f32
4982
4955
  }
4983
- struct Uniforms {
4984
- halfWidth: f32,
4985
- halfHeight: f32
4986
- }
4987
4956
 
4988
4957
  @group(0) @binding(0) var<uniform> uniforms: Uniforms;
4989
4958
  @group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;
4959
+ @group(0) @binding(2) var<storage> colors : array<vec4f>;
4990
4960
 
4991
- @group(1) @binding(0) var<storage> colors : array<vec4f>;
4961
+ @group(1) @binding(0) var fontTexture: texture_2d<f32>;
4962
+ @group(1) @binding(1) var fontSampler: sampler;
4963
+ @group(1) @binding(2) var<storage> fontChars: array<Char>;
4992
4964
 
4993
- @group(2) @binding(0) var fontTexture: texture_2d<f32>;
4994
- @group(2) @binding(1) var fontSampler: sampler;
4995
- @group(2) @binding(2) var<storage> fontChars: array<Char>;
4965
+ @group(2) @binding(0) var<storage> textChars: array<vec4f>;
4966
+ @group(2) @binding(1) var<storage> textMetadata: array<Text>;
4996
4967
 
4997
- @group(3) @binding(0) var<storage> textChars: array<vec4f>;
4998
- @group(3) @binding(1) var<storage> textMetadata: array<Text>;
4968
+ const quad = array(vec2f(0, -1), vec2f(1, -1), vec2f(0, 0), vec2f(1, 0));
4999
4969
 
5000
4970
  @vertex
5001
- fn vertexMain(input : VertexInput) -> VertexOutput {
5002
- let char = textChars[input.instance];
4971
+ fn vertexMain(v : VertexParams) -> FragmentParams {
4972
+ let char = textChars[v.instance];
5003
4973
 
5004
4974
  let text = textMetadata[i32(char.w)];
5005
4975
 
5006
4976
  let fontChar = fontChars[i32(char.z)];
5007
4977
 
5008
- let charPos = ((pos[input.vertex] * fontChar.size + char.xy + fontChar.offset) * text.scale) + text.pos;
4978
+ let charPos = ((quad[v.vertex] * fontChar.size + char.xy + fontChar.offset) * text.scale) + text.pos;
5009
4979
 
5010
4980
  var vert = vec4f(charPos, 0.0, 1.0);
5011
4981
  vert = transforms[i32(text.matrixIndex)] * vert;
5012
4982
  vert.x /= uniforms.halfWidth;
5013
4983
  vert.y /= uniforms.halfHeight;
5014
4984
 
5015
- var output : VertexOutput;
5016
- output.position = vert;
5017
- output.texCoord = (pos[input.vertex] * vec2f(1, -1)) * fontChar.texExtent + fontChar.texOffset;
5018
- output.fillColor = colors[i32(text.fillIndex)];
5019
- return output;
4985
+ var f : FragmentParams;
4986
+ f.position = vert;
4987
+ f.texCoord = (quad[v.vertex] * vec2f(1, -1)) * fontChar.texExtent + fontChar.texOffset;
4988
+ f.fillColor = colors[i32(text.fillIndex)];
4989
+ return f;
5020
4990
  }
5021
4991
 
5022
4992
  fn sampleMsdf(texCoord: vec2f) -> f32 {
@@ -5025,22 +4995,22 @@ fn sampleMsdf(texCoord: vec2f) -> f32 {
5025
4995
  }
5026
4996
 
5027
4997
  @fragment
5028
- fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
4998
+ fn fragmentMain(f : FragmentParams) -> @location(0) vec4f {
5029
4999
  // pxRange (AKA distanceRange) comes from the msdfgen tool,
5030
5000
  // uses the default which is 4.
5031
5001
  let pxRange = 4.0;
5032
5002
  let sz = vec2f(textureDimensions(fontTexture, 0));
5033
- let dx = sz.x*length(vec2f(dpdxFine(input.texCoord.x), dpdyFine(input.texCoord.x)));
5034
- let dy = sz.y*length(vec2f(dpdxFine(input.texCoord.y), dpdyFine(input.texCoord.y)));
5003
+ let dx = sz.x*length(vec2f(dpdxFine(f.texCoord.x), dpdyFine(f.texCoord.x)));
5004
+ let dy = sz.y*length(vec2f(dpdxFine(f.texCoord.y), dpdyFine(f.texCoord.y)));
5035
5005
  let toPixels = pxRange * inverseSqrt(dx * dx + dy * dy);
5036
- let sigDist = sampleMsdf(input.texCoord) - 0.5;
5006
+ let sigDist = sampleMsdf(f.texCoord) - 0.5;
5037
5007
  let pxDist = sigDist * toPixels;
5038
5008
  let edgeWidth = 0.5;
5039
5009
  let alpha = smoothstep(-edgeWidth, edgeWidth, pxDist);
5040
5010
  if (alpha < 0.001) {
5041
5011
  discard;
5042
5012
  }
5043
- return vec4f(input.fillColor.rgb, input.fillColor.a * alpha);
5013
+ return vec4f(f.fillColor.rgb, f.fillColor.a * alpha);
5044
5014
  }
5045
5015
  `
5046
5016
  });