p5 2.2.3 → 2.3.0-rc.1

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 (137) hide show
  1. package/dist/accessibility/color_namer.js +9 -11
  2. package/dist/accessibility/describe.js +0 -1
  3. package/dist/accessibility/gridOutput.js +0 -1
  4. package/dist/accessibility/index.js +9 -10
  5. package/dist/accessibility/outputs.js +0 -1
  6. package/dist/accessibility/textOutput.js +0 -1
  7. package/dist/app.js +11 -10
  8. package/dist/app.node.js +122 -0
  9. package/dist/color/color_conversion.js +9 -11
  10. package/dist/color/creating_reading.js +1 -1
  11. package/dist/color/index.js +2 -2
  12. package/dist/color/p5.Color.js +1 -1
  13. package/dist/color/setting.js +25 -12
  14. package/dist/{constants-BdTiYOQI.js → constants-0wkVUfqa.js} +2 -2
  15. package/dist/core/States.js +1 -1
  16. package/dist/core/constants.js +1 -1
  17. package/dist/core/environment.js +28 -29
  18. package/dist/core/filterShaders.js +1 -1
  19. package/dist/core/friendly_errors/fes_core.js +9 -8
  20. package/dist/core/friendly_errors/file_errors.js +1 -2
  21. package/dist/core/friendly_errors/index.js +1 -1
  22. package/dist/core/friendly_errors/param_validator.js +737 -640
  23. package/dist/core/friendly_errors/sketch_verifier.js +1 -1
  24. package/dist/core/friendly_errors/stacktrace.js +0 -1
  25. package/dist/core/helpers.js +3 -4
  26. package/dist/core/init.js +24 -21
  27. package/dist/core/internationalization.js +1 -1
  28. package/dist/core/legacy.js +9 -11
  29. package/dist/core/main.js +9 -10
  30. package/dist/core/p5.Graphics.js +5 -5
  31. package/dist/core/p5.Renderer.js +3 -3
  32. package/dist/core/p5.Renderer2D.js +9 -10
  33. package/dist/core/p5.Renderer3D.js +5 -5
  34. package/dist/core/rendering.js +5 -5
  35. package/dist/core/structure.js +0 -1
  36. package/dist/core/transform.js +7 -16
  37. package/dist/{creating_reading-C7hu6sg1.js → creating_reading-DLkHH80h.js} +11 -8
  38. package/dist/data/local_storage.js +0 -1
  39. package/dist/dom/dom.js +2 -3
  40. package/dist/dom/index.js +2 -2
  41. package/dist/dom/p5.Element.js +2 -2
  42. package/dist/dom/p5.MediaElement.js +2 -2
  43. package/dist/events/acceleration.js +5 -3
  44. package/dist/events/keyboard.js +0 -1
  45. package/dist/events/pointer.js +0 -2
  46. package/dist/image/const.js +1 -1
  47. package/dist/image/filterRenderer2D.js +19 -12
  48. package/dist/image/image.js +5 -5
  49. package/dist/image/index.js +5 -5
  50. package/dist/image/loading_displaying.js +5 -5
  51. package/dist/image/p5.Image.js +3 -3
  52. package/dist/image/pixels.js +0 -1
  53. package/dist/io/files.js +5 -5
  54. package/dist/io/index.js +5 -5
  55. package/dist/io/p5.Table.js +0 -1
  56. package/dist/io/p5.TableRow.js +0 -1
  57. package/dist/io/p5.XML.js +0 -1
  58. package/dist/{ir_builders-Cd6rU9Vm.js → ir_builders-C2ebb6Lu.js} +234 -1
  59. package/dist/{main-H_nu4eDs.js → main-D2kqeMXM.js} +107 -136
  60. package/dist/math/Matrices/Matrix.js +1 -1
  61. package/dist/math/Matrices/MatrixNumjs.js +1 -1
  62. package/dist/math/calculation.js +0 -1
  63. package/dist/math/index.js +3 -1
  64. package/dist/math/math.js +3 -17
  65. package/dist/math/noise.js +0 -1
  66. package/dist/math/p5.Matrix.js +1 -2
  67. package/dist/math/p5.Vector.js +237 -279
  68. package/dist/math/patch-vector.js +75 -0
  69. package/dist/math/random.js +0 -1
  70. package/dist/math/trigonometry.js +3 -4
  71. package/dist/{p5.Renderer-BmD2P6Wv.js → p5.Renderer-CQI8PO1F.js} +31 -24
  72. package/dist/{rendering-CC8JNTwG.js → rendering-ltTIxpF2.js} +732 -44
  73. package/dist/shape/2d_primitives.js +1 -4
  74. package/dist/shape/attributes.js +43 -8
  75. package/dist/shape/curves.js +0 -1
  76. package/dist/shape/custom_shapes.js +260 -5
  77. package/dist/shape/index.js +2 -2
  78. package/dist/shape/vertex.js +0 -2
  79. package/dist/strands/ir_builders.js +1 -1
  80. package/dist/strands/ir_types.js +5 -1
  81. package/dist/strands/p5.strands.js +286 -31
  82. package/dist/strands/strands_api.js +179 -8
  83. package/dist/strands/strands_codegen.js +26 -8
  84. package/dist/strands/strands_conditionals.js +1 -1
  85. package/dist/strands/strands_for.js +1 -1
  86. package/dist/strands/strands_node.js +1 -1
  87. package/dist/strands/strands_ternary.js +56 -0
  88. package/dist/strands/strands_transpiler.js +416 -251
  89. package/dist/strands_glslBackend-i-ReKgZo.js +423 -0
  90. package/dist/type/index.js +3 -3
  91. package/dist/type/lib/Typr.js +1 -1
  92. package/dist/type/p5.Font.js +3 -3
  93. package/dist/type/textCore.js +31 -24
  94. package/dist/utilities/conversion.js +0 -1
  95. package/dist/utilities/time_date.js +0 -1
  96. package/dist/utilities/utility_functions.js +0 -1
  97. package/dist/webgl/3d_primitives.js +5 -5
  98. package/dist/webgl/GeometryBuilder.js +1 -1
  99. package/dist/webgl/ShapeBuilder.js +26 -1
  100. package/dist/webgl/enums.js +1 -1
  101. package/dist/webgl/index.js +8 -9
  102. package/dist/webgl/interaction.js +8 -4
  103. package/dist/webgl/light.js +5 -5
  104. package/dist/webgl/loading.js +60 -21
  105. package/dist/webgl/material.js +5 -5
  106. package/dist/webgl/p5.Camera.js +5 -5
  107. package/dist/webgl/p5.Framebuffer.js +5 -5
  108. package/dist/webgl/p5.Geometry.js +3 -5
  109. package/dist/webgl/p5.Quat.js +1 -1
  110. package/dist/webgl/p5.RendererGL.js +17 -21
  111. package/dist/webgl/p5.Shader.js +129 -36
  112. package/dist/webgl/p5.Texture.js +5 -5
  113. package/dist/webgl/strands_glslBackend.js +5 -386
  114. package/dist/webgl/text.js +5 -5
  115. package/dist/webgl/utils.js +5 -5
  116. package/dist/webgl2Compatibility-DA7DLMuq.js +7 -0
  117. package/dist/webgpu/index.js +7 -3
  118. package/dist/webgpu/p5.RendererWebGPU.js +1146 -180
  119. package/dist/webgpu/shaders/color.js +1 -1
  120. package/dist/webgpu/shaders/compute.js +32 -0
  121. package/dist/webgpu/shaders/functions/randomComputeWGSL.js +31 -0
  122. package/dist/webgpu/shaders/functions/randomVertWGSL.js +30 -0
  123. package/dist/webgpu/shaders/functions/randomWGSL.js +30 -0
  124. package/dist/webgpu/shaders/line.js +1 -1
  125. package/dist/webgpu/shaders/material.js +3 -3
  126. package/dist/webgpu/strands_wgslBackend.js +137 -15
  127. package/lib/p5.esm.js +4092 -1950
  128. package/lib/p5.esm.min.js +1 -1
  129. package/lib/p5.js +4092 -1950
  130. package/lib/p5.min.js +1 -1
  131. package/lib/p5.webgpu.esm.js +1748 -306
  132. package/lib/p5.webgpu.js +1747 -305
  133. package/lib/p5.webgpu.min.js +1 -1
  134. package/package.json +6 -1
  135. package/types/global.d.ts +4182 -2441
  136. package/types/p5.d.ts +2776 -1675
  137. package/dist/noise3DGLSL-Bwrdi4gi.js +0 -9
