q5 1.9.2 → 1.9.3

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.
Files changed (4) hide show
  1. package/README.md +114 -79
  2. package/package.json +1 -1
  3. package/q5.js +304 -437
  4. package/q5.min.js +1 -1
package/q5.js CHANGED
@@ -10,26 +10,23 @@
10
10
  */
11
11
  function Q5(scope, parent) {
12
12
  let preloadCnt = 0;
13
- if (typeof scope == 'undefined') {
13
+ if (!scope) {
14
14
  scope = 'global';
15
15
  preloadCnt++;
16
16
  setTimeout(() => preloadCnt--, 32);
17
17
  }
18
18
  if (scope == 'auto') {
19
- if (typeof window.setup == 'undefined') return;
19
+ if (typeof window != 'object' || !(window.setup || window.draw)) return;
20
20
  else scope = 'global';
21
21
  }
22
- if (arguments.length == 1 && typeof scope != 'string' && typeof scope != 'function') {
23
- parent = arguments[0];
24
- scope = null;
25
- }
26
22
  if (scope == 'global') Q5._hasGlobal = true;
27
23
 
24
+ // CANVAS
25
+
28
26
  let $ = this;
29
27
  $.canvas = document.createElement('canvas');
30
- let ctx = ($._ctx = $.canvas.getContext('2d'));
31
- $.canvas.classList.add('p5Canvas', 'q5Canvas');
32
28
  $.canvas.id = 'defaultCanvas' + Q5._instanceCount++;
29
+ $.canvas.classList.add('p5Canvas', 'q5Canvas');
33
30
 
34
31
  $.width = 100;
35
32
  $.height = 100;
@@ -42,6 +39,9 @@ function Q5(scope, parent) {
42
39
  $._resize = () => {
43
40
  if ($.frameCount > 1) $._shouldResize = true;
44
41
  };
42
+ if (parent && typeof parent == 'string') {
43
+ parent = document.getElementById(parent);
44
+ }
45
45
  $.canvas.parent = (el) => {
46
46
  if (typeof el == 'string') el = document.getElementById(el);
47
47
  el.append($.canvas);
@@ -63,21 +63,29 @@ function Q5(scope, parent) {
63
63
  $.canvas.parent(parent);
64
64
  }
65
65
  if (document.body) appendCanvas();
66
- else window.addEventListener('load', appendCanvas);
66
+ else document.addEventListener('DOMContentLoaded', appendCanvas);
67
67
  }
68
68
 
69
- defaultStyle();
70
-
71
- $.MAGIC = 0x9a0ce55;
69
+ $._q5 = true;
72
70
  $.pixels = [];
73
71
  let imgData = null;
72
+ let ctx;
74
73
 
75
- $.createCanvas = function (width, height) {
74
+ $.createCanvas = function (width, height, renderer, options) {
75
+ if (renderer == 'webgl') throw `webgl renderer is not supported in q5, use '2d'`;
76
76
  $.width = width;
77
77
  $.height = height;
78
78
  $.canvas.width = width;
79
79
  $.canvas.height = height;
80
+ $.canvas.renderer = '2d';
81
+ let opt = Object.assign({}, Q5.canvasOptions);
82
+ if (options) Object.assign(opt, options);
83
+
84
+ ctx = $.ctx = $.drawingContext = $.canvas.getContext('2d', opt);
85
+ if (scope == 'global') window.ctx = window.drawingContext = ctx;
86
+ Object.assign($.canvas, opt);
80
87
  defaultStyle();
88
+ ctx.save();
81
89
  if (scope != 'image') {
82
90
  let pd = $.displayDensity();
83
91
  if (scope == 'graphics') pd = this._pixelDensity;
@@ -87,9 +95,7 @@ function Q5(scope, parent) {
87
95
  };
88
96
  $._createCanvas = $.createCanvas;
89
97
 
90
- //================================================================
91
98
  // IMAGE
92
- //================================================================
93
99
 
94
100
  $.loadPixels = () => {
95
101
  imgData = ctx.getImageData(0, 0, $.canvas.width, $.canvas.height);
@@ -189,7 +195,6 @@ function Q5(scope, parent) {
189
195
  }
190
196
  }
191
197
  };
192
-
193
198
  filterImpl[$.BLUR] = (data, rad) => {
194
199
  rad = rad || 1;
195
200
  rad = Math.floor(rad * $._pixelDensity);
@@ -268,6 +273,7 @@ function Q5(scope, parent) {
268
273
  tmpCtx.canvas.height = h;
269
274
  }
270
275
  }
276
+
271
277
  function makeTmpCt2(w, h) {
272
278
  if (tmpCt2 == null) {
273
279
  tmpCt2 = document.createElement('canvas').getContext('2d');
@@ -298,38 +304,38 @@ function Q5(scope, parent) {
298
304
  ctx.restore();
299
305
  }
300
306
 
307
+ function softFilter(typ, x) {
308
+ let imgData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
309
+ filterImpl[typ](imgData.data, x);
310
+ ctx.putImageData(imgData, 0, 0);
311
+ }
312
+
301
313
  $.filter = (typ, x) => {
302
- let support = $.HARDWARE_FILTERS && ctx.filter != undefined;
303
- if (support) {
304
- makeTmpCtx();
305
- if (typ == $.THRESHOLD) {
306
- x ??= 0.5;
307
- x = Math.max(x, 0.00001);
308
- let b = Math.floor((0.5 / x) * 100);
309
- nativeFilter(`saturate(0%) brightness(${b}%) contrast(1000000%)`);
310
- } else if (typ == $.GRAY) {
311
- nativeFilter(`saturate(0%)`);
312
- } else if (typ == $.OPAQUE) {
313
- tmpCtx.fillStyle = 'black';
314
- tmpCtx.fillRect(0, 0, tmpCtx.canvas.width, tmpCtx.canvas.height);
315
- tmpCtx.drawImage(ctx.canvas, 0, 0);
316
- ctx.save();
317
- ctx.resetTransform();
318
- ctx.drawImage(tmpCtx.canvas, 0, 0);
319
- ctx.restore();
320
- } else if (typ == $.INVERT) {
321
- nativeFilter(`invert(100%)`);
322
- } else if (typ == $.BLUR) {
323
- nativeFilter(`blur(${Math.ceil((x * $._pixelDensity) / 1) || 1}px)`);
324
- } else {
325
- let imgData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
326
- filterImpl[typ](imgData.data, x);
327
- ctx.putImageData(imgData, 0, 0);
328
- }
314
+ if (!ctx.filter) return softFilter(typ, x);
315
+ makeTmpCtx();
316
+ if (typeof typ == 'string') {
317
+ nativeFilter(typ);
318
+ } else if (typ == $.THRESHOLD) {
319
+ x ??= 0.5;
320
+ x = Math.max(x, 0.00001);
321
+ let b = Math.floor((0.5 / x) * 100);
322
+ nativeFilter(`saturate(0%) brightness(${b}%) contrast(1000000%)`);
323
+ } else if (typ == $.GRAY) {
324
+ nativeFilter(`saturate(0%)`);
325
+ } else if (typ == $.OPAQUE) {
326
+ tmpCtx.fillStyle = 'black';
327
+ tmpCtx.fillRect(0, 0, tmpCtx.canvas.width, tmpCtx.canvas.height);
328
+ tmpCtx.drawImage(ctx.canvas, 0, 0);
329
+ ctx.save();
330
+ ctx.resetTransform();
331
+ ctx.drawImage(tmpCtx.canvas, 0, 0);
332
+ ctx.restore();
333
+ } else if (typ == $.INVERT) {
334
+ nativeFilter(`invert(100%)`);
335
+ } else if (typ == $.BLUR) {
336
+ nativeFilter(`blur(${Math.ceil((x * $._pixelDensity) / 1) || 1}px)`);
329
337
  } else {
330
- let imgData = ctx.getImageData(0, 0, ctx.canvas.width, ctx.canvas.height);
331
- filterImpl[typ](imgData.data, x);
332
- ctx.putImageData(imgData, 0, 0);
338
+ softFilter(typ, x);
333
339
  }
334
340
  };
335
341
 
@@ -351,7 +357,7 @@ function Q5(scope, parent) {
351
357
  let pd = $._pixelDensity || 1;
352
358
  if (x !== undefined && w === undefined) {
353
359
  let c = ctx.getImageData(x * pd, y * pd, 1, 1).data;
354
- return new Q5.Color(c[0], c[1], c[2], c[3] / 255);
360
+ return new $.Color(c[0], c[1], c[2], c[3] / 255);
355
361
  }
356
362
  x = (x || 0) * pd;
357
363
  y = (y || 0) * pd;
@@ -369,7 +375,7 @@ function Q5(scope, parent) {
369
375
  };
370
376
 
371
377
  $.set = (x, y, c) => {
372
- if (c.MAGIC == $.MAGIC) {
378
+ if (c._q5) {
373
379
  let old = $._tint;
374
380
  $._tint = null;
375
381
  $.image(c, x, y);
@@ -418,8 +424,8 @@ function Q5(scope, parent) {
418
424
  ctx.drawImage(tmpCtx.canvas, 0, 0);
419
425
  ctx.restore();
420
426
  };
421
- $.tint = function () {
422
- $._tint = $.color(...Array.from(arguments));
427
+ $.tint = (c) => {
428
+ $._tint = c._q5Color ? c : $.color(...arguments);
423
429
  };
424
430
  $.noTint = () => ($._tint = null);
425
431
 
@@ -469,9 +475,8 @@ function Q5(scope, parent) {
469
475
  $.canvas.save = $.save;
470
476
  $.saveCanvas = $.save;
471
477
 
472
- //================================================================
473
478
  // PRIVATE VARS
474
- //================================================================
479
+
475
480
  let looper = null;
476
481
  let firstVertex = true;
477
482
  let curveBuff = [];
@@ -483,18 +488,11 @@ function Q5(scope, parent) {
483
488
 
484
489
  if (scope == 'image') return;
485
490
 
486
- $.remove = () => {
487
- $.noLoop();
488
- $.canvas.remove();
489
- };
490
-
491
- //================================================================
492
491
  // CONSTANTS
493
- //================================================================
494
492
 
495
- $.RGB = 0;
496
- $.HSV = 1;
497
- $.HSB = 1;
493
+ $.RGB = 'rgb';
494
+ $.RGBA = 'rgb';
495
+ $.HSB = 'hsb';
498
496
 
499
497
  $.CHORD = 0;
500
498
  $.PIE = 1;
@@ -589,18 +587,17 @@ function Q5(scope, parent) {
589
587
  $.SHR3 = 1;
590
588
  $.LCG = 2;
591
589
 
592
- $.HARDWARE_FILTERS = true;
593
590
  $.hint = (prop, val) => {
594
591
  $[prop] = val;
595
592
  };
596
593
 
597
- //================================================================
598
594
  // PUBLIC PROPERTIES
599
- //================================================================
595
+
600
596
  $.frameCount = 0;
601
597
  $.deltaTime = 16;
602
598
  $.mouseX = 0;
603
599
  $.mouseY = 0;
600
+ $.touches = [];
604
601
  $.mouseButton = null;
605
602
  $.keyIsPressed = false;
606
603
  $.mouseIsPressed = false;
@@ -615,7 +612,6 @@ function Q5(scope, parent) {
615
612
  $.relRotationX = 0;
616
613
  $.relRotationY = 0;
617
614
  $.relRotationZ = 0;
618
-
619
615
  $.pmouseX = 0;
620
616
  $.pmouseY = 0;
621
617
  $.pAccelerationX = 0;
@@ -628,55 +624,40 @@ function Q5(scope, parent) {
628
624
  $.pRelRotationY = 0;
629
625
  $.pRelRotationZ = 0;
630
626
 
631
- $.touches = [];
627
+ Object.defineProperty($, 'deviceOrientation', {
628
+ get: () => window.screen?.orientation?.type
629
+ });
630
+ Object.defineProperty($, 'windowWidth', {
631
+ get: () => window.innerWidth
632
+ });
633
+ Object.defineProperty($, 'windowHeight', {
634
+ get: () => window.innerHeight
635
+ });
636
+
637
+ // PRIVATE PROPERTIES
632
638
 
633
- $._colorMode = $.RGB;
639
+ $._colorMode = 'rgb';
634
640
  $._doStroke = true;
635
641
  $._doFill = true;
636
642
  $._strokeSet = false;
637
643
  $._fillSet = false;
644
+ $._tint = null;
638
645
  $._ellipseMode = $.CENTER;
639
646
  $._rectMode = $.CORNER;
640
647
  $._curveDetail = 20;
641
648
  $._curveAlpha = 0.0;
642
649
  $._loop = true;
643
-
644
650
  $._textFont = 'sans-serif';
645
651
  $._textSize = 12;
646
652
  $._textLeading = 15;
647
653
  $._textLeadDiff = 3;
648
654
  $._textStyle = 'normal';
649
-
650
655
  $._pixelDensity = 1;
651
656
  $._lastFrameTime = 0;
652
657
  $._targetFrameRate = null;
653
658
  $._frameRate = $._fps = 60;
654
659
 
655
- $._tint = null;
656
-
657
- //================================================================
658
- // ALIAS PROPERTIES
659
- //================================================================
660
-
661
- Object.defineProperty($, 'deviceOrientation', {
662
- get: () => window.screen?.orientation?.type
663
- });
664
-
665
- Object.defineProperty($, 'windowWidth', {
666
- get: () => window.innerWidth
667
- });
668
-
669
- Object.defineProperty($, 'windowHeight', {
670
- get: () => window.innerHeight
671
- });
672
-
673
- Object.defineProperty($, 'drawingContext', {
674
- get: () => ctx
675
- });
676
-
677
- //================================================================
678
660
  // CANVAS
679
- //================================================================
680
661
 
681
662
  function cloneCtx() {
682
663
  let c = {};
@@ -693,8 +674,7 @@ function Q5(scope, parent) {
693
674
  let c = cloneCtx();
694
675
  $.canvas.width = width * $._pixelDensity;
695
676
  $.canvas.height = height * $._pixelDensity;
696
- ctx = $._ctx = $.canvas.getContext('2d');
697
- for (let prop in c) $._ctx[prop] = c[prop];
677
+ for (let prop in c) $.ctx[prop] = c[prop];
698
678
  if (scope != 'image') $.pixelDensity($._pixelDensity);
699
679
  };
700
680
 
@@ -706,6 +686,7 @@ function Q5(scope, parent) {
706
686
  $.createImage = (width, height) => {
707
687
  return new Q5.Image(width, height);
708
688
  };
689
+
709
690
  $.displayDensity = () => window.devicePixelRatio;
710
691
  $.pixelDensity = (n) => {
711
692
  if (n === undefined) return $._pixelDensity;
@@ -716,16 +697,13 @@ function Q5(scope, parent) {
716
697
  $.canvas.height = Math.ceil($.height * n);
717
698
  $.canvas.style.width = $.width + 'px';
718
699
  $.canvas.style.height = $.height + 'px';
719
- ctx = $._ctx = $.canvas.getContext('2d');
720
- for (let prop in c) $._ctx[prop] = c[prop];
700
+ for (let prop in c) $.ctx[prop] = c[prop];
721
701
 
722
702
  ctx.scale($._pixelDensity, $._pixelDensity);
723
703
  return $._pixelDensity;
724
704
  };
725
705
 
726
- //================================================================
727
706
  // MATH
728
- //================================================================
729
707
 
730
708
  $.map = (value, istart, istop, ostart, ostop, clamp) => {
731
709
  let val = ostart + (ostop - ostart) * (((value - istart) * 1.0) / (istop - istart));
@@ -812,10 +790,7 @@ function Q5(scope, parent) {
812
790
  };
813
791
  $.createVector = (x, y, z) => new Q5.Vector(x, y, z, $);
814
792
 
815
- //================================================================
816
- // CURVE QUERY
817
- //================================================================
818
- //https://github.com/processing/p5.js/blob/1.1.9/src/core/shape/curves.js
793
+ // CURVES
819
794
 
820
795
  $.curvePoint = (a, b, c, d, t) => {
821
796
  const t3 = t * t * t,
@@ -855,13 +830,21 @@ function Q5(scope, parent) {
855
830
  );
856
831
  };
857
832
 
858
- //================================================================
859
- // COLORS
860
- //================================================================
833
+ // COLOR
834
+
835
+ $.Color = Q5.ColorRGBA_P3;
861
836
 
862
- $.Color = Q5.Color;
863
837
  $.colorMode = (mode) => {
864
838
  $._colorMode = mode;
839
+ if (mode == 'oklch') {
840
+ $.Color = Q5.ColorOKLCH;
841
+ } else if (mode == 'rgb') {
842
+ if ($.canvas.colorSpace == 'srgb') $.Color = Q5.ColorRGBA;
843
+ else $.Color = Q5.ColorRGBA_P3;
844
+ } else if (mode == 'srgb') {
845
+ $.Color = Q5.ColorRGBA;
846
+ $._colorMode = 'rgb';
847
+ }
865
848
  };
866
849
 
867
850
  let basicColors = {
@@ -897,113 +880,64 @@ function Q5(scope, parent) {
897
880
  yellow: [255, 255, 0]
898
881
  };
899
882
 
900
- $.color = function () {
883
+ $.color = function (c0, c1, c2, c3) {
884
+ let C = $.Color;
885
+ if (c0._q5Color) return new C(...c0.levels);
901
886
  let args = arguments;
902
887
  if (args.length == 1) {
903
- if (typeof args[0] == 'string') {
904
- if (args[0][0] == '#') {
905
- return new Q5.Color(
906
- parseInt(args[0].slice(1, 3), 16),
907
- parseInt(args[0].slice(3, 5), 16),
908
- parseInt(args[0].slice(5, 7), 16),
909
- 1
888
+ if (typeof c0 == 'string') {
889
+ if (c0[0] == '#') {
890
+ return new C(
891
+ parseInt(c0.slice(1, 3), 16),
892
+ parseInt(c0.slice(3, 5), 16),
893
+ parseInt(c0.slice(5, 7), 16),
894
+ c0.length != 9 ? null : parseInt(c0.slice(7, 9), 16)
910
895
  );
911
- } else {
912
- if (basicColors[args[0]]) {
913
- return new Q5.Color(...basicColors[args[0]], 1);
914
- }
915
- return new Q5.Color(0, 0, 0, 1);
916
- }
917
- }
918
- if (typeof args[0] != 'number' && args[0].MAGIC == 0xc010a) {
919
- return args[0];
920
- }
896
+ } else if (basicColors[c0]) return new C(...basicColors[c0]);
897
+ else return new C(0, 0, 0);
898
+ } else if (Array.isArray(c0)) return new C(...c0);
921
899
  }
922
- if ($._colorMode == $.RGB) {
923
- if (args.length == 1) {
924
- return new Q5.Color(args[0], args[0], args[0], 1);
925
- } else if (args.length == 2) {
926
- return new Q5.Color(args[0], args[0], args[0], args[1] / 255);
927
- } else if (args.length == 3) {
928
- return new Q5.Color(args[0], args[1], args[2], 1);
929
- } else if (args.length == 4) {
930
- return new Q5.Color(args[0], args[1], args[2], args[3] / 255);
931
- }
932
- } else {
933
- if (args.length == 1) {
934
- return new Q5.Color(...Q5.Color._hsv2rgb(0, 0, args[0] / 100), 1);
935
- } else if (args.length == 2) {
936
- return new Q5.Color(...Q5.Color._hsv2rgb(0, 0, args[0] / 100), args[1] / 255);
937
- } else if (args.length == 3) {
938
- return new Q5.Color(...Q5.Color._hsv2rgb(args[0], args[1] / 100, args[2] / 100), 1);
939
- } else if (args.length == 4) {
940
- return new Q5.Color(...Q5.Color._hsv2rgb(args[0], args[1] / 100, args[2] / 100), args[3]);
941
- }
900
+ if ($._colorMode == 'rgb') {
901
+ if (args.length == 1) return new C(c0, c0, c0);
902
+ else if (args.length == 2) return new C(c0, c0, c0, c1);
903
+ else if (args.length == 3) return new C(c0, c1, c2);
904
+ else if (args.length == 4) return new C(c0, c1, c2, c3);
942
905
  }
943
- return null;
944
906
  };
945
907
 
946
- $.red = (c) => {
947
- return c._r;
948
- };
949
- $.green = (c) => {
950
- return c._g;
951
- };
952
- $.blue = (c) => {
953
- return c._b;
954
- };
955
- $.alpha = (c) => {
956
- return c._a * 255;
957
- };
958
- $.hue = (c) => {
959
- c._inferHSV();
960
- return c._h;
961
- };
962
- $.saturation = (c) => {
963
- c._inferHSV();
964
- return c._s;
965
- };
966
- $.brightness = (c) => {
967
- c._inferHSV();
968
- return c._v;
969
- };
908
+ $.red = (c) => c._r;
909
+ $.green = (c) => c._g;
910
+ $.blue = (c) => c._b;
911
+ $.alpha = (c) => c._a;
970
912
  $.lightness = (c) => {
971
913
  return ((0.2126 * c._r + 0.7152 * c._g + 0.0722 * c._b) * 100) / 255;
972
914
  };
973
915
 
974
- function lerpHue(h0, h1, t) {
975
- var methods = [
976
- [Math.abs(h1 - h0), $.map(t, 0, 1, h0, h1)],
977
- [Math.abs(h1 + 360 - h0), $.map(t, 0, 1, h0, h1 + 360)],
978
- [Math.abs(h1 - 360 - h0), $.map(t, 0, 1, h0, h1 - 360)]
979
- ];
980
- methods.sort((x, y) => x[0] - y[0]);
981
- return (methods[0][1] + 720) % 360;
982
- }
983
-
984
916
  $.lerpColor = (a, b, t) => {
985
- if ($._colorMode == $.RGB) {
986
- return new Q5.Color(
987
- $.constrain($.lerp(a._r, b._r, t), 0, 255),
988
- $.constrain($.lerp(a._g, b._g, t), 0, 255),
989
- $.constrain($.lerp(a._b, b._b, t), 0, 255),
990
- $.constrain($.lerp(a._a, b._a, t), 0, 1)
917
+ if ($._colorMode == 'rgb') {
918
+ return new $.Color(
919
+ $.constrain($.lerp(a.r, b.r, t), 0, 255),
920
+ $.constrain($.lerp(a.g, b.g, t), 0, 255),
921
+ $.constrain($.lerp(a.b, b.b, t), 0, 255),
922
+ $.constrain($.lerp(a.a, b.a, t), 0, 255)
991
923
  );
992
924
  } else {
993
- a._inferHSV();
994
- b._inferHSV();
995
- return new Q5.Color(
996
- $.constrain(lerpHue(a._h, b._h, t), 0, 360),
997
- $.constrain($.lerp(a._s, b._s, t), 0, 100),
998
- $.constrain($.lerp(a._v, b._v, t), 0, 100),
999
- $.constrain($.lerp(a._a, b._a, t), 0, 1)
925
+ let deltaH = b.h - a.h;
926
+ if (deltaH > 180) deltaH -= 360;
927
+ if (deltaH < -180) deltaH += 360;
928
+ let h = a.h + t * deltaH;
929
+ if (h < 0) h += 360;
930
+ if (h > 360) h -= 360;
931
+ return new $.Color(
932
+ $.constrain($.lerp(a.l, b.l, t), 0, 100),
933
+ $.constrain($.lerp(a.c, b.c, t), 0, 100),
934
+ h,
935
+ $.constrain($.lerp(a.a, b.a, t), 0, 255)
1000
936
  );
1001
937
  }
1002
938
  };
1003
939
 
1004
- //================================================================
1005
- // DRAWING SETTING
1006
- //================================================================
940
+ // DRAWING SETTINGS
1007
941
 
1008
942
  function defaultStyle() {
1009
943
  ctx.fillStyle = 'white';
@@ -1017,34 +951,20 @@ function Q5(scope, parent) {
1017
951
  if (!n) $._doStroke = false;
1018
952
  ctx.lineWidth = n || 0.0001;
1019
953
  };
1020
- $.stroke = function () {
954
+ $.stroke = function (c) {
1021
955
  $._doStroke = true;
1022
956
  $._strokeSet = true;
1023
- if (typeof arguments[0] == 'string') {
1024
- ctx.strokeStyle = arguments[0];
1025
- return;
1026
- }
1027
- let col = $.color(...arguments);
1028
- if (col._a <= 0) {
1029
- $._doStroke = false;
1030
- return;
1031
- }
1032
- ctx.strokeStyle = col;
957
+ if (!c._q5Color) c = $.color(...arguments);
958
+ if (c._a <= 0) return ($._doStroke = false);
959
+ ctx.strokeStyle = c;
1033
960
  };
1034
961
  $.noStroke = () => ($._doStroke = false);
1035
- $.fill = function () {
962
+ $.fill = function (c) {
1036
963
  $._doFill = true;
1037
964
  $._fillSet = true;
1038
- if (typeof arguments[0] == 'string') {
1039
- ctx.fillStyle = arguments[0];
1040
- return;
1041
- }
1042
- let col = $.color(...arguments);
1043
- if (col._a <= 0) {
1044
- $._doFill = false;
1045
- return;
1046
- }
1047
- ctx.fillStyle = col;
965
+ if (!c._q5Color) c = $.color(...arguments);
966
+ if (c._a <= 0) return ($._doFill = false);
967
+ ctx.fillStyle = c;
1048
968
  };
1049
969
  $.noFill = () => ($._doFill = false);
1050
970
  $.smooth = () => ($._smooth = true);
@@ -1058,25 +978,18 @@ function Q5(scope, parent) {
1058
978
  $.curveAlpha = (x) => ($._curveAlpha = x);
1059
979
  $.curveTightness = (x) => ($._curveAlpha = x);
1060
980
 
1061
- //================================================================
1062
981
  // DRAWING
1063
- //================================================================
1064
982
 
1065
983
  $.clear = () => {
1066
984
  ctx.clearRect(0, 0, $.canvas.width, $.canvas.height);
1067
985
  };
1068
986
 
1069
- $.background = function () {
1070
- if (arguments[0] && arguments[0].MAGIC == $.MAGIC) {
1071
- return $.image(arguments[0], 0, 0, $.width, $.height);
1072
- }
987
+ $.background = function (c) {
988
+ if (c._q5) return $.image(c, 0, 0, $.width, $.height);
1073
989
  ctx.save();
1074
990
  ctx.resetTransform();
1075
- if (typeof arguments[0] == 'string') {
1076
- ctx.fillStyle = arguments[0];
1077
- } else {
1078
- ctx.fillStyle = $.color(...Array.from(arguments));
1079
- }
991
+ if (!c._q5color) c = $.color(...arguments);
992
+ ctx.fillStyle = c;
1080
993
  ctx.fillRect(0, 0, $.canvas.width, $.canvas.height);
1081
994
  ctx.restore();
1082
995
  };
@@ -1284,7 +1197,6 @@ function Q5(scope, parent) {
1284
1197
  if ($._doFill) ctx.fill();
1285
1198
  if ($._doStroke) ctx.stroke();
1286
1199
  if (!$._doFill && !$._doStroke) {
1287
- // eh.
1288
1200
  ctx.save();
1289
1201
  ctx.fillStyle = 'none';
1290
1202
  ctx.fill();
@@ -1292,7 +1204,6 @@ function Q5(scope, parent) {
1292
1204
  }
1293
1205
  };
1294
1206
  function catmullRomSpline(p0x, p0y, p1x, p1y, p2x, p2y, p3x, p3y, numPts, alpha) {
1295
- //https://en.wikipedia.org/wiki/Centripetal_Catmull–Rom_spline
1296
1207
  function catmullromSplineGetT(t, p0x, p0y, p1x, p1y, alpha) {
1297
1208
  let a = Math.pow(p1x - p0x, 2.0) + Math.pow(p1y - p0y, 2.0);
1298
1209
  let b = Math.pow(a, alpha * 0.5);
@@ -1378,30 +1289,22 @@ function Q5(scope, parent) {
1378
1289
  $.curveVertex(x4, y4);
1379
1290
  $.endShape();
1380
1291
  };
1292
+ $.opacity = (a) => (ctx.globalAlpha = a);
1381
1293
 
1382
- //================================================================
1383
1294
  // DRAWING MATRIX
1384
- //================================================================
1295
+
1385
1296
  $.translate = (x, y) => ctx.translate(x, y);
1386
1297
  $.rotate = (r) => {
1387
1298
  if ($._angleMode == 'degrees') r = $.radians(r);
1388
1299
  ctx.rotate(r);
1389
1300
  };
1390
-
1391
1301
  $.scale = (x, y) => {
1392
1302
  y ??= x;
1393
1303
  ctx.scale(x, y);
1394
1304
  };
1395
- $.applyMatrix = (a, b, c, d, e, f) => {
1396
- ctx.transform(a, b, c, d, e, f);
1397
- };
1398
- $.shearX = (ang) => {
1399
- ctx.transform(1, 0, $.tan(ang), 1, 0, 0);
1400
- };
1401
- $.shearY = (ang) => {
1402
- ctx.transform(1, $.tan(ang), 0, 1, 0, 0);
1403
- };
1404
-
1305
+ $.applyMatrix = (a, b, c, d, e, f) => ctx.transform(a, b, c, d, e, f);
1306
+ $.shearX = (ang) => ctx.transform(1, 0, $.tan(ang), 1, 0, 0);
1307
+ $.shearY = (ang) => ctx.transform(1, $.tan(ang), 0, 1, 0, 0);
1405
1308
  $.resetMatrix = () => {
1406
1309
  ctx.resetTransform();
1407
1310
  ctx.scale($._pixelDensity, $._pixelDensity);
@@ -1425,37 +1328,27 @@ function Q5(scope, parent) {
1425
1328
  '_textStyle',
1426
1329
  '_textWrap'
1427
1330
  ];
1428
-
1429
- $._ctxStyleNames = ['strokeStyle', 'fillStyle', 'lineWidth', 'lineCap', 'lineJoin'];
1430
-
1431
1331
  $._styles = [];
1432
- $._ctxStyles = [];
1433
1332
 
1434
- $.pushMatrix = $.push = () => {
1333
+ $.push = $.pushMatrix = () => {
1435
1334
  ctx.save();
1436
1335
  let styles = {};
1437
1336
  for (let s of $._styleNames) styles[s] = $[s];
1438
1337
  $._styles.push(styles);
1439
- let ctxStyles = {};
1440
- for (let s of $._ctxStyleNames) ctxStyles[s] = ctx[s];
1441
- $._ctxStyles.push(ctxStyles);
1442
1338
  };
1443
- $.popMatrix = $.pop = () => {
1339
+ $.pop = $.popMatrix = () => {
1444
1340
  ctx.restore();
1445
1341
  let styles = $._styles.pop();
1446
1342
  for (let s of $._styleNames) $[s] = styles[s];
1447
- let ctxStyles = $._ctxStyles.pop();
1448
- for (let s of $._ctxStyleNames) ctx[s] = ctxStyles[s];
1449
1343
  };
1450
1344
 
1451
- //================================================================
1452
1345
  // IMAGING
1453
- //================================================================
1454
- $.imageMode = (mode) => ($._imageMode = mode); // TODO
1346
+
1347
+ $.imageMode = (mode) => ($._imageMode = mode);
1455
1348
  $.image = (img, dx, dy, dWidth, dHeight, sx, sy, sWidth, sHeight) => {
1456
- let drawable = img.MAGIC == $.MAGIC ? img.canvas : img;
1349
+ let drawable = img._q5 ? img.canvas : img;
1457
1350
  function reset() {
1458
- if (img.MAGIC != $.MAGIC || !$._tint) return;
1351
+ if (!img._q5 || !$._tint) return;
1459
1352
  let c = img.canvas.getContext('2d');
1460
1353
  c.save();
1461
1354
  c.resetTransform();
@@ -1463,13 +1356,13 @@ function Q5(scope, parent) {
1463
1356
  c.drawImage(tmpCt2.canvas, 0, 0);
1464
1357
  c.restore();
1465
1358
  }
1466
- if (img.MAGIC == $.MAGIC && $._tint != null) {
1359
+ if (img._q5 && $._tint != null) {
1467
1360
  makeTmpCt2(img.canvas.width, img.canvas.height);
1468
1361
  tmpCt2.drawImage(img.canvas, 0, 0);
1469
1362
  img.tinted($._tint);
1470
1363
  }
1471
1364
  if (!dWidth) {
1472
- if (img.MAGIC == $.MAGIC || img.width) {
1365
+ if (img._q5 || img.width) {
1473
1366
  dWidth = img.width;
1474
1367
  dHeight = img.height;
1475
1368
  } else {
@@ -1523,9 +1416,7 @@ function Q5(scope, parent) {
1523
1416
  tmpBuf = null;
1524
1417
  };
1525
1418
 
1526
- //================================================================
1527
1419
  // TYPOGRAPHY
1528
- //================================================================
1529
1420
 
1530
1421
  $.loadFont = (url, cb) => {
1531
1422
  preloadCnt++;
@@ -1660,7 +1551,7 @@ function Q5(scope, parent) {
1660
1551
  return;
1661
1552
  }
1662
1553
  tg = $.createGraphics.call($, 1, 1);
1663
- c = tg._ctx;
1554
+ c = tg.ctx;
1664
1555
  pd = $._pixelDensity;
1665
1556
  }
1666
1557
  c.font = `${$._textStyle} ${$._textSize}px ${$._textFont}`;
@@ -1708,11 +1599,8 @@ function Q5(scope, parent) {
1708
1599
  $._imageMode = og;
1709
1600
  };
1710
1601
 
1711
- //================================================================
1712
1602
  // RANDOM
1713
- //================================================================
1714
1603
 
1715
- //https://github.com/processing/p5.js/blob/1.1.9/src/math/noise.js
1716
1604
  var PERLIN_YWRAPB = 4;
1717
1605
  var PERLIN_YWRAP = 1 << PERLIN_YWRAPB;
1718
1606
  var PERLIN_ZWRAPB = 8;
@@ -1856,7 +1744,7 @@ function Q5(scope, parent) {
1856
1744
  return rng1.rand() * a;
1857
1745
  }
1858
1746
  } else {
1859
- return a[~~(a.length * rng1.rand())];
1747
+ return a[Math.trunc(a.length * rng1.rand())];
1860
1748
  }
1861
1749
  };
1862
1750
  $.randomGenerator = (method) => {
@@ -1866,7 +1754,6 @@ function Q5(scope, parent) {
1866
1754
  };
1867
1755
 
1868
1756
  var ziggurat = new (function () {
1869
- //http://ziggurat.glitch.me/
1870
1757
  var iz;
1871
1758
  var jz;
1872
1759
  var kn = new Array(128);
@@ -2004,29 +1891,12 @@ function Q5(scope, parent) {
2004
1891
  return ziggurat.REXP();
2005
1892
  };
2006
1893
 
2007
- //================================================================
2008
- // ENVIRONMENT
2009
- //================================================================
1894
+ // DOM
2010
1895
 
2011
- $.print = console.log;
2012
- $.cursor = (name, x, y) => {
2013
- let pfx = '';
2014
- if (name.includes('.')) {
2015
- name = `url("${name}")`;
2016
- pfx = ', auto';
2017
- }
2018
- if (x !== undefined) {
2019
- name += ' ' + x + ' ' + y;
2020
- }
2021
- $.canvas.style.cursor = name + pfx;
2022
- };
2023
- $.noCursor = () => {
2024
- $.canvas.style.cursor = 'none';
1896
+ $.Element = function (a) {
1897
+ this.elt = a;
2025
1898
  };
2026
-
2027
- //================================================================
2028
- // DOM
2029
- //================================================================
1899
+ $._elements = [];
2030
1900
 
2031
1901
  $.createCapture = (x) => {
2032
1902
  var vid = document.createElement('video');
@@ -2042,6 +1912,10 @@ function Q5(scope, parent) {
2042
1912
  return vid;
2043
1913
  };
2044
1914
 
1915
+ // ENVIRONMENT
1916
+
1917
+ $.print = console.log;
1918
+
2045
1919
  function _draw() {
2046
1920
  let pre = performance.now();
2047
1921
  if ($._loop) {
@@ -2077,7 +1951,6 @@ function Q5(scope, parent) {
2077
1951
  $.pmouseX = $.mouseX;
2078
1952
  $.pmouseY = $.mouseY;
2079
1953
  }
2080
-
2081
1954
  $.noLoop = () => {
2082
1955
  $._loop = false;
2083
1956
  looper = null;
@@ -2087,6 +1960,11 @@ function Q5(scope, parent) {
2087
1960
  if (looper == null) _draw();
2088
1961
  };
2089
1962
  $.redraw = () => _draw();
1963
+ $.remove = () => {
1964
+ $.noLoop();
1965
+ $.canvas.remove();
1966
+ };
1967
+
2090
1968
  $.frameRate = (fps) => {
2091
1969
  if (fps) $._targetFrameRate = fps;
2092
1970
  return $._frameRate;
@@ -2094,26 +1972,31 @@ function Q5(scope, parent) {
2094
1972
  $.getFrameRate = () => $._frameRate;
2095
1973
  $.getFPS = () => $._fps;
2096
1974
 
2097
- $._updateMouse = function (e) {
2098
- let $ = this;
1975
+ $.storeItem = localStorage.setItem;
1976
+ $.getItem = localStorage.getItem;
1977
+ $.removeItem = localStorage.removeItem;
1978
+ $.clearStorage = localStorage.clear;
1979
+
1980
+ // USER INPUT
1981
+
1982
+ $._updateMouse = (e) => {
2099
1983
  let rect = $.canvas.getBoundingClientRect();
2100
1984
  let sx = $.canvas.scrollWidth / $.width || 1;
2101
1985
  let sy = $.canvas.scrollHeight / $.height || 1;
2102
1986
  $.mouseX = (e.clientX - rect.left) / sx;
2103
1987
  $.mouseY = (e.clientY - rect.top) / sy;
2104
- }.bind($);
2105
-
2106
- $._onmousemove = function (e) {
2107
- $._updateMouse(e);
2108
- if (this.mouseIsPressed) this._mouseDraggedFn(e);
2109
- else this._mouseMovedFn(e);
2110
- }.bind($);
1988
+ };
2111
1989
  $._onmousedown = (e) => {
2112
1990
  $._updateMouse(e);
2113
1991
  $.mouseIsPressed = true;
2114
1992
  $.mouseButton = [$.LEFT, $.CENTER, $.RIGHT][e.button];
2115
1993
  $._mousePressedFn(e);
2116
1994
  };
1995
+ $._onmousemove = (e) => {
1996
+ $._updateMouse(e);
1997
+ if ($.mouseIsPressed) $._mouseDraggedFn(e);
1998
+ else $._mouseMovedFn(e);
1999
+ };
2117
2000
  $._onmouseup = (e) => {
2118
2001
  $._updateMouse(e);
2119
2002
  $.mouseIsPressed = false;
@@ -2125,6 +2008,21 @@ function Q5(scope, parent) {
2125
2008
  $._mouseClickedFn(e);
2126
2009
  $.mouseIsPressed = false;
2127
2010
  };
2011
+ $.cursor = (name, x, y) => {
2012
+ let pfx = '';
2013
+ if (name.includes('.')) {
2014
+ name = `url("${name}")`;
2015
+ pfx = ', auto';
2016
+ }
2017
+ if (x !== undefined) {
2018
+ name += ' ' + x + ' ' + y;
2019
+ }
2020
+ $.canvas.style.cursor = name + pfx;
2021
+ };
2022
+ $.noCursor = () => {
2023
+ $.canvas.style.cursor = 'none';
2024
+ };
2025
+
2128
2026
  $._onkeydown = (e) => {
2129
2027
  if (e.repeat) return;
2130
2028
  $.keyIsPressed = true;
@@ -2194,6 +2092,8 @@ function Q5(scope, parent) {
2194
2092
  $.canvas.ontouchmove = (e) => $._ontouchmove(e);
2195
2093
  $.canvas.ontouchcancel = $.canvas.ontouchend = (e) => $._ontouchend(e);
2196
2094
 
2095
+ // SENSORS
2096
+
2197
2097
  $.hasSensorPermission =
2198
2098
  (!window.DeviceOrientationEvent && !window.DeviceMotionEvent) ||
2199
2099
  !(DeviceOrientationEvent.requestPermission || DeviceMotionEvent.requestPermission);
@@ -2217,11 +2117,6 @@ function Q5(scope, parent) {
2217
2117
  }
2218
2118
  };
2219
2119
 
2220
- //================================================================
2221
- // SENSORS
2222
- //================================================================
2223
-
2224
- // 3d transformation helpers
2225
2120
  let ROTX = (a) => [1, 0, 0, 0, 0, $.cos(a), -$.sin(a), 0, 0, $.sin(a), $.cos(a), 0, 0, 0, 0, 1];
2226
2121
  let ROTY = (a) => [$.cos(a), 0, $.sin(a), 0, 0, 1, 0, 0, -$.sin(a), 0, $.cos(a), 0, 0, 0, 0, 1];
2227
2122
  let MULT = (A, B) => [
@@ -2248,7 +2143,7 @@ function Q5(scope, parent) {
2248
2143
  (A[8] * v[0] + A[9] * v[1] + A[10] * v[2] + A[11]) / (A[12] * v[0] + A[13] * v[1] + A[14] * v[2] + A[15])
2249
2144
  ];
2250
2145
 
2251
- if (typeof window !== 'undefined') {
2146
+ if (typeof window != 'undefined') {
2252
2147
  window.ondeviceorientation = (e) => {
2253
2148
  $.pRotationX = $.rotationX;
2254
2149
  $.pRotationY = $.rotationY;
@@ -2260,8 +2155,8 @@ function Q5(scope, parent) {
2260
2155
  $.rotationX = e.beta * (Math.PI / 180.0);
2261
2156
  $.rotationY = e.gamma * (Math.PI / 180.0);
2262
2157
  $.rotationZ = e.alpha * (Math.PI / 180.0);
2263
- $.relRotationX = [-$.rotationY, -$.rotationX, $.rotationY][~~(window.orientation / 90) + 1];
2264
- $.relRotationY = [-$.rotationX, $.rotationY, $.rotationX][~~(window.orientation / 90) + 1];
2158
+ $.relRotationX = [-$.rotationY, -$.rotationX, $.rotationY][Math.trunc(window.orientation / 90) + 1];
2159
+ $.relRotationY = [-$.rotationX, $.rotationY, $.rotationX][Math.trunc(window.orientation / 90) + 1];
2265
2160
  $.relRotationZ = $.rotationZ;
2266
2161
  };
2267
2162
  window.ondevicemotion = (e) => {
@@ -2269,9 +2164,6 @@ function Q5(scope, parent) {
2269
2164
  $.pAccelerationY = $.accelerationY;
2270
2165
  $.pAccelerationZ = $.accelerationZ;
2271
2166
  if (!e.acceleration) {
2272
- // devices that don't support plain acceleration
2273
- // compute gravitational acceleration's component on X Y Z axes based on gyroscope
2274
- // g = ~ 9.80665
2275
2167
  let grav = TRFM(MULT(ROTY($.rotationY), ROTX($.rotationX)), [0, 0, -9.80665]);
2276
2168
  $.accelerationX = e.accelerationIncludingGravity.x + grav[0];
2277
2169
  $.accelerationY = e.accelerationIncludingGravity.y + grav[1];
@@ -2280,9 +2172,7 @@ function Q5(scope, parent) {
2280
2172
  };
2281
2173
  }
2282
2174
 
2283
- //================================================================
2284
2175
  // TIME
2285
- //================================================================
2286
2176
 
2287
2177
  $.year = () => new Date().getFullYear();
2288
2178
  $.day = () => new Date().getDay();
@@ -2291,10 +2181,7 @@ function Q5(scope, parent) {
2291
2181
  $.second = () => new Date().getSeconds();
2292
2182
  $.millis = () => performance.now() - millisStart;
2293
2183
 
2294
- $.storeItem = localStorage.setItem;
2295
- $.getItem = localStorage.getItem;
2296
- $.removeItem = localStorage.removeItem;
2297
- $.clearStorage = localStorage.clear;
2184
+ // LOAD FILES
2298
2185
 
2299
2186
  $._loadFile = (path, cb, type) => {
2300
2187
  preloadCnt++;
@@ -2314,7 +2201,6 @@ function Q5(scope, parent) {
2314
2201
 
2315
2202
  $.loadStrings = (path, cb) => $._loadFile(path, cb, 'text');
2316
2203
  $.loadJSON = (path, cb) => $._loadFile(path, cb, 'json');
2317
-
2318
2204
  $.loadSound = (path, cb) => {
2319
2205
  preloadCnt++;
2320
2206
  let a = new Audio(path);
@@ -2328,17 +2214,10 @@ function Q5(scope, parent) {
2328
2214
  return a;
2329
2215
  };
2330
2216
 
2331
- $.Element = function (a) {
2332
- this.elt = a;
2333
- };
2334
- $._elements = [];
2217
+ // INIT
2335
2218
 
2336
2219
  if (scope == 'global') {
2337
- // delete $.name;
2338
- // delete $.length;
2339
2220
  Object.assign(Q5, $);
2340
- // $.name = '';
2341
- // $.length = 0;
2342
2221
  delete Q5.Q5;
2343
2222
  }
2344
2223
  Q5.Image ??= _Q5Image;
@@ -2403,8 +2282,8 @@ function Q5(scope, parent) {
2403
2282
  millisStart = performance.now();
2404
2283
  function _start() {
2405
2284
  if (preloadCnt > 0) return requestAnimationFrame(_start);
2406
- ctx.save();
2407
2285
  $._setupFn();
2286
+ if (!ctx) $.createCanvas(100, 100);
2408
2287
  $._setupDone = true;
2409
2288
  ctx.restore();
2410
2289
  $.resetMatrix();
@@ -2420,127 +2299,100 @@ function Q5(scope, parent) {
2420
2299
  else requestAnimationFrame(_init);
2421
2300
  }
2422
2301
 
2302
+ // COLOR CLASSES
2303
+
2423
2304
  Q5.Color = class {
2305
+ constructor() {
2306
+ this._q5Color = true;
2307
+ }
2308
+ };
2309
+ Q5.ColorOKLCH = class extends Q5.Color {
2310
+ constructor(l, c, h, a) {
2311
+ super();
2312
+ this.l = l;
2313
+ this.c = c;
2314
+ this.h = h;
2315
+ this.a = a ?? 1;
2316
+ }
2317
+ toString() {
2318
+ return `color(oklch ${this.l} ${this.c} ${this.h} / ${this.a})`;
2319
+ }
2320
+ };
2321
+ Q5.ColorRGBA = class extends Q5.Color {
2424
2322
  constructor(r, g, b, a) {
2425
- this.MAGIC = 0xc010a;
2426
- this._r = r;
2427
- this._g = g;
2428
- this._b = b;
2429
- this._a = a;
2430
- this._h = 0;
2431
- this._s = 0;
2432
- this._v = 0;
2433
- this._hsvInferred = false;
2323
+ super();
2324
+ this.r = r;
2325
+ this.g = g;
2326
+ this.b = b;
2327
+ this.a = a ?? 255;
2434
2328
  }
2435
-
2436
- setRed(x) {
2437
- this._r = x;
2438
- this._hsvInferred = false;
2329
+ setRed(v) {
2330
+ this.r = v;
2439
2331
  }
2440
- setGreen(x) {
2441
- this._g = x;
2442
- this._hsvInferred = false;
2332
+ setGreen(v) {
2333
+ this.g = v;
2443
2334
  }
2444
- setBlue(x) {
2445
- this._b = x;
2446
- this._hsvInferred = false;
2335
+ setBlue(v) {
2336
+ this.b = v;
2447
2337
  }
2448
- setAlpha(x) {
2449
- this._a = x / 255;
2450
- this._hsvInferred = false;
2338
+ setAlpha(v) {
2339
+ this.a = v;
2451
2340
  }
2452
2341
  get levels() {
2453
- return [this._r, this._g, this._b, this._a * 255];
2454
- }
2455
- _inferHSV() {
2456
- if (!this._hsvInferred) {
2457
- [this._h, this._s, this._v] = Q5.Color._rgb2hsv(this._r, this._g, this._b);
2458
- this._hsvInferred = true;
2459
- }
2342
+ return [this.r, this.g, this.b, this.a];
2460
2343
  }
2461
2344
  toString() {
2462
- return `rgba(${Math.round(this._r)},${Math.round(this._g)},${Math.round(this._b)},${~~(this._a * 1000) / 1000})`;
2345
+ return `rgb(${this.r} ${this.g} ${this.b} / ${this.a / 255})`;
2463
2346
  }
2464
2347
  };
2465
- Q5._instanceCount = 0;
2466
- Q5.Color._rgb2hsv = (r, g, b) => {
2467
- //https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both
2468
- let rgbMin, rgbMax;
2469
- let h, s, v;
2470
- rgbMin = r < g ? (r < b ? r : b) : g < b ? g : b;
2471
- rgbMax = r > g ? (r > b ? r : b) : g > b ? g : b;
2472
- v = (rgbMax * 100) / 255;
2473
- if (v == 0) {
2474
- h = 0;
2475
- s = 0;
2476
- return [h, s, v];
2477
- }
2478
- s = (100 * (rgbMax - rgbMin)) / rgbMax;
2479
- if (s == 0) {
2480
- h = 0;
2481
- return [h, s, v];
2482
- }
2483
- if (rgbMax == r) h = 0 + (60 * (g - b)) / (rgbMax - rgbMin);
2484
- else if (rgbMax == g) h = 120 + (60 * (b - r)) / (rgbMax - rgbMin);
2485
- else h = 240 + (60 * (r - g)) / (rgbMax - rgbMin);
2486
- return [h, s, v];
2487
- };
2488
- Q5.Color._hsv2rgb = (h, s, v) => {
2489
- //https://stackoverflow.com/questions/3018313/algorithm-to-convert-rgb-to-hsv-and-hsv-to-rgb-in-range-0-255-for-both
2490
- let r, g, b;
2491
- let hh, i, ff, p, q, t;
2492
- if (s == 0) {
2493
- r = v;
2494
- g = v;
2495
- b = v;
2496
- return [r * 255, g * 255, b * 255];
2497
- }
2498
- hh = h;
2499
- if (hh > 360) hh = 0;
2500
- hh /= 60;
2501
- i = ~~hh;
2502
- ff = hh - i;
2503
- p = v * (1.0 - s);
2504
- q = v * (1.0 - s * ff);
2505
- t = v * (1.0 - s * (1.0 - ff));
2506
- switch (i) {
2507
- case 0:
2508
- r = v;
2509
- g = t;
2510
- b = p;
2511
- break;
2512
- case 1:
2513
- r = q;
2514
- g = v;
2515
- b = p;
2516
- break;
2517
- case 2:
2518
- r = p;
2519
- g = v;
2520
- b = t;
2521
- break;
2522
- case 3:
2523
- r = p;
2524
- g = q;
2525
- b = v;
2526
- break;
2527
- case 4:
2528
- r = t;
2529
- g = p;
2530
- b = v;
2531
- break;
2532
- default:
2533
- r = v;
2534
- g = p;
2535
- b = q;
2536
- break;
2537
- }
2538
- return [r * 255, g * 255, b * 255];
2348
+ Q5.ColorRGBA_P3 = class extends Q5.ColorRGBA {
2349
+ constructor(r, g, b, a) {
2350
+ super(r, g, b, a);
2351
+ this._edited = true;
2352
+ }
2353
+ get r() {
2354
+ return this._r;
2355
+ }
2356
+ set r(v) {
2357
+ this._r = v;
2358
+ this._edited = true;
2359
+ }
2360
+ get g() {
2361
+ return this._g;
2362
+ }
2363
+ set g(v) {
2364
+ this._g = v;
2365
+ this._edited = true;
2366
+ }
2367
+ get b() {
2368
+ return this._b;
2369
+ }
2370
+ set b(v) {
2371
+ this._b = v;
2372
+ this._edited = true;
2373
+ }
2374
+ get a() {
2375
+ return this._a;
2376
+ }
2377
+ set a(v) {
2378
+ this._a = v;
2379
+ this._edited = true;
2380
+ }
2381
+ toString() {
2382
+ if (this._edited) {
2383
+ let r = (this._r / 255).toFixed(3);
2384
+ let g = (this._g / 255).toFixed(3);
2385
+ let b = (this._b / 255).toFixed(3);
2386
+ let a = (this._a / 255).toFixed(3);
2387
+ this._css = `color(display-p3 ${r} ${g} ${b} / ${a})`;
2388
+ this._edited = false;
2389
+ }
2390
+ return this._css;
2391
+ }
2539
2392
  };
2540
2393
 
2541
- //================================================================
2542
2394
  // VECTOR
2543
- //================================================================
2395
+
2544
2396
  Q5.Vector = class {
2545
2397
  constructor(_x, _y, _z, _$) {
2546
2398
  this.x = _x || 0;
@@ -2550,7 +2402,6 @@ Q5.Vector = class {
2550
2402
  this._cn = null;
2551
2403
  this._cnsq = null;
2552
2404
  }
2553
-
2554
2405
  set(_x, _y, _z) {
2555
2406
  this.x = _x || 0;
2556
2407
  this.y = _y || 0;
@@ -2764,6 +2615,8 @@ for (let k of ['fromAngle', 'fromAngles', 'random2D', 'random3D']) {
2764
2615
  Q5.Vector[k] = (u, v, t) => new Q5.Vector()[k](u, v, t);
2765
2616
  }
2766
2617
 
2618
+ // IMAGE CLASS
2619
+
2767
2620
  class _Q5Image extends Q5 {
2768
2621
  constructor(width, height) {
2769
2622
  super('image');
@@ -2779,9 +2632,24 @@ class _Q5Image extends Q5 {
2779
2632
  }
2780
2633
  }
2781
2634
 
2635
+ // Q5
2636
+
2637
+ Q5.canvasOptions = {
2638
+ alpha: false,
2639
+ desynchronized: true,
2640
+ colorSpace: 'display-p3'
2641
+ };
2642
+
2643
+ if (typeof matchMedia == 'undefined' || !matchMedia('(dynamic-range: high) and (color-gamut: p3)').matches) {
2644
+ Q5.canvasOptions.colorSpace = 'srgb';
2645
+ }
2646
+
2647
+ Q5._instanceCount = 0;
2782
2648
  Q5._friendlyError = (msg, func) => {
2783
2649
  throw func + ': ' + msg;
2784
2650
  };
2651
+ Q5._validateParameters = () => true;
2652
+
2785
2653
  Q5.prototype._methods = {
2786
2654
  init: [],
2787
2655
  pre: [],
@@ -2790,7 +2658,6 @@ Q5.prototype._methods = {
2790
2658
  };
2791
2659
  Q5.prototype.registerMethod = (m, fn) => Q5.prototype._methods[m].push(fn);
2792
2660
  Q5.prototype.registerPreloadMethod = (n, fn) => (Q5.prototype[n] = fn[n]);
2793
- Q5._validateParameters = () => true;
2794
2661
 
2795
2662
  if (typeof module != 'undefined') module.exports = Q5;
2796
2663
  else window.p5 ??= Q5;