q5 2.2.4 → 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.
- package/README.md +3 -0
- package/package.json +1 -1
- package/q5.js +568 -422
- package/q5.min.js +2 -2
- package/src/q5-2d-canvas.js +9 -14
- package/src/q5-2d-drawing.js +3 -45
- package/src/q5-2d-image.js +8 -4
- package/src/q5-2d-text.js +4 -14
- package/src/q5-canvas.js +63 -2
- package/src/q5-core.js +3 -2
- package/src/q5-display.js +6 -0
- package/src/q5-math.js +27 -20
- package/src/q5-webgpu-canvas.js +132 -101
- package/src/q5-webgpu-drawing.js +120 -88
- package/src/q5-webgpu-image.js +160 -145
- package/src/q5-webgpu-text.js +38 -1
- package/src/readme.md +37 -6
package/src/q5-math.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Q5.modules.math = ($, q) => {
|
|
2
|
-
$.
|
|
3
|
-
$.
|
|
2
|
+
$.RADIANS = 0;
|
|
3
|
+
$.DEGREES = 1;
|
|
4
4
|
|
|
5
5
|
$.PI = Math.PI;
|
|
6
6
|
$.HALF_PI = Math.PI / 2;
|
|
@@ -21,9 +21,14 @@ Q5.modules.math = ($, q) => {
|
|
|
21
21
|
$.SHR3 = 1;
|
|
22
22
|
$.LCG = 2;
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
$.
|
|
24
|
+
let angleMode = 0;
|
|
25
|
+
|
|
26
|
+
$.angleMode = (mode) => {
|
|
27
|
+
if (mode == 'radians') mode = 0;
|
|
28
|
+
angleMode = $._angleMode = mode;
|
|
29
|
+
};
|
|
30
|
+
let DEGTORAD = ($._DEGTORAD = Math.PI / 180);
|
|
31
|
+
let RADTODEG = ($._RADTODEG = 180 / Math.PI);
|
|
27
32
|
$.degrees = (x) => x * $._RADTODEG;
|
|
28
33
|
$.radians = (x) => x * $._DEGTORAD;
|
|
29
34
|
|
|
@@ -49,24 +54,26 @@ Q5.modules.math = ($, q) => {
|
|
|
49
54
|
$.sq = (x) => x * x;
|
|
50
55
|
$.fract = (x) => x - Math.floor(x);
|
|
51
56
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
$.sin = (a) => Math.sin(!angleMode ? a : a * DEGTORAD);
|
|
58
|
+
$.cos = (a) => Math.cos(!angleMode ? a : a * DEGTORAD);
|
|
59
|
+
$.tan = (a) => Math.tan(!angleMode ? a : a * DEGTORAD);
|
|
60
|
+
|
|
61
|
+
$.asin = (x) => {
|
|
62
|
+
let a = Math.asin(x);
|
|
63
|
+
return !angleMode ? a : a * RADTODEG;
|
|
64
|
+
};
|
|
65
|
+
$.acos = (x) => {
|
|
66
|
+
let a = Math.acos(x);
|
|
67
|
+
return !angleMode ? a : a * RADTODEG;
|
|
68
|
+
};
|
|
69
|
+
$.atan = (x) => {
|
|
70
|
+
let a = Math.atan(x);
|
|
71
|
+
return !angleMode ? a : a * RADTODEG;
|
|
72
|
+
};
|
|
58
73
|
|
|
59
|
-
for (let fn of ['asin', 'acos', 'atan']) {
|
|
60
|
-
$[fn] = (x) => {
|
|
61
|
-
let a = Math[fn](x);
|
|
62
|
-
if ($._angleMode == 'degrees') a = $.degrees(a);
|
|
63
|
-
return a;
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
74
|
$.atan2 = (y, x) => {
|
|
67
75
|
let a = Math.atan2(y, x);
|
|
68
|
-
|
|
69
|
-
return a;
|
|
76
|
+
return !angleMode ? a : a * RADTODEG;
|
|
70
77
|
};
|
|
71
78
|
|
|
72
79
|
function lcg() {
|
package/src/q5-webgpu-canvas.js
CHANGED
|
@@ -13,70 +13,62 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
13
13
|
|
|
14
14
|
if ($.colorMode) $.colorMode('rgb', 'float');
|
|
15
15
|
|
|
16
|
-
let pass
|
|
16
|
+
let pass;
|
|
17
17
|
|
|
18
|
-
$.
|
|
19
|
-
q.ctx = q.drawingContext = c.getContext('webgpu');
|
|
20
|
-
|
|
21
|
-
opt.format = navigator.gpu.getPreferredCanvasFormat();
|
|
22
|
-
opt.device = Q5.device;
|
|
18
|
+
$.pipelines = [];
|
|
23
19
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
// pipeline changes for each draw call
|
|
29
|
-
$.pipelinesStack = [];
|
|
20
|
+
// local variables used for slightly better performance
|
|
21
|
+
// stores pipeline shifts and vertex counts/image indices
|
|
22
|
+
let drawStack = ($.drawStack = []);
|
|
30
23
|
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
// colors used for each draw call
|
|
25
|
+
let colorsStack = ($.colorsStack = [1, 1, 1, 1]);
|
|
33
26
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
$._envLayout = Q5.device.createBindGroupLayout({
|
|
28
|
+
entries: [
|
|
29
|
+
{
|
|
30
|
+
binding: 0,
|
|
31
|
+
visibility: GPUShaderStage.VERTEX,
|
|
32
|
+
buffer: {
|
|
33
|
+
type: 'uniform',
|
|
34
|
+
hasDynamicOffset: false
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
$._transformLayout = Q5.device.createBindGroupLayout({
|
|
41
|
+
entries: [
|
|
42
|
+
{
|
|
43
|
+
binding: 0,
|
|
44
|
+
visibility: GPUShaderStage.VERTEX,
|
|
45
|
+
buffer: {
|
|
46
|
+
type: 'read-only-storage',
|
|
47
|
+
hasDynamicOffset: false
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
});
|
|
39
52
|
|
|
40
|
-
|
|
41
|
-
$._colorIndex = 0;
|
|
53
|
+
$.bindGroupLayouts = [$._envLayout, $._transformLayout];
|
|
42
54
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
visibility: GPUShaderStage.VERTEX,
|
|
48
|
-
buffer: {
|
|
49
|
-
type: 'uniform',
|
|
50
|
-
hasDynamicOffset: false
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
]
|
|
54
|
-
});
|
|
55
|
+
const uniformBuffer = Q5.device.createBuffer({
|
|
56
|
+
size: 8, // Size of two floats
|
|
57
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
58
|
+
});
|
|
55
59
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
{
|
|
59
|
-
binding: 0,
|
|
60
|
-
visibility: GPUShaderStage.VERTEX,
|
|
61
|
-
buffer: {
|
|
62
|
-
type: 'read-only-storage',
|
|
63
|
-
hasDynamicOffset: false
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
]
|
|
67
|
-
});
|
|
60
|
+
$._createCanvas = (w, h, opt) => {
|
|
61
|
+
q.ctx = q.drawingContext = c.getContext('webgpu');
|
|
68
62
|
|
|
69
|
-
|
|
63
|
+
opt.format = navigator.gpu.getPreferredCanvasFormat();
|
|
64
|
+
opt.device = Q5.device;
|
|
70
65
|
|
|
71
|
-
|
|
72
|
-
size: 8, // Size of two floats
|
|
73
|
-
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
|
|
74
|
-
});
|
|
66
|
+
$.ctx.configure(opt);
|
|
75
67
|
|
|
76
68
|
Q5.device.queue.writeBuffer(uniformBuffer, 0, new Float32Array([$.canvas.hw, $.canvas.hh]));
|
|
77
69
|
|
|
78
|
-
|
|
79
|
-
layout:
|
|
70
|
+
$._envBindGroup = Q5.device.createBindGroup({
|
|
71
|
+
layout: $._envLayout,
|
|
80
72
|
entries: [
|
|
81
73
|
{
|
|
82
74
|
binding: 0,
|
|
@@ -135,14 +127,14 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
135
127
|
if (!x && !y && !z) return;
|
|
136
128
|
// Update the translation values
|
|
137
129
|
$._matrix[3] += x;
|
|
138
|
-
$._matrix[7]
|
|
130
|
+
$._matrix[7] -= y;
|
|
139
131
|
$._matrix[11] += z || 0;
|
|
140
132
|
$._matrixDirty = true;
|
|
141
133
|
};
|
|
142
134
|
|
|
143
135
|
$.rotate = (r) => {
|
|
144
136
|
if (!r) return;
|
|
145
|
-
if ($._angleMode
|
|
137
|
+
if ($._angleMode) r *= $._DEGTORAD;
|
|
146
138
|
|
|
147
139
|
let cosR = Math.cos(r);
|
|
148
140
|
let sinR = Math.sin(r);
|
|
@@ -183,10 +175,72 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
183
175
|
$._matrixDirty = false;
|
|
184
176
|
};
|
|
185
177
|
|
|
178
|
+
// current color index, used to associate a vertex with a color
|
|
179
|
+
let colorIndex = 0;
|
|
180
|
+
const addColor = (r, g, b, a = 1) => {
|
|
181
|
+
if (typeof r == 'string') r = $.color(r);
|
|
182
|
+
else if (b == undefined) {
|
|
183
|
+
// grayscale mode `fill(1, 0.5)`
|
|
184
|
+
a = g ?? 1;
|
|
185
|
+
g = b = r;
|
|
186
|
+
}
|
|
187
|
+
if (r._q5Color) colorsStack.push(r.r, r.g, r.b, r.a);
|
|
188
|
+
else colorsStack.push(r, g, b, a);
|
|
189
|
+
colorIndex++;
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
$.fill = (r, g, b, a) => {
|
|
193
|
+
addColor(r, g, b, a);
|
|
194
|
+
$._doFill = true;
|
|
195
|
+
$._fillIndex = colorIndex;
|
|
196
|
+
};
|
|
197
|
+
$.stroke = (r, g, b, a) => {
|
|
198
|
+
addColor(r, g, b, a);
|
|
199
|
+
$._doStroke = true;
|
|
200
|
+
$._strokeIndex = colorIndex;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
$.noFill = () => ($._doFill = false);
|
|
204
|
+
$.noStroke = () => ($._doStroke = false);
|
|
205
|
+
|
|
206
|
+
$._strokeWeight = 1;
|
|
207
|
+
$.strokeWeight = (v) => ($._strokeWeight = Math.abs(v));
|
|
208
|
+
|
|
209
|
+
$._calcBox = (x, y, w, h, mode) => {
|
|
210
|
+
let hw = w / 2;
|
|
211
|
+
let hh = h / 2;
|
|
212
|
+
|
|
213
|
+
// left, right, top, bottom
|
|
214
|
+
let l, r, t, b;
|
|
215
|
+
if (!mode || mode == 'corner') {
|
|
216
|
+
// CORNER
|
|
217
|
+
l = x;
|
|
218
|
+
r = x + w;
|
|
219
|
+
t = -y;
|
|
220
|
+
b = -(y + h);
|
|
221
|
+
} else if (mode == 'center') {
|
|
222
|
+
l = x - hw;
|
|
223
|
+
r = x + hw;
|
|
224
|
+
t = -(y - hh);
|
|
225
|
+
b = -(y + hh);
|
|
226
|
+
} else {
|
|
227
|
+
// CORNERS
|
|
228
|
+
l = x;
|
|
229
|
+
r = w;
|
|
230
|
+
t = -y;
|
|
231
|
+
b = -h;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return [l, r, t, b];
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
$.clear = () => {};
|
|
238
|
+
|
|
186
239
|
$._beginRender = () => {
|
|
187
240
|
$.encoder = Q5.device.createCommandEncoder();
|
|
188
241
|
|
|
189
242
|
pass = q.pass = $.encoder.beginRenderPass({
|
|
243
|
+
label: 'q5-webgpu',
|
|
190
244
|
colorAttachments: [
|
|
191
245
|
{
|
|
192
246
|
view: ctx.getCurrentTexture().createView(),
|
|
@@ -198,9 +252,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
198
252
|
};
|
|
199
253
|
|
|
200
254
|
$._render = () => {
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
if (transformStates.length > 1 || !transformBindGroup) {
|
|
255
|
+
if (transformStates.length > 1 || !$._transformBindGroup) {
|
|
204
256
|
const transformBuffer = Q5.device.createBuffer({
|
|
205
257
|
size: transformStates.length * 64, // Size of 16 floats
|
|
206
258
|
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST
|
|
@@ -208,8 +260,8 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
208
260
|
|
|
209
261
|
Q5.device.queue.writeBuffer(transformBuffer, 0, new Float32Array(transformStates.flat()));
|
|
210
262
|
|
|
211
|
-
|
|
212
|
-
layout: $.
|
|
263
|
+
$._transformBindGroup = Q5.device.createBindGroup({
|
|
264
|
+
layout: $._transformLayout,
|
|
213
265
|
entries: [
|
|
214
266
|
{
|
|
215
267
|
binding: 0,
|
|
@@ -221,27 +273,39 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
221
273
|
});
|
|
222
274
|
}
|
|
223
275
|
|
|
224
|
-
pass.setBindGroup(
|
|
276
|
+
pass.setBindGroup(0, $._envBindGroup);
|
|
277
|
+
pass.setBindGroup(1, $._transformBindGroup);
|
|
225
278
|
|
|
226
|
-
// run pre-render methods
|
|
227
279
|
for (let m of $._hooks.preRender) m();
|
|
228
280
|
|
|
229
|
-
// local variables used for performance
|
|
230
|
-
let drawStack = $.drawStack;
|
|
231
|
-
|
|
232
281
|
let drawVertOffset = 0;
|
|
282
|
+
let imageVertOffset = 0;
|
|
233
283
|
let curPipelineIndex = -1;
|
|
284
|
+
let curTextureIndex = -1;
|
|
285
|
+
|
|
286
|
+
pass.setPipeline($.pipelines[0]);
|
|
234
287
|
|
|
235
288
|
for (let i = 0; i < drawStack.length; i += 2) {
|
|
289
|
+
let v = drawStack[i + 1];
|
|
290
|
+
|
|
236
291
|
if (curPipelineIndex != drawStack[i]) {
|
|
237
292
|
curPipelineIndex = drawStack[i];
|
|
238
293
|
pass.setPipeline($.pipelines[curPipelineIndex]);
|
|
239
294
|
}
|
|
240
295
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
296
|
+
if (curPipelineIndex == 0) {
|
|
297
|
+
pass.draw(v, 1, drawVertOffset, 0);
|
|
298
|
+
drawVertOffset += v;
|
|
299
|
+
} else if (curPipelineIndex == 1) {
|
|
300
|
+
if (curTextureIndex != v) {
|
|
301
|
+
pass.setBindGroup(3, $._textureBindGroups[v]);
|
|
302
|
+
}
|
|
303
|
+
pass.draw(6, 1, imageVertOffset, 0);
|
|
304
|
+
imageVertOffset += 6;
|
|
305
|
+
}
|
|
244
306
|
}
|
|
307
|
+
|
|
308
|
+
for (let m of $._hooks.postRender) m();
|
|
245
309
|
};
|
|
246
310
|
|
|
247
311
|
$._finishRender = () => {
|
|
@@ -251,48 +315,15 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
251
315
|
q.pass = $.encoder = null;
|
|
252
316
|
|
|
253
317
|
// clear the stacks for the next frame
|
|
254
|
-
$.verticesStack.length = 0;
|
|
255
318
|
$.drawStack.length = 0;
|
|
256
319
|
$.colorsStack.length = 4;
|
|
257
|
-
|
|
258
|
-
$._colorIndex = 0;
|
|
320
|
+
colorIndex = 0;
|
|
259
321
|
rotation = 0;
|
|
260
322
|
$.resetMatrix();
|
|
261
323
|
$._matrixDirty = false;
|
|
262
324
|
$.transformStates.length = 1;
|
|
263
325
|
$._transformIndexStack.length = 0;
|
|
264
326
|
};
|
|
265
|
-
|
|
266
|
-
function addColor(r, g, b, a = 1) {
|
|
267
|
-
if (typeof r == 'string') r = Q5.color(r);
|
|
268
|
-
// grayscale mode `fill(1, 0.5)`
|
|
269
|
-
if (b == undefined) {
|
|
270
|
-
a = g;
|
|
271
|
-
g = b = r;
|
|
272
|
-
}
|
|
273
|
-
if (r._q5Color) colorsStack.push(...r.levels);
|
|
274
|
-
else colorsStack.push(r, g, b, a);
|
|
275
|
-
$._colorIndex++;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
$.fill = function () {
|
|
279
|
-
addColor(...arguments);
|
|
280
|
-
$._doFill = true;
|
|
281
|
-
$._fillIndex = $._colorIndex;
|
|
282
|
-
};
|
|
283
|
-
$.stroke = function () {
|
|
284
|
-
addColor(...arguments);
|
|
285
|
-
$._doStroke = true;
|
|
286
|
-
$._fillIndex = $._colorIndex;
|
|
287
|
-
};
|
|
288
|
-
|
|
289
|
-
$.noFill = () => ($._doFill = false);
|
|
290
|
-
$.noStroke = () => ($._doStroke = false);
|
|
291
|
-
|
|
292
|
-
$._strokeWeight = 1;
|
|
293
|
-
$.strokeWeight = (v) => ($._strokeWeight = v);
|
|
294
|
-
|
|
295
|
-
$.clear = () => {};
|
|
296
327
|
};
|
|
297
328
|
|
|
298
329
|
Q5.webgpu = async function (scope, parent) {
|