@@ -1,7 +1,8 @@
1
- import { p as CORNER, t as CORNERS, v as CENTER, aB as COVER, aC as CONTAIN, a9 as RIGHT, aw as BOTTOM, B as BLEND, aD as FILL, ad as IMAGE, C as CLAMP, w as ROUND, Y as LINES, X as POINTS, c as TRIANGLES, ab as BLUR, D as DARKEST, L as LIGHTEST, A as ADD, S as SUBTRACT, a as SCREEN, E as EXCLUSION, R as REPLACE, M as MULTIPLY, b as REMOVE, as as BURN, ao as OVERLAY, ap as HARD_LIGHT, aq as SOFT_LIGHT, ar as DODGE, d as UNSIGNED_INT, U as UNSIGNED_BYTE, av as LEFT, ax as BASELINE, ay as TOP, aE as SIMPLE, aF as FULL, q as TWO_PI, Q as OPEN, a2 as NORMAL, V as CLOSE, at as PIE, au as CHORD, h as TEXTURE, P as P2D, g as LINEAR, aa as WEBGL2, N as NEAREST, aG as LINEAR_MIPMAP, f as REPEAT, e as MIRROR, F as FLOAT, ac as WEBGL, H as HALF_FLOAT } from './constants-BdTiYOQI.js';
2
- import { C as Color, c as creatingReading, h as RGBA, R as RGB } from './creating_reading-C7hu6sg1.js';
1
+ import { n as CORNER, r as CORNERS, t as CENTER, aB as COVER, aC as CONTAIN, aa as RIGHT, aw as BOTTOM, B as BLEND, aD as FILL, ae as IMAGE, C as CLAMP, u as ROUND, Q as LINES, K as POINTS, c as TRIANGLES, ac as BLUR, D as DARKEST, L as LIGHTEST, A as ADD, S as SUBTRACT, a as SCREEN, E as EXCLUSION, R as REPLACE, M as MULTIPLY, b as REMOVE, au as BURN, aq as OVERLAY, ar as HARD_LIGHT, as as SOFT_LIGHT, at as DODGE, d as UNSIGNED_INT, U as UNSIGNED_BYTE, av as LEFT, ax as BASELINE, ay as TOP, aE as SIMPLE, aF as FULL, o as TWO_PI, O as OPEN, a1 as NORMAL, J as CLOSE, a0 as PIE, $ as CHORD, a7 as TEXTURE, P as P2D, g as LINEAR, ab as WEBGL2, N as NEAREST, aG as LINEAR_MIPMAP, f as REPEAT, e as MIRROR, F as FLOAT, ad as WEBGL, H as HALF_FLOAT, W as WEBGPU } from './constants-0wkVUfqa.js';
2
+ import { C as Color, c as creatingReading, h as RGBA, R as RGB } from './creating_reading-DLkHH80h.js';
3
+ import './strands/ir_types.js';
3
4
  import { Element } from './dom/p5.Element.js';
4
- import { R as Renderer, I as Image } from './p5.Renderer-BmD2P6Wv.js';
5
+ import { R as Renderer, I as Image } from './p5.Renderer-CQI8PO1F.js';
5
6
  import { MediaElement } from './dom/p5.MediaElement.js';
6
7
  import primitives from './shape/2d_primitives.js';
7
8
  import attributes from './shape/attributes.js';
@@ -12,7 +13,6 @@ import * as omggif from 'omggif';
12
13
  import canvas from './core/helpers.js';
13
14
  import { parse } from './io/csv.js';
14
15
  import { _checkFileExtension, downloadFile } from './io/utilities.js';
15
- import { GIFEncoder, quantize, nearestColorIndex } from 'gifenc';
16
16
  import pixels from './image/pixels.js';
17
17
  import transform from './core/transform.js';
18
18
  import GeometryBuilder from './webgl/GeometryBuilder.js';
@@ -37,7 +37,6 @@ import trigonometry from './math/trigonometry.js';
37
37
  * @module Image
38
38
  * @submodule Image
39
39
  * @for p5
40
- * @requires core
41
40
  */
42
41
 
43
42
 
