From 202b9d2da160fa49faf3bb2439ef02f98066814d Mon Sep 17 00:00:00 2001 From: Alejandro Date: Tue, 14 Nov 2023 10:26:15 +0100 Subject: [PATCH 1/5] Update to main --- p5.brush.js | 33 ++++++++++++++++++++++----------- p5.brush.min.js | 4 ++-- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/p5.brush.js b/p5.brush.js index b9fa7b1..1412400 100644 --- a/p5.brush.js +++ b/p5.brush.js @@ -1,6 +1,6 @@ /** * @fileoverview p5.brush - A comprehensive toolset for brush management in p5.js. - * @version 1.0 + * @version 1.0.1 * @license MIT * @author Alejandro Campos Uribe * @@ -371,6 +371,7 @@ * Object handling blending operations with WebGL shaders. * @property {boolean} loaded - Flag indicating if the blend shaders have been loaded. * @property {boolean} isBlending - Flag indicating if the blending has been initiated. + * @property {boolean} isCaching - Flag indicating if the color caching is active. * @property {Float32Array} currentColor - Typed array to hold color values for shaders. * @property {function} load - Loads resources and initializes blend operations. * @property {function} blend - Applies blending effects using the initialized shader. @@ -379,9 +380,9 @@ */ const Mix = { loaded: false, - currentColor: new Float32Array(3), isBlending: false, isCaching: true, + currentColor: new Float32Array(3), /** * Loads necessary resources and prepares the mask buffer and shader for colour blending. @@ -432,6 +433,12 @@ return colorArray; }, + // Properties for the two blend instances: one uses the 2D mask, the other the WEBGL mask + /** + * There are two parallel blender instances: one uses the 2D mask, the other the WEBGL mask + * 2D Canvas API mask: for basi geometry (circles, polygons, etc), which is much faster with the 2D API + * WEBGL mask: for image-type brushes. p5 image() is much faster in WEBGL mode + */ color1: new Float32Array(3), color2: new Float32Array(3), blending1: false, @@ -480,12 +487,16 @@ this.noBlend.clear() // Use the blend shader for rendering _r.shader(this.shader); - // Set shader uniforms: color to add, source texture, and mask texture + // Set shader uniforms + // Color to blend this.shader.setUniform('addColor', this.currentColor); + // Source canvas this.shader.setUniform('source', _r._renderer); + // Bool to active watercolor blender vs marker blender this.shader.setUniform('active', _watercolor); - let rA = [R.random(),R.random(),R.random()] - this.shader.setUniform('random', rA); + // Random values for watercolor blender + this.shader.setUniform('random', [R.random(),R.random(),R.random()]); + // We select and apply the correct mask here let mask = webgl_mask ? this.mask2: this.mask; this.shader.setUniform('mask', mask); // Draw a rectangle covering the whole canvas to apply the shader @@ -1286,7 +1297,7 @@ * @returns {number} The calculated alpha value. */ calculateAlpha(pressure) { - return Math.floor(this.p.opacity * Math.pow(pressure, this.p.type === "marker" ? 1 : 1.5)); + return Math.floor(this.p.opacity * Math.pow(pressure, this.p.type === "marker" ? 0.7 : 1.5)); }, /** @@ -1551,8 +1562,6 @@ hatchingParams: [5,45,{}], hatchingBrush: false, - - /** * Creates a hatching pattern across the given polygons. * @@ -1571,7 +1580,7 @@ if (H.hatchingBrush) B.set(H.hatchingBrush[0],H.hatchingBrush[1],H.hatchingBrush[2]) // Check angleMode for calculations and transform to degrees - angle = ((angleMode() === "radians") ? angle * 180 / Math.PI : angle) % 180 + angle = (((angleMode() === "radians") ? angle * 180 / Math.PI : angle) + 3 * 360) % 180 // Calculate the bounding area of the provided polygons let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity; @@ -2224,9 +2233,10 @@ * @param {number} _texture - The texture of the watercolor effect, from 0 to 1. * EXPORTED */ - function setBleed(_i, _texture = 0) { + function setBleed(_i, _texture = 0, _border = 0) { F.b = R.constrain(_i,0,0.6); F.t = _texture > 1 ? 1 : _texture; + F.border_strength = 1 + _border > 1 ? 1 : _border; } /** @@ -2260,6 +2270,7 @@ b: 0.07, t: 0, o: 80, + border_strength: 1, /** * Fills the given polygon with a watercolor effect. @@ -2421,7 +2432,7 @@ // Set fill and stroke properties once Mix.mask.fill(255, 0, 0, _alpha); if (bool) { - Mix.mask.stroke(255, 0, 0, 1); + Mix.mask.stroke(255, 0, 0, 1.5 * F.border_strength); Mix.mask.strokeWeight(R.map(_nr, 0, 24, 6, 0.5)); } else { Mix.mask.noStroke(); diff --git a/p5.brush.min.js b/p5.brush.min.js index 3ec5d08..d265f9c 100644 --- a/p5.brush.min.js +++ b/p5.brush.min.js @@ -1,2 +1,2 @@ -/*! p5.brush.js v1.0.0 2023 - by Alejandro Campos - MIT License */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).brush={})}(this,(function(t){"use strict";let e,i=!1;function s(t=!1){i=!0,e=t||window.self,c.load(),m.create(),f(e.width/250)}function n(){i||s()}p5.prototype.registerMethod("afterSetup",(()=>n()));const o={source:()=>random(),random(t=0,e=1){return 1===arguments.length?this.map(this.source(),0,1,0,t):this.map(this.source(),0,1,t,e)},randInt(t,e){return Math.floor(this.random(t,e))},weightedRand(t){let e,i,s=[];for(e in t)for(i=0;i<10*t[e];i++)s.push(e);return s[Math.floor(this.source()*s.length)]},map(t,e,i,s,n,o=!1){let r=s+(t-e)/(i-e)*(n-s);return o?sMath.max(Math.min(t,i),e),cos(t){return this.c[Math.floor((t%360+360)%360*4)]},sin(t){return this.s[Math.floor((t%360+360)%360*4)]},isPrecalculationDone:!1,preCalculation(){if(this.isPrecalculationDone)return;const t=1440,e=2*Math.PI/t;this.c=new Float64Array(t),this.s=new Float64Array(t);for(let i=0;i1))&&{x:o+x*p,y:r+x*f}}function l(t,e,i,s){return(Math.atan2(-(s-e),i-t)*(180/Math.PI)%360+360)%360}const c={loaded:!1,currentColor:new Float32Array(3),isBlending:!1,isCaching:!0,load(){this.mask=createGraphics(e.width,e.height),this.mask.pixelDensity(e.pixelDensity()),this.mask.clear(),this.mask.noSmooth(),this.mask.angleMode(DEGREES),t.mask=this.mask,c.loaded||(this.frag=this.frag.replace('#include "spectral.glsl"',this.glsl())),this.shader=e.createShader(this.vert,this.frag),c.loaded=!0,this.noBlend=createGraphics(e.width,e.height),this.noBlend.pixelDensity(e.pixelDensity()),this.noBlend.noSmooth(),this.noBlend.clear(),this.noBlend.angleMode(DEGREES),this.mask2=createGraphics(e.width,e.height,WEBGL),this.mask2.pixelDensity(e.pixelDensity()),this.mask2.clear(),this.mask2.angleMode(DEGREES)},getPigment(t){let e=t.levels,i=new Float32Array(3);return i[0]=e[0]/255,i[1]=e[1]/255,i[2]=e[2]/255,i},color1:new Float32Array(3),color2:new Float32Array(3),blending1:!1,blending2:!1,blend(t=!1,i=!1,s=!1,n=!1){if(this.isBlending=s?this.blending1:this.blending2,this.currentColor=s?this.color1:this.color2,!this.isBlending){if(!t)return e.push(),e.translate(-a()[0],-a()[1]),e.image(this.noBlend,-e.width/2,-e.height/2),this.noBlend.clear(),void e.pop();this.currentColor=this.getPigment(t),s?(this.blending1=!0,this.color1=this.currentColor):(this.blending2=!0,this.color2=this.currentColor)}if((t?this.getPigment(t):this.currentColor).toString()!==this.currentColor.toString()||i||!this.isCaching){e.push(),e.translate(-a()[0],-a()[1]),e.image(this.noBlend,-e.width/2,-e.height/2),this.noBlend.clear(),e.shader(this.shader),this.shader.setUniform("addColor",this.currentColor),this.shader.setUniform("source",e._renderer),this.shader.setUniform("active",n);let r=[o.random(),o.random(),o.random()];this.shader.setUniform("random",r);let h=s?this.mask2:this.mask;this.shader.setUniform("mask",h),e.fill(0,0,0,0),e.noStroke(),e.rect(-e.width/2,-e.height/2,e.width,e.height),e.pop(),h.clear(),i||(this.currentColor=this.getPigment(t),s?this.color1=this.currentColor:this.color2=this.currentColor)}i&&(this.isBlending=!1,s?this.blending1=this.isBlending:this.blending2=this.isBlending)},vert:"precision highp float;attribute vec3 aPosition;attribute vec2 aTexCoord;uniform mat4 uModelViewMatrix,uProjectionMatrix;varying vec2 vVertTexCoord;void main(){gl_Position=uProjectionMatrix*uModelViewMatrix*vec4(aPosition,1);vVertTexCoord=aTexCoord;}",frag:'precision highp float;varying vec2 vVertTexCoord;uniform sampler2D source,mask;uniform vec4 addColor;uniform vec3 random;uniform bool active;\n #include "spectral.glsl"\n float v(vec2 v,vec2 x,float y,out vec2 i){vec2 d=vec2(v.x+v.y*.5,v.y),m=floor(d),f=fract(d);float a=step(f.y,f.x);vec2 r=vec2(a,1.-a),l=m+r,e=m+1.,z=vec2(m.x-m.y*.5,m.y),k=vec2(z.x+r.x-r.y*.5,z.y+r.y),o=vec2(z.x+.5,z.y+1.),s=v-z,g=v-k,t=v-o;vec3 u,c,C,D;if(any(greaterThan(x,vec2(0)))){C=vec3(z.x,k.x,o);D=vec3(z.y,k.y,o.y);if(x.x>0.)C=mod(vec3(z.x,k.x,o),x.x);if(x.y>0.)D=mod(vec3(z.y,k.y,o.y),x.y);u=floor(C+.5*D+.5);c=floor(D+.5);}else u=vec3(m.x,l.x,e),c=vec3(m.y,l.y,e.y);vec3 b=mod(u,289.);b=mod((b*51.+2.)*b+c,289.);b=mod((b*34.+10.)*b,289.);vec3 h=b*.07482+y,E=cos(h),w=sin(h);vec2 A=vec2(E.x,w),B=vec2(E.y,w.y),F=vec2(E.z,w.z);vec3 G=.8-vec3(dot(s,s),dot(g,g),dot(t,t));G=max(G,0.);vec3 H=G*G,I=H*H,J=vec3(dot(A,s),dot(B,g),dot(F,t)),K=H*G,L=-8.*K*J;i=10.9*(I.x*A+L.x*s+(I.y*B+L.y*g)+(I.z*F+L.z*t));return 10.9*dot(I,J);}vec4 v(vec3 v,float f){return vec4(mix(v,vec3(dot(vec3(.299,.587,.114),v)),f),1);}float f(vec2 v,float x,float y,float d){return fract(sin(dot(v,vec2(x,y)))*d);}void main(){vec4 m=texture2D(mask,vVertTexCoord);if(m.x>0.){vec2 z=vec2(12.9898,78.233),k=vec2(7.9898,58.233),o=vec2(17.9898,3.233);float x=f(vVertTexCoord,z.x,z.y,43358.5453)*2.-1.,y=f(vVertTexCoord,k.x,k.y,43213.5453)*2.-1.,d=f(vVertTexCoord,o.x,o.y,33358.5453)*2.-1.;const vec2 s=vec2(0);vec2 t;vec3 u;if(active){float a=v(vVertTexCoord*10.,s,10.*random.x,t),c=v(vVertTexCoord*10.,s,10.*random.y,t),g=v(vVertTexCoord*10.,s,10.*random.z,t),w=.25+.25*v(vVertTexCoord*8.,s,3.*random.x,t);u=v(addColor.xyz,w).xyz+vec3(a,c,g)*.03;}else u=addColor.xyz;vec3 a=spectral_mix(texture2D(source,vVertTexCoord).xyz,u,m.w);if(m.w>.8)a=spectral_mix(a,vec3(0),(m.w-.8)*.4);gl_FragColor=vec4(a+.01*vec3(x,y,d),1);}}',glsl:()=>"float spectral_uncompand(float s){return s<.04045?s/12.92:pow((s+.055)/1.055,2.4);}float spectral_compand(float s){return s<.0031308?s*12.92:1.055*pow(s,1./2.4)-.055;}vec3 spectral_srgb_to_linear(vec3 s){return vec3(spectral_uncompand(s[0]),spectral_uncompand(s[1]),spectral_uncompand(s[2]));}vec3 spectral_linear_to_srgb(vec3 s){return clamp(vec3(spectral_compand(s[0]),spectral_compand(s[1]),spectral_compand(s[2])),0.,1.);}void spectral_upsampling(vec3 e,out float m,out float s,out float f,out float r,out float x,out float v,out float z){m=min(e.x,min(e.y,e.z));e-=m;s=min(e.y,e.z);f=min(e.x,e.z);r=min(e.x,e.y);x=min(max(0.,e.x-e.z),max(0.,e.x-e.y));v=min(max(0.,e.y-e.z),max(0.,e.y-e.x));z=min(max(0.,e.z-e.y),max(0.,e.z-e.x));}void spectral_linear_to_reflectance(vec3 s,inout float f[38]){float e,o,m,x,v,w,z;spectral_upsampling(s,e,o,m,x,v,w,z);f[0]=max(1e-4,e+o*.96853629+m*.51567122+x*.02055257+v*.03147571+w*.49108579+z*.97901834);f[1]=max(1e-4,e+o*.96855103+m*.5401552+x*.02059936+v*.03146636+w*.46944057+z*.97901649);f[2]=max(1e-4,e+o*.96859338+m*.62645502+x*.02062723+v*.03140624+w*.4016578+z*.97901118);f[3]=max(1e-4,e+o*.96877345+m*.75595012+x*.02073387+v*.03119611+w*.2449042+z*.97892146);f[4]=max(1e-4,e+o*.96942204+m*.92826996+x*.02114202+v*.03053888+w*.0682688+z*.97858555);f[5]=max(1e-4,e+o*.97143709+m*.97223624+x*.02233154+v*.02856855+w*.02732883+z*.97743705);f[6]=max(1e-4,e+o*.97541862+m*.98616174+x*.02556857+v*.02459485+w*.013606+z*.97428075);f[7]=max(1e-4,e+o*.98074186+m*.98955255+x*.03330189+v*.0192952+w*.01000187+z*.96663223);f[8]=max(1e-4,e+o*.98580992+m*.98676237+x*.05185294+v*.01423112+w*.01284127+z*.94822893);f[9]=max(1e-4,e+o*.98971194+m*.97312575+x*.10087639+v*.01033111+w*.02636635+z*.89937713);f[10]=max(1e-4,e+o*.99238027+m*.91944277+x*.24000413+v*.00765876+w*.07058713+z*.76070164);f[11]=max(1e-4,e+o*.99409844+m*.32564851+x*.53589066+v*.00593693+w*.70421692+z*.4642044);f[12]=max(1e-4,e+o*.995172+m*.13820628+x*.79874659+v*.00485616+w*.85473994+z*.20123039);f[13]=max(1e-4,e+o*.99576545+m*.05015143+x*.91186529+v*.00426186+w*.95081565+z*.08808402);f[14]=max(1e-4,e+o*.99593552+m*.02912336+x*.95399623+v*.00409039+w*.9717037+z*.04592894);f[15]=max(1e-4,e+o*.99564041+m*.02421691+x*.97137099+v*.00438375+w*.97651888+z*.02860373);f[16]=max(1e-4,e+o*.99464769+m*.02660696+x*.97939505+v*.00537525+w*.97429245+z*.02060067);f[17]=max(1e-4,e+o*.99229579+m*.03407586+x*.98345207+v*.00772962+w*.97012917+z*.01656701);f[18]=max(1e-4,e+o*.98638762+m*.04835936+x*.98553736+v*.0136612+w*.9425863+z*.01451549);f[19]=max(1e-4,e+o*.96829712+m*.0001172+x*.98648905+v*.03181352+w*.99989207+z*.01357964);f[20]=max(1e-4,e+o*.89228016+m*8.554e-5+x*.98674535+v*.10791525+w*.99989891+z*.01331243);f[21]=max(1e-4,e+o*.53740239+m*.85267882+x*.98657555+v*.46249516+w*.13823139+z*.01347661);f[22]=max(1e-4,e+o*.15360445+m*.93188793+x*.98611877+v*.84604333+w*.06968113+z*.01387181);f[23]=max(1e-4,e+o*.05705719+m*.94810268+x*.98559942+v*.94275572+w*.05628787+z*.01435472);f[24]=max(1e-4,e+o*.03126539+m*.94200977+x*.98507063+v*.96860996+w*.06111561+z*.01479836);f[25]=max(1e-4,e+o*.02205445+m*.91478045+x*.98460039+v*.97783966+w*.08987709+z*.0151525);f[26]=max(1e-4,e+o*.01802271+m*.87065445+x*.98425301+v*.98187757+w*.13656016+z*.01540513);f[27]=max(1e-4,e+o*.0161346+m*.78827548+x*.98403909+v*.98377315+w*.22169624+z*.01557233);f[28]=max(1e-4,e+o*.01520947+m*.65738359+x*.98388535+v*.98470202+w*.32176956+z*.0156571);f[29]=max(1e-4,e+o*.01475977+m*.59909403+x*.98376116+v*.98515481+w*.36157329+z*.01571025);f[30]=max(1e-4,e+o*.01454263+m*.56817268+x*.98368246+v*.98537114+w*.4836192+z*.01571916);f[31]=max(1e-4,e+o*.01444459+m*.54031997+x*.98365023+v*.98546685+w*.46488579+z*.01572133);f[32]=max(1e-4,e+o*.01439897+m*.52110241+x*.98361309+v*.98550011+w*.47440306+z*.01572502);f[33]=max(1e-4,e+o*.0143762+m*.51041094+x*.98357259+v*.98551031+w*.4857699+z*.01571717);f[34]=max(1e-4,e+o*.01436343+m*.50526577+x*.98353856+v*.98550741+w*.49267971+z*.01571905);f[35]=max(1e-4,e+o*.01435687+m*.5025508+x*.98351247+v*.98551323+w*.49625685+z*.01571059);f[36]=max(1e-4,e+o*.0143537+m*.50126452+x*.98350101+v*.98551563+w*.49807754+z*.01569728);f[37]=max(1e-4,e+o*.01435408+m*.50083021+x*.98350852+v*.98551547+w*.49889859+z*.0157002);}vec3 spectral_xyz_to_srgb(vec3 e){mat3 f;f[0]=vec3(3.24306333,-1.53837619,-.49893282);f[1]=vec3(-.96896309,1.87542451,.04154303);f[2]=vec3(.05568392,-.20417438,1.05799454);float s=dot(f[0],e),m=dot(f[1],e),z=dot(f[2],e);return spectral_linear_to_srgb(vec3(s,m,z));}vec3 spectral_reflectance_to_xyz(float f[38]){vec3 e=vec3(0);e+=f[0]*vec3(6.469e-5,1.84e-6,.00030502);e+=f[1]*vec3(.00021941,6.21e-6,.00103681);e+=f[2]*vec3(.00112057,3.101e-5,.00531314);e+=f[3]*vec3(.00376661,.00010475,.01795439);e+=f[4]*vec3(.01188055,.00035364,.05707758);e+=f[5]*vec3(.02328644,.00095147,.11365162);e+=f[6]*vec3(.03455942,.00228226,.17335873);e+=f[7]*vec3(.03722379,.00420733,.19620658);e+=f[8]*vec3(.03241838,.0066888,.18608237);e+=f[9]*vec3(.02123321,.0098884,.13995048);e+=f[10]*vec3(.01049099,.01524945,.08917453);e+=f[11]*vec3(.00329584,.02141831,.04789621);e+=f[12]*vec3(.00050704,.03342293,.02814563);e+=f[13]*vec3(.00094867,.05131001,.01613766);e+=f[14]*vec3(.00627372,.07040208,.0077591);e+=f[15]*vec3(.01686462,.08783871,.00429615);e+=f[16]*vec3(.02868965,.09424905,.00200551);e+=f[17]*vec3(.04267481,.09795667,.00086147);e+=f[18]*vec3(.05625475,.09415219,.00036904);e+=f[19]*vec3(.0694704,.08678102,.00019143);e+=f[20]*vec3(.08305315,.07885653,.00014956);e+=f[21]*vec3(.0861261,.0635267,9.231e-5);e+=f[22]*vec3(.09046614,.05374142,6.813e-5);e+=f[23]*vec3(.08500387,.04264606,2.883e-5);e+=f[24]*vec3(.07090667,.03161735,1.577e-5);e+=f[25]*vec3(.05062889,.02088521,3.94e-6);e+=f[26]*vec3(.03547396,.01386011,1.58e-6);e+=f[27]*vec3(.02146821,.00810264,0);e+=f[28]*vec3(.01251646,.0046301,0);e+=f[29]*vec3(.00680458,.00249138,0);e+=f[30]*vec3(.00346457,.0012593,0);e+=f[31]*vec3(.00149761,.00054165,0);e+=f[32]*vec3(.0007697,.00027795,0);e+=f[33]*vec3(.00040737,.00014711,0);e+=f[34]*vec3(.00016901,6.103e-5,0);e+=f[35]*vec3(9.522e-5,3.439e-5,0);e+=f[36]*vec3(4.903e-5,1.771e-5,0);e+=f[37]*vec3(2e-5,7.22e-6,0);return e;}float spectral_linear_to_concentration(float v,float m,float s){float z=m*pow(s,2.);return z/(v*pow(1.-s,2.)+z);}vec3 spectral_mix(vec3 s,vec3 f,float e){vec3 v=spectral_srgb_to_linear(s),m=spectral_srgb_to_linear(f);float z[38],o[38];spectral_linear_to_reflectance(v,z);spectral_linear_to_reflectance(m,o);float x=spectral_reflectance_to_xyz(z)[1],w=spectral_reflectance_to_xyz(o)[1];e=spectral_linear_to_concentration(x,w,e);float r[38];for(int c=0;c<38;c++){float y=(1.-e)*(pow(1.-z[c],2.)/(2.*z[c]))+e*(pow(1.-o[c],2.)/(2.*o[c]));r[c]=1.+y-sqrt(pow(y,2.)+2.*y);}return spectral_xyz_to_srgb(spectral_reflectance_to_xyz(r));}vec4 spectral_mix(vec4 s,vec4 e,float z){return vec4(spectral_mix(s.xyz,e.xyz,z),mix(s.w,e.w,z));}"};function d(t,e){n(),m.list.set(t,{gen:e}),m.current=t,m.refresh()}p5.prototype.registerMethod("afterSetup",(()=>c.blend(!1,!0))),p5.prototype.registerMethod("afterSetup",(()=>c.blend(!1,!0,!0))),p5.prototype.registerMethod("post",(()=>c.blend(!1,!0))),p5.prototype.registerMethod("post",(()=>c.blend(!1,!0,!0)));const m={isActive:!1,list:new Map,current:"",step_length:()=>Math.min(e.width,e.height)/1e3,create(){this.R=.01*e.width,this.left_x=-1*e.width,this.top_y=-1*e.height,this.num_columns=Math.round(2*e.width/this.R),this.num_rows=Math.round(2*e.height/this.R),this.addStandard()},flow_field(){return this.list.get(this.current).field},refresh(t=0){this.list.get(this.current).field=this.list.get(this.current).gen(t)},genField(){let t=new Array(m.num_columns);for(let e=0;e=0&&this.row_index>=0&&this.column_index=-t-a()[0]&&this.x<=t-a()[0]&&this.y>=-i-a()[1]&&this.y<=i-a()[1]}angle(){return this.isIn()&&m.isActive?m.flow_field()[this.column_index][this.row_index]:0}moveTo(t,e,i=m.step_length(),s=!0){if(this.isIn()){let n,r;s||(n=o.cos(-e),r=o.sin(-e));for(let a=0;a{const i="marker"===e.type||"custom"===e.type||"image"===e.type;"image"===e.type&&(v.add(e.image.src),e.tip=()=>g.mask.image(v.tips.get(g.p.image.src),-g.p.weight/2,-g.p.weight/2,g.p.weight,g.p.weight)),e.blend=!!(i&&!1!==e.blend||e.blend),g.list.set(t,{param:e,colors:[],buffers:[]})},set(t,e,i=1){g.name=t,g.c=e,g.w=i,g.isActive=!0},setBrush(t){g.name=t},setColor(t,e,i){arguments.length>0&&(g.c=arguments.length<2?t:[t,e,i]),g.isActive=!0},setWeight(t){g.w=t},clip(t){g.cr=t},noClip(){g.cr=null},line(t,e,i,s){n();let o=dist(t,e,i,s);if(0==o)return;g.initializeDrawingState(t,e,o,!1,!1);let r=l(t,e,i,s);g.draw(r,!1)},flowLine(t,e,i,s){n(),"radians"===angleMode()&&(s=180*s/Math.PI),g.initializeDrawingState(t,e,i,!0,!1),g.draw(s,!1)},flowShape(t,e,i,s){n(),g.initializeDrawingState(e,i,t.length,!0,t),g.draw(s,!0)},spacing(){return this.p=this.list.get(this.name).param,this.p.spacing*this.w},initializeDrawingState(t,e,i,s,n){this.position=new p(t,e),this.length=i,this.flow=s,this.plot=n,n&&n.calcIndex(0)},draw(t,e){e||(this.dir=t),this.pushState();const i=this.spacing(),s=e?Math.round(this.length*t/i):Math.round(this.length/i);for(let n=0;n=g.cr[0]&&this.position.x<=g.cr[2]&&this.position.y>=g.cr[1]&&this.position.y<=g.cr[3]},drawSpray(t){let e=this.w*this.p.vibration*t+this.w*randomGaussian()*this.p.vibration/3,i=this.p.weight*o.random(.9,1.1);const s=this.p.quality/t;for(let t=0;t.4&&this.mask.circle(this.position.x+.7*e*o.random(-1,1),this.position.y+e*o.random(-1,1),t*this.p.weight*this.w*o.random(.85,1.15))},adjustSizeAndRotation(t,e){if(this.mask.scale(t),"image"===this.p.type&&(this.p.blend?this.mask.tint(255,0,0,e/2):this.mask.tint(this.mask.red(this.c),this.mask.green(this.c),this.mask.blue(this.c),e)),"random"===this.p.rotate)this.mask.rotate(o.randInt(0,360));else if("natural"===this.p.rotate){let t=(this.plot?-this.plot.angle(this.position.plotted):-this.dir)+(this.flow?this.position.angle():0);t=this.plot?-this.plot.angle(this.position.plotted):-this.dir,this.mask.rotate(t)}},markerTip(){if(this.isInsideClippingArea()){let t=this.calculatePressure(),e=this.calculateAlpha(t);if(this.mask.fill(255,0,0,e/1.5),"marker"===g.p.type)for(let e=1;e<5;e++)this.drawMarker(t*e/5,!1);else if("custom"===g.p.type||"image"===g.p.type)for(let i=1;i<5;i++)this.drawCustomOrImage(t*i/5,e,!1)}}};const v={tips:new Map,add(t){const e=new Image;this.tips.set(t,!1),e.onload=function(){v.tips.set(t,v.imageToWhite(e))},e.src=t},imageToWhite(t){let e=document.createElement("canvas");e.width=t.width,e.height=t.height;let i=e.getContext("2d");i.drawImage(t,0,0);let s=i.getImageData(0,0,t.width,t.height);for(let e=0;e<4*t.width*t.height;e+=4){let t=(s.data[e]+s.data[e+1]+s.data[e+2])/3;s.data[e]=s.data[e+1]=s.data[e+2]=255,s.data[e+3]=255-t}return i.putImageData(s,0,0),e.toDataURL()},load(){if(0===this.tips.size)return console.log("ojo");for(let t of this.tips.keys())this.tips.set(t,loadImage(this.tips.get(t)))}};function x(t=5,e=45,i={rand:!1,continuous:!1,gradient:!1}){w.isActive=!0,w.hatchingParams=[t,e,i]}const w={isActive:!1,hatchingParams:[5,45,{}],hatchingBrush:!1,hatch(t){let e=w.hatchingParams[0],i=w.hatchingParams[1],s=w.hatchingParams[2],n=g.c,r=g.name,a=g.w,h=g.isActive;w.hatchingBrush&&g.set(w.hatchingBrush[0],w.hatchingBrush[1],w.hatchingBrush[2]),i=("radians"===angleMode()?180*i/Math.PI:i)%180;let l=1/0,c=-1/0,d=1/0,m=-1/0,p=t=>{for(let e of t.a)l=e[0]c?e[0]:c,d=e[1]m?e[1]:m};Array.isArray(t)||(t=[t]);for(let e of t)p(e);let f=new y([[l,d],[c,d],[c,m],[l,m]]),u=i<=90&&i>=0?d:m,v=s.gradient?map(s.gradient,0,1,1,1.1,!0):1,x=[],_=0,z=e,k=t=>({point1:{x:l+z*t*o.cos(90-i),y:u+z*t*o.sin(90-i)},point2:{x:l+z*t*o.cos(90-i)+o.cos(-i),y:u+z*t*o.sin(90-i)+o.sin(-i)}});for(;f.intersect(k(_)).length>0;){let e=[];for(let i of t)e.push(i.intersect(k(_)));x[_]=e.flat().sort(((t,e)=>t.x===e.x?t.y-e.y:t.x-e.x)),z*=v,_++}let M=[];for(let t of x)void 0!==t[0]&&M.push(t);for(let t=0;t0&&s.continuous;for(let s=0;s({x:t[0],y:t[1]}))),this.sides=this.vertices.map(((t,e,i)=>[t,i[(e+1)%i.length]]))}intersect(t){let e=`${t.point1.x},${t.point1.y}-${t.point2.x},${t.point2.y}`;if(this._intersectionCache&&this._intersectionCache[e])return this._intersectionCache[e];let i=[];for(let e of this.sides){let s=h(t.point1,t.point2,e[0],e[1]);!1!==s&&i.push(s)}return this._intersectionCache||(this._intersectionCache={}),this._intersectionCache[e]=i,i}draw(t=!1,e,i){let s=g.isActive;if(t&&g.set(t,e,i),g.isActive){n();for(let t of this.sides)g.line(t[0].x,t[0].y,t[1].x,t[1].y)}g.isActive=s}fill(t=!1,e,i,s){let o=P.isActive;t&&(S(t,e),I(i,s)),P.isActive&&(n(),P.fill(this)),P.isActive=o}hatch(t=!1,e,i){let s=w.isActive;t&&x(t,e,i),w.isActive&&(n(),w.hatch(this)),w.isActive=s}}class _{constructor(t){this.segments=[],this.angles=[],this.pres=[],this.type=t,this.dir=0,this.calcIndex(0),this.pol=!1}addSegment(t=0,e=0,i=1,s=!1){"radians"!==angleMode()||s||(t=180*t/Math.PI),this.angles.length>0&&this.angles.splice(-1),t=(t+360)%360,this.angles.push(t),this.pres.push(i),this.segments.push(e),this.length=this.segments.reduce(((t,e)=>t+e),0),this.angles.push(t)}endPlot(t=0,e=1,i=!1){"radians"!==angleMode()||i||(t=180*t/Math.PI),this.angles.splice(-1),this.angles.push(t),this.pres.push(e)}rotate(t){"radians"===angleMode()&&(t=180*t/Math.PI),this.dir=t}pressure(t){return t>this.length?this.pres[this.pres.length-1]:this.curving(this.pres,t)}angle(t){return t>this.length?this.angles[this.angles.length-1]:(this.calcIndex(t),"curve"===this.type?this.curving(this.angles,t)+this.dir:this.angles[this.index]+this.dir)}curving(t,e){let i=t[this.index],s=t[this.index+1];return void 0===s&&(s=i),Math.abs(s-i)>180&&(s>i?s=-(360-s):i=-(360-i)),o.map(e-this.suma,0,this.segments[this.index],i,s,!0)}calcIndex(t){this.index=-1,this.suma=0;let e=0;for(;e<=t;)this.suma=e,e+=this.segments[this.index+1],this.index++}genPol(t,e,i=1,s=!1){n();let o=0,r=9999;for(let t of this.segments)t*=i,0!==t&&(o=Math.max(o,t),r=Math.min(r,t));let a=g.spacing(),h=[],l=(o+r)*(s?.03:P.isAnimated?.25:P.b),c=new p(t,e),d=Math.round(this.length/a);for(let t=0;t0){i.origin=t[0];let s=0;for(let n=0;n0&&n1?1:e}const P={isActive:!1,isAnimated:!1,b:.07,t:0,o:80,fill(t){this.v=t.a.map((t=>createVector(t[0],t[1])));const e=this.v.length*o.random(.4);P.m=this.v.map(((t,i)=>{let s=o.random(.8,1.2)*this.b;return i=.2?Math.floor(t*this.v.length):this.v.length;const o=t=>t+.1*(randomGaussian(.5,.1)-.5),r="radians"===angleMode()?Math.PI/180:1;for(let a=0;as?o.random(-1,1):0;n.addSegment(0+a(),r+a(),1,!0),n.addSegment(-90+a(),r+a(),1,!0),n.addSegment(-180+a(),r+a(),1,!0),n.addSegment(-270+a(),r+a(),1,!0);let h=s?o.randInt(-5,5):0;if(s&&n.addSegment(0,h*(Math.PI/180)*i,!0),n.endPlot(h+0,1,!0),P.isActive||w.isActive){let s=n.genPol(t-i*o.sin(0),e-i*o.cos(-0));s.fill(),s.hatch()}g.isActive&&n.draw(t-i*o.sin(0),e-i*o.cos(-0),1)},t.polygon=function(t){if(!Array.isArray(t)||t.length<3)return void console.error("Invalid input for polygon: An array with at least 3 points is required.");let e=new y(t);e.fill(),e.hatch(),e.draw()},t.spline=function(t,e=.5){A(t,e).draw()},t.beginShape=M,t.vertex=b,t.endShape=C,t.beginStroke=function(t,e,i){z=[e,i],k=new _(t)},t.segment=function(t,e,i){k.addSegment(t,e,i)},t.endStroke=function(t,e){k.endPlot(t,e),k.draw(z[0],z[1],1),k=!1},t.hatchArray=w.hatch,t.hatch=x,t.setHatch=function(t,e,i=1){w.hatchingBrush=[t,e,i]},t.noHatch=function(){w.isActive=!1,w.hatchingBrush=!1},t.Polygon=y,t.Plot=_,t.Position=p})); \ No newline at end of file +/*! p5.brush.js v1.0.1 2023 - by Alejandro Campos - MIT License */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).brush={})}(this,(function(t){"use strict";let e,i=!1;function s(t=!1){i=!0,e=t||window.self,c.load(),m.create(),f(e.width/250)}function n(){i||s()}p5.prototype.registerMethod("afterSetup",(()=>n()));const o={source:()=>random(),random(t=0,e=1){return 1===arguments.length?this.map(this.source(),0,1,0,t):this.map(this.source(),0,1,t,e)},randInt(t,e){return Math.floor(this.random(t,e))},weightedRand(t){let e,i,s=[];for(e in t)for(i=0;i<10*t[e];i++)s.push(e);return s[Math.floor(this.source()*s.length)]},map(t,e,i,s,n,o=!1){let r=s+(t-e)/(i-e)*(n-s);return o?sMath.max(Math.min(t,i),e),cos(t){return this.c[Math.floor((t%360+360)%360*4)]},sin(t){return this.s[Math.floor((t%360+360)%360*4)]},isPrecalculationDone:!1,preCalculation(){if(this.isPrecalculationDone)return;const t=1440,e=2*Math.PI/t;this.c=new Float64Array(t),this.s=new Float64Array(t);for(let i=0;i1))&&{x:o+x*p,y:r+x*f}}function l(t,e,i,s){return(Math.atan2(-(s-e),i-t)*(180/Math.PI)%360+360)%360}const c={loaded:!1,isBlending:!1,isCaching:!0,currentColor:new Float32Array(3),load(){this.mask=createGraphics(e.width,e.height),this.mask.pixelDensity(e.pixelDensity()),this.mask.clear(),this.mask.noSmooth(),this.mask.angleMode(DEGREES),t.mask=this.mask,c.loaded||(this.frag=this.frag.replace('#include "spectral.glsl"',this.glsl())),this.shader=e.createShader(this.vert,this.frag),c.loaded=!0,this.noBlend=createGraphics(e.width,e.height),this.noBlend.pixelDensity(e.pixelDensity()),this.noBlend.noSmooth(),this.noBlend.clear(),this.noBlend.angleMode(DEGREES),this.mask2=createGraphics(e.width,e.height,WEBGL),this.mask2.pixelDensity(e.pixelDensity()),this.mask2.clear(),this.mask2.angleMode(DEGREES)},getPigment(t){let e=t.levels,i=new Float32Array(3);return i[0]=e[0]/255,i[1]=e[1]/255,i[2]=e[2]/255,i},color1:new Float32Array(3),color2:new Float32Array(3),blending1:!1,blending2:!1,blend(t=!1,i=!1,s=!1,n=!1){if(this.isBlending=s?this.blending1:this.blending2,this.currentColor=s?this.color1:this.color2,!this.isBlending){if(!t)return e.push(),e.translate(-a()[0],-a()[1]),e.image(this.noBlend,-e.width/2,-e.height/2),this.noBlend.clear(),void e.pop();this.currentColor=this.getPigment(t),s?(this.blending1=!0,this.color1=this.currentColor):(this.blending2=!0,this.color2=this.currentColor)}if((t?this.getPigment(t):this.currentColor).toString()!==this.currentColor.toString()||i||!this.isCaching){e.push(),e.translate(-a()[0],-a()[1]),e.image(this.noBlend,-e.width/2,-e.height/2),this.noBlend.clear(),e.shader(this.shader),this.shader.setUniform("addColor",this.currentColor),this.shader.setUniform("source",e._renderer),this.shader.setUniform("active",n),this.shader.setUniform("random",[o.random(),o.random(),o.random()]);let r=s?this.mask2:this.mask;this.shader.setUniform("mask",r),e.fill(0,0,0,0),e.noStroke(),e.rect(-e.width/2,-e.height/2,e.width,e.height),e.pop(),r.clear(),i||(this.currentColor=this.getPigment(t),s?this.color1=this.currentColor:this.color2=this.currentColor)}i&&(this.isBlending=!1,s?this.blending1=this.isBlending:this.blending2=this.isBlending)},vert:"precision highp float;attribute vec3 aPosition;attribute vec2 aTexCoord;uniform mat4 uModelViewMatrix,uProjectionMatrix;varying vec2 vVertTexCoord;void main(){gl_Position=uProjectionMatrix*uModelViewMatrix*vec4(aPosition,1);vVertTexCoord=aTexCoord;}",frag:'precision highp float;varying vec2 vVertTexCoord;uniform sampler2D source,mask;uniform vec4 addColor;uniform vec3 random;uniform bool active;\n #include "spectral.glsl"\n float v(vec2 v,vec2 x,float y,out vec2 i){vec2 d=vec2(v.x+v.y*.5,v.y),m=floor(d),f=fract(d);float a=step(f.y,f.x);vec2 r=vec2(a,1.-a),l=m+r,e=m+1.,z=vec2(m.x-m.y*.5,m.y),k=vec2(z.x+r.x-r.y*.5,z.y+r.y),o=vec2(z.x+.5,z.y+1.),s=v-z,g=v-k,t=v-o;vec3 u,c,C,D;if(any(greaterThan(x,vec2(0)))){C=vec3(z.x,k.x,o);D=vec3(z.y,k.y,o.y);if(x.x>0.)C=mod(vec3(z.x,k.x,o),x.x);if(x.y>0.)D=mod(vec3(z.y,k.y,o.y),x.y);u=floor(C+.5*D+.5);c=floor(D+.5);}else u=vec3(m.x,l.x,e),c=vec3(m.y,l.y,e.y);vec3 b=mod(u,289.);b=mod((b*51.+2.)*b+c,289.);b=mod((b*34.+10.)*b,289.);vec3 h=b*.07482+y,E=cos(h),w=sin(h);vec2 A=vec2(E.x,w),B=vec2(E.y,w.y),F=vec2(E.z,w.z);vec3 G=.8-vec3(dot(s,s),dot(g,g),dot(t,t));G=max(G,0.);vec3 H=G*G,I=H*H,J=vec3(dot(A,s),dot(B,g),dot(F,t)),K=H*G,L=-8.*K*J;i=10.9*(I.x*A+L.x*s+(I.y*B+L.y*g)+(I.z*F+L.z*t));return 10.9*dot(I,J);}vec4 v(vec3 v,float f){return vec4(mix(v,vec3(dot(vec3(.299,.587,.114),v)),f),1);}float f(vec2 v,float x,float y,float d){return fract(sin(dot(v,vec2(x,y)))*d);}void main(){vec4 m=texture2D(mask,vVertTexCoord);if(m.x>0.){vec2 z=vec2(12.9898,78.233),k=vec2(7.9898,58.233),o=vec2(17.9898,3.233);float x=f(vVertTexCoord,z.x,z.y,43358.5453)*2.-1.,y=f(vVertTexCoord,k.x,k.y,43213.5453)*2.-1.,d=f(vVertTexCoord,o.x,o.y,33358.5453)*2.-1.;const vec2 s=vec2(0);vec2 t;vec3 u;if(active){float a=v(vVertTexCoord*10.,s,10.*random.x,t),c=v(vVertTexCoord*10.,s,10.*random.y,t),g=v(vVertTexCoord*10.,s,10.*random.z,t),w=.25+.25*v(vVertTexCoord*8.,s,3.*random.x,t);u=v(addColor.xyz,w).xyz+vec3(a,c,g)*.03;}else u=addColor.xyz;vec3 a=spectral_mix(texture2D(source,vVertTexCoord).xyz,u,m.w);if(m.w>.8)a=spectral_mix(a,vec3(0),(m.w-.8)*.4);gl_FragColor=vec4(a+.01*vec3(x,y,d),1);}}',glsl:()=>"float spectral_uncompand(float s){return s<.04045?s/12.92:pow((s+.055)/1.055,2.4);}float spectral_compand(float s){return s<.0031308?s*12.92:1.055*pow(s,1./2.4)-.055;}vec3 spectral_srgb_to_linear(vec3 s){return vec3(spectral_uncompand(s[0]),spectral_uncompand(s[1]),spectral_uncompand(s[2]));}vec3 spectral_linear_to_srgb(vec3 s){return clamp(vec3(spectral_compand(s[0]),spectral_compand(s[1]),spectral_compand(s[2])),0.,1.);}void spectral_upsampling(vec3 e,out float m,out float s,out float f,out float r,out float x,out float v,out float z){m=min(e.x,min(e.y,e.z));e-=m;s=min(e.y,e.z);f=min(e.x,e.z);r=min(e.x,e.y);x=min(max(0.,e.x-e.z),max(0.,e.x-e.y));v=min(max(0.,e.y-e.z),max(0.,e.y-e.x));z=min(max(0.,e.z-e.y),max(0.,e.z-e.x));}void spectral_linear_to_reflectance(vec3 s,inout float f[38]){float e,o,m,x,v,w,z;spectral_upsampling(s,e,o,m,x,v,w,z);f[0]=max(1e-4,e+o*.96853629+m*.51567122+x*.02055257+v*.03147571+w*.49108579+z*.97901834);f[1]=max(1e-4,e+o*.96855103+m*.5401552+x*.02059936+v*.03146636+w*.46944057+z*.97901649);f[2]=max(1e-4,e+o*.96859338+m*.62645502+x*.02062723+v*.03140624+w*.4016578+z*.97901118);f[3]=max(1e-4,e+o*.96877345+m*.75595012+x*.02073387+v*.03119611+w*.2449042+z*.97892146);f[4]=max(1e-4,e+o*.96942204+m*.92826996+x*.02114202+v*.03053888+w*.0682688+z*.97858555);f[5]=max(1e-4,e+o*.97143709+m*.97223624+x*.02233154+v*.02856855+w*.02732883+z*.97743705);f[6]=max(1e-4,e+o*.97541862+m*.98616174+x*.02556857+v*.02459485+w*.013606+z*.97428075);f[7]=max(1e-4,e+o*.98074186+m*.98955255+x*.03330189+v*.0192952+w*.01000187+z*.96663223);f[8]=max(1e-4,e+o*.98580992+m*.98676237+x*.05185294+v*.01423112+w*.01284127+z*.94822893);f[9]=max(1e-4,e+o*.98971194+m*.97312575+x*.10087639+v*.01033111+w*.02636635+z*.89937713);f[10]=max(1e-4,e+o*.99238027+m*.91944277+x*.24000413+v*.00765876+w*.07058713+z*.76070164);f[11]=max(1e-4,e+o*.99409844+m*.32564851+x*.53589066+v*.00593693+w*.70421692+z*.4642044);f[12]=max(1e-4,e+o*.995172+m*.13820628+x*.79874659+v*.00485616+w*.85473994+z*.20123039);f[13]=max(1e-4,e+o*.99576545+m*.05015143+x*.91186529+v*.00426186+w*.95081565+z*.08808402);f[14]=max(1e-4,e+o*.99593552+m*.02912336+x*.95399623+v*.00409039+w*.9717037+z*.04592894);f[15]=max(1e-4,e+o*.99564041+m*.02421691+x*.97137099+v*.00438375+w*.97651888+z*.02860373);f[16]=max(1e-4,e+o*.99464769+m*.02660696+x*.97939505+v*.00537525+w*.97429245+z*.02060067);f[17]=max(1e-4,e+o*.99229579+m*.03407586+x*.98345207+v*.00772962+w*.97012917+z*.01656701);f[18]=max(1e-4,e+o*.98638762+m*.04835936+x*.98553736+v*.0136612+w*.9425863+z*.01451549);f[19]=max(1e-4,e+o*.96829712+m*.0001172+x*.98648905+v*.03181352+w*.99989207+z*.01357964);f[20]=max(1e-4,e+o*.89228016+m*8.554e-5+x*.98674535+v*.10791525+w*.99989891+z*.01331243);f[21]=max(1e-4,e+o*.53740239+m*.85267882+x*.98657555+v*.46249516+w*.13823139+z*.01347661);f[22]=max(1e-4,e+o*.15360445+m*.93188793+x*.98611877+v*.84604333+w*.06968113+z*.01387181);f[23]=max(1e-4,e+o*.05705719+m*.94810268+x*.98559942+v*.94275572+w*.05628787+z*.01435472);f[24]=max(1e-4,e+o*.03126539+m*.94200977+x*.98507063+v*.96860996+w*.06111561+z*.01479836);f[25]=max(1e-4,e+o*.02205445+m*.91478045+x*.98460039+v*.97783966+w*.08987709+z*.0151525);f[26]=max(1e-4,e+o*.01802271+m*.87065445+x*.98425301+v*.98187757+w*.13656016+z*.01540513);f[27]=max(1e-4,e+o*.0161346+m*.78827548+x*.98403909+v*.98377315+w*.22169624+z*.01557233);f[28]=max(1e-4,e+o*.01520947+m*.65738359+x*.98388535+v*.98470202+w*.32176956+z*.0156571);f[29]=max(1e-4,e+o*.01475977+m*.59909403+x*.98376116+v*.98515481+w*.36157329+z*.01571025);f[30]=max(1e-4,e+o*.01454263+m*.56817268+x*.98368246+v*.98537114+w*.4836192+z*.01571916);f[31]=max(1e-4,e+o*.01444459+m*.54031997+x*.98365023+v*.98546685+w*.46488579+z*.01572133);f[32]=max(1e-4,e+o*.01439897+m*.52110241+x*.98361309+v*.98550011+w*.47440306+z*.01572502);f[33]=max(1e-4,e+o*.0143762+m*.51041094+x*.98357259+v*.98551031+w*.4857699+z*.01571717);f[34]=max(1e-4,e+o*.01436343+m*.50526577+x*.98353856+v*.98550741+w*.49267971+z*.01571905);f[35]=max(1e-4,e+o*.01435687+m*.5025508+x*.98351247+v*.98551323+w*.49625685+z*.01571059);f[36]=max(1e-4,e+o*.0143537+m*.50126452+x*.98350101+v*.98551563+w*.49807754+z*.01569728);f[37]=max(1e-4,e+o*.01435408+m*.50083021+x*.98350852+v*.98551547+w*.49889859+z*.0157002);}vec3 spectral_xyz_to_srgb(vec3 e){mat3 f;f[0]=vec3(3.24306333,-1.53837619,-.49893282);f[1]=vec3(-.96896309,1.87542451,.04154303);f[2]=vec3(.05568392,-.20417438,1.05799454);float s=dot(f[0],e),m=dot(f[1],e),z=dot(f[2],e);return spectral_linear_to_srgb(vec3(s,m,z));}vec3 spectral_reflectance_to_xyz(float f[38]){vec3 e=vec3(0);e+=f[0]*vec3(6.469e-5,1.84e-6,.00030502);e+=f[1]*vec3(.00021941,6.21e-6,.00103681);e+=f[2]*vec3(.00112057,3.101e-5,.00531314);e+=f[3]*vec3(.00376661,.00010475,.01795439);e+=f[4]*vec3(.01188055,.00035364,.05707758);e+=f[5]*vec3(.02328644,.00095147,.11365162);e+=f[6]*vec3(.03455942,.00228226,.17335873);e+=f[7]*vec3(.03722379,.00420733,.19620658);e+=f[8]*vec3(.03241838,.0066888,.18608237);e+=f[9]*vec3(.02123321,.0098884,.13995048);e+=f[10]*vec3(.01049099,.01524945,.08917453);e+=f[11]*vec3(.00329584,.02141831,.04789621);e+=f[12]*vec3(.00050704,.03342293,.02814563);e+=f[13]*vec3(.00094867,.05131001,.01613766);e+=f[14]*vec3(.00627372,.07040208,.0077591);e+=f[15]*vec3(.01686462,.08783871,.00429615);e+=f[16]*vec3(.02868965,.09424905,.00200551);e+=f[17]*vec3(.04267481,.09795667,.00086147);e+=f[18]*vec3(.05625475,.09415219,.00036904);e+=f[19]*vec3(.0694704,.08678102,.00019143);e+=f[20]*vec3(.08305315,.07885653,.00014956);e+=f[21]*vec3(.0861261,.0635267,9.231e-5);e+=f[22]*vec3(.09046614,.05374142,6.813e-5);e+=f[23]*vec3(.08500387,.04264606,2.883e-5);e+=f[24]*vec3(.07090667,.03161735,1.577e-5);e+=f[25]*vec3(.05062889,.02088521,3.94e-6);e+=f[26]*vec3(.03547396,.01386011,1.58e-6);e+=f[27]*vec3(.02146821,.00810264,0);e+=f[28]*vec3(.01251646,.0046301,0);e+=f[29]*vec3(.00680458,.00249138,0);e+=f[30]*vec3(.00346457,.0012593,0);e+=f[31]*vec3(.00149761,.00054165,0);e+=f[32]*vec3(.0007697,.00027795,0);e+=f[33]*vec3(.00040737,.00014711,0);e+=f[34]*vec3(.00016901,6.103e-5,0);e+=f[35]*vec3(9.522e-5,3.439e-5,0);e+=f[36]*vec3(4.903e-5,1.771e-5,0);e+=f[37]*vec3(2e-5,7.22e-6,0);return e;}float spectral_linear_to_concentration(float v,float m,float s){float z=m*pow(s,2.);return z/(v*pow(1.-s,2.)+z);}vec3 spectral_mix(vec3 s,vec3 f,float e){vec3 v=spectral_srgb_to_linear(s),m=spectral_srgb_to_linear(f);float z[38],o[38];spectral_linear_to_reflectance(v,z);spectral_linear_to_reflectance(m,o);float x=spectral_reflectance_to_xyz(z)[1],w=spectral_reflectance_to_xyz(o)[1];e=spectral_linear_to_concentration(x,w,e);float r[38];for(int c=0;c<38;c++){float y=(1.-e)*(pow(1.-z[c],2.)/(2.*z[c]))+e*(pow(1.-o[c],2.)/(2.*o[c]));r[c]=1.+y-sqrt(pow(y,2.)+2.*y);}return spectral_xyz_to_srgb(spectral_reflectance_to_xyz(r));}vec4 spectral_mix(vec4 s,vec4 e,float z){return vec4(spectral_mix(s.xyz,e.xyz,z),mix(s.w,e.w,z));}"};function d(t,e){n(),m.list.set(t,{gen:e}),m.current=t,m.refresh()}p5.prototype.registerMethod("afterSetup",(()=>c.blend(!1,!0))),p5.prototype.registerMethod("afterSetup",(()=>c.blend(!1,!0,!0))),p5.prototype.registerMethod("post",(()=>c.blend(!1,!0))),p5.prototype.registerMethod("post",(()=>c.blend(!1,!0,!0)));const m={isActive:!1,list:new Map,current:"",step_length:()=>Math.min(e.width,e.height)/1e3,create(){this.R=.01*e.width,this.left_x=-1*e.width,this.top_y=-1*e.height,this.num_columns=Math.round(2*e.width/this.R),this.num_rows=Math.round(2*e.height/this.R),this.addStandard()},flow_field(){return this.list.get(this.current).field},refresh(t=0){this.list.get(this.current).field=this.list.get(this.current).gen(t)},genField(){let t=new Array(m.num_columns);for(let e=0;e=0&&this.row_index>=0&&this.column_index=-t-a()[0]&&this.x<=t-a()[0]&&this.y>=-i-a()[1]&&this.y<=i-a()[1]}angle(){return this.isIn()&&m.isActive?m.flow_field()[this.column_index][this.row_index]:0}moveTo(t,e,i=m.step_length(),s=!0){if(this.isIn()){let n,r;s||(n=o.cos(-e),r=o.sin(-e));for(let a=0;a{const i="marker"===e.type||"custom"===e.type||"image"===e.type;"image"===e.type&&(v.add(e.image.src),e.tip=()=>g.mask.image(v.tips.get(g.p.image.src),-g.p.weight/2,-g.p.weight/2,g.p.weight,g.p.weight)),e.blend=!!(i&&!1!==e.blend||e.blend),g.list.set(t,{param:e,colors:[],buffers:[]})},set(t,e,i=1){g.name=t,g.c=e,g.w=i,g.isActive=!0},setBrush(t){g.name=t},setColor(t,e,i){arguments.length>0&&(g.c=arguments.length<2?t:[t,e,i]),g.isActive=!0},setWeight(t){g.w=t},clip(t){g.cr=t},noClip(){g.cr=null},line(t,e,i,s){n();let o=dist(t,e,i,s);if(0==o)return;g.initializeDrawingState(t,e,o,!1,!1);let r=l(t,e,i,s);g.draw(r,!1)},flowLine(t,e,i,s){n(),"radians"===angleMode()&&(s=180*s/Math.PI),g.initializeDrawingState(t,e,i,!0,!1),g.draw(s,!1)},flowShape(t,e,i,s){n(),g.initializeDrawingState(e,i,t.length,!0,t),g.draw(s,!0)},spacing(){return this.p=this.list.get(this.name).param,this.p.spacing*this.w},initializeDrawingState(t,e,i,s,n){this.position=new p(t,e),this.length=i,this.flow=s,this.plot=n,n&&n.calcIndex(0)},draw(t,e){e||(this.dir=t),this.pushState();const i=this.spacing(),s=e?Math.round(this.length*t/i):Math.round(this.length/i);for(let n=0;n=g.cr[0]&&this.position.x<=g.cr[2]&&this.position.y>=g.cr[1]&&this.position.y<=g.cr[3]},drawSpray(t){let e=this.w*this.p.vibration*t+this.w*randomGaussian()*this.p.vibration/3,i=this.p.weight*o.random(.9,1.1);const s=this.p.quality/t;for(let t=0;t.4&&this.mask.circle(this.position.x+.7*e*o.random(-1,1),this.position.y+e*o.random(-1,1),t*this.p.weight*this.w*o.random(.85,1.15))},adjustSizeAndRotation(t,e){if(this.mask.scale(t),"image"===this.p.type&&(this.p.blend?this.mask.tint(255,0,0,e/2):this.mask.tint(this.mask.red(this.c),this.mask.green(this.c),this.mask.blue(this.c),e)),"random"===this.p.rotate)this.mask.rotate(o.randInt(0,360));else if("natural"===this.p.rotate){let t=(this.plot?-this.plot.angle(this.position.plotted):-this.dir)+(this.flow?this.position.angle():0);t=this.plot?-this.plot.angle(this.position.plotted):-this.dir,this.mask.rotate(t)}},markerTip(){if(this.isInsideClippingArea()){let t=this.calculatePressure(),e=this.calculateAlpha(t);if(this.mask.fill(255,0,0,e/1.5),"marker"===g.p.type)for(let e=1;e<5;e++)this.drawMarker(t*e/5,!1);else if("custom"===g.p.type||"image"===g.p.type)for(let i=1;i<5;i++)this.drawCustomOrImage(t*i/5,e,!1)}}};const v={tips:new Map,add(t){const e=new Image;this.tips.set(t,!1),e.onload=function(){v.tips.set(t,v.imageToWhite(e))},e.src=t},imageToWhite(t){let e=document.createElement("canvas");e.width=t.width,e.height=t.height;let i=e.getContext("2d");i.drawImage(t,0,0);let s=i.getImageData(0,0,t.width,t.height);for(let e=0;e<4*t.width*t.height;e+=4){let t=(s.data[e]+s.data[e+1]+s.data[e+2])/3;s.data[e]=s.data[e+1]=s.data[e+2]=255,s.data[e+3]=255-t}return i.putImageData(s,0,0),e.toDataURL()},load(){if(0===this.tips.size)return console.log("ojo");for(let t of this.tips.keys())this.tips.set(t,loadImage(this.tips.get(t)))}};function x(t=5,e=45,i={rand:!1,continuous:!1,gradient:!1}){w.isActive=!0,w.hatchingParams=[t,e,i]}const w={isActive:!1,hatchingParams:[5,45,{}],hatchingBrush:!1,hatch(t){let e=w.hatchingParams[0],i=w.hatchingParams[1],s=w.hatchingParams[2],n=g.c,r=g.name,a=g.w,h=g.isActive;w.hatchingBrush&&g.set(w.hatchingBrush[0],w.hatchingBrush[1],w.hatchingBrush[2]),i=(("radians"===angleMode()?180*i/Math.PI:i)+1080)%180;let l=1/0,c=-1/0,d=1/0,m=-1/0,p=t=>{for(let e of t.a)l=e[0]c?e[0]:c,d=e[1]m?e[1]:m};Array.isArray(t)||(t=[t]);for(let e of t)p(e);let f=new y([[l,d],[c,d],[c,m],[l,m]]),u=i<=90&&i>=0?d:m,v=s.gradient?map(s.gradient,0,1,1,1.1,!0):1,x=[],_=0,z=e,k=t=>({point1:{x:l+z*t*o.cos(90-i),y:u+z*t*o.sin(90-i)},point2:{x:l+z*t*o.cos(90-i)+o.cos(-i),y:u+z*t*o.sin(90-i)+o.sin(-i)}});for(;f.intersect(k(_)).length>0;){let e=[];for(let i of t)e.push(i.intersect(k(_)));x[_]=e.flat().sort(((t,e)=>t.x===e.x?t.y-e.y:t.x-e.x)),z*=v,_++}let M=[];for(let t of x)void 0!==t[0]&&M.push(t);for(let t=0;t0&&s.continuous;for(let s=0;s({x:t[0],y:t[1]}))),this.sides=this.vertices.map(((t,e,i)=>[t,i[(e+1)%i.length]]))}intersect(t){let e=`${t.point1.x},${t.point1.y}-${t.point2.x},${t.point2.y}`;if(this._intersectionCache&&this._intersectionCache[e])return this._intersectionCache[e];let i=[];for(let e of this.sides){let s=h(t.point1,t.point2,e[0],e[1]);!1!==s&&i.push(s)}return this._intersectionCache||(this._intersectionCache={}),this._intersectionCache[e]=i,i}draw(t=!1,e,i){let s=g.isActive;if(t&&g.set(t,e,i),g.isActive){n();for(let t of this.sides)g.line(t[0].x,t[0].y,t[1].x,t[1].y)}g.isActive=s}fill(t=!1,e,i,s){let o=P.isActive;t&&(S(t,e),I(i,s)),P.isActive&&(n(),P.fill(this)),P.isActive=o}hatch(t=!1,e,i){let s=w.isActive;t&&x(t,e,i),w.isActive&&(n(),w.hatch(this)),w.isActive=s}}class _{constructor(t){this.segments=[],this.angles=[],this.pres=[],this.type=t,this.dir=0,this.calcIndex(0),this.pol=!1}addSegment(t=0,e=0,i=1,s=!1){"radians"!==angleMode()||s||(t=180*t/Math.PI),this.angles.length>0&&this.angles.splice(-1),t=(t+360)%360,this.angles.push(t),this.pres.push(i),this.segments.push(e),this.length=this.segments.reduce(((t,e)=>t+e),0),this.angles.push(t)}endPlot(t=0,e=1,i=!1){"radians"!==angleMode()||i||(t=180*t/Math.PI),this.angles.splice(-1),this.angles.push(t),this.pres.push(e)}rotate(t){"radians"===angleMode()&&(t=180*t/Math.PI),this.dir=t}pressure(t){return t>this.length?this.pres[this.pres.length-1]:this.curving(this.pres,t)}angle(t){return t>this.length?this.angles[this.angles.length-1]:(this.calcIndex(t),"curve"===this.type?this.curving(this.angles,t)+this.dir:this.angles[this.index]+this.dir)}curving(t,e){let i=t[this.index],s=t[this.index+1];return void 0===s&&(s=i),Math.abs(s-i)>180&&(s>i?s=-(360-s):i=-(360-i)),o.map(e-this.suma,0,this.segments[this.index],i,s,!0)}calcIndex(t){this.index=-1,this.suma=0;let e=0;for(;e<=t;)this.suma=e,e+=this.segments[this.index+1],this.index++}genPol(t,e,i=1,s=!1){n();let o=0,r=9999;for(let t of this.segments)t*=i,0!==t&&(o=Math.max(o,t),r=Math.min(r,t));let a=g.spacing(),h=[],l=(o+r)*(s?.03:P.isAnimated?.25:P.b),c=new p(t,e),d=Math.round(this.length/a);for(let t=0;t0){i.origin=t[0];let s=0;for(let n=0;n0&&n1?1:e,P.border_strength=1+i>1?1:i}const P={isActive:!1,isAnimated:!1,b:.07,t:0,o:80,border_strength:1,fill(t){this.v=t.a.map((t=>createVector(t[0],t[1])));const e=this.v.length*o.random(.4);P.m=this.v.map(((t,i)=>{let s=o.random(.8,1.2)*this.b;return i=.2?Math.floor(t*this.v.length):this.v.length;const o=t=>t+.1*(randomGaussian(.5,.1)-.5),r="radians"===angleMode()?Math.PI/180:1;for(let a=0;as?o.random(-1,1):0;n.addSegment(0+a(),r+a(),1,!0),n.addSegment(-90+a(),r+a(),1,!0),n.addSegment(-180+a(),r+a(),1,!0),n.addSegment(-270+a(),r+a(),1,!0);let h=s?o.randInt(-5,5):0;if(s&&n.addSegment(0,h*(Math.PI/180)*i,!0),n.endPlot(h+0,1,!0),P.isActive||w.isActive){let s=n.genPol(t-i*o.sin(0),e-i*o.cos(-0));s.fill(),s.hatch()}g.isActive&&n.draw(t-i*o.sin(0),e-i*o.cos(-0),1)},t.polygon=function(t){if(!Array.isArray(t)||t.length<3)return void console.error("Invalid input for polygon: An array with at least 3 points is required.");let e=new y(t);e.fill(),e.hatch(),e.draw()},t.spline=function(t,e=.5){A(t,e).draw()},t.beginShape=M,t.vertex=b,t.endShape=C,t.beginStroke=function(t,e,i){z=[e,i],k=new _(t)},t.segment=function(t,e,i){k.addSegment(t,e,i)},t.endStroke=function(t,e){k.endPlot(t,e),k.draw(z[0],z[1],1),k=!1},t.hatchArray=w.hatch,t.hatch=x,t.setHatch=function(t,e,i=1){w.hatchingBrush=[t,e,i]},t.noHatch=function(){w.isActive=!1,w.hatchingBrush=!1},t.Polygon=y,t.Plot=_,t.Position=p})); \ No newline at end of file From ef2e0f57251b324698ee7eef961ff04e3678d1b1 Mon Sep 17 00:00:00 2001 From: Alejandro Date: Tue, 14 Nov 2023 11:15:05 +0100 Subject: [PATCH 2/5] loadImage for custom tips now uses p5 function --- index.html | 3 ++- p5.brush.js | 40 +++++++++++----------------------------- p5.brush.min.js | 2 +- sketch.js | 1 - 4 files changed, 14 insertions(+), 32 deletions(-) diff --git a/index.html b/index.html index afd75b4..68675de 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,8 @@ p5.brush.js Example - + + diff --git a/p5.brush.js b/p5.brush.js index 1412400..1f08093 100644 --- a/p5.brush.js +++ b/p5.brush.js @@ -1023,7 +1023,9 @@ const isBlendableType = b.type === "marker" || b.type === "custom" || b.type === "image"; if (b.type === "image") { T.add(b.image.src); - b.tip = () => B.mask.image(T.tips.get(B.p.image.src), -B.p.weight / 2, -B.p.weight / 2, B.p.weight, B.p.weight); + b.tip = () => { + B.mask.image(T.tips.get(B.p.image.src), -B.p.weight / 2, -B.p.weight / 2, B.p.weight, B.p.weight); + } } b.blend = ((isBlendableType && b.blend !== false) || b.blend) ? true : false; B.list.set(a, { param: b, colors: [], buffers: [] }); @@ -1453,61 +1455,41 @@ * @param {string} src - The source URL of the image to be added and processed. */ add (src) { - // Create a new Image object - const myImage = new Image(); // Initially set the source as not processed this.tips.set(src,false) - // Define the onload handler for the image - myImage.onload = function(){ - // Once the image is loaded, convert it to white and update the Map - T.tips.set(src,(T.imageToWhite(myImage))) - }; - // Set the source of the Image object, which begins the loading process - myImage.src = src; }, /** * Converts the given image to a white tint by setting all color channels to white and adjusting the alpha channel. * * @param {Image} image - The image to be converted. - * @returns {string} - The data URL of the converted canvas image. */ imageToWhite (image) { - // Create a canvas element to manipulate the image - let canvas = document.createElement("canvas"); - canvas.width = image.width, canvas.height = image.height; - let context = canvas.getContext("2d"); - // Draw the image onto the canvas - context.drawImage(image,0,0); - // Get the image data from the canvas - let imageData=context.getImageData(0,0, image.width, image.height); + image.loadPixels() // Modify the image data to create a white tint effect for (let i = 0; i < 4 * image.width * image.height; i += 4) { // Calculate the average for the grayscale value - let average = (imageData.data[i] + imageData.data[i + 1] + imageData.data[i + 2]) / 3; + let average = (image.pixels[i] + image.pixels[i + 1] + image.pixels[i + 2]) / 3; // Set all color channels to white - imageData.data[i] = imageData.data[i + 1] = imageData.data[i + 2] = 255; + image.pixels[i] = image.pixels[i + 1] = image.pixels[i + 2] = 255; // Adjust the alpha channel to the inverse of the average, creating the white tint effect - imageData.data[i + 3] = 255 - average; + image.pixels[i + 3] = 255 - average; } - // Put the modified image data back onto the canvas - context.putImageData(imageData,0,0); - // Return a data URL representing the canvas image - return canvas.toDataURL(); + image.updatePixels() }, /** * Loads all processed images into the p5.js environment. * If no images are in the tips Map, logs a warning message. */ load() { - if (this.tips.size === 0) return console.log("ojo"); + if (this.tips.size === 0) return console.log("There are no custom tips to load !"); for (let key of this.tips.keys()){ - this.tips.set(key,loadImage(this.tips.get(key))) + let image = loadImage(key, () => T.imageToWhite(image)) + this.tips.set(key, image) } } } - // ============================================================================= // Section: Hatching // ============================================================================= diff --git a/p5.brush.min.js b/p5.brush.min.js index d265f9c..b3bb898 100644 --- a/p5.brush.min.js +++ b/p5.brush.min.js @@ -1,2 +1,2 @@ /*! p5.brush.js v1.0.1 2023 - by Alejandro Campos - MIT License */ -!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).brush={})}(this,(function(t){"use strict";let e,i=!1;function s(t=!1){i=!0,e=t||window.self,c.load(),m.create(),f(e.width/250)}function n(){i||s()}p5.prototype.registerMethod("afterSetup",(()=>n()));const o={source:()=>random(),random(t=0,e=1){return 1===arguments.length?this.map(this.source(),0,1,0,t):this.map(this.source(),0,1,t,e)},randInt(t,e){return Math.floor(this.random(t,e))},weightedRand(t){let e,i,s=[];for(e in t)for(i=0;i<10*t[e];i++)s.push(e);return s[Math.floor(this.source()*s.length)]},map(t,e,i,s,n,o=!1){let r=s+(t-e)/(i-e)*(n-s);return o?sMath.max(Math.min(t,i),e),cos(t){return this.c[Math.floor((t%360+360)%360*4)]},sin(t){return this.s[Math.floor((t%360+360)%360*4)]},isPrecalculationDone:!1,preCalculation(){if(this.isPrecalculationDone)return;const t=1440,e=2*Math.PI/t;this.c=new Float64Array(t),this.s=new Float64Array(t);for(let i=0;i1))&&{x:o+x*p,y:r+x*f}}function l(t,e,i,s){return(Math.atan2(-(s-e),i-t)*(180/Math.PI)%360+360)%360}const c={loaded:!1,isBlending:!1,isCaching:!0,currentColor:new Float32Array(3),load(){this.mask=createGraphics(e.width,e.height),this.mask.pixelDensity(e.pixelDensity()),this.mask.clear(),this.mask.noSmooth(),this.mask.angleMode(DEGREES),t.mask=this.mask,c.loaded||(this.frag=this.frag.replace('#include "spectral.glsl"',this.glsl())),this.shader=e.createShader(this.vert,this.frag),c.loaded=!0,this.noBlend=createGraphics(e.width,e.height),this.noBlend.pixelDensity(e.pixelDensity()),this.noBlend.noSmooth(),this.noBlend.clear(),this.noBlend.angleMode(DEGREES),this.mask2=createGraphics(e.width,e.height,WEBGL),this.mask2.pixelDensity(e.pixelDensity()),this.mask2.clear(),this.mask2.angleMode(DEGREES)},getPigment(t){let e=t.levels,i=new Float32Array(3);return i[0]=e[0]/255,i[1]=e[1]/255,i[2]=e[2]/255,i},color1:new Float32Array(3),color2:new Float32Array(3),blending1:!1,blending2:!1,blend(t=!1,i=!1,s=!1,n=!1){if(this.isBlending=s?this.blending1:this.blending2,this.currentColor=s?this.color1:this.color2,!this.isBlending){if(!t)return e.push(),e.translate(-a()[0],-a()[1]),e.image(this.noBlend,-e.width/2,-e.height/2),this.noBlend.clear(),void e.pop();this.currentColor=this.getPigment(t),s?(this.blending1=!0,this.color1=this.currentColor):(this.blending2=!0,this.color2=this.currentColor)}if((t?this.getPigment(t):this.currentColor).toString()!==this.currentColor.toString()||i||!this.isCaching){e.push(),e.translate(-a()[0],-a()[1]),e.image(this.noBlend,-e.width/2,-e.height/2),this.noBlend.clear(),e.shader(this.shader),this.shader.setUniform("addColor",this.currentColor),this.shader.setUniform("source",e._renderer),this.shader.setUniform("active",n),this.shader.setUniform("random",[o.random(),o.random(),o.random()]);let r=s?this.mask2:this.mask;this.shader.setUniform("mask",r),e.fill(0,0,0,0),e.noStroke(),e.rect(-e.width/2,-e.height/2,e.width,e.height),e.pop(),r.clear(),i||(this.currentColor=this.getPigment(t),s?this.color1=this.currentColor:this.color2=this.currentColor)}i&&(this.isBlending=!1,s?this.blending1=this.isBlending:this.blending2=this.isBlending)},vert:"precision highp float;attribute vec3 aPosition;attribute vec2 aTexCoord;uniform mat4 uModelViewMatrix,uProjectionMatrix;varying vec2 vVertTexCoord;void main(){gl_Position=uProjectionMatrix*uModelViewMatrix*vec4(aPosition,1);vVertTexCoord=aTexCoord;}",frag:'precision highp float;varying vec2 vVertTexCoord;uniform sampler2D source,mask;uniform vec4 addColor;uniform vec3 random;uniform bool active;\n #include "spectral.glsl"\n float v(vec2 v,vec2 x,float y,out vec2 i){vec2 d=vec2(v.x+v.y*.5,v.y),m=floor(d),f=fract(d);float a=step(f.y,f.x);vec2 r=vec2(a,1.-a),l=m+r,e=m+1.,z=vec2(m.x-m.y*.5,m.y),k=vec2(z.x+r.x-r.y*.5,z.y+r.y),o=vec2(z.x+.5,z.y+1.),s=v-z,g=v-k,t=v-o;vec3 u,c,C,D;if(any(greaterThan(x,vec2(0)))){C=vec3(z.x,k.x,o);D=vec3(z.y,k.y,o.y);if(x.x>0.)C=mod(vec3(z.x,k.x,o),x.x);if(x.y>0.)D=mod(vec3(z.y,k.y,o.y),x.y);u=floor(C+.5*D+.5);c=floor(D+.5);}else u=vec3(m.x,l.x,e),c=vec3(m.y,l.y,e.y);vec3 b=mod(u,289.);b=mod((b*51.+2.)*b+c,289.);b=mod((b*34.+10.)*b,289.);vec3 h=b*.07482+y,E=cos(h),w=sin(h);vec2 A=vec2(E.x,w),B=vec2(E.y,w.y),F=vec2(E.z,w.z);vec3 G=.8-vec3(dot(s,s),dot(g,g),dot(t,t));G=max(G,0.);vec3 H=G*G,I=H*H,J=vec3(dot(A,s),dot(B,g),dot(F,t)),K=H*G,L=-8.*K*J;i=10.9*(I.x*A+L.x*s+(I.y*B+L.y*g)+(I.z*F+L.z*t));return 10.9*dot(I,J);}vec4 v(vec3 v,float f){return vec4(mix(v,vec3(dot(vec3(.299,.587,.114),v)),f),1);}float f(vec2 v,float x,float y,float d){return fract(sin(dot(v,vec2(x,y)))*d);}void main(){vec4 m=texture2D(mask,vVertTexCoord);if(m.x>0.){vec2 z=vec2(12.9898,78.233),k=vec2(7.9898,58.233),o=vec2(17.9898,3.233);float x=f(vVertTexCoord,z.x,z.y,43358.5453)*2.-1.,y=f(vVertTexCoord,k.x,k.y,43213.5453)*2.-1.,d=f(vVertTexCoord,o.x,o.y,33358.5453)*2.-1.;const vec2 s=vec2(0);vec2 t;vec3 u;if(active){float a=v(vVertTexCoord*10.,s,10.*random.x,t),c=v(vVertTexCoord*10.,s,10.*random.y,t),g=v(vVertTexCoord*10.,s,10.*random.z,t),w=.25+.25*v(vVertTexCoord*8.,s,3.*random.x,t);u=v(addColor.xyz,w).xyz+vec3(a,c,g)*.03;}else u=addColor.xyz;vec3 a=spectral_mix(texture2D(source,vVertTexCoord).xyz,u,m.w);if(m.w>.8)a=spectral_mix(a,vec3(0),(m.w-.8)*.4);gl_FragColor=vec4(a+.01*vec3(x,y,d),1);}}',glsl:()=>"float spectral_uncompand(float s){return s<.04045?s/12.92:pow((s+.055)/1.055,2.4);}float spectral_compand(float s){return s<.0031308?s*12.92:1.055*pow(s,1./2.4)-.055;}vec3 spectral_srgb_to_linear(vec3 s){return vec3(spectral_uncompand(s[0]),spectral_uncompand(s[1]),spectral_uncompand(s[2]));}vec3 spectral_linear_to_srgb(vec3 s){return clamp(vec3(spectral_compand(s[0]),spectral_compand(s[1]),spectral_compand(s[2])),0.,1.);}void spectral_upsampling(vec3 e,out float m,out float s,out float f,out float r,out float x,out float v,out float z){m=min(e.x,min(e.y,e.z));e-=m;s=min(e.y,e.z);f=min(e.x,e.z);r=min(e.x,e.y);x=min(max(0.,e.x-e.z),max(0.,e.x-e.y));v=min(max(0.,e.y-e.z),max(0.,e.y-e.x));z=min(max(0.,e.z-e.y),max(0.,e.z-e.x));}void spectral_linear_to_reflectance(vec3 s,inout float f[38]){float e,o,m,x,v,w,z;spectral_upsampling(s,e,o,m,x,v,w,z);f[0]=max(1e-4,e+o*.96853629+m*.51567122+x*.02055257+v*.03147571+w*.49108579+z*.97901834);f[1]=max(1e-4,e+o*.96855103+m*.5401552+x*.02059936+v*.03146636+w*.46944057+z*.97901649);f[2]=max(1e-4,e+o*.96859338+m*.62645502+x*.02062723+v*.03140624+w*.4016578+z*.97901118);f[3]=max(1e-4,e+o*.96877345+m*.75595012+x*.02073387+v*.03119611+w*.2449042+z*.97892146);f[4]=max(1e-4,e+o*.96942204+m*.92826996+x*.02114202+v*.03053888+w*.0682688+z*.97858555);f[5]=max(1e-4,e+o*.97143709+m*.97223624+x*.02233154+v*.02856855+w*.02732883+z*.97743705);f[6]=max(1e-4,e+o*.97541862+m*.98616174+x*.02556857+v*.02459485+w*.013606+z*.97428075);f[7]=max(1e-4,e+o*.98074186+m*.98955255+x*.03330189+v*.0192952+w*.01000187+z*.96663223);f[8]=max(1e-4,e+o*.98580992+m*.98676237+x*.05185294+v*.01423112+w*.01284127+z*.94822893);f[9]=max(1e-4,e+o*.98971194+m*.97312575+x*.10087639+v*.01033111+w*.02636635+z*.89937713);f[10]=max(1e-4,e+o*.99238027+m*.91944277+x*.24000413+v*.00765876+w*.07058713+z*.76070164);f[11]=max(1e-4,e+o*.99409844+m*.32564851+x*.53589066+v*.00593693+w*.70421692+z*.4642044);f[12]=max(1e-4,e+o*.995172+m*.13820628+x*.79874659+v*.00485616+w*.85473994+z*.20123039);f[13]=max(1e-4,e+o*.99576545+m*.05015143+x*.91186529+v*.00426186+w*.95081565+z*.08808402);f[14]=max(1e-4,e+o*.99593552+m*.02912336+x*.95399623+v*.00409039+w*.9717037+z*.04592894);f[15]=max(1e-4,e+o*.99564041+m*.02421691+x*.97137099+v*.00438375+w*.97651888+z*.02860373);f[16]=max(1e-4,e+o*.99464769+m*.02660696+x*.97939505+v*.00537525+w*.97429245+z*.02060067);f[17]=max(1e-4,e+o*.99229579+m*.03407586+x*.98345207+v*.00772962+w*.97012917+z*.01656701);f[18]=max(1e-4,e+o*.98638762+m*.04835936+x*.98553736+v*.0136612+w*.9425863+z*.01451549);f[19]=max(1e-4,e+o*.96829712+m*.0001172+x*.98648905+v*.03181352+w*.99989207+z*.01357964);f[20]=max(1e-4,e+o*.89228016+m*8.554e-5+x*.98674535+v*.10791525+w*.99989891+z*.01331243);f[21]=max(1e-4,e+o*.53740239+m*.85267882+x*.98657555+v*.46249516+w*.13823139+z*.01347661);f[22]=max(1e-4,e+o*.15360445+m*.93188793+x*.98611877+v*.84604333+w*.06968113+z*.01387181);f[23]=max(1e-4,e+o*.05705719+m*.94810268+x*.98559942+v*.94275572+w*.05628787+z*.01435472);f[24]=max(1e-4,e+o*.03126539+m*.94200977+x*.98507063+v*.96860996+w*.06111561+z*.01479836);f[25]=max(1e-4,e+o*.02205445+m*.91478045+x*.98460039+v*.97783966+w*.08987709+z*.0151525);f[26]=max(1e-4,e+o*.01802271+m*.87065445+x*.98425301+v*.98187757+w*.13656016+z*.01540513);f[27]=max(1e-4,e+o*.0161346+m*.78827548+x*.98403909+v*.98377315+w*.22169624+z*.01557233);f[28]=max(1e-4,e+o*.01520947+m*.65738359+x*.98388535+v*.98470202+w*.32176956+z*.0156571);f[29]=max(1e-4,e+o*.01475977+m*.59909403+x*.98376116+v*.98515481+w*.36157329+z*.01571025);f[30]=max(1e-4,e+o*.01454263+m*.56817268+x*.98368246+v*.98537114+w*.4836192+z*.01571916);f[31]=max(1e-4,e+o*.01444459+m*.54031997+x*.98365023+v*.98546685+w*.46488579+z*.01572133);f[32]=max(1e-4,e+o*.01439897+m*.52110241+x*.98361309+v*.98550011+w*.47440306+z*.01572502);f[33]=max(1e-4,e+o*.0143762+m*.51041094+x*.98357259+v*.98551031+w*.4857699+z*.01571717);f[34]=max(1e-4,e+o*.01436343+m*.50526577+x*.98353856+v*.98550741+w*.49267971+z*.01571905);f[35]=max(1e-4,e+o*.01435687+m*.5025508+x*.98351247+v*.98551323+w*.49625685+z*.01571059);f[36]=max(1e-4,e+o*.0143537+m*.50126452+x*.98350101+v*.98551563+w*.49807754+z*.01569728);f[37]=max(1e-4,e+o*.01435408+m*.50083021+x*.98350852+v*.98551547+w*.49889859+z*.0157002);}vec3 spectral_xyz_to_srgb(vec3 e){mat3 f;f[0]=vec3(3.24306333,-1.53837619,-.49893282);f[1]=vec3(-.96896309,1.87542451,.04154303);f[2]=vec3(.05568392,-.20417438,1.05799454);float s=dot(f[0],e),m=dot(f[1],e),z=dot(f[2],e);return spectral_linear_to_srgb(vec3(s,m,z));}vec3 spectral_reflectance_to_xyz(float f[38]){vec3 e=vec3(0);e+=f[0]*vec3(6.469e-5,1.84e-6,.00030502);e+=f[1]*vec3(.00021941,6.21e-6,.00103681);e+=f[2]*vec3(.00112057,3.101e-5,.00531314);e+=f[3]*vec3(.00376661,.00010475,.01795439);e+=f[4]*vec3(.01188055,.00035364,.05707758);e+=f[5]*vec3(.02328644,.00095147,.11365162);e+=f[6]*vec3(.03455942,.00228226,.17335873);e+=f[7]*vec3(.03722379,.00420733,.19620658);e+=f[8]*vec3(.03241838,.0066888,.18608237);e+=f[9]*vec3(.02123321,.0098884,.13995048);e+=f[10]*vec3(.01049099,.01524945,.08917453);e+=f[11]*vec3(.00329584,.02141831,.04789621);e+=f[12]*vec3(.00050704,.03342293,.02814563);e+=f[13]*vec3(.00094867,.05131001,.01613766);e+=f[14]*vec3(.00627372,.07040208,.0077591);e+=f[15]*vec3(.01686462,.08783871,.00429615);e+=f[16]*vec3(.02868965,.09424905,.00200551);e+=f[17]*vec3(.04267481,.09795667,.00086147);e+=f[18]*vec3(.05625475,.09415219,.00036904);e+=f[19]*vec3(.0694704,.08678102,.00019143);e+=f[20]*vec3(.08305315,.07885653,.00014956);e+=f[21]*vec3(.0861261,.0635267,9.231e-5);e+=f[22]*vec3(.09046614,.05374142,6.813e-5);e+=f[23]*vec3(.08500387,.04264606,2.883e-5);e+=f[24]*vec3(.07090667,.03161735,1.577e-5);e+=f[25]*vec3(.05062889,.02088521,3.94e-6);e+=f[26]*vec3(.03547396,.01386011,1.58e-6);e+=f[27]*vec3(.02146821,.00810264,0);e+=f[28]*vec3(.01251646,.0046301,0);e+=f[29]*vec3(.00680458,.00249138,0);e+=f[30]*vec3(.00346457,.0012593,0);e+=f[31]*vec3(.00149761,.00054165,0);e+=f[32]*vec3(.0007697,.00027795,0);e+=f[33]*vec3(.00040737,.00014711,0);e+=f[34]*vec3(.00016901,6.103e-5,0);e+=f[35]*vec3(9.522e-5,3.439e-5,0);e+=f[36]*vec3(4.903e-5,1.771e-5,0);e+=f[37]*vec3(2e-5,7.22e-6,0);return e;}float spectral_linear_to_concentration(float v,float m,float s){float z=m*pow(s,2.);return z/(v*pow(1.-s,2.)+z);}vec3 spectral_mix(vec3 s,vec3 f,float e){vec3 v=spectral_srgb_to_linear(s),m=spectral_srgb_to_linear(f);float z[38],o[38];spectral_linear_to_reflectance(v,z);spectral_linear_to_reflectance(m,o);float x=spectral_reflectance_to_xyz(z)[1],w=spectral_reflectance_to_xyz(o)[1];e=spectral_linear_to_concentration(x,w,e);float r[38];for(int c=0;c<38;c++){float y=(1.-e)*(pow(1.-z[c],2.)/(2.*z[c]))+e*(pow(1.-o[c],2.)/(2.*o[c]));r[c]=1.+y-sqrt(pow(y,2.)+2.*y);}return spectral_xyz_to_srgb(spectral_reflectance_to_xyz(r));}vec4 spectral_mix(vec4 s,vec4 e,float z){return vec4(spectral_mix(s.xyz,e.xyz,z),mix(s.w,e.w,z));}"};function d(t,e){n(),m.list.set(t,{gen:e}),m.current=t,m.refresh()}p5.prototype.registerMethod("afterSetup",(()=>c.blend(!1,!0))),p5.prototype.registerMethod("afterSetup",(()=>c.blend(!1,!0,!0))),p5.prototype.registerMethod("post",(()=>c.blend(!1,!0))),p5.prototype.registerMethod("post",(()=>c.blend(!1,!0,!0)));const m={isActive:!1,list:new Map,current:"",step_length:()=>Math.min(e.width,e.height)/1e3,create(){this.R=.01*e.width,this.left_x=-1*e.width,this.top_y=-1*e.height,this.num_columns=Math.round(2*e.width/this.R),this.num_rows=Math.round(2*e.height/this.R),this.addStandard()},flow_field(){return this.list.get(this.current).field},refresh(t=0){this.list.get(this.current).field=this.list.get(this.current).gen(t)},genField(){let t=new Array(m.num_columns);for(let e=0;e=0&&this.row_index>=0&&this.column_index=-t-a()[0]&&this.x<=t-a()[0]&&this.y>=-i-a()[1]&&this.y<=i-a()[1]}angle(){return this.isIn()&&m.isActive?m.flow_field()[this.column_index][this.row_index]:0}moveTo(t,e,i=m.step_length(),s=!0){if(this.isIn()){let n,r;s||(n=o.cos(-e),r=o.sin(-e));for(let a=0;a{const i="marker"===e.type||"custom"===e.type||"image"===e.type;"image"===e.type&&(v.add(e.image.src),e.tip=()=>g.mask.image(v.tips.get(g.p.image.src),-g.p.weight/2,-g.p.weight/2,g.p.weight,g.p.weight)),e.blend=!!(i&&!1!==e.blend||e.blend),g.list.set(t,{param:e,colors:[],buffers:[]})},set(t,e,i=1){g.name=t,g.c=e,g.w=i,g.isActive=!0},setBrush(t){g.name=t},setColor(t,e,i){arguments.length>0&&(g.c=arguments.length<2?t:[t,e,i]),g.isActive=!0},setWeight(t){g.w=t},clip(t){g.cr=t},noClip(){g.cr=null},line(t,e,i,s){n();let o=dist(t,e,i,s);if(0==o)return;g.initializeDrawingState(t,e,o,!1,!1);let r=l(t,e,i,s);g.draw(r,!1)},flowLine(t,e,i,s){n(),"radians"===angleMode()&&(s=180*s/Math.PI),g.initializeDrawingState(t,e,i,!0,!1),g.draw(s,!1)},flowShape(t,e,i,s){n(),g.initializeDrawingState(e,i,t.length,!0,t),g.draw(s,!0)},spacing(){return this.p=this.list.get(this.name).param,this.p.spacing*this.w},initializeDrawingState(t,e,i,s,n){this.position=new p(t,e),this.length=i,this.flow=s,this.plot=n,n&&n.calcIndex(0)},draw(t,e){e||(this.dir=t),this.pushState();const i=this.spacing(),s=e?Math.round(this.length*t/i):Math.round(this.length/i);for(let n=0;n=g.cr[0]&&this.position.x<=g.cr[2]&&this.position.y>=g.cr[1]&&this.position.y<=g.cr[3]},drawSpray(t){let e=this.w*this.p.vibration*t+this.w*randomGaussian()*this.p.vibration/3,i=this.p.weight*o.random(.9,1.1);const s=this.p.quality/t;for(let t=0;t.4&&this.mask.circle(this.position.x+.7*e*o.random(-1,1),this.position.y+e*o.random(-1,1),t*this.p.weight*this.w*o.random(.85,1.15))},adjustSizeAndRotation(t,e){if(this.mask.scale(t),"image"===this.p.type&&(this.p.blend?this.mask.tint(255,0,0,e/2):this.mask.tint(this.mask.red(this.c),this.mask.green(this.c),this.mask.blue(this.c),e)),"random"===this.p.rotate)this.mask.rotate(o.randInt(0,360));else if("natural"===this.p.rotate){let t=(this.plot?-this.plot.angle(this.position.plotted):-this.dir)+(this.flow?this.position.angle():0);t=this.plot?-this.plot.angle(this.position.plotted):-this.dir,this.mask.rotate(t)}},markerTip(){if(this.isInsideClippingArea()){let t=this.calculatePressure(),e=this.calculateAlpha(t);if(this.mask.fill(255,0,0,e/1.5),"marker"===g.p.type)for(let e=1;e<5;e++)this.drawMarker(t*e/5,!1);else if("custom"===g.p.type||"image"===g.p.type)for(let i=1;i<5;i++)this.drawCustomOrImage(t*i/5,e,!1)}}};const v={tips:new Map,add(t){const e=new Image;this.tips.set(t,!1),e.onload=function(){v.tips.set(t,v.imageToWhite(e))},e.src=t},imageToWhite(t){let e=document.createElement("canvas");e.width=t.width,e.height=t.height;let i=e.getContext("2d");i.drawImage(t,0,0);let s=i.getImageData(0,0,t.width,t.height);for(let e=0;e<4*t.width*t.height;e+=4){let t=(s.data[e]+s.data[e+1]+s.data[e+2])/3;s.data[e]=s.data[e+1]=s.data[e+2]=255,s.data[e+3]=255-t}return i.putImageData(s,0,0),e.toDataURL()},load(){if(0===this.tips.size)return console.log("ojo");for(let t of this.tips.keys())this.tips.set(t,loadImage(this.tips.get(t)))}};function x(t=5,e=45,i={rand:!1,continuous:!1,gradient:!1}){w.isActive=!0,w.hatchingParams=[t,e,i]}const w={isActive:!1,hatchingParams:[5,45,{}],hatchingBrush:!1,hatch(t){let e=w.hatchingParams[0],i=w.hatchingParams[1],s=w.hatchingParams[2],n=g.c,r=g.name,a=g.w,h=g.isActive;w.hatchingBrush&&g.set(w.hatchingBrush[0],w.hatchingBrush[1],w.hatchingBrush[2]),i=(("radians"===angleMode()?180*i/Math.PI:i)+1080)%180;let l=1/0,c=-1/0,d=1/0,m=-1/0,p=t=>{for(let e of t.a)l=e[0]c?e[0]:c,d=e[1]m?e[1]:m};Array.isArray(t)||(t=[t]);for(let e of t)p(e);let f=new y([[l,d],[c,d],[c,m],[l,m]]),u=i<=90&&i>=0?d:m,v=s.gradient?map(s.gradient,0,1,1,1.1,!0):1,x=[],_=0,z=e,k=t=>({point1:{x:l+z*t*o.cos(90-i),y:u+z*t*o.sin(90-i)},point2:{x:l+z*t*o.cos(90-i)+o.cos(-i),y:u+z*t*o.sin(90-i)+o.sin(-i)}});for(;f.intersect(k(_)).length>0;){let e=[];for(let i of t)e.push(i.intersect(k(_)));x[_]=e.flat().sort(((t,e)=>t.x===e.x?t.y-e.y:t.x-e.x)),z*=v,_++}let M=[];for(let t of x)void 0!==t[0]&&M.push(t);for(let t=0;t0&&s.continuous;for(let s=0;s({x:t[0],y:t[1]}))),this.sides=this.vertices.map(((t,e,i)=>[t,i[(e+1)%i.length]]))}intersect(t){let e=`${t.point1.x},${t.point1.y}-${t.point2.x},${t.point2.y}`;if(this._intersectionCache&&this._intersectionCache[e])return this._intersectionCache[e];let i=[];for(let e of this.sides){let s=h(t.point1,t.point2,e[0],e[1]);!1!==s&&i.push(s)}return this._intersectionCache||(this._intersectionCache={}),this._intersectionCache[e]=i,i}draw(t=!1,e,i){let s=g.isActive;if(t&&g.set(t,e,i),g.isActive){n();for(let t of this.sides)g.line(t[0].x,t[0].y,t[1].x,t[1].y)}g.isActive=s}fill(t=!1,e,i,s){let o=P.isActive;t&&(S(t,e),I(i,s)),P.isActive&&(n(),P.fill(this)),P.isActive=o}hatch(t=!1,e,i){let s=w.isActive;t&&x(t,e,i),w.isActive&&(n(),w.hatch(this)),w.isActive=s}}class _{constructor(t){this.segments=[],this.angles=[],this.pres=[],this.type=t,this.dir=0,this.calcIndex(0),this.pol=!1}addSegment(t=0,e=0,i=1,s=!1){"radians"!==angleMode()||s||(t=180*t/Math.PI),this.angles.length>0&&this.angles.splice(-1),t=(t+360)%360,this.angles.push(t),this.pres.push(i),this.segments.push(e),this.length=this.segments.reduce(((t,e)=>t+e),0),this.angles.push(t)}endPlot(t=0,e=1,i=!1){"radians"!==angleMode()||i||(t=180*t/Math.PI),this.angles.splice(-1),this.angles.push(t),this.pres.push(e)}rotate(t){"radians"===angleMode()&&(t=180*t/Math.PI),this.dir=t}pressure(t){return t>this.length?this.pres[this.pres.length-1]:this.curving(this.pres,t)}angle(t){return t>this.length?this.angles[this.angles.length-1]:(this.calcIndex(t),"curve"===this.type?this.curving(this.angles,t)+this.dir:this.angles[this.index]+this.dir)}curving(t,e){let i=t[this.index],s=t[this.index+1];return void 0===s&&(s=i),Math.abs(s-i)>180&&(s>i?s=-(360-s):i=-(360-i)),o.map(e-this.suma,0,this.segments[this.index],i,s,!0)}calcIndex(t){this.index=-1,this.suma=0;let e=0;for(;e<=t;)this.suma=e,e+=this.segments[this.index+1],this.index++}genPol(t,e,i=1,s=!1){n();let o=0,r=9999;for(let t of this.segments)t*=i,0!==t&&(o=Math.max(o,t),r=Math.min(r,t));let a=g.spacing(),h=[],l=(o+r)*(s?.03:P.isAnimated?.25:P.b),c=new p(t,e),d=Math.round(this.length/a);for(let t=0;t0){i.origin=t[0];let s=0;for(let n=0;n0&&n1?1:e,P.border_strength=1+i>1?1:i}const P={isActive:!1,isAnimated:!1,b:.07,t:0,o:80,border_strength:1,fill(t){this.v=t.a.map((t=>createVector(t[0],t[1])));const e=this.v.length*o.random(.4);P.m=this.v.map(((t,i)=>{let s=o.random(.8,1.2)*this.b;return i=.2?Math.floor(t*this.v.length):this.v.length;const o=t=>t+.1*(randomGaussian(.5,.1)-.5),r="radians"===angleMode()?Math.PI/180:1;for(let a=0;as?o.random(-1,1):0;n.addSegment(0+a(),r+a(),1,!0),n.addSegment(-90+a(),r+a(),1,!0),n.addSegment(-180+a(),r+a(),1,!0),n.addSegment(-270+a(),r+a(),1,!0);let h=s?o.randInt(-5,5):0;if(s&&n.addSegment(0,h*(Math.PI/180)*i,!0),n.endPlot(h+0,1,!0),P.isActive||w.isActive){let s=n.genPol(t-i*o.sin(0),e-i*o.cos(-0));s.fill(),s.hatch()}g.isActive&&n.draw(t-i*o.sin(0),e-i*o.cos(-0),1)},t.polygon=function(t){if(!Array.isArray(t)||t.length<3)return void console.error("Invalid input for polygon: An array with at least 3 points is required.");let e=new y(t);e.fill(),e.hatch(),e.draw()},t.spline=function(t,e=.5){A(t,e).draw()},t.beginShape=M,t.vertex=b,t.endShape=C,t.beginStroke=function(t,e,i){z=[e,i],k=new _(t)},t.segment=function(t,e,i){k.addSegment(t,e,i)},t.endStroke=function(t,e){k.endPlot(t,e),k.draw(z[0],z[1],1),k=!1},t.hatchArray=w.hatch,t.hatch=x,t.setHatch=function(t,e,i=1){w.hatchingBrush=[t,e,i]},t.noHatch=function(){w.isActive=!1,w.hatchingBrush=!1},t.Polygon=y,t.Plot=_,t.Position=p})); \ No newline at end of file +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?e(exports):"function"==typeof define&&define.amd?define(["exports"],e):e((t=t||self).brush={})}(this,(function(t){"use strict";let e,i=!1;function s(t=!1){i=!0,e=t||window.self,c.load(),m.create(),f(e.width/250)}function n(){i||s()}p5.prototype.registerMethod("afterSetup",(()=>n()));const o={source:()=>random(),random(t=0,e=1){return 1===arguments.length?this.map(this.source(),0,1,0,t):this.map(this.source(),0,1,t,e)},randInt(t,e){return Math.floor(this.random(t,e))},weightedRand(t){let e,i,s=[];for(e in t)for(i=0;i<10*t[e];i++)s.push(e);return s[Math.floor(this.source()*s.length)]},map(t,e,i,s,n,o=!1){let r=s+(t-e)/(i-e)*(n-s);return o?sMath.max(Math.min(t,i),e),cos(t){return this.c[Math.floor((t%360+360)%360*4)]},sin(t){return this.s[Math.floor((t%360+360)%360*4)]},isPrecalculationDone:!1,preCalculation(){if(this.isPrecalculationDone)return;const t=1440,e=2*Math.PI/t;this.c=new Float64Array(t),this.s=new Float64Array(t);for(let i=0;i1))&&{x:o+x*p,y:r+x*f}}function l(t,e,i,s){return(Math.atan2(-(s-e),i-t)*(180/Math.PI)%360+360)%360}const c={loaded:!1,isBlending:!1,isCaching:!0,currentColor:new Float32Array(3),load(){this.mask=createGraphics(e.width,e.height),this.mask.pixelDensity(e.pixelDensity()),this.mask.clear(),this.mask.noSmooth(),this.mask.angleMode(DEGREES),t.mask=this.mask,c.loaded||(this.frag=this.frag.replace('#include "spectral.glsl"',this.glsl())),this.shader=e.createShader(this.vert,this.frag),c.loaded=!0,this.noBlend=createGraphics(e.width,e.height),this.noBlend.pixelDensity(e.pixelDensity()),this.noBlend.noSmooth(),this.noBlend.clear(),this.noBlend.angleMode(DEGREES),this.mask2=createGraphics(e.width,e.height,WEBGL),this.mask2.pixelDensity(e.pixelDensity()),this.mask2.clear(),this.mask2.angleMode(DEGREES)},getPigment(t){let e=t.levels,i=new Float32Array(3);return i[0]=e[0]/255,i[1]=e[1]/255,i[2]=e[2]/255,i},color1:new Float32Array(3),color2:new Float32Array(3),blending1:!1,blending2:!1,blend(t=!1,i=!1,s=!1,n=!1){if(this.isBlending=s?this.blending1:this.blending2,this.currentColor=s?this.color1:this.color2,!this.isBlending){if(!t)return e.push(),e.translate(-a()[0],-a()[1]),e.image(this.noBlend,-e.width/2,-e.height/2),this.noBlend.clear(),void e.pop();this.currentColor=this.getPigment(t),s?(this.blending1=!0,this.color1=this.currentColor):(this.blending2=!0,this.color2=this.currentColor)}if((t?this.getPigment(t):this.currentColor).toString()!==this.currentColor.toString()||i||!this.isCaching){e.push(),e.translate(-a()[0],-a()[1]),e.image(this.noBlend,-e.width/2,-e.height/2),this.noBlend.clear(),e.shader(this.shader),this.shader.setUniform("addColor",this.currentColor),this.shader.setUniform("source",e._renderer),this.shader.setUniform("active",n),this.shader.setUniform("random",[o.random(),o.random(),o.random()]);let r=s?this.mask2:this.mask;this.shader.setUniform("mask",r),e.fill(0,0,0,0),e.noStroke(),e.rect(-e.width/2,-e.height/2,e.width,e.height),e.pop(),r.clear(),i||(this.currentColor=this.getPigment(t),s?this.color1=this.currentColor:this.color2=this.currentColor)}i&&(this.isBlending=!1,s?this.blending1=this.isBlending:this.blending2=this.isBlending)},vert:"precision highp float;attribute vec3 aPosition;attribute vec2 aTexCoord;uniform mat4 uModelViewMatrix,uProjectionMatrix;varying vec2 vVertTexCoord;void main(){gl_Position=uProjectionMatrix*uModelViewMatrix*vec4(aPosition,1);vVertTexCoord=aTexCoord;}",frag:'precision highp float;varying vec2 vVertTexCoord;uniform sampler2D source,mask;uniform vec4 addColor;uniform vec3 random;uniform bool active;\n #include "spectral.glsl"\n float v(vec2 v,vec2 x,float y,out vec2 i){vec2 d=vec2(v.x+v.y*.5,v.y),m=floor(d),f=fract(d);float a=step(f.y,f.x);vec2 r=vec2(a,1.-a),l=m+r,e=m+1.,z=vec2(m.x-m.y*.5,m.y),k=vec2(z.x+r.x-r.y*.5,z.y+r.y),o=vec2(z.x+.5,z.y+1.),s=v-z,g=v-k,t=v-o;vec3 u,c,C,D;if(any(greaterThan(x,vec2(0)))){C=vec3(z.x,k.x,o);D=vec3(z.y,k.y,o.y);if(x.x>0.)C=mod(vec3(z.x,k.x,o),x.x);if(x.y>0.)D=mod(vec3(z.y,k.y,o.y),x.y);u=floor(C+.5*D+.5);c=floor(D+.5);}else u=vec3(m.x,l.x,e),c=vec3(m.y,l.y,e.y);vec3 b=mod(u,289.);b=mod((b*51.+2.)*b+c,289.);b=mod((b*34.+10.)*b,289.);vec3 h=b*.07482+y,E=cos(h),w=sin(h);vec2 A=vec2(E.x,w),B=vec2(E.y,w.y),F=vec2(E.z,w.z);vec3 G=.8-vec3(dot(s,s),dot(g,g),dot(t,t));G=max(G,0.);vec3 H=G*G,I=H*H,J=vec3(dot(A,s),dot(B,g),dot(F,t)),K=H*G,L=-8.*K*J;i=10.9*(I.x*A+L.x*s+(I.y*B+L.y*g)+(I.z*F+L.z*t));return 10.9*dot(I,J);}vec4 v(vec3 v,float f){return vec4(mix(v,vec3(dot(vec3(.299,.587,.114),v)),f),1);}float f(vec2 v,float x,float y,float d){return fract(sin(dot(v,vec2(x,y)))*d);}void main(){vec4 m=texture2D(mask,vVertTexCoord);if(m.x>0.){vec2 z=vec2(12.9898,78.233),k=vec2(7.9898,58.233),o=vec2(17.9898,3.233);float x=f(vVertTexCoord,z.x,z.y,43358.5453)*2.-1.,y=f(vVertTexCoord,k.x,k.y,43213.5453)*2.-1.,d=f(vVertTexCoord,o.x,o.y,33358.5453)*2.-1.;const vec2 s=vec2(0);vec2 t;vec3 u;if(active){float a=v(vVertTexCoord*10.,s,10.*random.x,t),c=v(vVertTexCoord*10.,s,10.*random.y,t),g=v(vVertTexCoord*10.,s,10.*random.z,t),w=.25+.25*v(vVertTexCoord*8.,s,3.*random.x,t);u=v(addColor.xyz,w).xyz+vec3(a,c,g)*.03;}else u=addColor.xyz;vec3 a=spectral_mix(texture2D(source,vVertTexCoord).xyz,u,m.w);if(m.w>.8)a=spectral_mix(a,vec3(0),(m.w-.8)*.4);gl_FragColor=vec4(a+.01*vec3(x,y,d),1);}}',glsl:()=>"float spectral_uncompand(float s){return s<.04045?s/12.92:pow((s+.055)/1.055,2.4);}float spectral_compand(float s){return s<.0031308?s*12.92:1.055*pow(s,1./2.4)-.055;}vec3 spectral_srgb_to_linear(vec3 s){return vec3(spectral_uncompand(s[0]),spectral_uncompand(s[1]),spectral_uncompand(s[2]));}vec3 spectral_linear_to_srgb(vec3 s){return clamp(vec3(spectral_compand(s[0]),spectral_compand(s[1]),spectral_compand(s[2])),0.,1.);}void spectral_upsampling(vec3 e,out float m,out float s,out float f,out float r,out float x,out float v,out float z){m=min(e.x,min(e.y,e.z));e-=m;s=min(e.y,e.z);f=min(e.x,e.z);r=min(e.x,e.y);x=min(max(0.,e.x-e.z),max(0.,e.x-e.y));v=min(max(0.,e.y-e.z),max(0.,e.y-e.x));z=min(max(0.,e.z-e.y),max(0.,e.z-e.x));}void spectral_linear_to_reflectance(vec3 s,inout float f[38]){float e,o,m,x,v,w,z;spectral_upsampling(s,e,o,m,x,v,w,z);f[0]=max(1e-4,e+o*.96853629+m*.51567122+x*.02055257+v*.03147571+w*.49108579+z*.97901834);f[1]=max(1e-4,e+o*.96855103+m*.5401552+x*.02059936+v*.03146636+w*.46944057+z*.97901649);f[2]=max(1e-4,e+o*.96859338+m*.62645502+x*.02062723+v*.03140624+w*.4016578+z*.97901118);f[3]=max(1e-4,e+o*.96877345+m*.75595012+x*.02073387+v*.03119611+w*.2449042+z*.97892146);f[4]=max(1e-4,e+o*.96942204+m*.92826996+x*.02114202+v*.03053888+w*.0682688+z*.97858555);f[5]=max(1e-4,e+o*.97143709+m*.97223624+x*.02233154+v*.02856855+w*.02732883+z*.97743705);f[6]=max(1e-4,e+o*.97541862+m*.98616174+x*.02556857+v*.02459485+w*.013606+z*.97428075);f[7]=max(1e-4,e+o*.98074186+m*.98955255+x*.03330189+v*.0192952+w*.01000187+z*.96663223);f[8]=max(1e-4,e+o*.98580992+m*.98676237+x*.05185294+v*.01423112+w*.01284127+z*.94822893);f[9]=max(1e-4,e+o*.98971194+m*.97312575+x*.10087639+v*.01033111+w*.02636635+z*.89937713);f[10]=max(1e-4,e+o*.99238027+m*.91944277+x*.24000413+v*.00765876+w*.07058713+z*.76070164);f[11]=max(1e-4,e+o*.99409844+m*.32564851+x*.53589066+v*.00593693+w*.70421692+z*.4642044);f[12]=max(1e-4,e+o*.995172+m*.13820628+x*.79874659+v*.00485616+w*.85473994+z*.20123039);f[13]=max(1e-4,e+o*.99576545+m*.05015143+x*.91186529+v*.00426186+w*.95081565+z*.08808402);f[14]=max(1e-4,e+o*.99593552+m*.02912336+x*.95399623+v*.00409039+w*.9717037+z*.04592894);f[15]=max(1e-4,e+o*.99564041+m*.02421691+x*.97137099+v*.00438375+w*.97651888+z*.02860373);f[16]=max(1e-4,e+o*.99464769+m*.02660696+x*.97939505+v*.00537525+w*.97429245+z*.02060067);f[17]=max(1e-4,e+o*.99229579+m*.03407586+x*.98345207+v*.00772962+w*.97012917+z*.01656701);f[18]=max(1e-4,e+o*.98638762+m*.04835936+x*.98553736+v*.0136612+w*.9425863+z*.01451549);f[19]=max(1e-4,e+o*.96829712+m*.0001172+x*.98648905+v*.03181352+w*.99989207+z*.01357964);f[20]=max(1e-4,e+o*.89228016+m*8.554e-5+x*.98674535+v*.10791525+w*.99989891+z*.01331243);f[21]=max(1e-4,e+o*.53740239+m*.85267882+x*.98657555+v*.46249516+w*.13823139+z*.01347661);f[22]=max(1e-4,e+o*.15360445+m*.93188793+x*.98611877+v*.84604333+w*.06968113+z*.01387181);f[23]=max(1e-4,e+o*.05705719+m*.94810268+x*.98559942+v*.94275572+w*.05628787+z*.01435472);f[24]=max(1e-4,e+o*.03126539+m*.94200977+x*.98507063+v*.96860996+w*.06111561+z*.01479836);f[25]=max(1e-4,e+o*.02205445+m*.91478045+x*.98460039+v*.97783966+w*.08987709+z*.0151525);f[26]=max(1e-4,e+o*.01802271+m*.87065445+x*.98425301+v*.98187757+w*.13656016+z*.01540513);f[27]=max(1e-4,e+o*.0161346+m*.78827548+x*.98403909+v*.98377315+w*.22169624+z*.01557233);f[28]=max(1e-4,e+o*.01520947+m*.65738359+x*.98388535+v*.98470202+w*.32176956+z*.0156571);f[29]=max(1e-4,e+o*.01475977+m*.59909403+x*.98376116+v*.98515481+w*.36157329+z*.01571025);f[30]=max(1e-4,e+o*.01454263+m*.56817268+x*.98368246+v*.98537114+w*.4836192+z*.01571916);f[31]=max(1e-4,e+o*.01444459+m*.54031997+x*.98365023+v*.98546685+w*.46488579+z*.01572133);f[32]=max(1e-4,e+o*.01439897+m*.52110241+x*.98361309+v*.98550011+w*.47440306+z*.01572502);f[33]=max(1e-4,e+o*.0143762+m*.51041094+x*.98357259+v*.98551031+w*.4857699+z*.01571717);f[34]=max(1e-4,e+o*.01436343+m*.50526577+x*.98353856+v*.98550741+w*.49267971+z*.01571905);f[35]=max(1e-4,e+o*.01435687+m*.5025508+x*.98351247+v*.98551323+w*.49625685+z*.01571059);f[36]=max(1e-4,e+o*.0143537+m*.50126452+x*.98350101+v*.98551563+w*.49807754+z*.01569728);f[37]=max(1e-4,e+o*.01435408+m*.50083021+x*.98350852+v*.98551547+w*.49889859+z*.0157002);}vec3 spectral_xyz_to_srgb(vec3 e){mat3 f;f[0]=vec3(3.24306333,-1.53837619,-.49893282);f[1]=vec3(-.96896309,1.87542451,.04154303);f[2]=vec3(.05568392,-.20417438,1.05799454);float s=dot(f[0],e),m=dot(f[1],e),z=dot(f[2],e);return spectral_linear_to_srgb(vec3(s,m,z));}vec3 spectral_reflectance_to_xyz(float f[38]){vec3 e=vec3(0);e+=f[0]*vec3(6.469e-5,1.84e-6,.00030502);e+=f[1]*vec3(.00021941,6.21e-6,.00103681);e+=f[2]*vec3(.00112057,3.101e-5,.00531314);e+=f[3]*vec3(.00376661,.00010475,.01795439);e+=f[4]*vec3(.01188055,.00035364,.05707758);e+=f[5]*vec3(.02328644,.00095147,.11365162);e+=f[6]*vec3(.03455942,.00228226,.17335873);e+=f[7]*vec3(.03722379,.00420733,.19620658);e+=f[8]*vec3(.03241838,.0066888,.18608237);e+=f[9]*vec3(.02123321,.0098884,.13995048);e+=f[10]*vec3(.01049099,.01524945,.08917453);e+=f[11]*vec3(.00329584,.02141831,.04789621);e+=f[12]*vec3(.00050704,.03342293,.02814563);e+=f[13]*vec3(.00094867,.05131001,.01613766);e+=f[14]*vec3(.00627372,.07040208,.0077591);e+=f[15]*vec3(.01686462,.08783871,.00429615);e+=f[16]*vec3(.02868965,.09424905,.00200551);e+=f[17]*vec3(.04267481,.09795667,.00086147);e+=f[18]*vec3(.05625475,.09415219,.00036904);e+=f[19]*vec3(.0694704,.08678102,.00019143);e+=f[20]*vec3(.08305315,.07885653,.00014956);e+=f[21]*vec3(.0861261,.0635267,9.231e-5);e+=f[22]*vec3(.09046614,.05374142,6.813e-5);e+=f[23]*vec3(.08500387,.04264606,2.883e-5);e+=f[24]*vec3(.07090667,.03161735,1.577e-5);e+=f[25]*vec3(.05062889,.02088521,3.94e-6);e+=f[26]*vec3(.03547396,.01386011,1.58e-6);e+=f[27]*vec3(.02146821,.00810264,0);e+=f[28]*vec3(.01251646,.0046301,0);e+=f[29]*vec3(.00680458,.00249138,0);e+=f[30]*vec3(.00346457,.0012593,0);e+=f[31]*vec3(.00149761,.00054165,0);e+=f[32]*vec3(.0007697,.00027795,0);e+=f[33]*vec3(.00040737,.00014711,0);e+=f[34]*vec3(.00016901,6.103e-5,0);e+=f[35]*vec3(9.522e-5,3.439e-5,0);e+=f[36]*vec3(4.903e-5,1.771e-5,0);e+=f[37]*vec3(2e-5,7.22e-6,0);return e;}float spectral_linear_to_concentration(float v,float m,float s){float z=m*pow(s,2.);return z/(v*pow(1.-s,2.)+z);}vec3 spectral_mix(vec3 s,vec3 f,float e){vec3 v=spectral_srgb_to_linear(s),m=spectral_srgb_to_linear(f);float z[38],o[38];spectral_linear_to_reflectance(v,z);spectral_linear_to_reflectance(m,o);float x=spectral_reflectance_to_xyz(z)[1],w=spectral_reflectance_to_xyz(o)[1];e=spectral_linear_to_concentration(x,w,e);float r[38];for(int c=0;c<38;c++){float y=(1.-e)*(pow(1.-z[c],2.)/(2.*z[c]))+e*(pow(1.-o[c],2.)/(2.*o[c]));r[c]=1.+y-sqrt(pow(y,2.)+2.*y);}return spectral_xyz_to_srgb(spectral_reflectance_to_xyz(r));}vec4 spectral_mix(vec4 s,vec4 e,float z){return vec4(spectral_mix(s.xyz,e.xyz,z),mix(s.w,e.w,z));}"};function d(t,e){n(),m.list.set(t,{gen:e}),m.current=t,m.refresh()}p5.prototype.registerMethod("afterSetup",(()=>c.blend(!1,!0))),p5.prototype.registerMethod("afterSetup",(()=>c.blend(!1,!0,!0))),p5.prototype.registerMethod("post",(()=>c.blend(!1,!0))),p5.prototype.registerMethod("post",(()=>c.blend(!1,!0,!0)));const m={isActive:!1,list:new Map,current:"",step_length:()=>Math.min(e.width,e.height)/1e3,create(){this.R=.01*e.width,this.left_x=-1*e.width,this.top_y=-1*e.height,this.num_columns=Math.round(2*e.width/this.R),this.num_rows=Math.round(2*e.height/this.R),this.addStandard()},flow_field(){return this.list.get(this.current).field},refresh(t=0){this.list.get(this.current).field=this.list.get(this.current).gen(t)},genField(){let t=new Array(m.num_columns);for(let e=0;e=0&&this.row_index>=0&&this.column_index=-t-a()[0]&&this.x<=t-a()[0]&&this.y>=-i-a()[1]&&this.y<=i-a()[1]}angle(){return this.isIn()&&m.isActive?m.flow_field()[this.column_index][this.row_index]:0}moveTo(t,e,i=m.step_length(),s=!0){if(this.isIn()){let n,r;s||(n=o.cos(-e),r=o.sin(-e));for(let a=0;a{const i="marker"===e.type||"custom"===e.type||"image"===e.type;"image"===e.type&&(v.add(e.image.src),e.tip=()=>{g.mask.image(v.tips.get(g.p.image.src),-g.p.weight/2,-g.p.weight/2,g.p.weight,g.p.weight)}),e.blend=!!(i&&!1!==e.blend||e.blend),g.list.set(t,{param:e,colors:[],buffers:[]})},set(t,e,i=1){g.name=t,g.c=e,g.w=i,g.isActive=!0},setBrush(t){g.name=t},setColor(t,e,i){arguments.length>0&&(g.c=arguments.length<2?t:[t,e,i]),g.isActive=!0},setWeight(t){g.w=t},clip(t){g.cr=t},noClip(){g.cr=null},line(t,e,i,s){n();let o=dist(t,e,i,s);if(0==o)return;g.initializeDrawingState(t,e,o,!1,!1);let r=l(t,e,i,s);g.draw(r,!1)},flowLine(t,e,i,s){n(),"radians"===angleMode()&&(s=180*s/Math.PI),g.initializeDrawingState(t,e,i,!0,!1),g.draw(s,!1)},flowShape(t,e,i,s){n(),g.initializeDrawingState(e,i,t.length,!0,t),g.draw(s,!0)},spacing(){return this.p=this.list.get(this.name).param,this.p.spacing*this.w},initializeDrawingState(t,e,i,s,n){this.position=new p(t,e),this.length=i,this.flow=s,this.plot=n,n&&n.calcIndex(0)},draw(t,e){e||(this.dir=t),this.pushState();const i=this.spacing(),s=e?Math.round(this.length*t/i):Math.round(this.length/i);for(let n=0;n=g.cr[0]&&this.position.x<=g.cr[2]&&this.position.y>=g.cr[1]&&this.position.y<=g.cr[3]},drawSpray(t){let e=this.w*this.p.vibration*t+this.w*randomGaussian()*this.p.vibration/3,i=this.p.weight*o.random(.9,1.1);const s=this.p.quality/t;for(let t=0;t.4&&this.mask.circle(this.position.x+.7*e*o.random(-1,1),this.position.y+e*o.random(-1,1),t*this.p.weight*this.w*o.random(.85,1.15))},adjustSizeAndRotation(t,e){if(this.mask.scale(t),"image"===this.p.type&&(this.p.blend?this.mask.tint(255,0,0,e/2):this.mask.tint(this.mask.red(this.c),this.mask.green(this.c),this.mask.blue(this.c),e)),"random"===this.p.rotate)this.mask.rotate(o.randInt(0,360));else if("natural"===this.p.rotate){let t=(this.plot?-this.plot.angle(this.position.plotted):-this.dir)+(this.flow?this.position.angle():0);t=this.plot?-this.plot.angle(this.position.plotted):-this.dir,this.mask.rotate(t)}},markerTip(){if(this.isInsideClippingArea()){let t=this.calculatePressure(),e=this.calculateAlpha(t);if(this.mask.fill(255,0,0,e/1.5),"marker"===g.p.type)for(let e=1;e<5;e++)this.drawMarker(t*e/5,!1);else if("custom"===g.p.type||"image"===g.p.type)for(let i=1;i<5;i++)this.drawCustomOrImage(t*i/5,e,!1)}}};const v={tips:new Map,add(t){this.tips.set(t,!1)},imageToWhite(t){t.loadPixels();for(let e=0;e<4*t.width*t.height;e+=4){let i=(t.pixels[e]+t.pixels[e+1]+t.pixels[e+2])/3;t.pixels[e]=t.pixels[e+1]=t.pixels[e+2]=255,t.pixels[e+3]=255-i}t.updatePixels()},load(){if(0===this.tips.size)return console.log("There are no custom tips to load !");for(let t of this.tips.keys()){let e=loadImage(t,(()=>v.imageToWhite(e)));this.tips.set(t,e)}}};function x(t=5,e=45,i={rand:!1,continuous:!1,gradient:!1}){y.isActive=!0,y.hatchingParams=[t,e,i]}const y={isActive:!1,hatchingParams:[5,45,{}],hatchingBrush:!1,hatch(t){let e=y.hatchingParams[0],i=y.hatchingParams[1],s=y.hatchingParams[2],n=g.c,r=g.name,a=g.w,h=g.isActive;y.hatchingBrush&&g.set(y.hatchingBrush[0],y.hatchingBrush[1],y.hatchingBrush[2]),i=(("radians"===angleMode()?180*i/Math.PI:i)+1080)%180;let l=1/0,c=-1/0,d=1/0,m=-1/0,p=t=>{for(let e of t.a)l=e[0]c?e[0]:c,d=e[1]m?e[1]:m};Array.isArray(t)||(t=[t]);for(let e of t)p(e);let f=new w([[l,d],[c,d],[c,m],[l,m]]),u=i<=90&&i>=0?d:m,v=s.gradient?map(s.gradient,0,1,1,1.1,!0):1,x=[],_=0,z=e,k=t=>({point1:{x:l+z*t*o.cos(90-i),y:u+z*t*o.sin(90-i)},point2:{x:l+z*t*o.cos(90-i)+o.cos(-i),y:u+z*t*o.sin(90-i)+o.sin(-i)}});for(;f.intersect(k(_)).length>0;){let e=[];for(let i of t)e.push(i.intersect(k(_)));x[_]=e.flat().sort(((t,e)=>t.x===e.x?t.y-e.y:t.x-e.x)),z*=v,_++}let M=[];for(let t of x)void 0!==t[0]&&M.push(t);for(let t=0;t0&&s.continuous;for(let s=0;s({x:t[0],y:t[1]}))),this.sides=this.vertices.map(((t,e,i)=>[t,i[(e+1)%i.length]]))}intersect(t){let e=`${t.point1.x},${t.point1.y}-${t.point2.x},${t.point2.y}`;if(this._intersectionCache&&this._intersectionCache[e])return this._intersectionCache[e];let i=[];for(let e of this.sides){let s=h(t.point1,t.point2,e[0],e[1]);!1!==s&&i.push(s)}return this._intersectionCache||(this._intersectionCache={}),this._intersectionCache[e]=i,i}draw(t=!1,e,i){let s=g.isActive;if(t&&g.set(t,e,i),g.isActive){n();for(let t of this.sides)g.line(t[0].x,t[0].y,t[1].x,t[1].y)}g.isActive=s}fill(t=!1,e,i,s){let o=I.isActive;t&&(S(t,e),P(i,s)),I.isActive&&(n(),I.fill(this)),I.isActive=o}hatch(t=!1,e,i){let s=y.isActive;t&&x(t,e,i),y.isActive&&(n(),y.hatch(this)),y.isActive=s}}class _{constructor(t){this.segments=[],this.angles=[],this.pres=[],this.type=t,this.dir=0,this.calcIndex(0),this.pol=!1}addSegment(t=0,e=0,i=1,s=!1){"radians"!==angleMode()||s||(t=180*t/Math.PI),this.angles.length>0&&this.angles.splice(-1),t=(t+360)%360,this.angles.push(t),this.pres.push(i),this.segments.push(e),this.length=this.segments.reduce(((t,e)=>t+e),0),this.angles.push(t)}endPlot(t=0,e=1,i=!1){"radians"!==angleMode()||i||(t=180*t/Math.PI),this.angles.splice(-1),this.angles.push(t),this.pres.push(e)}rotate(t){"radians"===angleMode()&&(t=180*t/Math.PI),this.dir=t}pressure(t){return t>this.length?this.pres[this.pres.length-1]:this.curving(this.pres,t)}angle(t){return t>this.length?this.angles[this.angles.length-1]:(this.calcIndex(t),"curve"===this.type?this.curving(this.angles,t)+this.dir:this.angles[this.index]+this.dir)}curving(t,e){let i=t[this.index],s=t[this.index+1];return void 0===s&&(s=i),Math.abs(s-i)>180&&(s>i?s=-(360-s):i=-(360-i)),o.map(e-this.suma,0,this.segments[this.index],i,s,!0)}calcIndex(t){this.index=-1,this.suma=0;let e=0;for(;e<=t;)this.suma=e,e+=this.segments[this.index+1],this.index++}genPol(t,e,i=1,s=!1){n();let o=0,r=9999;for(let t of this.segments)t*=i,0!==t&&(o=Math.max(o,t),r=Math.min(r,t));let a=g.spacing(),h=[],l=(o+r)*(s?.03:I.isAnimated?.25:I.b),c=new p(t,e),d=Math.round(this.length/a);for(let t=0;t0){i.origin=t[0];let s=0;for(let n=0;n0&&n1?1:e,I.border_strength=1+i>1?1:i}const I={isActive:!1,isAnimated:!1,b:.07,t:0,o:80,border_strength:1,fill(t){this.v=t.a.map((t=>createVector(t[0],t[1])));const e=this.v.length*o.random(.4);I.m=this.v.map(((t,i)=>{let s=o.random(.8,1.2)*this.b;return i=.2?Math.floor(t*this.v.length):this.v.length;const o=t=>t+.1*(randomGaussian(.5,.1)-.5),r="radians"===angleMode()?Math.PI/180:1;for(let a=0;as?o.random(-1,1):0;n.addSegment(0+a(),r+a(),1,!0),n.addSegment(-90+a(),r+a(),1,!0),n.addSegment(-180+a(),r+a(),1,!0),n.addSegment(-270+a(),r+a(),1,!0);let h=s?o.randInt(-5,5):0;if(s&&n.addSegment(0,h*(Math.PI/180)*i,!0),n.endPlot(h+0,1,!0),I.isActive||y.isActive){let s=n.genPol(t-i*o.sin(0),e-i*o.cos(-0));s.fill(),s.hatch()}g.isActive&&n.draw(t-i*o.sin(0),e-i*o.cos(-0),1)},t.polygon=function(t){if(!Array.isArray(t)||t.length<3)return void console.error("Invalid input for polygon: An array with at least 3 points is required.");let e=new w(t);e.fill(),e.hatch(),e.draw()},t.spline=function(t,e=.5){A(t,e).draw()},t.beginShape=M,t.vertex=b,t.endShape=C,t.beginStroke=function(t,e,i){z=[e,i],k=new _(t)},t.segment=function(t,e,i){k.addSegment(t,e,i)},t.endStroke=function(t,e){k.endPlot(t,e),k.draw(z[0],z[1],1),k=!1},t.hatchArray=y.hatch,t.hatch=x,t.setHatch=function(t,e,i=1){y.hatchingBrush=[t,e,i]},t.noHatch=function(){y.isActive=!1,y.hatchingBrush=!1},t.Polygon=w,t.Plot=_,t.Position=p})); \ No newline at end of file diff --git a/sketch.js b/sketch.js index f59693c..8dd08e4 100644 --- a/sketch.js +++ b/sketch.js @@ -57,7 +57,6 @@ brush.add("watercolor", { rotate: "natural", // "none" disables rotation | "natural" follows the direction of the stroke | "random" }) - ////////////////////////////////////////////////// // P5 FUNCTIONS From 1b431fe46a7a8110ec95abf61dc534093d7f2590 Mon Sep 17 00:00:00 2001 From: Alejandro Date: Tue, 14 Nov 2023 11:25:05 +0100 Subject: [PATCH 3/5] Smaller res for example --- sketch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sketch.js b/sketch.js index 8dd08e4..3573fe4 100644 --- a/sketch.js +++ b/sketch.js @@ -23,7 +23,7 @@ const C = { }; // SET CANVAS SIZE: width, height, pixelDensity, html_id for the canvas // Here I'm working with mm units, so I want a big pixelDensity for high-res. -C.setSize(250,280,10,'mainCanvas') +C.setSize(250,280,5,'mainCanvas') function windowResized () { C.resize(); From 97d2079cf4aa5842016a6fe8b786ab4b8d87b222 Mon Sep 17 00:00:00 2001 From: Alejandro Date: Tue, 14 Nov 2023 11:26:15 +0100 Subject: [PATCH 4/5] Use min version --- index.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/index.html b/index.html index 68675de..afd75b4 100644 --- a/index.html +++ b/index.html @@ -3,8 +3,7 @@ p5.brush.js Example - - + From 6a1b8443339d15ab1f32df671c4ac00fccc036da Mon Sep 17 00:00:00 2001 From: Alejandro Date: Tue, 14 Nov 2023 11:28:51 +0100 Subject: [PATCH 5/5] Minor tweak --- p5.brush.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/p5.brush.js b/p5.brush.js index 1f08093..c9422ec 100644 --- a/p5.brush.js +++ b/p5.brush.js @@ -1023,9 +1023,7 @@ const isBlendableType = b.type === "marker" || b.type === "custom" || b.type === "image"; if (b.type === "image") { T.add(b.image.src); - b.tip = () => { - B.mask.image(T.tips.get(B.p.image.src), -B.p.weight / 2, -B.p.weight / 2, B.p.weight, B.p.weight); - } + b.tip = () => B.mask.image(T.tips.get(B.p.image.src), -B.p.weight / 2, -B.p.weight / 2, B.p.weight, B.p.weight); } b.blend = ((isBlendableType && b.blend !== false) || b.blend) ? true : false; B.list.set(a, { param: b, colors: [], buffers: [] });