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/src/q5-math.js CHANGED
@@ -1,6 +1,6 @@
1
1
  Q5.modules.math = ($, q) => {
2
- $.DEGREES = 'degrees';
3
- $.RADIANS = 'radians';
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
- $.angleMode = (mode) => ($._angleMode = mode);
25
- $._DEGTORAD = Math.PI / 180;
26
- $._RADTODEG = 180 / Math.PI;
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
- for (let fn of ['sin', 'cos', 'tan']) {
53
- $[fn] = (a) => {
54
- if ($._angleMode == 'degrees') a = $.radians(a);
55
- return Math[fn](a);
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
- if ($._angleMode == 'degrees') a = $.degrees(a);
69
- return a;
76
+ return !angleMode ? a : a * RADTODEG;
70
77
  };
71
78
 
72
79
  function lcg() {
@@ -13,70 +13,62 @@ Q5.renderers.webgpu.canvas = ($, q) => {
13
13
 
14
14
  if ($.colorMode) $.colorMode('rgb', 'float');
15
15
 
16
- let pass, colorsStack, envBindGroup, transformBindGroup;
16
+ let pass;
17
17
 
18
- $._createCanvas = (w, h, opt) => {
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
- $.ctx.configure(opt);
25
-
26
- $.pipelines = [];
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
- // vertices for each draw call
32
- $.verticesStack = [];
24
+ // colors used for each draw call
25
+ let colorsStack = ($.colorsStack = [1, 1, 1, 1]);
33
26
 
34
- // number of vertices for each draw call
35
- $.drawStack = [];
36
-
37
- // colors used for each draw call
38
- colorsStack = $.colorsStack = [1, 1, 1, 1];
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
- // current color index, used to associate a vertex with a color
41
- $._colorIndex = 0;
53
+ $.bindGroupLayouts = [$._envLayout, $._transformLayout];
42
54
 
43
- let envLayout = Q5.device.createBindGroupLayout({
44
- entries: [
45
- {
46
- binding: 0,
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
- let transformLayout = Q5.device.createBindGroupLayout({
57
- entries: [
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
- $.bindGroupLayouts = [envLayout, transformLayout];
63
+ opt.format = navigator.gpu.getPreferredCanvasFormat();
64
+ opt.device = Q5.device;
70
65
 
71
- const uniformBuffer = Q5.device.createBuffer({
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
- envBindGroup = Q5.device.createBindGroup({
79
- layout: envLayout,
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] += y;
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 == 'degrees') r = $.radians(r);
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
- pass.setBindGroup(0, envBindGroup);
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
- transformBindGroup = Q5.device.createBindGroup({
212
- layout: $.bindGroupLayouts[1],
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(1, transformBindGroup);
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
- let vertCount = drawStack[i + 1];
242
- pass.draw(vertCount, 1, drawVertOffset, 0);
243
- drawVertOffset += vertCount;
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
- $.pipelinesStack.length = 0;
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) {