q5 2.0.17 → 2.1.0
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/settings.json +3 -0
- package/README.md +8 -5
- package/package.json +5 -4
- package/q5-webgpu.js +3308 -0
- package/q5-webgpu.min.js +8 -0
- package/q5.js +531 -565
- package/q5.min.js +2 -2
- package/src/q5-2d-canvas.js +50 -174
- package/src/q5-2d-drawing.js +8 -39
- package/src/q5-2d-image.js +141 -279
- package/src/q5-2d-soft-filters.js +6 -6
- package/src/q5-2d-text.js +3 -3
- package/src/q5-ai.js +2 -2
- package/src/q5-canvas.js +200 -0
- package/src/q5-color.js +56 -30
- package/src/q5-core.js +41 -33
- package/src/q5-display.js +6 -0
- package/src/q5-input.js +46 -34
- package/src/q5-math.js +3 -3
- package/src/q5-sound.js +10 -3
- package/src/q5-util.js +3 -3
- package/src/q5-vector.js +1 -1
- package/src/q5-webgpu-canvas.js +119 -0
- package/src/q5-webgpu-drawing.js +281 -0
- package/src/q5-webgpu-image.js +1 -0
- package/src/q5-webgpu-text.js +1 -0
- package/src/readme.md +83 -6
package/src/q5-canvas.js
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
Q5.modules.canvas = ($, q) => {
|
|
2
|
+
$._OffscreenCanvas =
|
|
3
|
+
window.OffscreenCanvas ||
|
|
4
|
+
function () {
|
|
5
|
+
return document.createElement('canvas');
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
if (Q5._nodejs) {
|
|
9
|
+
if (Q5._createNodeJSCanvas) {
|
|
10
|
+
q.canvas = Q5._createNodeJSCanvas(100, 100);
|
|
11
|
+
}
|
|
12
|
+
} else if ($._scope == 'image' || $._scope == 'graphics') {
|
|
13
|
+
q.canvas = new $._OffscreenCanvas(100, 100);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (!$.canvas) {
|
|
17
|
+
if (typeof document == 'object') {
|
|
18
|
+
q.canvas = document.createElement('canvas');
|
|
19
|
+
$.canvas.id = 'q5Canvas' + Q5._instanceCount;
|
|
20
|
+
$.canvas.classList.add('q5Canvas');
|
|
21
|
+
} else $.noCanvas();
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let c = $.canvas;
|
|
25
|
+
c.width = $.width = 100;
|
|
26
|
+
c.height = $.height = 100;
|
|
27
|
+
if ($._scope != 'image') {
|
|
28
|
+
c.renderer = $._renderer;
|
|
29
|
+
c[$._renderer] = true;
|
|
30
|
+
}
|
|
31
|
+
$._pixelDensity = 1;
|
|
32
|
+
|
|
33
|
+
$._adjustDisplay = () => {
|
|
34
|
+
if (c.style) {
|
|
35
|
+
c.style.width = c.w + 'px';
|
|
36
|
+
c.style.height = c.h + 'px';
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
$.createCanvas = function (w, h, options) {
|
|
41
|
+
options ??= arguments[3];
|
|
42
|
+
|
|
43
|
+
let opt = Object.assign({}, Q5.canvasOptions);
|
|
44
|
+
if (typeof options == 'object') Object.assign(opt, options);
|
|
45
|
+
|
|
46
|
+
if ($._scope != 'image') {
|
|
47
|
+
let pd = $.displayDensity();
|
|
48
|
+
if ($._scope == 'graphics') pd = this._pixelDensity;
|
|
49
|
+
else if (window.IntersectionObserver) {
|
|
50
|
+
new IntersectionObserver((e) => {
|
|
51
|
+
c.visible = e[0].isIntersecting;
|
|
52
|
+
}).observe(c);
|
|
53
|
+
}
|
|
54
|
+
$._pixelDensity = Math.ceil(pd);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
$._setCanvasSize(w, h);
|
|
58
|
+
|
|
59
|
+
Object.assign(c, opt);
|
|
60
|
+
let rend = $._createCanvas(c.w, c.h, opt);
|
|
61
|
+
|
|
62
|
+
if ($._hooks) {
|
|
63
|
+
for (let m of $._hooks.postCanvas) m();
|
|
64
|
+
}
|
|
65
|
+
return rend;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
$._save = async (data, name, ext) => {
|
|
69
|
+
name = name || 'untitled';
|
|
70
|
+
ext = ext || 'png';
|
|
71
|
+
if (ext == 'jpg' || ext == 'png' || ext == 'webp') {
|
|
72
|
+
if (data instanceof OffscreenCanvas) {
|
|
73
|
+
const blob = await data.convertToBlob({ type: 'image/' + ext });
|
|
74
|
+
data = await new Promise((resolve) => {
|
|
75
|
+
const reader = new FileReader();
|
|
76
|
+
reader.onloadend = () => resolve(reader.result);
|
|
77
|
+
reader.readAsDataURL(blob);
|
|
78
|
+
});
|
|
79
|
+
} else {
|
|
80
|
+
data = data.toDataURL('image/' + ext);
|
|
81
|
+
}
|
|
82
|
+
} else {
|
|
83
|
+
let type = 'text/plain';
|
|
84
|
+
if (ext == 'json') {
|
|
85
|
+
if (typeof data != 'string') data = JSON.stringify(data);
|
|
86
|
+
type = 'text/json';
|
|
87
|
+
}
|
|
88
|
+
data = new Blob([data], { type });
|
|
89
|
+
data = URL.createObjectURL(data);
|
|
90
|
+
}
|
|
91
|
+
let a = document.createElement('a');
|
|
92
|
+
a.href = data;
|
|
93
|
+
a.download = name + '.' + ext;
|
|
94
|
+
a.click();
|
|
95
|
+
URL.revokeObjectURL(a.href);
|
|
96
|
+
};
|
|
97
|
+
$.save = (a, b, c) => {
|
|
98
|
+
if (!a || (typeof a == 'string' && (!b || (!c && b.length < 5)))) {
|
|
99
|
+
c = b;
|
|
100
|
+
b = a;
|
|
101
|
+
a = $.canvas;
|
|
102
|
+
}
|
|
103
|
+
if (c) return $._save(a, b, c);
|
|
104
|
+
if (b) {
|
|
105
|
+
b = b.split('.');
|
|
106
|
+
$._save(a, b[0], b.at(-1));
|
|
107
|
+
} else $._save(a);
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
$._setCanvasSize = (w, h) => {
|
|
111
|
+
w ??= window.innerWidth;
|
|
112
|
+
h ??= window.innerHeight;
|
|
113
|
+
c.w = w = Math.ceil(w);
|
|
114
|
+
c.h = h = Math.ceil(h);
|
|
115
|
+
c.hw = w / 2;
|
|
116
|
+
c.hh = h / 2;
|
|
117
|
+
c.width = Math.ceil(w * $._pixelDensity);
|
|
118
|
+
c.height = Math.ceil(h * $._pixelDensity);
|
|
119
|
+
|
|
120
|
+
if (!$._da) {
|
|
121
|
+
q.width = w;
|
|
122
|
+
q.height = h;
|
|
123
|
+
} else $.flexibleCanvas($._dau);
|
|
124
|
+
|
|
125
|
+
if ($.displayMode && !c.displayMode) $.displayMode();
|
|
126
|
+
else $._adjustDisplay();
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
if ($._scope == 'image') return;
|
|
130
|
+
|
|
131
|
+
if (c && $._scope != 'graphics') {
|
|
132
|
+
c.parent = (el) => {
|
|
133
|
+
if (c.parentElement) c.parentElement.removeChild(c);
|
|
134
|
+
|
|
135
|
+
if (typeof el == 'string') el = document.getElementById(el);
|
|
136
|
+
el.append(c);
|
|
137
|
+
|
|
138
|
+
function parentResized() {
|
|
139
|
+
if ($.frameCount > 1) {
|
|
140
|
+
$._shouldResize = true;
|
|
141
|
+
$._adjustDisplay();
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
if (typeof ResizeObserver == 'function') {
|
|
145
|
+
if ($._ro) $._ro.disconnect();
|
|
146
|
+
$._ro = new ResizeObserver(parentResized);
|
|
147
|
+
$._ro.observe(el);
|
|
148
|
+
} else if (!$.frameCount) {
|
|
149
|
+
window.addEventListener('resize', parentResized);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
function addCanvas() {
|
|
154
|
+
let el = $._parent;
|
|
155
|
+
el ??= document.getElementsByTagName('main')[0];
|
|
156
|
+
if (!el) {
|
|
157
|
+
el = document.createElement('main');
|
|
158
|
+
document.body.append(el);
|
|
159
|
+
}
|
|
160
|
+
c.parent(el);
|
|
161
|
+
}
|
|
162
|
+
if (document.body) addCanvas();
|
|
163
|
+
else document.addEventListener('DOMContentLoaded', addCanvas);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
$.resizeCanvas = (w, h) => {
|
|
167
|
+
if (!$.ctx) return $.createCanvas(w, h);
|
|
168
|
+
if (w == c.w && h == c.h) return;
|
|
169
|
+
|
|
170
|
+
$._resizeCanvas(w, h);
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
$.canvas.resize = $.resizeCanvas;
|
|
174
|
+
$.canvas.save = $.saveCanvas = $.save;
|
|
175
|
+
|
|
176
|
+
$.displayDensity = () => window.devicePixelRatio;
|
|
177
|
+
$.pixelDensity = (v) => {
|
|
178
|
+
if (!v || v == $._pixelDensity) return $._pixelDensity;
|
|
179
|
+
$._pixelDensity = v;
|
|
180
|
+
$._setCanvasSize(c.w, c.h);
|
|
181
|
+
return v;
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
$.flexibleCanvas = (unit = 400) => {
|
|
185
|
+
if (unit) {
|
|
186
|
+
$._da = c.width / (unit * $._pixelDensity);
|
|
187
|
+
q.width = $._dau = unit;
|
|
188
|
+
q.height = (c.h / c.w) * unit;
|
|
189
|
+
} else $._da = 0;
|
|
190
|
+
};
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
Q5.canvasOptions = {
|
|
194
|
+
alpha: false,
|
|
195
|
+
colorSpace: 'display-p3'
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
if (!window.matchMedia || !matchMedia('(dynamic-range: high) and (color-gamut: p3)').matches) {
|
|
199
|
+
Q5.canvasOptions.colorSpace = 'srgb';
|
|
200
|
+
} else Q5.supportsHDR = true;
|
package/src/q5-color.js
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
Q5.modules.color = ($,
|
|
1
|
+
Q5.modules.color = ($, q) => {
|
|
2
2
|
$.RGB = $.RGBA = $._colorMode = 'rgb';
|
|
3
3
|
$.OKLCH = 'oklch';
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
else $.Color = Q5.ColorRGBA;
|
|
7
|
-
|
|
8
|
-
$.colorMode = (mode) => {
|
|
5
|
+
$.colorMode = (mode, format) => {
|
|
9
6
|
$._colorMode = mode;
|
|
7
|
+
let srgb = $.canvas.colorSpace == 'srgb' || mode == 'srgb';
|
|
8
|
+
format ??= srgb ? 'integer' : 'float';
|
|
9
|
+
$._colorFormat = format;
|
|
10
10
|
if (mode == 'oklch') {
|
|
11
|
-
|
|
12
|
-
} else
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
11
|
+
q.Color = Q5.ColorOKLCH;
|
|
12
|
+
} else {
|
|
13
|
+
let srgb = $.canvas.colorSpace == 'srgb';
|
|
14
|
+
if ($._colorFormat == 'integer') {
|
|
15
|
+
q.Color = srgb ? Q5.ColorRGBA_8 : Q5.ColorRGBA_P3_8;
|
|
16
|
+
} else {
|
|
17
|
+
q.Color = srgb ? Q5.ColorRGBA : Q5.ColorRGBA_P3;
|
|
18
|
+
}
|
|
17
19
|
$._colorMode = 'rgb';
|
|
18
20
|
}
|
|
19
21
|
};
|
|
@@ -58,27 +60,33 @@ Q5.modules.color = ($, p) => {
|
|
|
58
60
|
let args = arguments;
|
|
59
61
|
if (args.length == 1) {
|
|
60
62
|
if (typeof c0 == 'string') {
|
|
63
|
+
let r, g, b, a;
|
|
61
64
|
if (c0[0] == '#') {
|
|
62
65
|
if (c0.length <= 5) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
);
|
|
66
|
+
r = parseInt(c0[1] + c0[1], 16);
|
|
67
|
+
g = parseInt(c0[2] + c0[2], 16);
|
|
68
|
+
b = parseInt(c0[3] + c0[3], 16);
|
|
69
|
+
a = c0.length == 4 ? null : parseInt(c0[4] + c0[4], 16);
|
|
70
|
+
} else {
|
|
71
|
+
r = parseInt(c0.slice(1, 3), 16);
|
|
72
|
+
g = parseInt(c0.slice(3, 5), 16);
|
|
73
|
+
b = parseInt(c0.slice(5, 7), 16);
|
|
74
|
+
a = c0.length == 7 ? null : parseInt(c0.slice(7, 9), 16);
|
|
69
75
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
c0.length == 7 ? null : parseInt(c0.slice(7, 9), 16)
|
|
76
|
+
} else if ($._namedColors[c0]) [r, g, b] = $._namedColors[c0];
|
|
77
|
+
else {
|
|
78
|
+
console.error(
|
|
79
|
+
"q5 can't parse color: " + c0 + '\nOnly numeric input, hex, and common named colors are supported.'
|
|
75
80
|
);
|
|
81
|
+
return new C(0, 0, 0);
|
|
76
82
|
}
|
|
77
|
-
if ($.
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
83
|
+
if ($._colorFormat != 'integer') {
|
|
84
|
+
r /= 255;
|
|
85
|
+
g /= 255;
|
|
86
|
+
b /= 255;
|
|
87
|
+
if (a != null) a /= 255;
|
|
88
|
+
}
|
|
89
|
+
return new C(r, g, b, a);
|
|
82
90
|
}
|
|
83
91
|
if (Array.isArray(c0)) return new C(...c0);
|
|
84
92
|
}
|
|
@@ -148,7 +156,24 @@ Q5.ColorRGBA = class extends Q5.Color {
|
|
|
148
156
|
this.r = r;
|
|
149
157
|
this.g = g;
|
|
150
158
|
this.b = b;
|
|
151
|
-
this.a = a ??
|
|
159
|
+
this.a = a ?? 1;
|
|
160
|
+
}
|
|
161
|
+
get levels() {
|
|
162
|
+
return [this.r, this.g, this.b, this.a];
|
|
163
|
+
}
|
|
164
|
+
toString() {
|
|
165
|
+
return `color(srgb ${this.r} ${this.g} ${this.b} / ${this.a})`;
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
Q5.ColorRGBA_P3 = class extends Q5.ColorRGBA {
|
|
169
|
+
toString() {
|
|
170
|
+
return `color(display-p3 ${this.r} ${this.g} ${this.b} / ${this.a})`;
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
// legacy 8-bit (0-255) integer color format
|
|
174
|
+
Q5.ColorRGBA_8 = class extends Q5.ColorRGBA {
|
|
175
|
+
constructor(r, g, b, a) {
|
|
176
|
+
super(r, g, b, a ?? 255);
|
|
152
177
|
}
|
|
153
178
|
setRed(v) {
|
|
154
179
|
this.r = v;
|
|
@@ -169,9 +194,10 @@ Q5.ColorRGBA = class extends Q5.Color {
|
|
|
169
194
|
return `rgb(${this.r} ${this.g} ${this.b} / ${this.a / 255})`;
|
|
170
195
|
}
|
|
171
196
|
};
|
|
172
|
-
|
|
197
|
+
// p3 10-bit color in integer color format, for backwards compatibility
|
|
198
|
+
Q5.ColorRGBA_P3_8 = class extends Q5.ColorRGBA {
|
|
173
199
|
constructor(r, g, b, a) {
|
|
174
|
-
super(r, g, b, a);
|
|
200
|
+
super(r, g, b, a ?? 255);
|
|
175
201
|
this._edited = true;
|
|
176
202
|
}
|
|
177
203
|
get r() {
|
package/src/q5-core.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* q5.js
|
|
3
|
-
* @version 2.
|
|
3
|
+
* @version 2.1
|
|
4
4
|
* @author quinton-ashley, Tezumie, and LingDong-
|
|
5
5
|
* @license LGPL-3.0
|
|
6
6
|
* @class Q5
|
|
7
7
|
*/
|
|
8
|
-
function Q5(scope, parent) {
|
|
8
|
+
function Q5(scope, parent, renderer) {
|
|
9
9
|
let $ = this;
|
|
10
10
|
$._q5 = true;
|
|
11
|
-
$._scope = scope;
|
|
12
11
|
$._parent = parent;
|
|
12
|
+
$._renderer = renderer || 'q2d';
|
|
13
13
|
$._preloadCount = 0;
|
|
14
14
|
|
|
15
15
|
scope ??= 'global';
|
|
@@ -17,13 +17,14 @@ function Q5(scope, parent) {
|
|
|
17
17
|
if (!(window.setup || window.draw)) return;
|
|
18
18
|
scope = 'global';
|
|
19
19
|
}
|
|
20
|
+
$._scope = scope;
|
|
20
21
|
let globalScope;
|
|
21
22
|
if (scope == 'global') {
|
|
22
23
|
Q5._hasGlobal = $._isGlobal = true;
|
|
23
24
|
globalScope = !Q5._nodejs ? window : global;
|
|
24
25
|
}
|
|
25
26
|
|
|
26
|
-
let
|
|
27
|
+
let q = new Proxy($, {
|
|
27
28
|
set: (t, p, v) => {
|
|
28
29
|
$[p] = v;
|
|
29
30
|
if ($._isGlobal) globalScope[p] = v;
|
|
@@ -41,6 +42,10 @@ function Q5(scope, parent) {
|
|
|
41
42
|
$._targetFrameDuration = 16.666666666666668;
|
|
42
43
|
$._frameRate = $._fps = 60;
|
|
43
44
|
$._loop = true;
|
|
45
|
+
$._hooks = {
|
|
46
|
+
postCanvas: [],
|
|
47
|
+
preRender: []
|
|
48
|
+
};
|
|
44
49
|
|
|
45
50
|
let millisStart = 0;
|
|
46
51
|
$.millis = () => performance.now() - millisStart;
|
|
@@ -48,7 +53,7 @@ function Q5(scope, parent) {
|
|
|
48
53
|
$.noCanvas = () => {
|
|
49
54
|
if ($.canvas?.remove) $.canvas.remove();
|
|
50
55
|
$.canvas = 0;
|
|
51
|
-
|
|
56
|
+
q.ctx = q.drawingContext = 0;
|
|
52
57
|
};
|
|
53
58
|
|
|
54
59
|
if (window) {
|
|
@@ -57,10 +62,10 @@ function Q5(scope, parent) {
|
|
|
57
62
|
$.deviceOrientation = window.screen?.orientation?.type;
|
|
58
63
|
}
|
|
59
64
|
|
|
60
|
-
$._incrementPreload = () =>
|
|
61
|
-
$._decrementPreload = () =>
|
|
65
|
+
$._incrementPreload = () => q._preloadCount++;
|
|
66
|
+
$._decrementPreload = () => q._preloadCount--;
|
|
62
67
|
|
|
63
|
-
|
|
68
|
+
$._draw = (timestamp) => {
|
|
64
69
|
let ts = timestamp || performance.now();
|
|
65
70
|
$._lastFrameTime ??= ts - $._targetFrameDuration;
|
|
66
71
|
|
|
@@ -69,44 +74,43 @@ function Q5(scope, parent) {
|
|
|
69
74
|
$._shouldResize = false;
|
|
70
75
|
}
|
|
71
76
|
|
|
72
|
-
if ($._loop) looper = raf(_draw);
|
|
77
|
+
if ($._loop) looper = raf($._draw);
|
|
73
78
|
else if ($.frameCount && !$._redraw) return;
|
|
74
79
|
|
|
75
80
|
if (looper && $.frameCount) {
|
|
76
81
|
let time_since_last = ts - $._lastFrameTime;
|
|
77
|
-
if (time_since_last < $._targetFrameDuration -
|
|
82
|
+
if (time_since_last < $._targetFrameDuration - 4) return;
|
|
78
83
|
}
|
|
79
|
-
|
|
84
|
+
q.deltaTime = ts - $._lastFrameTime;
|
|
80
85
|
$._frameRate = 1000 / $.deltaTime;
|
|
81
|
-
|
|
86
|
+
q.frameCount++;
|
|
82
87
|
let pre = performance.now();
|
|
83
|
-
|
|
84
|
-
if ($.ctx) $.
|
|
88
|
+
if ($._beginRender) $._beginRender();
|
|
89
|
+
if ($.ctx) $.resetMatrix();
|
|
90
|
+
for (let m of Q5.methods.pre) m.call($);
|
|
85
91
|
$.draw();
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
p.pmouseX = $.mouseX;
|
|
92
|
-
p.pmouseY = $.mouseY;
|
|
92
|
+
if ($._render) $._render();
|
|
93
|
+
for (let m of Q5.methods.post) m.call($);
|
|
94
|
+
if ($._finishRender) $._finishRender();
|
|
95
|
+
q.pmouseX = $.mouseX;
|
|
96
|
+
q.pmouseY = $.mouseY;
|
|
93
97
|
$._lastFrameTime = ts;
|
|
94
98
|
let post = performance.now();
|
|
95
99
|
$._fps = Math.round(1000 / (post - pre));
|
|
96
|
-
}
|
|
100
|
+
};
|
|
97
101
|
$.noLoop = () => {
|
|
98
102
|
$._loop = false;
|
|
99
103
|
looper = null;
|
|
100
104
|
};
|
|
101
105
|
$.loop = () => {
|
|
102
106
|
$._loop = true;
|
|
103
|
-
if (looper == null) _draw();
|
|
107
|
+
if (looper == null) $._draw();
|
|
104
108
|
};
|
|
105
109
|
$.isLooping = () => $._loop;
|
|
106
110
|
$.redraw = (n = 1) => {
|
|
107
111
|
$._redraw = true;
|
|
108
112
|
for (let i = 0; i < n; i++) {
|
|
109
|
-
_draw();
|
|
113
|
+
$._draw();
|
|
110
114
|
}
|
|
111
115
|
$._redraw = false;
|
|
112
116
|
};
|
|
@@ -136,7 +140,12 @@ function Q5(scope, parent) {
|
|
|
136
140
|
$.describe = () => {};
|
|
137
141
|
|
|
138
142
|
for (let m in Q5.modules) {
|
|
139
|
-
Q5.modules[m]($,
|
|
143
|
+
Q5.modules[m]($, q);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
let r = Q5.renderers[$._renderer];
|
|
147
|
+
for (let m in r) {
|
|
148
|
+
r[m]($, q);
|
|
140
149
|
}
|
|
141
150
|
|
|
142
151
|
// INIT
|
|
@@ -147,12 +156,14 @@ function Q5(scope, parent) {
|
|
|
147
156
|
}
|
|
148
157
|
}
|
|
149
158
|
|
|
159
|
+
if (scope == 'graphics') return;
|
|
160
|
+
|
|
150
161
|
if (scope == 'global') {
|
|
151
162
|
Object.assign(Q5, $);
|
|
152
163
|
delete Q5.Q5;
|
|
153
164
|
}
|
|
154
165
|
|
|
155
|
-
for (let m of Q5.
|
|
166
|
+
for (let m of Q5.methods.init) {
|
|
156
167
|
m.call($);
|
|
157
168
|
}
|
|
158
169
|
|
|
@@ -169,8 +180,6 @@ function Q5(scope, parent) {
|
|
|
169
180
|
|
|
170
181
|
if (typeof scope == 'function') scope($);
|
|
171
182
|
|
|
172
|
-
if (scope == 'graphics') return;
|
|
173
|
-
|
|
174
183
|
Q5._instanceCount++;
|
|
175
184
|
|
|
176
185
|
let raf =
|
|
@@ -218,8 +227,6 @@ function Q5(scope, parent) {
|
|
|
218
227
|
|
|
219
228
|
if (!($.setup || $.draw)) return;
|
|
220
229
|
|
|
221
|
-
$._startDone = false;
|
|
222
|
-
|
|
223
230
|
async function _start() {
|
|
224
231
|
$._startDone = true;
|
|
225
232
|
if ($._preloadCount > 0) return raf(_start);
|
|
@@ -229,7 +236,7 @@ function Q5(scope, parent) {
|
|
|
229
236
|
if ($.ctx === null) $.createCanvas(100, 100);
|
|
230
237
|
$._setupDone = true;
|
|
231
238
|
if ($.ctx) $.resetMatrix();
|
|
232
|
-
raf(_draw);
|
|
239
|
+
raf($._draw);
|
|
233
240
|
}
|
|
234
241
|
|
|
235
242
|
if ((arguments.length && scope != 'namespace') || preloadDefined) {
|
|
@@ -243,6 +250,7 @@ function Q5(scope, parent) {
|
|
|
243
250
|
}
|
|
244
251
|
}
|
|
245
252
|
|
|
253
|
+
Q5.renderers = {};
|
|
246
254
|
Q5.modules = {};
|
|
247
255
|
|
|
248
256
|
Q5._nodejs = typeof process == 'object';
|
|
@@ -253,13 +261,13 @@ Q5._friendlyError = (msg, func) => {
|
|
|
253
261
|
};
|
|
254
262
|
Q5._validateParameters = () => true;
|
|
255
263
|
|
|
256
|
-
Q5.
|
|
264
|
+
Q5.methods = {
|
|
257
265
|
init: [],
|
|
258
266
|
pre: [],
|
|
259
267
|
post: [],
|
|
260
268
|
remove: []
|
|
261
269
|
};
|
|
262
|
-
Q5.prototype.registerMethod = (m, fn) => Q5.
|
|
270
|
+
Q5.prototype.registerMethod = (m, fn) => Q5.methods[m].push(fn);
|
|
263
271
|
Q5.prototype.registerPreloadMethod = (n, fn) => (Q5.prototype[n] = fn[n]);
|
|
264
272
|
|
|
265
273
|
if (Q5._nodejs) global.p5 ??= global.Q5 = Q5;
|
package/src/q5-display.js
CHANGED
|
@@ -84,4 +84,10 @@ main {
|
|
|
84
84
|
Object.assign(c, { displayMode, renderQuality, displayScale });
|
|
85
85
|
$._adjustDisplay();
|
|
86
86
|
};
|
|
87
|
+
|
|
88
|
+
$.fullscreen = (v) => {
|
|
89
|
+
if (v === undefined) return document.fullscreenElement;
|
|
90
|
+
if (v) document.body.requestFullscreen();
|
|
91
|
+
else document.body.exitFullscreen();
|
|
92
|
+
};
|
|
87
93
|
};
|
package/src/q5-input.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
Q5.modules.input = ($,
|
|
1
|
+
Q5.modules.input = ($, q) => {
|
|
2
2
|
if ($._scope == 'graphics') return;
|
|
3
3
|
|
|
4
4
|
$.mouseX = 0;
|
|
@@ -42,17 +42,26 @@ Q5.modules.input = ($, p) => {
|
|
|
42
42
|
|
|
43
43
|
$._updateMouse = (e) => {
|
|
44
44
|
if (e.changedTouches) return;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
45
|
+
if (c) {
|
|
46
|
+
let rect = c.getBoundingClientRect();
|
|
47
|
+
let sx = c.scrollWidth / $.width || 1;
|
|
48
|
+
let sy = c.scrollHeight / $.height || 1;
|
|
49
|
+
q.mouseX = (e.clientX - rect.left) / sx;
|
|
50
|
+
q.mouseY = (e.clientY - rect.top) / sy;
|
|
51
|
+
if (c.renderer == 'webgpu') {
|
|
52
|
+
q.mouseX -= c.hw;
|
|
53
|
+
q.mouseY -= c.hh;
|
|
54
|
+
}
|
|
55
|
+
} else {
|
|
56
|
+
q.mouseX = e.clientX;
|
|
57
|
+
q.mouseY = e.clientY;
|
|
58
|
+
}
|
|
50
59
|
};
|
|
51
60
|
$._onmousedown = (e) => {
|
|
52
61
|
$._startAudio();
|
|
53
62
|
$._updateMouse(e);
|
|
54
|
-
|
|
55
|
-
|
|
63
|
+
q.mouseIsPressed = true;
|
|
64
|
+
q.mouseButton = mouseBtns[e.button];
|
|
56
65
|
$.mousePressed(e);
|
|
57
66
|
};
|
|
58
67
|
$._onmousemove = (e) => {
|
|
@@ -62,18 +71,15 @@ Q5.modules.input = ($, p) => {
|
|
|
62
71
|
};
|
|
63
72
|
$._onmouseup = (e) => {
|
|
64
73
|
$._updateMouse(e);
|
|
65
|
-
|
|
74
|
+
q.mouseIsPressed = false;
|
|
66
75
|
$.mouseReleased(e);
|
|
67
76
|
};
|
|
68
77
|
$._onclick = (e) => {
|
|
69
78
|
$._updateMouse(e);
|
|
70
|
-
|
|
79
|
+
q.mouseIsPressed = true;
|
|
71
80
|
$.mouseClicked(e);
|
|
72
|
-
|
|
81
|
+
q.mouseIsPressed = false;
|
|
73
82
|
};
|
|
74
|
-
c.addEventListener('mousedown', (e) => $._onmousedown(e));
|
|
75
|
-
c.addEventListener('mouseup', (e) => $._onmouseup(e));
|
|
76
|
-
c.addEventListener('click', (e) => $._onclick(e));
|
|
77
83
|
|
|
78
84
|
$.cursor = (name, x, y) => {
|
|
79
85
|
let pfx = '';
|
|
@@ -95,17 +101,17 @@ Q5.modules.input = ($, p) => {
|
|
|
95
101
|
$._onkeydown = (e) => {
|
|
96
102
|
if (e.repeat) return;
|
|
97
103
|
$._startAudio();
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
104
|
+
q.keyIsPressed = true;
|
|
105
|
+
q.key = e.key;
|
|
106
|
+
q.keyCode = e.keyCode;
|
|
101
107
|
keysHeld[$.keyCode] = keysHeld[$.key.toLowerCase()] = true;
|
|
102
108
|
$.keyPressed(e);
|
|
103
109
|
if (e.key.length == 1) $.keyTyped(e);
|
|
104
110
|
};
|
|
105
111
|
$._onkeyup = (e) => {
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
112
|
+
q.keyIsPressed = false;
|
|
113
|
+
q.key = e.key;
|
|
114
|
+
q.keyCode = e.keyCode;
|
|
109
115
|
keysHeld[$.keyCode] = keysHeld[$.key.toLowerCase()] = false;
|
|
110
116
|
$.keyReleased(e);
|
|
111
117
|
};
|
|
@@ -123,37 +129,43 @@ Q5.modules.input = ($, p) => {
|
|
|
123
129
|
}
|
|
124
130
|
$._ontouchstart = (e) => {
|
|
125
131
|
$._startAudio();
|
|
126
|
-
|
|
132
|
+
q.touches = [...e.touches].map(getTouchInfo);
|
|
127
133
|
if (!$._isTouchAware) {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
134
|
+
q.mouseX = $.touches[0].x;
|
|
135
|
+
q.mouseY = $.touches[0].y;
|
|
136
|
+
q.mouseIsPressed = true;
|
|
137
|
+
q.mouseButton = $.LEFT;
|
|
132
138
|
if (!$.mousePressed(e)) e.preventDefault();
|
|
133
139
|
}
|
|
134
140
|
if (!$.touchStarted(e)) e.preventDefault();
|
|
135
141
|
};
|
|
136
142
|
$._ontouchmove = (e) => {
|
|
137
|
-
|
|
143
|
+
q.touches = [...e.touches].map(getTouchInfo);
|
|
138
144
|
if (!$._isTouchAware) {
|
|
139
|
-
|
|
140
|
-
|
|
145
|
+
q.mouseX = $.touches[0].x;
|
|
146
|
+
q.mouseY = $.touches[0].y;
|
|
141
147
|
if (!$.mouseDragged(e)) e.preventDefault();
|
|
142
148
|
}
|
|
143
149
|
if (!$.touchMoved(e)) e.preventDefault();
|
|
144
150
|
};
|
|
145
151
|
$._ontouchend = (e) => {
|
|
146
|
-
|
|
152
|
+
q.touches = [...e.touches].map(getTouchInfo);
|
|
147
153
|
if (!$._isTouchAware && !$.touches.length) {
|
|
148
|
-
|
|
154
|
+
q.mouseIsPressed = false;
|
|
149
155
|
if (!$.mouseReleased(e)) e.preventDefault();
|
|
150
156
|
}
|
|
151
157
|
if (!$.touchEnded(e)) e.preventDefault();
|
|
152
158
|
};
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
159
|
+
|
|
160
|
+
if (c) {
|
|
161
|
+
c.addEventListener('mousedown', (e) => $._onmousedown(e));
|
|
162
|
+
c.addEventListener('mouseup', (e) => $._onmouseup(e));
|
|
163
|
+
c.addEventListener('click', (e) => $._onclick(e));
|
|
164
|
+
c.addEventListener('touchstart', (e) => $._ontouchstart(e));
|
|
165
|
+
c.addEventListener('touchmove', (e) => $._ontouchmove(e));
|
|
166
|
+
c.addEventListener('touchcancel', (e) => $._ontouchend(e));
|
|
167
|
+
c.addEventListener('touchend', (e) => $._ontouchend(e));
|
|
168
|
+
}
|
|
157
169
|
|
|
158
170
|
if (window) {
|
|
159
171
|
let l = window.addEventListener;
|