q5 2.21.1 → 2.21.4

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 (4) hide show
  1. package/package.json +2 -2
  2. package/q5.d.ts +63 -32
  3. package/q5.js +213 -159
  4. package/q5.min.js +1 -1
package/q5.js CHANGED
@@ -1317,7 +1317,7 @@ Q5.renderers.c2d.image = ($, q) => {
1317
1317
  };
1318
1318
  });
1319
1319
 
1320
- img.src = url;
1320
+ g.src = img.src = url;
1321
1321
 
1322
1322
  if ($._disablePreload) return g._loader;
1323
1323
  return g;
@@ -4520,12 +4520,13 @@ struct Q5 {
4520
4520
 
4521
4521
  if ($.colorMode) $.colorMode('rgb', 1);
4522
4522
 
4523
- let pass,
4523
+ let encoder,
4524
+ pass,
4524
4525
  mainView,
4525
4526
  frameA,
4526
4527
  frameB,
4528
+ frameLayout,
4527
4529
  frameSampler,
4528
- framePipeline,
4529
4530
  frameBindGroup,
4530
4531
  colorIndex = 1,
4531
4532
  colorStackIndex = 8;
@@ -4533,6 +4534,7 @@ struct Q5 {
4533
4534
  $._pipelineConfigs = [];
4534
4535
  $._pipelines = [];
4535
4536
  $._buffers = [];
4537
+ $._framePL = 0;
4536
4538
 
4537
4539
  // local variables used for slightly better performance
4538
4540
  // stores pipeline shifts and vertex counts/image indices
@@ -4599,18 +4601,40 @@ struct Q5 {
4599
4601
  $._frameA = frameA = Q5.device.createTexture({ size, format, usage });
4600
4602
  $._frameB = frameB = Q5.device.createTexture({ size, format, usage });
4601
4603
 
4602
- let finalShader = Q5.device.createShaderModule({
4603
- code: `
4604
- @vertex fn v(@builtin(vertex_index)i:u32)->@builtin(position)vec4<f32>{
4605
- const pos=array(vec2(-1f,-1f),vec2(1f,-1f),vec2(-1f,1f),vec2(1f,1f));
4606
- return vec4(pos[i],0f,1f);
4604
+ $._frameShaderCode =
4605
+ $._baseShaderCode +
4606
+ /* wgsl */ `
4607
+ struct VertexParams {
4608
+ @builtin(vertex_index) vertexIndex: u32
4609
+ }
4610
+ struct FragParams {
4611
+ @builtin(position) position: vec4f,
4612
+ @location(0) texCoord: vec2f
4613
+ }
4614
+
4615
+ const ndc = array(vec2f(-1,-1), vec2f(1,-1), vec2f(-1,1), vec2f(1,1));
4616
+ const quad = array(vec2f(0,1), vec2f(1,1), vec2f(0,0), vec2f(1,0));
4617
+
4618
+ @group(0) @binding(0) var<uniform> q: Q5;
4619
+ @group(0) @binding(1) var samp: sampler;
4620
+ @group(0) @binding(2) var tex: texture_2d<f32>;
4621
+
4622
+ @vertex
4623
+ fn vertexMain(v: VertexParams) -> FragParams {
4624
+ var f: FragParams;
4625
+ f.position = vec4f(ndc[v.vertexIndex], 0.0, 1.0);
4626
+ f.texCoord = quad[v.vertexIndex];
4627
+ return f;
4607
4628
  }
4608
- @group(0) @binding(0) var s: sampler;
4609
- @group(0) @binding(1) var t: texture_2d<f32>;
4610
- @fragment fn f(@builtin(position)c:vec4<f32>)->@location(0)vec4<f32>{
4611
- let uv=c.xy/vec2(${w}, ${h});
4612
- return textureSample(t,s,uv);
4613
- }`
4629
+
4630
+ @fragment
4631
+ fn fragMain(f: FragParams ) -> @location(0) vec4f {
4632
+ return textureSample(tex, samp, f.texCoord);
4633
+ }`;
4634
+
4635
+ let frameShader = Q5.device.createShaderModule({
4636
+ label: 'frameShader',
4637
+ code: $._frameShaderCode
4614
4638
  });
4615
4639
 
4616
4640
  frameSampler = Q5.device.createSampler({
@@ -4618,18 +4642,45 @@ struct Q5 {
4618
4642
  minFilter: 'linear'
4619
4643
  });
4620
4644
 
4621
- // Create a pipeline for rendering
4622
- framePipeline = Q5.device.createRenderPipeline({
4623
- layout: 'auto',
4624
- vertex: { module: finalShader, entryPoint: 'v' },
4645
+ frameLayout = Q5.device.createBindGroupLayout({
4646
+ label: 'frameLayout',
4647
+ entries: [
4648
+ {
4649
+ binding: 0,
4650
+ visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
4651
+ buffer: { type: 'uniform' }
4652
+ },
4653
+ {
4654
+ binding: 1,
4655
+ visibility: GPUShaderStage.FRAGMENT,
4656
+ sampler: { type: 'filtering' }
4657
+ },
4658
+ {
4659
+ binding: 2,
4660
+ visibility: GPUShaderStage.FRAGMENT,
4661
+ texture: { viewDimension: '2d', sampleType: 'float' }
4662
+ }
4663
+ ]
4664
+ });
4665
+
4666
+ let framePipelineLayout = Q5.device.createPipelineLayout({
4667
+ bindGroupLayouts: [frameLayout]
4668
+ });
4669
+
4670
+ $._pipelineConfigs[0] = {
4671
+ layout: framePipelineLayout,
4672
+ vertex: { module: frameShader, entryPoint: 'vertexMain' },
4625
4673
  fragment: {
4626
- module: finalShader,
4627
- entryPoint: 'f',
4628
- targets: [{ format, writeMask: GPUColorWrite.ALL }]
4674
+ module: frameShader,
4675
+ entryPoint: 'fragMain',
4676
+ targets: [{ format, blend: $.blendConfigs.normal }]
4629
4677
  },
4630
4678
  primitive: { topology: 'triangle-strip' },
4631
4679
  multisample: { count: 4 }
4632
- });
4680
+ };
4681
+
4682
+ // Create a pipeline for rendering frames
4683
+ $._pipelines[0] = Q5.device.createRenderPipeline($._pipelineConfigs[0]);
4633
4684
  };
4634
4685
 
4635
4686
  $._createCanvas = (w, h, opt) => {
@@ -4992,33 +5043,27 @@ struct Q5 {
4992
5043
  }
4993
5044
  };
4994
5045
 
4995
- let shouldClear = false;
5046
+ let shouldClear;
4996
5047
  $.clear = () => {
4997
5048
  shouldClear = true;
4998
5049
  };
4999
5050
 
5000
- const _drawFrame = () => {
5001
- pass.setPipeline(framePipeline);
5002
- pass.setBindGroup(0, frameBindGroup);
5003
- pass.draw(4);
5004
- };
5005
-
5006
5051
  $._beginRender = () => {
5052
+ if (encoder) return;
5053
+
5007
5054
  // swap the frame textures
5008
5055
  const temp = frameA;
5009
5056
  frameA = frameB;
5010
5057
  frameB = temp;
5011
5058
 
5012
- $.encoder = Q5.device.createCommandEncoder();
5059
+ encoder = Q5.device.createCommandEncoder();
5013
5060
 
5014
- let target = shouldClear ? $.ctx.getCurrentTexture().createView() : frameA.createView();
5015
-
5016
- pass = q.pass = $.encoder.beginRenderPass({
5061
+ $._pass = pass = encoder.beginRenderPass({
5017
5062
  label: 'q5-webgpu',
5018
5063
  colorAttachments: [
5019
5064
  {
5020
5065
  view: mainView,
5021
- resolveTarget: target,
5066
+ resolveTarget: frameA.createView(),
5022
5067
  loadOp: 'clear',
5023
5068
  storeOp: 'store',
5024
5069
  clearValue: [0, 0, 0, 0]
@@ -5026,17 +5071,21 @@ struct Q5 {
5026
5071
  ]
5027
5072
  });
5028
5073
 
5029
- if (!shouldClear) {
5030
- frameBindGroup = Q5.device.createBindGroup({
5031
- layout: framePipeline.getBindGroupLayout(0),
5032
- entries: [
5033
- { binding: 0, resource: frameSampler },
5034
- { binding: 1, resource: frameB.createView() }
5035
- ]
5036
- });
5074
+ frameBindGroup = Q5.device.createBindGroup({
5075
+ layout: frameLayout,
5076
+ entries: [
5077
+ { binding: 0, resource: { buffer: uniformBuffer } },
5078
+ { binding: 1, resource: frameSampler },
5079
+ { binding: 2, resource: frameB.createView() }
5080
+ ]
5081
+ });
5037
5082
 
5038
- _drawFrame();
5083
+ if (!shouldClear) {
5084
+ pass.setPipeline($._pipelines[0]);
5085
+ pass.setBindGroup(0, frameBindGroup);
5086
+ pass.draw(4);
5039
5087
  }
5088
+ shouldClear = false;
5040
5089
  };
5041
5090
 
5042
5091
  $._render = () => {
@@ -5102,7 +5151,7 @@ struct Q5 {
5102
5151
  pass.setPipeline($._pipelines[curPipelineIndex]);
5103
5152
  }
5104
5153
 
5105
- if (curPipelineIndex == 3 || curPipelineIndex >= 400) {
5154
+ if (curPipelineIndex == 4 || curPipelineIndex >= 4000) {
5106
5155
  // draw text
5107
5156
  let o = drawStack[i + 2];
5108
5157
  pass.setBindGroup(1, $._fonts[o].bindGroup);
@@ -5112,13 +5161,13 @@ struct Q5 {
5112
5161
  pass.draw(4, v, 0, textCharOffset);
5113
5162
  textCharOffset += v;
5114
5163
  i++;
5115
- } else if (curPipelineIndex == 1 || curPipelineIndex == 2 || curPipelineIndex >= 200) {
5164
+ } else if (curPipelineIndex == 2 || curPipelineIndex == 3 || curPipelineIndex >= 2000) {
5116
5165
  // draw an image or video frame
5117
5166
  // v is the texture index
5118
5167
  pass.setBindGroup(1, $._textureBindGroups[v]);
5119
5168
  pass.draw(4, 1, imageVertOffset);
5120
5169
  imageVertOffset += 4;
5121
- } else if (curPipelineIndex == 0 || curPipelineIndex >= 100) {
5170
+ } else if (curPipelineIndex == 1 || curPipelineIndex >= 1000) {
5122
5171
  // draw a shape
5123
5172
  // v is the number of vertices
5124
5173
  pass.draw(v, 1, drawVertOffset);
@@ -5130,32 +5179,33 @@ struct Q5 {
5130
5179
  $._finishRender = () => {
5131
5180
  pass.end();
5132
5181
 
5133
- if (!shouldClear) {
5134
- pass = $.encoder.beginRenderPass({
5135
- colorAttachments: [
5136
- {
5137
- view: mainView,
5138
- resolveTarget: $.ctx.getCurrentTexture().createView(),
5139
- loadOp: 'clear',
5140
- storeOp: 'store',
5141
- clearValue: [0, 0, 0, 0]
5142
- }
5143
- ]
5144
- });
5182
+ pass = encoder.beginRenderPass({
5183
+ colorAttachments: [
5184
+ {
5185
+ view: mainView,
5186
+ resolveTarget: $.ctx.getCurrentTexture().createView(),
5187
+ loadOp: 'clear',
5188
+ storeOp: 'store',
5189
+ clearValue: [0, 0, 0, 0]
5190
+ }
5191
+ ]
5192
+ });
5145
5193
 
5146
- frameBindGroup = Q5.device.createBindGroup({
5147
- layout: framePipeline.getBindGroupLayout(0),
5148
- entries: [
5149
- { binding: 0, resource: frameSampler },
5150
- { binding: 1, resource: frameA.createView() }
5151
- ]
5152
- });
5153
- _drawFrame();
5154
- pass.end();
5155
- shouldClear = false;
5156
- }
5194
+ frameBindGroup = Q5.device.createBindGroup({
5195
+ layout: frameLayout,
5196
+ entries: [
5197
+ { binding: 0, resource: { buffer: uniformBuffer } },
5198
+ { binding: 1, resource: frameSampler },
5199
+ { binding: 2, resource: frameA.createView() }
5200
+ ]
5201
+ });
5202
+
5203
+ pass.setPipeline($._pipelines[$._framePL]);
5204
+ pass.setBindGroup(0, frameBindGroup);
5205
+ pass.draw(4);
5206
+ pass.end();
5157
5207
 
5158
- Q5.device.queue.submit([$.encoder.finish()]);
5208
+ Q5.device.queue.submit([encoder.finish()]);
5159
5209
 
5160
5210
  // destroy buffers
5161
5211
  Q5.device.queue.onSubmittedWorkDone().then(() => {
@@ -5163,7 +5213,7 @@ struct Q5 {
5163
5213
  $._buffers = [];
5164
5214
  });
5165
5215
 
5166
- q.pass = $.encoder = null;
5216
+ $._pass = pass = encoder = null;
5167
5217
 
5168
5218
  // clear the stacks for the next frame
5169
5219
  drawStack.splice(0, drawStack.length);
@@ -5205,7 +5255,7 @@ Q5.webgpu = async function (scope, parent) {
5205
5255
  return new Q5(scope, parent, 'webgpu');
5206
5256
  };
5207
5257
  Q5.renderers.webgpu.shapes = ($) => {
5208
- $._shapesPL = 0;
5258
+ $._shapesPL = 1;
5209
5259
 
5210
5260
  $._shapesShaderCode =
5211
5261
  $._baseShaderCode +
@@ -5275,7 +5325,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5275
5325
  bindGroupLayouts: $.bindGroupLayouts
5276
5326
  });
5277
5327
 
5278
- $._pipelineConfigs[0] = {
5328
+ $._pipelineConfigs[1] = {
5279
5329
  label: 'shapesPipeline',
5280
5330
  layout: pipelineLayout,
5281
5331
  vertex: {
@@ -5292,7 +5342,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5292
5342
  multisample: { count: 4 }
5293
5343
  };
5294
5344
 
5295
- $._pipelines[0] = Q5.device.createRenderPipeline($._pipelineConfigs[0]);
5345
+ $._pipelines[1] = Q5.device.createRenderPipeline($._pipelineConfigs[1]);
5296
5346
 
5297
5347
  const addVert = (x, y, ci, ti) => {
5298
5348
  let v = vertexStack,
@@ -5831,7 +5881,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5831
5881
  };
5832
5882
 
5833
5883
  $._hooks.preRender.push(() => {
5834
- $.pass.setPipeline($._pipelines[0]);
5884
+ $._pass.setPipeline($._pipelines[1]);
5835
5885
 
5836
5886
  let vertexBuffer = Q5.device.createBuffer({
5837
5887
  size: vertIndex * 4,
@@ -5842,7 +5892,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5842
5892
  new Float32Array(vertexBuffer.getMappedRange()).set(vertexStack.slice(0, vertIndex));
5843
5893
  vertexBuffer.unmap();
5844
5894
 
5845
- $.pass.setVertexBuffer(0, vertexBuffer);
5895
+ $._pass.setVertexBuffer(0, vertexBuffer);
5846
5896
 
5847
5897
  $._buffers.push(vertexBuffer);
5848
5898
  });
@@ -5852,8 +5902,8 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5852
5902
  });
5853
5903
  };
5854
5904
  Q5.renderers.webgpu.image = ($, q) => {
5855
- $._imagePL = 1;
5856
- $._videoPL = 2;
5905
+ $._imagePL = 2;
5906
+ $._videoPL = 3;
5857
5907
 
5858
5908
  $._imageShaderCode =
5859
5909
  $._baseShaderCode +
@@ -5881,7 +5931,7 @@ struct FragParams {
5881
5931
  @group(1) @binding(1) var tex: texture_2d<f32>;
5882
5932
 
5883
5933
  fn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {
5884
- var vert = vec4f(pos, 0.0, 1.0);
5934
+ var vert = vec4f(pos, 0f, 1f);
5885
5935
  vert = transforms[i32(matrixIndex)] * vert;
5886
5936
  vert.x /= q.halfWidth;
5887
5937
  vert.y /= q.halfHeight;
@@ -5985,7 +6035,7 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
5985
6035
  bindGroupLayouts: [...$.bindGroupLayouts, videoTextureLayout]
5986
6036
  });
5987
6037
 
5988
- $._pipelineConfigs[1] = {
6038
+ $._pipelineConfigs[2] = {
5989
6039
  label: 'imagePipeline',
5990
6040
  layout: imagePipelineLayout,
5991
6041
  vertex: {
@@ -6002,9 +6052,9 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6002
6052
  multisample: { count: 4 }
6003
6053
  };
6004
6054
 
6005
- $._pipelines[1] = Q5.device.createRenderPipeline($._pipelineConfigs[1]);
6055
+ $._pipelines[2] = Q5.device.createRenderPipeline($._pipelineConfigs[2]);
6006
6056
 
6007
- $._pipelineConfigs[2] = {
6057
+ $._pipelineConfigs[3] = {
6008
6058
  label: 'videoPipeline',
6009
6059
  layout: videoPipelineLayout,
6010
6060
  vertex: {
@@ -6021,10 +6071,66 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6021
6071
  multisample: { count: 4 }
6022
6072
  };
6023
6073
 
6024
- $._pipelines[2] = Q5.device.createRenderPipeline($._pipelineConfigs[2]);
6074
+ $._pipelines[3] = Q5.device.createRenderPipeline($._pipelineConfigs[3]);
6025
6075
 
6026
6076
  $._textureBindGroups = [];
6027
6077
 
6078
+ $._saveCanvas = async (data, ext) => {
6079
+ let texture = data.texture,
6080
+ w = texture.width,
6081
+ h = texture.height,
6082
+ bytesPerRow = Math.ceil((w * 4) / 256) * 256;
6083
+
6084
+ let buffer = Q5.device.createBuffer({
6085
+ size: bytesPerRow * h,
6086
+ usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
6087
+ });
6088
+
6089
+ $._buffers.push(buffer);
6090
+
6091
+ let en = Q5.device.createCommandEncoder();
6092
+
6093
+ en.copyTextureToBuffer({ texture }, { buffer, bytesPerRow, rowsPerImage: h }, { width: w, height: h });
6094
+
6095
+ Q5.device.queue.submit([en.finish()]);
6096
+
6097
+ await buffer.mapAsync(GPUMapMode.READ);
6098
+
6099
+ let pad = new Uint8Array(buffer.getMappedRange());
6100
+ data = new Uint8Array(w * h * 4); // unpadded data
6101
+
6102
+ // Remove padding from each row and swap BGR to RGB
6103
+ for (let y = 0; y < h; y++) {
6104
+ const p = y * bytesPerRow; // padded row offset
6105
+ const u = y * w * 4; // unpadded row offset
6106
+ for (let x = 0; x < w; x++) {
6107
+ const pp = p + x * 4; // padded pixel offset
6108
+ const up = u + x * 4; // unpadded pixel offset
6109
+ data[up + 0] = pad[pp + 2]; // R <- B
6110
+ data[up + 1] = pad[pp + 1]; // G <- G
6111
+ data[up + 2] = pad[pp + 0]; // B <- R
6112
+ data[up + 3] = pad[pp + 3]; // A <- A
6113
+ }
6114
+ }
6115
+
6116
+ buffer.unmap();
6117
+
6118
+ let colorSpace = $.canvas.colorSpace;
6119
+ data = new Uint8ClampedArray(data.buffer);
6120
+ data = new ImageData(data, w, h, { colorSpace });
6121
+ let cnv = new $._Canvas(w, h);
6122
+ let ctx = cnv.getContext('2d', { colorSpace });
6123
+ ctx.putImageData(data, 0, 0);
6124
+
6125
+ // Convert to blob then data URL
6126
+ let blob = await cnv.convertToBlob({ type: 'image/' + ext });
6127
+ return await new Promise((resolve) => {
6128
+ let r = new FileReader();
6129
+ r.onloadend = () => resolve(r.result);
6130
+ r.readAsDataURL(blob);
6131
+ });
6132
+ };
6133
+
6028
6134
  let makeSampler = (filter) => {
6029
6135
  $._imageSampler = Q5.device.createSampler({
6030
6136
  magFilter: filter,
@@ -6065,7 +6171,8 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6065
6171
  img.texture = texture;
6066
6172
  img.textureIndex = tIdx + vidFrames;
6067
6173
 
6068
- $._textureBindGroups[tIdx + vidFrames] = Q5.device.createBindGroup({
6174
+ $._textureBindGroups[img.textureIndex] = Q5.device.createBindGroup({
6175
+ label: img.src || 'canvas',
6069
6176
  layout: textureLayout,
6070
6177
  entries: [
6071
6178
  { binding: 0, resource: $._imageSampler },
@@ -6206,67 +6313,11 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6206
6313
  }
6207
6314
  };
6208
6315
 
6209
- $._saveCanvas = async (data, ext) => {
6210
- let texture = data.texture,
6211
- w = texture.width,
6212
- h = texture.height,
6213
- bytesPerRow = Math.ceil((w * 4) / 256) * 256;
6214
-
6215
- let buffer = Q5.device.createBuffer({
6216
- size: bytesPerRow * h,
6217
- usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
6218
- });
6219
-
6220
- $._buffers.push(buffer);
6221
-
6222
- let en = Q5.device.createCommandEncoder();
6223
-
6224
- en.copyTextureToBuffer({ texture }, { buffer, bytesPerRow, rowsPerImage: h }, { width: w, height: h });
6225
-
6226
- Q5.device.queue.submit([en.finish()]);
6227
-
6228
- await buffer.mapAsync(GPUMapMode.READ);
6229
-
6230
- let pad = new Uint8Array(buffer.getMappedRange());
6231
- data = new Uint8Array(w * h * 4); // unpadded data
6232
-
6233
- // Remove padding from each row and swap BGR to RGB
6234
- for (let y = 0; y < h; y++) {
6235
- const p = y * bytesPerRow; // padded row offset
6236
- const u = y * w * 4; // unpadded row offset
6237
- for (let x = 0; x < w; x++) {
6238
- const pp = p + x * 4; // padded pixel offset
6239
- const up = u + x * 4; // unpadded pixel offset
6240
- data[up + 0] = pad[pp + 2]; // R <- B
6241
- data[up + 1] = pad[pp + 1]; // G <- G
6242
- data[up + 2] = pad[pp + 0]; // B <- R
6243
- data[up + 3] = pad[pp + 3]; // A <- A
6244
- }
6245
- }
6246
-
6247
- buffer.unmap();
6248
-
6249
- let colorSpace = $.canvas.colorSpace;
6250
- data = new Uint8ClampedArray(data.buffer);
6251
- data = new ImageData(data, w, h, { colorSpace });
6252
- let cnv = new $._Canvas(w, h);
6253
- let ctx = cnv.getContext('2d', { colorSpace });
6254
- ctx.putImageData(data, 0, 0);
6255
-
6256
- // Convert to blob then data URL
6257
- let blob = await cnv.convertToBlob({ type: 'image/' + ext });
6258
- return await new Promise((resolve) => {
6259
- let r = new FileReader();
6260
- r.onloadend = () => resolve(r.result);
6261
- r.readAsDataURL(blob);
6262
- });
6263
- };
6264
-
6265
6316
  $._hooks.preRender.push(() => {
6266
6317
  if (!vertIndex) return;
6267
6318
 
6268
6319
  // Switch to image pipeline
6269
- $.pass.setPipeline($._pipelines[1]);
6320
+ $._pass.setPipeline($._pipelines[2]);
6270
6321
 
6271
6322
  let vertexBuffer = Q5.device.createBuffer({
6272
6323
  size: vertIndex * 5,
@@ -6277,14 +6328,14 @@ fn fragMain(f: FragParams) -> @location(0) vec4f {
6277
6328
  new Float32Array(vertexBuffer.getMappedRange()).set(vertexStack.slice(0, vertIndex));
6278
6329
  vertexBuffer.unmap();
6279
6330
 
6280
- $.pass.setVertexBuffer(1, vertexBuffer);
6331
+ $._pass.setVertexBuffer(1, vertexBuffer);
6281
6332
 
6282
6333
  $._buffers.push(vertexBuffer);
6283
6334
 
6284
6335
  if (vidFrames) {
6285
6336
  // Switch to video pipeline
6286
- $.pass.setPipeline($._pipelines[3]);
6287
- $.pass.setVertexBuffer(1, vertexBuffer);
6337
+ $._pass.setPipeline($._pipelines[3]);
6338
+ $._pass.setVertexBuffer(1, vertexBuffer);
6288
6339
  }
6289
6340
  });
6290
6341
 
@@ -6304,7 +6355,7 @@ Q5.DILATE = 6;
6304
6355
  Q5.ERODE = 7;
6305
6356
  Q5.BLUR = 8;
6306
6357
  Q5.renderers.webgpu.text = ($, q) => {
6307
- $._textPL = 3;
6358
+ $._textPL = 4;
6308
6359
 
6309
6360
  $._textShaderCode =
6310
6361
  $._baseShaderCode +
@@ -6347,6 +6398,7 @@ struct Text {
6347
6398
  @group(2) @binding(1) var<storage> textMetadata: array<Text>;
6348
6399
 
6349
6400
  const quad = array(vec2f(0, -1), vec2f(1, -1), vec2f(0, 0), vec2f(1, 0));
6401
+ const uvs = array(vec2f(0, 1), vec2f(1, 1), vec2f(0, 0), vec2f(1, 0));
6350
6402
 
6351
6403
  fn calcPos(i: u32, char: vec4f, fontChar: Char, text: Text) -> vec2f {
6352
6404
  return ((quad[i] * fontChar.size + char.xy + fontChar.offset) *
@@ -6354,8 +6406,7 @@ fn calcPos(i: u32, char: vec4f, fontChar: Char, text: Text) -> vec2f {
6354
6406
  }
6355
6407
 
6356
6408
  fn calcUV(i: u32, fontChar: Char) -> vec2f {
6357
- return (quad[i] * vec2f(1, -1)) *
6358
- fontChar.texExtent + fontChar.texOffset;
6409
+ return uvs[i] * fontChar.texExtent + fontChar.texOffset;
6359
6410
  }
6360
6411
 
6361
6412
  fn transformVertex(pos: vec2f, matrixIndex: f32) -> vec4f {
@@ -6475,7 +6526,7 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
6475
6526
  bindGroupLayouts: [...$.bindGroupLayouts, fontBindGroupLayout, textBindGroupLayout]
6476
6527
  });
6477
6528
 
6478
- $._pipelineConfigs[3] = {
6529
+ $._pipelineConfigs[4] = {
6479
6530
  label: 'textPipeline',
6480
6531
  layout: fontPipelineLayout,
6481
6532
  vertex: { module: textShader, entryPoint: 'vertexMain' },
@@ -6488,7 +6539,7 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
6488
6539
  multisample: { count: 4 }
6489
6540
  };
6490
6541
 
6491
- $._pipelines[3] = Q5.device.createRenderPipeline($._pipelineConfigs[3]);
6542
+ $._pipelines[4] = Q5.device.createRenderPipeline($._pipelineConfigs[4]);
6492
6543
 
6493
6544
  class MsdfFont {
6494
6545
  constructor(bindGroup, lineHeight, chars, kernings) {
@@ -6934,13 +6985,14 @@ fn fragMain(f : FragParams) -> @location(0) vec4f {
6934
6985
  });
6935
6986
  };
6936
6987
  Q5.renderers.webgpu.shaders = ($) => {
6937
- let pipelineTypes = ['shapes', 'image', 'video', 'text'];
6988
+ let pipelineTypes = ['frame', 'shapes', 'image', 'video', 'text'];
6938
6989
 
6939
6990
  let plCounters = {
6940
- shapes: 100,
6941
- image: 200,
6942
- video: 300,
6943
- text: 400
6991
+ frame: 10,
6992
+ shapes: 1000,
6993
+ image: 2000,
6994
+ video: 3000,
6995
+ text: 4000
6944
6996
  };
6945
6997
 
6946
6998
  $._createShader = (code, type = 'shapes') => {
@@ -6976,12 +7028,14 @@ Q5.renderers.webgpu.shaders = ($) => {
6976
7028
  let pl = plCounters[type];
6977
7029
  $._pipelines[pl] = Q5.device.createRenderPipeline(config);
6978
7030
  shader.pipelineIndex = pl;
7031
+
6979
7032
  plCounters[type]++;
6980
7033
 
6981
7034
  return shader;
6982
7035
  };
6983
7036
 
6984
7037
  $.createShader = $.createShapesShader = $._createShader;
7038
+ $.createFrameShader = (code) => $._createShader(code, 'frame');
6985
7039
  $.createImageShader = (code) => $._createShader(code, 'image');
6986
7040
  $.createVideoShader = (code) => $._createShader(code, 'video');
6987
7041
  $.createTextShader = (code) => $._createShader(code, 'text');
@@ -6995,10 +7049,10 @@ Q5.renderers.webgpu.shaders = ($) => {
6995
7049
  };
6996
7050
 
6997
7051
  $.resetShaders = () => {
6998
- $._shapesPL = 0;
6999
- $._imagePL = 1;
7000
- $._videoPL = 2;
7001
- $._textPL = 3;
7002
- $._planePL = 4;
7052
+ $._framePL = 0;
7053
+ $._shapesPL = 1;
7054
+ $._imagePL = 2;
7055
+ $._videoPL = 3;
7056
+ $._textPL = 4;
7003
7057
  };
7004
7058
  };