q5 2.9.22 → 2.9.23
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/.vscode/launch.json +26 -0
- package/bun.lockb +0 -0
- package/p5-tests/js/chai_helpers.js +20 -0
- package/p5-tests/js/mocha_setup.js +2 -0
- package/p5-tests/js/modernizr.js +5 -0
- package/p5-tests/js/p5_helpers.js +135 -0
- package/p5-tests/js/sinon.js +5949 -0
- package/p5-tests/mocha.css +289 -0
- package/p5-tests/test.html +71 -0
- package/p5-tests/unit/color/color_conversion.js +68 -0
- package/p5-tests/unit/color/creating_reading.js +217 -0
- package/p5-tests/unit/color/p5.Color.js +1000 -0
- package/p5-tests/unit/color/setting.js +289 -0
- package/p5-tests/unit/core/2d_primitives.js +490 -0
- package/p5-tests/unit/core/attributes.js +115 -0
- package/p5-tests/unit/core/curves.js +139 -0
- package/p5-tests/unit/core/environment.js +248 -0
- package/p5-tests/unit/core/error_helpers.js +1158 -0
- package/p5-tests/unit/core/main.js +340 -0
- package/p5-tests/unit/core/p5.Element.js +773 -0
- package/p5-tests/unit/core/p5.Graphics.js +179 -0
- package/p5-tests/unit/core/preload.js +285 -0
- package/p5-tests/unit/core/rendering.js +116 -0
- package/p5-tests/unit/core/structure.js +293 -0
- package/p5-tests/unit/core/transform.js +144 -0
- package/p5-tests/unit/core/version.js +28 -0
- package/p5-tests/unit/core/vertex.js +137 -0
- package/p5-tests/unit/dom/dom.js +2146 -0
- package/p5-tests/unit/events/acceleration.js +213 -0
- package/p5-tests/unit/events/keyboard.js +179 -0
- package/p5-tests/unit/events/mouse.js +487 -0
- package/p5-tests/unit/events/touch.js +180 -0
- package/p5-tests/unit/image/downloading.js +379 -0
- package/p5-tests/unit/image/filters.js +92 -0
- package/p5-tests/unit/image/loading.js +413 -0
- package/p5-tests/unit/image/p5.Image.js +201 -0
- package/p5-tests/unit/image/pixels.js +234 -0
- package/p5-tests/unit/io/files.js +378 -0
- package/p5-tests/unit/io/loadBytes.js +149 -0
- package/p5-tests/unit/io/loadImage.js +123 -0
- package/p5-tests/unit/io/loadJSON.js +185 -0
- package/p5-tests/unit/io/loadModel.js +215 -0
- package/p5-tests/unit/io/loadShader.js +176 -0
- package/p5-tests/unit/io/loadStrings.js +140 -0
- package/p5-tests/unit/io/loadTable.js +183 -0
- package/p5-tests/unit/io/loadXML.js +127 -0
- package/p5-tests/unit/io/saveModel.js +113 -0
- package/p5-tests/unit/io/saveTable.js +142 -0
- package/p5-tests/unit/math/calculation.js +452 -0
- package/p5-tests/unit/math/noise.js +66 -0
- package/p5-tests/unit/math/p5.Vector.js +1886 -0
- package/p5-tests/unit/math/random.js +177 -0
- package/p5-tests/unit/math/trigonometry.js +144 -0
- package/p5-tests/unit/spec.js +50 -0
- package/p5-tests/unit/typography/attributes.js +120 -0
- package/p5-tests/unit/typography/loadFont.js +162 -0
- package/p5-tests/unit/typography/p5.Font.js +63 -0
- package/p5-tests/unit/utilities/conversion.js +329 -0
- package/p5-tests/unit/utilities/time_date.js +133 -0
- package/package.json +1 -1
- package/q5.js +48 -37
- package/q5.min.js +1 -1
- package/src/q5-2d-image.js +3 -1
- package/src/q5-core.js +3 -1
- package/src/q5-math.js +1 -0
- package/src/q5-webgpu-canvas.js +8 -7
- package/src/q5-webgpu-drawing.js +15 -12
- package/src/q5-webgpu-image.js +1 -1
- package/src/q5-webgpu-text.js +17 -15
package/q5.js
CHANGED
|
@@ -118,7 +118,7 @@ function Q5(scope, parent, renderer) {
|
|
|
118
118
|
};
|
|
119
119
|
$.loop = () => {
|
|
120
120
|
$._loop = true;
|
|
121
|
-
if (looper == null) $._draw();
|
|
121
|
+
if ($._setupDone && looper == null) $._draw();
|
|
122
122
|
};
|
|
123
123
|
$.isLooping = () => $._loop;
|
|
124
124
|
$.redraw = (n = 1) => {
|
|
@@ -309,6 +309,8 @@ function createCanvas(w, h, opt) {
|
|
|
309
309
|
}
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
+
Q5.version = Q5.VERSION = '2.9';
|
|
313
|
+
|
|
312
314
|
if (typeof document == 'object') {
|
|
313
315
|
document.addEventListener('DOMContentLoaded', () => {
|
|
314
316
|
if (!Q5._hasGlobal) new Q5('auto');
|
|
@@ -1248,7 +1250,9 @@ Q5.renderers.q2d.image = ($, q) => {
|
|
|
1248
1250
|
$.loadImage = function (url, cb, opt) {
|
|
1249
1251
|
if (url.canvas) return url;
|
|
1250
1252
|
if (url.slice(-3).toLowerCase() == 'gif') {
|
|
1251
|
-
throw new Error(
|
|
1253
|
+
throw new Error(
|
|
1254
|
+
`q5 doesn't support GIFs. Use a video or p5play animation instead. https://github.com/q5js/q5.js/issues/84`
|
|
1255
|
+
);
|
|
1252
1256
|
}
|
|
1253
1257
|
q._preloadCount++;
|
|
1254
1258
|
let last = [...arguments].at(-1);
|
|
@@ -2403,6 +2407,7 @@ Q5.modules.math = ($, q) => {
|
|
|
2403
2407
|
|
|
2404
2408
|
$.angleMode = (mode) => {
|
|
2405
2409
|
angleMode = $._angleMode = mode == 0 || mode == 'radians' ? 0 : 1;
|
|
2410
|
+
return !angleMode ? 'radians' : 'degrees';
|
|
2406
2411
|
};
|
|
2407
2412
|
let DEGTORAD = ($._DEGTORAD = Math.PI / 180);
|
|
2408
2413
|
let RADTODEG = ($._RADTODEG = 180 / Math.PI);
|
|
@@ -3371,7 +3376,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3371
3376
|
$.strokeWeight = (v) => ($._strokeWeight = Math.abs(v));
|
|
3372
3377
|
|
|
3373
3378
|
$.resetMatrix = () => {
|
|
3374
|
-
//
|
|
3379
|
+
// initialize the transformation matrix as 4x4 identity matrix
|
|
3375
3380
|
|
|
3376
3381
|
// prettier-ignore
|
|
3377
3382
|
$._matrix = [
|
|
@@ -3395,7 +3400,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3395
3400
|
|
|
3396
3401
|
$.translate = (x, y, z) => {
|
|
3397
3402
|
if (!x && !y && !z) return;
|
|
3398
|
-
//
|
|
3403
|
+
// update the translation values
|
|
3399
3404
|
$._matrix[12] += x;
|
|
3400
3405
|
$._matrix[13] -= y;
|
|
3401
3406
|
$._matrix[14] += z || 0;
|
|
@@ -3494,25 +3499,25 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3494
3499
|
else m = args;
|
|
3495
3500
|
|
|
3496
3501
|
if (m.length == 9) {
|
|
3497
|
-
//
|
|
3502
|
+
// convert 3x3 matrix to 4x4 matrix
|
|
3498
3503
|
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]];
|
|
3499
3504
|
} else if (m.length != 16) {
|
|
3500
3505
|
throw new Error('Matrix must be a 3x3 or 4x4 array.');
|
|
3501
3506
|
}
|
|
3502
3507
|
|
|
3503
|
-
//
|
|
3508
|
+
// overwrite the current transformation matrix
|
|
3504
3509
|
$._matrix = m.slice();
|
|
3505
3510
|
$._matrixDirty = true;
|
|
3506
3511
|
};
|
|
3507
3512
|
|
|
3508
|
-
//
|
|
3513
|
+
// function to save the current matrix state if dirty
|
|
3509
3514
|
$._saveMatrix = () => {
|
|
3510
3515
|
transformStates.push($._matrix.slice());
|
|
3511
3516
|
$._transformIndex = transformStates.length - 1;
|
|
3512
3517
|
$._matrixDirty = false;
|
|
3513
3518
|
};
|
|
3514
3519
|
|
|
3515
|
-
//
|
|
3520
|
+
// push the current matrix index onto the stack
|
|
3516
3521
|
$.pushMatrix = () => {
|
|
3517
3522
|
if ($._matrixDirty) $._saveMatrix();
|
|
3518
3523
|
$._transformIndexStack.push($._transformIndex);
|
|
@@ -3522,7 +3527,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3522
3527
|
if (!$._transformIndexStack.length) {
|
|
3523
3528
|
return console.warn('Matrix index stack is empty!');
|
|
3524
3529
|
}
|
|
3525
|
-
//
|
|
3530
|
+
// pop the last matrix index and set it as the current matrix index
|
|
3526
3531
|
let idx = $._transformIndexStack.pop();
|
|
3527
3532
|
$._matrix = transformStates[idx].slice();
|
|
3528
3533
|
$._transformIndex = idx;
|
|
@@ -3585,6 +3590,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3585
3590
|
'max' // 4
|
|
3586
3591
|
];
|
|
3587
3592
|
|
|
3593
|
+
// other blend modes are not supported yet
|
|
3588
3594
|
const blendModes = {
|
|
3589
3595
|
normal: [2, 3, 0, 2, 3, 0],
|
|
3590
3596
|
// destination_over: [6, 1, 0, 6, 1, 0],
|
|
@@ -4048,19 +4054,22 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4048
4054
|
if ($._matrixDirty) $._saveMatrix();
|
|
4049
4055
|
let ti = $._transformIndex,
|
|
4050
4056
|
ci = $._stroke,
|
|
4051
|
-
sw = $._strokeWeight
|
|
4052
|
-
hsw = sw / 2;
|
|
4057
|
+
sw = $._strokeWeight;
|
|
4053
4058
|
|
|
4054
4059
|
if (sw < 2) {
|
|
4055
4060
|
let [l, r, t, b] = $._calcBox(x, y, sw, sw, 'corner');
|
|
4056
4061
|
addRect(l, t, r, t, r, b, l, b, ci, ti);
|
|
4057
4062
|
} else {
|
|
4058
4063
|
let n = getArcSegments(sw);
|
|
4059
|
-
|
|
4064
|
+
sw /= 2;
|
|
4065
|
+
addEllipse(x, y, sw, sw, n, ci, ti);
|
|
4060
4066
|
}
|
|
4061
4067
|
};
|
|
4062
4068
|
|
|
4063
|
-
|
|
4069
|
+
$.stokeJoin = (x) => {
|
|
4070
|
+
$.log("q5 WebGPU doesn't support changing stroke join style.");
|
|
4071
|
+
};
|
|
4072
|
+
|
|
4064
4073
|
$.line = (x1, y1, x2, y2) => {
|
|
4065
4074
|
if ($._matrixDirty) $._saveMatrix();
|
|
4066
4075
|
let ti = $._transformIndex,
|
|
@@ -4068,12 +4077,12 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4068
4077
|
sw = $._strokeWeight,
|
|
4069
4078
|
hsw = sw / 2;
|
|
4070
4079
|
|
|
4071
|
-
//
|
|
4080
|
+
// calculate the direction vector and length
|
|
4072
4081
|
let dx = x2 - x1,
|
|
4073
4082
|
dy = y2 - y1,
|
|
4074
4083
|
length = Math.hypot(dx, dy);
|
|
4075
4084
|
|
|
4076
|
-
//
|
|
4085
|
+
// calculate the perpendicular vector for line thickness
|
|
4077
4086
|
let px = -(dy / length) * hsw,
|
|
4078
4087
|
py = (dx / length) * hsw;
|
|
4079
4088
|
|
|
@@ -4109,10 +4118,10 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4109
4118
|
|
|
4110
4119
|
$.endShape = (close) => {
|
|
4111
4120
|
if (curveVertices.length > 0) {
|
|
4112
|
-
//
|
|
4121
|
+
// duplicate start and end points if necessary
|
|
4113
4122
|
let points = [...curveVertices];
|
|
4114
4123
|
if (points.length < 4) {
|
|
4115
|
-
//
|
|
4124
|
+
// duplicate first and last points
|
|
4116
4125
|
while (points.length < 4) {
|
|
4117
4126
|
points.unshift(points[0]);
|
|
4118
4127
|
points.push(points[points.length - 1]);
|
|
@@ -4153,7 +4162,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4153
4162
|
throw new Error('A shape must have at least 3 vertices.');
|
|
4154
4163
|
}
|
|
4155
4164
|
|
|
4156
|
-
//
|
|
4165
|
+
// close the shape if requested
|
|
4157
4166
|
if (close) {
|
|
4158
4167
|
let firstIndex = 0;
|
|
4159
4168
|
let lastIndex = (shapeVertCount - 1) * 4;
|
|
@@ -4170,7 +4179,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4170
4179
|
}
|
|
4171
4180
|
|
|
4172
4181
|
if ($._doFill) {
|
|
4173
|
-
//
|
|
4182
|
+
// triangulate the shape
|
|
4174
4183
|
for (let i = 1; i < shapeVertCount - 1; i++) {
|
|
4175
4184
|
let v0 = 0;
|
|
4176
4185
|
let v1 = i * 4;
|
|
@@ -4184,7 +4193,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4184
4193
|
}
|
|
4185
4194
|
|
|
4186
4195
|
if ($._doStroke) {
|
|
4187
|
-
//
|
|
4196
|
+
// draw lines between vertices
|
|
4188
4197
|
for (let i = 0; i < shapeVertCount - 1; i++) {
|
|
4189
4198
|
let v1 = i * 4;
|
|
4190
4199
|
let v2 = (i + 1) * 4;
|
|
@@ -4197,7 +4206,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4197
4206
|
}
|
|
4198
4207
|
}
|
|
4199
4208
|
|
|
4200
|
-
//
|
|
4209
|
+
// reset for the next shape
|
|
4201
4210
|
shapeVertCount = 0;
|
|
4202
4211
|
sv = [];
|
|
4203
4212
|
curveVertices = [];
|
|
@@ -4412,7 +4421,7 @@ fn fragmentMain(@location(0) texCoord: vec2f) -> @location(0) vec4f {
|
|
|
4412
4421
|
|
|
4413
4422
|
tIdx = (tIdx + 1) % MAX_TEXTURES;
|
|
4414
4423
|
|
|
4415
|
-
//
|
|
4424
|
+
// if the texture array is full, destroy the oldest texture
|
|
4416
4425
|
if ($._textures[tIdx]) {
|
|
4417
4426
|
$._textures[tIdx].destroy();
|
|
4418
4427
|
delete $._textures[tIdx];
|
|
@@ -4679,8 +4688,9 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
|
|
|
4679
4688
|
getChar(charCode) {
|
|
4680
4689
|
return this.chars[charCode] ?? this.defaultChar;
|
|
4681
4690
|
}
|
|
4682
|
-
// Gets the distance in pixels a line should advance for a given
|
|
4683
|
-
// character code
|
|
4691
|
+
// Gets the distance in pixels a line should advance for a given
|
|
4692
|
+
// character code. If the upcoming character code is given any
|
|
4693
|
+
// kerning between the two characters will be taken into account.
|
|
4684
4694
|
getXAdvance(charCode, nextCharCode = -1) {
|
|
4685
4695
|
let char = this.getChar(charCode);
|
|
4686
4696
|
if (nextCharCode >= 0) {
|
|
@@ -4722,8 +4732,8 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
|
|
|
4722
4732
|
});
|
|
4723
4733
|
Q5.device.queue.copyExternalImageToTexture({ source: img }, { texture }, imgSize);
|
|
4724
4734
|
|
|
4725
|
-
//
|
|
4726
|
-
//
|
|
4735
|
+
// chars and kernings can be stored as csv strings, making the file
|
|
4736
|
+
// size smaller, but they need to be parsed into arrays of objects
|
|
4727
4737
|
if (typeof atlas.chars == 'string') {
|
|
4728
4738
|
atlas.chars = $.CSV.parse(atlas.chars, ' ');
|
|
4729
4739
|
atlas.kernings = $.CSV.parse(atlas.kernings, ' ');
|
|
@@ -4849,7 +4859,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
|
|
|
4849
4859
|
let charCode = nextCharCode;
|
|
4850
4860
|
nextCharCode = i < text.length - 1 ? text.charCodeAt(i + 1) : -1;
|
|
4851
4861
|
switch (charCode) {
|
|
4852
|
-
case 10: //
|
|
4862
|
+
case 10: // newline
|
|
4853
4863
|
lineWidths.push(offsetX);
|
|
4854
4864
|
line++;
|
|
4855
4865
|
maxWidth = Math.max(maxWidth, offsetX);
|
|
@@ -4858,11 +4868,11 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
|
|
|
4858
4868
|
break;
|
|
4859
4869
|
case 13: // CR
|
|
4860
4870
|
break;
|
|
4861
|
-
case 32: //
|
|
4871
|
+
case 32: // space
|
|
4862
4872
|
// advance the offset without actually adding a character
|
|
4863
4873
|
offsetX += font.getXAdvance(charCode);
|
|
4864
4874
|
break;
|
|
4865
|
-
case 9: //
|
|
4875
|
+
case 9: // tab
|
|
4866
4876
|
offsetX += font.getXAdvance(charCode) * 2;
|
|
4867
4877
|
break;
|
|
4868
4878
|
default:
|
|
@@ -4887,7 +4897,8 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
|
|
|
4887
4897
|
|
|
4888
4898
|
$.text = (str, x, y, w, h) => {
|
|
4889
4899
|
if (!$._font) {
|
|
4890
|
-
// check if online and loading the default font
|
|
4900
|
+
// check if online and loading the default font
|
|
4901
|
+
// hasn't been attempted yet
|
|
4891
4902
|
if (navigator.onLine && !initLoadDefaultFont) {
|
|
4892
4903
|
initLoadDefaultFont = true;
|
|
4893
4904
|
$.loadFont('https://q5js.org/fonts/YaHei-msdf.json');
|
|
@@ -5046,27 +5057,27 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
|
|
|
5046
5057
|
$._hooks.preRender.push(() => {
|
|
5047
5058
|
if (!$._charStack.length) return;
|
|
5048
5059
|
|
|
5049
|
-
//
|
|
5060
|
+
// calculate total buffer size for text data
|
|
5050
5061
|
let totalTextSize = 0;
|
|
5051
5062
|
for (let charsData of $._charStack) {
|
|
5052
5063
|
totalTextSize += charsData.length * 4;
|
|
5053
5064
|
}
|
|
5054
5065
|
|
|
5055
|
-
//
|
|
5066
|
+
// create a single buffer for all the char data
|
|
5056
5067
|
let charBuffer = Q5.device.createBuffer({
|
|
5057
5068
|
size: totalTextSize,
|
|
5058
5069
|
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
|
|
5059
5070
|
mappedAtCreation: true
|
|
5060
5071
|
});
|
|
5061
5072
|
|
|
5062
|
-
//
|
|
5073
|
+
// copy all the text data into the buffer
|
|
5063
5074
|
new Float32Array(charBuffer.getMappedRange()).set($._charStack.flat());
|
|
5064
5075
|
charBuffer.unmap();
|
|
5065
5076
|
|
|
5066
|
-
//
|
|
5077
|
+
// calculate total buffer size for metadata
|
|
5067
5078
|
let totalMetadataSize = $._textStack.length * 6 * 4;
|
|
5068
5079
|
|
|
5069
|
-
//
|
|
5080
|
+
// create a single buffer for all metadata
|
|
5070
5081
|
let textBuffer = Q5.device.createBuffer({
|
|
5071
5082
|
label: 'textBuffer',
|
|
5072
5083
|
size: totalMetadataSize,
|
|
@@ -5074,11 +5085,11 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
|
|
|
5074
5085
|
mappedAtCreation: true
|
|
5075
5086
|
});
|
|
5076
5087
|
|
|
5077
|
-
//
|
|
5088
|
+
// copy all metadata into the buffer
|
|
5078
5089
|
new Float32Array(textBuffer.getMappedRange()).set($._textStack.flat());
|
|
5079
5090
|
textBuffer.unmap();
|
|
5080
5091
|
|
|
5081
|
-
//
|
|
5092
|
+
// create a single bind group for the text buffer and metadata buffer
|
|
5082
5093
|
$._textBindGroup = Q5.device.createBindGroup({
|
|
5083
5094
|
label: 'msdf text bind group',
|
|
5084
5095
|
layout: textBindGroupLayout,
|