q5 2.5.5 → 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,39 +1,45 @@
1
1
  Q5.renderers.webgpu.drawing = ($, q) => {
2
- let c = $.canvas;
3
-
4
- let drawStack = $.drawStack;
5
- let colorsStack = $.colorsStack;
6
-
7
- let verticesStack = [];
8
-
9
- let colorIndex, colorsLayout;
2
+ let c = $.canvas,
3
+ drawStack = $.drawStack,
4
+ vertexStack = new Float32Array(1e7),
5
+ indexStack = new Uint32Array(1e6),
6
+ vertIndex = 0,
7
+ vertCount = 0,
8
+ idxBufferIndex = 0,
9
+ colorIndex;
10
10
 
11
11
  let vertexShader = Q5.device.createShaderModule({
12
12
  label: 'drawingVertexShader',
13
13
  code: `
14
+ struct VertexInput {
15
+ @location(0) pos: vec2f,
16
+ @location(1) colorIndex: f32,
17
+ @location(2) transformIndex: f32
18
+ }
14
19
  struct VertexOutput {
15
20
  @builtin(position) position: vec4f,
16
- @location(0) colorIndex: f32
17
- };
18
-
21
+ @location(0) color: vec4f
22
+ }
19
23
  struct Uniforms {
20
24
  halfWidth: f32,
21
25
  halfHeight: f32
22
- };
26
+ }
23
27
 
24
28
  @group(0) @binding(0) var<uniform> uniforms: Uniforms;
25
- @group(0) @binding(1) var<storage, read> transforms: array<mat4x4<f32>>;
29
+ @group(0) @binding(1) var<storage> transforms: array<mat4x4<f32>>;
30
+
31
+ @group(1) @binding(0) var<storage> colors : array<vec4f>;
26
32
 
27
33
  @vertex
28
- fn vertexMain(@location(0) pos: vec2f, @location(1) colorIndex: f32, @location(2) transformIndex: f32) -> VertexOutput {
29
- var vert = vec4f(pos, 0.0, 1.0);
30
- vert = transforms[i32(transformIndex)] * vert;
34
+ fn vertexMain(input: VertexInput) -> VertexOutput {
35
+ var vert = vec4f(input.pos, 0.0, 1.0);
36
+ vert = transforms[i32(input.transformIndex)] * vert;
31
37
  vert.x /= uniforms.halfWidth;
32
38
  vert.y /= uniforms.halfHeight;
33
39
 
34
40
  var output: VertexOutput;
35
41
  output.position = vert;
36
- output.colorIndex = colorIndex;
42
+ output.color = colors[i32(input.colorIndex)];
37
43
  return output;
38
44
  }
39
45
  `
@@ -42,32 +48,13 @@ fn vertexMain(@location(0) pos: vec2f, @location(1) colorIndex: f32, @location(2
42
48
  let fragmentShader = Q5.device.createShaderModule({
43
49
  label: 'drawingFragmentShader',
44
50
  code: `
45
- @group(1) @binding(0) var<storage, read> colors : array<vec4f>;
46
-
47
51
  @fragment
48
- fn fragmentMain(@location(0) colorIndex: f32) -> @location(0) vec4f {
49
- let index = i32(colorIndex);
50
- return mix(colors[index], colors[index + 1], fract(colorIndex));
52
+ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
53
+ return color;
51
54
  }
52
55
  `
53
56
  });
54
57
 
55
- colorsLayout = Q5.device.createBindGroupLayout({
56
- label: 'colorsLayout',
57
- entries: [
58
- {
59
- binding: 0,
60
- visibility: GPUShaderStage.FRAGMENT,
61
- buffer: {
62
- type: 'read-only-storage',
63
- hasDynamicOffset: false
64
- }
65
- }
66
- ]
67
- });
68
-
69
- $.bindGroupLayouts.push(colorsLayout);
70
-
71
58
  let vertexBufferLayout = {
72
59
  arrayStride: 16, // 2 coordinates + 1 color index + 1 transform index * 4 bytes each
73
60
  attributes: [
@@ -77,193 +64,212 @@ fn fragmentMain(@location(0) colorIndex: f32) -> @location(0) vec4f {
77
64
  ]
78
65
  };
79
66
 
80
- // prettier-ignore
81
- let blendFactors = [
82
- 'zero', // 0
83
- 'one', // 1
84
- 'src-alpha', // 2
85
- 'one-minus-src-alpha', // 3
86
- 'dst', // 4
87
- 'dst-alpha', // 5
88
- 'one-minus-dst-alpha', // 6
89
- 'one-minus-src' // 7
90
- ];
91
- let blendOps = [
92
- 'add', // 0
93
- 'subtract', // 1
94
- 'reverse-subtract', // 2
95
- 'min', // 3
96
- 'max' // 4
97
- ];
98
-
99
- const blendModes = {
100
- normal: [2, 3, 0, 2, 3, 0],
101
- lighter: [2, 1, 0, 2, 1, 0],
102
- subtract: [2, 1, 2, 2, 1, 2],
103
- multiply: [4, 0, 0, 5, 0, 0],
104
- screen: [1, 3, 0, 1, 3, 0],
105
- darken: [1, 3, 3, 1, 3, 3],
106
- lighten: [1, 3, 4, 1, 3, 4],
107
- overlay: [2, 3, 0, 2, 3, 0],
108
- hard_light: [2, 3, 0, 2, 3, 0],
109
- soft_light: [2, 3, 0, 2, 3, 0],
110
- difference: [2, 3, 2, 2, 3, 2],
111
- exclusion: [2, 3, 0, 2, 3, 0],
112
- color_dodge: [1, 7, 0, 1, 7, 0],
113
- color_burn: [6, 1, 0, 6, 1, 0],
114
- linear_dodge: [2, 1, 0, 2, 1, 0],
115
- linear_burn: [2, 7, 1, 2, 7, 1],
116
- vivid_light: [2, 7, 0, 2, 7, 0],
117
- pin_light: [2, 7, 0, 2, 7, 0],
118
- hard_mix: [2, 7, 0, 2, 7, 0]
119
- };
120
-
121
- $.blendConfigs = {};
122
-
123
- for (const [name, mode] of Object.entries(blendModes)) {
124
- $.blendConfigs[name] = {
125
- color: {
126
- srcFactor: blendFactors[mode[0]],
127
- dstFactor: blendFactors[mode[1]],
128
- operation: blendOps[mode[2]]
129
- },
130
- alpha: {
131
- srcFactor: blendFactors[mode[3]],
132
- dstFactor: blendFactors[mode[4]],
133
- operation: blendOps[mode[5]]
134
- }
135
- };
136
- }
137
-
138
- $._blendMode = 'normal';
139
- $.blendMode = (mode) => {
140
- if (mode == $._blendMode) return;
141
- if (mode == 'source-over') mode = 'normal';
142
- mode = mode.toLowerCase().replace(/[ -]/g, '_');
143
- $._blendMode = mode;
144
- $.pipelines[0] = $._createPipeline($.blendConfigs[mode]);
145
- };
146
-
147
67
  let pipelineLayout = Q5.device.createPipelineLayout({
148
68
  label: 'drawingPipelineLayout',
149
69
  bindGroupLayouts: $.bindGroupLayouts
150
70
  });
151
71
 
152
- $._createPipeline = (blendConfig) => {
153
- return Q5.device.createRenderPipeline({
154
- label: 'drawingPipeline',
155
- layout: pipelineLayout,
156
- vertex: {
157
- module: vertexShader,
158
- entryPoint: 'vertexMain',
159
- buffers: [vertexBufferLayout]
160
- },
161
- fragment: {
162
- module: fragmentShader,
163
- entryPoint: 'fragmentMain',
164
- targets: [{ format: 'bgra8unorm', blend: blendConfig }]
165
- },
166
- primitive: { topology: 'triangle-list' }
167
- });
72
+ $._pipelineConfigs[0] = {
73
+ label: 'drawingPipeline',
74
+ layout: pipelineLayout,
75
+ vertex: {
76
+ module: vertexShader,
77
+ entryPoint: 'vertexMain',
78
+ buffers: [vertexBufferLayout]
79
+ },
80
+ fragment: {
81
+ module: fragmentShader,
82
+ entryPoint: 'fragmentMain',
83
+ targets: [{ format: 'bgra8unorm', blend: $.blendConfigs.normal }]
84
+ },
85
+ primitive: { topology: 'triangle-list' },
86
+ multisample: {
87
+ count: 4
88
+ }
168
89
  };
169
90
 
170
- $.pipelines[0] = $._createPipeline($.blendConfigs.normal);
171
-
172
- let shapeVertices;
91
+ $._pipelines[0] = Q5.device.createRenderPipeline($._pipelineConfigs[0]);
92
+
93
+ const addVert = (x, y, ci, ti) => {
94
+ let v = vertexStack,
95
+ i = vertIndex;
96
+ v[i++] = x;
97
+ v[i++] = y;
98
+ v[i++] = ci;
99
+ v[i++] = ti;
100
+ vertIndex = i;
101
+ vertCount++;
102
+ };
173
103
 
174
- $.beginShape = () => {
175
- shapeVertices = [];
104
+ const addIndex = (i1, i2, i3) => {
105
+ let is = indexStack,
106
+ ii = idxBufferIndex;
107
+ is[ii++] = i1;
108
+ is[ii++] = i2;
109
+ is[ii++] = i3;
110
+ idxBufferIndex = ii;
176
111
  };
177
112
 
178
- $.vertex = (x, y) => {
179
- if ($._matrixDirty) $._saveMatrix();
180
- shapeVertices.push(x, -y, $._fillIndex, $._transformIndex);
113
+ const addQuad = (x1, y1, x2, y2, x3, y3, x4, y4, ci, ti) => {
114
+ let v = vertexStack,
115
+ i = vertIndex;
116
+
117
+ let i1 = vertCount++;
118
+ v[i++] = x1;
119
+ v[i++] = y1;
120
+ v[i++] = ci;
121
+ v[i++] = ti;
122
+
123
+ let i2 = vertCount++;
124
+ v[i++] = x2;
125
+ v[i++] = y2;
126
+ v[i++] = ci;
127
+ v[i++] = ti;
128
+
129
+ let i3 = vertCount++;
130
+ v[i++] = x3;
131
+ v[i++] = y3;
132
+ v[i++] = ci;
133
+ v[i++] = ti;
134
+
135
+ let i4 = vertCount++;
136
+ v[i++] = x4;
137
+ v[i++] = y4;
138
+ v[i++] = ci;
139
+ v[i++] = ti;
140
+
141
+ vertIndex = i;
142
+
143
+ let is = indexStack,
144
+ ii = idxBufferIndex;
145
+ is[ii++] = i1;
146
+ is[ii++] = i2;
147
+ is[ii++] = i3;
148
+ is[ii++] = i1;
149
+ is[ii++] = i3;
150
+ is[ii++] = i4;
151
+ idxBufferIndex = ii;
152
+
153
+ drawStack.push(0, 6, 4);
181
154
  };
182
155
 
183
- $.endShape = (close) => {
184
- if (!$._doFill) {
185
- shapeVertices = [];
186
- return;
187
- }
188
- let v = shapeVertices;
189
- if (v.length < 12) {
190
- throw new Error('A shape must have at least 3 vertices.');
191
- }
192
- if (close) {
193
- // Close the shape by adding the first vertex at the end
194
- v.push(v[0], v[1], v[2], v[3]);
156
+ const addEllipse = (x, y, a, b, n, ci, ti) => {
157
+ let t = 0,
158
+ angleIncrement = $.TAU / n,
159
+ indicesStart = vertIndex / 4;
160
+ addVert(x, y, ci, ti); // Center vertex
161
+ for (let i = 0; i <= n; i++) {
162
+ let vx = x + a * Math.cos(t),
163
+ vy = y + b * Math.sin(t);
164
+ addVert(vx, vy, ci, ti);
165
+ if (i > 0) {
166
+ addIndex(indicesStart, indicesStart + i, indicesStart + i + 1);
167
+ }
168
+ t += angleIncrement;
195
169
  }
196
- // Convert the shape to triangles
197
- let triangles = [];
198
- for (let i = 4; i < v.length; i += 4) {
199
- triangles.push(
200
- v[0], // First vertex
201
- v[1],
202
- v[2],
203
- v[3],
204
- v[i - 4], // Previous vertex
205
- v[i - 3],
206
- v[i - 2],
207
- v[i - 1],
208
- v[i], // Current vertex
209
- v[i + 1],
210
- v[i + 2],
211
- v[i + 3]
212
- );
170
+ drawStack.push(0, n * 3, n + 2);
171
+ };
172
+
173
+ $.rectMode = (x) => ($._rectMode = x);
174
+
175
+ $.rect = (x, y, w, h) => {
176
+ let [l, r, t, b] = $._calcBox(x, y, w, h, $._rectMode);
177
+ let ci, ti;
178
+ if ($._matrixDirty) $._saveMatrix();
179
+ ti = $._transformIndex;
180
+
181
+ if ($._doStroke) {
182
+ ci = $._strokeIndex;
183
+
184
+ // outer rectangle coordinates
185
+ let sw = $._strokeWeight / 2;
186
+ let to = t + sw,
187
+ bo = b - sw,
188
+ lo = l - sw,
189
+ ro = r + sw;
190
+
191
+ // stroke is simply a bigger rectangle drawn first
192
+ addQuad(lo, to, ro, to, ro, bo, lo, bo, ci, ti);
193
+
194
+ // inner rectangle coordinates
195
+ t -= sw;
196
+ b += sw;
197
+ l += sw;
198
+ r -= sw;
213
199
  }
214
- shapeVertices = [];
215
200
 
216
- verticesStack.push(...triangles);
217
- drawStack.push(0, triangles.length / 4);
218
- };
201
+ if ($._doFill) {
202
+ ci = colorIndex ?? $._fillIndex;
219
203
 
220
- $.triangle = (x1, y1, x2, y2, x3, y3) => {
221
- $.beginShape();
222
- $.vertex(x1, y1);
223
- $.vertex(x2, y2);
224
- $.vertex(x3, y3);
225
- $.endShape(1);
204
+ // two triangles make a rectangle
205
+ addQuad(l, t, r, t, r, b, l, b, ci, ti);
206
+ }
226
207
  };
227
208
 
228
- $.quad = (x1, y1, x2, y2, x3, y3, x4, y4) => {
229
- $.beginShape();
230
- $.vertex(x1, y1);
231
- $.vertex(x2, y2);
232
- $.vertex(x3, y3);
233
- $.vertex(x4, y4);
234
- $.endShape(1);
235
- };
209
+ $.square = (x, y, s) => $.rect(x, y, s, s);
236
210
 
237
- $.rectMode = (x) => ($._rectMode = x);
211
+ // prettier-ignore
212
+ const getArcSegments = (d) =>
213
+ d < 4 ? 6 :
214
+ d < 6 ? 8 :
215
+ d < 10 ? 10 :
216
+ d < 16 ? 12 :
217
+ d < 20 ? 14 :
218
+ d < 22 ? 16 :
219
+ d < 24 ? 18 :
220
+ d < 28 ? 20 :
221
+ d < 34 ? 22 :
222
+ d < 42 ? 24 :
223
+ d < 48 ? 26 :
224
+ d < 56 ? 28 :
225
+ d < 64 ? 30 :
226
+ d < 72 ? 32 :
227
+ d < 84 ? 34 :
228
+ d < 96 ? 36 :
229
+ d < 98 ? 38 :
230
+ d < 113 ? 40 :
231
+ d < 149 ? 44 :
232
+ d < 199 ? 48 :
233
+ d < 261 ? 52 :
234
+ d < 353 ? 56 :
235
+ d < 461 ? 60 :
236
+ d < 585 ? 64 :
237
+ d < 1200 ? 70 :
238
+ d < 1800 ? 80 :
239
+ d < 2400 ? 90 :
240
+ 100;
238
241
 
239
- $.rect = (x, y, w, h) => {
240
- let [l, r, t, b] = $._calcBox(x, y, w, h, $._rectMode);
242
+ $.ellipseMode = (x) => ($._ellipseMode = x);
241
243
 
242
- let ci = colorIndex ?? $._fillIndex;
244
+ $.ellipse = (x, y, w, h) => {
245
+ let n = getArcSegments(w == h ? w : Math.max(w, h));
246
+ let a = Math.max(w, 1) / 2;
247
+ let b = w == h ? a : Math.max(h, 1) / 2;
248
+ let ci;
243
249
  if ($._matrixDirty) $._saveMatrix();
244
250
  let ti = $._transformIndex;
245
- // two triangles make a rectangle
246
- // prettier-ignore
247
- verticesStack.push(
248
- l, t, ci, ti,
249
- r, t, ci, ti,
250
- l, b, ci, ti,
251
- r, t, ci, ti,
252
- l, b, ci, ti,
253
- r, b, ci, ti
254
- );
255
- drawStack.push(0, 6);
251
+ if ($._doStroke) {
252
+ let sw = $._strokeWeight / 2;
253
+ addEllipse(x, y, a + sw, b + sw, n, $._strokeIndex, ti);
254
+ a -= sw;
255
+ b -= sw;
256
+ }
257
+ if ($._doFill) {
258
+ addEllipse(x, y, a, b, n, colorIndex ?? $._fillIndex, ti);
259
+ }
256
260
  };
257
261
 
258
- $.square = (x, y, s) => $.rect(x, y, s, s);
262
+ $.circle = (x, y, d) => $.ellipse(x, y, d, d);
259
263
 
260
264
  $.point = (x, y) => {
261
265
  colorIndex = $._strokeIndex;
266
+ $._doStroke = false;
262
267
  let sw = $._strokeWeight;
263
268
  if (sw < 2) {
264
269
  sw = Math.round(sw);
265
270
  $.rect(x, y, sw, sw);
266
271
  } else $.ellipse(x, y, sw, sw);
272
+ $._doStroke = true;
267
273
  colorIndex = null;
268
274
  };
269
275
 
@@ -271,19 +277,97 @@ fn fragmentMain(@location(0) colorIndex: f32) -> @location(0) vec4f {
271
277
  colorIndex = $._strokeIndex;
272
278
 
273
279
  $.push();
274
- $.translate(x1, y1);
280
+ $._doStroke = false;
281
+ $.translate(x1, -y1);
275
282
  $.rotate($.atan2(y2 - y1, x2 - x1));
276
283
  let length = Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
277
- let sw = $._strokeWeight;
278
- $.rect(0, -sw / 2, length, sw);
284
+ let sw = $._strokeWeight,
285
+ hsw = sw / 2;
286
+ $._rectMode = 'corner';
287
+ if (sw < 4) {
288
+ $.rect(-hsw, -hsw, length + hsw, sw);
289
+ } else {
290
+ $._ellipseMode = 'center';
291
+ $.ellipse(0, 0, sw, sw);
292
+ $.ellipse(length, 0, sw, sw);
293
+ $.rect(0, -hsw, length, sw);
294
+ }
295
+
279
296
  $.pop();
280
297
 
281
298
  colorIndex = null;
282
299
  };
283
300
 
301
+ let shapeVertCount;
302
+
303
+ $.beginShape = () => {
304
+ shapeVertCount = 0;
305
+ };
306
+
307
+ $.vertex = (x, y) => {
308
+ if ($._matrixDirty) $._saveMatrix();
309
+ addVert(x, -y, $._fillIndex, $._transformIndex);
310
+ shapeVertCount++;
311
+ };
312
+
313
+ $.endShape = (close) => {
314
+ if (shapeVertCount < 3) {
315
+ throw new Error('A shape must have at least 3 vertices.');
316
+ }
317
+
318
+ let firstVert = vertCount - shapeVertCount;
319
+
320
+ if ($._doFill) {
321
+ // make a simple triangle fan, starting from the first vertex
322
+ for (let i = firstVert + 1; i < vertCount - 1; i++) {
323
+ addIndex(firstVert, i, i + 1);
324
+ }
325
+ drawStack.push(0, (shapeVertCount - 2) * 3, shapeVertCount);
326
+ }
327
+
328
+ if ($._doStroke) {
329
+ let first = firstVert * 4,
330
+ last = vertIndex - 4;
331
+ for (let i = first; i < last; i += 4) {
332
+ let x1 = vertexStack[i],
333
+ y1 = vertexStack[i + 1],
334
+ x2 = vertexStack[i + 4],
335
+ y2 = vertexStack[i + 5];
336
+ $.line(x1, y1, x2, y2);
337
+ }
338
+ if (close) {
339
+ let x1 = vertexStack[last],
340
+ y1 = vertexStack[last + 1],
341
+ x2 = vertexStack[first],
342
+ y2 = vertexStack[first + 1];
343
+ $.line(x1, y1, x2, y2);
344
+ }
345
+ }
346
+
347
+ shapeVertCount = 0;
348
+ };
349
+
350
+ $.triangle = (x1, y1, x2, y2, x3, y3) => {
351
+ $.beginShape();
352
+ $.vertex(x1, y1);
353
+ $.vertex(x2, y2);
354
+ $.vertex(x3, y3);
355
+ $.endShape();
356
+ };
357
+
358
+ $.quad = (x1, y1, x2, y2, x3, y3, x4, y4) => {
359
+ $.beginShape();
360
+ $.vertex(x1, y1);
361
+ $.vertex(x2, y2);
362
+ $.vertex(x3, y3);
363
+ $.vertex(x4, y4);
364
+ $.endShape();
365
+ };
366
+
284
367
  $.background = (r, g, b, a) => {
285
368
  $.push();
286
369
  $.resetMatrix();
370
+ $._doStroke = false;
287
371
  if (r.src) {
288
372
  let og = $._imageMode;
289
373
  $._imageMode = 'corner';
@@ -297,115 +381,38 @@ fn fragmentMain(@location(0) colorIndex: f32) -> @location(0) vec4f {
297
381
  $._rectMode = og;
298
382
  }
299
383
  $.pop();
384
+ if (!$._fillSet) $._fillIndex = 1;
300
385
  };
301
386
 
302
- /**
303
- * Derived from: ceil(Math.log(d) * 7) * 2 - ceil(28)
304
- * This lookup table is used for better performance.
305
- * @param {Number} d diameter of the circle
306
- * @returns n number of segments
307
- */
308
- // prettier-ignore
309
- const getArcSegments = (d) =>
310
- d < 4 ? 6 :
311
- d < 6 ? 8 :
312
- d < 10 ? 10 :
313
- d < 16 ? 12 :
314
- d < 20 ? 14 :
315
- d < 22 ? 16 :
316
- d < 24 ? 18 :
317
- d < 28 ? 20 :
318
- d < 34 ? 22 :
319
- d < 42 ? 24 :
320
- d < 48 ? 26 :
321
- d < 56 ? 28 :
322
- d < 64 ? 30 :
323
- d < 72 ? 32 :
324
- d < 84 ? 34 :
325
- d < 96 ? 36 :
326
- d < 98 ? 38 :
327
- d < 113 ? 40 :
328
- d < 149 ? 44 :
329
- d < 199 ? 48 :
330
- d < 261 ? 52 :
331
- d < 353 ? 56 :
332
- d < 461 ? 60 :
333
- d < 585 ? 64 :
334
- d < 1200 ? 70 :
335
- d < 1800 ? 80 :
336
- d < 2400 ? 90 :
337
- 100;
338
-
339
- $.ellipseMode = (x) => ($._ellipseMode = x);
340
-
341
- $.ellipse = (x, y, w, h) => {
342
- const n = getArcSegments(w == h ? w : Math.max(w, h));
343
-
344
- let a = Math.max(w, 1) / 2;
345
- let b = w == h ? a : Math.max(h, 1) / 2;
346
-
347
- let t = 0; // theta
348
- const angleIncrement = $.TAU / n;
349
- const ci = colorIndex ?? $._fillIndex;
350
- if ($._matrixDirty) $._saveMatrix();
351
- const ti = $._transformIndex;
352
- let vx1, vy1, vx2, vy2;
353
- for (let i = 0; i <= n; i++) {
354
- vx1 = vx2;
355
- vy1 = vy2;
356
- vx2 = x + a * Math.cos(t);
357
- vy2 = y + b * Math.sin(t);
358
- t += angleIncrement;
359
-
360
- if (i == 0) continue;
361
-
362
- verticesStack.push(x, y, ci, ti, vx1, vy1, ci, ti, vx2, vy2, ci, ti);
363
- }
364
-
365
- drawStack.push(0, n * 3);
366
- };
367
-
368
- $.circle = (x, y, d) => $.ellipse(x, y, d, d);
369
-
370
387
  $._hooks.preRender.push(() => {
371
- $.pass.setPipeline($.pipelines[0]);
372
-
373
- const vertices = new Float32Array(verticesStack);
388
+ $.pass.setPipeline($._pipelines[0]);
374
389
 
375
- const vertexBuffer = Q5.device.createBuffer({
376
- size: vertices.byteLength,
377
- usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
390
+ let vertexBuffer = Q5.device.createBuffer({
391
+ size: vertIndex * 4,
392
+ usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
393
+ mappedAtCreation: true
378
394
  });
379
395
 
380
- Q5.device.queue.writeBuffer(vertexBuffer, 0, vertices);
396
+ new Float32Array(vertexBuffer.getMappedRange()).set(vertexStack.slice(0, vertIndex));
397
+ vertexBuffer.unmap();
398
+
381
399
  $.pass.setVertexBuffer(0, vertexBuffer);
382
400
 
383
- const colorsBuffer = Q5.device.createBuffer({
384
- size: colorsStack.length * 4,
385
- usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
401
+ let indexBuffer = Q5.device.createBuffer({
402
+ size: idxBufferIndex * 4,
403
+ usage: GPUBufferUsage.INDEX | GPUBufferUsage.COPY_DST,
404
+ mappedAtCreation: true
386
405
  });
387
406
 
388
- Q5.device.queue.writeBuffer(colorsBuffer, 0, new Float32Array(colorsStack));
389
-
390
- $._colorsBindGroup = Q5.device.createBindGroup({
391
- layout: colorsLayout,
392
- entries: [
393
- {
394
- binding: 0,
395
- resource: {
396
- buffer: colorsBuffer,
397
- offset: 0,
398
- size: colorsStack.length * 4
399
- }
400
- }
401
- ]
402
- });
407
+ new Uint32Array(indexBuffer.getMappedRange()).set(indexStack.slice(0, idxBufferIndex));
408
+ indexBuffer.unmap();
403
409
 
404
- // set the bind group once before rendering
405
- $.pass.setBindGroup(1, $._colorsBindGroup);
410
+ $.pass.setIndexBuffer(indexBuffer, 'uint32');
406
411
  });
407
412
 
408
413
  $._hooks.postRender.push(() => {
409
- verticesStack.length = 0;
414
+ vertIndex = 0;
415
+ vertCount = 0;
416
+ idxBufferIndex = 0;
410
417
  });
411
418
  };