q5 2.2.3 → 2.4.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,39 +1,16 @@
1
1
  Q5.renderers.webgpu.drawing = ($, q) => {
2
- $.CLOSE = 1;
2
+ let c = $.canvas;
3
3
 
4
- let verticesStack, drawStack, colorsStack;
4
+ let drawStack = $.drawStack;
5
+ let colorsStack = $.colorsStack;
5
6
 
6
- $._hooks.postCanvas.push(() => {
7
- let colorsLayout = Q5.device.createBindGroupLayout({
8
- entries: [
9
- {
10
- binding: 0,
11
- visibility: GPUShaderStage.FRAGMENT,
12
- buffer: {
13
- type: 'read-only-storage',
14
- hasDynamicOffset: false
15
- }
16
- }
17
- ]
18
- });
19
-
20
- $.bindGroupLayouts.push(colorsLayout);
21
-
22
- verticesStack = $.verticesStack;
23
- drawStack = $.drawStack;
24
- colorsStack = $.colorsStack;
7
+ let verticesStack = [];
25
8
 
26
- let vertexBufferLayout = {
27
- arrayStride: 16, // 2 coordinates + 1 color index + 1 transform index * 4 bytes each
28
- attributes: [
29
- { format: 'float32x2', offset: 0, shaderLocation: 0 }, // position
30
- { format: 'float32', offset: 8, shaderLocation: 1 }, // colorIndex
31
- { format: 'float32', offset: 12, shaderLocation: 2 } // transformIndex
32
- ]
33
- };
9
+ let colorIndex, colorsLayout;
34
10
 
35
- let vertexShader = Q5.device.createShaderModule({
36
- code: `
11
+ let vertexShader = Q5.device.createShaderModule({
12
+ label: 'drawingVertexShader',
13
+ code: `
37
14
  struct VertexOutput {
38
15
  @builtin(position) position: vec4<f32>,
39
16
  @location(1) colorIndex: f32
@@ -60,10 +37,11 @@ fn vertexMain(@location(0) pos: vec2<f32>, @location(1) colorIndex: f32, @locati
60
37
  return output;
61
38
  }
62
39
  `
63
- });
40
+ });
64
41
 
65
- let fragmentShader = Q5.device.createShaderModule({
66
- code: `
42
+ let fragmentShader = Q5.device.createShaderModule({
43
+ label: 'drawingFragmentShader',
44
+ code: `
67
45
  @group(2) @binding(0) var<storage, read> uColors : array<vec4<f32>>;
68
46
 
69
47
  @fragment
@@ -72,31 +50,31 @@ fn fragmentMain(@location(1) colorIndex: f32) -> @location(0) vec4<f32> {
72
50
  return mix(uColors[index], uColors[index + 1u], fract(colorIndex));
73
51
  }
74
52
  `
75
- });
53
+ });
76
54
 
77
- let pipelineLayout = Q5.device.createPipelineLayout({
78
- bindGroupLayouts: $.bindGroupLayouts
79
- });
55
+ colorsLayout = Q5.device.createBindGroupLayout({
56
+ entries: [
57
+ {
58
+ binding: 0,
59
+ visibility: GPUShaderStage.FRAGMENT,
60
+ buffer: {
61
+ type: 'read-only-storage',
62
+ hasDynamicOffset: false
63
+ }
64
+ }
65
+ ]
66
+ });
80
67
 
81
- $._createPipeline = (blendConfig) => {
82
- return Q5.device.createRenderPipeline({
83
- layout: pipelineLayout,
84
- vertex: {
85
- module: vertexShader,
86
- entryPoint: 'vertexMain',
87
- buffers: [vertexBufferLayout]
88
- },
89
- fragment: {
90
- module: fragmentShader,
91
- entryPoint: 'fragmentMain',
92
- targets: [{ format: 'bgra8unorm', blend: blendConfig }]
93
- },
94
- primitive: { topology: 'triangle-list' }
95
- });
96
- };
68
+ $.bindGroupLayouts.push(colorsLayout);
97
69
 
98
- $.pipelines[0] = $._createPipeline(blendConfigs.normal);
99
- });
70
+ let vertexBufferLayout = {
71
+ arrayStride: 16, // 2 coordinates + 1 color index + 1 transform index * 4 bytes each
72
+ attributes: [
73
+ { format: 'float32x2', offset: 0, shaderLocation: 0 }, // position
74
+ { format: 'float32', offset: 8, shaderLocation: 1 }, // colorIndex
75
+ { format: 'float32', offset: 12, shaderLocation: 2 } // transformIndex
76
+ ]
77
+ };
100
78
 
101
79
  // prettier-ignore
102
80
  let blendFactors = [
@@ -141,7 +119,7 @@ fn fragmentMain(@location(1) colorIndex: f32) -> @location(0) vec4<f32> {
141
119
 
142
120
  $.blendConfigs = {};
143
121
 
144
- Object.entries(blendModes).forEach(([name, mode]) => {
122
+ for (const [name, mode] of Object.entries(blendModes)) {
145
123
  $.blendConfigs[name] = {
146
124
  color: {
147
125
  srcFactor: blendFactors[mode[0]],
@@ -154,7 +132,7 @@ fn fragmentMain(@location(1) colorIndex: f32) -> @location(0) vec4<f32> {
154
132
  operation: blendOps[mode[5]]
155
133
  }
156
134
  };
157
- });
135
+ }
158
136
 
159
137
  $._blendMode = 'normal';
160
138
  $.blendMode = (mode) => {
@@ -165,6 +143,31 @@ fn fragmentMain(@location(1) colorIndex: f32) -> @location(0) vec4<f32> {
165
143
  $.pipelines[0] = $._createPipeline($.blendConfigs[mode]);
166
144
  };
167
145
 
146
+ let pipelineLayout = Q5.device.createPipelineLayout({
147
+ label: 'drawingPipelineLayout',
148
+ bindGroupLayouts: $.bindGroupLayouts
149
+ });
150
+
151
+ $._createPipeline = (blendConfig) => {
152
+ return Q5.device.createRenderPipeline({
153
+ label: 'drawingPipeline',
154
+ layout: pipelineLayout,
155
+ vertex: {
156
+ module: vertexShader,
157
+ entryPoint: 'vertexMain',
158
+ buffers: [vertexBufferLayout]
159
+ },
160
+ fragment: {
161
+ module: fragmentShader,
162
+ entryPoint: 'fragmentMain',
163
+ targets: [{ format: 'bgra8unorm', blend: blendConfig }]
164
+ },
165
+ primitive: { topology: 'triangle-list' }
166
+ });
167
+ };
168
+
169
+ $.pipelines[0] = $._createPipeline($.blendConfigs.normal);
170
+
168
171
  let shapeVertices;
169
172
 
170
173
  $.beginShape = () => {
@@ -173,7 +176,7 @@ fn fragmentMain(@location(1) colorIndex: f32) -> @location(0) vec4<f32> {
173
176
 
174
177
  $.vertex = (x, y) => {
175
178
  if ($._matrixDirty) $._saveMatrix();
176
- shapeVertices.push(x, -y, $._colorIndex, $._transformIndex);
179
+ shapeVertices.push(x, -y, $._fillIndex, $._transformIndex);
177
180
  };
178
181
 
179
182
  $.endShape = (close) => {
@@ -217,38 +220,61 @@ fn fragmentMain(@location(1) colorIndex: f32) -> @location(0) vec4<f32> {
217
220
  $.endShape(1);
218
221
  };
219
222
 
220
- $.rect = (x, y, w, h) => {
221
- let hw = w / 2;
222
- let hh = h / 2;
223
+ $.rectMode = (x) => ($._rectMode = x);
223
224
 
224
- let left = x - hw;
225
- let right = x + hw;
226
- let top = -(y - hh); // y is inverted in WebGPU
227
- let bottom = -(y + hh);
225
+ $.rect = (x, y, w, h) => {
226
+ let [l, r, t, b] = $._calcBox(x, y, w, h, $._rectMode);
228
227
 
229
- let ci = $._colorIndex;
228
+ let ci = colorIndex ?? $._fillIndex;
230
229
  if ($._matrixDirty) $._saveMatrix();
231
230
  let ti = $._transformIndex;
232
231
  // two triangles make a rectangle
233
232
  // prettier-ignore
234
233
  verticesStack.push(
235
- left, top, ci, ti,
236
- right, top, ci, ti,
237
- left, bottom, ci, ti,
238
- right, top, ci, ti,
239
- left, bottom, ci, ti,
240
- right, bottom, ci, ti
234
+ l, t, ci, ti,
235
+ r, t, ci, ti,
236
+ l, b, ci, ti,
237
+ r, t, ci, ti,
238
+ l, b, ci, ti,
239
+ r, b, ci, ti
241
240
  );
242
241
  drawStack.push(0, 6);
243
242
  };
244
243
 
245
244
  $.point = (x, y) => {
245
+ colorIndex = $._strokeIndex;
246
246
  let sw = $._strokeWeight;
247
- if (sw == 1) $.rect(x, y, 1, 1);
248
- else $.ellipse(x, y, sw, sw);
247
+ if (sw < 2) {
248
+ sw = Math.round(sw);
249
+ $.rect(x, y, sw, sw);
250
+ } else $.ellipse(x, y, sw, sw);
251
+ colorIndex = null;
249
252
  };
250
253
 
251
- $.background = () => {};
254
+ $.line = (x1, y1, x2, y2) => {
255
+ colorIndex = $._strokeIndex;
256
+
257
+ $.push();
258
+ $.translate(x1, y1);
259
+ $.rotate($.atan2(y2 - y1, x2 - x1));
260
+ let length = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
261
+ let sw = $._strokeWeight;
262
+ $.rect(0, -sw / 2, length, sw);
263
+ $.pop();
264
+
265
+ colorIndex = null;
266
+ };
267
+
268
+ $.background = (r, g, b, a) => {
269
+ $.push();
270
+ $.resetMatrix();
271
+ if (r.src) $.image(r, -c.hw, -c.hh, c.w, c.h);
272
+ else {
273
+ $.fill(r, g, b, a);
274
+ $.rect(-c.hw, -c.hh, c.w, c.h);
275
+ }
276
+ $.pop();
277
+ };
252
278
 
253
279
  /**
254
280
  * Derived from: ceil(Math.log(d) * 7) * 2 - ceil(28)
@@ -258,9 +284,10 @@ fn fragmentMain(@location(1) colorIndex: f32) -> @location(0) vec4<f32> {
258
284
  */
259
285
  // prettier-ignore
260
286
  const getArcSegments = (d) =>
261
- d < 14 ? 8 :
262
- d < 16 ? 10 :
263
- d < 18 ? 12 :
287
+ d < 4 ? 6 :
288
+ d < 6 ? 8 :
289
+ d < 10 ? 10 :
290
+ d < 16 ? 12 :
264
291
  d < 20 ? 14 :
265
292
  d < 22 ? 16 :
266
293
  d < 24 ? 18 :
@@ -294,7 +321,7 @@ fn fragmentMain(@location(1) colorIndex: f32) -> @location(0) vec4<f32> {
294
321
 
295
322
  let t = 0; // theta
296
323
  const angleIncrement = $.TAU / n;
297
- const ci = $._colorIndex;
324
+ const ci = colorIndex ?? $._fillIndex;
298
325
  if ($._matrixDirty) $._saveMatrix();
299
326
  const ti = $._transformIndex;
300
327
  let vx1, vy1, vx2, vy2;
@@ -316,12 +343,16 @@ fn fragmentMain(@location(1) colorIndex: f32) -> @location(0) vec4<f32> {
316
343
  $.circle = (x, y, d) => $.ellipse(x, y, d, d);
317
344
 
318
345
  $._hooks.preRender.push(() => {
346
+ $.pass.setPipeline($.pipelines[0]);
347
+
348
+ const vertices = new Float32Array(verticesStack);
349
+
319
350
  const vertexBuffer = Q5.device.createBuffer({
320
- size: verticesStack.length * 6,
351
+ size: vertices.byteLength,
321
352
  usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
322
353
  });
323
354
 
324
- Q5.device.queue.writeBuffer(vertexBuffer, 0, new Float32Array(verticesStack));
355
+ Q5.device.queue.writeBuffer(vertexBuffer, 0, vertices);
325
356
  $.pass.setVertexBuffer(0, vertexBuffer);
326
357
 
327
358
  const colorsBuffer = Q5.device.createBuffer({
@@ -331,8 +362,8 @@ fn fragmentMain(@location(1) colorIndex: f32) -> @location(0) vec4<f32> {
331
362
 
332
363
  Q5.device.queue.writeBuffer(colorsBuffer, 0, new Float32Array(colorsStack));
333
364
 
334
- const colorsBindGroup = Q5.device.createBindGroup({
335
- layout: $.bindGroupLayouts[2],
365
+ $._colorsBindGroup = Q5.device.createBindGroup({
366
+ layout: colorsLayout,
336
367
  entries: [
337
368
  {
338
369
  binding: 0,
@@ -346,6 +377,10 @@ fn fragmentMain(@location(1) colorIndex: f32) -> @location(0) vec4<f32> {
346
377
  });
347
378
 
348
379
  // set the bind group once before rendering
349
- $.pass.setBindGroup(2, colorsBindGroup);
380
+ $.pass.setBindGroup(2, $._colorsBindGroup);
381
+ });
382
+
383
+ $._hooks.postRender.push(() => {
384
+ verticesStack.length = 0;
350
385
  });
351
386
  };
@@ -1,130 +1,196 @@
1
1
  Q5.renderers.webgpu.image = ($, q) => {
2
- $.imageStack = [];
3
- $.textures = [];
2
+ $._textureBindGroups = [];
3
+ let verticesStack = [];
4
4
 
5
- $._hooks.postCanvas.push(() => {
6
- let imageVertexShader = Q5.device.createShaderModule({
7
- code: `
5
+ let vertexShader = Q5.device.createShaderModule({
6
+ label: 'imageVertexShader',
7
+ code: `
8
8
  struct VertexOutput {
9
- @builtin(position) position: vec4<f32>,
10
- @location(0) texCoord: vec2<f32>,
11
- @location(1) textureIndex: f32
9
+ @builtin(position) position: vec4<f32>,
10
+ @location(0) texCoord: vec2<f32>
12
11
  };
13
12
 
14
13
  struct Uniforms {
15
- halfWidth: f32,
16
- halfHeight: f32
14
+ halfWidth: f32,
15
+ halfHeight: f32
17
16
  };
18
17
 
19
18
  @group(0) @binding(0) var<uniform> uniforms: Uniforms;
20
19
  @group(1) @binding(0) var<storage, read> transforms: array<mat4x4<f32>>;
21
20
 
22
21
  @vertex
23
- fn vertexMain(@location(0) pos: vec2<f32>, @location(1) texCoord: vec2<f32>, @location(2) transformIndex: f32, @location(3) textureIndex: f32) -> VertexOutput {
24
- var vert = vec4<f32>(pos, 0.0, 1.0);
25
- vert *= transforms[i32(transformIndex)];
26
- vert.x /= uniforms.halfWidth;
27
- vert.y /= uniforms.halfHeight;
28
-
29
- var output: VertexOutput;
30
- output.position = vert;
31
- output.texCoord = texCoord;
32
- output.textureIndex = textureIndex;
33
- return output;
22
+ fn vertexMain(@location(0) pos: vec2<f32>, @location(1) texCoord: vec2<f32>, @location(2) transformIndex: f32) -> VertexOutput {
23
+ var vert = vec4<f32>(pos, 0.0, 1.0);
24
+ vert *= transforms[i32(transformIndex)];
25
+ vert.x /= uniforms.halfWidth;
26
+ vert.y /= uniforms.halfHeight;
27
+
28
+ var output: VertexOutput;
29
+ output.position = vert;
30
+ output.texCoord = texCoord;
31
+ return output;
34
32
  }
35
- `
36
- });
33
+ `
34
+ });
37
35
 
38
- let imageFragmentShader = Q5.device.createShaderModule({
39
- code: `
40
- @group(0) @binding(0) var samp: sampler;
41
- @group(0) @binding(1) var textures: array<texture_2d<f32>>;
36
+ let fragmentShader = Q5.device.createShaderModule({
37
+ label: 'imageFragmentShader',
38
+ code: `
39
+ @group(3) @binding(0) var samp: sampler;
40
+ @group(3) @binding(1) var texture: texture_2d<f32>;
42
41
 
43
42
  @fragment
44
- fn fragmentMain(@location(0) texCoord: vec2<f32>, @location(1) textureIndex: f32) -> @location(0) vec4<f32> {
45
- return textureSample(textures[i32(textureIndex)], samp, texCoord);
43
+ fn fragmentMain(@location(0) texCoord: vec2<f32>) -> @location(0) vec4<f32> {
44
+ // Sample the texture using the interpolated texture coordinate
45
+ return textureSample(texture, samp, texCoord);
46
46
  }
47
- `
48
- });
49
-
50
- const bindGroupLayouts = [
51
- Q5.device.createBindGroupLayout({
52
- entries: [
53
- { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } },
54
- { binding: 1, visibility: GPUShaderStage.FRAGMENT, sampler: {} },
55
- { binding: 2, visibility: GPUShaderStage.FRAGMENT, texture: { viewDimension: '2d', sampleType: 'float' } }
56
- ]
57
- }),
58
- Q5.device.createBindGroupLayout({
59
- entries: [{ binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'read-only-storage' } }]
60
- })
61
- ];
62
-
63
- const pipelineLayout = Q5.device.createPipelineLayout({
64
- bindGroupLayouts: bindGroupLayouts
65
- });
47
+ `
48
+ });
66
49
 
67
- $.pipelines[1] = Q5.device.createRenderPipeline({
68
- layout: pipelineLayout,
69
- vertex: {
70
- module: imageVertexShader,
71
- entryPoint: 'vertexMain',
72
- buffers: [
73
- {
74
- arrayStride: 5 * 4, // 4 floats for position and texCoord, 1 float for textureIndex
75
- attributes: [
76
- { shaderLocation: 0, offset: 0, format: 'float32x2' },
77
- { shaderLocation: 1, offset: 2 * 4, format: 'float32x2' },
78
- { shaderLocation: 2, offset: 4 * 4, format: 'float32' } // textureIndex
79
- ]
80
- }
81
- ]
50
+ let textureLayout = Q5.device.createBindGroupLayout({
51
+ label: 'textureLayout',
52
+ entries: [
53
+ {
54
+ binding: 0,
55
+ visibility: GPUShaderStage.FRAGMENT,
56
+ sampler: { type: 'filtering' }
82
57
  },
83
- fragment: {
84
- module: imageFragmentShader,
85
- entryPoint: 'fragmentMain',
86
- targets: [{ format: 'bgra8unorm' }]
87
- },
88
- primitive: {
89
- topology: 'triangle-list'
58
+ {
59
+ binding: 1,
60
+ visibility: GPUShaderStage.FRAGMENT,
61
+ texture: { viewDimension: '2d', sampleType: 'float' }
90
62
  }
63
+ ]
64
+ });
65
+
66
+ const vertexBufferLayout = {
67
+ arrayStride: 20,
68
+ attributes: [
69
+ { shaderLocation: 0, offset: 0, format: 'float32x2' },
70
+ { shaderLocation: 1, offset: 8, format: 'float32x2' },
71
+ { shaderLocation: 2, offset: 16, format: 'float32' } // transformIndex
72
+ ]
73
+ };
74
+
75
+ $.bindGroupLayouts.push(textureLayout);
76
+
77
+ const pipelineLayout = Q5.device.createPipelineLayout({
78
+ label: 'imagePipelineLayout',
79
+ bindGroupLayouts: $.bindGroupLayouts
80
+ });
81
+
82
+ $.pipelines[1] = Q5.device.createRenderPipeline({
83
+ label: 'imagePipeline',
84
+ layout: pipelineLayout,
85
+ vertex: {
86
+ module: vertexShader,
87
+ entryPoint: 'vertexMain',
88
+ buffers: [{ arrayStride: 0, attributes: [] }, vertexBufferLayout]
89
+ },
90
+ fragment: {
91
+ module: fragmentShader,
92
+ entryPoint: 'fragmentMain',
93
+ targets: [
94
+ {
95
+ format: 'bgra8unorm',
96
+ blend: $.blendConfigs?.normal || {
97
+ color: {
98
+ srcFactor: 'src-alpha',
99
+ dstFactor: 'one-minus-src-alpha',
100
+ operation: 'add'
101
+ },
102
+ alpha: {
103
+ srcFactor: 'src-alpha',
104
+ dstFactor: 'one-minus-src-alpha',
105
+ operation: 'add'
106
+ }
107
+ }
108
+ }
109
+ ]
110
+ },
111
+ primitive: {
112
+ topology: 'triangle-list'
113
+ }
114
+ });
115
+
116
+ let sampler = Q5.device.createSampler({
117
+ magFilter: 'linear',
118
+ minFilter: 'linear'
119
+ });
120
+
121
+ $._createTexture = (img) => {
122
+ let textureSize = [img.width, img.height, 1];
123
+
124
+ const texture = Q5.device.createTexture({
125
+ size: textureSize,
126
+ format: 'bgra8unorm',
127
+ usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT
91
128
  });
92
129
 
93
- $.sampler = Q5.device.createSampler({
94
- magFilter: 'linear',
95
- minFilter: 'linear'
130
+ Q5.device.queue.copyExternalImageToTexture({ source: img }, { texture }, textureSize);
131
+
132
+ img.textureIndex = $._textureBindGroups.length;
133
+
134
+ const textureBindGroup = Q5.device.createBindGroup({
135
+ layout: textureLayout,
136
+ entries: [
137
+ { binding: 0, resource: sampler },
138
+ { binding: 1, resource: texture.createView() }
139
+ ]
96
140
  });
97
- });
141
+ $._textureBindGroups.push(textureBindGroup);
142
+ };
98
143
 
99
- $.loadImage = async (src) => {
144
+ $.loadImage = $.loadTexture = (src) => {
145
+ q._preloadCount++;
100
146
  const img = new Image();
101
- img.onload = async () => {
102
- const imageBitmap = await createImageBitmap(img);
103
- const texture = Q5.device.createTexture({
104
- size: [img.width, img.height, 1],
105
- format: 'bgra8unorm',
106
- usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT
107
- });
108
-
109
- Q5.device.queue.copyExternalImageToTexture({ source: imageBitmap }, { texture }, [img.width, img.height, 1]);
110
-
111
- img.texture = texture;
112
- img.index = $.textures.length;
113
- $.textures.push(texture);
147
+ img.crossOrigin = 'Anonymous';
148
+ img.onload = () => {
149
+ $._createTexture(img);
150
+ q._preloadCount--;
114
151
  };
115
- img.onerror = reject;
116
152
  img.src = src;
117
153
  return img;
118
154
  };
119
155
 
156
+ $.imageMode = (x) => ($._imageMode = x);
157
+
158
+ $.image = (img, x, y, w, h) => {
159
+ if (img.canvas) img = img.canvas;
160
+ if (img.textureIndex == undefined) return;
161
+
162
+ if ($._matrixDirty) $._saveMatrix();
163
+ let ti = $._transformIndex;
164
+
165
+ w ??= img.width;
166
+ h ??= img.height;
167
+
168
+ w /= $._pixelDensity;
169
+ h /= $._pixelDensity;
170
+
171
+ let [l, r, t, b] = $._calcBox(x, y, w, h, $._imageMode);
172
+
173
+ // prettier-ignore
174
+ verticesStack.push(
175
+ l, t, 0, 0, ti,
176
+ r, t, 1, 0, ti,
177
+ l, b, 0, 1, ti,
178
+ r, t, 1, 0, ti,
179
+ l, b, 0, 1, ti,
180
+ r, b, 1, 1, ti
181
+ );
182
+
183
+ $.drawStack.push(1, img.textureIndex);
184
+ };
185
+
120
186
  $._hooks.preRender.push(() => {
121
- if (!$.imageStack.length) return;
187
+ if (!$._textureBindGroups.length) return;
122
188
 
123
189
  // Switch to image pipeline
124
190
  $.pass.setPipeline($.pipelines[1]);
125
191
 
126
192
  // Create a vertex buffer for the image quads
127
- const vertices = new Float32Array($.vertexStack);
193
+ const vertices = new Float32Array(verticesStack);
128
194
 
129
195
  const vertexBuffer = Q5.device.createBuffer({
130
196
  size: vertices.byteLength,
@@ -132,56 +198,10 @@ fn fragmentMain(@location(0) texCoord: vec2<f32>, @location(1) textureIndex: f32
132
198
  });
133
199
 
134
200
  Q5.device.queue.writeBuffer(vertexBuffer, 0, vertices);
135
- $.pass.setVertexBuffer(0, vertexBuffer);
136
-
137
- // Set the bind group for the sampler and textures
138
- if ($.textures.length !== previousTextureCount) {
139
- previousTextureCount = $.textures.length;
140
-
141
- // Create the bind group for all textures
142
- const textureViews = $.textures.map((tex) => tex.createView());
143
-
144
- $.textureBindGroup = Q5.device.createBindGroup({
145
- layout: $.pipelines[1].getBindGroupLayout(0),
146
- entries: [
147
- { binding: 0, resource: $.sampler },
148
- ...textureViews.map((view, i) => ({ binding: i + 1, resource: view }))
149
- ]
150
- });
151
- }
152
-
153
- // Set the bind group for the sampler and textures
154
- $.pass.setBindGroup(0, $.textureBindGroup);
201
+ $.pass.setVertexBuffer(1, vertexBuffer);
155
202
  });
156
203
 
157
- $.image = (img, x, y, w, h) => {
158
- if ($._matrixDirty) $._saveMatrix();
159
- let ti = $._transformIndex;
160
-
161
- $.imageStack.push(img.index);
162
-
163
- // Calculate half-width and half-height
164
- let hw = w / 2;
165
- let hh = h / 2;
166
-
167
- // Calculate vertices positions
168
- let left = x - hw;
169
- let right = x + hw;
170
- let top = -(y - hh); // y is inverted in WebGPU
171
- let bottom = -(y + hh);
172
-
173
- let ii = img.index;
174
-
175
- // prettier-ignore
176
- $.vertexStack.push(
177
- left, top, 0, 0, ti, ii,
178
- right, top, 1, 0, ti, ii,
179
- left, bottom, 0, 1, ti, ii,
180
- right, top, 1, 0, ti, ii,
181
- left, bottom, 0, 1, ti, ii,
182
- right, bottom, 1, 1, ti, ii
183
- );
184
-
185
- $.drawStack.push(6);
186
- };
204
+ $._hooks.postRender.push(() => {
205
+ verticesStack.length = 0;
206
+ });
187
207
  };