q5 2.9.20 → 2.9.22
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 +20 -18
- package/package.json +1 -1
- package/q5.js +196 -103
- package/q5.min.js +1 -1
- package/src/q5-2d-canvas.js +8 -2
- package/src/q5-2d-drawing.js +41 -83
- package/src/q5-2d-image.js +1 -0
- package/src/q5-2d-text.js +7 -0
- package/src/q5-canvas.js +6 -5
- package/src/q5-color.js +5 -0
- package/src/q5-core.js +11 -1
- package/src/q5-input.js +12 -0
- package/src/q5-math.js +10 -3
- package/src/q5-record.js +2 -0
- package/src/q5-vector.js +33 -0
- package/src/q5-webgpu-canvas.js +4 -4
- package/src/q5-webgpu-drawing.js +53 -5
- package/src/q5-webgpu-text.js +5 -0
package/q5.js
CHANGED
|
@@ -9,7 +9,12 @@ function Q5(scope, parent, renderer) {
|
|
|
9
9
|
let $ = this;
|
|
10
10
|
$._q5 = true;
|
|
11
11
|
$._parent = parent;
|
|
12
|
-
|
|
12
|
+
if (renderer == 'webgpu-fallback') {
|
|
13
|
+
$._webgpuFallback = true;
|
|
14
|
+
$._renderer = 'q2d';
|
|
15
|
+
} else {
|
|
16
|
+
$._renderer = renderer || 'q2d';
|
|
17
|
+
}
|
|
13
18
|
$._preloadCount = 0;
|
|
14
19
|
|
|
15
20
|
let autoLoaded = scope == 'auto';
|
|
@@ -172,6 +177,11 @@ function Q5(scope, parent, renderer) {
|
|
|
172
177
|
delete Q5.Q5;
|
|
173
178
|
}
|
|
174
179
|
|
|
180
|
+
if ($._webgpuFallback) {
|
|
181
|
+
$.colorMode('rgb', 1);
|
|
182
|
+
$._beginRender = () => $.translate($.canvas.hw, $.canvas.hh);
|
|
183
|
+
}
|
|
184
|
+
|
|
175
185
|
for (let m of Q5.methods.init) {
|
|
176
186
|
m.call($);
|
|
177
187
|
}
|
|
@@ -452,7 +462,7 @@ Q5.modules.canvas = ($, q) => {
|
|
|
452
462
|
return g;
|
|
453
463
|
};
|
|
454
464
|
|
|
455
|
-
|
|
465
|
+
async function saveFile(data, name, ext) {
|
|
456
466
|
name = name || 'untitled';
|
|
457
467
|
ext = ext || 'png';
|
|
458
468
|
if (ext == 'jpg' || ext == 'png' || ext == 'webp') {
|
|
@@ -480,18 +490,19 @@ Q5.modules.canvas = ($, q) => {
|
|
|
480
490
|
a.download = name + '.' + ext;
|
|
481
491
|
a.click();
|
|
482
492
|
URL.revokeObjectURL(a.href);
|
|
483
|
-
}
|
|
493
|
+
}
|
|
494
|
+
|
|
484
495
|
$.save = (a, b, c) => {
|
|
485
496
|
if (!a || (typeof a == 'string' && (!b || (!c && b.length < 5)))) {
|
|
486
497
|
c = b;
|
|
487
498
|
b = a;
|
|
488
499
|
a = $.canvas;
|
|
489
500
|
}
|
|
490
|
-
if (c) return
|
|
501
|
+
if (c) return saveFile(a, b, c);
|
|
491
502
|
if (b) {
|
|
492
503
|
b = b.split('.');
|
|
493
|
-
|
|
494
|
-
} else
|
|
504
|
+
saveFile(a, b[0], b.at(-1));
|
|
505
|
+
} else saveFile(a);
|
|
495
506
|
};
|
|
496
507
|
|
|
497
508
|
$._setCanvasSize = (w, h) => {
|
|
@@ -706,7 +717,7 @@ Q5.renderers.q2d.canvas = ($, q) => {
|
|
|
706
717
|
}
|
|
707
718
|
$.ctx.fillStyle = $._fill = c.toString();
|
|
708
719
|
};
|
|
709
|
-
|
|
720
|
+
|
|
710
721
|
$.stroke = function (c) {
|
|
711
722
|
$._doStroke = $._strokeSet = true;
|
|
712
723
|
if (Q5.Color) {
|
|
@@ -718,13 +729,15 @@ Q5.renderers.q2d.canvas = ($, q) => {
|
|
|
718
729
|
}
|
|
719
730
|
$.ctx.strokeStyle = $._stroke = c.toString();
|
|
720
731
|
};
|
|
732
|
+
|
|
721
733
|
$.strokeWeight = (n) => {
|
|
722
734
|
if (!n) $._doStroke = false;
|
|
723
735
|
if ($._da) n *= $._da;
|
|
724
736
|
$.ctx.lineWidth = $._strokeWeight = n || 0.0001;
|
|
725
737
|
};
|
|
726
|
-
$.noStroke = () => ($._doStroke = false);
|
|
727
738
|
|
|
739
|
+
$.noFill = () => ($._doFill = false);
|
|
740
|
+
$.noStroke = () => ($._doStroke = false);
|
|
728
741
|
$.opacity = (a) => ($.ctx.globalAlpha = a);
|
|
729
742
|
|
|
730
743
|
// DRAWING MATRIX
|
|
@@ -736,10 +749,12 @@ Q5.renderers.q2d.canvas = ($, q) => {
|
|
|
736
749
|
}
|
|
737
750
|
$.ctx.translate(x, y);
|
|
738
751
|
};
|
|
752
|
+
|
|
739
753
|
$.rotate = (r) => {
|
|
740
754
|
if ($._angleMode) r = $.radians(r);
|
|
741
755
|
$.ctx.rotate(r);
|
|
742
756
|
};
|
|
757
|
+
|
|
743
758
|
$.scale = (x, y) => {
|
|
744
759
|
if (x.x) {
|
|
745
760
|
y = x.y;
|
|
@@ -748,9 +763,11 @@ Q5.renderers.q2d.canvas = ($, q) => {
|
|
|
748
763
|
y ??= x;
|
|
749
764
|
$.ctx.scale(x, y);
|
|
750
765
|
};
|
|
766
|
+
|
|
751
767
|
$.applyMatrix = (a, b, c, d, e, f) => $.ctx.transform(a, b, c, d, e, f);
|
|
752
768
|
$.shearX = (ang) => $.ctx.transform(1, 0, $.tan(ang), 1, 0, 0);
|
|
753
769
|
$.shearY = (ang) => $.ctx.transform(1, $.tan(ang), 0, 1, 0, 0);
|
|
770
|
+
|
|
754
771
|
$.resetMatrix = () => {
|
|
755
772
|
if ($.ctx) {
|
|
756
773
|
$.ctx.resetTransform();
|
|
@@ -842,12 +859,7 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
842
859
|
|
|
843
860
|
$.line = (x0, y0, x1, y1) => {
|
|
844
861
|
if ($._doStroke) {
|
|
845
|
-
|
|
846
|
-
x0 *= $._da;
|
|
847
|
-
y0 *= $._da;
|
|
848
|
-
x1 *= $._da;
|
|
849
|
-
y1 *= $._da;
|
|
850
|
-
}
|
|
862
|
+
$._da && ((x0 *= $._da), (y0 *= $._da), (x1 *= $._da), (y1 *= $._da));
|
|
851
863
|
$.ctx.beginPath();
|
|
852
864
|
$.ctx.moveTo(x0, y0);
|
|
853
865
|
$.ctx.lineTo(x1, y1);
|
|
@@ -887,6 +899,7 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
887
899
|
$.ctx.stroke();
|
|
888
900
|
}
|
|
889
901
|
}
|
|
902
|
+
|
|
890
903
|
$.arc = (x, y, w, h, start, stop, mode) => {
|
|
891
904
|
if (start == stop) return $.ellipse(x, y, w, h);
|
|
892
905
|
|
|
@@ -896,7 +909,6 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
896
909
|
w *= $._da;
|
|
897
910
|
h *= $._da;
|
|
898
911
|
}
|
|
899
|
-
|
|
900
912
|
mode ??= $.PIE_OPEN;
|
|
901
913
|
|
|
902
914
|
if ($._ellipseMode == $.CENTER) {
|
|
@@ -915,6 +927,7 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
915
927
|
$.ctx.ellipse(x, y, w / 2, h / 2, 0, 0, $.TAU);
|
|
916
928
|
ink();
|
|
917
929
|
}
|
|
930
|
+
|
|
918
931
|
$.ellipse = (x, y, w, h) => {
|
|
919
932
|
h ??= w;
|
|
920
933
|
if ($._da) {
|
|
@@ -933,6 +946,7 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
933
946
|
ellipse((x + w) / 2, (y + h) / 2, w - x, h - y);
|
|
934
947
|
}
|
|
935
948
|
};
|
|
949
|
+
|
|
936
950
|
$.circle = (x, y, d) => {
|
|
937
951
|
if ($._ellipseMode == $.CENTER) {
|
|
938
952
|
if ($._da) {
|
|
@@ -974,6 +988,7 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
974
988
|
$.ctx.rect(x, y, w, h);
|
|
975
989
|
ink();
|
|
976
990
|
}
|
|
991
|
+
|
|
977
992
|
function roundedRect(x, y, w, h, tl, tr, br, bl) {
|
|
978
993
|
if (tl === undefined) {
|
|
979
994
|
return rect(x, y, w, h);
|
|
@@ -1006,30 +1021,34 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
1006
1021
|
roundedRect(x, y, w - x, h - y, tl, tr, br, bl);
|
|
1007
1022
|
}
|
|
1008
1023
|
};
|
|
1024
|
+
|
|
1009
1025
|
$.square = (x, y, s, tl, tr, br, bl) => {
|
|
1010
1026
|
return $.rect(x, y, s, s, tl, tr, br, bl);
|
|
1011
1027
|
};
|
|
1012
1028
|
|
|
1013
1029
|
$.beginShape = () => {
|
|
1014
|
-
curveBuff =
|
|
1030
|
+
curveBuff.length = 0;
|
|
1015
1031
|
$.ctx.beginPath();
|
|
1016
1032
|
firstVertex = true;
|
|
1017
1033
|
};
|
|
1034
|
+
|
|
1018
1035
|
$.beginContour = () => {
|
|
1019
1036
|
$.ctx.closePath();
|
|
1020
|
-
curveBuff =
|
|
1037
|
+
curveBuff.length = 0;
|
|
1021
1038
|
firstVertex = true;
|
|
1022
1039
|
};
|
|
1040
|
+
|
|
1023
1041
|
$.endContour = () => {
|
|
1024
|
-
curveBuff =
|
|
1042
|
+
curveBuff.length = 0;
|
|
1025
1043
|
firstVertex = true;
|
|
1026
1044
|
};
|
|
1045
|
+
|
|
1027
1046
|
$.vertex = (x, y) => {
|
|
1028
1047
|
if ($._da) {
|
|
1029
1048
|
x *= $._da;
|
|
1030
1049
|
y *= $._da;
|
|
1031
1050
|
}
|
|
1032
|
-
curveBuff =
|
|
1051
|
+
curveBuff.length = 0;
|
|
1033
1052
|
if (firstVertex) {
|
|
1034
1053
|
$.ctx.moveTo(x, y);
|
|
1035
1054
|
} else {
|
|
@@ -1037,6 +1056,7 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
1037
1056
|
}
|
|
1038
1057
|
firstVertex = false;
|
|
1039
1058
|
};
|
|
1059
|
+
|
|
1040
1060
|
$.bezierVertex = (cp1x, cp1y, cp2x, cp2y, x, y) => {
|
|
1041
1061
|
if ($._da) {
|
|
1042
1062
|
cp1x *= $._da;
|
|
@@ -1046,9 +1066,10 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
1046
1066
|
x *= $._da;
|
|
1047
1067
|
y *= $._da;
|
|
1048
1068
|
}
|
|
1049
|
-
curveBuff =
|
|
1069
|
+
curveBuff.length = 0;
|
|
1050
1070
|
$.ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y);
|
|
1051
1071
|
};
|
|
1072
|
+
|
|
1052
1073
|
$.quadraticVertex = (cp1x, cp1y, x, y) => {
|
|
1053
1074
|
if ($._da) {
|
|
1054
1075
|
cp1x *= $._da;
|
|
@@ -1056,15 +1077,17 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
1056
1077
|
x *= $._da;
|
|
1057
1078
|
y *= $._da;
|
|
1058
1079
|
}
|
|
1059
|
-
curveBuff =
|
|
1080
|
+
curveBuff.length = 0;
|
|
1060
1081
|
$.ctx.quadraticCurveTo(cp1x, cp1y, x, y);
|
|
1061
1082
|
};
|
|
1083
|
+
|
|
1062
1084
|
$.bezier = (x1, y1, x2, y2, x3, y3, x4, y4) => {
|
|
1063
1085
|
$.beginShape();
|
|
1064
1086
|
$.vertex(x1, y1);
|
|
1065
1087
|
$.bezierVertex(x2, y2, x3, y3, x4, y4);
|
|
1066
1088
|
$.endShape();
|
|
1067
1089
|
};
|
|
1090
|
+
|
|
1068
1091
|
$.triangle = (x1, y1, x2, y2, x3, y3) => {
|
|
1069
1092
|
$.beginShape();
|
|
1070
1093
|
$.vertex(x1, y1);
|
|
@@ -1072,6 +1095,7 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
1072
1095
|
$.vertex(x3, y3);
|
|
1073
1096
|
$.endShape($.CLOSE);
|
|
1074
1097
|
};
|
|
1098
|
+
|
|
1075
1099
|
$.quad = (x1, y1, x2, y2, x3, y3, x4, y4) => {
|
|
1076
1100
|
$.beginShape();
|
|
1077
1101
|
$.vertex(x1, y1);
|
|
@@ -1080,69 +1104,12 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
1080
1104
|
$.vertex(x4, y4);
|
|
1081
1105
|
$.endShape($.CLOSE);
|
|
1082
1106
|
};
|
|
1107
|
+
|
|
1083
1108
|
$.endShape = (close) => {
|
|
1084
|
-
curveBuff =
|
|
1109
|
+
curveBuff.length = 0;
|
|
1085
1110
|
if (close) $.ctx.closePath();
|
|
1086
1111
|
ink();
|
|
1087
1112
|
};
|
|
1088
|
-
function catmullRomSpline(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y, numPts, alpha) {
|
|
1089
|
-
function catmullromSplineGetT(t, p0x, p0y, p1x, p1y, alpha) {
|
|
1090
|
-
let a = Math.pow(p1x - p0x, 2.0) + Math.pow(p1y - p0y, 2.0);
|
|
1091
|
-
let b = Math.pow(a, alpha * 0.5);
|
|
1092
|
-
return b + t;
|
|
1093
|
-
}
|
|
1094
|
-
let pts = [];
|
|
1095
|
-
|
|
1096
|
-
let t0 = 0.0;
|
|
1097
|
-
let t1 = catmullromSplineGetT(t0, p0x, p0y, p1x, p1y, alpha);
|
|
1098
|
-
let t2 = catmullromSplineGetT(t1, p1x, p1y, p2x, p2y, alpha);
|
|
1099
|
-
let t3 = catmullromSplineGetT(t2, p2x, p2y, p3x, p3y, alpha);
|
|
1100
|
-
|
|
1101
|
-
for (let i = 0; i < numPts; i++) {
|
|
1102
|
-
let t = t1 + (i / (numPts - 1)) * (t2 - t1);
|
|
1103
|
-
let s = [
|
|
1104
|
-
(t1 - t) / (t1 - t0),
|
|
1105
|
-
(t - t0) / (t1 - t0),
|
|
1106
|
-
(t2 - t) / (t2 - t1),
|
|
1107
|
-
(t - t1) / (t2 - t1),
|
|
1108
|
-
(t3 - t) / (t3 - t2),
|
|
1109
|
-
(t - t2) / (t3 - t2),
|
|
1110
|
-
(t2 - t) / (t2 - t0),
|
|
1111
|
-
(t - t0) / (t2 - t0),
|
|
1112
|
-
(t3 - t) / (t3 - t1),
|
|
1113
|
-
(t - t1) / (t3 - t1)
|
|
1114
|
-
];
|
|
1115
|
-
for (let j = 0; j < s.length; j += 2) {
|
|
1116
|
-
if (isNaN(s[j])) {
|
|
1117
|
-
s[j] = 1;
|
|
1118
|
-
s[j + 1] = 0;
|
|
1119
|
-
}
|
|
1120
|
-
if (!isFinite(s[j])) {
|
|
1121
|
-
if (s[j] > 0) {
|
|
1122
|
-
s[j] = 1;
|
|
1123
|
-
s[j + 1] = 0;
|
|
1124
|
-
} else {
|
|
1125
|
-
s[j] = 0;
|
|
1126
|
-
s[j + 1] = 1;
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1130
|
-
let a1x = p0x * s[0] + p1x * s[1];
|
|
1131
|
-
let a1y = p0y * s[0] + p1y * s[1];
|
|
1132
|
-
let a2x = p1x * s[2] + p2x * s[3];
|
|
1133
|
-
let a2y = p1y * s[2] + p2y * s[3];
|
|
1134
|
-
let a3x = p2x * s[4] + p3x * s[5];
|
|
1135
|
-
let a3y = p2y * s[4] + p3y * s[5];
|
|
1136
|
-
let b1x = a1x * s[6] + a2x * s[7];
|
|
1137
|
-
let b1y = a1y * s[6] + a2y * s[7];
|
|
1138
|
-
let b2x = a2x * s[8] + a3x * s[9];
|
|
1139
|
-
let b2y = a2y * s[8] + a3y * s[9];
|
|
1140
|
-
let cx = b1x * s[2] + b2x * s[3];
|
|
1141
|
-
let cy = b1y * s[2] + b2y * s[3];
|
|
1142
|
-
pts.push([cx, cy]);
|
|
1143
|
-
}
|
|
1144
|
-
return pts;
|
|
1145
|
-
}
|
|
1146
1113
|
|
|
1147
1114
|
$.curveVertex = (x, y) => {
|
|
1148
1115
|
if ($._da) {
|
|
@@ -1151,20 +1118,24 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
1151
1118
|
}
|
|
1152
1119
|
curveBuff.push([x, y]);
|
|
1153
1120
|
if (curveBuff.length < 4) return;
|
|
1154
|
-
|
|
1155
|
-
let
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1121
|
+
|
|
1122
|
+
let p0 = curveBuff.at(-4),
|
|
1123
|
+
p1 = curveBuff.at(-3),
|
|
1124
|
+
p2 = curveBuff.at(-2),
|
|
1125
|
+
p3 = curveBuff.at(-1);
|
|
1126
|
+
|
|
1127
|
+
let cp1x = p1[0] + (p2[0] - p0[0]) / 6,
|
|
1128
|
+
cp1y = p1[1] + (p2[1] - p0[1]) / 6,
|
|
1129
|
+
cp2x = p2[0] - (p3[0] - p1[0]) / 6,
|
|
1130
|
+
cp2y = p2[1] - (p3[1] - p1[1]) / 6;
|
|
1131
|
+
|
|
1132
|
+
if (firstVertex) {
|
|
1133
|
+
$.ctx.moveTo(p1[0], p1[1]);
|
|
1165
1134
|
firstVertex = false;
|
|
1166
1135
|
}
|
|
1136
|
+
$.ctx.bezierCurveTo(cp1x, cp1y, cp2x, cp2y, p2[0], p2[1]);
|
|
1167
1137
|
};
|
|
1138
|
+
|
|
1168
1139
|
$.curve = (x1, y1, x2, y2, x3, y3, x4, y4) => {
|
|
1169
1140
|
$.beginShape();
|
|
1170
1141
|
$.curveVertex(x1, y1);
|
|
@@ -1173,6 +1144,7 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
1173
1144
|
$.curveVertex(x4, y4);
|
|
1174
1145
|
$.endShape();
|
|
1175
1146
|
};
|
|
1147
|
+
|
|
1176
1148
|
$.curvePoint = (a, b, c, d, t) => {
|
|
1177
1149
|
const t3 = t * t * t,
|
|
1178
1150
|
t2 = t * t,
|
|
@@ -1182,6 +1154,7 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
1182
1154
|
f4 = 0.5 * t3 - 0.5 * t2;
|
|
1183
1155
|
return a * f1 + b * f2 + c * f3 + d * f4;
|
|
1184
1156
|
};
|
|
1157
|
+
|
|
1185
1158
|
$.bezierPoint = (a, b, c, d, t) => {
|
|
1186
1159
|
const adjustedT = 1 - t;
|
|
1187
1160
|
return (
|
|
@@ -1191,6 +1164,7 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
1191
1164
|
Math.pow(t, 3) * d
|
|
1192
1165
|
);
|
|
1193
1166
|
};
|
|
1167
|
+
|
|
1194
1168
|
$.curveTangent = (a, b, c, d, t) => {
|
|
1195
1169
|
const t2 = t * t,
|
|
1196
1170
|
f1 = (-3 * t2) / 2 + 2 * t - 0.5,
|
|
@@ -1199,6 +1173,7 @@ Q5.renderers.q2d.drawing = ($) => {
|
|
|
1199
1173
|
f4 = (3 * t2) / 2 - t;
|
|
1200
1174
|
return a * f1 + b * f2 + c * f3 + d * f4;
|
|
1201
1175
|
};
|
|
1176
|
+
|
|
1202
1177
|
$.bezierTangent = (a, b, c, d, t) => {
|
|
1203
1178
|
const adjustedT = 1 - t;
|
|
1204
1179
|
return (
|
|
@@ -1316,6 +1291,7 @@ Q5.renderers.q2d.image = ($, q) => {
|
|
|
1316
1291
|
};
|
|
1317
1292
|
|
|
1318
1293
|
$.imageMode = (mode) => ($._imageMode = mode);
|
|
1294
|
+
|
|
1319
1295
|
$.image = (img, dx, dy, dw, dh, sx = 0, sy = 0, sw, sh) => {
|
|
1320
1296
|
if (!img) return;
|
|
1321
1297
|
let drawable = img?.canvas || img;
|
|
@@ -1557,6 +1533,7 @@ Q5.renderers.q2d.text = ($, q) => {
|
|
|
1557
1533
|
fontMod = true;
|
|
1558
1534
|
styleHash = -1;
|
|
1559
1535
|
};
|
|
1536
|
+
|
|
1560
1537
|
$.textSize = (x) => {
|
|
1561
1538
|
if (x == undefined || x == $._textSize) return $._textSize;
|
|
1562
1539
|
if ($._da) x *= $._da;
|
|
@@ -1568,12 +1545,14 @@ Q5.renderers.q2d.text = ($, q) => {
|
|
|
1568
1545
|
leadDiff = leading - x;
|
|
1569
1546
|
}
|
|
1570
1547
|
};
|
|
1548
|
+
|
|
1571
1549
|
$.textStyle = (x) => {
|
|
1572
1550
|
if (!x || x == emphasis) return emphasis;
|
|
1573
1551
|
emphasis = x;
|
|
1574
1552
|
fontMod = true;
|
|
1575
1553
|
styleHash = -1;
|
|
1576
1554
|
};
|
|
1555
|
+
|
|
1577
1556
|
$.textLeading = (x) => {
|
|
1578
1557
|
leadingSet = true;
|
|
1579
1558
|
if (x == undefined || x == leading) return leading;
|
|
@@ -1582,6 +1561,7 @@ Q5.renderers.q2d.text = ($, q) => {
|
|
|
1582
1561
|
leadDiff = x - $._textSize;
|
|
1583
1562
|
styleHash = -1;
|
|
1584
1563
|
};
|
|
1564
|
+
|
|
1585
1565
|
$.textAlign = (horiz, vert) => {
|
|
1586
1566
|
$.ctx.textAlign = $._textAlign = horiz;
|
|
1587
1567
|
if (vert) {
|
|
@@ -1611,6 +1591,7 @@ Q5.renderers.q2d.text = ($, q) => {
|
|
|
1611
1591
|
if (enable !== undefined) useCache = enable;
|
|
1612
1592
|
return useCache;
|
|
1613
1593
|
};
|
|
1594
|
+
|
|
1614
1595
|
$.createTextImage = (str, w, h) => {
|
|
1615
1596
|
genTextImage = true;
|
|
1616
1597
|
img = $.text(str, 0, 0, w, h);
|
|
@@ -1619,6 +1600,7 @@ Q5.renderers.q2d.text = ($, q) => {
|
|
|
1619
1600
|
};
|
|
1620
1601
|
|
|
1621
1602
|
let lines = [];
|
|
1603
|
+
|
|
1622
1604
|
$.text = (str, x, y, w, h) => {
|
|
1623
1605
|
if (str === undefined || (!$._doFill && !$._doStroke)) return;
|
|
1624
1606
|
str = str.toString();
|
|
@@ -1744,6 +1726,7 @@ Q5.renderers.q2d.text = ($, q) => {
|
|
|
1744
1726
|
$.textImage(img, x, y);
|
|
1745
1727
|
}
|
|
1746
1728
|
};
|
|
1729
|
+
|
|
1747
1730
|
$.textImage = (img, x, y) => {
|
|
1748
1731
|
if (typeof img == 'string') img = $.createTextImage(img);
|
|
1749
1732
|
|
|
@@ -1987,6 +1970,7 @@ Q5.Color = class {
|
|
|
1987
1970
|
this._q5Color = true;
|
|
1988
1971
|
}
|
|
1989
1972
|
};
|
|
1973
|
+
|
|
1990
1974
|
Q5.ColorOKLCH = class extends Q5.Color {
|
|
1991
1975
|
constructor(l, c, h, a) {
|
|
1992
1976
|
super();
|
|
@@ -1999,6 +1983,7 @@ Q5.ColorOKLCH = class extends Q5.Color {
|
|
|
1999
1983
|
return `oklch(${this.l} ${this.c} ${this.h} / ${this.a})`;
|
|
2000
1984
|
}
|
|
2001
1985
|
};
|
|
1986
|
+
|
|
2002
1987
|
Q5.ColorRGBA = class extends Q5.Color {
|
|
2003
1988
|
constructor(r, g, b, a) {
|
|
2004
1989
|
super();
|
|
@@ -2014,11 +1999,13 @@ Q5.ColorRGBA = class extends Q5.Color {
|
|
|
2014
1999
|
return `color(srgb ${this.r} ${this.g} ${this.b} / ${this.a})`;
|
|
2015
2000
|
}
|
|
2016
2001
|
};
|
|
2002
|
+
|
|
2017
2003
|
Q5.ColorRGBA_P3 = class extends Q5.ColorRGBA {
|
|
2018
2004
|
toString() {
|
|
2019
2005
|
return `color(display-p3 ${this.r} ${this.g} ${this.b} / ${this.a})`;
|
|
2020
2006
|
}
|
|
2021
2007
|
};
|
|
2008
|
+
|
|
2022
2009
|
// legacy 8-bit (0-255) integer color format
|
|
2023
2010
|
Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
|
|
2024
2011
|
constructor(r, g, b, a) {
|
|
@@ -2043,6 +2030,7 @@ Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
|
|
|
2043
2030
|
return `rgb(${this.r} ${this.g} ${this.b} / ${this.a / 255})`;
|
|
2044
2031
|
}
|
|
2045
2032
|
};
|
|
2033
|
+
|
|
2046
2034
|
// p3 10-bit color in integer color format, for backwards compatibility
|
|
2047
2035
|
Q5.ColorRGBA_P3_8 = class extends Q5.ColorRGBA {
|
|
2048
2036
|
constructor(r, g, b, a) {
|
|
@@ -2251,6 +2239,7 @@ Q5.modules.input = ($, q) => {
|
|
|
2251
2239
|
q.moveX = e.movementX;
|
|
2252
2240
|
q.moveY = e.movementY;
|
|
2253
2241
|
};
|
|
2242
|
+
|
|
2254
2243
|
$._onmousedown = (e) => {
|
|
2255
2244
|
$._startAudio();
|
|
2256
2245
|
$._updateMouse(e);
|
|
@@ -2258,22 +2247,26 @@ Q5.modules.input = ($, q) => {
|
|
|
2258
2247
|
q.mouseButton = mouseBtns[e.button];
|
|
2259
2248
|
$.mousePressed(e);
|
|
2260
2249
|
};
|
|
2250
|
+
|
|
2261
2251
|
$._onmousemove = (e) => {
|
|
2262
2252
|
$._updateMouse(e);
|
|
2263
2253
|
if ($.mouseIsPressed) $.mouseDragged(e);
|
|
2264
2254
|
else $.mouseMoved(e);
|
|
2265
2255
|
};
|
|
2256
|
+
|
|
2266
2257
|
$._onmouseup = (e) => {
|
|
2267
2258
|
$._updateMouse(e);
|
|
2268
2259
|
q.mouseIsPressed = false;
|
|
2269
2260
|
$.mouseReleased(e);
|
|
2270
2261
|
};
|
|
2262
|
+
|
|
2271
2263
|
$._onclick = (e) => {
|
|
2272
2264
|
$._updateMouse(e);
|
|
2273
2265
|
q.mouseIsPressed = true;
|
|
2274
2266
|
$.mouseClicked(e);
|
|
2275
2267
|
q.mouseIsPressed = false;
|
|
2276
2268
|
};
|
|
2269
|
+
|
|
2277
2270
|
$._onwheel = (e) => {
|
|
2278
2271
|
$._updateMouse(e);
|
|
2279
2272
|
e.delta = e.deltaY;
|
|
@@ -2291,9 +2284,11 @@ Q5.modules.input = ($, q) => {
|
|
|
2291
2284
|
}
|
|
2292
2285
|
$.canvas.style.cursor = name + pfx;
|
|
2293
2286
|
};
|
|
2287
|
+
|
|
2294
2288
|
$.noCursor = () => {
|
|
2295
2289
|
$.canvas.style.cursor = 'none';
|
|
2296
2290
|
};
|
|
2291
|
+
|
|
2297
2292
|
if (window) {
|
|
2298
2293
|
$.requestPointerLock = document.body?.requestPointerLock;
|
|
2299
2294
|
$.exitPointerLock = document.exitPointerLock;
|
|
@@ -2309,6 +2304,7 @@ Q5.modules.input = ($, q) => {
|
|
|
2309
2304
|
$.keyPressed(e);
|
|
2310
2305
|
if (e.key.length == 1) $.keyTyped(e);
|
|
2311
2306
|
};
|
|
2307
|
+
|
|
2312
2308
|
$._onkeyup = (e) => {
|
|
2313
2309
|
q.keyIsPressed = false;
|
|
2314
2310
|
q.key = e.key;
|
|
@@ -2316,6 +2312,7 @@ Q5.modules.input = ($, q) => {
|
|
|
2316
2312
|
keysHeld[$.keyCode] = keysHeld[$.key.toLowerCase()] = false;
|
|
2317
2313
|
$.keyReleased(e);
|
|
2318
2314
|
};
|
|
2315
|
+
|
|
2319
2316
|
$.keyIsDown = (v) => !!keysHeld[typeof v == 'string' ? v.toLowerCase() : v];
|
|
2320
2317
|
|
|
2321
2318
|
function getTouchInfo(touch) {
|
|
@@ -2328,6 +2325,7 @@ Q5.modules.input = ($, q) => {
|
|
|
2328
2325
|
id: touch.identifier
|
|
2329
2326
|
};
|
|
2330
2327
|
}
|
|
2328
|
+
|
|
2331
2329
|
$._ontouchstart = (e) => {
|
|
2332
2330
|
$._startAudio();
|
|
2333
2331
|
q.touches = [...e.touches].map(getTouchInfo);
|
|
@@ -2340,6 +2338,7 @@ Q5.modules.input = ($, q) => {
|
|
|
2340
2338
|
}
|
|
2341
2339
|
if (!$.touchStarted(e)) e.preventDefault();
|
|
2342
2340
|
};
|
|
2341
|
+
|
|
2343
2342
|
$._ontouchmove = (e) => {
|
|
2344
2343
|
q.touches = [...e.touches].map(getTouchInfo);
|
|
2345
2344
|
if (!$._isTouchAware) {
|
|
@@ -2349,6 +2348,7 @@ Q5.modules.input = ($, q) => {
|
|
|
2349
2348
|
}
|
|
2350
2349
|
if (!$.touchMoved(e)) e.preventDefault();
|
|
2351
2350
|
};
|
|
2351
|
+
|
|
2352
2352
|
$._ontouchend = (e) => {
|
|
2353
2353
|
q.touches = [...e.touches].map(getTouchInfo);
|
|
2354
2354
|
if (!$._isTouchAware && !$.touches.length) {
|
|
@@ -2420,13 +2420,15 @@ Q5.modules.math = ($, q) => {
|
|
|
2420
2420
|
return Math.min(Math.max(val, ostop), ostart);
|
|
2421
2421
|
}
|
|
2422
2422
|
};
|
|
2423
|
-
|
|
2424
|
-
$.constrain = (x, lo, hi) => Math.min(Math.max(x, lo), hi);
|
|
2423
|
+
|
|
2425
2424
|
$.dist = function () {
|
|
2426
2425
|
let a = arguments;
|
|
2427
2426
|
if (a.length == 4) return Math.hypot(a[0] - a[2], a[1] - a[3]);
|
|
2428
2427
|
else return Math.hypot(a[0] - a[3], a[1] - a[4], a[2] - a[5]);
|
|
2429
2428
|
};
|
|
2429
|
+
|
|
2430
|
+
$.lerp = (a, b, t) => a * (1 - t) + b * t;
|
|
2431
|
+
$.constrain = (x, lo, hi) => Math.min(Math.max(x, lo), hi);
|
|
2430
2432
|
$.norm = (value, start, stop) => $.map(value, start, stop, 0, 1);
|
|
2431
2433
|
$.sq = (x) => x * x;
|
|
2432
2434
|
$.fract = (x) => x - Math.floor(x);
|
|
@@ -2447,7 +2449,6 @@ Q5.modules.math = ($, q) => {
|
|
|
2447
2449
|
let a = Math.atan(x);
|
|
2448
2450
|
return !angleMode ? a : a * RADTODEG;
|
|
2449
2451
|
};
|
|
2450
|
-
|
|
2451
2452
|
$.atan2 = (y, x) => {
|
|
2452
2453
|
let a = Math.atan2(y, x);
|
|
2453
2454
|
return !angleMode ? a : a * RADTODEG;
|
|
@@ -2471,6 +2472,7 @@ Q5.modules.math = ($, q) => {
|
|
|
2471
2472
|
}
|
|
2472
2473
|
};
|
|
2473
2474
|
}
|
|
2475
|
+
|
|
2474
2476
|
function shr3() {
|
|
2475
2477
|
let jsr, seed;
|
|
2476
2478
|
let m = 4294967295;
|
|
@@ -2489,6 +2491,7 @@ Q5.modules.math = ($, q) => {
|
|
|
2489
2491
|
}
|
|
2490
2492
|
};
|
|
2491
2493
|
}
|
|
2494
|
+
|
|
2492
2495
|
let rng1 = shr3();
|
|
2493
2496
|
rng1.setSeed();
|
|
2494
2497
|
|
|
@@ -2505,6 +2508,7 @@ Q5.modules.math = ($, q) => {
|
|
|
2505
2508
|
return a[Math.trunc(a.length * rng1.rand())];
|
|
2506
2509
|
}
|
|
2507
2510
|
};
|
|
2511
|
+
|
|
2508
2512
|
$.randomGenerator = (method) => {
|
|
2509
2513
|
if (method == $.LCG) rng1 = lcg();
|
|
2510
2514
|
else if (method == $.SHR3) rng1 = shr3();
|
|
@@ -2660,13 +2664,16 @@ Q5.modules.math = ($, q) => {
|
|
|
2660
2664
|
q.Noise = Q5[mode[0].toUpperCase() + mode.slice(1) + 'Noise'];
|
|
2661
2665
|
_noise = null;
|
|
2662
2666
|
};
|
|
2667
|
+
|
|
2663
2668
|
$.noiseSeed = (seed) => {
|
|
2664
2669
|
_noise = new $.Noise(seed);
|
|
2665
2670
|
};
|
|
2671
|
+
|
|
2666
2672
|
$.noise = (x = 0, y = 0, z = 0) => {
|
|
2667
2673
|
_noise ??= new $.Noise();
|
|
2668
2674
|
return _noise.noise(x, y, z);
|
|
2669
2675
|
};
|
|
2676
|
+
|
|
2670
2677
|
$.noiseDetail = (lod, falloff) => {
|
|
2671
2678
|
_noise ??= new $.Noise();
|
|
2672
2679
|
if (lod > 0) _noise.octaves = lod;
|
|
@@ -2902,15 +2909,18 @@ Q5.Vector = class {
|
|
|
2902
2909
|
this._cn = null;
|
|
2903
2910
|
this._cnsq = null;
|
|
2904
2911
|
}
|
|
2912
|
+
|
|
2905
2913
|
set(x, y, z) {
|
|
2906
2914
|
this.x = x?.x || x || 0;
|
|
2907
2915
|
this.y = x?.y || y || 0;
|
|
2908
2916
|
this.z = x?.z || z || 0;
|
|
2909
2917
|
return this;
|
|
2910
2918
|
}
|
|
2919
|
+
|
|
2911
2920
|
copy() {
|
|
2912
2921
|
return new Q5.Vector(this.x, this.y, this.z);
|
|
2913
2922
|
}
|
|
2923
|
+
|
|
2914
2924
|
_arg2v(x, y, z) {
|
|
2915
2925
|
if (x?.x !== undefined) return x;
|
|
2916
2926
|
if (y !== undefined) {
|
|
@@ -2918,10 +2928,12 @@ Q5.Vector = class {
|
|
|
2918
2928
|
}
|
|
2919
2929
|
return { x: x, y: x, z: x };
|
|
2920
2930
|
}
|
|
2931
|
+
|
|
2921
2932
|
_calcNorm() {
|
|
2922
2933
|
this._cnsq = this.x * this.x + this.y * this.y + this.z * this.z;
|
|
2923
2934
|
this._cn = Math.sqrt(this._cnsq);
|
|
2924
2935
|
}
|
|
2936
|
+
|
|
2925
2937
|
add() {
|
|
2926
2938
|
let u = this._arg2v(...arguments);
|
|
2927
2939
|
this.x += u.x;
|
|
@@ -2929,6 +2941,7 @@ Q5.Vector = class {
|
|
|
2929
2941
|
this.z += u.z;
|
|
2930
2942
|
return this;
|
|
2931
2943
|
}
|
|
2944
|
+
|
|
2932
2945
|
rem() {
|
|
2933
2946
|
let u = this._arg2v(...arguments);
|
|
2934
2947
|
this.x %= u.x;
|
|
@@ -2936,6 +2949,7 @@ Q5.Vector = class {
|
|
|
2936
2949
|
this.z %= u.z;
|
|
2937
2950
|
return this;
|
|
2938
2951
|
}
|
|
2952
|
+
|
|
2939
2953
|
sub() {
|
|
2940
2954
|
let u = this._arg2v(...arguments);
|
|
2941
2955
|
this.x -= u.x;
|
|
@@ -2943,6 +2957,7 @@ Q5.Vector = class {
|
|
|
2943
2957
|
this.z -= u.z;
|
|
2944
2958
|
return this;
|
|
2945
2959
|
}
|
|
2960
|
+
|
|
2946
2961
|
mult() {
|
|
2947
2962
|
let u = this._arg2v(...arguments);
|
|
2948
2963
|
this.x *= u.x;
|
|
@@ -2950,6 +2965,7 @@ Q5.Vector = class {
|
|
|
2950
2965
|
this.z *= u.z;
|
|
2951
2966
|
return this;
|
|
2952
2967
|
}
|
|
2968
|
+
|
|
2953
2969
|
div() {
|
|
2954
2970
|
let u = this._arg2v(...arguments);
|
|
2955
2971
|
if (u.x) this.x /= u.x;
|
|
@@ -2960,18 +2976,22 @@ Q5.Vector = class {
|
|
|
2960
2976
|
else this.z = 0;
|
|
2961
2977
|
return this;
|
|
2962
2978
|
}
|
|
2979
|
+
|
|
2963
2980
|
mag() {
|
|
2964
2981
|
this._calcNorm();
|
|
2965
2982
|
return this._cn;
|
|
2966
2983
|
}
|
|
2984
|
+
|
|
2967
2985
|
magSq() {
|
|
2968
2986
|
this._calcNorm();
|
|
2969
2987
|
return this._cnsq;
|
|
2970
2988
|
}
|
|
2989
|
+
|
|
2971
2990
|
dot() {
|
|
2972
2991
|
let u = this._arg2v(...arguments);
|
|
2973
2992
|
return this.x * u.x + this.y * u.y + this.z * u.z;
|
|
2974
2993
|
}
|
|
2994
|
+
|
|
2975
2995
|
dist() {
|
|
2976
2996
|
let u = this._arg2v(...arguments);
|
|
2977
2997
|
let x = this.x - u.x;
|
|
@@ -2979,6 +2999,7 @@ Q5.Vector = class {
|
|
|
2979
2999
|
let z = this.z - u.z;
|
|
2980
3000
|
return Math.sqrt(x * x + y * y + z * z);
|
|
2981
3001
|
}
|
|
3002
|
+
|
|
2982
3003
|
cross() {
|
|
2983
3004
|
let u = this._arg2v(...arguments);
|
|
2984
3005
|
let x = this.y * u.z - this.z * u.y;
|
|
@@ -2989,6 +3010,7 @@ Q5.Vector = class {
|
|
|
2989
3010
|
this.z = z;
|
|
2990
3011
|
return this;
|
|
2991
3012
|
}
|
|
3013
|
+
|
|
2992
3014
|
normalize() {
|
|
2993
3015
|
this._calcNorm();
|
|
2994
3016
|
let n = this._cn;
|
|
@@ -3001,6 +3023,7 @@ Q5.Vector = class {
|
|
|
3001
3023
|
this._cnsq = 1;
|
|
3002
3024
|
return this;
|
|
3003
3025
|
}
|
|
3026
|
+
|
|
3004
3027
|
limit(m) {
|
|
3005
3028
|
this._calcNorm();
|
|
3006
3029
|
let n = this._cn;
|
|
@@ -3014,6 +3037,7 @@ Q5.Vector = class {
|
|
|
3014
3037
|
}
|
|
3015
3038
|
return this;
|
|
3016
3039
|
}
|
|
3040
|
+
|
|
3017
3041
|
setMag(m) {
|
|
3018
3042
|
this._calcNorm();
|
|
3019
3043
|
let n = this._cn;
|
|
@@ -3025,15 +3049,18 @@ Q5.Vector = class {
|
|
|
3025
3049
|
this._cnsq = m * m;
|
|
3026
3050
|
return this;
|
|
3027
3051
|
}
|
|
3052
|
+
|
|
3028
3053
|
heading() {
|
|
3029
3054
|
return this._$.atan2(this.y, this.x);
|
|
3030
3055
|
}
|
|
3056
|
+
|
|
3031
3057
|
setHeading(ang) {
|
|
3032
3058
|
let mag = this.mag();
|
|
3033
3059
|
this.x = mag * this._$.cos(ang);
|
|
3034
3060
|
this.y = mag * this._$.sin(ang);
|
|
3035
3061
|
return this;
|
|
3036
3062
|
}
|
|
3063
|
+
|
|
3037
3064
|
rotate(ang) {
|
|
3038
3065
|
let costh = this._$.cos(ang);
|
|
3039
3066
|
let sinth = this._$.sin(ang);
|
|
@@ -3043,12 +3070,14 @@ Q5.Vector = class {
|
|
|
3043
3070
|
this.y = vy;
|
|
3044
3071
|
return this;
|
|
3045
3072
|
}
|
|
3073
|
+
|
|
3046
3074
|
angleBetween() {
|
|
3047
3075
|
let u = this._arg2v(...arguments);
|
|
3048
3076
|
let o = Q5.Vector.cross(this, u);
|
|
3049
3077
|
let ang = this._$.atan2(o.mag(), this.dot(u));
|
|
3050
3078
|
return ang * Math.sign(o.z || 1);
|
|
3051
3079
|
}
|
|
3080
|
+
|
|
3052
3081
|
lerp() {
|
|
3053
3082
|
let args = [...arguments];
|
|
3054
3083
|
let amt = args.at(-1);
|
|
@@ -3059,6 +3088,7 @@ Q5.Vector = class {
|
|
|
3059
3088
|
this.z += (u.z - this.z) * amt;
|
|
3060
3089
|
return this;
|
|
3061
3090
|
}
|
|
3091
|
+
|
|
3062
3092
|
slerp() {
|
|
3063
3093
|
let args = [...arguments];
|
|
3064
3094
|
let amt = args.at(-1);
|
|
@@ -3097,17 +3127,21 @@ Q5.Vector = class {
|
|
|
3097
3127
|
this.z = this.z * cosMultiplier + ey.z * sinMultiplier;
|
|
3098
3128
|
return this;
|
|
3099
3129
|
}
|
|
3130
|
+
|
|
3100
3131
|
reflect(n) {
|
|
3101
3132
|
n.normalize();
|
|
3102
3133
|
return this.sub(n.mult(2 * this.dot(n)));
|
|
3103
3134
|
}
|
|
3135
|
+
|
|
3104
3136
|
array() {
|
|
3105
3137
|
return [this.x, this.y, this.z];
|
|
3106
3138
|
}
|
|
3139
|
+
|
|
3107
3140
|
equals(u, epsilon) {
|
|
3108
3141
|
epsilon ??= Number.EPSILON || 0;
|
|
3109
3142
|
return Math.abs(u.x - this.x) < epsilon && Math.abs(u.y - this.y) < epsilon && Math.abs(u.z - this.z) < epsilon;
|
|
3110
3143
|
}
|
|
3144
|
+
|
|
3111
3145
|
fromAngle(th, l) {
|
|
3112
3146
|
if (l === undefined) l = 1;
|
|
3113
3147
|
this._cn = l;
|
|
@@ -3117,6 +3151,7 @@ Q5.Vector = class {
|
|
|
3117
3151
|
this.z = 0;
|
|
3118
3152
|
return this;
|
|
3119
3153
|
}
|
|
3154
|
+
|
|
3120
3155
|
fromAngles(th, ph, l) {
|
|
3121
3156
|
if (l === undefined) l = 1;
|
|
3122
3157
|
this._cn = l;
|
|
@@ -3130,18 +3165,22 @@ Q5.Vector = class {
|
|
|
3130
3165
|
this.z = l * sinth * cosph;
|
|
3131
3166
|
return this;
|
|
3132
3167
|
}
|
|
3168
|
+
|
|
3133
3169
|
random2D() {
|
|
3134
3170
|
this._cn = this._cnsq = 1;
|
|
3135
3171
|
return this.fromAngle(Math.random() * Math.PI * 2);
|
|
3136
3172
|
}
|
|
3173
|
+
|
|
3137
3174
|
random3D() {
|
|
3138
3175
|
this._cn = this._cnsq = 1;
|
|
3139
3176
|
return this.fromAngles(Math.random() * Math.PI * 2, Math.random() * Math.PI * 2);
|
|
3140
3177
|
}
|
|
3178
|
+
|
|
3141
3179
|
toString() {
|
|
3142
3180
|
return `[${this.x}, ${this.y}, ${this.z}]`;
|
|
3143
3181
|
}
|
|
3144
3182
|
};
|
|
3183
|
+
|
|
3145
3184
|
Q5.Vector.add = (v, u) => v.copy().add(u);
|
|
3146
3185
|
Q5.Vector.cross = (v, u) => v.copy().cross(u);
|
|
3147
3186
|
Q5.Vector.dist = (v, u) => Math.hypot(v.x - u.x, v.y - u.y, v.z - u.z);
|
|
@@ -3158,6 +3197,7 @@ Q5.Vector.mult = (v, u) => v.copy().mult(u);
|
|
|
3158
3197
|
Q5.Vector.normalize = (v) => v.copy().normalize();
|
|
3159
3198
|
Q5.Vector.rem = (v, u) => v.copy().rem(u);
|
|
3160
3199
|
Q5.Vector.sub = (v, u) => v.copy().sub(u);
|
|
3200
|
+
|
|
3161
3201
|
for (let k of ['fromAngle', 'fromAngles', 'random2D', 'random3D']) {
|
|
3162
3202
|
Q5.Vector[k] = (u, v, t) => new Q5.Vector()[k](u, v, t);
|
|
3163
3203
|
}
|
|
@@ -3477,6 +3517,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3477
3517
|
if ($._matrixDirty) $._saveMatrix();
|
|
3478
3518
|
$._transformIndexStack.push($._transformIndex);
|
|
3479
3519
|
};
|
|
3520
|
+
|
|
3480
3521
|
$.popMatrix = () => {
|
|
3481
3522
|
if (!$._transformIndexStack.length) {
|
|
3482
3523
|
return console.warn('Matrix index stack is empty!');
|
|
@@ -3492,6 +3533,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3492
3533
|
$.pushMatrix();
|
|
3493
3534
|
$.pushStyles();
|
|
3494
3535
|
};
|
|
3536
|
+
|
|
3495
3537
|
$.pop = () => {
|
|
3496
3538
|
$.popMatrix();
|
|
3497
3539
|
$.popStyles();
|
|
@@ -3573,6 +3615,7 @@ Q5.renderers.webgpu.canvas = ($, q) => {
|
|
|
3573
3615
|
}
|
|
3574
3616
|
|
|
3575
3617
|
$._blendMode = 'normal';
|
|
3618
|
+
|
|
3576
3619
|
$.blendMode = (mode) => {
|
|
3577
3620
|
if (mode == $._blendMode) return;
|
|
3578
3621
|
if (mode == 'source-over') mode = 'normal';
|
|
@@ -3717,10 +3760,7 @@ Q5.initWebGPU = async () => {
|
|
|
3717
3760
|
Q5.webgpu = async function (scope, parent) {
|
|
3718
3761
|
if (!scope || scope == 'global') Q5._hasGlobal = true;
|
|
3719
3762
|
if (!(await Q5.initWebGPU())) {
|
|
3720
|
-
|
|
3721
|
-
q.colorMode('rgb', 1);
|
|
3722
|
-
q._beginRender = () => q.translate(q.canvas.hw, q.canvas.hh);
|
|
3723
|
-
return q;
|
|
3763
|
+
return new Q5(scope, parent, 'webgpu-fallback');
|
|
3724
3764
|
}
|
|
3725
3765
|
return new Q5(scope, parent, 'webgpu');
|
|
3726
3766
|
};
|
|
@@ -4048,10 +4088,12 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4048
4088
|
|
|
4049
4089
|
let shapeVertCount;
|
|
4050
4090
|
let sv = []; // shape vertices
|
|
4091
|
+
let curveVertices = []; // curve vertices
|
|
4051
4092
|
|
|
4052
4093
|
$.beginShape = () => {
|
|
4053
4094
|
shapeVertCount = 0;
|
|
4054
4095
|
sv = [];
|
|
4096
|
+
curveVertices = [];
|
|
4055
4097
|
};
|
|
4056
4098
|
|
|
4057
4099
|
$.vertex = (x, y) => {
|
|
@@ -4060,12 +4102,58 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4060
4102
|
shapeVertCount++;
|
|
4061
4103
|
};
|
|
4062
4104
|
|
|
4105
|
+
$.curveVertex = (x, y) => {
|
|
4106
|
+
if ($._matrixDirty) $._saveMatrix();
|
|
4107
|
+
curveVertices.push({ x: x, y: -y });
|
|
4108
|
+
};
|
|
4109
|
+
|
|
4063
4110
|
$.endShape = (close) => {
|
|
4111
|
+
if (curveVertices.length > 0) {
|
|
4112
|
+
// Duplicate start and end points if necessary
|
|
4113
|
+
let points = [...curveVertices];
|
|
4114
|
+
if (points.length < 4) {
|
|
4115
|
+
// Duplicate first and last points
|
|
4116
|
+
while (points.length < 4) {
|
|
4117
|
+
points.unshift(points[0]);
|
|
4118
|
+
points.push(points[points.length - 1]);
|
|
4119
|
+
}
|
|
4120
|
+
}
|
|
4121
|
+
|
|
4122
|
+
for (let i = 0; i < points.length - 3; i++) {
|
|
4123
|
+
let p0 = points[i];
|
|
4124
|
+
let p1 = points[i + 1];
|
|
4125
|
+
let p2 = points[i + 2];
|
|
4126
|
+
let p3 = points[i + 3];
|
|
4127
|
+
|
|
4128
|
+
for (let t = 0; t <= 1; t += 0.1) {
|
|
4129
|
+
let t2 = t * t;
|
|
4130
|
+
let t3 = t2 * t;
|
|
4131
|
+
|
|
4132
|
+
let x =
|
|
4133
|
+
0.5 *
|
|
4134
|
+
(2 * p1.x +
|
|
4135
|
+
(-p0.x + p2.x) * t +
|
|
4136
|
+
(2 * p0.x - 5 * p1.x + 4 * p2.x - p3.x) * t2 +
|
|
4137
|
+
(-p0.x + 3 * p1.x - 3 * p2.x + p3.x) * t3);
|
|
4138
|
+
|
|
4139
|
+
let y =
|
|
4140
|
+
0.5 *
|
|
4141
|
+
(2 * p1.y +
|
|
4142
|
+
(-p0.y + p2.y) * t +
|
|
4143
|
+
(2 * p0.y - 5 * p1.y + 4 * p2.y - p3.y) * t2 +
|
|
4144
|
+
(-p0.y + 3 * p1.y - 3 * p2.y + p3.y) * t3);
|
|
4145
|
+
|
|
4146
|
+
sv.push(x, y, $._fill, $._transformIndex);
|
|
4147
|
+
shapeVertCount++;
|
|
4148
|
+
}
|
|
4149
|
+
}
|
|
4150
|
+
}
|
|
4151
|
+
|
|
4064
4152
|
if (shapeVertCount < 3) {
|
|
4065
4153
|
throw new Error('A shape must have at least 3 vertices.');
|
|
4066
4154
|
}
|
|
4067
4155
|
|
|
4068
|
-
//
|
|
4156
|
+
// Close the shape if needed
|
|
4069
4157
|
if (close) {
|
|
4070
4158
|
let firstIndex = 0;
|
|
4071
4159
|
let lastIndex = (shapeVertCount - 1) * 4;
|
|
@@ -4076,14 +4164,13 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4076
4164
|
let lastY = sv[lastIndex + 1];
|
|
4077
4165
|
|
|
4078
4166
|
if (firstX !== lastX || firstY !== lastY) {
|
|
4079
|
-
// append the first vertex to close the shape
|
|
4080
4167
|
sv.push(firstX, firstY, sv[firstIndex + 2], sv[firstIndex + 3]);
|
|
4081
4168
|
shapeVertCount++;
|
|
4082
4169
|
}
|
|
4083
4170
|
}
|
|
4084
4171
|
|
|
4085
4172
|
if ($._doFill) {
|
|
4086
|
-
//
|
|
4173
|
+
// Triangulate the shape
|
|
4087
4174
|
for (let i = 1; i < shapeVertCount - 1; i++) {
|
|
4088
4175
|
let v0 = 0;
|
|
4089
4176
|
let v1 = i * 4;
|
|
@@ -4097,7 +4184,7 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4097
4184
|
}
|
|
4098
4185
|
|
|
4099
4186
|
if ($._doStroke) {
|
|
4100
|
-
//
|
|
4187
|
+
// Draw lines between vertices
|
|
4101
4188
|
for (let i = 0; i < shapeVertCount - 1; i++) {
|
|
4102
4189
|
let v1 = i * 4;
|
|
4103
4190
|
let v2 = (i + 1) * 4;
|
|
@@ -4110,9 +4197,10 @@ fn fragmentMain(@location(0) color: vec4f) -> @location(0) vec4f {
|
|
|
4110
4197
|
}
|
|
4111
4198
|
}
|
|
4112
4199
|
|
|
4113
|
-
//
|
|
4200
|
+
// Reset for the next shape
|
|
4114
4201
|
shapeVertCount = 0;
|
|
4115
4202
|
sv = [];
|
|
4203
|
+
curveVertices = [];
|
|
4116
4204
|
};
|
|
4117
4205
|
|
|
4118
4206
|
$.triangle = (x1, y1, x2, y2, x3, y3) => {
|
|
@@ -4537,6 +4625,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
|
|
|
4537
4625
|
mipmapFilter: 'linear',
|
|
4538
4626
|
maxAnisotropy: 16
|
|
4539
4627
|
});
|
|
4628
|
+
|
|
4540
4629
|
let fontBindGroupLayout = Q5.device.createBindGroupLayout({
|
|
4541
4630
|
label: 'MSDF font group layout',
|
|
4542
4631
|
entries: [
|
|
@@ -4574,6 +4663,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
|
|
|
4574
4663
|
primitive: { topology: 'triangle-strip', stripIndexFormat: 'uint32' },
|
|
4575
4664
|
multisample: { count: 4 }
|
|
4576
4665
|
};
|
|
4666
|
+
|
|
4577
4667
|
$._pipelines[2] = Q5.device.createRenderPipeline($._pipelineConfigs[2]);
|
|
4578
4668
|
|
|
4579
4669
|
class MsdfFont {
|
|
@@ -4722,6 +4812,7 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
|
|
|
4722
4812
|
$.textFont = (fontName) => {
|
|
4723
4813
|
$._font = fonts[fontName];
|
|
4724
4814
|
};
|
|
4815
|
+
|
|
4725
4816
|
$.textSize = (size) => {
|
|
4726
4817
|
$._textSize = size;
|
|
4727
4818
|
if (!leadingSet) {
|
|
@@ -4729,12 +4820,14 @@ fn fragmentMain(input : VertexOutput) -> @location(0) vec4f {
|
|
|
4729
4820
|
leadDiff = leading - size;
|
|
4730
4821
|
}
|
|
4731
4822
|
};
|
|
4823
|
+
|
|
4732
4824
|
$.textLeading = (lineHeight) => {
|
|
4733
4825
|
$._font.lineHeight = leading = lineHeight;
|
|
4734
4826
|
leadDiff = leading - $._textSize;
|
|
4735
4827
|
leadPercent = leading / $._textSize;
|
|
4736
4828
|
leadingSet = true;
|
|
4737
4829
|
};
|
|
4830
|
+
|
|
4738
4831
|
$.textAlign = (horiz, vert) => {
|
|
4739
4832
|
$._textAlign = horiz;
|
|
4740
4833
|
if (vert) $._textBaseline = vert;
|