q5 2.4.4 → 2.4.5

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.
@@ -86,6 +86,37 @@ Q5.renderers.webgpu.canvas = ($, q) => {
86
86
  $._setCanvasSize(w, h);
87
87
  };
88
88
 
89
+ // current color index, used to associate a vertex with a color
90
+ let colorIndex = 0;
91
+ const addColor = (r, g, b, a = 1) => {
92
+ if (typeof r == 'string') r = $.color(r);
93
+ else if (b == undefined) {
94
+ // grayscale mode `fill(1, 0.5)`
95
+ a = g ?? 1;
96
+ g = b = r;
97
+ }
98
+ if (r._q5Color) colorsStack.push(r.r, r.g, r.b, r.a);
99
+ else colorsStack.push(r, g, b, a);
100
+ colorIndex++;
101
+ };
102
+
103
+ $.fill = (r, g, b, a) => {
104
+ addColor(r, g, b, a);
105
+ $._doFill = true;
106
+ $._fillIndex = colorIndex;
107
+ };
108
+ $.stroke = (r, g, b, a) => {
109
+ addColor(r, g, b, a);
110
+ $._doStroke = true;
111
+ $._strokeIndex = colorIndex;
112
+ };
113
+
114
+ $.noFill = () => ($._doFill = false);
115
+ $.noStroke = () => ($._doStroke = false);
116
+
117
+ $._strokeWeight = 1;
118
+ $.strokeWeight = (v) => ($._strokeWeight = Math.abs(v));
119
+
89
120
  $.resetMatrix = () => {
90
121
  // Initialize the transformation matrix as 4x4 identity matrix
91
122
 
@@ -109,24 +140,6 @@ Q5.renderers.webgpu.canvas = ($, q) => {
109
140
  // Stack to keep track of transformation matrix indexes
110
141
  $._transformIndexStack = [];
111
142
 
112
- $.push = $.pushMatrix = () => {
113
- // Push the current matrix index onto the stack
114
- $._transformIndexStack.push($._transformIndex);
115
- $._pushStyles();
116
- };
117
-
118
- $.pop = $.popMatrix = () => {
119
- if (!$._transformIndexStack.length) {
120
- return console.warn('Matrix index stack is empty!');
121
- }
122
- // Pop the last matrix index from the stack and set it as the current matrix index
123
- let idx = $._transformIndexStack.pop();
124
- $._matrix = $.transformStates[idx].slice();
125
- $._transformIndex = idx;
126
- $._matrixDirty = false;
127
- $._popStyles();
128
- };
129
-
130
143
  $.translate = (x, y, z) => {
131
144
  if (!x && !y && !z) return;
132
145
  // Update the translation values
@@ -172,6 +185,57 @@ Q5.renderers.webgpu.canvas = ($, q) => {
172
185
  $._matrixDirty = true;
173
186
  };
174
187
 
188
+ $.shearX = (ang) => {
189
+ if (!ang) return;
190
+ if ($._angleMode) ang *= $._DEGTORAD;
191
+
192
+ let tanAng = Math.tan(ang);
193
+
194
+ let m0 = $._matrix[0],
195
+ m1 = $._matrix[1],
196
+ m4 = $._matrix[4],
197
+ m5 = $._matrix[5];
198
+
199
+ $._matrix[0] = m0 + m4 * tanAng;
200
+ $._matrix[1] = m1 + m5 * tanAng;
201
+
202
+ $._matrixDirty = true;
203
+ };
204
+
205
+ $.shearY = (ang) => {
206
+ if (!ang) return;
207
+ if ($._angleMode) ang *= $._DEGTORAD;
208
+
209
+ let tanAng = Math.tan(ang);
210
+
211
+ let m0 = $._matrix[0],
212
+ m1 = $._matrix[1],
213
+ m4 = $._matrix[4],
214
+ m5 = $._matrix[5];
215
+
216
+ $._matrix[4] = m4 + m0 * tanAng;
217
+ $._matrix[5] = m5 + m1 * tanAng;
218
+
219
+ $._matrixDirty = true;
220
+ };
221
+
222
+ $.applyMatrix = (...args) => {
223
+ let m;
224
+ if (args.length == 1) m = args[0];
225
+ else m = args;
226
+
227
+ if (m.length == 9) {
228
+ // Convert 3x3 matrix to 4x4 matrix
229
+ m = [m[0], m[1], 0, m[2], m[3], m[4], 0, m[5], 0, 0, 1, 0, m[6], m[7], 0, m[8]];
230
+ } else if (m.length != 16) {
231
+ throw new Error('Matrix must be a 3x3 or 4x4 array.');
232
+ }
233
+
234
+ // Overwrite the current transformation matrix
235
+ $._matrix = m.slice();
236
+ $._matrixDirty = true;
237
+ };
238
+
175
239
  // Function to save the current matrix state if dirty
176
240
  $._saveMatrix = () => {
177
241
  $.transformStates.push($._matrix.slice());
@@ -179,37 +243,31 @@ Q5.renderers.webgpu.canvas = ($, q) => {
179
243
  $._matrixDirty = false;
180
244
  };
181
245
 
182
- // current color index, used to associate a vertex with a color
183
- let colorIndex = 0;
184
- const addColor = (r, g, b, a = 1) => {
185
- if (typeof r == 'string') r = $.color(r);
186
- else if (b == undefined) {
187
- // grayscale mode `fill(1, 0.5)`
188
- a = g ?? 1;
189
- g = b = r;
246
+ // Push the current matrix index onto the stack
247
+ $.pushMatrix = () => {
248
+ if ($._matrixDirty) $._saveMatrix();
249
+ $._transformIndexStack.push($._transformIndex);
250
+ };
251
+ $.popMatrix = () => {
252
+ if (!$._transformIndexStack.length) {
253
+ return console.warn('Matrix index stack is empty!');
190
254
  }
191
- if (r._q5Color) colorsStack.push(r.r, r.g, r.b, r.a);
192
- else colorsStack.push(r, g, b, a);
193
- colorIndex++;
255
+ // Pop the last matrix index from the stack and set it as the current matrix index
256
+ let idx = $._transformIndexStack.pop();
257
+ $._matrix = $.transformStates[idx].slice();
258
+ $._transformIndex = idx;
259
+ $._matrixDirty = false;
194
260
  };
195
261
 
196
- $.fill = (r, g, b, a) => {
197
- addColor(r, g, b, a);
198
- $._doFill = true;
199
- $._fillIndex = colorIndex;
262
+ $.push = () => {
263
+ $.pushMatrix();
264
+ $.pushStyles();
200
265
  };
201
- $.stroke = (r, g, b, a) => {
202
- addColor(r, g, b, a);
203
- $._doStroke = true;
204
- $._strokeIndex = colorIndex;
266
+ $.pop = () => {
267
+ $.popMatrix();
268
+ $.popStyles();
205
269
  };
206
270
 
207
- $.noFill = () => ($._doFill = false);
208
- $.noStroke = () => ($._doStroke = false);
209
-
210
- $._strokeWeight = 1;
211
- $.strokeWeight = (v) => ($._strokeWeight = Math.abs(v));
212
-
213
271
  $._calcBox = (x, y, w, h, mode) => {
214
272
  let hw = w / 2;
215
273
  let hh = h / 2;
@@ -224,6 +224,15 @@ fn fragmentMain(@location(1) colorIndex: f32) -> @location(0) vec4<f32> {
224
224
  $.endShape(1);
225
225
  };
226
226
 
227
+ $.quad = (x1, y1, x2, y2, x3, y3, x4, y4) => {
228
+ $.beginShape();
229
+ $.vertex(x1, y1);
230
+ $.vertex(x2, y2);
231
+ $.vertex(x3, y3);
232
+ $.vertex(x4, y4);
233
+ $.endShape(1);
234
+ };
235
+
227
236
  $.rectMode = (x) => ($._rectMode = x);
228
237
 
229
238
  $.rect = (x, y, w, h) => {
@@ -245,6 +254,8 @@ fn fragmentMain(@location(1) colorIndex: f32) -> @location(0) vec4<f32> {
245
254
  drawStack.push(0, 6);
246
255
  };
247
256
 
257
+ $.square = (x, y, s) => $.rect(x, y, s, s);
258
+
248
259
  $.point = (x, y) => {
249
260
  colorIndex = $._strokeIndex;
250
261
  let sw = $._strokeWeight;
@@ -204,3 +204,12 @@ fn fragmentMain(@location(0) texCoord: vec2<f32>) -> @location(0) vec4<f32> {
204
204
  verticesStack.length = 0;
205
205
  });
206
206
  };
207
+
208
+ Q5.THRESHOLD = 1;
209
+ Q5.GRAY = 2;
210
+ Q5.OPAQUE = 3;
211
+ Q5.INVERT = 4;
212
+ Q5.POSTERIZE = 5;
213
+ Q5.DILATE = 6;
214
+ Q5.ERODE = 7;
215
+ Q5.BLUR = 8;
package/src/readme.md CHANGED
@@ -181,15 +181,15 @@ Implemented functions:
181
181
 
182
182
  > Use `textFill` and `textStroke` to set text colors.
183
183
 
184
- WebGPU (and WebGL) don't have HTML5 based text rasterization functionality like Canvas2D does.
184
+ WebGPU (and WebGL) don't have fast HTML5 based text rasterization functionality, like Canvas2D does.
185
185
 
186
- In p5.js WebGL mode, text is drawn directly to the canvas. This is a complex task, since letters have intricate geometry: thus many triangles must be used to render text at high resolution. For typical use, the performance cost is actually negligible. Yet since p5.js depends on opentype.js for this, which is 528kb (171kb minified), a different approach was needed to keep q5 lightweight.
186
+ In p5.js WebGL mode, text is drawn directly to the canvas. This is a complex task, since letters have intricate geometry: thus many triangles must be used to render text at high resolution. Unless a user wants to render a lot of text, the performance cost is actually negligible. Yet since p5.js depends on opentype.js for this, which is 528kb (171kb minified), a different approach was needed to keep q5 lightweight.
187
187
 
188
- Internally, q5's WebGPU renderer uses a q5 graphics object to draw text to a Canvas2D canvas via `createTextImage`, then converts that canvas to a WebGPU texture. Each texture is cached so it doesn't have to be recreated every frame that users want to display the same text.
188
+ Internally, q5's WebGPU renderer uses a q5 graphics object to draw text to a Canvas2D canvas via `createTextImage`, then converts that canvas to a WebGPU texture. Each texture is cached, so it doesn't have to be recreated every frame that users want to display the same text.
189
189
 
190
- As long as text content doesn't change often, this method is 4x more efficient.
190
+ Creating a text image is slower than rendering text if it's only displayed for one frame, but displaying static text multiple frames from a cached image is way faster than re-rendering the text. So just try not to have long strings of text that change every frame.
191
191
 
192
- As a best practice, separate static text from dynamic text rendering. For example render labels like "Score: " and corresponding values with separate calls to `text`.
192
+ For typical use cases, this is a great trade-off!
193
193
 
194
194
  Complete implementation of text rendering in WebGPU.
195
195