q5 2.5.4 → 2.6.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.
@@ -1,6 +1,6 @@
1
1
  Q5.renderers.webgpu.image = ($, q) => {
2
2
  $._textureBindGroups = [];
3
- let verticesStack = [];
3
+ let vertexStack = [];
4
4
 
5
5
  let vertexShader = Q5.device.createShaderModule({
6
6
  label: 'imageVertexShader',
@@ -8,15 +8,14 @@ Q5.renderers.webgpu.image = ($, q) => {
8
8
  struct VertexOutput {
9
9
  @builtin(position) position: vec4f,
10
10
  @location(0) texCoord: vec2f
11
- };
12
-
11
+ }
13
12
  struct Uniforms {
14
13
  halfWidth: f32,
15
14
  halfHeight: f32
16
- };
15
+ }
17
16
 
18
17
  @group(0) @binding(0) var<uniform> uniforms: Uniforms;
19
- @group(0) @binding(1) var<storage, read> transforms: array<mat4x4<f32>>;
18
+ @group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;
20
19
 
21
20
  @vertex
22
21
  fn vertexMain(@location(0) pos: vec2f, @location(1) texCoord: vec2f, @location(2) transformIndex: f32) -> VertexOutput {
@@ -77,7 +76,7 @@ fn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {
77
76
  bindGroupLayouts: [...$.bindGroupLayouts, textureLayout]
78
77
  });
79
78
 
80
- $.pipelines[1] = Q5.device.createRenderPipeline({
79
+ $._pipelineConfigs[1] = {
81
80
  label: 'imagePipeline',
82
81
  layout: pipelineLayout,
83
82
  vertex: {
@@ -88,28 +87,12 @@ fn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {
88
87
  fragment: {
89
88
  module: fragmentShader,
90
89
  entryPoint: 'fragmentMain',
91
- targets: [
92
- {
93
- format: 'bgra8unorm',
94
- blend: $.blendConfigs?.normal || {
95
- color: {
96
- srcFactor: 'src-alpha',
97
- dstFactor: 'one-minus-src-alpha',
98
- operation: 'add'
99
- },
100
- alpha: {
101
- srcFactor: 'src-alpha',
102
- dstFactor: 'one-minus-src-alpha',
103
- operation: 'add'
104
- }
105
- }
106
- }
107
- ]
90
+ targets: [{ format: 'bgra8unorm', blend: $.blendConfigs.normal }]
108
91
  },
109
- primitive: {
110
- topology: 'triangle-list'
111
- }
112
- });
92
+ primitive: { topology: 'triangle-list' }
93
+ };
94
+
95
+ $._pipelines[1] = Q5.device.createRenderPipeline($._pipelineConfigs[1]);
113
96
 
114
97
  let sampler = Q5.device.createSampler({
115
98
  magFilter: 'linear',
@@ -134,7 +117,11 @@ fn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {
134
117
 
135
118
  Q5.device.queue.copyExternalImageToTexture(
136
119
  { source: img },
137
- { texture, colorSpace: $.canvas.colorSpace },
120
+ {
121
+ texture,
122
+ colorSpace: $.canvas.colorSpace
123
+ // premultipliedAlpha: true
124
+ },
138
125
  textureSize
139
126
  );
140
127
 
@@ -187,7 +174,7 @@ fn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {
187
174
  let [l, r, t, b] = $._calcBox(x, y, w, h, $._imageMode);
188
175
 
189
176
  // prettier-ignore
190
- verticesStack.push(
177
+ vertexStack.push(
191
178
  l, t, 0, 0, ti,
192
179
  r, t, 1, 0, ti,
193
180
  l, b, 0, 1, ti,
@@ -196,29 +183,29 @@ fn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {
196
183
  r, b, 1, 1, ti
197
184
  );
198
185
 
199
- $.drawStack.push(1, img.textureIndex);
186
+ $.drawStack.push(1, img.textureIndex, 0);
200
187
  };
201
188
 
202
189
  $._hooks.preRender.push(() => {
203
190
  if (!$._textureBindGroups.length) return;
204
191
 
205
192
  // Switch to image pipeline
206
- $.pass.setPipeline($.pipelines[1]);
207
-
208
- // Create a vertex buffer for the image quads
209
- const vertices = new Float32Array(verticesStack);
193
+ $.pass.setPipeline($._pipelines[1]);
210
194
 
211
195
  const vertexBuffer = Q5.device.createBuffer({
212
- size: vertices.byteLength,
213
- usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
196
+ size: vertexStack.length * 4,
197
+ usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
198
+ mappedAtCreation: true
214
199
  });
215
200
 
216
- Q5.device.queue.writeBuffer(vertexBuffer, 0, vertices);
201
+ new Float32Array(vertexBuffer.getMappedRange()).set(vertices);
202
+ vertexBuffer.unmap();
203
+
217
204
  $.pass.setVertexBuffer(1, vertexBuffer);
218
205
  });
219
206
 
220
207
  $._hooks.postRender.push(() => {
221
- verticesStack.length = 0;
208
+ vertexStack.length = 0;
222
209
  });
223
210
  };
224
211
 
@@ -7,35 +7,35 @@ const pos = array(vec2f(0, -1), vec2f(1, -1), vec2f(0, 0), vec2f(1, 0));
7
7
 
8
8
  struct VertexInput {
9
9
  @builtin(vertex_index) vertex : u32,
10
- @builtin(instance_index) instance : u32,
11
- };
10
+ @builtin(instance_index) instance : u32
11
+ }
12
12
  struct VertexOutput {
13
13
  @builtin(position) position : vec4f,
14
- @location(0) texcoord : vec2f,
15
- @location(1) colorIndex : f32
16
- };
14
+ @location(0) texCoord : vec2f,
15
+ @location(1) fillColor : vec4f
16
+ }
17
17
  struct Char {
18
18
  texOffset: vec2f,
19
19
  texExtent: vec2f,
20
20
  size: vec2f,
21
21
  offset: vec2f,
22
- };
22
+ }
23
23
  struct Text {
24
24
  pos: vec2f,
25
25
  scale: f32,
26
26
  transformIndex: f32,
27
27
  fillIndex: f32,
28
28
  strokeIndex: f32
29
- };
29
+ }
30
30
  struct Uniforms {
31
31
  halfWidth: f32,
32
32
  halfHeight: f32
33
- };
33
+ }
34
34
 
35
35
  @group(0) @binding(0) var<uniform> uniforms: Uniforms;
36
- @group(0) @binding(1) var<storage, read> transforms: array<mat4x4<f32>>;
36
+ @group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;
37
37
 
38
- @group(1) @binding(0) var<storage, read> colors : array<vec4f>;
38
+ @group(1) @binding(0) var<storage> colors : array<vec4f>;
39
39
 
40
40
  @group(2) @binding(0) var fontTexture: texture_2d<f32>;
41
41
  @group(2) @binding(1) var fontSampler: sampler;
@@ -61,13 +61,13 @@ fn vertexMain(input : VertexInput) -> VertexOutput {
61
61
 
62
62
  var output : VertexOutput;
63
63
  output.position = vert;
64
- output.texcoord = (pos[input.vertex] * vec2f(1, -1)) * fontChar.texExtent + fontChar.texOffset;
65
- output.colorIndex = text.fillIndex;
64
+ output.texCoord = (pos[input.vertex] * vec2f(1, -1)) * fontChar.texExtent + fontChar.texOffset;
65
+ output.fillColor = colors[i32(text.fillIndex)];
66
66
  return output;
67
67
  }
68
68
 
69
- fn sampleMsdf(texcoord: vec2f) -> f32 {
70
- let c = textureSample(fontTexture, fontSampler, texcoord);
69
+ fn sampleMsdf(texCoord: vec2f) -> f32 {
70
+ let c = textureSample(fontTexture, fontSampler, texCoord);
71
71
  return max(min(c.r, c.g), min(max(c.r, c.g), c.b));
72
72
  }
73
73
 
@@ -77,25 +77,83 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
77
77
  // uses the default which is 4.
78
78
  let pxRange = 4.0;
79
79
  let sz = vec2f(textureDimensions(fontTexture, 0));
80
- let dx = sz.x*length(vec2f(dpdxFine(input.texcoord.x), dpdyFine(input.texcoord.x)));
81
- let dy = sz.y*length(vec2f(dpdxFine(input.texcoord.y), dpdyFine(input.texcoord.y)));
80
+ let dx = sz.x*length(vec2f(dpdxFine(input.texCoord.x), dpdyFine(input.texCoord.x)));
81
+ let dy = sz.y*length(vec2f(dpdxFine(input.texCoord.y), dpdyFine(input.texCoord.y)));
82
82
  let toPixels = pxRange * inverseSqrt(dx * dx + dy * dy);
83
- let sigDist = sampleMsdf(input.texcoord) - 0.5;
83
+ let sigDist = sampleMsdf(input.texCoord) - 0.5;
84
84
  let pxDist = sigDist * toPixels;
85
85
  let edgeWidth = 0.5;
86
86
  let alpha = smoothstep(-edgeWidth, edgeWidth, pxDist);
87
87
  if (alpha < 0.001) {
88
88
  discard;
89
89
  }
90
- let fillColor = colors[i32(input.colorIndex)];
91
- return vec4f(fillColor.rgb, fillColor.a * alpha);
90
+ return vec4f(input.fillColor.rgb, input.fillColor.a * alpha);
92
91
  }
93
92
  `
94
93
  });
95
94
 
95
+ let textBindGroupLayout = Q5.device.createBindGroupLayout({
96
+ label: 'MSDF text group layout',
97
+ entries: [
98
+ {
99
+ binding: 0,
100
+ visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
101
+ buffer: { type: 'read-only-storage' }
102
+ },
103
+ {
104
+ binding: 1,
105
+ visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
106
+ buffer: { type: 'read-only-storage' }
107
+ }
108
+ ]
109
+ });
110
+
111
+ let fontSampler = Q5.device.createSampler({
112
+ minFilter: 'linear',
113
+ magFilter: 'linear',
114
+ mipmapFilter: 'linear',
115
+ maxAnisotropy: 16
116
+ });
117
+ let fontBindGroupLayout = Q5.device.createBindGroupLayout({
118
+ label: 'MSDF font group layout',
119
+ entries: [
120
+ {
121
+ binding: 0,
122
+ visibility: GPUShaderStage.FRAGMENT,
123
+ texture: {}
124
+ },
125
+ {
126
+ binding: 1,
127
+ visibility: GPUShaderStage.FRAGMENT,
128
+ sampler: {}
129
+ },
130
+ {
131
+ binding: 2,
132
+ visibility: GPUShaderStage.VERTEX,
133
+ buffer: { type: 'read-only-storage' }
134
+ }
135
+ ]
136
+ });
137
+
138
+ let fontPipelineLayout = Q5.device.createPipelineLayout({
139
+ bindGroupLayouts: [...$.bindGroupLayouts, fontBindGroupLayout, textBindGroupLayout]
140
+ });
141
+
142
+ $._pipelineConfigs[2] = {
143
+ label: 'msdf font pipeline',
144
+ layout: fontPipelineLayout,
145
+ vertex: { module: textShader, entryPoint: 'vertexMain' },
146
+ fragment: {
147
+ module: textShader,
148
+ entryPoint: 'fragmentMain',
149
+ targets: [{ format: 'bgra8unorm', blend: $.blendConfigs.normal }]
150
+ },
151
+ primitive: { topology: 'triangle-strip', stripIndexFormat: 'uint32' }
152
+ };
153
+ $._pipelines[2] = Q5.device.createRenderPipeline($._pipelineConfigs[2]);
154
+
96
155
  class MsdfFont {
97
- constructor(pipeline, bindGroup, lineHeight, chars, kernings) {
98
- this.pipeline = pipeline;
156
+ constructor(bindGroup, lineHeight, chars, kernings) {
99
157
  this.bindGroup = bindGroup;
100
158
  this.lineHeight = lineHeight;
101
159
  this.chars = chars;
@@ -121,22 +179,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
121
179
  }
122
180
  }
123
181
 
124
- let textBindGroupLayout = Q5.device.createBindGroupLayout({
125
- label: 'MSDF text group layout',
126
- entries: [
127
- {
128
- binding: 0,
129
- visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
130
- buffer: { type: 'read-only-storage' }
131
- },
132
- {
133
- binding: 1,
134
- visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
135
- buffer: { type: 'read-only-storage' }
136
- }
137
- ]
138
- });
139
-
182
+ $._fonts = [];
140
183
  let fonts = {};
141
184
 
142
185
  let createFont = async (fontJsonUrl, fontName, cb) => {
@@ -199,74 +242,11 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
199
242
  }
200
243
  charsBuffer.unmap();
201
244
 
202
- let fontSampler = Q5.device.createSampler({
203
- minFilter: 'linear',
204
- magFilter: 'linear',
205
- mipmapFilter: 'linear',
206
- maxAnisotropy: 16
207
- });
208
- let fontBindGroupLayout = Q5.device.createBindGroupLayout({
209
- label: 'MSDF font group layout',
210
- entries: [
211
- {
212
- binding: 0,
213
- visibility: GPUShaderStage.FRAGMENT,
214
- texture: {}
215
- },
216
- {
217
- binding: 1,
218
- visibility: GPUShaderStage.FRAGMENT,
219
- sampler: {}
220
- },
221
- {
222
- binding: 2,
223
- visibility: GPUShaderStage.VERTEX,
224
- buffer: { type: 'read-only-storage' }
225
- }
226
- ]
227
- });
228
- let fontPipeline = Q5.device.createRenderPipeline({
229
- label: 'msdf font pipeline',
230
- layout: Q5.device.createPipelineLayout({
231
- bindGroupLayouts: [...$.bindGroupLayouts, fontBindGroupLayout, textBindGroupLayout]
232
- }),
233
- vertex: {
234
- module: textShader,
235
- entryPoint: 'vertexMain'
236
- },
237
- fragment: {
238
- module: textShader,
239
- entryPoint: 'fragmentMain',
240
- targets: [
241
- {
242
- format: 'bgra8unorm',
243
- blend: {
244
- color: {
245
- srcFactor: 'src-alpha',
246
- dstFactor: 'one-minus-src-alpha'
247
- },
248
- alpha: {
249
- srcFactor: 'one',
250
- dstFactor: 'one'
251
- }
252
- }
253
- }
254
- ]
255
- },
256
- primitive: {
257
- topology: 'triangle-strip',
258
- stripIndexFormat: 'uint32'
259
- }
260
- });
261
-
262
245
  let fontBindGroup = Q5.device.createBindGroup({
263
246
  label: 'msdf font bind group',
264
247
  layout: fontBindGroupLayout,
265
248
  entries: [
266
- {
267
- binding: 0,
268
- resource: texture.createView()
269
- },
249
+ { binding: 0, resource: texture.createView() },
270
250
  { binding: 1, resource: fontSampler },
271
251
  { binding: 2, resource: { buffer: charsBuffer } }
272
252
  ]
@@ -284,10 +264,11 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
284
264
  }
285
265
  }
286
266
 
287
- $._font = new MsdfFont(fontPipeline, fontBindGroup, atlas.common.lineHeight, chars, kernings);
267
+ $._font = new MsdfFont(fontBindGroup, atlas.common.lineHeight, chars, kernings);
288
268
 
269
+ $._font.index = $._fonts.length;
270
+ $._fonts.push($._font);
289
271
  fonts[fontName] = $._font;
290
- $.pipelines[2] = $._font.pipeline;
291
272
 
292
273
  q._preloadCount--;
293
274
 
@@ -316,12 +297,6 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
316
297
 
317
298
  $.textFont = (fontName) => {
318
299
  $._font = fonts[fontName];
319
-
320
- // replay the change of font in the draw stack
321
- $.drawStack.push(-1, () => {
322
- $._font = fonts[fontName];
323
- $.pipelines[2] = $._font.pipeline;
324
- });
325
300
  };
326
301
  $.textSize = (size) => {
327
302
  $._textSize = size;
@@ -434,7 +409,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
434
409
  }
435
410
  }
436
411
 
437
- let charsData = new Float32Array((str.length - spaces) * 4);
412
+ let charsData = [];
438
413
 
439
414
  let ta = $._textAlign,
440
415
  tb = $._textBaseline,
@@ -480,7 +455,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
480
455
  }
481
456
  $._charStack.push(charsData);
482
457
 
483
- let text = new Float32Array(6);
458
+ let text = [];
484
459
 
485
460
  if ($._matrixDirty) $._saveMatrix();
486
461
 
@@ -488,11 +463,11 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
488
463
  text[1] = -y;
489
464
  text[2] = $._textSize / 44;
490
465
  text[3] = $._transformIndex;
491
- text[4] = $._fillIndex;
466
+ text[4] = $._fillSet ? $._fillIndex : 0;
492
467
  text[5] = $._strokeIndex;
493
468
 
494
469
  $._textStack.push(text);
495
- $.drawStack.push(2, measurements.printedCharCount);
470
+ $.drawStack.push(2, measurements.printedCharCount, $._font.index);
496
471
  };
497
472
 
498
473
  $.textWidth = (str) => {
@@ -505,11 +480,11 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
505
480
 
506
481
  if ($._doFill) {
507
482
  let fi = $._fillIndex * 4;
508
- g.fill(colorsStack.slice(fi, fi + 4));
483
+ g.fill(colorStack.slice(fi, fi + 4));
509
484
  }
510
485
  if ($._doStroke) {
511
486
  let si = $._strokeIndex * 4;
512
- g.stroke(colorsStack.slice(si, si + 4));
487
+ g.stroke(colorStack.slice(si, si + 4));
513
488
  }
514
489
 
515
490
  let img = g.createTextImage(str, w, h);
@@ -560,21 +535,15 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
560
535
  totalTextSize += charsData.length * 4;
561
536
  }
562
537
 
563
- // Create a single buffer for all text data
538
+ // Create a single buffer for all char data
564
539
  let charBuffer = Q5.device.createBuffer({
565
- label: 'charBuffer',
566
540
  size: totalTextSize,
567
541
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
568
542
  mappedAtCreation: true
569
543
  });
570
544
 
571
545
  // Copy all text data into the buffer
572
- let textArray = new Float32Array(charBuffer.getMappedRange());
573
- let o = 0;
574
- for (let array of $._charStack) {
575
- textArray.set(array, o);
576
- o += array.length;
577
- }
546
+ new Float32Array(charBuffer.getMappedRange()).set($._charStack.flat());
578
547
  charBuffer.unmap();
579
548
 
580
549
  // Calculate total buffer size for metadata
@@ -589,12 +558,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
589
558
  });
590
559
 
591
560
  // Copy all metadata into the buffer
592
- let metadataArray = new Float32Array(textBuffer.getMappedRange());
593
- o = 0;
594
- for (let array of $._textStack) {
595
- metadataArray.set(array, o);
596
- o += array.length;
597
- }
561
+ new Float32Array(textBuffer.getMappedRange()).set($._textStack.flat());
598
562
  textBuffer.unmap();
599
563
 
600
564
  // Create a single bind group for the text buffer and metadata buffer
@@ -602,14 +566,8 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
602
566
  label: 'msdf text bind group',
603
567
  layout: textBindGroupLayout,
604
568
  entries: [
605
- {
606
- binding: 0,
607
- resource: { buffer: charBuffer }
608
- },
609
- {
610
- binding: 1,
611
- resource: { buffer: textBuffer }
612
- }
569
+ { binding: 0, resource: { buffer: charBuffer } },
570
+ { binding: 1, resource: { buffer: textBuffer } }
613
571
  ]
614
572
  });
615
573
  });
package/src/readme.md CHANGED
@@ -1,6 +1,6 @@
1
- # Modular Use
1
+ # q5.js Source Documentation
2
2
 
3
- To use q5 modules, "q5.js" (the default bundle) or the "q5-core.js" module must be loaded first!
3
+ For modular use, the "q5-core.js" module must be loaded first.
4
4
 
5
5
  ```html
6
6
  <script src="https://q5js.org/src/q5-core.js"></script>
@@ -9,6 +9,7 @@ To use q5 modules, "q5.js" (the default bundle) or the "q5-core.js" module must
9
9
  These modules are included in the default "q5.js" bundle:
10
10
 
11
11
  ```html
12
+ <script src="https://q5js.org/src/q5-core.js"></script>
12
13
  <script src="https://q5js.org/src/q5-2d-canvas.js"></script>
13
14
  <script src="https://q5js.org/src/q5-2d-drawing.js"></script>
14
15
  <script src="https://q5js.org/src/q5-2d-image.js"></script>
@@ -37,19 +38,21 @@ WebGPU rendering modules are in development:
37
38
  ```html
38
39
  <script src="https://q5js.org/src/q5-webgpu-canvas.js"></script>
39
40
  <script src="https://q5js.org/src/q5-webgpu-drawing.js"></script>
41
+ <script src="https://q5js.org/src/q5-webgpu-image.js"></script>
42
+ <script src="https://q5js.org/src/q5-webgpu-text.js"></script>
40
43
  ```
41
44
 
42
45
  # Module Info
43
46
 
44
- - [Modular Use](#modular-use)
47
+ - [q5.js Source Documentation](#q5js-source-documentation)
45
48
  - [Module Info](#module-info)
46
- - [core](#core)
47
- - [canvas](#canvas)
49
+ - [q5-core](#q5-core)
50
+ - [q5-canvas](#q5-canvas)
48
51
  - [q2d-canvas](#q2d-canvas)
49
- - [q2d-drawing](#q2d-drawing)
50
- - [q2d-image](#q2d-image)
51
- - [q2d-soft-filters](#q2d-soft-filters)
52
- - [q2d-text](#q2d-text)
52
+ - [q5-q2d-drawing](#q5-q2d-drawing)
53
+ - [q5-q2d-image](#q5-q2d-image)
54
+ - [q5-q2d-soft-filters](#q5-q2d-soft-filters)
55
+ - [q5-q2d-text](#q5-q2d-text)
53
56
  - [webgpu-canvas](#webgpu-canvas)
54
57
  - [webgpu-drawing](#webgpu-drawing)
55
58
  - [webgpu-image](#webgpu-image)
@@ -59,19 +62,19 @@ WebGPU rendering modules are in development:
59
62
  - [Load a MSDF font](#load-a-msdf-font)
60
63
  - [Displaying Emojis](#displaying-emojis)
61
64
  - [Lightweight Use](#lightweight-use)
62
- - [Implemented functions](#implemented-functions)
65
+ - [Limitations](#limitations)
63
66
  - [math](#math)
64
67
  - [noisier](#noisier)
65
68
 
66
- ## core
69
+ ## q5-core
67
70
 
68
71
  The core module provides the absolute basic functionality necessary to run q5.
69
72
 
70
73
  It loads other modules by passing `$` (alias for `this`) and `q` (which in global mode is a proxy for `this` and `window` or `global`).
71
74
 
72
- ## canvas
75
+ ## q5-canvas
73
76
 
74
- The canvas module provides shared functionality for all canvas renderers, such as adding the canvas to the DOM, resizing the canvas, setting pixel density,
77
+ The canvas module provides shared functionality for all canvas renderers, such as adding the canvas to the DOM, resizing the canvas, setting pixel density.
75
78
 
76
79
  ## q2d-canvas
77
80
 
@@ -81,17 +84,17 @@ All other 2D modules depend on this module.
81
84
 
82
85
  Though loading q5-color is recommend, it's not required since `fill` and `stroke` can be set to a CSS color string.
83
86
 
84
- ## q2d-drawing
87
+ ## q5-q2d-drawing
85
88
 
86
89
  Adds Canvas2D drawing functions to q5.
87
90
 
88
- ## q2d-image
91
+ ## q5-q2d-image
89
92
 
90
93
  Adds Canvas2D image support to q5.
91
94
 
92
95
  The filters in q5-image use the [CanvasRenderingContext2D.filter](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/filter) property to apply native hardware-accelerated filters to images.
93
96
 
94
- ## q2d-soft-filters
97
+ ## q5-q2d-soft-filters
95
98
 
96
99
  Software implementation of image filters.
97
100
 
@@ -101,23 +104,17 @@ These filters are slow. Real-time use of them is not recommended.
101
104
 
102
105
  As of April 2024, Safari Technology Preview supports `ctx.filter` under a flag. Hopefully in the near future this module can be omitted from the default bundle.
103
106
 
104
- ## q2d-text
107
+ ## q5-q2d-text
105
108
 
106
109
  Adds Canvas2D text rendering support to q5.
107
110
 
108
111
  Image based features in this module require the q5-2d-image module.
109
112
 
110
- `createTextImage(str, w, h)` provides a simple way for users to create images from text.
111
-
112
- `textImage(img, x, y)` displays text images, complying with the user's text position settings instead of their image position settings. The idea is that text will appear in the same place as it would if it were drawn with the `text` function.
113
-
114
- `textCache(bool, maxSize)` enables or disables text caching.
115
-
116
113
  ## webgpu-canvas
117
114
 
118
115
  > ⚠️ Experimental features! ⚠️
119
116
 
120
- To use q5's WebGPU renderer, run `Q5.webgpu()` at the bottom of your sketch. Explicit use of `createCanvas` is required.
117
+ To use q5's WebGPU renderer, run `Q5.webgpu()` at the bottom of your sketch.
121
118
 
122
119
  ```js
123
120
  function setup() {
@@ -135,53 +132,24 @@ Q5.webgpu();
135
132
 
136
133
  WebGPU has different default settings compared to q5's q2d renderer and p5's P2D and WEBGL modes.
137
134
 
135
+ - Explicit use of `createCanvas` is required before anything can be drawn.
138
136
  - The default color mode is RGB in 0-1 "float" format: `colorMode(RGB, 1)`.
139
137
  - The origin of the canvas (0, 0) is in the center, not the top left.
140
- - Mouse and touch coordinates correspond to canvas pixels.
141
- - Use `textFill` and `textStroke` to set text colors.
142
- - For now, strokes are only implemented for the `point`, `line`, and `text` functions.
138
+ - Mouse and touch coordinates correspond to canvas pixels (unlike in p5 WEBGL mode).
143
139
 
144
140
  The sketches you create with the q5-webgpu renderer will still display properly if WebGPU is not supported on a viewer's browser. q5 will put a warning in the console and apply a compatibility layer to display sketches with the fallback q2d renderer.
145
141
 
146
- Use of top level global mode with the WebGPU renderer requires that you make your sketch file a js module and await for `Q5.webgpu()` to return the Q5 instance (`q`), which you can then use to set q5 functions such as `draw`.
147
-
148
- ```html
149
- <script type="module" src="sketch.js">
150
- ```
151
-
152
- ```js
153
- let q = await Q5.webgpu();
154
-
155
- createCanvas(200, 200);
156
- noStroke();
157
-
158
- q.draw = () => {
159
- clear();
160
- rect(50, 50, 100, 100);
161
- };
162
- ```
163
-
164
- Implemented functions:
165
-
166
- `createCanvas`, `resizeCanvas`, `fill`, `clear`, `push`, `pop`, `resetMatrix`, `translate`, `rotate`, `scale`
167
-
168
142
  ## webgpu-drawing
169
143
 
170
144
  > Uses `colorMode(RGB, 1)` by default. Changing it to 'oklch' is not supported yet for the webgpu renderer.
171
145
 
172
- All basic shapes are drawn from their center. Strokes are not implemented yet.
173
-
174
146
  q5's WebGPU renderer drawing functions like `rect` don't immediately draw on the canvas. Instead, they prepare vertex and color data to be sent to the GPU in bulk, which occurs after the user's `draw` function and any post-draw functions are run. This approach better utilizes the GPU, so it doesn't have to repeatedly wait for the CPU to send small chunks of data that describe each individual shape. It's the main reason why WebGPU is faster than Canvas2D.
175
147
 
176
- Implemented functions:
177
-
178
- `rect`, `circle`, `ellipse`, `triangle`, `beginShape`, `vertex`, `endShape`, `blendMode`
148
+ Rounded rectangles, stroke modes, and functions for drawing curves like `bezier` and `curve` are not implemented yet.
179
149
 
180
150
  ## webgpu-image
181
151
 
182
- Implemented functions:
183
-
184
- `loadImage`, `loadTexture`, `image`, `imageMode`
152
+ Using `image` to drawn a subsection of an image and most blending modes are not yet implemented.
185
153
 
186
154
  ## webgpu-text
187
155
 
@@ -260,9 +228,9 @@ For super lightweight use load <https://q5js.org/fonts/YaHei-256-msdf.json>, whi
260
228
  !@'",-.0123456789:ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
261
229
  ```
262
230
 
263
- ### Implemented functions
231
+ ### Limitations
264
232
 
265
- `loadFont`, `text`, `textFont`, `textSize`, `textAlign`, `textWidth`, `createTextImage`, `textImage`
233
+ Text strokes are not supported yet, except with `textImage`.
266
234
 
267
235
  ## math
268
236