@@ -736,7 +735,6 @@ if(typeof p5 !== 'undefined'){
736
735
  * @module IO
737
736
  * @submodule Input
738
737
  * @for p5
739
- * @requires core
740
738
  */
741
739
 
742
740
 
@@ -2851,11 +2849,12 @@ if(typeof p5 !== 'undefined'){
2851
2849
  files(p5, p5.prototype);
2852
2850
  }
2853
2851
 
2852
+ var X={trailer:59};function F(t=256){let e=0,s=new Uint8Array(t);return {get buffer(){return s.buffer},reset(){e=0;},bytesView(){return s.subarray(0,e)},bytes(){return s.slice(0,e)},writeByte(r){n(e+1),s[e]=r,e++;},writeBytes(r,o=0,i=r.length){n(e+i);for(let c=0;c<i;c++)s[e++]=r[c+o];},writeBytesView(r,o=0,i=r.byteLength){n(e+i),s.set(r.subarray(o,o+i),e),e+=i;}};function n(r){var o=s.length;if(o>=r)return;var i=1024*1024;r=Math.max(r,o*(o<i?2:1.125)>>>0),o!=0&&(r=Math.max(r,256));let c=s;s=new Uint8Array(r),e>0&&s.set(c.subarray(0,e),0);}}var O=12,J=5003,lt=[0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535];function at(t,e,s,n,r=F(512),o=new Uint8Array(256),i=new Int32Array(J),c=new Int32Array(J)){let x=i.length,a=Math.max(2,n);o.fill(0),c.fill(0),i.fill(-1);let l=0,f=0,g=a+1,h=g,b=false,w=h,_=(1<<w)-1,u=1<<g-1,k=u+1,B=u+2,p=0,A=s[0],z=0;for(let y=x;y<65536;y*=2)++z;z=8-z,r.writeByte(a),I(u);let d=s.length;for(let y=1;y<d;y++){t:{let m=s[y],v=(m<<O)+A,M=m<<z^A;if(i[M]===v){A=c[M];break t}let V=M===0?1:x-M;for(;i[M]>=0;)if(M-=V,M<0&&(M+=x),i[M]===v){A=c[M];break t}I(A),A=m,B<1<<O?(c[M]=B++,i[M]=v):(i.fill(-1),B=u+2,b=true,I(u));}}return I(A),I(k),r.writeByte(0),r.bytesView();function I(y){for(l&=lt[f],f>0?l|=y<<f:l=y,f+=w;f>=8;)o[p++]=l&255,p>=254&&(r.writeByte(p),r.writeBytesView(o,0,p),p=0),l>>=8,f-=8;if((B>_||b)&&(b?(w=h,_=(1<<w)-1,b=false):(++w,_=w===O?1<<w:(1<<w)-1)),y==k){for(;f>0;)o[p++]=l&255,p>=254&&(r.writeByte(p),r.writeBytesView(o,0,p),p=0),l>>=8,f-=8;p>0&&(r.writeByte(p),r.writeBytesView(o,0,p),p=0);}}}var $=at;function D(t,e,s){return t<<8&63488|e<<2&992|s>>3}function G(t,e,s,n){return t>>4|e&240|(s&240)<<4|(n&240)<<8}function j(t,e,s){return t>>4<<8|e&240|s>>4}function R(t,e,s){return t<e?e:t>s?s:t}function T(t){return t*t}function tt(t,e,s){var n=0,r=1e100;let o=t[e],i=o.cnt;o.ac;let x=o.rc,a=o.gc,l=o.bc;for(var f=o.fw;f!=0;f=t[f].fw){let h=t[f],b=h.cnt,w=i*b/(i+b);if(!(w>=r)){var g=0;(g+=w*T(h.rc-x),!(g>=r)&&(g+=w*T(h.gc-a),!(g>=r)&&(g+=w*T(h.bc-l),!(g>=r)&&(r=g,n=f))));}}o.err=r,o.nn=n;}function Q(){return {ac:0,rc:0,gc:0,bc:0,cnt:0,nn:0,fw:0,bk:0,tm:0,mtm:0,err:0}}function ut(t,e){let s=e==="rgb444"?4096:65536,n=new Array(s),r=t.length;if(e==="rgba4444")for(let o=0;o<r;++o){let i=t[o],c=i>>24&255,x=i>>16&255,a=i>>8&255,l=i&255,f=G(l,a,x,c),g=f in n?n[f]:n[f]=Q();g.rc+=l,g.gc+=a,g.bc+=x,g.ac+=c,g.cnt++;}else if(e==="rgb444")for(let o=0;o<r;++o){let i=t[o],c=i>>16&255,x=i>>8&255,a=i&255,l=j(a,x,c),f=l in n?n[l]:n[l]=Q();f.rc+=a,f.gc+=x,f.bc+=c,f.cnt++;}else for(let o=0;o<r;++o){let i=t[o],c=i>>16&255,x=i>>8&255,a=i&255,l=D(a,x,c),f=l in n?n[l]:n[l]=Q();f.rc+=a,f.gc+=x,f.bc+=c,f.cnt++;}return n}function H(t,e,s={}){let{format:n="rgb565",clearAlpha:r=true,clearAlphaColor:o=0,clearAlphaThreshold:i=0,oneBitAlpha:c=false}=s;if(!t||!t.buffer)throw new Error("quantize() expected RGBA Uint8Array data");if(!(t instanceof Uint8Array)&&!(t instanceof Uint8ClampedArray))throw new Error("quantize() expected RGBA Uint8Array data");let x=new Uint32Array(t.buffer),a=s.useSqrt!==false,l=n==="rgba4444",f=ut(x,n),g=f.length,h=g-1,b=new Uint32Array(g+1);for(var w=0,u=0;u<g;++u){let C=f[u];if(C!=null){var _=1/C.cnt;l&&(C.ac*=_),C.rc*=_,C.gc*=_,C.bc*=_,f[w++]=C;}}T(e)/w<.022&&(a=false);for(var u=0;u<w-1;++u)f[u].fw=u+1,f[u+1].bk=u,a&&(f[u].cnt=Math.sqrt(f[u].cnt));a&&(f[u].cnt=Math.sqrt(f[u].cnt));var k,B,p;for(u=0;u<w;++u){tt(f,u);var A=f[u].err;for(B=++b[0];B>1&&(p=B>>1,!(f[k=b[p]].err<=A));B=p)b[B]=k;b[B]=u;}var z=w-e;for(u=0;u<z;){for(var d;;){var I=b[1];if(d=f[I],d.tm>=d.mtm&&f[d.nn].mtm<=d.tm)break;d.mtm==h?I=b[1]=b[b[0]--]:(tt(f,I),d.tm=u);var A=f[I].err;for(B=1;(p=B+B)<=b[0]&&(p<b[0]&&f[b[p]].err>f[b[p+1]].err&&p++,!(A<=f[k=b[p]].err));B=p)b[B]=k;b[B]=I;}var y=f[d.nn],m=d.cnt,v=y.cnt,_=1/(m+v);l&&(d.ac=_*(m*d.ac+v*y.ac)),d.rc=_*(m*d.rc+v*y.rc),d.gc=_*(m*d.gc+v*y.gc),d.bc=_*(m*d.bc+v*y.bc),d.cnt+=y.cnt,d.mtm=++u,f[y.bk].fw=y.fw,f[y.fw].bk=y.bk,y.mtm=h;}let M=[];var V=0;for(u=0;;++V){let L=R(Math.round(f[u].rc),0,255),C=R(Math.round(f[u].gc),0,255),Y=R(Math.round(f[u].bc),0,255),E=255;if(l){if(E=R(Math.round(f[u].ac),0,255),c){let st=typeof c=="number"?c:127;E=E<=st?0:255;}r&&E<=i&&(L=C=Y=o,E=0);}let K=l?[L,C,Y,E]:[L,C,Y];if(xt(M,K)||M.push(K),(u=f[u].fw)==0)break}return M}function xt(t,e){for(let s=0;s<t.length;s++){let n=t[s],r=n[0]===e[0]&&n[1]===e[1]&&n[2]===e[2],o=n.length>=4&&e.length>=4?n[3]===e[3]:true;if(r&&o)return true}return false}function U(t,e){var s=0,n;for(n=0;n<t.length;n++){let r=t[n]-e[n];s+=r*r;}return s}function W(t,e,s=U){let n=Infinity,r=-1;for(let o=0;o<t.length;o++){let i=t[o],c=s(e,i);c<n&&(n=c,r=o);}return r}function ct(t={}){let{initialCapacity:e=4096,auto:s=true}=t,n=F(e),r=5003,o=new Uint8Array(256),i=new Int32Array(r),c=new Int32Array(r),x=false;return {reset(){n.reset(),x=false;},finish(){n.writeByte(X.trailer);},bytes(){return n.bytes()},bytesView(){return n.bytesView()},get buffer(){return n.buffer},get stream(){return n},writeHeader:a,writeFrame(l,f,g,h={}){let{transparent:b=false,transparentIndex:w=0,delay:_=0,palette:u=null,repeat:k=0,colorDepth:B=8,dispose:p=-1}=h,A=false;if(s?x||(A=true,a(),x=true):A=Boolean(h.first),f=Math.max(0,Math.floor(f)),g=Math.max(0,Math.floor(g)),A){if(!u)throw new Error("First frame must include a { palette } option");pt(n,f,g,u,B),it(n,u),k>=0&&dt(n,k);}let z=Math.round(_/10);wt(n,p,z,b,w);let d=Boolean(u)&&!A;ht(n,f,g,d?u:null),d&&it(n,u),yt(n,l,f,g,B,o,i,c);}};function a(){ft(n,"GIF89a");}}function wt(t,e,s,n,r){t.writeByte(33),t.writeByte(249),t.writeByte(4),r<0&&(r=0,n=false);var o,i;n?(o=1,i=2):(o=0,i=0),e>=0&&(i=e&7),i<<=2;let c=0;t.writeByte(0|i|c|o),S(t,s),t.writeByte(r||0),t.writeByte(0);}function pt(t,e,s,n,r=8){let o=1,i=0,c=Z(n.length)-1,x=o<<7|r-1<<4|i<<3|c,a=0,l=0;S(t,e),S(t,s),t.writeBytes([x,a,l]);}function dt(t,e){t.writeByte(33),t.writeByte(255),t.writeByte(11),ft(t,"NETSCAPE2.0"),t.writeByte(3),t.writeByte(1),S(t,e),t.writeByte(0);}function it(t,e){let s=1<<Z(e.length);for(let n=0;n<s;n++){let r=[0,0,0];n<e.length&&(r=e[n]),t.writeByte(r[0]),t.writeByte(r[1]),t.writeByte(r[2]);}}function ht(t,e,s,n){if(t.writeByte(44),S(t,0),S(t,0),S(t,e),S(t,s),n){let r=0,o=0,i=Z(n.length)-1;t.writeByte(128|r|o|0|i);}else t.writeByte(0);}function yt(t,e,s,n,r=8,o,i,c){$(s,n,e,r,t,o,i,c);}function S(t,e){t.writeByte(e&255),t.writeByte(e>>8&255);}function ft(t,e){for(var s=0;s<e.length;s++)t.writeByte(e.charCodeAt(s));}function Z(t){return Math.max(Math.ceil(Math.log2(t)),1)}
2853
+
2854
2854
  /**
2855
2855
  * @module Image
2856
2856
  * @submodule Loading & Displaying
2857
2857
  * @for p5
2858
- * @requires core
2859
2858
  */
2860
2859
 
2861
2860
 
@@ -3266,7 +3265,7 @@ function loadingDisplaying(p5, fn){
3266
3265
  this.pixelDensity(lastPixelDensity);
3267
3266
 
3268
3267
  // create the gif encoder and the colorspace format
3269
- const gif = GIFEncoder();
3268
+ const gif = ct();
3270
3269
 
3271
3270
  // calculate the global palette for this set of frames
3272
3271
  const globalPalette = _generateGlobalPalette(frames);
@@ -3287,7 +3286,7 @@ function loadingDisplaying(p5, fn){
3287
3286
  (frame[i * 4 + 2] << 8) |
3288
3287
  frame[i * 4 + 3];
3289
3288
  if (paletteCache[key] === undefined) {
3290
- paletteCache[key] = nearestColorIndex(
3289
+ paletteCache[key] = W(
3291
3290
  globalPalette,
3292
3291
  frame.slice(i * 4, (i + 1) * 4)
3293
3292
  );
@@ -3414,7 +3413,7 @@ function loadingDisplaying(p5, fn){
3414
3413
  }
3415
3414
 
3416
3415
  // quantize this massive array into 256 colors and return it!
3417
- let colorPalette = quantize(allColors, 256, {
3416
+ let colorPalette = H(allColors, 256, {
3418
3417
  format: 'rgba4444',
3419
3418
  oneBitAlpha: true
3420
3419
  });
@@ -3986,6 +3985,9 @@ function loadingDisplaying(p5, fn){
3986
3985
  * sets the alpha value. For example, `tint(255, 0, 0, 100)` will give images
3987
3986
  * a red tint and make them transparent.
3988
3987
  *
3988
+ * Calling `tint()` without an argument returns the current tint as a
3989
+ * <a href="#/p5.Color">p5.Color</a> object.
3990
+ *
3989
3991
  * @method tint
3990
3992
  * @param {Number} v1 red or hue value.
3991
3993
  * @param {Number} v2 green or saturation value.
@@ -4090,10 +4092,18 @@ function loadingDisplaying(p5, fn){
4090
4092
  * @method tint
4091
4093
  * @param {p5.Color} color the tint color
4092
4094
  */
4095
+ /**
4096
+ * @method tint
4097
+ * @return {p5.Color} the current tint color
4098
+ */
4093
4099
  fn.tint = function(...args) {
4094
- // p5._validateParameters('tint', args);
4095
- const c = this.color(...args);
4096
- this._renderer.states.setValue('tint', c._getRGBA([255, 255, 255, 255]));
4100
+ if (args.length === 0) {
4101
+ return this._renderer.states.tint; // getter
4102
+ }
4103
+ else {
4104
+ this._renderer.states.setValue('tint', this.color(...args));
4105
+ return this;
4106
+ }
4097
4107
  };
4098
4108
 
4099
4109
  /**
@@ -4127,6 +4137,7 @@ function loadingDisplaying(p5, fn){
4127
4137
  */
4128
4138
  fn.noTint = function() {
4129
4139
  this._renderer.states.setValue('tint', null);
4140
+ return this;
4130
4141
  };
4131
4142
 
4132
4143
  /**
@@ -4158,6 +4169,8 @@ function loadingDisplaying(p5, fn){
4158
4169
  * <a href="#/p5/image">image()</a> as the x- and y-coordinates of the image's
4159
4170
  * center. The next parameters are its width and height.
4160
4171
  *
4172
+ * Calling `imageMode()` without an argument returns the current image mode, either `CORNER`, `CORNERS`, or `CENTER`.
4173
+ *
4161
4174
  * @method imageMode
4162
4175
  * @param {(CORNER|CORNERS|CENTER)} mode either CORNER, CORNERS, or CENTER.
4163
4176
  *
@@ -4221,8 +4234,15 @@ function loadingDisplaying(p5, fn){
4221
4234
  * describe('A square image of a brick wall is drawn on a gray square.');
4222
4235
  * }
4223
4236
  */
4237
+ /**
4238
+ * @method imageMode
4239
+ * @return {(CORNER|CORNERS|CENTER)} the current image mode
4240
+ */
4224
4241
  fn.imageMode = function(m) {
4225
4242
  // p5._validateParameters('imageMode', arguments);
4243
+ if (typeof m === 'undefined') { // getter
4244
+ return this._renderer.states.imageMode;
4245
+ }
4226
4246
  if (
4227
4247
  m === CORNER ||
4228
4248
  m === CORNERS ||
@@ -4240,7 +4260,6 @@ if(typeof p5 !== 'undefined'){
4240
4260
  /**
4241
4261
  * @module 3D
4242
4262
  * @submodule Camera
4243
- * @requires core
4244
4263
  */
4245
4264
 
4246
4265
 
@@ -5836,10 +5855,10 @@ class Camera {
5836
5855
  const up1 = rotMat1.row(1);
5837
5856
 
5838
5857
  // prepare new vectors.
5839
- const newFront = new Vector();
5840
- const newUp = new Vector();
5841
- const newEye = new Vector();
5842
- const newCenter = new Vector();
5858
+ const newFront = new Vector(0, 0, 0);
5859
+ const newUp = new Vector(0, 0, 0);
5860
+ const newEye = new Vector(0, 0, 0);
5861
+ const newCenter = new Vector(0, 0, 0);
5843
5862
 
5844
5863
  // Create the inverse matrix of mat0 by transposing mat0,
5845
5864
  // and multiply it to mat1 from the right.
@@ -8093,6 +8112,12 @@ if(typeof p5 !== 'undefined'){
8093
8112
  camera(p5, p5.prototype);
8094
8113
  }
8095
8114
 
8115
+ /**
8116
+ * @module 3D
8117
+ * @for p5
8118
+ */
8119
+
8120
+
8096
8121
  const { STROKE_CAP_ENUM, STROKE_JOIN_ENUM } = getStrokeDefs(()=>"");
8097
8122
 
8098
8123
  class Renderer3D extends Renderer {
@@ -8205,7 +8230,7 @@ class Renderer3D extends Renderer {
8205
8230
  this.states._useShininess = 1;
8206
8231
  this.states._useMetalness = 0;
8207
8232
 
8208
- this.states.tint = [255, 255, 255, 255];
8233
+ this.states.tint = new Color([1, 1, 1, 1]);
8209
8234
 
8210
8235
  this.states.constantAttenuation = 1;
8211
8236
  this.states.linearAttenuation = 0;
@@ -8228,6 +8253,7 @@ class Renderer3D extends Renderer {
8228
8253
 
8229
8254
  // clipping
8230
8255
  this._clipDepths = [];
8256
+ this._textContextSavedStack = [];
8231
8257
  this._isClipApplied = false;
8232
8258
  this._stencilTestOn = false;
8233
8259
 
@@ -8289,6 +8315,8 @@ class Renderer3D extends Renderer {
8289
8315
  // Used by beginShape/endShape functions to construct a p5.Geometry
8290
8316
  this.shapeBuilder = new ShapeBuilder(this);
8291
8317
 
8318
+ this._largeTessellationAcknowledged = false;
8319
+
8292
8320
  this.geometryBufferCache = new GeometryBufferCache(this);
8293
8321
 
8294
8322
  this.curStrokeCap = ROUND;
@@ -8545,10 +8573,6 @@ class Renderer3D extends Renderer {
8545
8573
  * combining them with `buildGeometry()` once and then drawing that will run
8546
8574
  * faster than repeatedly drawing the individual pieces.
8547
8575
  *
8548
- * One can also draw shapes directly between
8549
- * <a href="#/p5/beginGeometry">beginGeometry()</a> and
8550
- * <a href="#/p5/endGeometry">endGeometry()</a> instead of using a callback
8551
- * function.
8552
8576
  * @param {Function} callback A function that draws shapes.
8553
8577
  * @returns {p5.Geometry} The model that was built from the callback function.
8554
8578
  */
@@ -8794,7 +8818,7 @@ class Renderer3D extends Renderer {
8794
8818
  this.states.setValue("enableLighting", false);
8795
8819
 
8796
8820
  //reset tint value for new frame
8797
- this.states.setValue("tint", [255, 255, 255, 255]);
8821
+ this.states.setValue("tint", new Color([1,1,1,1]));
8798
8822
 
8799
8823
  //Clear depth every frame
8800
8824
  this._resetBuffersBeforeDraw();
@@ -9395,6 +9419,15 @@ class Renderer3D extends Renderer {
9395
9419
  return this;
9396
9420
  }
9397
9421
 
9422
+ push() {
9423
+ super.push();
9424
+ const saved = !!(this.states.textFont?.font);
9425
+ if (saved) {
9426
+ this.textDrawingContext().save();
9427
+ }
9428
+ this._textContextSavedStack.push(saved);
9429
+ }
9430
+
9398
9431
  pop(...args) {
9399
9432
  if (
9400
9433
  this._clipDepths.length > 0 &&
@@ -9402,6 +9435,9 @@ class Renderer3D extends Renderer {
9402
9435
  ) {
9403
9436
  this._clearClip();
9404
9437
  }
9438
+ if (this._textContextSavedStack.pop()) {
9439
+ this.textDrawingContext().restore();
9440
+ }
9405
9441
  super.pop(...args);
9406
9442
  this._applyStencilTestIfClipping();
9407
9443
  }
@@ -9559,7 +9595,7 @@ class Renderer3D extends Renderer {
9559
9595
  // works differently and is global p5 state. If the p5 state has
9560
9596
  // been cleared, we also need to clear the value in uSampler to match.
9561
9597
  fillShader.setUniform("uSampler", this.states._tex || empty);
9562
- fillShader.setUniform("uTint", this.states.tint);
9598
+ fillShader.setUniform("uTint", this.states.tint._getRGBA([255, 255, 255, 255]));
9563
9599
 
9564
9600
  fillShader.setUniform("uHasSetAmbient", this.states._hasSetAmbient);
9565
9601
  fillShader.setUniform("uAmbientMatColor", this.states.curAmbientColor);
@@ -10058,8 +10094,598 @@ class Renderer3D extends Renderer {
10058
10094
  }
10059
10095
  }
10060
10096
 
10097
+ const webGPUAddonMessage = 'Add the WebGPU add-on to your project and pass WEBGPU as the last argument to createCanvas.';
10098
+
10061
10099
  function renderer3D(p5, fn) {
10062
10100
  p5.Renderer3D = Renderer3D;
10101
+
10102
+ ShapeBuilder.prototype.friendlyErrorsDisabled = function() {
10103
+ return Boolean(p5.disableFriendlyErrors);
10104
+ };
10105
+
10106
+ /**
10107
+ * Creates a <a href="#/p5/p5.StorageBuffer">`p5.StorageBuffer`</a>, which is
10108
+ * a block of data that shaders can read from, and compute shaders
10109
+ * can also write to. This is only available in WebGPU mode.
10110
+ *
10111
+ * To read or write the data inside a shader, use
10112
+ * <a href="#/p5/uniformStorage">`uniformStorage()`</a>. To update its contents
10113
+ * from JavaScript, call <a href="#/p5.StorageBuffer/update">`.update()`</a>
10114
+ * on the result with new data.
10115
+ *
10116
+ * Pass an array of objects to store a list of items, each with named
10117
+ * properties. The properties can be numbers, arrays of numbers, vectors
10118
+ * created with <a href="#/p5/createVector">`createVector()`</a>, or colors
10119
+ * created with <a href="#/p5/color">`color()`</a>. Inside the shader, each
10120
+ * item is accessed by index, and its properties are available by name.
10121
+ *
10122
+ * ```js example
10123
+ * let instanceData;
10124
+ * let instancesShader;
10125
+ * let instance;
10126
+ * let count = 5;
10127
+ *
10128
+ * async function setup() {
10129
+ * await createCanvas(200, 200, WEBGPU);
10130
+ *
10131
+ * let data = [];
10132
+ * for (let i = 0; i < count; i++) {
10133
+ * data.push({
10134
+ * position: createVector(
10135
+ * random(-1, 1) * width / 2,
10136
+ * random(-1, 1) * height / 2,
10137
+ * 0,
10138
+ * ),
10139
+ * color: color(
10140
+ * random(255),
10141
+ * random(255),
10142
+ * random(255)
10143
+ * )
10144
+ * });
10145
+ * }
10146
+ * instanceData = createStorage(data);
10147
+ * instance = buildGeometry(drawInstance);
10148
+ * instancesShader = buildMaterialShader(drawInstances);
10149
+ * describe('Five spheres at random positions, each a different random color.');
10150
+ * }
10151
+ *
10152
+ * function drawInstance() {
10153
+ * sphere(15);
10154
+ * }
10155
+ *
10156
+ * function drawInstances() {
10157
+ * let data = uniformStorage(instanceData);
10158
+ * let itemColor = sharedVec4();
10159
+ *
10160
+ * worldInputs.begin();
10161
+ * let item = data[instanceID()];
10162
+ * itemColor = item.color;
10163
+ * worldInputs.position += item.position;
10164
+ * worldInputs.end();
10165
+ *
10166
+ * finalColor.begin();
10167
+ * finalColor.set(itemColor);
10168
+ * finalColor.end();
10169
+ * }
10170
+ *
10171
+ * function draw() {
10172
+ * background(220);
10173
+ * lights();
10174
+ * noStroke();
10175
+ * shader(instancesShader);
10176
+ * model(instance, count);
10177
+ * }
10178
+ * ```
10179
+ *
10180
+ * You can also store a plain list of numbers by passing an array of numbers.
10181
+ * Inside the shader, each number is accessed by index directly. To create an
10182
+ * empty list to be filled in by a compute shader, pass a count instead.
10183
+ *
10184
+ * ```js example
10185
+ * let cells;
10186
+ * let nextCells;
10187
+ * let gameShader;
10188
+ * let displayShader;
10189
+ * const W = 100;
10190
+ * const H = 100;
10191
+ *
10192
+ * async function setup() {
10193
+ * await createCanvas(100, 100, WEBGPU);
10194
+ *
10195
+ * let initial = new Float32Array(W * H);
10196
+ * for (let i = 0; i < initial.length; i++) {
10197
+ * initial[i] = random() > 0.7 ? 1 : 0;
10198
+ * }
10199
+ * cells = createStorage(initial);
10200
+ * nextCells = createStorage(W * H);
10201
+ *
10202
+ * gameShader = buildComputeShader(simulate);
10203
+ * displayShader = buildFilterShader(display);
10204
+ * describe('An animated Game of Life simulation displayed as black and white pixels.');
10205
+ * }
10206
+ *
10207
+ * function simulate() {
10208
+ * let current = uniformStorage(() => cells);
10209
+ * let next = uniformStorage(() => nextCells);
10210
+ * let w = uniformInt(() => W);
10211
+ * let h = uniformInt(() => H);
10212
+ * let x = index.x;
10213
+ * let y = index.y;
10214
+ *
10215
+ * let n = 0;
10216
+ * for (let dy = -1; dy <= 1; dy++) {
10217
+ * for (let dx = -1; dx <= 1; dx++) {
10218
+ * if (dx != 0 || dy != 0) {
10219
+ * let nx = (x + dx + w) % w;
10220
+ * let ny = (y + dy + h) % h;
10221
+ * n += current[ny * w + nx];
10222
+ * }
10223
+ * }
10224
+ * }
10225
+ *
10226
+ * let alive = current[y * w + x];
10227
+ * let nextOutput = 0;
10228
+ * if (alive == 1) {
10229
+ * if (abs(n - 2) < 0.1 || abs(n - 3) < 0.1) {
10230
+ * nextOutput = 1;
10231
+ * }
10232
+ * } else {
10233
+ * if (abs(n - 3) < 0.1) {
10234
+ * nextOutput = 1;
10235
+ * }
10236
+ * }
10237
+ * next[y * w + x] = nextOutput;
10238
+ * }
10239
+ *
10240
+ * function display() {
10241
+ * let data = uniformStorage(() => cells);
10242
+ * let w = uniformInt(() => W);
10243
+ * let h = uniformInt(() => H);
10244
+ *
10245
+ * filterColor.begin();
10246
+ * let x = floor(filterColor.texCoord.x * w);
10247
+ * let y = floor(filterColor.texCoord.y * h);
10248
+ * let alive = data[y * w + x];
10249
+ * filterColor.set([alive, alive, alive, 1]);
10250
+ * filterColor.end();
10251
+ * }
10252
+ *
10253
+ * function draw() {
10254
+ * compute(gameShader, W, H);
10255
+ * [nextCells, cells] = [cells, nextCells];
10256
+ * filter(displayShader);
10257
+ * }
10258
+ * ```
10259
+ *
10260
+ * @method createStorage
10261
+ * @submodule p5.strands
10262
+ * @beta
10263
+ * @webgpu
10264
+ * @webgpuOnly
10265
+ * @param {Number|Array|Float32Array|Object[]} dataOrCount Either a number specifying the count of floats,
10266
+ * an array/Float32Array of floats, or an array of objects describing struct elements.
10267
+ * @returns {p5.StorageBuffer} A storage buffer.
10268
+ */
10269
+ fn.createStorage = function (dataOrCount) {
10270
+ if (!this._renderer.createStorage) {
10271
+ p5._friendlyError(
10272
+ `createStorage() is only available with the WebGPU renderer. ${webGPUAddonMessage}`,
10273
+ 'createStorage'
10274
+ );
10275
+ return;
10276
+ }
10277
+ return this._renderer.createStorage(dataOrCount);
10278
+ };
10279
+
10280
+ /**
10281
+ * Returns the default shader used for compute operations.
10282
+ *
10283
+ * Calling <a href="#/p5/buildComputeShader">`buildComputeShader(shaderFunction)`</a>
10284
+ * is equivalent to calling `baseComputeShader().modify(shaderFunction)`.
10285
+ *
10286
+ * Read <a href="#/p5/buildComputeShader">the `buildComputeShader` reference</a> or
10287
+ * call `baseComputeShader().inspectHooks()` for more information on what you can do with
10288
+ * the base compute shader.
10289
+ *
10290
+ * @method baseComputeShader
10291
+ * @submodule p5.strands
10292
+ * @beta
10293
+ * @webgpu
10294
+ * @webgpuOnly
10295
+ * @returns {p5.Shader} The base compute shader.
10296
+ */
10297
+ fn.baseComputeShader = function () {
10298
+ if (!this._renderer.baseComputeShader) {
10299
+ p5._friendlyError(
10300
+ `baseComputeShader() is only available with the WebGPU renderer. ${webGPUAddonMessage}`,
10301
+ 'baseComputeShader'
10302
+ );
10303
+ return;
10304
+ }
10305
+ return this._renderer.baseComputeShader();
10306
+ };
10307
+
10308
+ /**
10309
+ * Create a new compute shader using p5.strands.
10310
+ *
10311
+ * A compute shader lets you run many calculations all at once on your GPU. They
10312
+ * are similar to a <a href="#/p5/for>`for` loop,</a> but each iteration of the
10313
+ * loop happens in parallel on the GPU rather than running one after the other.
10314
+ * This makes them ideal for calculations or simulations involving many items.
10315
+ *
10316
+ * You create a compute shader by passing a function to `buildComputeShader`.
10317
+ * The function represents one iteration of a loop.
10318
+ *
10319
+ * The compute shader can be run by calling <a href="#/p5/compute">`compute()`</a>
10320
+ * and passing the shader in, along with the number of iterations in up to three
10321
+ * dimensions. Use the <a href="#/p5/index">`index`</a> vector inside of your
10322
+ * iteration function to refer to the current iteration of the loop. The `x`, `y`,
10323
+ * and `z` properties will count up from zero to the count in each dimension passed
10324
+ * into `compute`.
10325
+ *
10326
+ * A compute shader will read from and write to storage, which is often an array of
10327
+ * numbers or objects. Use <a href="#/p5/createStorage">`createStorage`</a> to construct
10328
+ * initial data. Connect your iteration function to the storage by passing the storage
10329
+ * into <a href="#/p5/uniformStorage">`uniformStorage`</a>.
10330
+ *
10331
+ * Often, compute shaders are paired with <a href="#/p5/model">`model(myGeometry, count)`</a>
10332
+ * to draw one instance per object in the storage, and a shader that uses
10333
+ * <a href="#/p5/instanceID">`instanceID()`</a> to position each instance.
10334
+ *
10335
+ * ```js example
10336
+ * let particles;
10337
+ * let computeShader;
10338
+ * let displayShader;
10339
+ * let instance;
10340
+ * const numParticles = 100;
10341
+ *
10342
+ * async function setup() {
10343
+ * await createCanvas(100, 100, WEBGPU);
10344
+ * particles = createStorage(makeParticles(width / 2, height / 2));
10345
+ * computeShader = buildComputeShader(simulate);
10346
+ * displayShader = buildMaterialShader(display);
10347
+ * instance = buildGeometry(drawParticle);
10348
+ * describe('100 orange particles shooting outward.');
10349
+ * }
10350
+ *
10351
+ * function makeParticles(x, y) {
10352
+ * let data = [];
10353
+ * for (let i = 0; i < numParticles; i++) {
10354
+ * let angle = (i / numParticles) * TWO_PI;
10355
+ * let speed = random(0.5, 2);
10356
+ * data.push({
10357
+ * position: createVector(x, y),
10358
+ * velocity: createVector(cos(angle) * speed, sin(angle) * speed),
10359
+ * });
10360
+ * }
10361
+ * return data;
10362
+ * }
10363
+ *
10364
+ * function drawParticle() {
10365
+ * sphere(2);
10366
+ * }
10367
+ *
10368
+ * function simulate() {
10369
+ * let data = uniformStorage(particles);
10370
+ * let idx = index.x;
10371
+ * data[idx].position = data[idx].position + data[idx].velocity;
10372
+ * }
10373
+ *
10374
+ * function display() {
10375
+ * let data = uniformStorage(particles);
10376
+ * worldInputs.begin();
10377
+ * let pos = data[instanceID()].position;
10378
+ * worldInputs.position.xy += pos - [width / 2, height / 2];
10379
+ * worldInputs.end();
10380
+ * }
10381
+ *
10382
+ * function draw() {
10383
+ * background(30);
10384
+ * if (frameCount % 60 === 0) {
10385
+ * particles.update(makeParticles(random(width), random(height)));
10386
+ * }
10387
+ * compute(computeShader, numParticles);
10388
+ * noStroke();
10389
+ * fill(255, 200, 50);
10390
+ * shader(displayShader);
10391
+ * model(instance, numParticles);
10392
+ * }
10393
+ * ```
10394
+ *
10395
+ * ```js example
10396
+ * let particles;
10397
+ * let computeShader;
10398
+ * let displayShader;
10399
+ * let instance;
10400
+ * const numParticles = 50;
10401
+ *
10402
+ * async function setup() {
10403
+ * await createCanvas(100, 100, WEBGPU);
10404
+ *
10405
+ * let data = [];
10406
+ * for (let i = 0; i < numParticles; i++) {
10407
+ * data.push({
10408
+ * position: createVector(
10409
+ * random(-40, 40),
10410
+ * random(-40, 40)
10411
+ * ),
10412
+ * velocity: createVector(
10413
+ * random(-1, 1),
10414
+ * random(-1, 1)
10415
+ * ),
10416
+ * });
10417
+ * }
10418
+ * particles = createStorage(data);
10419
+ *
10420
+ * computeShader = buildComputeShader(simulate);
10421
+ * displayShader = buildMaterialShader(display);
10422
+ * instance = buildGeometry(drawParticle);
10423
+ * describe('50 white spheres bouncing around the canvas.');
10424
+ * }
10425
+ *
10426
+ * function drawParticle() {
10427
+ * sphere(3);
10428
+ * }
10429
+ *
10430
+ * function simulate() {
10431
+ * let r = 3;
10432
+ * let data = uniformStorage(particles);
10433
+ * let idx = index.x;
10434
+ * let pos = data[idx].position;
10435
+ * let vel = data[idx].velocity;
10436
+ * pos = pos + vel;
10437
+ * if (pos.x > width/2 - r || pos.x < -height/2 + r) {
10438
+ * vel.x = -vel.x;
10439
+ * pos.x = clamp(pos.x, -width/2 + r, width/2 - r);
10440
+ * }
10441
+ * if (pos.y > height/2 - r || pos.y < -height/2 + r) {
10442
+ * vel.y = -vel.y;
10443
+ * pos.y = clamp(pos.y, -height/2 + r, height/2 - r);
10444
+ * }
10445
+ * data[idx].position = pos;
10446
+ * data[idx].velocity = vel;
10447
+ * }
10448
+ *
10449
+ * function display() {
10450
+ * let data = uniformStorage(particles);
10451
+ * worldInputs.begin();
10452
+ * let pos = data[instanceID()].position;
10453
+ * worldInputs.position.xy += pos;
10454
+ * worldInputs.end();
10455
+ * }
10456
+ *
10457
+ * function draw() {
10458
+ * background(30);
10459
+ * compute(computeShader, numParticles);
10460
+ * noStroke();
10461
+ * fill(255);
10462
+ * lights();
10463
+ * shader(displayShader);
10464
+ * model(instance, numParticles);
10465
+ * }
10466
+ * ```
10467
+ *
10468
+ * @method buildComputeShader
10469
+ * @submodule p5.strands
10470
+ * @beta
10471
+ * @webgpu
10472
+ * @webgpuOnly
10473
+ * @param {Function} callback A function building a p5.strands compute shader.
10474
+ * @returns {p5.Shader} The compute shader.
10475
+ */
10476
+ fn.buildComputeShader = function (cb, context) {
10477
+ if (!this._renderer.baseComputeShader) {
10478
+ p5._friendlyError(
10479
+ `buildComputeShader() is only available with the WebGPU renderer. ${webGPUAddonMessage}`,
10480
+ 'buildComputeShader'
10481
+ );
10482
+ return;
10483
+ }
10484
+ return this.baseComputeShader().modify(cb, context, { hook: 'iteration' });
10485
+ };
10486
+
10487
+ /**
10488
+ * Dispatches a compute shader to run on the GPU.
10489
+ *
10490
+ * The first parameter, `shader`, is a compute shader created with
10491
+ * <a href="#/p5/buildComputeShader">`buildComputeShader`</a>.
10492
+ *
10493
+ * Pass a number for `x` to run a simple loop. Inside the shader's iteration
10494
+ * function, <a href="#/p5/index">`index.x`</a> will count up from 0 to
10495
+ * that number.
10496
+ *
10497
+ * ```js example
10498
+ * let particles;
10499
+ * let computeShader;
10500
+ * let displayShader;
10501
+ * let instance;
10502
+ * const numParticles = 50;
10503
+ *
10504
+ * async function setup() {
10505
+ * await createCanvas(100, 100, WEBGPU);
10506
+ *
10507
+ * let data = [];
10508
+ * for (let i = 0; i < numParticles; i++) {
10509
+ * data.push({
10510
+ * position: createVector(
10511
+ * random(-40, 40),
10512
+ * random(-40, 40)
10513
+ * ),
10514
+ * velocity: createVector(
10515
+ * random(-1, 1),
10516
+ * random(-1, 1)
10517
+ * ),
10518
+ * });
10519
+ * }
10520
+ * particles = createStorage(data);
10521
+ *
10522
+ * computeShader = buildComputeShader(simulate);
10523
+ * displayShader = buildMaterialShader(display);
10524
+ * instance = buildGeometry(drawParticle);
10525
+ * describe('50 white spheres bouncing around the canvas.');
10526
+ * }
10527
+ *
10528
+ * function drawParticle() {
10529
+ * sphere(3);
10530
+ * }
10531
+ *
10532
+ * function simulate() {
10533
+ * let r = 3;
10534
+ * let data = uniformStorage(particles);
10535
+ * let idx = index.x;
10536
+ * let pos = data[idx].position;
10537
+ * let vel = data[idx].velocity;
10538
+ * pos = pos + vel;
10539
+ * if (pos.x > width/2 - r || pos.x < -height/2 + r) {
10540
+ * vel.x = -vel.x;
10541
+ * pos.x = clamp(pos.x, -width/2 + r, width/2 - r);
10542
+ * }
10543
+ * if (pos.y > height/2 - r || pos.y < -height/2 + r) {
10544
+ * vel.y = -vel.y;
10545
+ * pos.y = clamp(pos.y, -height/2 + r, height/2 - r);
10546
+ * }
10547
+ * data[idx].position = pos;
10548
+ * data[idx].velocity = vel;
10549
+ * }
10550
+ *
10551
+ * function display() {
10552
+ * let data = uniformStorage(particles);
10553
+ * worldInputs.begin();
10554
+ * let pos = data[instanceID()].position;
10555
+ * worldInputs.position.xy += pos;
10556
+ * worldInputs.end();
10557
+ * }
10558
+ *
10559
+ * function draw() {
10560
+ * background(30);
10561
+ * compute(computeShader, numParticles);
10562
+ * noStroke();
10563
+ * fill(255);
10564
+ * lights();
10565
+ * shader(displayShader);
10566
+ * model(instance, numParticles);
10567
+ * }
10568
+ * ```
10569
+ *
10570
+ * You can also pass `y` and `z` to loop in up to three dimensions, using
10571
+ * `index.y` and `index.z` to get the position in each. This is useful for
10572
+ * working with 2D grids, like in the Game of Life example below.
10573
+ *
10574
+ * ```js example
10575
+ * let cells;
10576
+ * let nextCells;
10577
+ * let gameShader;
10578
+ * let displayShader;
10579
+ * const W = 100;
10580
+ * const H = 100;
10581
+ *
10582
+ * async function setup() {
10583
+ * await createCanvas(100, 100, WEBGPU);
10584
+ *
10585
+ * let initial = new Float32Array(W * H);
10586
+ * for (let i = 0; i < initial.length; i++) {
10587
+ * initial[i] = random() > 0.7 ? 1 : 0;
10588
+ * }
10589
+ * cells = createStorage(initial);
10590
+ * nextCells = createStorage(W * H);
10591
+ *
10592
+ * gameShader = buildComputeShader(simulate);
10593
+ * displayShader = buildFilterShader(display);
10594
+ * describe('An animated Game of Life simulation displayed as black and white pixels.');
10595
+ * }
10596
+ *
10597
+ * function simulate() {
10598
+ * let current = uniformStorage(() => cells);
10599
+ * let next = uniformStorage(() => nextCells);
10600
+ * let w = uniformInt(() => W);
10601
+ * let h = uniformInt(() => H);
10602
+ * let x = index.x;
10603
+ * let y = index.y;
10604
+ *
10605
+ * let n = 0;
10606
+ * for (let dy = -1; dy <= 1; dy++) {
10607
+ * for (let dx = -1; dx <= 1; dx++) {
10608
+ * if (dx != 0 || dy != 0) {
10609
+ * let nx = (x + dx + w) % w;
10610
+ * let ny = (y + dy + h) % h;
10611
+ * n += current[ny * w + nx];
10612
+ * }
10613
+ * }
10614
+ * }
10615
+ *
10616
+ * let alive = current[y * w + x];
10617
+ * let nextOutput = 0;
10618
+ * if (alive == 1) {
10619
+ * if (abs(n - 2) < 0.1 || abs(n - 3) < 0.1) {
10620
+ * nextOutput = 1;
10621
+ * }
10622
+ * } else {
10623
+ * if (abs(n - 3) < 0.1) {
10624
+ * nextOutput = 1;
10625
+ * }
10626
+ * }
10627
+ * next[y * w + x] = nextOutput;
10628
+ * }
10629
+ *
10630
+ * function display() {
10631
+ * let data = uniformStorage(() => cells);
10632
+ * let w = uniformInt(() => W);
10633
+ * let h = uniformInt(() => H);
10634
+ *
10635
+ * filterColor.begin();
10636
+ * let x = floor(filterColor.texCoord.x * w);
10637
+ * let y = floor(filterColor.texCoord.y * h);
10638
+ * let alive = data[y * w + x];
10639
+ * filterColor.set([alive, alive, alive, 1]);
10640
+ * filterColor.end();
10641
+ * }
10642
+ *
10643
+ * function draw() {
10644
+ * compute(gameShader, W, H);
10645
+ * [nextCells, cells] = [cells, nextCells];
10646
+ * filter(displayShader);
10647
+ * }
10648
+ * ```
10649
+ *
10650
+ * @method compute
10651
+ * @submodule p5.strands
10652
+ * @beta
10653
+ * @webgpu
10654
+ * @webgpuOnly
10655
+ * @param {p5.Shader} shader The compute shader to run.
10656
+ * @param {Number} x Number of invocations in the X dimension.
10657
+ * @param {Number} [y=1] Number of invocations in the Y dimension.
10658
+ * @param {Number} [z=1] Number of invocations in the Z dimension.
10659
+ */
10660
+ fn.compute = function (shader, x, y, z) {
10661
+ if (!this._renderer.compute) {
10662
+ p5._friendlyError(
10663
+ `compute() is only available with the WebGPU renderer. ${webGPUAddonMessage}`,
10664
+ 'compute'
10665
+ );
10666
+ return;
10667
+ }
10668
+ this._renderer.compute(shader, x, y, z);
10669
+ };
10670
+
10671
+ /**
10672
+ * Information about the current iteration of a compute shader.
10673
+ *
10674
+ * Use it inside a
10675
+ * <a href="#/p5/buildComputeShader">`buildComputeShader()`</a>
10676
+ * function to write a loop that runs in parallel on the GPU.
10677
+ *
10678
+ * `index` is a three-component vector with the current index
10679
+ * across all dimensions passed to
10680
+ * <a href="#/p5/compute">`compute()`</a>. For example, use
10681
+ * `index.x` to get the index when looping in one dimension.
10682
+ *
10683
+ * @property index
10684
+ * @submodule p5.strands
10685
+ * @beta
10686
+ * @webgpu
10687
+ * @webgpuOnly
10688
+ */
10063
10689
  }
10064
10690
 
10065
10691
  if (typeof p5 !== "undefined") {
@@ -10070,8 +10696,6 @@ if (typeof p5 !== "undefined") {
10070
10696
  * @module Shape
10071
10697
  * @submodule 3D Primitives
10072
10698
  * @for p5
10073
- * @requires core
10074
- * @requires p5.Geometry
10075
10699
  */
10076
10700
 
10077
10701
 
@@ -11857,33 +12481,38 @@ function primitives3D(p5, fn){
11857
12481
  const prevMode = this.states.textureMode;
11858
12482
  this.states.setValue('textureMode', NORMAL);
11859
12483
  const prevOrder = this.bezierOrder();
11860
- this.bezierOrder(2);
12484
+ this.bezierOrder(3);
11861
12485
  this.beginShape();
11862
12486
  const addUVs = (x, y) => [x, y, 0, (x - x1)/width, (y - y1)/height];
12487
+ const rr = 0.5523; // kappa: 4*(sqrt(2)-1)/3, handle ratio for cubic bezier circle approximation
11863
12488
  if (tr !== 0) {
11864
12489
  this.vertex(...addUVs(x2 - tr, y1));
11865
- this.bezierVertex(...addUVs(x2, y1));
12490
+ this.bezierVertex(...addUVs(x2 - tr + tr * rr, y1));
12491
+ this.bezierVertex(...addUVs(x2, y1 + tr - tr * rr));
11866
12492
  this.bezierVertex(...addUVs(x2, y1 + tr));
11867
12493
  } else {
11868
12494
  this.vertex(...addUVs(x2, y1));
11869
12495
  }
11870
12496
  if (br !== 0) {
11871
12497
  this.vertex(...addUVs(x2, y2 - br));
11872
- this.bezierVertex(...addUVs(x2, y2));
12498
+ this.bezierVertex(...addUVs(x2, y2 - br + br * rr));
12499
+ this.bezierVertex(...addUVs(x2 - br + rr * br, y2));
11873
12500
  this.bezierVertex(...addUVs(x2 - br, y2));
11874
12501
  } else {
11875
12502
  this.vertex(...addUVs(x2, y2));
11876
12503
  }
11877
12504
  if (bl !== 0) {
11878
12505
  this.vertex(...addUVs(x1 + bl, y2));
11879
- this.bezierVertex(...addUVs(x1, y2));
12506
+ this.bezierVertex(...addUVs(x1 + bl - bl * rr, y2));
12507
+ this.bezierVertex(...addUVs(x1, y2 - bl + bl * rr));
11880
12508
  this.bezierVertex(...addUVs(x1, y2 - bl));
11881
12509
  } else {
11882
12510
  this.vertex(...addUVs(x1, y2));
11883
12511
  }
11884
12512
  if (tl !== 0) {
11885
12513
  this.vertex(...addUVs(x1, y1 + tl));
11886
- this.bezierVertex(...addUVs(x1, y1));
12514
+ this.bezierVertex(...addUVs(x1, y1 + tl - tl * rr));
12515
+ this.bezierVertex(...addUVs(x1 + tl - tl * rr, y1));
11887
12516
  this.bezierVertex(...addUVs(x1 + tl, y1));
11888
12517
  } else {
11889
12518
  this.vertex(...addUVs(x1, y1));
@@ -12665,7 +13294,6 @@ if(typeof p5 !== 'undefined'){
12665
13294
  * @module 3D
12666
13295
  * @submodule Lights
12667
13296
  * @for p5
12668
- * @requires core
12669
13297
  */
12670
13298
 
12671
13299
 
@@ -14428,7 +15056,6 @@ if(typeof p5 !== 'undefined'){
14428
15056
  * @module 3D
14429
15057
  * @submodule Material
14430
15058
  * @for p5
14431
- * @requires core
14432
15059
  */
14433
15060
 
14434
15061
 
@@ -14921,6 +15548,7 @@ function material(p5, fn) {
14921
15548
  * `loadFilterShader('myShader.js', onLoaded)`.
14922
15549
  *
14923
15550
  * @method loadFilterShader
15551
+ * @beta
14924
15552
  * @submodule p5.strands
14925
15553
  * @param {String} filename path to a p5.strands JavaScript file or a GLSL fragment shader file
14926
15554
  * @param {Function} [successCallback] callback to be called once the shader is
@@ -17073,6 +17701,8 @@ function material(p5, fn) {
17073
17701
  *
17074
17702
  * Note: `textureMode()` can only be used in WebGL mode.
17075
17703
  *
17704
+ * Calling `textureMode()` with no arguments returns the current texture mode.
17705
+ *
17076
17706
  * @method textureMode
17077
17707
  * @param {(IMAGE|NORMAL)} mode either IMAGE or NORMAL.
17078
17708
  *
@@ -17135,7 +17765,14 @@ function material(p5, fn) {
17135
17765
  * endShape();
17136
17766
  * }
17137
17767
  */
17768
+ /**
17769
+ * @method textureMode
17770
+ * @return {(IMAGE|NORMAL)} The current texture mode, either IMAGE or NORMAL.
17771
+ */
17138
17772
  fn.textureMode = function (mode) {
17773
+ if (typeof mode === 'undefined') { // getter
17774
+ return this._renderer.states.textureMode;
17775
+ }
17139
17776
  if (mode !== IMAGE && mode !== NORMAL) {
17140
17777
  console.warn(
17141
17778
  `You tried to set ${mode} textureMode only supports IMAGE & NORMAL `,
@@ -17243,6 +17880,9 @@ function material(p5, fn) {
17243
17880
  *
17244
17881
  * Note: `textureWrap()` can only be used in WebGL mode.
17245
17882
  *
17883
+ * Calling `textureWrap()` with no arguments returns an object with the current
17884
+ * mode for x and y directions, as in `{ wrapX: CLAMP, wrapY: REPEAT }`.
17885
+ *
17246
17886
  * @method textureWrap
17247
17887
  * @param {(CLAMP|REPEAT|MIRROR)} wrapX either CLAMP, REPEAT, or MIRROR
17248
17888
  * @param {(CLAMP|REPEAT|MIRROR)} [wrapY=wrapX] either CLAMP, REPEAT, or MIRROR
@@ -17398,13 +18038,31 @@ function material(p5, fn) {
17398
18038
  * endShape();
17399
18039
  * }
17400
18040
  */
18041
+ /**
18042
+ * @method textureWrap
18043
+ * @return {{x: (CLAMP|REPEAT|MIRROR), y: (CLAMP|REPEAT|MIRROR)}} The current texture wrapping for x and y.
18044
+ */
17401
18045
  fn.textureWrap = function (wrapX, wrapY = wrapX) {
17402
- this._renderer.states.setValue("textureWrapX", wrapX);
17403
- this._renderer.states.setValue("textureWrapY", wrapY);
18046
+ if (typeof wrapX === 'undefined') { // getter
18047
+ return {
18048
+ x: this._renderer.states.textureWrapX,
18049
+ y: this._renderer.states.textureWrapY
18050
+ };
18051
+ }
18052
+ // accept what is returned from the getter
18053
+ if (wrapX.hasOwnProperty('x') && wrapX.hasOwnProperty('y')) {
18054
+ wrapX = wrapX.x;
18055
+ wrapY = wrapX.y;
18056
+ }
18057
+ this._renderer.states.setValue('textureWrapX', wrapX);
18058
+ this._renderer.states.setValue('textureWrapY', wrapY);
17404
18059
 
17405
- for (const texture of this._renderer.textures.values()) {
17406
- texture.setWrapMode(wrapX, wrapY);
18060
+ if (this._renderer.textures) {
18061
+ for (const texture of this._renderer.textures.values()) {
18062
+ texture.setWrapMode(wrapX, wrapY);
18063
+ }
17407
18064
  }
18065
+ return this;
17408
18066
  };
17409
18067
 
17410
18068
  /**
@@ -18896,7 +19554,6 @@ function graphics(p5, fn){
18896
19554
  * @module 3D
18897
19555
  * @submodule Material
18898
19556
  * @for p5
18899
- * @requires core
18900
19557
  */
18901
19558
 
18902
19559
 
@@ -19304,8 +19961,8 @@ if(typeof p5 !== 'undefined'){
19304
19961
  * @param {Uint8Array|Float32Array|undefined} pixels An existing pixels array to reuse if the size is the same
19305
19962
  * @param {WebGLRenderingContext} gl The WebGL context
19306
19963
  * @param {WebGLFramebuffer|null} framebuffer The Framebuffer to read
19307
- * @param {Number} x The x coordiante to read, premultiplied by pixel density
19308
- * @param {Number} y The y coordiante to read, premultiplied by pixel density
19964
+ * @param {Number} x The x coordinate to read, premultiplied by pixel density
19965
+ * @param {Number} y The y coordinate to read, premultiplied by pixel density
19309
19966
  * @param {Number} width The width in pixels to be read (factoring in pixel density)
19310
19967
  * @param {Number} height The height in pixels to be read (factoring in pixel density)
19311
19968
  * @param {GLEnum} format Either RGB or RGBA depending on how many channels to read
@@ -19727,6 +20384,20 @@ function populateGLSLHooks(shader, src, shaderType) {
19727
20384
  }
19728
20385
  }
19729
20386
  }
20387
+
20388
+ // Handle instanceID varying for fragment access
20389
+ if (shader.hooks.instanceIDVarying) {
20390
+ const { declaration, source, interpolation } = shader.hooks.instanceIDVarying;
20391
+ const qualifier = interpolation ? `${interpolation} ` : '';
20392
+ if (shaderType === "vertex") {
20393
+ // Emit flat out declaration and inject assignment into main() body
20394
+ hooks += `${qualifier}OUT ${declaration};\n`;
20395
+ postMain = postMain.replace(/\{/, `{\n ${declaration.split(' ').pop()} = ${source};`);
20396
+ } else if (shaderType === "fragment") {
20397
+ hooks += `${qualifier}IN ${declaration};\n`;
20398
+ }
20399
+ }
20400
+
19730
20401
  for (const hookDef in shader.hooks.helpers) {
19731
20402
  hooks += `${hookDef}${shader.hooks.helpers[hookDef]}\n`;
19732
20403
  }
@@ -19783,7 +20454,6 @@ function checkWebGLCapabilities({ GL, webglVersion }) {
19783
20454
 
19784
20455
  /**
19785
20456
  * @module Rendering
19786
- * @requires constants
19787
20457
  */
19788
20458
 
19789
20459
 
@@ -21230,10 +21900,12 @@ function rendering(p5, fn){
21230
21900
  * system variable to check what version is being used, or call
21231
21901
  * `setAttributes({ version: 1 })` to create a WebGL1 context.
21232
21902
  *
21903
+ * Note: In WebGPU mode, you must `await` this function.
21904
+ *
21233
21905
  * @method createCanvas
21234
21906
  * @param {Number} [width] width of the canvas. Defaults to 100.
21235
21907
  * @param {Number} [height] height of the canvas. Defaults to 100.
21236
- * @param {(P2D|WEBGL|P2DHDR|WEBGPU)} [renderer] either P2D, WEBGL, or WEBGPU. Defaults to `P2D`.
21908
+ * @param {(P2D|WEBGL|P2DHDR)} [renderer] either P2D or WEBGL. Defaults to `P2D`.
21237
21909
  * @param {HTMLCanvasElement} [canvas] existing canvas element that should be used for the sketch.
21238
21910
  * @return {p5.Renderer} new `p5.Renderer` that holds the canvas.
21239
21911
  *
@@ -21291,6 +21963,14 @@ function rendering(p5, fn){
21291
21963
  * describe('A diagonal line drawn from top-left to bottom-right on a gray background.');
21292
21964
  * }
21293
21965
  */
21966
+ /**
21967
+ * @method createCanvas
21968
+ * @param {Number} width
21969
+ * @param {Number} height
21970
+ * @param {WEBGPU} renderer
21971
+ * @param {HTMLCanvasElement} [canvas]
21972
+ * @return {Promise<p5.Renderer>}
21973
+ */
21294
21974
  /**
21295
21975
  * @method createCanvas
21296
21976
  * @param {Number} [width]
@@ -21310,6 +21990,14 @@ function rendering(p5, fn){
21310
21990
  args.unshift(renderer);
21311
21991
  }
21312
21992
 
21993
+ if (!renderers[selectedRenderer]) {
21994
+ if (selectedRenderer === WEBGPU) {
21995
+ p5._friendlyError(`To create a WEBGPU canvas, remember to add the WebGPU add-on to your project.`);
21996
+ } else {
21997
+ p5._friendlyError(`We weren't able to find a renderer called ${selectedRenderer}.`);
21998
+ }
21999
+ }
22000
+
21313
22001
  // Init our graphics renderer
21314
22002
  if(this._renderer) this._renderer.remove();
21315
22003
  this._renderer = new renderers[selectedRenderer](this, w, h, true, ...args);
@@ -21846,4 +22534,4 @@ if(typeof p5 !== 'undefined'){
21846
22534
  rendering(p5, p5.prototype);
21847
22535
  }
21848
22536
 
21849
- export { Camera as C, FramebufferTexture as F, Graphics as G, MipmapTexture as M, Renderer3D as R, Texture as T, request as a, loadingDisplaying as b, camera as c, files as d, setWebGLTextureParams as e, framebuffer as f, getWebGLUniformMetadata as g, getWebGLShaderAttributes as h, image as i, populateGLSLHooks as j, rendering as k, light as l, material as m, graphics as n, readPixelWebGL as o, primitives3D as p, readPixelsWebGL as q, renderer3D as r, setWebGLUniformValue as s, texture as t, checkWebGLCapabilities as u, FramebufferCamera as v, Framebuffer as w, renderers as x };
22537
+ export { Camera as C, FramebufferTexture as F, Graphics as G, MipmapTexture as M, Renderer3D as R, Texture as T, light as a, framebuffer as b, camera as c, request as d, setWebGLTextureParams as e, files as f, getWebGLUniformMetadata as g, getWebGLShaderAttributes as h, image as i, populateGLSLHooks as j, rendering as k, loadingDisplaying as l, material as m, graphics as n, readPixelWebGL as o, primitives3D as p, readPixelsWebGL as q, renderer3D as r, setWebGLUniformValue as s, texture as t, checkWebGLCapabilities as u, FramebufferCamera as v, Framebuffer as w, renderers as x };