q5 2.4.5 → 2.5.0
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/README.md +5 -2
- package/package.json +1 -1
- package/q5.d.ts +27 -4
- package/q5.js +939 -275
- package/q5.min.js +1 -1
- package/src/q5-2d-canvas.js +10 -19
- package/src/q5-2d-text.js +162 -127
- package/src/q5-canvas.js +11 -7
- package/src/q5-core.js +2 -2
- package/src/q5-util.js +17 -1
- package/src/q5-webgpu-canvas.js +81 -64
- package/src/q5-webgpu-drawing.js +21 -13
- package/src/q5-webgpu-image.js +33 -16
- package/src/q5-webgpu-text.js +601 -25
- package/src/readme.md +76 -9
package/src/q5-webgpu-canvas.js
CHANGED
|
@@ -24,7 +24,8 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
24
24
|
// colors used for each draw call
|
|
25
25
|
let colorsStack = ($.colorsStack = [1, 1, 1, 1]);
|
|
26
26
|
|
|
27
|
-
$.
|
|
27
|
+
$._transformLayout = Q5.device.createBindGroupLayout({
|
|
28
|
+
label: 'transformLayout',
|
|
28
29
|
entries: [
|
|
29
30
|
{
|
|
30
31
|
binding: 0,
|
|
@@ -33,14 +34,9 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
33
34
|
type: 'uniform',
|
|
34
35
|
hasDynamicOffset: false
|
|
35
36
|
}
|
|
36
|
-
}
|
|
37
|
-
]
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
$._transformLayout = Q5.device.createBindGroupLayout({
|
|
41
|
-
entries: [
|
|
37
|
+
},
|
|
42
38
|
{
|
|
43
|
-
binding:
|
|
39
|
+
binding: 1,
|
|
44
40
|
visibility: GPUShaderStage.VERTEX,
|
|
45
41
|
buffer: {
|
|
46
42
|
type: 'read-only-storage',
|
|
@@ -50,9 +46,9 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
50
46
|
]
|
|
51
47
|
});
|
|
52
48
|
|
|
53
|
-
$.bindGroupLayouts = [$.
|
|
49
|
+
$.bindGroupLayouts = [$._transformLayout];
|
|
54
50
|
|
|
55
|
-
|
|
51
|
+
let uniformBuffer = Q5.device.createBuffer({
|
|
56
52
|
size: 8, // Size of two floats
|
|
57
53
|
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
58
54
|
});
|
|
@@ -60,25 +56,13 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
60
56
|
$._createCanvas = (w, h, opt) => {
|
|
61
57
|
q.ctx = q.drawingContext = c.getContext('webgpu');
|
|
62
58
|
|
|
63
|
-
opt.format
|
|
64
|
-
opt.device
|
|
59
|
+
opt.format ??= navigator.gpu.getPreferredCanvasFormat();
|
|
60
|
+
opt.device ??= Q5.device;
|
|
65
61
|
|
|
66
62
|
$.ctx.configure(opt);
|
|
67
63
|
|
|
68
64
|
Q5.device.queue.writeBuffer(uniformBuffer, 0, new Float32Array([$.canvas.hw, $.canvas.hh]));
|
|
69
65
|
|
|
70
|
-
$._envBindGroup = Q5.device.createBindGroup({
|
|
71
|
-
layout: $._envLayout,
|
|
72
|
-
entries: [
|
|
73
|
-
{
|
|
74
|
-
binding: 0,
|
|
75
|
-
resource: {
|
|
76
|
-
buffer: uniformBuffer
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
]
|
|
80
|
-
});
|
|
81
|
-
|
|
82
66
|
return c;
|
|
83
67
|
};
|
|
84
68
|
|
|
@@ -88,7 +72,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
88
72
|
|
|
89
73
|
// current color index, used to associate a vertex with a color
|
|
90
74
|
let colorIndex = 0;
|
|
91
|
-
|
|
75
|
+
let addColor = (r, g, b, a = 1) => {
|
|
92
76
|
if (typeof r == 'string') r = $.color(r);
|
|
93
77
|
else if (b == undefined) {
|
|
94
78
|
// grayscale mode `fill(1, 0.5)`
|
|
@@ -100,6 +84,8 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
100
84
|
colorIndex++;
|
|
101
85
|
};
|
|
102
86
|
|
|
87
|
+
$._fillIndex = $._strokeIndex = -1;
|
|
88
|
+
|
|
103
89
|
$.fill = (r, g, b, a) => {
|
|
104
90
|
addColor(r, g, b, a);
|
|
105
91
|
$._doFill = true;
|
|
@@ -131,56 +117,70 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
131
117
|
};
|
|
132
118
|
$.resetMatrix();
|
|
133
119
|
|
|
134
|
-
//
|
|
120
|
+
// tracks if the matrix has been modified
|
|
135
121
|
$._matrixDirty = false;
|
|
136
122
|
|
|
137
|
-
//
|
|
123
|
+
// array to store transformation matrices for the render pass
|
|
138
124
|
$.transformStates = [$._matrix.slice()];
|
|
139
125
|
|
|
140
|
-
//
|
|
126
|
+
// stack to keep track of transformation matrix indexes
|
|
141
127
|
$._transformIndexStack = [];
|
|
142
128
|
|
|
143
129
|
$.translate = (x, y, z) => {
|
|
144
130
|
if (!x && !y && !z) return;
|
|
145
131
|
// Update the translation values
|
|
146
|
-
$._matrix[
|
|
147
|
-
$._matrix[
|
|
148
|
-
$._matrix[
|
|
132
|
+
$._matrix[12] += x;
|
|
133
|
+
$._matrix[13] -= y;
|
|
134
|
+
$._matrix[14] += z || 0;
|
|
149
135
|
$._matrixDirty = true;
|
|
150
136
|
};
|
|
151
137
|
|
|
152
|
-
$.rotate = (
|
|
153
|
-
if (!
|
|
154
|
-
if ($._angleMode)
|
|
138
|
+
$.rotate = (a) => {
|
|
139
|
+
if (!a) return;
|
|
140
|
+
if ($._angleMode) a *= $._DEGTORAD;
|
|
155
141
|
|
|
156
|
-
let cosR = Math.cos(
|
|
157
|
-
let sinR = Math.sin(
|
|
142
|
+
let cosR = Math.cos(a);
|
|
143
|
+
let sinR = Math.sin(a);
|
|
144
|
+
|
|
145
|
+
let m = $._matrix;
|
|
146
|
+
|
|
147
|
+
let m0 = m[0],
|
|
148
|
+
m1 = m[1],
|
|
149
|
+
m4 = m[4],
|
|
150
|
+
m5 = m[5];
|
|
158
151
|
|
|
159
|
-
let m0 = $._matrix[0],
|
|
160
|
-
m1 = $._matrix[1],
|
|
161
|
-
m4 = $._matrix[4],
|
|
162
|
-
m5 = $._matrix[5];
|
|
163
152
|
if (!m0 && !m1 && !m4 && !m5) {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
153
|
+
m[0] = cosR;
|
|
154
|
+
m[1] = sinR;
|
|
155
|
+
m[4] = -sinR;
|
|
156
|
+
m[5] = cosR;
|
|
168
157
|
} else {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
158
|
+
m[0] = m0 * cosR + m4 * sinR;
|
|
159
|
+
m[1] = m1 * cosR + m5 * sinR;
|
|
160
|
+
m[4] = m4 * cosR - m0 * sinR;
|
|
161
|
+
m[5] = m5 * cosR - m1 * sinR;
|
|
173
162
|
}
|
|
174
163
|
|
|
175
164
|
$._matrixDirty = true;
|
|
176
165
|
};
|
|
177
166
|
|
|
178
|
-
$.scale = (
|
|
179
|
-
|
|
167
|
+
$.scale = (x = 1, y, z = 1) => {
|
|
168
|
+
y ??= x;
|
|
169
|
+
|
|
170
|
+
let m = $._matrix;
|
|
180
171
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
172
|
+
m[0] *= x;
|
|
173
|
+
m[1] *= x;
|
|
174
|
+
m[2] *= x;
|
|
175
|
+
m[3] *= x;
|
|
176
|
+
m[4] *= y;
|
|
177
|
+
m[5] *= y;
|
|
178
|
+
m[6] *= y;
|
|
179
|
+
m[7] *= y;
|
|
180
|
+
m[8] *= z;
|
|
181
|
+
m[9] *= z;
|
|
182
|
+
m[10] *= z;
|
|
183
|
+
m[11] *= z;
|
|
184
184
|
|
|
185
185
|
$._matrixDirty = true;
|
|
186
186
|
};
|
|
@@ -252,7 +252,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
252
252
|
if (!$._transformIndexStack.length) {
|
|
253
253
|
return console.warn('Matrix index stack is empty!');
|
|
254
254
|
}
|
|
255
|
-
// Pop the last matrix index
|
|
255
|
+
// Pop the last matrix index and set it as the current matrix index
|
|
256
256
|
let idx = $._transformIndexStack.pop();
|
|
257
257
|
$._matrix = $.transformStates[idx].slice();
|
|
258
258
|
$._transformIndex = idx;
|
|
@@ -275,7 +275,6 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
275
275
|
// left, right, top, bottom
|
|
276
276
|
let l, r, t, b;
|
|
277
277
|
if (!mode || mode == 'corner') {
|
|
278
|
-
// CORNER
|
|
279
278
|
l = x;
|
|
280
279
|
r = x + w;
|
|
281
280
|
t = -y;
|
|
@@ -315,7 +314,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
315
314
|
|
|
316
315
|
$._render = () => {
|
|
317
316
|
if (transformStates.length > 1 || !$._transformBindGroup) {
|
|
318
|
-
|
|
317
|
+
let transformBuffer = Q5.device.createBuffer({
|
|
319
318
|
size: transformStates.length * 64, // Size of 16 floats
|
|
320
319
|
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
|
|
321
320
|
});
|
|
@@ -327,6 +326,12 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
327
326
|
entries: [
|
|
328
327
|
{
|
|
329
328
|
binding: 0,
|
|
329
|
+
resource: {
|
|
330
|
+
buffer: uniformBuffer
|
|
331
|
+
}
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
binding: 1,
|
|
330
335
|
resource: {
|
|
331
336
|
buffer: transformBuffer
|
|
332
337
|
}
|
|
@@ -335,35 +340,47 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
335
340
|
});
|
|
336
341
|
}
|
|
337
342
|
|
|
338
|
-
pass.setBindGroup(0, $.
|
|
339
|
-
pass.setBindGroup(1, $._transformBindGroup);
|
|
343
|
+
pass.setBindGroup(0, $._transformBindGroup);
|
|
340
344
|
|
|
341
345
|
for (let m of $._hooks.preRender) m();
|
|
342
346
|
|
|
343
347
|
let drawVertOffset = 0;
|
|
344
348
|
let imageVertOffset = 0;
|
|
349
|
+
let textCharOffset = 0;
|
|
345
350
|
let curPipelineIndex = -1;
|
|
346
351
|
let curTextureIndex = -1;
|
|
347
352
|
|
|
348
|
-
pass.setPipeline($.pipelines[0]);
|
|
349
|
-
|
|
350
353
|
for (let i = 0; i < drawStack.length; i += 2) {
|
|
351
354
|
let v = drawStack[i + 1];
|
|
352
355
|
|
|
356
|
+
if (drawStack[i] == -1) {
|
|
357
|
+
v();
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
|
|
353
361
|
if (curPipelineIndex != drawStack[i]) {
|
|
354
362
|
curPipelineIndex = drawStack[i];
|
|
355
363
|
pass.setPipeline($.pipelines[curPipelineIndex]);
|
|
356
364
|
}
|
|
357
365
|
|
|
358
366
|
if (curPipelineIndex == 0) {
|
|
359
|
-
|
|
367
|
+
// v is the number of vertices
|
|
368
|
+
pass.draw(v, 1, drawVertOffset);
|
|
360
369
|
drawVertOffset += v;
|
|
361
370
|
} else if (curPipelineIndex == 1) {
|
|
362
371
|
if (curTextureIndex != v) {
|
|
363
|
-
|
|
372
|
+
// v is the texture index
|
|
373
|
+
pass.setBindGroup(2, $._textureBindGroups[v]);
|
|
364
374
|
}
|
|
365
|
-
pass.draw(6, 1, imageVertOffset
|
|
375
|
+
pass.draw(6, 1, imageVertOffset);
|
|
366
376
|
imageVertOffset += 6;
|
|
377
|
+
} else if (curPipelineIndex == 2) {
|
|
378
|
+
pass.setBindGroup(2, $._font.bindGroup);
|
|
379
|
+
pass.setBindGroup(3, $._textBindGroup);
|
|
380
|
+
|
|
381
|
+
// v is the number of characters in the text
|
|
382
|
+
pass.draw(4, v, 0, textCharOffset);
|
|
383
|
+
textCharOffset += v;
|
|
367
384
|
}
|
|
368
385
|
}
|
|
369
386
|
|
|
@@ -372,7 +389,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
372
389
|
|
|
373
390
|
$._finishRender = () => {
|
|
374
391
|
pass.end();
|
|
375
|
-
|
|
392
|
+
let commandBuffer = $.encoder.finish();
|
|
376
393
|
Q5.device.queue.submit([commandBuffer]);
|
|
377
394
|
q.pass = $.encoder = null;
|
|
378
395
|
|
package/src/q5-webgpu-drawing.js
CHANGED
|
@@ -12,8 +12,8 @@ Q5.renderers.webgpu.drawing = ($, q) => {
|
|
|
12
12
|
label: 'drawingVertexShader',
|
|
13
13
|
code: `
|
|
14
14
|
struct VertexOutput {
|
|
15
|
-
@builtin(position) position:
|
|
16
|
-
@location(
|
|
15
|
+
@builtin(position) position: vec4f,
|
|
16
|
+
@location(0) colorIndex: f32
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
struct Uniforms {
|
|
@@ -22,12 +22,12 @@ struct Uniforms {
|
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
|
25
|
-
@group(
|
|
25
|
+
@group(0) @binding(1) var<storage, read> transforms: array<mat4x4<f32>>;
|
|
26
26
|
|
|
27
27
|
@vertex
|
|
28
|
-
fn vertexMain(@location(0) pos:
|
|
29
|
-
var vert =
|
|
30
|
-
vert
|
|
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;
|
|
31
31
|
vert.x /= uniforms.halfWidth;
|
|
32
32
|
vert.y /= uniforms.halfHeight;
|
|
33
33
|
|
|
@@ -42,17 +42,18 @@ fn vertexMain(@location(0) pos: vec2<f32>, @location(1) colorIndex: f32, @locati
|
|
|
42
42
|
let fragmentShader = Q5.device.createShaderModule({
|
|
43
43
|
label: 'drawingFragmentShader',
|
|
44
44
|
code: `
|
|
45
|
-
@group(
|
|
45
|
+
@group(1) @binding(0) var<storage, read> colors : array<vec4f>;
|
|
46
46
|
|
|
47
47
|
@fragment
|
|
48
|
-
fn fragmentMain(@location(
|
|
49
|
-
let index =
|
|
50
|
-
return mix(
|
|
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));
|
|
51
51
|
}
|
|
52
52
|
`
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
colorsLayout = Q5.device.createBindGroupLayout({
|
|
56
|
+
label: 'colorsLayout',
|
|
56
57
|
entries: [
|
|
57
58
|
{
|
|
58
59
|
binding: 0,
|
|
@@ -283,10 +284,17 @@ fn fragmentMain(@location(1) colorIndex: f32) -> @location(0) vec4<f32> {
|
|
|
283
284
|
$.background = (r, g, b, a) => {
|
|
284
285
|
$.push();
|
|
285
286
|
$.resetMatrix();
|
|
286
|
-
if (r.src)
|
|
287
|
-
|
|
287
|
+
if (r.src) {
|
|
288
|
+
let og = $._imageMode;
|
|
289
|
+
$._imageMode = 'corner';
|
|
290
|
+
$.image(r, -c.hw, -c.hh, c.w, c.h);
|
|
291
|
+
$._imageMode = og;
|
|
292
|
+
} else {
|
|
293
|
+
let og = $._rectMode;
|
|
294
|
+
$._rectMode = 'corner';
|
|
288
295
|
$.fill(r, g, b, a);
|
|
289
296
|
$.rect(-c.hw, -c.hh, c.w, c.h);
|
|
297
|
+
$._rectMode = og;
|
|
290
298
|
}
|
|
291
299
|
$.pop();
|
|
292
300
|
};
|
|
@@ -394,7 +402,7 @@ fn fragmentMain(@location(1) colorIndex: f32) -> @location(0) vec4<f32> {
|
|
|
394
402
|
});
|
|
395
403
|
|
|
396
404
|
// set the bind group once before rendering
|
|
397
|
-
$.pass.setBindGroup(
|
|
405
|
+
$.pass.setBindGroup(1, $._colorsBindGroup);
|
|
398
406
|
});
|
|
399
407
|
|
|
400
408
|
$._hooks.postRender.push(() => {
|
package/src/q5-webgpu-image.js
CHANGED
|
@@ -6,8 +6,8 @@ Q5.renderers.webgpu.image = ($, q) => {
|
|
|
6
6
|
label: 'imageVertexShader',
|
|
7
7
|
code: `
|
|
8
8
|
struct VertexOutput {
|
|
9
|
-
@builtin(position) position:
|
|
10
|
-
@location(0) texCoord:
|
|
9
|
+
@builtin(position) position: vec4f,
|
|
10
|
+
@location(0) texCoord: vec2f
|
|
11
11
|
};
|
|
12
12
|
|
|
13
13
|
struct Uniforms {
|
|
@@ -16,12 +16,12 @@ struct Uniforms {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
|
|
19
|
-
@group(
|
|
19
|
+
@group(0) @binding(1) var<storage, read> transforms: array<mat4x4<f32>>;
|
|
20
20
|
|
|
21
21
|
@vertex
|
|
22
|
-
fn vertexMain(@location(0) pos:
|
|
23
|
-
var vert =
|
|
24
|
-
vert
|
|
22
|
+
fn vertexMain(@location(0) pos: vec2f, @location(1) texCoord: vec2f, @location(2) transformIndex: f32) -> VertexOutput {
|
|
23
|
+
var vert = vec4f(pos, 0.0, 1.0);
|
|
24
|
+
vert = transforms[i32(transformIndex)] * vert;
|
|
25
25
|
vert.x /= uniforms.halfWidth;
|
|
26
26
|
vert.y /= uniforms.halfHeight;
|
|
27
27
|
|
|
@@ -36,11 +36,11 @@ fn vertexMain(@location(0) pos: vec2<f32>, @location(1) texCoord: vec2<f32>, @lo
|
|
|
36
36
|
let fragmentShader = Q5.device.createShaderModule({
|
|
37
37
|
label: 'imageFragmentShader',
|
|
38
38
|
code: `
|
|
39
|
-
@group(
|
|
40
|
-
@group(
|
|
39
|
+
@group(2) @binding(0) var samp: sampler;
|
|
40
|
+
@group(2) @binding(1) var texture: texture_2d<f32>;
|
|
41
41
|
|
|
42
42
|
@fragment
|
|
43
|
-
fn fragmentMain(@location(0) texCoord:
|
|
43
|
+
fn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {
|
|
44
44
|
// Sample the texture using the interpolated texture coordinate
|
|
45
45
|
return textureSample(texture, samp, texCoord);
|
|
46
46
|
}
|
|
@@ -72,11 +72,9 @@ fn fragmentMain(@location(0) texCoord: vec2<f32>) -> @location(0) vec4<f32> {
|
|
|
72
72
|
]
|
|
73
73
|
};
|
|
74
74
|
|
|
75
|
-
$.bindGroupLayouts.push(textureLayout);
|
|
76
|
-
|
|
77
75
|
const pipelineLayout = Q5.device.createPipelineLayout({
|
|
78
76
|
label: 'imagePipelineLayout',
|
|
79
|
-
bindGroupLayouts:
|
|
77
|
+
bindGroupLayouts: [...$.bindGroupLayouts, textureLayout]
|
|
80
78
|
});
|
|
81
79
|
|
|
82
80
|
$.pipelines[1] = Q5.device.createRenderPipeline({
|
|
@@ -118,20 +116,30 @@ fn fragmentMain(@location(0) texCoord: vec2<f32>) -> @location(0) vec4<f32> {
|
|
|
118
116
|
minFilter: 'linear'
|
|
119
117
|
});
|
|
120
118
|
|
|
119
|
+
let MAX_TEXTURES = 12000;
|
|
120
|
+
|
|
121
|
+
$._textures = [];
|
|
122
|
+
let tIdx = 0;
|
|
123
|
+
|
|
121
124
|
$._createTexture = (img) => {
|
|
122
125
|
if (img.canvas) img = img.canvas;
|
|
123
126
|
|
|
124
127
|
let textureSize = [img.width, img.height, 1];
|
|
125
128
|
|
|
126
|
-
|
|
129
|
+
let texture = Q5.device.createTexture({
|
|
127
130
|
size: textureSize,
|
|
128
131
|
format: 'bgra8unorm',
|
|
129
132
|
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_DST | GPUTextureUsage.RENDER_ATTACHMENT
|
|
130
133
|
});
|
|
131
134
|
|
|
132
|
-
Q5.device.queue.copyExternalImageToTexture(
|
|
135
|
+
Q5.device.queue.copyExternalImageToTexture(
|
|
136
|
+
{ source: img },
|
|
137
|
+
{ texture, colorSpace: $.canvas.colorSpace },
|
|
138
|
+
textureSize
|
|
139
|
+
);
|
|
133
140
|
|
|
134
|
-
|
|
141
|
+
$._textures[tIdx] = texture;
|
|
142
|
+
img.textureIndex = tIdx;
|
|
135
143
|
|
|
136
144
|
const textureBindGroup = Q5.device.createBindGroup({
|
|
137
145
|
layout: textureLayout,
|
|
@@ -140,7 +148,16 @@ fn fragmentMain(@location(0) texCoord: vec2<f32>) -> @location(0) vec4<f32> {
|
|
|
140
148
|
{ binding: 1, resource: texture.createView() }
|
|
141
149
|
]
|
|
142
150
|
});
|
|
143
|
-
$._textureBindGroups
|
|
151
|
+
$._textureBindGroups[tIdx] = textureBindGroup;
|
|
152
|
+
|
|
153
|
+
tIdx = (tIdx + 1) % MAX_TEXTURES;
|
|
154
|
+
|
|
155
|
+
// If the texture array is full, destroy the oldest texture
|
|
156
|
+
if ($._textures[tIdx]) {
|
|
157
|
+
$._textures[tIdx].destroy();
|
|
158
|
+
delete $._textures[tIdx];
|
|
159
|
+
delete $._textureBindGroups[tIdx];
|
|
160
|
+
}
|
|
144
161
|
};
|
|
145
162
|
|
|
146
163
|
$.loadImage = $.loadTexture = (src) => {
|